diff --git a/plugins/ros/ros.cache.default b/plugins/ros/ros.cache.default new file mode 100644 index 000000000..a4e35be06 --- /dev/null +++ b/plugins/ros/ros.cache.default @@ -0,0 +1,5 @@ +master_ip_default = localhost +master_ip = localhost +ros_distro_default = +ros_interface = +ros_workspace = diff --git a/plugins/ros/ros.plugin.zsh b/plugins/ros/ros.plugin.zsh new file mode 100644 index 000000000..037f1a78a --- /dev/null +++ b/plugins/ros/ros.plugin.zsh @@ -0,0 +1,369 @@ +# ------------------------------------------------------------------------------ +# @brief oh-my-zsh plugin for ROS framework. +# @author Mickael GERMAIN (https://github.com/migermain) +# @version 1.0.0 +# +# This oh-my-zsh plugin attempts to help manage ros ecosystem settings and +# perform automatic configurations as often as possible. +# It also supplies prompt integration to give informations about ros state. +# +# ------------------------------------------------------------------------------ + +[ -z "$_OMZ_ROS_DIR" ] && readonly _OMZ_ROS_DIR="${0:A:h}" + +rosmaster() { + + [ $# -eq 0 ] && \ + echo "$ROS_MASTER_URI" | sed 's/http:\/\/\([^:]\+\):11311/\1/' && return 0 + + local master_ip_tag='master_ip' + local masters="$(_omz_ros_config_get_line $master_ip_tag)" + local finded="" + + [ $# -eq 2 ] && finded=$(echo "$masters" | grep -o "$2") + + case "$1" in + list) + [ $# -ne 1 ] && >&2 echo "Usage : $0 list" && return 1 + echo "$masters" | sed 's/[[:space:]]\+/\n/g' | nl + ;; + + add) + [ $# -ne 2 ] && >&2 echo "Usage : $0 add " && return 1 + [ "$finded" ] && >&2 echo "Master IP $2 is already registered" && return 3 + _omz_ros_config_add_to_line "$master_ip_tag" "$2" + ;; + + remove) + [ $# -ne 2 ] && \ + >&2 echo "Usage : $0 remove " && + return 1 + [ -z "$finded" ] && >&2 echo "Master IP $2 is not registered" && return 3 + _omz_ros_config_remove_from_line "$master_ip_tag" "$2" + ;; + + default) + local master_ip_default_tag='master_ip_default' + [ $# -ne 2 ] && >&2 echo "Usage : $0 default " && return 1 + [ ! "$finded" ] && _omz_ros_config_add_to_line "$master_ip_default_tag" "$2" + _omz_ros_config_set_line "$master_ip_default_tag" "$2" + ;; + + set) + if [ $# -eq 3 ]; then + rosinterface set "$3" && \ + export ROS_MASTER_URI="http://$2:11311" || return "$?" + elif [ $# -eq 2 ]; then + export ROS_MASTER_URI="http://$2:11311" + else + >&2 echo "Usage : $0 set " && return 1 + fi + ;; + + autoset) + [ $# -ne 1 ] && >&2 echo "Usage : $0 autoset" && return 1 + local master_ip_default=$(_omz_ros_config_get_line 'master_ip_default') + rosmaster set "$master_ip_default" + ;; + + *) + >&2 echo "Usage : $0 [option]" && return 1 + ;; + esac + + return 0 +} + +rosinterface() { + + [ $# -eq 0 ] && echo "$ROS_IP" && return 0 + + local ros_interface_tag='ros_interface' + local ros_interfaces="$(_omz_ros_config_get_line $ros_interface_tag)" + local finded="" + + [ $# -eq 2 ] && finded=$(echo "$ros_interfaces" | grep -o "$2") + + case "$1" in + list) + [ $# -ne 1 ] && >&2 echo "Usage : $0 list" && return 1 + echo "$ros_interfaces" | sed 's/[[:space:]]\+/\n/g' | nl + ;; + + add) + [ $# -ne 2 ] && >&2 echo "Usage : $0 add " && return 1 + local exist=$(_omz_ros_interface_get_list | grep -o "$2") + [ ! "$exist" ] && >&2 echo "Interface $2 does not exist" && return 3 + [ "$finded" ] && >&2 echo "Interface $2 is already registered" && return 3 + _omz_ros_config_add_to_line "$ros_interface_tag" "$2" + ;; + + remove) + [ $# -ne 2 ] && \ + >&2 echo "Usage : $0 remove " && \ + return 1 + [ ! "$finded" ] && >&2 echo "Interface $2 is not registered" && return 3 + _omz_ros_config_remove_from_line "$ros_interface_tag" "$2" + ;; + + up) + [ $# -ne 2 ] && >&2 echo "Usage : $0 up " && \ + return 1 + [ ! "$finded" ] && >&2 echo "Interface $2 is not registered" && return 3 + _omz_ros_config_up "$ros_interface_tag" "$2" + ;; + + down) + [ $# -ne 2 ] && >&2 echo "Usage : $0 down " && \ + return 1 + [ ! "$finded" ] && >&2 echo "Interface $2 is not registered" && return 3 + _omz_ros_config_down "$ros_interface_tag" "$2" + ;; + + set) + [ $# -ne 2 ] && >&2 echo "Usage : $0 set " && return 1 + local available=$(_omz_ros_interface_get_available | grep -o "$2") + [ ! "$available" ] && >&2 echo "Interface $2 is not available" && return 3 + export ROS_IP=$(_omz_ros_interface_to_ip "$2") + ;; + + autoset) + [ $# -ne 1 ] && >&2 echo "Usage : $0 autoset" && return 1 + local ros_interfaces_candidate="$(echo "$ros_interfaces" | + grep -E "$(_omz_ros_interface_get_available | tr ' ' '|')")" + local ros_interface="" + for ros_interface in $(echo "$ros_interfaces_candidate"); do + local ip=$(_omz_ros_interface_to_ip "$ros_interface") + if [ "$ip" ]; then + export ROS_IP="$ip" + break + fi + done + ;; + + *) + >&2 echo "Usage : $0 [option]" && return 1 + ;; + esac + + return 0 +} + +rosdistro() { + + [ $# -eq 0 ] && \ + echo "$ROS_DISTRO" && return 0 + + case "$1" in + list) + [ $# -ne 1 ] && >&2 echo "Usage : $0 list" && return 1 + _omz_ros_distro_get_list | sed 's/[[:space:]]\+/\n/g' | nl + ;; + + default) + [ $# -ne 2 ] && >&2 echo "Usage : $0 default " && return 1 + local exist=$(_omz_ros_distro_get_list | grep -o "$2") + [ ! "$exist" ] && >&2 echo "Distro $2 is not available" && return 3 + _omz_ros_config_set_line "ros_distro_default" "$2" + ;; + + set) + [ $# -ne 2 ] && >&2 echo "Usage : $0 set " && return 1 + local exist=$(_omz_ros_distro_get_list | grep -o "$2") + [ ! "$exist" ] && >&2 echo "Distro $2 is not available" && return 3 + source "/opt/ros/$2/setup.zsh" + rosworkspace source + ;; + + autoset) + [ $# -ne 1 ] && >&2 echo "Usage : $0 autoset" && return 1 + local ros_distro_default=$(_omz_ros_config_get_line 'ros_distro_default') + [ ! "$ros_distro_default" ] && >&2 echo "Default distro not set" && \ + return 3 + rosdistro set "$ros_distro_default" + ;; + + *) + >&2 echo "Usage : $0 [option]" && return 1 + ;; + esac + + return 0 +} + +rosworkspace() { + + local workspace_tag='ros_workspace' + local ros_workspaces="$(_omz_ros_config_get_line $workspace_tag)" + local finded="" + + [ $# -eq 2 ] && finded=$(echo "$ros_workspaces" | grep -o "$2") + + case "$1" in + list) + [ $# -ne 1 ] && >&2 echo "Usage : $0 list" && return 1 + _omz_ros_workspace_get_list | sed 's/[[:space:]]\+/\n/g' | nl + ;; + + add) + [ $# -ne 2 ] && >&2 echo "Usage : $0 add " && return 1 + [ ! -f "$2/.catkin_workspace" ] && \ + >&2 echo "Workspace $2 does not exist" && return 3 + [ "$finded" ] && >&2 echo "Workspace $2 is already registered" && return 3 + local sed_path=$(echo "$2" | sed 's/\//\\\//g') + _omz_ros_config_add_to_line "$workspace_tag" "$sed_path" + rosworkspace source + ;; + + remove) + [ $# -ne 2 ] && \ + >&2 echo "Usage : $0 remove " && \ + return 1 + [ ! "$finded" ] && >&2 echo "Workspace $2 is not registered" && return 3 + local sed_path=$(echo "$2" | sed 's/\//\\\//g') + _omz_ros_config_remove_from_line "$workspace_tag" "$sed_path" + ;; + + source) + [ $# -ne 1 ] && >&2 echo "Usage : $0 source" && return 1 + local ros_workspace="" + for ros_workspace in $(echo "$ros_workspaces"); do + source "$ros_workspace/devel/setup.zsh" || return "$?" + done + ;; + + *) + >&2 echo "Usage : $0 [option]" && return 1 + ;; + esac + + return 0 +} + +_omz_ros_config_init() { + [ ! -d "$ZSH_CACHE_DIR" ] && mkdir -p "$ZSH_CACHE_DIR" + if [ ! -f "$ZSH_CACHE_DIR/ros.cache" ]; then + cp "$_OMZ_ROS_DIR/ros.cache.default" "$ZSH_CACHE_DIR/ros.cache" || \ + return "$?" + [ ! "$(_omz_ros_config_get_line 'ros_distro_default')" ] && \ + _omz_ros_config_set_line 'ros_distro_default' \ + $(_omz_ros_distro_get_list | tail -n 1) || return "$?" + fi + + return 0 +} + +_omz_ros_config_get_line() { + cat "$ZSH_CACHE_DIR/ros.cache" | + grep "^[[:space:]]*$1[[:space:]]*=" | sed 's/.*=[[:space:]]*\(.*\)/\1/' +} + +_omz_ros_config_set_line() { + _omz_ros_config_do "$1" '=.*$' "= $2" +} + +_omz_ros_config_up() { + _omz_ros_config_do "$1" "\([^[:space:]=]\+\)[[:space:]]\+$2" "$2 \1" +} + +_omz_ros_config_down() { + _omz_ros_config_do "$1" "$2[[:space:]]\+\([^[:space:]]*\)" "\1 $2" +} + +_omz_ros_config_add_to_line() { + _omz_ros_config_do "$1" '[[:space:]]*$' " $2" +} + +_omz_ros_config_remove_from_line() { + _omz_ros_config_do "$1" "[[:space:]]*$2[[:space:]]*" ' ' +} + +_omz_ros_config_do() { + local line_exist="$(cat "$ZSH_CACHE_DIR/ros.cache" | + grep "^[[:space:]]*$1[[:space:]]*=" )" + [ ! "$line_exist" ] && echo "$1 =" >> "$ZSH_CACHE_DIR/ros.cache" + sed -i "/^[[:space:]]*$1[[:space:]]*=/s/$2/$3/" \ + "$ZSH_CACHE_DIR/ros.cache" +} + +_omz_ros_workspace_get_list() { + echo "$ROS_PACKAGE_PATH" | tr ':' '\n' | grep -v '/opt/ros' | + sed 's/\/src$//' | paste -sd ' ' +} + +_omz_ros_interface_get_list() { + ip link show | grep -E '^[0-9]+: ' | sed 's/ //g' | cut -d ':' -f 2 | + paste -sd ' ' +} + +_omz_ros_interface_get_available() { + ifconfig | grep -oE "^[[:alnum:]]+" | paste -sd ' ' +} + +_omz_ros_interface_to_ip() { + ifconfig | sed '/./{H;$!d};x;/'"$1"'/!d' | grep -o 'inet addr:[0-9.]\+' | + cut -d ':' -f 2 +} + +_omz_ros_distro_get_list() { + ls -l '/opt/ros' | grep '^d' | tr -s ' ' | cut --complement -d ' ' -f 1-8 | + paste -sd ' ' +} + +ros_prompt_info() { + local ros_status="" + local master_ip=$(rosmaster) + if [ "$master_ip" ]; then + ros_status+="$ZSH_THEME_ROS_PROMPT_PREFIX%{$fg_no_bold[white]%}" + curl -m 0.1 -s -o /dev/null \ + --request POST "$ROS_MASTER_URI/RPC2" --data " + getUri + " + case "$?" in + 0) + # master up and responding + [ "$(rosparam get use_sim_time 2>&1 | grep "true")" ] && \ + ros_status+="$ZSH_THEME_ROS_PROMPT_USE_SIM_TIME%{$fg_no_bold[white]%}" + ros_status+="$ZSH_THEME_ROS_PROMPT_MASTER_UP" + ;; + 7) + # master down and machine responding + ros_status+="$ZSH_THEME_ROS_PROMPT_MASTER_DOWN" + ;; + 6|28) + # Could not resolve host + # Connection timeout + ros_status+="$ZSH_THEME_ROS_PROMPT_MASTER_OUT" + ;; + *) + # Unexpected + ros_status+="$ZSH_THEME_ROS_PROMPT_MASTER_OUT" + ;; + esac + ros_status+="$master_ip%{$fg_no_bold[white]%}" + ros_status+="$ZSH_THEME_ROS_PROMPT_SUFFIX%{$fg_no_bold[white]%}" + fi + echo "$ros_status" + return 0 +} + +_omz_ros_config_init + +[ ! "$ROS_IP" ] && rosinterface autoset +[ ! "$ROS_MASTER_URI" ] && rosmaster autoset +[ ! "$ROS_DISTRO" ] && rosdistro autoset || rosworkspace source + +# Default values for the appearance of the prompt. +if [ "$(fc-list | grep 'FontAwesome')" ]; then + ZSH_THEME_ROS_PROMPT_PREFIX="%{$fg[blue]%} %{$fg_bold[blue]%}(" + ZSH_THEME_ROS_PROMPT_USE_SIM_TIME="%{$fg_bold[yellow]%} " +else + ZSH_THEME_ROS_PROMPT_PREFIX="%{$fg_bold[blue]%}ros:(" + ZSH_THEME_ROS_PROMPT_USE_SIM_TIME="%{$fg[yellow]%}⌚ " +fi + +ZSH_THEME_ROS_PROMPT_SUFFIX="%{$fg_bold[blue]%})" +ZSH_THEME_ROS_PROMPT_MASTER_UP="%{$fg_bold[green]%}" +ZSH_THEME_ROS_PROMPT_MASTER_DOWN="%{$fg_bold[red]%}" +ZSH_THEME_ROS_PROMPT_MASTER_OUT="%{$fg_bold[magenta]%}" +