diff --git a/.env b/.env index 77ed88ef4..bdd6f251e 100644 --- a/.env +++ b/.env @@ -12,7 +12,7 @@ PROJECT_NAME="airstack" # If you've run ./airstack.sh setup, then this will auto-generate from the git commit hash every time a change is made # to a Dockerfile or docker-compose.yaml file. Otherwise this can also be set explicitly to make a release version. # auto-generated from git commit hash -VERSION="0.19.0-alpha.5" +VERSION="0.19.0-alpha.6" # Choose "dev" or "prebuilt". "dev" is for mounted code that must be built live. "prebuilt" is for built ros_ws baked into the image DOCKER_IMAGE_BUILD_MODE="dev" # Where to push and pull images from. Can replace with your docker hub username if using docker hub. diff --git a/CHANGELOG.md b/CHANGELOG.md index a87adb205..747f670b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Battery and telemetry display in GCS RQT control panel (voltage and percentage per robot when MAVROS battery topic is bridged) +- `TARGET_ARCH` build arg (default `x86_64`) in `Dockerfile.robot` to arch-parametrize `LD_LIBRARY_PATH`; `docker-compose.yaml` passes `TARGET_ARCH: aarch64` to the `voxl` and `l4t` real-robot image builds +- `ros-${ROS_DISTRO}-mavros-extras` in the robot image (provides the vision_pose plugin used for external-pose deployments) + +### Fixed + +- Robot name resolution now honors a pre-set `ROBOT_NAME` (e.g. injected via docker compose) instead of always overriding it from the container/hostname mapping (`robot/docker/.bashrc`) +- Robot name-map catch-all fallback now maps to `unknown_robot` (valid ROS namespace token) instead of `unknown-robot` (`default_robot_name_map.yaml`) ## [1.0.0] - 2024-12-19 diff --git a/robot/docker/.bashrc b/robot/docker/.bashrc index d2c3c877d..b3903a144 100755 --- a/robot/docker/.bashrc +++ b/robot/docker/.bashrc @@ -69,35 +69,39 @@ function cws(){ source /opt/ros/jazzy/setup.bash sws # source the ROS2 workspace by default -# Only extract robot name and ROS domain ID iff they are not already set in the environment (e.g. by docker compose) -if [ "$ROBOT_NAME_SOURCE" == "container_name" ]; then - # https://wiki.psuter.ch/doku.php?id=get_docker_container_name_from_within_the_container - # WARNING: this technique ONLY works with docker version 29 and up. - name_to_map=$(host $(host $(hostname) | awk '{print $NF}') | awk '{print $NF}' | awk -F . '{print $1}') - CONTAINER_NAME=":$name_to_map" -elif [ "$ROBOT_NAME_SOURCE" == "hostname" ]; then - name_to_map=$(hostname) -else - echo "Warning: ROBOT_NAME_SOURCE=$ROBOT_NAME_SOURCE not set to a valid value. Defaulting to 'unknown_robot'." - name_to_map="" - export ROBOT_NAME="unknown_robot" - export ROS_DOMAIN_ID=0 -fi -# set ROBOT_NAME and ROS_DOMAIN_ID from the mapping script if NAME_TO_MAP is not empty -if [ -n "$name_to_map" ]; then - script_path="$HOME/AirStack/robot/docker/robot_name_map/resolve_robot_name.py" - script_dir=$(dirname "$script_path") +# If ROBOT_NAME is pre-set (e.g. via docker compose), keep it. +# Otherwise extract robot name and ROS domain ID from the container/hostname mapping. +if [ -z "${ROBOT_NAME:-}" ]; then + if [ "$ROBOT_NAME_SOURCE" == "container_name" ]; then + # https://wiki.psuter.ch/doku.php?id=get_docker_container_name_from_within_the_container + # WARNING: this technique ONLY works with docker version 29 and up. + name_to_map=$(host $(host $(hostname) | awk '{print $NF}') | awk '{print $NF}' | awk -F . '{print $1}') + CONTAINER_NAME=":$name_to_map" + elif [ "$ROBOT_NAME_SOURCE" == "hostname" ]; then + name_to_map=$(hostname) + else + echo "Warning: ROBOT_NAME_SOURCE=$ROBOT_NAME_SOURCE not set to a valid value. Defaulting to 'unknown_robot'." + name_to_map="" + export ROBOT_NAME="unknown_robot" + export ROS_DOMAIN_ID=0 + fi - existing_robot_domain_id=${ROS_DOMAIN_ID:-} + # set ROBOT_NAME and ROS_DOMAIN_ID from the mapping script if NAME_TO_MAP is not empty + if [ -n "$name_to_map" ]; then + script_path="$HOME/AirStack/robot/docker/robot_name_map/resolve_robot_name.py" + script_dir=$(dirname "$script_path") - eval "$($script_path $name_to_map $script_dir/$ROBOT_NAME_MAP_CONFIG_FILE)" - export ROBOT_NAME + existing_robot_domain_id=${ROS_DOMAIN_ID:-} - # if ROS_DOMAIN_ID was already set in the environment, use that instead of the mapped value - if [ -z "$existing_robot_domain_id" ]; then - export ROS_DOMAIN_ID - else - export ROS_DOMAIN_ID=$existing_robot_domain_id + eval "$($script_path $name_to_map $script_dir/$ROBOT_NAME_MAP_CONFIG_FILE)" + export ROBOT_NAME + + # if ROS_DOMAIN_ID was already set in the environment, use that instead of the mapped value + if [ -z "$existing_robot_domain_id" ]; then + export ROS_DOMAIN_ID + else + export ROS_DOMAIN_ID=$existing_robot_domain_id + fi fi fi diff --git a/robot/docker/Dockerfile.robot b/robot/docker/Dockerfile.robot index 894874961..92fd116fe 100644 --- a/robot/docker/Dockerfile.robot +++ b/robot/docker/Dockerfile.robot @@ -12,6 +12,7 @@ ARG UPDATE_FLAGS="-o Acquire::AllowInsecureRepositories=true -o Acquire::AllowDo ARG INSTALL_FLAGS="-o APT::Get::AllowUnauthenticated=true" ARG SKIP_MACVO=false ARG SKIP_TENSORRT=false +ARG TARGET_ARCH=x86_64 ARG PIP_VERSION=24.0 ARG PYTHON_VERSION=3.12 @@ -65,7 +66,7 @@ RUN sudo add-apt-repository universe \ ENV AMENT_PREFIX_PATH=/opt/ros/${ROS_DISTRO} ENV COLCON_PREFIX_PATH=/opt/ros/${ROS_DISTRO} -ENV LD_LIBRARY_PATH=/opt/ros/${ROS_DISTRO}/lib/x86_64-linux-gnu:/opt/ros/${ROS_DISTRO}/lib +ENV LD_LIBRARY_PATH=/opt/ros/${ROS_DISTRO}/lib/${TARGET_ARCH}-linux-gnu:/opt/ros/${ROS_DISTRO}/lib ENV PATH=/opt/ros/${ROS_DISTRO}/bin:$PATH ENV PYTHONPATH=/opt/ros/${ROS_DISTRO}/local/lib/python${PYTHON_VERSION}/dist-packages:/opt/ros/${ROS_DISTRO}/lib/python${PYTHON_VERSION}/site-packages ENV ROS_PYTHON_VERSION=3 @@ -96,6 +97,7 @@ RUN python3 -m pip install --no-cache-dir --break-system-packages --ignore-insta RUN apt update -y && apt install -y --no-install-recommends \ ros-dev-tools \ ros-${ROS_DISTRO}-mavros \ + ros-${ROS_DISTRO}-mavros-extras \ ros-${ROS_DISTRO}-tf2* \ ros-${ROS_DISTRO}-stereo-image-proc \ ros-${ROS_DISTRO}-image-view \ @@ -245,6 +247,7 @@ ARG UPDATE_FLAGS="-o Acquire::AllowInsecureRepositories=true -o Acquire::AllowDo ARG INSTALL_FLAGS="-o APT::Get::AllowUnauthenticated=true" ARG SKIP_MACVO=false ARG SKIP_TENSORRT=false +ARG TARGET_ARCH=x86_64 ARG PIP_VERSION=24.0 ARG PYTHON_VERSION=3.12 @@ -297,7 +300,7 @@ RUN sudo add-apt-repository universe \ ENV AMENT_PREFIX_PATH=/opt/ros/${ROS_DISTRO} ENV COLCON_PREFIX_PATH=/opt/ros/${ROS_DISTRO} -ENV LD_LIBRARY_PATH=/opt/ros/${ROS_DISTRO}/lib/x86_64-linux-gnu:/opt/ros/${ROS_DISTRO}/lib +ENV LD_LIBRARY_PATH=/opt/ros/${ROS_DISTRO}/lib/${TARGET_ARCH}-linux-gnu:/opt/ros/${ROS_DISTRO}/lib ENV PATH=/opt/ros/${ROS_DISTRO}/bin:$PATH ENV PYTHONPATH=/opt/ros/${ROS_DISTRO}/local/lib/python${PYTHON_VERSION}/dist-packages:/opt/ros/${ROS_DISTRO}/lib/python${PYTHON_VERSION}/site-packages ENV ROS_PYTHON_VERSION=3 @@ -328,6 +331,7 @@ RUN python3 -m pip install --no-cache-dir --break-system-packages --ignore-insta RUN apt update -y && apt install -y --no-install-recommends \ ros-dev-tools \ ros-${ROS_DISTRO}-mavros \ + ros-${ROS_DISTRO}-mavros-extras \ ros-${ROS_DISTRO}-tf2* \ ros-${ROS_DISTRO}-stereo-image-proc \ ros-${ROS_DISTRO}-image-view \ diff --git a/robot/docker/docker-compose.yaml b/robot/docker/docker-compose.yaml index f1799f48d..71b71e425 100644 --- a/robot/docker/docker-compose.yaml +++ b/robot/docker/docker-compose.yaml @@ -122,6 +122,7 @@ services: REAL_ROBOT: true SKIP_MACVO: true SKIP_TENSORRT: true + TARGET_ARCH: aarch64 ROS_DISTRO: jazzy tags: - *voxl_image @@ -179,6 +180,7 @@ services: REAL_ROBOT: true SKIP_MACVO: true SKIP_TENSORRT: true + TARGET_ARCH: aarch64 ROS_DISTRO: jazzy tags: - *l4t_image diff --git a/robot/docker/robot_name_map/default_robot_name_map.yaml b/robot/docker/robot_name_map/default_robot_name_map.yaml index d01cda199..5d638b6ed 100644 --- a/robot/docker/robot_name_map/default_robot_name_map.yaml +++ b/robot/docker/robot_name_map/default_robot_name_map.yaml @@ -12,5 +12,5 @@ mappings: # catch all fall-back - pattern: '.*' - robot: 'unknown-robot' + robot: 'unknown_robot' domain_id: '0' \ No newline at end of file