From 64bbfab5d7892ae52b74118e7f8de4172fe077fb Mon Sep 17 00:00:00 2001 From: Bona Date: Thu, 15 Jan 2026 17:24:47 -0800 Subject: [PATCH 01/16] verified working foxglove bridge, docker build and run start.sh --hardware --- docker/navigation/Dockerfile | 8 +- docker/navigation/Overwatch.json | 270 +++++++++++++++++++++++++++ docker/navigation/docker-compose.yml | 34 +++- docker/navigation/start.sh | 34 +++- 4 files changed, 333 insertions(+), 13 deletions(-) create mode 100644 docker/navigation/Overwatch.json diff --git a/docker/navigation/Dockerfile b/docker/navigation/Dockerfile index 69378ea7c7..0ec92255f8 100644 --- a/docker/navigation/Dockerfile +++ b/docker/navigation/Dockerfile @@ -11,6 +11,7 @@ ENV DIMOS_PATH=/workspace/dimos RUN apt-get update && apt-get install -y \ # ROS packages ros-jazzy-pcl-ros \ + ros-jazzy-foxglove-bridge \ # Development tools git \ git-lfs \ @@ -118,7 +119,7 @@ RUN echo "source /opt/dimos-venv/bin/activate" >> ~/.bashrc WORKDIR ${DIMOS_PATH} RUN /bin/bash -c "source /opt/dimos-venv/bin/activate && \ pip install --upgrade pip setuptools wheel && \ - pip install -e .[cpu,dev] 'mmengine>=0.10.3' 'mmcv>=2.1.0'" + pip install -e .[cpu,dev,agents] 'mmengine>=0.10.3' 'mmcv>=2.1.0' rerun-sdk" # Copy helper scripts COPY docker/navigation/run_both.sh /usr/local/bin/run_both.sh @@ -157,9 +158,8 @@ if [ "${HARDWARE_MODE}" = "true" ]; then\n\ if [ -n "${LIDAR_INTERFACE}" ] && [ -n "${LIDAR_COMPUTER_IP}" ]; then\n\ ip addr add ${LIDAR_COMPUTER_IP}/24 dev ${LIDAR_INTERFACE} 2>/dev/null || true\n\ ip link set ${LIDAR_INTERFACE} up 2>/dev/null || true\n\ - if [ -n "${LIDAR_GATEWAY}" ]; then\n\ - ip route add default via ${LIDAR_GATEWAY} dev ${LIDAR_INTERFACE} 2>/dev/null || true\n\ - fi\n\ + # Note: Do NOT add default route via LIDAR_GATEWAY as it would override internet access\n\ + # The /24 subnet route is automatically added when we assign the IP address\n\ fi\n\ \n\ # Generate MID360_config.json if LIDAR_COMPUTER_IP and LIDAR_IP are set\n\ diff --git a/docker/navigation/Overwatch.json b/docker/navigation/Overwatch.json new file mode 100644 index 0000000000..1057d8889b --- /dev/null +++ b/docker/navigation/Overwatch.json @@ -0,0 +1,270 @@ +{ + "configById": { + "3D!main": { + "cameraState": { + "perspective": true, + "distance": 20, + "phi": 60, + "thetaOffset": 45, + "targetOffset": [0, 0, 0], + "target": [0, 0, 0], + "targetOrientation": [0, 0, 0, 1], + "fovy": 45, + "near": 0.01, + "far": 5000 + }, + "followMode": "follow-pose", + "followTf": "vehicle", + "scene": { + "backgroundColor": "#000000", + "enableStats": false, + "syncCamera": false + }, + "transforms": { + "frame:vehicle": { + "visible": true + }, + "frame:map": { + "visible": true + } + }, + "topics": { + "/registered_scan": { + "visible": true, + "colorField": "intensity", + "colorMode": "flat", + "flatColor": "#ffffff", + "pointSize": 2, + "decayTime": 5 + }, + "/overall_map": { + "visible": true, + "colorField": "intensity", + "colorMode": "flat", + "flatColor": "#ffffff", + "pointSize": 2, + "decayTime": 0 + }, + "/free_paths": { + "visible": true, + "colorField": "intensity", + "colorMode": "colormap", + "colorMap": "turbo", + "pointSize": 2 + }, + "/path": { + "visible": true, + "type": "line", + "lineWidth": 0.05, + "color": "#19ff00" + }, + "/way_point": { + "visible": true, + "color": "#cc29cc" + }, + "/navigation_boundary": { + "visible": true, + "color": "#00ff00", + "lineWidth": 0.05 + }, + "/goal_pose": { + "visible": true, + "color": "#ff1900", + "type": "arrow" + }, + "/terrain_map": { + "visible": false, + "colorField": "intensity", + "colorMode": "colormap", + "colorMap": "rainbow", + "pointSize": 4 + }, + "/terrain_map_ext": { + "visible": false, + "colorField": "intensity", + "colorMode": "colormap", + "colorMap": "rainbow", + "pointSize": 4 + }, + "/sensor_scan": { + "visible": false, + "colorField": "intensity", + "colorMode": "flat", + "flatColor": "#ffffff", + "pointSize": 2 + }, + "/added_obstacles": { + "visible": false, + "colorField": "intensity", + "colorMode": "flat", + "flatColor": "#ff1900", + "pointSize": 3 + }, + "/explored_areas": { + "visible": false, + "colorField": "intensity", + "colorMode": "flat", + "flatColor": "#00aaff", + "pointSize": 2 + }, + "/trajectory": { + "visible": false, + "colorField": "intensity", + "colorMode": "colormap", + "colorMap": "rainbow", + "pointSize": 7 + } + }, + "layers": { + "grid": { + "layerId": "foxglove.Grid", + "visible": true, + "frameLocked": true, + "label": "Grid", + "position": [0, 0, 0], + "rotation": [0, 0, 0], + "color": "#248f24", + "size": 100, + "divisions": 100, + "lineWidth": 1, + "frameId": "map" + } + }, + "publish": { + "type": "point", + "poseTopic": "/goal_pose", + "pointTopic": "/way_point", + "poseEstimateTopic": "/initialpose", + "poseEstimateXDeviation": 0.5, + "poseEstimateYDeviation": 0.5, + "poseEstimateThetaDeviation": 0.26179939 + } + }, + "Image!camera": { + "cameraTopic": "/camera/image", + "enabledMarkerTopics": [], + "synchronize": false, + "transformMarkers": true, + "smooth": false, + "flipHorizontal": false, + "flipVertical": false, + "minValue": 0, + "maxValue": 1, + "rotation": 0 + }, + "Image!semantic": { + "cameraTopic": "/camera/semantic_image", + "enabledMarkerTopics": [], + "synchronize": false, + "transformMarkers": true, + "smooth": false, + "flipHorizontal": false, + "flipVertical": false, + "minValue": 0, + "maxValue": 1, + "rotation": 0 + }, + "Teleop!teleop": { + "topic": "/cmd_vel", + "publishRate": 10, + "upButton": { "field": "linear.x", "value": 0.5 }, + "downButton": { "field": "linear.x", "value": -0.5 }, + "leftButton": { "field": "angular.z", "value": 0.5 }, + "rightButton": { "field": "angular.z", "value": -0.5 } + }, + "RawMessages!odom": { + "diffEnabled": false, + "diffMethod": "custom", + "diffTopicPath": "", + "showFullMessageForDiff": false, + "topicPath": "/state_estimation.pose.pose" + }, + "RawMessages!cmdvel": { + "diffEnabled": false, + "diffMethod": "custom", + "diffTopicPath": "", + "showFullMessageForDiff": false, + "topicPath": "/cmd_vel.twist" + }, + "Plot!speed": { + "paths": [ + { "value": "/cmd_vel.twist.linear.x", "enabled": true, "timestampMethod": "receiveTime", "label": "Linear X" }, + { "value": "/cmd_vel.twist.linear.y", "enabled": true, "timestampMethod": "receiveTime", "label": "Linear Y" }, + { "value": "/cmd_vel.twist.angular.z", "enabled": true, "timestampMethod": "receiveTime", "label": "Angular Z" } + ], + "showXAxisLabels": true, + "showYAxisLabels": true, + "showLegend": true, + "legendDisplay": "floating", + "showPlotValuesInLegend": true, + "isSynced": true, + "xAxisVal": "timestamp", + "sidebarDimension": 240, + "minYValue": -2, + "maxYValue": 2, + "followingViewWidth": 30 + }, + "Indicator!goalreached": { + "path": "/goal_reached.data", + "style": "background", + "fallbackColor": "#a0a0a0", + "fallbackLabel": "No Data", + "rules": [ + { "operator": "=", "rawValue": "true", "color": "#68e24a", "label": "Goal Reached" }, + { "operator": "=", "rawValue": "false", "color": "#f5f5f5", "label": "Navigating" } + ] + }, + "Indicator!stop": { + "path": "/stop.data", + "style": "background", + "fallbackColor": "#a0a0a0", + "fallbackLabel": "No Data", + "rules": [ + { "operator": "=", "rawValue": "0", "color": "#68e24a", "label": "OK" }, + { "operator": "=", "rawValue": "1", "color": "#f5ba42", "label": "Speed Stop" }, + { "operator": "=", "rawValue": "2", "color": "#eb4034", "label": "Full Stop" } + ] + } + }, + "globalVariables": {}, + "userNodes": {}, + "playbackConfig": { + "speed": 1 + }, + "layout": { + "first": { + "first": "3D!main", + "second": { + "first": "Image!camera", + "second": "Image!semantic", + "direction": "column", + "splitPercentage": 50 + }, + "direction": "row", + "splitPercentage": 70 + }, + "second": { + "first": { + "first": "Teleop!teleop", + "second": { + "first": "Indicator!goalreached", + "second": "Indicator!stop", + "direction": "row", + "splitPercentage": 50 + }, + "direction": "row", + "splitPercentage": 40 + }, + "second": { + "first": "RawMessages!cmdvel", + "second": "Plot!speed", + "direction": "row", + "splitPercentage": 30 + }, + "direction": "column", + "splitPercentage": 40 + }, + "direction": "column", + "splitPercentage": 75 + } +} diff --git a/docker/navigation/docker-compose.yml b/docker/navigation/docker-compose.yml index f26b7fbabd..30e464c7d5 100644 --- a/docker/navigation/docker-compose.yml +++ b/docker/navigation/docker-compose.yml @@ -70,6 +70,10 @@ services: container_name: dimos_hardware_container profiles: ["hardware"] + # Load environment from .env file + env_file: + - .env + # Enable interactive terminal stdin_open: true tty: true @@ -83,9 +87,14 @@ services: # Override runtime for GPU support runtime: ${DOCKER_RUNTIME:-runc} + # Add host groups for device access (input for joystick, dialout for serial) + group_add: + - ${INPUT_GID:-995} + - ${DIALOUT_GID:-20} + # Hardware environment variables environment: - - DISPLAY=${DISPLAY} + - DISPLAY=${DISPLAY:-:0} - QT_X11_NO_MITSHM=1 - NVIDIA_VISIBLE_DEVICES=all - NVIDIA_DRIVER_CAPABILITIES=all @@ -120,6 +129,8 @@ services: - ./config:/ros2_ws/config:rw # Hardware-specific volumes - ./logs:/ros2_ws/logs:rw + # Foxglove layout + - ./foxglove_layout.json:/ros2_ws/foxglove_layout.json:ro - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /dev/bus/usb:/dev/bus/usb:rw @@ -127,8 +138,8 @@ services: # Device access for hardware devices: - # Joystick controllers - - /dev/input:/dev/input + # Joystick controller (specific device to avoid permission issues) + - /dev/input/js0:/dev/input/js0 # GPU access - /dev/dri:/dev/dri # Motor controller serial ports @@ -142,8 +153,21 @@ services: # Working directory working_dir: /workspace/dimos - # Command - for hardware, we run bash as the user will launch specific scripts - command: bash + # Command - launch the real robot system with foxglove_bridge + command: + - bash + - -c + - | + echo "Checking joystick..." + ls -la /dev/input/js0 2>/dev/null || echo "Warning: No joystick found at /dev/input/js0" + echo "Starting real robot system..." + cd /ros2_ws + source install/setup.bash + ros2 launch vehicle_simulator system_real_robot.launch & + sleep 2 + echo "Starting Foxglove Bridge on port 8765..." + echo "Connect via Foxglove Studio: ws://$(hostname -I | awk '{print $1}'):8765" + ros2 launch foxglove_bridge foxglove_bridge_launch.xml port:=8765 # Capabilities for hardware operations cap_add: diff --git a/docker/navigation/start.sh b/docker/navigation/start.sh index 4347006957..d842a7a4a1 100755 --- a/docker/navigation/start.sh +++ b/docker/navigation/start.sh @@ -74,7 +74,16 @@ if [ "$MODE" = "hardware" ]; then set -a source .env set +a + fi + + # Auto-detect group IDs for device permissions + echo -e "${GREEN}Detecting device group IDs...${NC}" + export INPUT_GID=$(getent group input | cut -d: -f3 || echo "995") + export DIALOUT_GID=$(getent group dialout | cut -d: -f3 || echo "20") + echo -e " input group GID: ${INPUT_GID}" + echo -e " dialout group GID: ${DIALOUT_GID}" + if [ -f ".env" ]; then # Check for required environment variables if [ -z "$LIDAR_IP" ] || [ "$LIDAR_IP" = "192.168.1.116" ]; then echo -e "${YELLOW}Warning: LIDAR_IP still using default value in .env${NC}" @@ -175,12 +184,24 @@ fi if [ -z "$DISPLAY" ]; then echo -e "${YELLOW}Warning: DISPLAY not set. GUI applications may not work.${NC}" export DISPLAY=:0 +else + echo -e "${GREEN}Using DISPLAY: $DISPLAY${NC}" fi +export DISPLAY # Allow X11 connections from Docker echo -e "${GREEN}Configuring X11 access...${NC}" xhost +local:docker 2>/dev/null || true +# Setup X11 auth for remote/SSH connections +XAUTH=/tmp/.docker.xauth +touch $XAUTH 2>/dev/null || true +if [ -n "$DISPLAY" ]; then + xauth nlist $DISPLAY 2>/dev/null | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge - 2>/dev/null || true + chmod 644 $XAUTH 2>/dev/null || true + echo -e "${GREEN}X11 auth configured for display: $DISPLAY${NC}" +fi + cleanup() { xhost -local:docker 2>/dev/null || true } @@ -210,12 +231,14 @@ fi # Print helpful info before starting echo "" if [ "$MODE" = "hardware" ]; then - echo "Hardware mode - Interactive shell" + echo "Hardware mode - Auto-starting ROS real robot system" + echo "" + echo "The container will automatically run:" + echo " - ROS navigation stack (system_real_robot.launch)" + echo " - RViz visualization" echo "" - echo -e "${GREEN}=================================================${NC}" - echo -e "${GREEN}The container is running. Exec in to run scripts:${NC}" + echo "To enter the container from another terminal:" echo -e " ${YELLOW}docker exec -it ${CONTAINER_NAME} bash${NC}" - echo -e "${GREEN}=================================================${NC}" else echo "Simulation mode - Auto-starting ROS simulation and DimOS" echo "" @@ -227,6 +250,9 @@ else echo " docker exec -it ${CONTAINER_NAME} bash" fi +# Note: DISPLAY is now passed directly via environment variable +# No need to write RUNTIME_DISPLAY to .env for local host running + if [ "$MODE" = "hardware" ]; then docker compose -f docker-compose.yml --profile hardware up else From d515d9d85162fe112afbbb0baf50f6bca30a1eb8 Mon Sep 17 00:00:00 2001 From: Bona Date: Thu, 15 Jan 2026 23:44:36 -0800 Subject: [PATCH 02/16] verified rviz flag work, route planner flag work, and can use joystick to controll robot --- docker/navigation/Dockerfile | 287 ++++++++++++++++++--------- docker/navigation/Overwatch.json | 217 +++++++++++++++++--- docker/navigation/docker-compose.yml | 36 +++- docker/navigation/start.sh | 50 ++++- 4 files changed, 455 insertions(+), 135 deletions(-) diff --git a/docker/navigation/Dockerfile b/docker/navigation/Dockerfile index 0ec92255f8..9b8bbfcfc4 100644 --- a/docker/navigation/Dockerfile +++ b/docker/navigation/Dockerfile @@ -1,154 +1,255 @@ -# Base image with ROS Jazzy desktop full -FROM osrf/ros:jazzy-desktop-full +# ============================================================================= +# OPTIMIZED DOCKERFILE - Multi-stage build for reduced image size +# ============================================================================= +# +# Key optimizations: +# 1. Use ros:jazzy-ros-base instead of desktop-full (~2.5 GB saved) +# 2. Multi-stage build to discard build artifacts +# 3. No Python ML dependencies (~14 GB saved) +# 4. Don't COPY dimos source - it's volume-mounted at runtime (~1.2 GB saved) +# 5. Clean up build directories after compile (~800 MB saved) +# 6. Minimal apt packages with --no-install-recommends +# 7. DDS configuration for optimized ROS 2 communication +# +# ============================================================================= + +# ----------------------------------------------------------------------------- +# STAGE 1: Build Stage - compile all C++ dependencies +# ----------------------------------------------------------------------------- +FROM osrf/ros:jazzy-desktop-full AS builder -# Set environment variables ENV DEBIAN_FRONTEND=noninteractive ENV ROS_DISTRO=jazzy ENV WORKSPACE=/ros2_ws -ENV DIMOS_PATH=/workspace/dimos -# Install system dependencies -RUN apt-get update && apt-get install -y \ - # ROS packages - ros-jazzy-pcl-ros \ - ros-jazzy-foxglove-bridge \ - # Development tools +# Install build dependencies only +RUN apt-get update && apt-get install -y --no-install-recommends \ + # Build tools git \ - git-lfs \ cmake \ build-essential \ python3-colcon-common-extensions \ - # PCL and system libraries + # Libraries needed for building libpcl-dev \ libgoogle-glog-dev \ libgflags-dev \ libatlas-base-dev \ libeigen3-dev \ libsuitesparse-dev \ - # X11 and GUI support for RVIZ - x11-apps \ - xorg \ - openbox \ - # Networking tools - iputils-ping \ - net-tools \ - iproute2 \ - ethtool \ - # USB and serial tools (for hardware support) - usbutils \ - udev \ - # Time synchronization (for multi-computer setup) - chrony \ - # Editor (optional but useful) - nano \ - vim \ - # Python tools - python3-pip \ - python3-setuptools \ - python3-venv \ - # Additional dependencies for dimos - ffmpeg \ - portaudio19-dev \ - libsndfile1 \ - # For OpenCV - libgl1 \ - libglib2.0-0 \ - # For Open3D - libgomp1 \ - # For TurboJPEG - libturbojpeg0-dev \ - # Clean up + # ROS packages needed for build + ros-jazzy-pcl-ros \ && rm -rf /var/lib/apt/lists/* -# Create workspace directory +# Create workspace RUN mkdir -p ${WORKSPACE}/src -# Copy the autonomy stack repository (should be cloned by build.sh) +# Copy autonomy stack source COPY docker/navigation/ros-navigation-autonomy-stack ${WORKSPACE}/src/ros-navigation-autonomy-stack -# Set working directory -WORKDIR ${WORKSPACE} - -# Set up ROS environment -RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> ~/.bashrc - -# Build all hardware dependencies -RUN \ - # Build Livox-SDK2 for Mid-360 lidar - cd ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/utilities/livox_ros_driver2/Livox-SDK2 && \ +# Build Livox-SDK2 +RUN cd ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/utilities/livox_ros_driver2/Livox-SDK2 && \ mkdir -p build && cd build && \ cmake .. && make -j$(nproc) && make install && ldconfig && \ - # Install Sophus - cd ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/dependency/Sophus && \ + rm -rf ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/utilities/livox_ros_driver2/Livox-SDK2/build + +# Build Sophus +RUN cd ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/dependency/Sophus && \ mkdir -p build && cd build && \ cmake .. -DBUILD_TESTS=OFF && make -j$(nproc) && make install && \ - # Install Ceres Solver - cd ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/dependency/ceres-solver && \ + rm -rf ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/dependency/Sophus/build + +# Build Ceres Solver +RUN cd ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/dependency/ceres-solver && \ mkdir -p build && cd build && \ cmake .. && make -j$(nproc) && make install && \ - # Install GTSAM - cd ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/dependency/gtsam && \ + rm -rf ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/dependency/ceres-solver/build + +# Build GTSAM +RUN cd ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/dependency/gtsam && \ mkdir -p build && cd build && \ cmake .. -DGTSAM_USE_SYSTEM_EIGEN=ON -DGTSAM_BUILD_WITH_MARCH_NATIVE=OFF && \ - make -j$(nproc) && make install && ldconfig + make -j$(nproc) && make install && ldconfig && \ + rm -rf ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/dependency/gtsam/build -# Build the autonomy stack +# Build ROS workspace (no --symlink-install for multi-stage build compatibility) RUN /bin/bash -c "source /opt/ros/${ROS_DISTRO}/setup.bash && \ cd ${WORKSPACE} && \ - colcon build --symlink-install --cmake-args -DCMAKE_BUILD_TYPE=Release" + colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release" -# Source the workspace setup -RUN echo "source ${WORKSPACE}/install/setup.bash" >> ~/.bashrc +# ----------------------------------------------------------------------------- +# STAGE 2: Runtime Stage - minimal image for running +# ----------------------------------------------------------------------------- +FROM osrf/ros:jazzy-desktop-full AS runtime -# Create directory for Unity environment models -RUN mkdir -p ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/base_autonomy/vehicle_simulator/mesh/unity +ENV DEBIAN_FRONTEND=noninteractive +ENV ROS_DISTRO=jazzy +ENV WORKSPACE=/ros2_ws +ENV DIMOS_PATH=/workspace/dimos -# Copy the dimos repository -RUN mkdir -p ${DIMOS_PATH} -COPY . ${DIMOS_PATH}/ +# DDS Configuration - Use FastDDS (default ROS 2 middleware) +ENV RMW_IMPLEMENTATION=rmw_fastrtps_cpp +ENV FASTRTPS_DEFAULT_PROFILES_FILE=/ros2_ws/config/fastdds.xml -# Create a virtual environment in /opt (not in /workspace/dimos) -# This ensures the venv won't be overwritten when we mount the host dimos directory -# The container will always use its own dependencies, independent of the host -RUN python3 -m venv /opt/dimos-venv +# Install runtime dependencies only (no build tools) +RUN apt-get update && apt-get install -y --no-install-recommends \ + # ROS packages + ros-jazzy-pcl-ros \ + ros-jazzy-foxglove-bridge \ + ros-jazzy-rviz2 \ + ros-jazzy-rqt* \ + # DDS middleware (FastDDS is default, just ensure it's installed) + ros-jazzy-rmw-fastrtps-cpp \ + # Runtime libraries + libpcl-dev \ + libgoogle-glog-dev \ + libgflags-dev \ + libatlas-base-dev \ + libeigen3-dev \ + libsuitesparse-dev \ + # X11 for GUI (minimal) + libx11-6 \ + libxext6 \ + libxrender1 \ + libgl1 \ + libglib2.0-0 \ + # Networking tools + iputils-ping \ + net-tools \ + iproute2 \ + # Serial/USB for hardware + usbutils \ + # Python (minimal) + python3-pip \ + python3-venv \ + # Joystick support + joystick \ + # Time sync for multi-computer setups + chrony \ + && rm -rf /var/lib/apt/lists/* -# Activate Python virtual environment in interactive shells -RUN echo "source /opt/dimos-venv/bin/activate" >> ~/.bashrc +# Copy installed libraries from builder +COPY --from=builder /usr/local/lib /usr/local/lib +COPY --from=builder /usr/local/include /usr/local/include +RUN ldconfig -# Install Python dependencies for dimos -WORKDIR ${DIMOS_PATH} -RUN /bin/bash -c "source /opt/dimos-venv/bin/activate && \ - pip install --upgrade pip setuptools wheel && \ - pip install -e .[cpu,dev,agents] 'mmengine>=0.10.3' 'mmcv>=2.1.0' rerun-sdk" +# Copy built ROS workspace from builder +COPY --from=builder ${WORKSPACE}/install ${WORKSPACE}/install +COPY --from=builder ${WORKSPACE}/src/ros-navigation-autonomy-stack ${WORKSPACE}/src/ros-navigation-autonomy-stack + +# Create directories +RUN mkdir -p ${DIMOS_PATH} \ + ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/base_autonomy/vehicle_simulator/mesh/unity \ + ${WORKSPACE}/bagfiles \ + ${WORKSPACE}/logs \ + ${WORKSPACE}/config + +# Create FastDDS configuration file +RUN cat > ${WORKSPACE}/config/fastdds.xml <<'EOF' + + + + + + ros2_navigation_participant + + + SIMPLE + + 10 + 0 + + + 3 + 0 + + + + + 10485760 + 10485760 + true + + + + + + + udp_transport + UDPv4 + 10485760 + 10485760 + 65500 + + + + shm_transport + SHM + 10485760 + 1048576 + + + +EOF + +# Install portaudio for unitree-webrtc-connect (pyaudio dependency) +RUN apt-get update && apt-get install -y --no-install-recommends \ + portaudio19-dev \ + && rm -rf /var/lib/apt/lists/* + +# Create Python venv and install dependencies +RUN python3 -m venv /opt/dimos-venv && \ + /opt/dimos-venv/bin/pip install --no-cache-dir \ + pyyaml \ + unitree-webrtc-connect==2.0.4 + +# Set up shell environment +RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> ~/.bashrc && \ + echo "source ${WORKSPACE}/install/setup.bash" >> ~/.bashrc && \ + echo "source /opt/dimos-venv/bin/activate" >> ~/.bashrc && \ + echo "export RMW_IMPLEMENTATION=rmw_fastrtps_cpp" >> ~/.bashrc && \ + echo "export FASTRTPS_DEFAULT_PROFILES_FILE=/ros2_ws/config/fastdds.xml" >> ~/.bashrc # Copy helper scripts COPY docker/navigation/run_both.sh /usr/local/bin/run_both.sh COPY docker/navigation/ros_launch_wrapper.py /usr/local/bin/ros_launch_wrapper.py RUN chmod +x /usr/local/bin/run_both.sh /usr/local/bin/ros_launch_wrapper.py -# Set up udev rules for USB devices (motor controller) -RUN echo 'SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", MODE="0666", GROUP="dialout"' > /etc/udev/rules.d/99-motor-controller.rules && \ - usermod -a -G dialout root || true +# Set up udev rules for motor controller +RUN mkdir -p /etc/udev/rules.d && \ + echo 'SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", MODE="0666", GROUP="dialout"' \ + > /etc/udev/rules.d/99-motor-controller.rules # Set up entrypoint script RUN echo '#!/bin/bash\n\ set -e\n\ \n\ -git config --global --add safe.directory /workspace/dimos\n\ +# Mark git directories as safe\n\ +git config --global --add safe.directory /workspace/dimos 2>/dev/null || true\n\ +git config --global --add safe.directory /ros2_ws/src/ros-navigation-autonomy-stack 2>/dev/null || true\n\ \n\ # Source ROS setup\n\ source /opt/ros/${ROS_DISTRO}/setup.bash\n\ source ${WORKSPACE}/install/setup.bash\n\ \n\ -# Activate Python virtual environment for dimos\n\ +# Activate Python virtual environment\n\ source /opt/dimos-venv/bin/activate\n\ \n\ +# DDS Configuration (FastDDS)\n\ +export RMW_IMPLEMENTATION=rmw_fastrtps_cpp\n\ +export FASTRTPS_DEFAULT_PROFILES_FILE=/ros2_ws/config/fastdds.xml\n\ +\n\ +# Use custom DDS config if provided via mount\n\ +if [ -f "/ros2_ws/config/custom_fastdds.xml" ]; then\n\ + export FASTRTPS_DEFAULT_PROFILES_FILE=/ros2_ws/config/custom_fastdds.xml\n\ + echo "Using custom FastDDS configuration"\n\ +fi\n\ +\n\ # Export ROBOT_CONFIG_PATH for autonomy stack\n\ export ROBOT_CONFIG_PATH="${ROBOT_CONFIG_PATH:-mechanum_drive}"\n\ \n\ # Hardware-specific configurations\n\ if [ "${HARDWARE_MODE}" = "true" ]; then\n\ - # Set network buffer sizes for WiFi data transmission (if needed)\n\ + # Set network buffer sizes for WiFi data transmission\n\ if [ "${ENABLE_WIFI_BUFFER}" = "true" ]; then\n\ sysctl -w net.core.rmem_max=67108864 net.core.rmem_default=67108864 2>/dev/null || true\n\ sysctl -w net.core.wmem_max=67108864 net.core.wmem_default=67108864 2>/dev/null || true\n\ @@ -158,8 +259,6 @@ if [ "${HARDWARE_MODE}" = "true" ]; then\n\ if [ -n "${LIDAR_INTERFACE}" ] && [ -n "${LIDAR_COMPUTER_IP}" ]; then\n\ ip addr add ${LIDAR_COMPUTER_IP}/24 dev ${LIDAR_INTERFACE} 2>/dev/null || true\n\ ip link set ${LIDAR_INTERFACE} up 2>/dev/null || true\n\ - # Note: Do NOT add default route via LIDAR_GATEWAY as it would override internet access\n\ - # The /24 subnet route is automatically added when we assign the IP address\n\ fi\n\ \n\ # Generate MID360_config.json if LIDAR_COMPUTER_IP and LIDAR_IP are set\n\ @@ -214,13 +313,15 @@ EOF\n\ if [ -n "${ROBOT_IP}" ]; then\n\ echo "Robot IP configured on local network: ${ROBOT_IP}"\n\ fi\n\ - \n\ fi\n\ \n\ # Execute the command\n\ exec "$@"' > /ros_entrypoint.sh && \ chmod +x /ros_entrypoint.sh +# Working directory +WORKDIR ${DIMOS_PATH} + # Set the entrypoint ENTRYPOINT ["/ros_entrypoint.sh"] diff --git a/docker/navigation/Overwatch.json b/docker/navigation/Overwatch.json index 1057d8889b..e3b5f6dc7a 100644 --- a/docker/navigation/Overwatch.json +++ b/docker/navigation/Overwatch.json @@ -3,12 +3,25 @@ "3D!main": { "cameraState": { "perspective": true, - "distance": 20, - "phi": 60, - "thetaOffset": 45, - "targetOffset": [0, 0, 0], - "target": [0, 0, 0], - "targetOrientation": [0, 0, 0, 1], + "distance": 9.265824603193959, + "phi": 33.79912663755718, + "thetaOffset": -77.09606986899745, + "targetOffset": [ + -1.7933117489605865, + 0.24901413852157717, + 2.305722675118687e-16 + ], + "target": [ + 0, + 0, + 0 + ], + "targetOrientation": [ + 0, + 0, + 0, + 1 + ], "fovy": 45, "near": 0.01, "far": 5000 @@ -31,11 +44,11 @@ "topics": { "/registered_scan": { "visible": true, - "colorField": "intensity", - "colorMode": "flat", + "colorField": "z", + "colorMode": "colormap", "flatColor": "#ffffff", "pointSize": 2, - "decayTime": 5 + "decayTime": 1 }, "/overall_map": { "visible": true, @@ -121,8 +134,16 @@ "visible": true, "frameLocked": true, "label": "Grid", - "position": [0, 0, 0], - "rotation": [0, 0, 0], + "position": [ + 0, + 0, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], "color": "#248f24", "size": 100, "divisions": 100, @@ -138,7 +159,8 @@ "poseEstimateXDeviation": 0.5, "poseEstimateYDeviation": 0.5, "poseEstimateThetaDeviation": 0.26179939 - } + }, + "imageMode": {} }, "Image!camera": { "cameraTopic": "/camera/image", @@ -150,7 +172,47 @@ "flipVertical": false, "minValue": 0, "maxValue": 1, - "rotation": 0 + "rotation": 0, + "cameraState": { + "distance": 20, + "perspective": true, + "phi": 60, + "target": [ + 0, + 0, + 0 + ], + "targetOffset": [ + 0, + 0, + 0 + ], + "targetOrientation": [ + 0, + 0, + 0, + 1 + ], + "thetaOffset": 45, + "fovy": 45, + "near": 0.5, + "far": 5000 + }, + "followMode": "follow-pose", + "scene": {}, + "transforms": {}, + "topics": {}, + "layers": {}, + "publish": { + "type": "point", + "poseTopic": "/move_base_simple/goal", + "pointTopic": "/clicked_point", + "poseEstimateTopic": "/initialpose", + "poseEstimateXDeviation": 0.5, + "poseEstimateYDeviation": 0.5, + "poseEstimateThetaDeviation": 0.26179939 + }, + "imageMode": {} }, "Image!semantic": { "cameraTopic": "/camera/semantic_image", @@ -162,15 +224,67 @@ "flipVertical": false, "minValue": 0, "maxValue": 1, - "rotation": 0 + "rotation": 0, + "cameraState": { + "distance": 20, + "perspective": true, + "phi": 60, + "target": [ + 0, + 0, + 0 + ], + "targetOffset": [ + 0, + 0, + 0 + ], + "targetOrientation": [ + 0, + 0, + 0, + 1 + ], + "thetaOffset": 45, + "fovy": 45, + "near": 0.5, + "far": 5000 + }, + "followMode": "follow-pose", + "scene": {}, + "transforms": {}, + "topics": {}, + "layers": {}, + "publish": { + "type": "point", + "poseTopic": "/move_base_simple/goal", + "pointTopic": "/clicked_point", + "poseEstimateTopic": "/initialpose", + "poseEstimateXDeviation": 0.5, + "poseEstimateYDeviation": 0.5, + "poseEstimateThetaDeviation": 0.26179939 + }, + "imageMode": {} }, "Teleop!teleop": { "topic": "/cmd_vel", "publishRate": 10, - "upButton": { "field": "linear.x", "value": 0.5 }, - "downButton": { "field": "linear.x", "value": -0.5 }, - "leftButton": { "field": "angular.z", "value": 0.5 }, - "rightButton": { "field": "angular.z", "value": -0.5 } + "upButton": { + "field": "linear.x", + "value": 0.5 + }, + "downButton": { + "field": "linear.x", + "value": -0.5 + }, + "leftButton": { + "field": "angular.z", + "value": 0.5 + }, + "rightButton": { + "field": "angular.z", + "value": -0.5 + } }, "RawMessages!odom": { "diffEnabled": false, @@ -184,13 +298,29 @@ "diffMethod": "custom", "diffTopicPath": "", "showFullMessageForDiff": false, - "topicPath": "/cmd_vel.twist" + "topicPath": "/cmd_vel.twist", + "fontSize": 12 }, "Plot!speed": { "paths": [ - { "value": "/cmd_vel.twist.linear.x", "enabled": true, "timestampMethod": "receiveTime", "label": "Linear X" }, - { "value": "/cmd_vel.twist.linear.y", "enabled": true, "timestampMethod": "receiveTime", "label": "Linear Y" }, - { "value": "/cmd_vel.twist.angular.z", "enabled": true, "timestampMethod": "receiveTime", "label": "Angular Z" } + { + "value": "/cmd_vel.twist.linear.x", + "enabled": true, + "timestampMethod": "receiveTime", + "label": "Linear X" + }, + { + "value": "/cmd_vel.twist.linear.y", + "enabled": true, + "timestampMethod": "receiveTime", + "label": "Linear Y" + }, + { + "value": "/cmd_vel.twist.angular.z", + "enabled": true, + "timestampMethod": "receiveTime", + "label": "Angular Z" + } ], "showXAxisLabels": true, "showYAxisLabels": true, @@ -210,9 +340,20 @@ "fallbackColor": "#a0a0a0", "fallbackLabel": "No Data", "rules": [ - { "operator": "=", "rawValue": "true", "color": "#68e24a", "label": "Goal Reached" }, - { "operator": "=", "rawValue": "false", "color": "#f5f5f5", "label": "Navigating" } - ] + { + "operator": "=", + "rawValue": "true", + "color": "#68e24a", + "label": "Goal Reached" + }, + { + "operator": "=", + "rawValue": "false", + "color": "#f5f5f5", + "label": "Navigating" + } + ], + "fontSize": 36 }, "Indicator!stop": { "path": "/stop.data", @@ -220,10 +361,26 @@ "fallbackColor": "#a0a0a0", "fallbackLabel": "No Data", "rules": [ - { "operator": "=", "rawValue": "0", "color": "#68e24a", "label": "OK" }, - { "operator": "=", "rawValue": "1", "color": "#f5ba42", "label": "Speed Stop" }, - { "operator": "=", "rawValue": "2", "color": "#eb4034", "label": "Full Stop" } - ] + { + "operator": "=", + "rawValue": "0", + "color": "#68e24a", + "label": "OK" + }, + { + "operator": "=", + "rawValue": "1", + "color": "#f5ba42", + "label": "Speed Stop" + }, + { + "operator": "=", + "rawValue": "2", + "color": "#eb4034", + "label": "Full Stop" + } + ], + "fontSize": 36 } }, "globalVariables": {}, @@ -267,4 +424,4 @@ "direction": "column", "splitPercentage": 75 } -} +} \ No newline at end of file diff --git a/docker/navigation/docker-compose.yml b/docker/navigation/docker-compose.yml index 30e464c7d5..713fe9388d 100644 --- a/docker/navigation/docker-compose.yml +++ b/docker/navigation/docker-compose.yml @@ -28,6 +28,9 @@ services: - ROBOT_CONFIG_PATH=${ROBOT_CONFIG_PATH:-mechanum_drive} - ROBOT_IP=${ROBOT_IP:-} - HARDWARE_MODE=false + # DDS Configuration (FastDDS) + - RMW_IMPLEMENTATION=rmw_fastrtps_cpp + - FASTRTPS_DEFAULT_PROFILES_FILE=/ros2_ws/config/fastdds.xml # Volume mounts volumes: @@ -102,6 +105,9 @@ services: - ROBOT_CONFIG_PATH=${ROBOT_CONFIG_PATH:-mechanum_drive} - ROBOT_IP=${ROBOT_IP:-} - HARDWARE_MODE=true + # DDS Configuration (FastDDS) + - RMW_IMPLEMENTATION=rmw_fastrtps_cpp + - FASTRTPS_DEFAULT_PROFILES_FILE=/ros2_ws/config/fastdds.xml # Mid-360 Lidar configuration - LIDAR_INTERFACE=${LIDAR_INTERFACE:-} - LIDAR_COMPUTER_IP=${LIDAR_COMPUTER_IP:-192.168.1.5} @@ -111,6 +117,13 @@ services: - MOTOR_SERIAL_DEVICE=${MOTOR_SERIAL_DEVICE:-/dev/ttyACM0} # Network optimization - ENABLE_WIFI_BUFFER=true + # Route planner option + - USE_ROUTE_PLANNER=${USE_ROUTE_PLANNER:-false} + # RViz option + - USE_RVIZ=${USE_RVIZ:-false} + # Unitree robot configuration + - UNITREE_IP=${UNITREE_IP:-192.168.12.1} + - UNITREE_CONN=${UNITREE_CONN:-LocalAP} # Volume mounts volumes: @@ -160,11 +173,30 @@ services: - | echo "Checking joystick..." ls -la /dev/input/js0 2>/dev/null || echo "Warning: No joystick found at /dev/input/js0" - echo "Starting real robot system..." cd /ros2_ws source install/setup.bash - ros2 launch vehicle_simulator system_real_robot.launch & + source /opt/dimos-venv/bin/activate + if [ "$USE_ROUTE_PLANNER" = "true" ]; then + echo "Starting real robot system WITH route planner..." + ros2 launch vehicle_simulator system_real_robot_with_route_planner.launch & + else + echo "Starting real robot system (base autonomy)..." + ros2 launch vehicle_simulator system_real_robot.launch & + fi sleep 2 + if [ "$USE_RVIZ" = "true" ]; then + echo "Starting RViz2..." + if [ "$USE_ROUTE_PLANNER" = "true" ]; then + ros2 run rviz2 rviz2 -d /ros2_ws/src/ros-navigation-autonomy-stack/src/route_planner/far_planner/rviz/default.rviz & + else + ros2 run rviz2 rviz2 -d /ros2_ws/src/ros-navigation-autonomy-stack/src/base_autonomy/vehicle_simulator/rviz/vehicle_simulator.rviz & + fi + fi + # Launch Unitree control if ROBOT_CONFIG_PATH contains "unitree" + if [[ "$ROBOT_CONFIG_PATH" == *"unitree"* ]]; then + echo "Starting Unitree WebRTC control (IP: $UNITREE_IP, Method: $UNITREE_CONN)..." + ros2 launch unitree_webrtc_ros unitree_control.launch.py robot_ip:=$UNITREE_IP connection_method:=$UNITREE_CONN & + fi echo "Starting Foxglove Bridge on port 8765..." echo "Connect via Foxglove Studio: ws://$(hostname -I | awk '{print $1}'):8765" ros2 launch foxglove_bridge foxglove_bridge_launch.xml port:=8765 diff --git a/docker/navigation/start.sh b/docker/navigation/start.sh index d842a7a4a1..32cf929a12 100755 --- a/docker/navigation/start.sh +++ b/docker/navigation/start.sh @@ -9,6 +9,8 @@ NC='\033[0m' # Parse command line arguments MODE="simulation" +USE_ROUTE_PLANNER="false" +USE_RVIZ="false" while [[ $# -gt 0 ]]; do case $1 in --hardware) @@ -19,17 +21,29 @@ while [[ $# -gt 0 ]]; do MODE="simulation" shift ;; + --route-planner) + USE_ROUTE_PLANNER="true" + shift + ;; + --rviz) + USE_RVIZ="true" + shift + ;; --help|-h) echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" - echo " --simulation Start simulation container (default)" - echo " --hardware Start hardware container for real robot" - echo " --help, -h Show this help message" + echo " --simulation Start simulation container (default)" + echo " --hardware Start hardware container for real robot" + echo " --route-planner Enable FAR route planner (for hardware mode)" + echo " --rviz Launch RViz2 visualization" + echo " --help, -h Show this help message" echo "" echo "Examples:" - echo " $0 # Start simulation container" - echo " $0 --hardware # Start hardware container" + echo " $0 # Start simulation container" + echo " $0 --hardware # Start hardware (base autonomy)" + echo " $0 --hardware --route-planner # Hardware with route planner" + echo " $0 --hardware --route-planner --rviz # Hardware with route planner + RViz" echo "" echo "Press Ctrl+C to stop the container" exit 0 @@ -228,14 +242,30 @@ else CONTAINER_NAME="dimos_simulation_container" fi +# Export settings for docker-compose +export USE_ROUTE_PLANNER +export USE_RVIZ + # Print helpful info before starting echo "" if [ "$MODE" = "hardware" ]; then - echo "Hardware mode - Auto-starting ROS real robot system" - echo "" - echo "The container will automatically run:" - echo " - ROS navigation stack (system_real_robot.launch)" - echo " - RViz visualization" + if [ "$USE_ROUTE_PLANNER" = "true" ]; then + echo "Hardware mode - Auto-starting ROS real robot system WITH route planner" + echo "" + echo "The container will automatically run:" + echo " - ROS navigation stack (system_real_robot_with_route_planner.launch)" + echo " - FAR Planner for goal-based navigation" + echo " - Foxglove Bridge" + else + echo "Hardware mode - Auto-starting ROS real robot system (base autonomy)" + echo "" + echo "The container will automatically run:" + echo " - ROS navigation stack (system_real_robot.launch)" + echo " - Foxglove Bridge" + fi + if [ "$USE_RVIZ" = "true" ]; then + echo " - RViz2 visualization" + fi echo "" echo "To enter the container from another terminal:" echo -e " ${YELLOW}docker exec -it ${CONTAINER_NAME} bash${NC}" From e2c60e678494f067b760409d74647686c0f384b1 Mon Sep 17 00:00:00 2001 From: Bona Date: Fri, 16 Jan 2026 09:37:35 -0800 Subject: [PATCH 03/16] verified working on robot, without src folder and build folder copied to docker --- docker/navigation/Dockerfile | 12 ++++++++++-- docker/navigation/Overwatch.json | 17 +++++++++-------- docker/navigation/docker-compose.yml | 8 +++----- docker/navigation/start.sh | 21 +++++++++++++++++++-- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/docker/navigation/Dockerfile b/docker/navigation/Dockerfile index 9b8bbfcfc4..01cabf07f4 100644 --- a/docker/navigation/Dockerfile +++ b/docker/navigation/Dockerfile @@ -134,7 +134,14 @@ RUN ldconfig # Copy built ROS workspace from builder COPY --from=builder ${WORKSPACE}/install ${WORKSPACE}/install -COPY --from=builder ${WORKSPACE}/src/ros-navigation-autonomy-stack ${WORKSPACE}/src/ros-navigation-autonomy-stack + +# Copy only config/rviz files from src (not the large dependency folders) +# These are needed if running without volume mount +COPY --from=builder ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/base_autonomy/vehicle_simulator/rviz ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/base_autonomy/vehicle_simulator/rviz +COPY --from=builder ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/route_planner/far_planner/rviz ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/route_planner/far_planner/rviz +COPY --from=builder ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/exploration_planner/tare_planner/rviz ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/exploration_planner/tare_planner/rviz +COPY --from=builder ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/arise_slam_mid360/config ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/arise_slam_mid360/config +COPY --from=builder ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/utilities/livox_ros_driver2/config ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/utilities/livox_ros_driver2/config # Create directories RUN mkdir -p ${DIMOS_PATH} \ @@ -212,7 +219,8 @@ RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> ~/.bashrc && \ # Copy helper scripts COPY docker/navigation/run_both.sh /usr/local/bin/run_both.sh COPY docker/navigation/ros_launch_wrapper.py /usr/local/bin/ros_launch_wrapper.py -RUN chmod +x /usr/local/bin/run_both.sh /usr/local/bin/ros_launch_wrapper.py +COPY docker/navigation/ros-navigation-autonomy-stack/src/utilities/twist_relay/twist_relay.py /usr/local/bin/twist_relay.py +RUN chmod +x /usr/local/bin/run_both.sh /usr/local/bin/ros_launch_wrapper.py /usr/local/bin/twist_relay.py # Set up udev rules for motor controller RUN mkdir -p /etc/udev/rules.d && \ diff --git a/docker/navigation/Overwatch.json b/docker/navigation/Overwatch.json index e3b5f6dc7a..8faba5472a 100644 --- a/docker/navigation/Overwatch.json +++ b/docker/navigation/Overwatch.json @@ -3,13 +3,13 @@ "3D!main": { "cameraState": { "perspective": true, - "distance": 9.265824603193959, - "phi": 33.79912663755718, - "thetaOffset": -77.09606986899745, + "distance": 11.376001845526945, + "phi": 60.000000000004256, + "thetaOffset": -154.65065502183666, "targetOffset": [ - -1.7933117489605865, - 0.24901413852157717, - 2.305722675118687e-16 + -1.3664627921863377, + -0.4507491962036497, + 2.2548288625522925e-16 ], "target": [ 0, @@ -26,7 +26,7 @@ "near": 0.01, "far": 5000 }, - "followMode": "follow-pose", + "followMode": "follow-none", "followTf": "vehicle", "scene": { "backgroundColor": "#000000", @@ -160,7 +160,8 @@ "poseEstimateYDeviation": 0.5, "poseEstimateThetaDeviation": 0.26179939 }, - "imageMode": {} + "imageMode": {}, + "fixedFrame": "map" }, "Image!camera": { "cameraTopic": "/camera/image", diff --git a/docker/navigation/docker-compose.yml b/docker/navigation/docker-compose.yml index 713fe9388d..0425cbaf48 100644 --- a/docker/navigation/docker-compose.yml +++ b/docker/navigation/docker-compose.yml @@ -41,9 +41,6 @@ services: # Mount Unity environment models (if available) - ./unity_models:/ros2_ws/src/ros-navigation-autonomy-stack/src/base_autonomy/vehicle_simulator/mesh/unity:rw - # Mount the autonomy stack source for development - - ./ros-navigation-autonomy-stack:/ros2_ws/src/ros-navigation-autonomy-stack:rw - # Mount entire dimos directory for live development - ../..:/workspace/dimos:rw @@ -132,8 +129,6 @@ services: - ${HOME}/.Xauthority:/root/.Xauthority:rw # Mount Unity environment models (optional for hardware) - ./unity_models:/ros2_ws/src/ros-navigation-autonomy-stack/src/base_autonomy/vehicle_simulator/mesh/unity:rw - # Mount the autonomy stack source - - ./ros-navigation-autonomy-stack:/ros2_ws/src/ros-navigation-autonomy-stack:rw # Mount entire dimos directory - ../..:/workspace/dimos:rw # Mount bagfiles directory @@ -197,6 +192,9 @@ services: echo "Starting Unitree WebRTC control (IP: $UNITREE_IP, Method: $UNITREE_CONN)..." ros2 launch unitree_webrtc_ros unitree_control.launch.py robot_ip:=$UNITREE_IP connection_method:=$UNITREE_CONN & fi + # Start twist relay for Foxglove Teleop (converts Twist -> TwistStamped) + echo "Starting Twist relay for Foxglove Teleop..." + python3 /ros2_ws/src/ros-navigation-autonomy-stack/src/utilities/twist_relay/twist_relay.py & echo "Starting Foxglove Bridge on port 8765..." echo "Connect via Foxglove Studio: ws://$(hostname -I | awk '{print $1}'):8765" ros2 launch foxglove_bridge foxglove_bridge_launch.xml port:=8765 diff --git a/docker/navigation/start.sh b/docker/navigation/start.sh index 32cf929a12..8007947fc9 100755 --- a/docker/navigation/start.sh +++ b/docker/navigation/start.sh @@ -11,6 +11,7 @@ NC='\033[0m' MODE="simulation" USE_ROUTE_PLANNER="false" USE_RVIZ="false" +DEV_MODE="false" while [[ $# -gt 0 ]]; do case $1 in --hardware) @@ -29,6 +30,10 @@ while [[ $# -gt 0 ]]; do USE_RVIZ="true" shift ;; + --dev) + DEV_MODE="true" + shift + ;; --help|-h) echo "Usage: $0 [OPTIONS]" echo "" @@ -37,6 +42,7 @@ while [[ $# -gt 0 ]]; do echo " --hardware Start hardware container for real robot" echo " --route-planner Enable FAR route planner (for hardware mode)" echo " --rviz Launch RViz2 visualization" + echo " --dev Development mode (mount src for config editing)" echo " --help, -h Show this help message" echo "" echo "Examples:" @@ -44,6 +50,7 @@ while [[ $# -gt 0 ]]; do echo " $0 --hardware # Start hardware (base autonomy)" echo " $0 --hardware --route-planner # Hardware with route planner" echo " $0 --hardware --route-planner --rviz # Hardware with route planner + RViz" + echo " $0 --hardware --dev # Hardware with src mounted for development" echo "" echo "Press Ctrl+C to stop the container" exit 0 @@ -266,6 +273,10 @@ if [ "$MODE" = "hardware" ]; then if [ "$USE_RVIZ" = "true" ]; then echo " - RViz2 visualization" fi + if [ "$DEV_MODE" = "true" ]; then + echo "" + echo -e " ${YELLOW}Development mode: src folder mounted for config editing${NC}" + fi echo "" echo "To enter the container from another terminal:" echo -e " ${YELLOW}docker exec -it ${CONTAINER_NAME} bash${NC}" @@ -283,8 +294,14 @@ fi # Note: DISPLAY is now passed directly via environment variable # No need to write RUNTIME_DISPLAY to .env for local host running +# Build compose command with optional dev mode +COMPOSE_CMD="docker compose -f docker-compose.yml" +if [ "$DEV_MODE" = "true" ]; then + COMPOSE_CMD="$COMPOSE_CMD -f docker-compose.dev.yml" +fi + if [ "$MODE" = "hardware" ]; then - docker compose -f docker-compose.yml --profile hardware up + $COMPOSE_CMD --profile hardware up else - docker compose -f docker-compose.yml up + $COMPOSE_CMD up fi From d0b6ffec9ced2ddde13437fb1df0b889f465e9fe Mon Sep 17 00:00:00 2001 From: Bona Date: Fri, 16 Jan 2026 15:30:22 -0800 Subject: [PATCH 04/16] verified working foxglove layout, docker build, added goal send feature for foxglove --- docker/navigation/Dockerfile | 3 +- docker/navigation/Overwatch.json | 44 +++++++++++++++++++++++----- docker/navigation/docker-compose.yml | 5 +++- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/docker/navigation/Dockerfile b/docker/navigation/Dockerfile index 01cabf07f4..5491d6983c 100644 --- a/docker/navigation/Dockerfile +++ b/docker/navigation/Dockerfile @@ -220,7 +220,8 @@ RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> ~/.bashrc && \ COPY docker/navigation/run_both.sh /usr/local/bin/run_both.sh COPY docker/navigation/ros_launch_wrapper.py /usr/local/bin/ros_launch_wrapper.py COPY docker/navigation/ros-navigation-autonomy-stack/src/utilities/twist_relay/twist_relay.py /usr/local/bin/twist_relay.py -RUN chmod +x /usr/local/bin/run_both.sh /usr/local/bin/ros_launch_wrapper.py /usr/local/bin/twist_relay.py +COPY docker/navigation/ros-navigation-autonomy-stack/src/utilities/twist_relay/goal_autonomy_relay.py /usr/local/bin/goal_autonomy_relay.py +RUN chmod +x /usr/local/bin/run_both.sh /usr/local/bin/ros_launch_wrapper.py /usr/local/bin/twist_relay.py /usr/local/bin/goal_autonomy_relay.py # Set up udev rules for motor controller RUN mkdir -p /etc/udev/rules.d && \ diff --git a/docker/navigation/Overwatch.json b/docker/navigation/Overwatch.json index 8faba5472a..392bd1b14a 100644 --- a/docker/navigation/Overwatch.json +++ b/docker/navigation/Overwatch.json @@ -27,7 +27,7 @@ "far": 5000 }, "followMode": "follow-none", - "followTf": "vehicle", + "followTf": "map", "scene": { "backgroundColor": "#000000", "enableStats": false, @@ -126,6 +126,9 @@ "colorMode": "colormap", "colorMap": "rainbow", "pointSize": 7 + }, + "/viz_graph_topic": { + "visible": true } }, "layers": { @@ -152,13 +155,14 @@ } }, "publish": { - "type": "point", + "type": "pose", "poseTopic": "/goal_pose", "pointTopic": "/way_point", "poseEstimateTopic": "/initialpose", "poseEstimateXDeviation": 0.5, "poseEstimateYDeviation": 0.5, - "poseEstimateThetaDeviation": 0.26179939 + "poseEstimateThetaDeviation": 0.26179939, + "frameId": "map" }, "imageMode": {}, "fixedFrame": "map" @@ -268,7 +272,7 @@ "imageMode": {} }, "Teleop!teleop": { - "topic": "/cmd_vel", + "topic": "/foxglove_teleop", "publishRate": 10, "upButton": { "field": "linear.x", @@ -382,6 +386,27 @@ } ], "fontSize": 36 + }, + "Indicator!autonomy": { + "path": "/joy.axes[2]", + "style": "background", + "fallbackColor": "#a0a0a0", + "fallbackLabel": "No Joystick", + "rules": [ + { + "operator": "<", + "rawValue": "-0.1", + "color": "#68e24a", + "label": "Autonomy ON" + }, + { + "operator": ">=", + "rawValue": "-0.1", + "color": "#eb4034", + "label": "Autonomy OFF" + } + ], + "fontSize": 36 } }, "globalVariables": {}, @@ -405,10 +430,15 @@ "first": { "first": "Teleop!teleop", "second": { - "first": "Indicator!goalreached", - "second": "Indicator!stop", + "first": "Indicator!autonomy", + "second": { + "first": "Indicator!goalreached", + "second": "Indicator!stop", + "direction": "row", + "splitPercentage": 50 + }, "direction": "row", - "splitPercentage": 50 + "splitPercentage": 33 }, "direction": "row", "splitPercentage": 40 diff --git a/docker/navigation/docker-compose.yml b/docker/navigation/docker-compose.yml index 0425cbaf48..5ee2238e17 100644 --- a/docker/navigation/docker-compose.yml +++ b/docker/navigation/docker-compose.yml @@ -194,7 +194,10 @@ services: fi # Start twist relay for Foxglove Teleop (converts Twist -> TwistStamped) echo "Starting Twist relay for Foxglove Teleop..." - python3 /ros2_ws/src/ros-navigation-autonomy-stack/src/utilities/twist_relay/twist_relay.py & + python3 /usr/local/bin/twist_relay.py & + # Start goal autonomy relay (publishes Joy to enable autonomy when goal_pose received) + echo "Starting Goal Autonomy relay for Foxglove..." + python3 /usr/local/bin/goal_autonomy_relay.py & echo "Starting Foxglove Bridge on port 8765..." echo "Connect via Foxglove Studio: ws://$(hostname -I | awk '{print $1}'):8765" ros2 launch foxglove_bridge foxglove_bridge_launch.xml port:=8765 From 3061d6020a128aecefe87277acf936a464635623 Mon Sep 17 00:00:00 2001 From: Bona Date: Fri, 16 Jan 2026 21:37:33 -0800 Subject: [PATCH 05/16] verified working with both humble and jazzy, use --jazzy or --humble when build and run start.sh --- docker/navigation/Dockerfile | 41 ++++++++++++++++------ docker/navigation/build.sh | 52 +++++++++++++++++++++++++--- docker/navigation/docker-compose.yml | 8 +++-- docker/navigation/start.sh | 28 +++++++++++---- 4 files changed, 106 insertions(+), 23 deletions(-) diff --git a/docker/navigation/Dockerfile b/docker/navigation/Dockerfile index 5491d6983c..c3e454a9da 100644 --- a/docker/navigation/Dockerfile +++ b/docker/navigation/Dockerfile @@ -11,15 +11,22 @@ # 6. Minimal apt packages with --no-install-recommends # 7. DDS configuration for optimized ROS 2 communication # +# Supported ROS distributions: jazzy, humble +# Build with: docker build --build-arg ROS_DISTRO=humble ... +# # ============================================================================= +# Build argument for ROS distribution (default: humble) +ARG ROS_DISTRO=humble + # ----------------------------------------------------------------------------- # STAGE 1: Build Stage - compile all C++ dependencies # ----------------------------------------------------------------------------- -FROM osrf/ros:jazzy-desktop-full AS builder +FROM osrf/ros:${ROS_DISTRO}-desktop-full AS builder +ARG ROS_DISTRO ENV DEBIAN_FRONTEND=noninteractive -ENV ROS_DISTRO=jazzy +ENV ROS_DISTRO=${ROS_DISTRO} ENV WORKSPACE=/ros2_ws # Install build dependencies only @@ -37,7 +44,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libeigen3-dev \ libsuitesparse-dev \ # ROS packages needed for build - ros-jazzy-pcl-ros \ + ros-${ROS_DISTRO}-pcl-ros \ + ros-${ROS_DISTRO}-cv-bridge \ && rm -rf /var/lib/apt/lists/* # Create workspace @@ -46,6 +54,16 @@ RUN mkdir -p ${WORKSPACE}/src # Copy autonomy stack source COPY docker/navigation/ros-navigation-autonomy-stack ${WORKSPACE}/src/ros-navigation-autonomy-stack +# Compatibility fix: In Humble, cv_bridge uses .h extension, but Jazzy uses .hpp +# Create a symlink so code written for Jazzy works on Humble +RUN if [ "${ROS_DISTRO}" = "humble" ]; then \ + CV_BRIDGE_DIR=$(find /opt/ros/humble/include -name "cv_bridge.h" -printf "%h\n" 2>/dev/null | head -1) && \ + if [ -n "$CV_BRIDGE_DIR" ]; then \ + ln -sf "$CV_BRIDGE_DIR/cv_bridge.h" "$CV_BRIDGE_DIR/cv_bridge.hpp"; \ + echo "Created cv_bridge.hpp symlink in $CV_BRIDGE_DIR"; \ + fi; \ + fi + # Build Livox-SDK2 RUN cd ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/utilities/livox_ros_driver2/Livox-SDK2 && \ mkdir -p build && cd build && \ @@ -79,10 +97,12 @@ RUN /bin/bash -c "source /opt/ros/${ROS_DISTRO}/setup.bash && \ # ----------------------------------------------------------------------------- # STAGE 2: Runtime Stage - minimal image for running # ----------------------------------------------------------------------------- -FROM osrf/ros:jazzy-desktop-full AS runtime +ARG ROS_DISTRO +FROM osrf/ros:${ROS_DISTRO}-desktop-full AS runtime +ARG ROS_DISTRO ENV DEBIAN_FRONTEND=noninteractive -ENV ROS_DISTRO=jazzy +ENV ROS_DISTRO=${ROS_DISTRO} ENV WORKSPACE=/ros2_ws ENV DIMOS_PATH=/workspace/dimos @@ -93,12 +113,13 @@ ENV FASTRTPS_DEFAULT_PROFILES_FILE=/ros2_ws/config/fastdds.xml # Install runtime dependencies only (no build tools) RUN apt-get update && apt-get install -y --no-install-recommends \ # ROS packages - ros-jazzy-pcl-ros \ - ros-jazzy-foxglove-bridge \ - ros-jazzy-rviz2 \ - ros-jazzy-rqt* \ + ros-${ROS_DISTRO}-pcl-ros \ + ros-${ROS_DISTRO}-cv-bridge \ + ros-${ROS_DISTRO}-foxglove-bridge \ + ros-${ROS_DISTRO}-rviz2 \ + ros-${ROS_DISTRO}-rqt* \ # DDS middleware (FastDDS is default, just ensure it's installed) - ros-jazzy-rmw-fastrtps-cpp \ + ros-${ROS_DISTRO}-rmw-fastrtps-cpp \ # Runtime libraries libpcl-dev \ libgoogle-glog-dev \ diff --git a/docker/navigation/build.sh b/docker/navigation/build.sh index da0aa2de8c..5f39a26e6f 100755 --- a/docker/navigation/build.sh +++ b/docker/navigation/build.sh @@ -4,16 +4,57 @@ set -e GREEN='\033[0;32m' YELLOW='\033[1;33m' +RED='\033[0;31m' NC='\033[0m' +# Default ROS distribution +ROS_DISTRO="humble" + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + --humble) + ROS_DISTRO="humble" + shift + ;; + --jazzy) + ROS_DISTRO="jazzy" + shift + ;; + --help|-h) + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Options:" + echo " --humble Build with ROS 2 Humble (default)" + echo " --jazzy Build with ROS 2 Jazzy" + echo " --help, -h Show this help message" + echo "" + echo "Examples:" + echo " $0 # Build with ROS Humble (default)" + echo " $0 --jazzy # Build with ROS Jazzy" + echo " $0 --humble # Build with ROS Humble" + exit 0 + ;; + *) + echo -e "${RED}Unknown option: $1${NC}" + echo "Run '$0 --help' for usage information" + exit 1 + ;; + esac +done + +export ROS_DISTRO + echo -e "${GREEN}================================================${NC}" echo -e "${GREEN}Building DimOS + ROS Autonomy Stack Docker Image${NC}" +echo -e "${GREEN}ROS Distribution: ${ROS_DISTRO}${NC}" echo -e "${GREEN}================================================${NC}" echo "" SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd "$SCRIPT_DIR" +# Clone ros-navigation-autonomy-stack (uses jazzy branch for both ROS distros) if [ ! -d "ros-navigation-autonomy-stack" ]; then echo -e "${YELLOW}Cloning ros-navigation-autonomy-stack repository...${NC}" git clone -b jazzy git@github.com:dimensionalOS/ros-navigation-autonomy-stack.git @@ -29,7 +70,7 @@ fi echo "" echo -e "${YELLOW}Building Docker image with docker compose...${NC}" echo "This will take a while as it needs to:" -echo " - Download base ROS Jazzy image" +echo " - Download base ROS ${ROS_DISTRO^} image" echo " - Install ROS packages and dependencies" echo " - Build the autonomy stack" echo " - Build Livox-SDK2 for Mid-360 lidar" @@ -42,18 +83,19 @@ cd ../.. docker compose -f docker/navigation/docker-compose.yml build echo "" -echo -e "${GREEN}================================${NC}" +echo -e "${GREEN}============================================${NC}" echo -e "${GREEN}Docker image built successfully!${NC}" -echo -e "${GREEN}================================${NC}" +echo -e "${GREEN}Image: dimos_autonomy_stack:${ROS_DISTRO}${NC}" +echo -e "${GREEN}============================================${NC}" echo "" echo "To run in SIMULATION mode:" -echo -e "${YELLOW} ./start.sh${NC}" +echo -e "${YELLOW} ./start.sh --${ROS_DISTRO}${NC}" echo "" echo "To run in HARDWARE mode:" echo " 1. Configure your hardware settings in .env file" echo " (copy from .env.hardware if needed)" echo " 2. Run the hardware container:" -echo -e "${YELLOW} ./start.sh --hardware${NC}" +echo -e "${YELLOW} ./start.sh --hardware --${ROS_DISTRO}${NC}" echo "" echo "The script runs in foreground. Press Ctrl+C to stop." echo "" diff --git a/docker/navigation/docker-compose.yml b/docker/navigation/docker-compose.yml index 5ee2238e17..8a45af27d0 100644 --- a/docker/navigation/docker-compose.yml +++ b/docker/navigation/docker-compose.yml @@ -4,7 +4,9 @@ services: build: context: ../.. dockerfile: docker/navigation/Dockerfile - image: dimos_autonomy_stack:jazzy + args: + ROS_DISTRO: ${ROS_DISTRO:-humble} + image: dimos_autonomy_stack:${ROS_DISTRO:-humble} container_name: dimos_simulation_container profiles: ["", "simulation"] # Active by default (empty profile) AND with --profile simulation @@ -66,7 +68,9 @@ services: build: context: ../.. dockerfile: docker/navigation/Dockerfile - image: dimos_autonomy_stack:jazzy + args: + ROS_DISTRO: ${ROS_DISTRO:-humble} + image: dimos_autonomy_stack:${ROS_DISTRO:-humble} container_name: dimos_hardware_container profiles: ["hardware"] diff --git a/docker/navigation/start.sh b/docker/navigation/start.sh index 8007947fc9..3559757a9b 100755 --- a/docker/navigation/start.sh +++ b/docker/navigation/start.sh @@ -12,6 +12,7 @@ MODE="simulation" USE_ROUTE_PLANNER="false" USE_RVIZ="false" DEV_MODE="false" +ROS_DISTRO="humble" while [[ $# -gt 0 ]]; do case $1 in --hardware) @@ -34,6 +35,14 @@ while [[ $# -gt 0 ]]; do DEV_MODE="true" shift ;; + --humble) + ROS_DISTRO="humble" + shift + ;; + --jazzy) + ROS_DISTRO="jazzy" + shift + ;; --help|-h) echo "Usage: $0 [OPTIONS]" echo "" @@ -43,11 +52,15 @@ while [[ $# -gt 0 ]]; do echo " --route-planner Enable FAR route planner (for hardware mode)" echo " --rviz Launch RViz2 visualization" echo " --dev Development mode (mount src for config editing)" + echo " --humble Use ROS 2 Humble image (default)" + echo " --jazzy Use ROS 2 Jazzy image" echo " --help, -h Show this help message" echo "" echo "Examples:" - echo " $0 # Start simulation container" - echo " $0 --hardware # Start hardware (base autonomy)" + echo " $0 # Start simulation (Humble)" + echo " $0 --jazzy # Start simulation (Jazzy)" + echo " $0 --hardware # Start hardware (base autonomy, Humble)" + echo " $0 --hardware --jazzy # Start hardware (Jazzy)" echo " $0 --hardware --route-planner # Hardware with route planner" echo " $0 --hardware --route-planner --rviz # Hardware with route planner + RViz" echo " $0 --hardware --dev # Hardware with src mounted for development" @@ -63,12 +76,15 @@ while [[ $# -gt 0 ]]; do esac done +export ROS_DISTRO + SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd "$SCRIPT_DIR" echo -e "${GREEN}================================================${NC}" echo -e "${GREEN}Starting DimOS Docker Container${NC}" echo -e "${GREEN}Mode: ${MODE}${NC}" +echo -e "${GREEN}ROS Distribution: ${ROS_DISTRO}${NC}" echo -e "${GREEN}================================================${NC}" echo "" @@ -195,10 +211,10 @@ if [ "$MODE" = "hardware" ]; then fi -# Check if unified image exists -if ! docker images | grep -q "dimos_autonomy_stack.*jazzy"; then - echo -e "${YELLOW}Docker image not found. Building...${NC}" - ./build.sh +# Check if the correct ROS distro image exists +if ! docker images | grep -q "dimos_autonomy_stack.*${ROS_DISTRO}"; then + echo -e "${YELLOW}Docker image for ROS ${ROS_DISTRO} not found. Building...${NC}" + ./build.sh --${ROS_DISTRO} fi # Check for X11 display From f5bf1c172cb7578ef85127891866340135b657ef Mon Sep 17 00:00:00 2001 From: Bona Date: Sat, 17 Jan 2026 12:28:36 -0800 Subject: [PATCH 06/16] switch to use dev branch for ros-navigation-autonomy-stack, added pathc for cv_bridge if humble. verified start.sh --simulation with --jazzy and --humble work. verified start.sh --hardware --route-planner with --humble and --jazzy work on real robot, --rviz option preserved --- docker/navigation/Dockerfile | 7 +++ docker/navigation/Overwatch.json | 32 ++++++++++- docker/navigation/README.md | 80 ++++++++++++++++++++++------ docker/navigation/build.sh | 22 ++++++-- docker/navigation/docker-compose.yml | 8 +++ 5 files changed, 128 insertions(+), 21 deletions(-) diff --git a/docker/navigation/Dockerfile b/docker/navigation/Dockerfile index c3e454a9da..23db1bd32f 100644 --- a/docker/navigation/Dockerfile +++ b/docker/navigation/Dockerfile @@ -151,6 +151,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ # Copy installed libraries from builder COPY --from=builder /usr/local/lib /usr/local/lib COPY --from=builder /usr/local/include /usr/local/include + RUN ldconfig # Copy built ROS workspace from builder @@ -164,6 +165,9 @@ COPY --from=builder ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/explorati COPY --from=builder ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/arise_slam_mid360/config ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/slam/arise_slam_mid360/config COPY --from=builder ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/utilities/livox_ros_driver2/config ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/utilities/livox_ros_driver2/config +# Copy simulation shell scripts (real robot mode uses volume mount) +COPY --from=builder ${WORKSPACE}/src/ros-navigation-autonomy-stack/system_simulation*.sh ${WORKSPACE}/src/ros-navigation-autonomy-stack/ + # Create directories RUN mkdir -p ${DIMOS_PATH} \ ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/base_autonomy/vehicle_simulator/mesh/unity \ @@ -336,6 +340,9 @@ if [ "${HARDWARE_MODE}" = "true" ]; then\n\ ]\n\ }\n\ EOF\n\ + # Also copy to installed location where the driver actually reads from\n\ + cp ${WORKSPACE}/src/ros-navigation-autonomy-stack/src/utilities/livox_ros_driver2/config/MID360_config.json \\\n\ + ${WORKSPACE}/install/livox_ros_driver2/share/livox_ros_driver2/config/MID360_config.json 2>/dev/null || true\n\ echo "Generated MID360_config.json with LIDAR_COMPUTER_IP=${LIDAR_COMPUTER_IP} and LIDAR_IP=${LIDAR_IP}"\n\ fi\n\ \n\ diff --git a/docker/navigation/Overwatch.json b/docker/navigation/Overwatch.json index 392bd1b14a..8b2bc7bc55 100644 --- a/docker/navigation/Overwatch.json +++ b/docker/navigation/Overwatch.json @@ -1,4 +1,12 @@ { + "_watermark": { + "creator": "DIMOS Navigation", + "author": "bona", + "organization": "iServe Robotics", + "version": "1.0", + "timestamp": "2026-01-17", + "signature": "dimos-nav-overwatch-layout" + }, "configById": { "3D!main": { "cameraState": { @@ -78,7 +86,7 @@ "/navigation_boundary": { "visible": true, "color": "#00ff00", - "lineWidth": 0.05 + "lineWidth": 0.2 }, "/goal_pose": { "visible": true, @@ -128,7 +136,27 @@ "pointSize": 7 }, "/viz_graph_topic": { - "visible": true + "visible": true, + "namespaces": { + "angle_direct": { "visible": false }, + "boundary_edge": { "visible": false }, + "boundary_vertex": { "visible": false }, + "freespace_vertex": { "visible": false }, + "freespace_vgraph": { "visible": true }, + "frontier_vertex": { "visible": false }, + "global_vertex": { "visible": false }, + "global_vgraph": { "visible": false }, + "localrange_vertex": { "visible": false }, + "odom_edge": { "visible": false }, + "polygon_edge": { "visible": true }, + "to_goal_edge": { "visible": false }, + "trajectory_edge": { "visible": false }, + "trajectory_vertex": { "visible": false }, + "updating_vertex": { "visible": false }, + "vertex_angle": { "visible": false }, + "vertices_matches": { "visible": false }, + "visibility_edge": { "visible": false } + } } }, "layers": { diff --git a/docker/navigation/README.md b/docker/navigation/README.md index 1505786914..4213b237e3 100644 --- a/docker/navigation/README.md +++ b/docker/navigation/README.md @@ -16,28 +16,39 @@ This is an optimistic overview. Use the commands below for an in depth version. ```bash cd docker/navigation -./build.sh +./build.sh --humble # Build with ROS 2 Humble (default) +# or +./build.sh --jazzy # Build with ROS 2 Jazzy ``` This will: -- Clone the ros-navigation-autonomy-stack repository (jazzy branch) +- Clone the ros-navigation-autonomy-stack repository (matching branch: humble or jazzy) - Build a Docker image with both ROS and DimOS dependencies - Set up the environment for both systems -Note that the build will take over 10 minutes and build an image over 30GiB. +The resulting image will be named `dimos_autonomy_stack:humble` or `dimos_autonomy_stack:jazzy` depending on the option used. + +Note that the build will take a while and produce an image of approximately 7-8 GB. **Run the simulator to test it's working:** +Use the same ROS distribution flag as your build: + ```bash -./start.sh --simulation +./start.sh --simulation --humble # If built with --humble +# or +./start.sh --simulation --jazzy # If built with --jazzy ``` -## Manual build +
+

Manual build

-Go to the docker dir and clone the ROS navigation stack. +Go to the docker dir and clone the ROS navigation stack (choose the branch matching your ROS distribution). ```bash cd docker/navigation +git clone -b humble git@github.com:dimensionalOS/ros-navigation-autonomy-stack.git +# or git clone -b jazzy git@github.com:dimensionalOS/ros-navigation-autonomy-stack.git ``` @@ -50,13 +61,17 @@ tar -xf ../../data/.lfs/office_building_1.tar.gz mv office_building_1 unity_models ``` -Then, go back to the root and build the docker image: +Then, go back to the root (from docker/navigation) and build the docker image: ```bash -cd ../.. -docker compose -f docker/navigation/docker-compose.yml build +cd ../.. # Back to dimos root +ROS_DISTRO=humble docker compose -f docker/navigation/docker-compose.yml build +# or +ROS_DISTRO=jazzy docker compose -f docker/navigation/docker-compose.yml build ``` +
+ ## On Real Hardware ### Configure the WiFi @@ -77,36 +92,67 @@ cp .env.hardware .env Key configuration parameters: ```bash +# Robot Configuration +ROBOT_CONFIG_PATH=unitree/unitree_go2 # Robot type (mechanum_drive, unitree/unitree_go2, unitree/unitree_g1) + # Lidar Configuration LIDAR_INTERFACE=eth0 # Your ethernet interface (find with: ip link show) LIDAR_COMPUTER_IP=192.168.1.5 # Computer IP on the lidar subnet LIDAR_GATEWAY=192.168.1.1 # Gateway IP address for the lidar subnet -LIDAR_IP=192.168.1.116 # Full IP address of your Mid-360 lidar +LIDAR_IP=192.168.1.1xx # xx = last two digits from lidar QR code serial number ROBOT_IP= # IP addres of robot on local network (if using WebRTC connection) # Motor Controller MOTOR_SERIAL_DEVICE=/dev/ttyACM0 # Serial device (check with: ls /dev/ttyACM*) ``` -### Start the Container +### Start the Navigation Stack + +#### Start with Route Planner automatically + +Use --humble or --jazzy matching your build: + +```bash +./start.sh --hardware --humble --route-planner # Run route planner automatically +./start.sh --hardware --humble --route-planner --rviz # Route planner + RViz2 visualization +./start.sh --hardware --humble --dev # Development mode (mount src for config editing) +``` -Start the container and leave it open. +[Foxglove Studio](https://foxglove.dev/download) is the default visualization tool. It's ideal for remote operation - SSH with port forwarding to the robot's mini PC and run commands there: ```bash -./start.sh --hardware +ssh -L 8765:localhost:8765 user@robot-ip +``` + +Then on your local machine: +1. Open Foxglove and connect to `ws://localhost:8765` +2. Load the layout from `docker/navigation/Overwatch.json` (Layout menu → Import) +3. Click in the 3D panel to drop a target pose (similar to RViz). The "Autonomy ON" indicator should be green, and "Goal Reached" will show when the robot arrives. + +
+

Start manually

+ +Start the container and leave it open. Use the same ROS distribution flag as your build: + +```bash +./start.sh --hardware --humble # If built with --humble +# or +./start.sh --hardware --jazzy # If built with --jazzy ``` It doesn't do anything by default. You have to run commands on it by `exec`-ing: +To enter the container from another terminal: + ```bash docker exec -it dimos_hardware_container bash ``` -### In the container +##### In the container In the container to run the full navigation stack you must run both the dimensional python runfile with connection module and the navigation stack. -#### Dimensional Python + Connection Module +###### Dimensional Python + Connection Module For the Unitree G1 ```bash @@ -114,7 +160,7 @@ dimos run unitree-g1 ROBOT_IP=XX.X.X.XXX dimos run unitree-g1 # If ROBOT_IP env variable is not set in .env ``` -#### Navigation Stack +###### Navigation Stack ```bash cd /ros2_ws/src/ros-navigation-autonomy-stack @@ -122,3 +168,5 @@ cd /ros2_ws/src/ros-navigation-autonomy-stack ``` Now you can place goal points/poses in RVIZ by clicking the "Goalpoint" button. The robot will navigate to the point, running both local and global planners for dynamic obstacle avoidance. + +
diff --git a/docker/navigation/build.sh b/docker/navigation/build.sh index 5f39a26e6f..8191515670 100755 --- a/docker/navigation/build.sh +++ b/docker/navigation/build.sh @@ -54,11 +54,27 @@ echo "" SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd "$SCRIPT_DIR" -# Clone ros-navigation-autonomy-stack (uses jazzy branch for both ROS distros) +# Clone or checkout ros-navigation-autonomy-stack with dev branch if [ ! -d "ros-navigation-autonomy-stack" ]; then - echo -e "${YELLOW}Cloning ros-navigation-autonomy-stack repository...${NC}" - git clone -b jazzy git@github.com:dimensionalOS/ros-navigation-autonomy-stack.git + echo -e "${YELLOW}Cloning ros-navigation-autonomy-stack repository (dev branch)...${NC}" + git clone -b dev git@github.com:dimensionalOS/ros-navigation-autonomy-stack.git echo -e "${GREEN}Repository cloned successfully!${NC}" +else + # Directory exists, ensure we're on the dev branch + cd ros-navigation-autonomy-stack + CURRENT_BRANCH=$(git branch --show-current) + if [ "$CURRENT_BRANCH" != "dev" ]; then + echo -e "${YELLOW}Switching from ${CURRENT_BRANCH} to dev branch...${NC}" + # Stash any local changes (e.g., auto-generated config files) + git stash --quiet 2>/dev/null || true + git fetch origin dev + git checkout dev + git pull origin dev + echo -e "${GREEN}Switched to dev branch${NC}" + else + echo -e "${GREEN}Already on dev branch${NC}" + fi + cd .. fi if [ ! -d "unity_models" ]; then diff --git a/docker/navigation/docker-compose.yml b/docker/navigation/docker-compose.yml index 8a45af27d0..b16bd9b92a 100644 --- a/docker/navigation/docker-compose.yml +++ b/docker/navigation/docker-compose.yml @@ -4,12 +4,16 @@ services: build: context: ../.. dockerfile: docker/navigation/Dockerfile + network: host args: ROS_DISTRO: ${ROS_DISTRO:-humble} image: dimos_autonomy_stack:${ROS_DISTRO:-humble} container_name: dimos_simulation_container profiles: ["", "simulation"] # Active by default (empty profile) AND with --profile simulation + # Shared memory size for ROS 2 FastDDS + shm_size: '8gb' + # Enable interactive terminal stdin_open: true tty: true @@ -68,12 +72,16 @@ services: build: context: ../.. dockerfile: docker/navigation/Dockerfile + network: host args: ROS_DISTRO: ${ROS_DISTRO:-humble} image: dimos_autonomy_stack:${ROS_DISTRO:-humble} container_name: dimos_hardware_container profiles: ["hardware"] + # Shared memory size for ROS 2 FastDDS + shm_size: '8gb' + # Load environment from .env file env_file: - .env From 137d87c5661da42bc114cb85f61ae43bffed8dbb Mon Sep 17 00:00:00 2001 From: Bona Date: Sat, 17 Jan 2026 16:31:23 -0800 Subject: [PATCH 07/16] fix: move foxglove relay scripts to foxglove_utility folder, remove unused layout mount - Created foxglove_utility/ folder with twist_relay.py and goal_autonomy_relay.py - Updated Dockerfile to copy relay scripts from foxglove_utility/ instead of ros-navigation-autonomy-stack - Removed foxglove_layout.json mount from docker-compose.yml (not needed in container) --- docker/navigation/Dockerfile | 4 +- docker/navigation/docker-compose.yml | 2 - .../foxglove_utility/goal_autonomy_relay.py | 86 +++++++++++++++++++ .../foxglove_utility/twist_relay.py | 71 +++++++++++++++ 4 files changed, 159 insertions(+), 4 deletions(-) create mode 100755 docker/navigation/foxglove_utility/goal_autonomy_relay.py create mode 100644 docker/navigation/foxglove_utility/twist_relay.py diff --git a/docker/navigation/Dockerfile b/docker/navigation/Dockerfile index 23db1bd32f..fd390abe51 100644 --- a/docker/navigation/Dockerfile +++ b/docker/navigation/Dockerfile @@ -244,8 +244,8 @@ RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> ~/.bashrc && \ # Copy helper scripts COPY docker/navigation/run_both.sh /usr/local/bin/run_both.sh COPY docker/navigation/ros_launch_wrapper.py /usr/local/bin/ros_launch_wrapper.py -COPY docker/navigation/ros-navigation-autonomy-stack/src/utilities/twist_relay/twist_relay.py /usr/local/bin/twist_relay.py -COPY docker/navigation/ros-navigation-autonomy-stack/src/utilities/twist_relay/goal_autonomy_relay.py /usr/local/bin/goal_autonomy_relay.py +COPY docker/navigation/foxglove_utility/twist_relay.py /usr/local/bin/twist_relay.py +COPY docker/navigation/foxglove_utility/goal_autonomy_relay.py /usr/local/bin/goal_autonomy_relay.py RUN chmod +x /usr/local/bin/run_both.sh /usr/local/bin/ros_launch_wrapper.py /usr/local/bin/twist_relay.py /usr/local/bin/goal_autonomy_relay.py # Set up udev rules for motor controller diff --git a/docker/navigation/docker-compose.yml b/docker/navigation/docker-compose.yml index b16bd9b92a..215ec64279 100644 --- a/docker/navigation/docker-compose.yml +++ b/docker/navigation/docker-compose.yml @@ -149,8 +149,6 @@ services: - ./config:/ros2_ws/config:rw # Hardware-specific volumes - ./logs:/ros2_ws/logs:rw - # Foxglove layout - - ./foxglove_layout.json:/ros2_ws/foxglove_layout.json:ro - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro - /dev/bus/usb:/dev/bus/usb:rw diff --git a/docker/navigation/foxglove_utility/goal_autonomy_relay.py b/docker/navigation/foxglove_utility/goal_autonomy_relay.py new file mode 100755 index 0000000000..6b8d69b52b --- /dev/null +++ b/docker/navigation/foxglove_utility/goal_autonomy_relay.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +""" +Relay node that publishes Joy message to enable autonomy mode when goal_pose is received. +Mimics the behavior of the goalpoint_rviz_plugin for Foxglove compatibility. +""" + +import rclpy +from rclpy.node import Node +from rclpy.qos import QoSProfile, ReliabilityPolicy, HistoryPolicy, DurabilityPolicy +from geometry_msgs.msg import PoseStamped, PointStamped +from sensor_msgs.msg import Joy + + +class GoalAutonomyRelay(Node): + def __init__(self): + super().__init__('goal_autonomy_relay') + + # QoS for goal topics (match foxglove_bridge) + goal_qos = QoSProfile( + reliability=ReliabilityPolicy.RELIABLE, + history=HistoryPolicy.KEEP_LAST, + durability=DurabilityPolicy.VOLATILE, + depth=5 + ) + + # Subscribe to goal_pose (PoseStamped from Foxglove) + self.pose_sub = self.create_subscription( + PoseStamped, + '/goal_pose', + self.goal_pose_callback, + goal_qos + ) + + # Subscribe to way_point (PointStamped from Foxglove) + self.point_sub = self.create_subscription( + PointStamped, + '/way_point', + self.way_point_callback, + goal_qos + ) + + # Publisher for Joy message to enable autonomy + self.joy_pub = self.create_publisher(Joy, '/joy', 5) + + self.get_logger().info('Goal autonomy relay started - will publish Joy to enable autonomy when goals are received') + + def publish_autonomy_joy(self): + """Publish Joy message that enables autonomy mode (mimics goalpoint_rviz_plugin)""" + joy = Joy() + joy.header.stamp = self.get_clock().now().to_msg() + joy.header.frame_id = 'goal_autonomy_relay' + + # axes[2] = -1.0 enables autonomy mode in pathFollower + # axes[4] = 1.0 sets forward speed + # axes[5] = 1.0 enables obstacle checking + joy.axes = [0.0, 0.0, -1.0, 0.0, 1.0, 1.0, 0.0, 0.0] + + # buttons[7] = 1 (same as RViz plugin) + joy.buttons = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0] + + self.joy_pub.publish(joy) + self.get_logger().info('Published Joy message to enable autonomy mode') + + def goal_pose_callback(self, msg: PoseStamped): + self.get_logger().info(f'Received goal_pose at ({msg.pose.position.x:.2f}, {msg.pose.position.y:.2f})') + self.publish_autonomy_joy() + + def way_point_callback(self, msg: PointStamped): + self.get_logger().info(f'Received way_point at ({msg.point.x:.2f}, {msg.point.y:.2f})') + self.publish_autonomy_joy() + + +def main(args=None): + rclpy.init(args=args) + node = GoalAutonomyRelay() + try: + rclpy.spin(node) + except KeyboardInterrupt: + pass + finally: + node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/docker/navigation/foxglove_utility/twist_relay.py b/docker/navigation/foxglove_utility/twist_relay.py new file mode 100644 index 0000000000..3a13de724d --- /dev/null +++ b/docker/navigation/foxglove_utility/twist_relay.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +""" +Simple relay node that converts geometry_msgs/Twist to geometry_msgs/TwistStamped. +Used for Foxglove Teleop panel which only publishes Twist. +""" + +import rclpy +from rclpy.node import Node +from rclpy.qos import QoSProfile, ReliabilityPolicy, HistoryPolicy +from geometry_msgs.msg import Twist, TwistStamped + + +class TwistRelay(Node): + def __init__(self): + super().__init__('twist_relay') + + # Declare parameters + self.declare_parameter('input_topic', '/foxglove_teleop') + self.declare_parameter('output_topic', '/cmd_vel') + self.declare_parameter('frame_id', 'vehicle') + + input_topic = self.get_parameter('input_topic').value + output_topic = self.get_parameter('output_topic').value + self.frame_id = self.get_parameter('frame_id').value + + # QoS for real-time control + qos = QoSProfile( + reliability=ReliabilityPolicy.BEST_EFFORT, + history=HistoryPolicy.KEEP_LAST, + depth=1 + ) + + # Subscribe to Twist (from Foxglove Teleop) + self.subscription = self.create_subscription( + Twist, + input_topic, + self.twist_callback, + qos + ) + + # Publish TwistStamped + self.publisher = self.create_publisher( + TwistStamped, + output_topic, + qos + ) + + self.get_logger().info(f'Twist relay: {input_topic} (Twist) -> {output_topic} (TwistStamped)') + + def twist_callback(self, msg: Twist): + stamped = TwistStamped() + stamped.header.stamp = self.get_clock().now().to_msg() + stamped.header.frame_id = self.frame_id + stamped.twist = msg + self.publisher.publish(stamped) + + +def main(args=None): + rclpy.init(args=args) + node = TwistRelay() + try: + rclpy.spin(node) + except KeyboardInterrupt: + pass + finally: + node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() From e7b686b83ec9bfab667d7ebb7154a9f6dc04924b Mon Sep 17 00:00:00 2001 From: Bona Date: Sat, 17 Jan 2026 16:35:47 -0800 Subject: [PATCH 08/16] add warning log if cv_bridge.h not found during Humble compatibility fix --- docker/navigation/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/navigation/Dockerfile b/docker/navigation/Dockerfile index fd390abe51..d72312962c 100644 --- a/docker/navigation/Dockerfile +++ b/docker/navigation/Dockerfile @@ -61,6 +61,8 @@ RUN if [ "${ROS_DISTRO}" = "humble" ]; then \ if [ -n "$CV_BRIDGE_DIR" ]; then \ ln -sf "$CV_BRIDGE_DIR/cv_bridge.h" "$CV_BRIDGE_DIR/cv_bridge.hpp"; \ echo "Created cv_bridge.hpp symlink in $CV_BRIDGE_DIR"; \ + else \ + echo "Warning: cv_bridge.h not found, skipping symlink creation"; \ fi; \ fi From 9907939898bff0b51f9e4ada925b9c33a1ce081b Mon Sep 17 00:00:00 2001 From: Bona Date: Sat, 17 Jan 2026 16:38:06 -0800 Subject: [PATCH 09/16] add message when stashing local changes in build.sh --- docker/navigation/build.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docker/navigation/build.sh b/docker/navigation/build.sh index 8191515670..ea1729fb63 100755 --- a/docker/navigation/build.sh +++ b/docker/navigation/build.sh @@ -66,7 +66,9 @@ else if [ "$CURRENT_BRANCH" != "dev" ]; then echo -e "${YELLOW}Switching from ${CURRENT_BRANCH} to dev branch...${NC}" # Stash any local changes (e.g., auto-generated config files) - git stash --quiet 2>/dev/null || true + if git stash --quiet 2>/dev/null; then + echo -e "${YELLOW}Stashed local changes${NC}" + fi git fetch origin dev git checkout dev git pull origin dev From 16281890bf33bbad54e571bbc19d33fefd378452 Mon Sep 17 00:00:00 2001 From: Bona Date: Sat, 17 Jan 2026 16:39:59 -0800 Subject: [PATCH 10/16] add warnings when fallback GIDs are used for device permissions --- docker/navigation/start.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docker/navigation/start.sh b/docker/navigation/start.sh index 3559757a9b..9b27a1a3ce 100755 --- a/docker/navigation/start.sh +++ b/docker/navigation/start.sh @@ -117,6 +117,13 @@ if [ "$MODE" = "hardware" ]; then echo -e "${GREEN}Detecting device group IDs...${NC}" export INPUT_GID=$(getent group input | cut -d: -f3 || echo "995") export DIALOUT_GID=$(getent group dialout | cut -d: -f3 || echo "20") + # Warn if fallback values are being used + if ! getent group input > /dev/null 2>&1; then + echo -e "${YELLOW}Warning: input group not found, using fallback GID ${INPUT_GID}${NC}" + fi + if ! getent group dialout > /dev/null 2>&1; then + echo -e "${YELLOW}Warning: dialout group not found, using fallback GID ${DIALOUT_GID}${NC}" + fi echo -e " input group GID: ${INPUT_GID}" echo -e " dialout group GID: ${DIALOUT_GID}" From 5f1d610100681534b2bfa36cd86cbbb461d4a088 Mon Sep 17 00:00:00 2001 From: Bona Date: Sat, 17 Jan 2026 20:53:25 -0800 Subject: [PATCH 11/16] fix: source ROS setup.bash correctly and auto-install dimos package at runtime --- docker/navigation/run_both.sh | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docker/navigation/run_both.sh b/docker/navigation/run_both.sh index 24c480eaea..56d21b913b 100755 --- a/docker/navigation/run_both.sh +++ b/docker/navigation/run_both.sh @@ -87,11 +87,20 @@ cleanup() { # Set up trap to call cleanup on exit trap cleanup EXIT INT TERM +# Source ROS environment +echo "Sourcing ROS environment..." +source /opt/ros/${ROS_DISTRO:-humble}/setup.bash +source /ros2_ws/install/setup.bash + # Start ROS route planner in background (in new process group) echo "Starting ROS route planner..." cd /ros2_ws/src/ros-navigation-autonomy-stack -setsid bash -c './system_simulation_with_route_planner.sh' & +# Run simulation directly instead of using the script (which has wrong install path) +./src/base_autonomy/vehicle_simulator/mesh/unity/environment/Model.x86_64 & +sleep 3 +setsid bash -c 'ros2 launch vehicle_simulator system_simulation_with_route_planner.launch' & ROS_PID=$! +ros2 run rviz2 rviz2 -d src/route_planner/far_planner/rviz/default.rviz & # Wait a bit for ROS to initialize echo "Waiting for ROS to initialize..." @@ -111,6 +120,16 @@ else source /opt/dimos-venv/bin/activate echo "Python path: $(which python)" echo "Python version: $(python --version)" + + # Install dimos package if not already installed + if ! python -c "import dimos" 2>/dev/null; then + echo "Installing dimos package..." + if [ -f "/workspace/dimos/setup.py" ] || [ -f "/workspace/dimos/pyproject.toml" ]; then + pip install -e /workspace/dimos --quiet + else + echo "WARNING: dimos package not found at /workspace/dimos" + fi + fi else echo "WARNING: Virtual environment not found at /opt/dimos-venv, using system Python" fi From e430b807d19b16d4f67fee691dc87d0afef2f8b4 Mon Sep 17 00:00:00 2001 From: Bona Date: Sat, 17 Jan 2026 22:48:09 -0800 Subject: [PATCH 12/16] add langchain dependencies and pre-install dimos package in navigation Dockerfile - Add langchain-core and langchain to pip install for dimos.agents support - Copy dimos source and install as editable package during build - Update comment to reflect dimos source handling --- docker/navigation/Dockerfile | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docker/navigation/Dockerfile b/docker/navigation/Dockerfile index d72312962c..631b3244b5 100644 --- a/docker/navigation/Dockerfile +++ b/docker/navigation/Dockerfile @@ -6,7 +6,7 @@ # 1. Use ros:jazzy-ros-base instead of desktop-full (~2.5 GB saved) # 2. Multi-stage build to discard build artifacts # 3. No Python ML dependencies (~14 GB saved) -# 4. Don't COPY dimos source - it's volume-mounted at runtime (~1.2 GB saved) +# 4. COPY dimos source for editable pip install (volume-mounted at runtime overlays it) # 5. Clean up build directories after compile (~800 MB saved) # 6. Minimal apt packages with --no-install-recommends # 7. DDS configuration for optimized ROS 2 communication @@ -234,7 +234,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN python3 -m venv /opt/dimos-venv && \ /opt/dimos-venv/bin/pip install --no-cache-dir \ pyyaml \ - unitree-webrtc-connect==2.0.4 + unitree-webrtc-connect==2.0.4 \ + langchain-core \ + langchain + +# Copy dimos source and install as editable package +# The volume mount at runtime will overlay /workspace/dimos, but the editable +# install creates a link that will use the volume-mounted files +COPY pyproject.toml setup.py /workspace/dimos/ +COPY dimos /workspace/dimos/dimos +RUN /opt/dimos-venv/bin/pip install --no-cache-dir -e /workspace/dimos # Set up shell environment RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> ~/.bashrc && \ From d314f81beafdfe3bc9aaefe3745a5e7e18b9e66b Mon Sep 17 00:00:00 2001 From: Bona Date: Sat, 17 Jan 2026 23:38:11 -0800 Subject: [PATCH 13/16] udpate build image size --- docker/navigation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/navigation/README.md b/docker/navigation/README.md index 4213b237e3..26e760eff4 100644 --- a/docker/navigation/README.md +++ b/docker/navigation/README.md @@ -28,7 +28,7 @@ This will: The resulting image will be named `dimos_autonomy_stack:humble` or `dimos_autonomy_stack:jazzy` depending on the option used. -Note that the build will take a while and produce an image of approximately 7-8 GB. +Note that the build will take a while and produce an image of approximately 10 GB. **Run the simulator to test it's working:** From 01d8072c61aade8a6f3050ede4583b61890fcbeb Mon Sep 17 00:00:00 2001 From: alexlin2 Date: Sun, 18 Jan 2026 17:29:25 -0500 Subject: [PATCH 14/16] changed dependency fixed launch bug --- docker/navigation/Dockerfile | 7 ++----- docker/navigation/docker-compose.yml | 8 ++++++-- docker/navigation/run_both.sh | 5 +++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docker/navigation/Dockerfile b/docker/navigation/Dockerfile index 631b3244b5..a109bf3b61 100644 --- a/docker/navigation/Dockerfile +++ b/docker/navigation/Dockerfile @@ -233,17 +233,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ # Create Python venv and install dependencies RUN python3 -m venv /opt/dimos-venv && \ /opt/dimos-venv/bin/pip install --no-cache-dir \ - pyyaml \ - unitree-webrtc-connect==2.0.4 \ - langchain-core \ - langchain + pyyaml # Copy dimos source and install as editable package # The volume mount at runtime will overlay /workspace/dimos, but the editable # install creates a link that will use the volume-mounted files COPY pyproject.toml setup.py /workspace/dimos/ COPY dimos /workspace/dimos/dimos -RUN /opt/dimos-venv/bin/pip install --no-cache-dir -e /workspace/dimos +RUN /opt/dimos-venv/bin/pip install --no-cache-dir -e "/workspace/dimos[unitree]" # Set up shell environment RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> ~/.bashrc && \ diff --git a/docker/navigation/docker-compose.yml b/docker/navigation/docker-compose.yml index 215ec64279..d2abf73296 100644 --- a/docker/navigation/docker-compose.yml +++ b/docker/navigation/docker-compose.yml @@ -21,6 +21,10 @@ services: # Network configuration - required for ROS communication network_mode: host + # Allow `ip link set ...` (needed by DimOS LCM autoconf) without requiring sudo + cap_add: + - NET_ADMIN + # Use nvidia runtime for GPU acceleration (falls back to runc if not available) runtime: ${DOCKER_RUNTIME:-nvidia} @@ -183,10 +187,10 @@ services: source /opt/dimos-venv/bin/activate if [ "$USE_ROUTE_PLANNER" = "true" ]; then echo "Starting real robot system WITH route planner..." - ros2 launch vehicle_simulator system_real_robot_with_route_planner.launch & + ros2 launch vehicle_simulator system_real_robot_with_route_planner.launch.py & else echo "Starting real robot system (base autonomy)..." - ros2 launch vehicle_simulator system_real_robot.launch & + ros2 launch vehicle_simulator system_real_robot.launch.py & fi sleep 2 if [ "$USE_RVIZ" = "true" ]; then diff --git a/docker/navigation/run_both.sh b/docker/navigation/run_both.sh index 56d21b913b..e59a15ef5e 100755 --- a/docker/navigation/run_both.sh +++ b/docker/navigation/run_both.sh @@ -98,7 +98,7 @@ cd /ros2_ws/src/ros-navigation-autonomy-stack # Run simulation directly instead of using the script (which has wrong install path) ./src/base_autonomy/vehicle_simulator/mesh/unity/environment/Model.x86_64 & sleep 3 -setsid bash -c 'ros2 launch vehicle_simulator system_simulation_with_route_planner.launch' & +setsid bash -c 'ros2 launch vehicle_simulator system_simulation_with_route_planner.launch.py' & ROS_PID=$! ros2 run rviz2 rviz2 -d src/route_planner/far_planner/rviz/default.rviz & @@ -125,7 +125,8 @@ else if ! python -c "import dimos" 2>/dev/null; then echo "Installing dimos package..." if [ -f "/workspace/dimos/setup.py" ] || [ -f "/workspace/dimos/pyproject.toml" ]; then - pip install -e /workspace/dimos --quiet + # Install Unitree extra (includes agents stack + unitree deps used by demo) + pip install -e "/workspace/dimos[unitree]" --quiet else echo "WARNING: dimos package not found at /workspace/dimos" fi From f6f55370b3a72c7edea46efd7f7f2b4453f93cd1 Mon Sep 17 00:00:00 2001 From: Bona Date: Sun, 18 Jan 2026 17:09:21 -0800 Subject: [PATCH 15/16] docs: update image size estimate from 10 GB to 24 GB Co-Authored-By: Claude Opus 4.5 --- docker/navigation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/navigation/README.md b/docker/navigation/README.md index 26e760eff4..f578c42ee7 100644 --- a/docker/navigation/README.md +++ b/docker/navigation/README.md @@ -28,7 +28,7 @@ This will: The resulting image will be named `dimos_autonomy_stack:humble` or `dimos_autonomy_stack:jazzy` depending on the option used. -Note that the build will take a while and produce an image of approximately 10 GB. +Note that the build will take a while and produce an image of approximately 24 GB. **Run the simulator to test it's working:** From 8473830e33e124eb48fd0bb4f52b7799f11e5991 Mon Sep 17 00:00:00 2001 From: alexlin2 Date: Tue, 20 Jan 2026 10:17:31 -0500 Subject: [PATCH 16/16] updated README for G1 EDU --- docker/navigation/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docker/navigation/README.md b/docker/navigation/README.md index f578c42ee7..66fc238dbe 100644 --- a/docker/navigation/README.md +++ b/docker/navigation/README.md @@ -102,8 +102,12 @@ LIDAR_GATEWAY=192.168.1.1 # Gateway IP address for the lidar subnet LIDAR_IP=192.168.1.1xx # xx = last two digits from lidar QR code serial number ROBOT_IP= # IP addres of robot on local network (if using WebRTC connection) -# Motor Controller -MOTOR_SERIAL_DEVICE=/dev/ttyACM0 # Serial device (check with: ls /dev/ttyACM*) +# Special Configuration for Unitree G1 EDU +For the Unitree G1 EDU, use these specific values: +LIDAR_COMPUTER_IP=192.168.123.5 +LIDAR_GATEWAY=192.168.123.1 +LIDAR_IP=192.168.123.120 +ROBOT_IP=192.168.12.1 # For WebRTC local AP mode (optional, need additional wifi dongle) ``` ### Start the Navigation Stack