Files
go2_navigation_provincial/go2_autonomous_navigation/scripts/go2_env.sh

277 lines
8.0 KiB
Bash

#!/usr/bin/env bash
# Shared environment bootstrap for the open-source go2-nav2-amcl workspace.
# Source this from scripts that need ROS 2 + Unitree DDS + this workspace.
_go2_os_fail() {
printf '[go2_env] ERROR: %s\n' "$*" >&2
return 1 2>/dev/null || exit 1
}
_go2_os_script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export GO2_REPO_ROOT="$(cd "${_go2_os_script_dir}/.." && pwd)"
if [[ -n "${1:-}" ]]; then
GO2_OS_ROLE="$1"
fi
_go2_os_restore_nounset=0
case "$-" in
*u*)
_go2_os_restore_nounset=1
set +u
;;
esac
_go2_runtime_env="${GO2_OS_RUNTIME_ENV:-${GO2_REPO_ROOT}/scripts/go2_runtime.env}"
if [[ -f "${_go2_runtime_env}" ]]; then
# shellcheck disable=SC1090
source "${_go2_runtime_env}"
fi
_go2_os_filter_old_go2_path_var() {
local var_name="$1"
local raw_value="${!var_name:-}"
local filtered=""
local part
[[ -n "${raw_value}" ]] || return 0
IFS=':' read -r -a _go2_os_path_parts <<< "${raw_value}"
for part in "${_go2_os_path_parts[@]}"; do
[[ -n "${part}" ]] || continue
if [[ "${part}" == *"/GO2/"* || "${part}" == *"/GO2" ]]; then
continue
fi
if [[ -z "${filtered}" ]]; then
filtered="${part}"
else
filtered="${filtered}:${part}"
fi
done
printf -v "${var_name}" '%s' "${filtered}"
export "${var_name}"
}
_go2_os_cyclonedds_uri() {
local iface="$1"
local peers="${2:-}"
local discovery_xml=""
local peer_xml=""
local peer
peers="${peers//,/ }"
for peer in ${peers}; do
[[ -n "${peer}" ]] || continue
peer_xml="${peer_xml}<Peer Address=\"${peer}\"/>"
done
if [[ -n "${peer_xml}" ]]; then
discovery_xml="<Discovery><Peers>${peer_xml}</Peers></Discovery>"
fi
printf '<CycloneDDS><Domain><General><Interfaces><NetworkInterface name="%s" priority="default" multicast="default" /></Interfaces></General>%s</Domain></CycloneDDS>' "${iface}" "${discovery_xml}"
}
_go2_os_iface_exists() {
local iface="$1"
[[ -n "${iface}" && -d "/sys/class/net/${iface}" ]]
}
_go2_os_iface_operstate() {
local iface="$1"
cat "/sys/class/net/${iface}/operstate" 2>/dev/null || true
}
_go2_os_iface_carrier() {
local iface="$1"
cat "/sys/class/net/${iface}/carrier" 2>/dev/null || true
}
_go2_os_iface_ipv4() {
local iface="$1"
ip -4 -o addr show dev "${iface}" 2>/dev/null | awk '{print $4}' | cut -d/ -f1 | head -n 1
}
_go2_os_iface_ready() {
local iface="$1"
local require_ipv4="${2:-1}"
local state=""
local carrier=""
local ipv4=""
_go2_os_iface_exists "${iface}" || return 1
state="$(_go2_os_iface_operstate "${iface}")"
[[ "${state}" == "up" ]] || return 1
carrier="$(_go2_os_iface_carrier "${iface}")"
if [[ -n "${carrier}" && "${carrier}" != "1" ]]; then
return 1
fi
if [[ "${require_ipv4}" == "1" ]]; then
ipv4="$(_go2_os_iface_ipv4 "${iface}")"
[[ -n "${ipv4}" ]] || return 1
fi
return 0
}
_go2_os_iface_status_text() {
local iface="$1"
if ! _go2_os_iface_exists "${iface}"; then
printf 'missing'
return
fi
local state carrier ipv4
state="$(_go2_os_iface_operstate "${iface}")"
carrier="$(_go2_os_iface_carrier "${iface}")"
ipv4="$(_go2_os_iface_ipv4 "${iface}")"
printf 'state=%s carrier=%s ipv4=%s' "${state:-unknown}" "${carrier:-n/a}" "${ipv4:-none}"
}
_go2_os_role_transport_policy() {
if [[ "${GO2_OS_FORCE_WIRED:-0}" == "1" ]]; then
printf 'wired_required'
return
fi
case "${GO2_OS_ROLE}" in
mapping|map|slam|save_map|teleop|build)
printf 'wired_required'
;;
dashboard|nav|navigation|patrol|inspection)
printf 'wired_required'
;;
*)
printf 'wired_required'
;;
esac
}
_go2_os_select_iface() {
local policy="$1"
local selected_iface=""
local selected_reason=""
local fallback_active=0
case "${policy}" in
wired_required)
if _go2_os_iface_ready "${GO2_WIRED_IFACE}" 1; then
selected_iface="${GO2_WIRED_IFACE}"
selected_reason="wired_required:${GO2_WIRED_IFACE}"
else
GO2_NETWORK_ERROR="wired_required:${GO2_WIRED_IFACE}:$(_go2_os_iface_status_text "${GO2_WIRED_IFACE}")"
export GO2_NETWORK_ERROR
return 1
fi
;;
wireless_preferred)
if _go2_os_iface_ready "${GO2_WIRELESS_IFACE}" 1; then
selected_iface="${GO2_WIRELESS_IFACE}"
selected_reason="wireless_selected:${GO2_WIRELESS_IFACE}"
elif _go2_os_iface_ready "${GO2_WIRED_IFACE}" 1; then
selected_iface="${GO2_WIRED_IFACE}"
selected_reason="wireless_unavailable_using_wired_fallback:${GO2_WIRELESS_IFACE}:${GO2_WIRED_IFACE}"
fallback_active=1
else
GO2_NETWORK_ERROR="robot_ros_network_unavailable:${GO2_WIRELESS_IFACE}:${GO2_WIRED_IFACE}"
export GO2_NETWORK_ERROR
return 1
fi
;;
*)
GO2_NETWORK_ERROR="unknown_network_policy:${policy}"
export GO2_NETWORK_ERROR
return 1
;;
esac
GO2_OS_SELECTED_IFACE="${selected_iface}"
GO2_OS_SELECTED_IFACE_REASON="${selected_reason}"
GO2_OS_FALLBACK_ACTIVE="${fallback_active}"
export GO2_OS_SELECTED_IFACE GO2_OS_SELECTED_IFACE_REASON GO2_OS_FALLBACK_ACTIVE
return 0
}
for _go2_os_path_var in AMENT_PREFIX_PATH CMAKE_PREFIX_PATH COLCON_PREFIX_PATH PYTHONPATH LD_LIBRARY_PATH PATH; do
_go2_os_filter_old_go2_path_var "${_go2_os_path_var}"
done
: "${GO2_OS_ROLE:=generic}"
: "${GO2_WIRED_IFACE:=ens160}"
: "${GO2_WIRELESS_IFACE:=ens192}"
: "${GO2_OS_MAPPING_IFACE:=${GO2_WIRED_IFACE}}"
: "${GO2_OS_NAV_IFACE:=${GO2_WIRED_IFACE}}"
: "${GO2_OS_DASHBOARD_IFACE:=${GO2_WIRED_IFACE}}"
: "${GO2_OS_MAPPING_PEERS:=}"
: "${GO2_OS_NAV_PEERS:=}"
: "${GO2_OS_DASHBOARD_PEERS:=${GO2_OS_NAV_PEERS}}"
: "${GO2_UNITREE_SETUP:=${HOME}/unitree_ros2/cyclonedds_ws/install/setup.bash}"
: "${GO2_OS_MAP_DIR:=${HOME}/go2_maps}"
: "${GO2_OS_MAP_NAME:=competition_map}"
GO2_TRANSPORT_POLICY="$(_go2_os_role_transport_policy)"
export GO2_TRANSPORT_POLICY
unset GO2_NETWORK_ERROR
unset GO2_OS_SELECTED_IFACE
unset GO2_OS_SELECTED_IFACE_REASON
unset GO2_OS_FALLBACK_ACTIVE
if [[ -z "${GO2_ROS_IFACE:-}" ]]; then
_go2_os_select_iface "${GO2_TRANSPORT_POLICY}" || _go2_os_fail "${GO2_NETWORK_ERROR}"
GO2_ROS_IFACE="${GO2_OS_SELECTED_IFACE}"
fi
if [[ -z "${GO2_DDS_PEERS:-}" ]]; then
case "${GO2_OS_ROLE}" in
mapping|map|slam|save_map|teleop|build)
GO2_DDS_PEERS="${GO2_OS_MAPPING_PEERS}"
;;
dashboard)
GO2_DDS_PEERS="${GO2_OS_DASHBOARD_PEERS}"
;;
nav|navigation|patrol|inspection)
GO2_DDS_PEERS="${GO2_OS_NAV_PEERS}"
;;
*)
GO2_DDS_PEERS="${GO2_OS_MAPPING_PEERS}"
;;
esac
fi
[[ -f /opt/ros/humble/setup.bash ]] || _go2_os_fail "missing /opt/ros/humble/setup.bash"
[[ -f "${GO2_UNITREE_SETUP}" ]] || _go2_os_fail "missing Unitree setup: ${GO2_UNITREE_SETUP}"
[[ -d "/sys/class/net/${GO2_ROS_IFACE}" ]] || _go2_os_fail "network interface not found: ${GO2_ROS_IFACE}"
_go2_os_iface_state="$(_go2_os_iface_operstate "${GO2_ROS_IFACE}")"
if [[ "${_go2_os_iface_state}" != "up" && "${GO2_ALLOW_IFACE_DOWN:-0}" != "1" ]]; then
_go2_os_fail "network interface ${GO2_ROS_IFACE} is ${_go2_os_iface_state:-unknown}; connect the Go2 network first"
fi
# shellcheck disable=SC1091
source /opt/ros/humble/setup.bash
# shellcheck disable=SC1090
source "${GO2_UNITREE_SETUP}"
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
export CYCLONEDDS_URI="$(_go2_os_cyclonedds_uri "${GO2_ROS_IFACE}" "${GO2_DDS_PEERS}")"
export GO2_OS_ROLE
export GO2_WIRED_IFACE
export GO2_WIRELESS_IFACE
export GO2_OS_MAPPING_IFACE
export GO2_OS_NAV_IFACE
export GO2_OS_DASHBOARD_IFACE
export GO2_OS_MAPPING_PEERS
export GO2_OS_NAV_PEERS
export GO2_OS_DASHBOARD_PEERS
export GO2_DDS_PEERS
export GO2_ROS_IFACE
export GO2_OS_MAP_DIR
export GO2_OS_MAP_NAME
if [[ "${GO2_OS_SKIP_WORKSPACE_SETUP:-0}" != "1" && -f "${GO2_REPO_ROOT}/install/setup.bash" ]]; then
# shellcheck disable=SC1091
source "${GO2_REPO_ROOT}/install/setup.bash"
fi
if [[ "${_go2_os_restore_nounset}" == "1" ]]; then
set -u
fi
unset _go2_os_script_dir _go2_runtime_env _go2_os_iface_state _go2_os_restore_nounset
unset _go2_os_path_var _go2_os_path_parts
unset -f _go2_os_filter_old_go2_path_var
unset -f _go2_os_cyclonedds_uri