Docker-orchestrated PX4 SITL + Gazebo Harmonic + ROS 2 Jazzy simulation stack. Pull a pre-built image from Docker Hub and launch with Docker Compose.
| Component | Version |
|---|---|
| Stack release | v3.0.0 |
| PX4-Autopilot | v1.17.0 |
| px4_msgs | v1.17.0 (tag v${PX4_VERSION}) |
| px4_ros_com | main (examples only) |
| ROS 2 | Jazzy |
| Gazebo | Harmonic (gz-harmonic) |
| DDS | CycloneDDS (rmw_cyclonedds_cpp) |
| Micro-XRCE-DDS-Agent | v2.4.3 |
# Allow Docker containers to use the host display (for QGC / RViz)
xhost +local:
# Configure image tag from Docker Hub or a local build
cp .env.example .env
# Start full stack (core + GCS + SLAM + navigation)
CameraType=rgbd World=default ./scripts/up.sh
# Or start only the simulation core
COMPOSE_PROFILES= ./scripts/up.sh| Variable | Description | Default |
|---|---|---|
registry |
Image registry | docker.io/alienkh |
px4TAG |
Image tag in .env |
v3.0.0 |
CameraType |
rgbd or stereo |
rgbd |
World |
Gazebo world filename stem | default |
COMPOSE_PROFILES |
Comma-separated profiles | gcs,slam,nav |
CI publishes tags like v3.0.0 and v3.0.0-latest (GPU: v3.0.0_GPU, v3.0.0-latest_GPU). Update px4TAG in .env after pulling a new build.
| Profile | Services |
|---|---|
| (none) | PX4, StatePublisher |
gcs |
QGroundControl |
slam |
RTAB-Map |
nav |
Nav2 + RViz (use with slam) |
# Simulation + ground station only
COMPOSE_PROFILES=gcs CameraType=rgbd World=apt_world ./scripts/up.sh
# Full robotics stack
COMPOSE_PROFILES=gcs,slam,nav CameraType=rgbd World=default ./scripts/up.sh
# Stereo camera in a custom world
COMPOSE_PROFILES=gcs CameraType=stereo World=husarion_office ./scripts/up.shYou can also set CameraType and World in .env instead of the command line.
World names match SDF filenames under includes/gz/worlds/ (without .sdf):
default— PX4 default worldapt_worldhusarion_officehusarion_worldsonoma_racewayempty_with_plugins
How CameraType and World are applied: scripts/up.sh exports both variables into Compose. The PX4 container runs gz_modifications.bash (camera + custom models/worlds) then gz_start_px4_gz_sim.sh (world/make target). If the slam profile is active, Rtabmap receives the same CameraType.
Changing world or camera on a running stack: These are applied at container start. Bring the stack down first, or recreate PX4:
docker compose -f docker-compose-px4.yml down
CameraType=stereo World=apt_world ./scripts/up.sh
# or: CameraType=stereo World=apt_world docker compose -f docker-compose-px4.yml up -d --force-recreate PX4Verify: docker logs px4_sim 2>&1 | grep "Selected Camera Type"
Profile dependencies: nav depends on slam (Nav2 waits for Rtabmap). Use COMPOSE_PROFILES=slam,nav or include both. Services without a profile (PX4, StatePublisher) always start.
Without up.sh: CameraType=rgbd World=default docker compose -f docker-compose-px4.yml --profile gcs up -d
Display / X11: QGC and RViz need DISPLAY and xhost +local:. Set XAUTH if your setup uses /tmp/.docker.xauth (Compose may warn if unset).
| Service | Container | Role |
|---|---|---|
| PX4 | px4_sim |
SITL, Gazebo, XRCE agent, ros_gz bridge |
| StatePublisher | statePublisher |
x500 TF / URDF |
| Qground | qground |
QGroundControl (gcs) |
| Rtabmap | rtabmap |
SLAM (slam) |
| NAV2 / Nav2_Rviz | nav2, nav2_rviz |
Navigation + RViz (nav) |
Simulation assets and startup scripts live under includes/. See includes/README.md for layout and GitHub automation.
Operational scripts: scripts/README.md (up.sh, smoke_test.sh).
Docker Compose runs multiple containers on a custom bridge network (10.20.10.0/24). The PX4 container bundles SITL, Gazebo, Micro-XRCE-DDS agent, and the ros_gz bridge because ROS 2 discovery across containers requires extra DDS configuration.
Build locally:
./DockerBuild.sh dockerFile/Dockerfile_px4_sim_NO_GPU localGUI apps (QGroundControl, RViz) need X11 forwarding:
sudo apt-get install xauth xorg openbox
xhost +local:PX4 v1.17 with Gazebo Harmonic simulation. Custom models and worlds are overlaid at container start via includes/gz/gz_modifications.bash.
Add a UDP comm link in QGC pointing at the PX4 container hostname px4_sim on ports 14550, 14540, 14580, 18570. MAVLink ports are visible in:
docker logs px4_sim 2>&1 | grep mavlinkBridge config: includes/gz/config_gz_bridge.yaml
CycloneDDS is pre-installed in the image (ros-jazzy-rmw-cyclonedds-cpp).
The PX4 service healthcheck verifies /clock and /fmu/out/vehicle_odometry. RTAB-Map checks /rtabmap/odom. Scripts live in HealthCheck/.
.github/workflows/docker-image.yml builds NO-GPU and GPU images on Dockerfile changes, pushes versioned tags, and runs a headless SITL smoke test on the NO-GPU image.
The following are planned but not in scope for the current non-GPU release:
- GPU compose — docker-compose-px4-GPU.yml needs YAML/env fixes and NVIDIA runtime configuration
- Image slimming — multi-stage builds and optional minimal image without Nav2/RTAB-Map/QGC
- Vagrant host — vagrant/ still targets ROS Humble on Ubuntu 22.04
- Gazebo Classic assets: includes/gazebo_classic/
- DockerRun.sh — legacy single-container workflow; use
scripts/up.shinstead - includes/gz/CMakeLists.txt — legacy PX4 1.15 overlay; PX4 1.17 discovers worlds via upstream
gz_bridgeCMake GLOB after copying SDF files