saltylab-firmware/jetson/docker-compose.yml
sl-perception dc01efe323 feat: 4x IMX219 surround vision + Nav2 camera obstacle layer (Phase 2c)
New ROS2 package saltybot_surround:

surround_costmap_node
  - Subscribes to /camera/{front,left,rear,right}/image_raw
  - Detects obstacles via Canny edge detection + ground projection
  - Pinhole back-projection: pixel row → forward distance (d = h*fy/(v-cy))
  - Rotates per-camera points to base_link frame using known camera yaws
  - Publishes /surround_vision/obstacles (PointCloud2, 5 Hz)
  - Catches chairs, glass walls, people that RPLIDAR misses
  - Placeholder IMX219 fisheye calibration (hook for real cal via cv2.fisheye)

surround_vision_node
  - IPM homography computed from camera height + pinhole model
  - 4× bird's-eye patches composited into 240×240px 360° overhead view
  - Publishes /surround_vision/birdseye (Image, 10 Hz)
  - Robot footprint + compass overlay

surround_vision.launch.py
  - Launches both nodes with surround_vision_params.yaml
  - start_cameras arg: set false when csi-cameras container runs separately

Updated:
- jetson/config/nav2_params.yaml   add surround_cameras PointCloud2 source
                                    to local + global costmap obstacle_layer
- jetson/docker-compose.yml        add saltybot-surround service
                                    (depends_on: csi-cameras, start_cameras:=false)
- projects/saltybot/SLAM-SETUP-PLAN.md  Phase 2c  Done

Calibration TODO (run after hardware assembly):
  ros2 run camera_calibration cameracalibrator --size 8x6 --square 0.025 \
    image:=/camera/front/image_raw camera:=/camera/front
  Replace placeholder K/D in surround_costmap_node._undistort()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 23:19:23 -05:00

225 lines
7.1 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

version: "3.8"
# Jetson Orin Nano Super — ROS2 Humble SLAM stack
# Run with: docker compose up -d
# Requires: NVIDIA Container Toolkit (JetPack 6) on host
services:
# ── Core ROS2 + SLAM node ─────────────────────────────────────────────────
saltybot-ros2:
image: saltybot/ros2-humble:jetson-orin
build:
context: .
dockerfile: Dockerfile
container_name: saltybot-ros2
restart: unless-stopped
runtime: nvidia # JetPack NVIDIA runtime
privileged: false # use device passthrough instead
network_mode: host # ROS2 DDS multicast needs host networking
environment:
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=all
- RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
- ROS_DOMAIN_ID=42
- DISPLAY=${DISPLAY:-:0} # for RViz2 on host X11
volumes:
# X11 socket for RViz2
- /tmp/.X11-unix:/tmp/.X11-unix:rw
# ROS2 workspace (host-mounted for live dev)
- ./ros2_ws/src:/ros2_ws/src:rw
# Persistent SLAM maps on NVMe
- /mnt/nvme/saltybot/maps:/maps
# NVMe data volume
- /mnt/nvme/saltybot:/data:rw
# Config files
- ./config:/config:ro
devices:
# RPLIDAR A1M8 — stable symlink via udev
- /dev/rplidar:/dev/rplidar
# STM32 USB CDC bridge — stable symlink via udev
- /dev/stm32-bridge:/dev/stm32-bridge
# RealSense D435i — USB3 device, needs udev rules
- /dev/bus/usb:/dev/bus/usb
# I2C bus (Orin Nano i2c-7 = 40-pin header pins 3/5)
- /dev/i2c-7:/dev/i2c-7
# CSI cameras via V4L2
- /dev/video0:/dev/video0
- /dev/video2:/dev/video2
- /dev/video4:/dev/video4
- /dev/video6:/dev/video6
command: >
bash -c "
source /opt/ros/humble/setup.bash &&
ros2 launch saltybot_bringup slam_rtabmap.launch.py
"
# ── RPLIDAR driver node ────────────────────────────────────────────────────
rplidar:
image: saltybot/ros2-humble:jetson-orin
build:
context: .
dockerfile: Dockerfile
container_name: saltybot-rplidar
restart: unless-stopped
runtime: nvidia
network_mode: host
environment:
- ROS_DOMAIN_ID=42
- RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
devices:
- /dev/rplidar:/dev/rplidar
command: >
bash -c "
source /opt/ros/humble/setup.bash &&
ros2 launch rplidar_ros rplidar_a1_launch.py
serial_port:=/dev/rplidar
frame_id:=laser
"
# ── RealSense D435i driver node ────────────────────────────────────────────
realsense:
image: saltybot/ros2-humble:jetson-orin
build:
context: .
dockerfile: Dockerfile
container_name: saltybot-realsense
restart: unless-stopped
runtime: nvidia
network_mode: host
environment:
- ROS_DOMAIN_ID=42
- RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
devices:
- /dev/bus/usb:/dev/bus/usb
volumes:
- /dev:/dev
command: >
bash -c "
source /opt/ros/humble/setup.bash &&
ros2 launch realsense2_camera rs_launch.py
enable_color:=true
enable_depth:=true
enable_gyro:=true
enable_accel:=true
unite_imu_method:=linear_interpolation
depth_module.profile:=640x480x30
rgb_camera.profile:=640x480x30
"
# ── STM32 bridge node (bidirectional serial↔ROS2) ─────────────────────────
stm32-bridge:
image: saltybot/ros2-humble:jetson-orin
build:
context: .
dockerfile: Dockerfile
container_name: saltybot-stm32-bridge
restart: unless-stopped
runtime: nvidia
network_mode: host
environment:
- ROS_DOMAIN_ID=42
- RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
devices:
- /dev/stm32-bridge:/dev/stm32-bridge
command: >
bash -c "
source /opt/ros/humble/setup.bash &&
ros2 launch saltybot_bridge bridge.launch.py
mode:=bidirectional
serial_port:=/dev/stm32-bridge
"
# ── 4× IMX219 CSI cameras ─────────────────────────────────────────────────
csi-cameras:
image: saltybot/ros2-humble:jetson-orin
build:
context: .
dockerfile: Dockerfile
container_name: saltybot-csi-cameras
restart: unless-stopped
runtime: nvidia
network_mode: host
privileged: true # CSI camera access requires elevated perms
environment:
- ROS_DOMAIN_ID=42
- RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=all
devices:
- /dev/video0:/dev/video0
- /dev/video2:/dev/video2
- /dev/video4:/dev/video4
- /dev/video6:/dev/video6
command: >
bash -c "
source /opt/ros/humble/setup.bash &&
ros2 launch saltybot_cameras csi_cameras.launch.py
width:=640
height:=480
fps:=30
"
# ── Surround vision — 360° bird's-eye view + Nav2 camera obstacle layer ─────
saltybot-surround:
image: saltybot/ros2-humble:jetson-orin
build:
context: .
dockerfile: Dockerfile
container_name: saltybot-surround
restart: unless-stopped
runtime: nvidia
network_mode: host
depends_on:
- csi-cameras # IMX219 /camera/*/image_raw must be publishing
environment:
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=all
- RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
- ROS_DOMAIN_ID=42
volumes:
- ./ros2_ws/src:/ros2_ws/src:rw
- ./config:/config:ro
command: >
bash -c "
source /opt/ros/humble/setup.bash &&
ros2 launch saltybot_surround surround_vision.launch.py
start_cameras:=false
camera_height:=0.30
publish_rate:=5.0
"
# ── Nav2 autonomous navigation stack ────────────────────────────────────────
saltybot-nav2:
image: saltybot/ros2-humble:jetson-orin
build:
context: .
dockerfile: Dockerfile
container_name: saltybot-nav2
restart: unless-stopped
runtime: nvidia
network_mode: host
depends_on:
- saltybot-ros2 # RTAB-Map + sensors must be running first
environment:
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=all
- RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
- ROS_DOMAIN_ID=42
volumes:
- ./ros2_ws/src:/ros2_ws/src:rw
- ./config:/config:ro
command: >
bash -c "
source /opt/ros/humble/setup.bash &&
ros2 launch saltybot_bringup nav2.launch.py
"
volumes:
saltybot-maps:
driver: local