Production-grade setup guide for PX4 SITL integration with ROS2 Humble and Gazebo Classic using containerized Ubuntu 22.04 environments via Distrobox.
This repository provides comprehensive instructions for establishing a complete autonomous drone simulation stack, enabling MAVLink communication, ROS2 topic interfacing, and high-fidelity physics simulation.
- System Architecture
- Prerequisites
- Installation Methods
- Component Installation
- Integration Configuration
- Verification and Testing
- Advanced Configuration
- Troubleshooting
- API Reference
┌─────────────────────────────────────────────────────────┐
│ Host System │
│ ┌──────────────────┐ ┌─────────────────────┐ `│
│ │ QGroundControl │◄────►│ Display Server │ │
│ │ (MAVLink GCS) │ │ (X11/Wayland) │ │
│ └──────────────────┘ └─────────────────────┘ │
│ ▲ │
│ │ UDP 14550 (MAVLink) │
│ │ │
│ ┌────────┴──────────────────────────────────────────┐ │
│ │ Distrobox Container (Ubuntu 22.04) │ │
│ │ ┌──────────────────────────────────────────┐ │ │
│ │ │ PX4 Autopilot SITL │ │ │
│ │ │ • Flight Controller Firmware │ │ │
│ │ │ • MAVLink Protocol Stack │ │ │
│ │ │ • uORB Message Bus │ │ │
│ │ └─────────┬────────────────────────────────┘ │ │
│ │ │ TCP 4560 (Simulator Protocol) │ │
│ │ ┌─────────▼────────────────────────────────┐ │ │
│ │ │ Gazebo Classic │ │ │
│ │ │ • Physics Engine (ODE/Bullet) │ │ │
│ │ │ • Sensor Simulation │ │ │
│ │ │ • 3D Rendering Pipeline │ │ │
│ │ └─────────┬────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌─────────▼────────────────────────────────┐ │ │
│ │ │ ROS2 Humble │ │ │
│ │ │ • DDS Middleware (FastDDS/CycloneDDS) │ │ │
│ │ │ • px4_msgs Package │ │ │
│ │ │ • MicroXRCE-DDS Agent │ │ │
│ │ └──────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
| Protocol | Port | Direction | Purpose |
|---|---|---|---|
| MAVLink UDP | 14540 | PX4 → QGC | Telemetry, Commands |
| MAVLink UDP | 14550 | PX4 ↔ QGC | Bidirectional Control |
| TCP | 4560 | PX4 ↔ Gazebo | Sensor/Actuator Data |
| DDS/RTPS | 8888 | PX4 ↔ ROS2 | uORB Topics Bridge |
| Component | Minimum | Recommended |
|---|---|---|
| CPU | 4 cores @ 2.0GHz | 8+ cores @ 3.0GHz |
| RAM | 8 GB | 16+ GB |
| Storage | 20 GB free | 50+ GB SSD |
| GPU | Integrated | Dedicated (NVIDIA/AMD) |
Supported Operating Systems:
- Arch Linux, Garuda Linux, Manjaro, EndeavourOS
- Ubuntu 20.04+, Debian 11+, Pop!_OS 22.04+
- Fedora 36+, openSUSE Tumbleweed
Required Package Versions:
- Distrobox: ≥1.4.0
- Podman/Docker: ≥20.10
- Python: ≥3.8
- CMake: ≥3.16
- GCC/G++: ≥9.0
| Host OS | Distrobox | PX4 Version | ROS2 | Gazebo | Status |
|---|---|---|---|---|---|
| Arch | Required | v1.14+ | Humble | Classic 11 | ✓ Tested |
| Ubuntu 22.04 | Optional | v1.14+ | Humble | Classic 11 | ✓ Tested |
| Fedora 36+ | Required | v1.14+ | Humble | Classic 11 | ✓ Tested |
| Debian 11+ | Optional | v1.14+ | Humble | Classic 11 | ⚠ Experimental |
Arch-based distributions (Garuda, Manjaro, EndeavourOS) require Distrobox for Ubuntu 22.04 containerization due to ABI compatibility requirements with PX4's precompiled binaries.
# Update system packages
sudo pacman -Syu
# Install Distrobox and Podman
sudo pacman -S distrobox podman
# Verify installation
distrobox --version
podman --versionExpected Output:
distrobox 1.5.0
podman version 4.8.0
Explanation: Podman provides OCI-compliant container runtime without requiring root privileges. Distrobox creates seamless integration between host and container environments.
# Create named container with Ubuntu 22.04 base image
distrobox create --name ubuntu-px4 --image ubuntu:22.04
# Enter container environment
distrobox enter ubuntu-px4Container Configuration:
- Name:
ubuntu-px4 - Base Image:
docker.io/library/ubuntu:22.04 - Init System: systemd (optional)
- Home Directory: Shared with host (
~/)
# Inside container: Update package repositories
sudo apt update && sudo apt upgrade -y
# Install essential build tools
sudo apt install -y \
build-essential \
git \
wget \
curl \
lsb-release \
gnupg2 \
software-properties-commonUbuntu 22.04 and Debian-based distributions can install components directly on the host system. Distrobox is optional but recommended for environment isolation.
# Update package database
sudo apt update && sudo apt upgrade -y
# Install prerequisites
sudo apt install -y \
build-essential \
cmake \
git \
python3-pip \
wget \
curl \
lsb-releaseFor environment isolation on Debian systems:
# Install Distrobox and Docker
sudo apt install -y distrobox docker.io
# Enable Docker service
sudo systemctl enable --now docker
# Add user to docker group
sudo usermod -aG docker $USER
newgrp docker
# Create container
distrobox create --name ubuntu-px4 --image ubuntu:22.04
distrobox enter ubuntu-px4All subsequent commands assume execution inside the Distrobox container (or directly on Ubuntu 22.04 host).
# Add ROS2 GPG key
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | \
sudo apt-key add -
# Add ROS2 repository
sudo add-apt-repository "deb http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main"
# Update package index
sudo apt update# Install full desktop configuration
sudo apt install -y ros-humble-desktop
# Install development tools
sudo apt install -y \
python3-colcon-common-extensions \
python3-rosdep \
python3-vcstoolPackage Contents:
ros-humble-desktop: Core ROS2 libraries, rclcpp, rclpy, visualization tools (RViz2)python3-colcon: Build system for ROS2 workspacespython3-rosdep: Dependency management utilitypython3-vcstool: Version control system tool for managing repositories
# Initialize rosdep (first-time setup)
sudo rosdep init
rosdep update# Source ROS2 setup script
source /opt/ros/humble/setup.bash
# Add to shell configuration for persistent sourcing
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
source ~/.bashrc# Check ROS2 environment variables
printenv | grep ROS
# Expected output includes:
# ROS_VERSION=2
# ROS_DISTRO=humble
# ROS_PYTHON_VERSION=3
# Test ROS2 installation
ros2 run demo_nodes_cpp talker
# In another terminal:
ros2 run demo_nodes_cpp listener# Create workspace directory
mkdir -p ~/px4_ws
cd ~/px4_ws
# Clone PX4 with submodules
git clone --recursive https://github.com/PX4/PX4-Autopilot.git
cd PX4-Autopilot
# Checkout stable release (optional but recommended)
git checkout v1.14.3
git submodule update --init --recursiveRepository Structure:
PX4-Autopilot/
├── src/ # Core flight stack source code
├── Tools/ # Build and simulation tools
├── platforms/ # Platform-specific implementations
├── msg/ # uORB message definitions
└── ROMFS/ # Root filesystem for embedded targets
# Run automated dependency installation script
# --no-nuttx flag excludes embedded toolchain (SITL only)
bash ./Tools/setup/ubuntu.sh --no-nuttx
# Manual verification of critical dependencies:
python3 --version # Should be ≥3.8
cmake --version # Should be ≥3.16Installed Components:
- Python packages: jinja2, empy, pyros-genmsg, packaging, toml
- Build tools: ninja-build, cmake, ccache
- Libraries: libeigen3-dev, libxml2-utils
- Gazebo integration: libgazebo-dev, gazebo-plugin-base
# Build for software-in-the-loop simulation
make px4_sitl_default
# First build may take 10-15 minutes
# Subsequent builds use ccache for accelerationBuild Targets:
px4_sitl_default: Standard SITL with default configurationpx4_sitl_rtps: SITL with RTPS/DDS enabledpx4_sitl_nolockstep: SITL without lockstep timing
# Launch PX4 SITL (no Gazebo)
make px4_sitl_default none
# Expected output:
# ______ __ __ ___
# | ___ \ \ \ / / / |
# | |_/ / \ V / / /| |
# | __/ / \ / /_| |
# | | / /^\ \ \___ |
# \_| \/ \/ |_/
#
# px4 starting.
# INFO [px4] Startup script: /bin/sh etc/init.d-posix/rcS 0
# pxh>In the pxh> shell, test commands:
pxh> commander status
pxh> param show SYS_AUTOSTART
pxh> shutdown# Add OSRF package repository
sudo sh -c 'echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" > /etc/apt/sources.list.d/gazebo-stable.list'
# Add repository key
wget https://packages.osrfoundation.org/gazebo.key -O - | sudo apt-key add -
# Update and install
sudo apt update
sudo apt install -y gazebo11 libgazebo11-devAlternative (using ROS2 dependencies):
sudo apt install -y ros-humble-gazebo-*# Essential libraries
sudo apt install -y \
libeigen3-dev \
libopencv-dev \
libxml2-dev \
protobuf-compiler \
libprotobuf-dev \
libprotoc-dev \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev# Source Gazebo setup
source /usr/share/gazebo/setup.sh
# Add to shell configuration
echo "source /usr/share/gazebo/setup.sh" >> ~/.bashrc# Launch Gazebo GUI
gazebo --version
# Expected output:
# Gazebo multi-robot simulator, version 11.x.x
# Test Gazebo launch (may take 30-60 seconds first time)
gazebo --verboseTroubleshooting Graphics:
# If using NVIDIA GPU:
export SVGA_VGPU10=0
# If using Intel/AMD integrated graphics:
export LIBGL_ALWAYS_SOFTWARE=1QGroundControl runs on the host system, not inside Distrobox.
# Exit Distrobox if inside
exit
# Download latest AppImage
cd ~/Applications # or ~/Downloads
wget https://d176tv9ibo4jno.cloudfront.net/latest/QGroundControl.AppImage
# Make executable
chmod +x QGroundControl.AppImage
# Run QGroundControl
./QGroundControl.AppImage# Force XWayland compatibility
QT_QPA_PLATFORM=xcb ./QGroundControl.AppImagecat > ~/.local/share/applications/qgroundcontrol.desktop << 'EOF'
[Desktop Entry]
Version=1.0
Type=Application
Name=QGroundControl
Comment=Ground Control Station
Exec=/home/YOUR_USERNAME/Applications/QGroundControl.AppImage
Icon=qgroundcontrol
Terminal=false
Categories=Science;Education;
EOF
# Replace YOUR_USERNAME with actual usernamecd ~/px4_ws/PX4-Autopilot
# Build with Gazebo integration
make px4_sitl gazebo
# This command:
# 1. Builds PX4 firmware
# 2. Launches Gazebo
# 3. Spawns default vehicle (Iris quadcopter)
# 4. Starts PX4 SITL instanceDefault Vehicle Models:
iris: Standard quadcoptertyphoon_h480: Hexacopter with camera gimbalplane: Fixed-wing aircraftstandard_vtol: VTOL (vertical takeoff and landing)
# Launch with specific vehicle
make px4_sitl gazebo_iris
# Launch at specific location (GPS coordinates)
make px4_sitl gazebo_iris__baylands
# Available worlds:
# - empty (default)
# - baylands
# - ksql_airport
# - mcmillan_airfield
# - sonoma_racewayIn Gazebo, you should see:
- Vehicle model loaded
- Propellers spinning slightly (arming state)
In PX4 console (pxh>):
pxh> listener sensor_combined
pxh> listener vehicle_attitude
pxh> listener vehicle_gps_position# Create ROS2 workspace
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
# Clone px4_msgs repository
git clone https://github.com/PX4/px4_msgs.git
# Build workspace
cd ~/ros2_ws
colcon build --packages-select px4_msgs
# Source workspace
source install/setup.bash
echo "source ~/ros2_ws/install/setup.bash" >> ~/.bashrc# Clone Micro-XRCE-DDS-Agent
cd ~/px4_ws
git clone https://github.com/eProsima/Micro-XRCE-DDS-Agent.git
cd Micro-XRCE-DDS-Agent
mkdir build && cd build
# Build agent
cmake ..
make -j$(nproc)
sudo make install
sudo ldconfig /usr/local/lib/cd ~/px4_ws/PX4-Autopilot
# Build PX4 with RTPS client
make px4_sitl_rtps gazeboIn a new terminal:
# Source ROS2 environment
source ~/ros2_ws/install/setup.bash
# Start agent (UDP on port 8888)
MicroXRCEAgent udp4 -p 8888# List available PX4 topics
ros2 topic list | grep fmu
# Expected output:
# /fmu/in/obstacle_distance
# /fmu/in/offboard_control_mode
# /fmu/in/trajectory_setpoint
# /fmu/in/vehicle_command
# /fmu/out/vehicle_attitude
# /fmu/out/vehicle_local_position
# /fmu/out/vehicle_status
# ...
# Echo a topic
ros2 topic echo /fmu/out/vehicle_attitudeQGroundControl automatically detects PX4 SITL on:
- UDP Port: 14550 (default listening port)
- IP: 127.0.0.1 (localhost)
No manual configuration required for local SITL.
If auto-connection fails:
- Open QGroundControl
- Navigate to: Application Settings → Comm Links
- Click Add to create new connection:
- Name: PX4 SITL
- Type: UDP
- Listening Port: 14550
- Target Hosts: 127.0.0.1:14540
- Click OK and Connect
In QGroundControl:
- Main toolbar should show vehicle icon (Iris)
- Altitude indicator should display 0m
- Status text should show "Ready to fly" or "Disarmed"
If connection is unstable, enable MAVLink broadcasting in PX4:
# In PX4 shell (pxh>)
param set MAV_0_BROADCAST 1
param save
rebootcd ~/px4_ws/PX4-Autopilot
make px4_sitl gazebosource ~/ros2_ws/install/setup.bash
MicroXRCEAgent udp4 -p 8888source ~/ros2_ws/install/setup.bash
# Monitor vehicle status
ros2 topic echo /fmu/out/vehicle_status
# Monitor GPS position
ros2 topic echo /fmu/out/vehicle_gps_position# Exit Distrobox if inside
exit
# Run QGC
./QGroundControl.AppImageIn QGroundControl:
-
Arm the vehicle:
- Click Disarmed button
- Slide to Arm
-
Takeoff:
- Click Takeoff button
- Set altitude (e.g., 10m)
- Confirm
-
Observe in Gazebo:
- Vehicle should lift off
- Propellers spinning
- Stabilized hover
-
Monitor ROS2 Data:
# In Terminal 3 ros2 topic echo /fmu/out/vehicle_local_position # Verify z-position increases to ~-10.0 (NED frame)
-
Land:
- Click Land button in QGC
- Vehicle descends and disarms
mkdir -p ~/gazebo_ws/worlds
cd ~/gazebo_ws/worldsCreate custom_world.world:
<?xml version="1.0" ?>
<sdf version="1.6">
<world name="custom_world">
<include>
<uri>model://sun</uri>
</include>
<include>
<uri>model://ground_plane</uri>
</include>
<!-- Add custom models, obstacles, etc. -->
</world>
</sdf>cd ~/px4_ws/PX4-Autopilot
# Set environment variable
export PX4_SITL_WORLD=$HOME/gazebo_ws/worlds/custom_world.world
# Launch
make px4_sitl gazebo# In PX4 shell (pxh>)
param set MC_ROLLRATE_P 0.15
param set MC_PITCHRATE_P 0.15
param save- Copy existing airframe file:
cd ~/px4_ws/PX4-Autopilot/ROMFS/px4fmu_common/init.d-posix/airframes
cp 4001_gz_x500 4999_custom_drone-
Modify parameters in
4999_custom_drone -
Set custom airframe:
param set SYS_AUTOSTART 4999
param save
reboot# Install ccache
sudo apt install -y ccache
# Configure CMake to use ccache
export CC="ccache gcc"
export CXX="ccache g++"
# Rebuild PX4
cd ~/px4_ws/PX4-Autopilot
make clean
make px4_sitl_default# Reduce physics update rate
export GAZEBO_PHYSICS_UPDATE_RATE=250 # Default: 1000
# Disable shadows
export GAZEBO_SHADOWS=0
# Use CPU rendering if GPU issues
export LIBGL_ALWAYS_SOFTWARE=1Issue: fatal error: Eigen/Dense: No such file or directory
Solution:
sudo apt install -y libeigen3-dev
# Create symlink if needed
sudo ln -s /usr/include/eigen3/Eigen /usr/include/EigenIssue: Python module import errors
Solution:
# Reinstall Python dependencies
pip3 install --user --upgrade \
jinja2 \
empy \
packaging \
pyros-genmsg \
tomlIssue: Gazebo crashes with "GLXBadFBConfig" error
Solution:
# Force software rendering
export LIBGL_ALWAYS_SOFTWARE=1
export SVGA_VGPU10=0
gazeboIssue: Black screen in Gazebo
Solution:
# Update graphics drivers (Arch)
sudo pacman -S mesa lib32-mesa vulkan-intel
# Ubuntu
sudo apt install -y mesa-utils libgl1-mesa-driIssue: Gazebo models not loading
Solution:
# Download default Gazebo models
cd ~/
git clone https://github.com/osrf/gazebo_models.git
export GAZEBO_MODEL_PATH=$HOME/gazebo_models:$GAZEBO_MODEL_PATHIssue: MicroXRCE-DDS agent not connecting
Solution:
# Check if port 8888 is in use
sudo netstat -tulpn | grep 8888
# Rebuild PX4 with RTPS
cd ~/px4_ws/PX4-Autopilot
make clean
make px4_sitl_rtps gazebo
# Verify client is running
pxh> microdds_client statusIssue: No ROS2 topics visible
Solution:
# Verify px4_msgs is sourced
source ~/ros2_ws/install/setup.bash
# Check DDS configuration
printenv | grep FASTRTPS
printenv | grep ROS_DOMAIN_ID
# Restart MicroXRCE-DDS agent with verbose logging
MicroXRCEAgent udp4 -p 8888 -v6Issue: QGC not detecting vehicle
Solution:
# In PX4 shell
param show MAV_0_BROADCAST
param set MAV_0_BROADCAST 1
param save
# Check MAVLink streams
mavlink statusIssue: QGC AppImage won't run
Solution:
# Install FUSE
sudo pacman -S fuse2 # Arch
sudo apt install fuse libfuse2 # Ubuntu
# Extract and run
./QGroundControl.AppImage --appimage-extract
./squashfs-root/AppRunIssue: Container creation fails
Solution:
# Use Docker instead of Podman
sudo pacman -S docker
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
# Create container with Docker
distrobox create --name ubuntu-px4 --image ubuntu:22.04 --additional-flags "--runtime docker"Issue: Display not forwarding to container
Solution:
# Enable X11 forwarding
xhost +local:
# Create container with display access
distrobox create --name ubuntu-px4 --image ubuntu:22.04 --additional-flags "-e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix"Common commands in PX4 shell (pxh>):
# System commands
commander status # Flight controller status
param show [NAME] # Show parameter value
param set [NAME] [VALUE] # Set parameter
param save # Save parameters
reboot # Reboot flight controller
# Sensor monitoring
listener sensor_combined # IMU data
listener vehicle_gps_position # GPS data
listener vehicle_attitude # Attitude estimation
# MAVLink
mavlink status # MAVLink stream status
mavlink stream -d /dev/ttyACM0 -s [STREAM] -r [RATE]
# uORB topics
uorb top # Monitor topic update ratesKey PX4 topics in ROS2:
# Sensor outputs
/fmu/out/vehicle_attitude
/fmu/out/vehicle_local_position
/fmu/out/vehicle_gps_position
/fmu/out/sensor_combined
/fmu/out/battery_status
# Control inputs
/fmu/in/offboard_control_mode
/fmu/in/trajectory_setpoint
/fmu/in/vehicle_command
/fmu/in/vehicle_rates_setpoint
# Example: Send offboard command
ros2 topic pub /fmu/in/offboard_control_mode px4_msgs/msg/OffboardControlMode "{
timestamp: 0,
position: true,
velocity: false,
acceleration: false
}"Common MAVLink messages:
- HEARTBEAT (ID: 0): System status
- ATTITUDE (ID: 30): Roll, pitch, yaw
- GLOBAL_POSITION_INT (ID: 33): GPS position
- COMMAND_LONG (ID: 76): Execute command
| System | CPU | Cores | Initial Build | Incremental |
|---|---|---|---|---|
| Arch Linux | Ryzen 7 5800X | 16 | 8m 32s | 45s |
| Ubuntu 22.04 | i7-10750H | 12 | 12m 18s | 1m 12s |
| Fedora 36 | i5-9300H | 8 | 15m 47s | 1m 35s |
| Vehicle | Physics Rate | Render FPS | CPU Usage | RAM Usage |
|---|---|---|---|---|
| Iris (quadcopter) | 1000 Hz | 60 | 35% | 2.1 GB |
| Plane | 1000 Hz | 60 | 28% | 1.8 GB |
| Standard VTOL | 1000 Hz | 45 | 42% | 2.4 GB |
Contributions are welcome. Please follow these guidelines:
Include the following information:
- Operating system and version
- PX4 commit hash (
git rev-parse HEAD) - ROS2 version (
ros2 --version) - Gazebo version (
gazebo --version) - Full error logs
- Steps to reproduce
- Fork the repository
- Create feature branch (
git checkout -b feature/enhancement) - Follow existing code style and documentation format
- Test changes on at least one Arch-based and one Debian-based system
- Update README with any new procedures
- Submit pull request with detailed description
- PX4 Autopilot: https://docs.px4.io/
- ROS2 Humble: https://docs.ros.org/en/humble/
- Gazebo Classic: https://classic.gazebosim.org/
- MAVLink Protocol: https://mavlink.io/en/
- QGroundControl: https://docs.qgroundcontrol.com/
- Meier, L., et al. (2015). "PIXHAWK: A micro aerial vehicle design for multi-modal applications." Autonomous Robots
- Furrer, F., et al. (2016). "RotorS—A Modular Gazebo MAV Simulator Framework." Robot Operating System (ROS)
- PX4 Discuss: https://discuss.px4.io/
- ROS Discourse: https://discourse.ros.org/
- Gazebo Community: https://community.gazebosim.org/
This project is licensed under the MIT License. See LICENSE file for details.
- PX4 Development Team
- Open Robotics (ROS2 and Gazebo)
- Distrobox maintainers
- MAVLink protocol contributors
Author: Nagaraj S Bhat
Contact: nagarajsbhat12@gmail.com
Repository: https://github.com/Nags016/PX4-ROS2-Gazebo-setup-guide
Last Updated: January 2026