# ============================================================================= # RDC Simulation - Docker Compose (Multi-Service with Proper Ordering) # ============================================================================= # Runs 3 services in order: # 1. gazebo - Gazebo Harmonic simulation (starts first) # 2. sitl - ArduPilot SITL (waits for Gazebo) # 3. controller - Python flight controller (waits for SITL) # # Usage: # # Start all 3 services # docker compose up # # # Or start specific services # docker compose up gazebo # docker compose up gazebo sitl # docker compose up gazebo sitl controller # # # Interactive shell (for debugging) # docker compose run --rm simulation bash # # # Stop everything # docker compose down # ============================================================================= # Common configuration anchor x-common: &common image: rdc-simulation:latest build: context: . dockerfile: Dockerfile # GPU support (NVIDIA) deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [ gpu ] # Environment variables - Wayland with GPU environment: # Wayland display &common-env - WAYLAND_DISPLAY=${WAYLAND_DISPLAY:-wayland-0} - XDG_RUNTIME_DIR=/run/user/1000 # X11 fallback - DISPLAY=${DISPLAY:-:0} # GPU - NVIDIA_VISIBLE_DEVICES=all - NVIDIA_DRIVER_CAPABILITIES=all # Qt platform - Wayland - QT_QPA_PLATFORM=wayland - QT_WAYLAND_DISABLE_WINDOWDECORATION=1 # OpenGL settings - __GLX_VENDOR_LIBRARY_NAME=nvidia - __NV_PRIME_RENDER_OFFLOAD=1 # Gazebo paths - GZ_SIM_SYSTEM_PLUGIN_PATH=/home/pilot/ardupilot_gazebo/build - GZ_SIM_RESOURCE_PATH=/home/pilot/ardupilot_gazebo/models:/home/pilot/ardupilot_gazebo/worlds:/home/pilot/RDC_Simulation/gazebo/models # Mount Wayland and X11 sockets volumes: - ${XDG_RUNTIME_DIR:-/run/user/1000}/${WAYLAND_DISPLAY:-wayland-0}:/run/user/1000/wayland-0:rw - /tmp/.X11-unix:/tmp/.X11-unix:rw - /dev/dri:/dev/dri:rw # Host network for SITL <-> Gazebo communication network_mode: host # Run as user 1000 user: "1000:1000" stdin_open: true tty: true working_dir: /home/pilot/RDC_Simulation services: # ========================================================================= # SERVICE 1: Gazebo Simulation (must start first) # ========================================================================= gazebo: <<: *common container_name: rdc-gazebo entrypoint: [ "/bin/bash", "-c" ] command: - | echo "==========================================" echo " SERVICE 1: Starting Gazebo Harmonic" echo "==========================================" source /opt/ros/jazzy/setup.bash source ~/.bashrc export GZ_SIM_SYSTEM_PLUGIN_PATH=/home/pilot/ardupilot_gazebo/build export GZ_SIM_RESOURCE_PATH=/home/pilot/ardupilot_gazebo/models:/home/pilot/ardupilot_gazebo/worlds:/home/pilot/RDC_Simulation/gazebo/models cd /home/pilot/RDC_Simulation echo "Launching Gazebo world: iris_runway" gz sim -r /home/pilot/ardupilot_gazebo/worlds/iris_runway.sdf healthcheck: test: [ "CMD-SHELL", "pgrep -x gz || exit 1" ] interval: 5s timeout: 10s retries: 30 start_period: 30s # ========================================================================= # SERVICE 2: ArduPilot SITL (waits for Gazebo) # ========================================================================= sitl: <<: *common container_name: rdc-sitl depends_on: gazebo: condition: service_started entrypoint: [ "/bin/bash", "-c" ] command: - | echo "==========================================" echo " SERVICE 2: Starting ArduPilot SITL" echo "==========================================" source /opt/ros/jazzy/setup.bash source ~/.bashrc source ~/.profile 2>/dev/null || true # Wait for Gazebo to be ready (check if port 9002 is listening) echo "Waiting for Gazebo to be ready..." for i in {1..60}; do if nc -z localhost 9002 2>/dev/null; then echo "Gazebo is ready!" break fi echo "Waiting... ($$i/60)" sleep 2 done echo "Starting ArduCopter SITL..." cd /home/pilot/ardupilot sim_vehicle.py -v ArduCopter -f gazebo-iris --model JSON --console --map # ========================================================================= # SERVICE 3: Flight Controller (waits for SITL) # ========================================================================= controller: <<: *common container_name: rdc-controller depends_on: sitl: condition: service_started entrypoint: [ "/bin/bash", "-c" ] command: - | echo "==========================================" echo " SERVICE 3: Starting Flight Controller" echo "==========================================" source /opt/ros/jazzy/setup.bash source ~/.bashrc source /home/pilot/RDC_Simulation/venv/bin/activate # Wait for SITL to be ready (check MAVLink port 14550) echo "Waiting for ArduPilot SITL to be ready..." for i in {1..90}; do if nc -z localhost 14550 2>/dev/null; then echo "SITL is ready!" break fi echo "Waiting... ($$i/90)" sleep 2 done # Additional wait for SITL to fully initialize echo "Waiting 10 more seconds for SITL to stabilize..." sleep 10 echo "Starting flight controller with square pattern..." cd /home/pilot/RDC_Simulation python scripts/run_ardupilot.py --pattern square # ========================================================================= # Interactive Shell (for debugging) # ========================================================================= simulation: <<: *common container_name: rdc-sim profiles: [ "debug" ] entrypoint: [ "/home/pilot/docker-entrypoint.sh" ] command: [ "bash" ] # ========================================================================= # Headless Mode (CI/Server - no display) # ========================================================================= simulation-headless: <<: *common container_name: rdc-sim-headless profiles: [ "headless" ] environment: - NVIDIA_VISIBLE_DEVICES=all - NVIDIA_DRIVER_CAPABILITIES=compute,utility - HEADLESS=1 - LIBGL_ALWAYS_SOFTWARE=1 - GZ_SIM_SYSTEM_PLUGIN_PATH=/home/pilot/ardupilot_gazebo/build - GZ_SIM_RESOURCE_PATH=/home/pilot/ardupilot_gazebo/models:/home/pilot/ardupilot_gazebo/worlds:/home/pilot/RDC_Simulation/gazebo/models volumes: [] entrypoint: [ "/home/pilot/docker-entrypoint.sh" ] command: [ "bash" ]