DUDuuu.studio

Back

Introduction#

PX4, as one of the most popular open-source flight controllers worldwide, provides convenience for developers in drone design and control. ROS, as a robot operating system, simplifies the drone formation simulation workflow through its distributed communication architecture, while the Gazebo physics simulation engine provides a realistic simulation environment.

ROS has now been updated to ROS2, which offers greater applicability and maintainability compared to ROS1. There are currently few ROS2+PX4 simulation tutorials available, and continuous updates of both platforms bring many environment configuration challenges. This article provides a personal development workflow.

ROS2+PX4 simulation system architecture
Figure 1: ROS2+PX4 simulation system architecture

Installing Ubuntu#

This environment is built on Ubuntu 22.04. You can install it as a virtual machine or set up a dual-boot system alongside Windows. Here is a video tutorial for installing Ubuntu 22.04 as a dual-boot system on Windows 11:

Now we begin the environment setup process. For reference, here is another developer’s workflow that is similar to ours and quite concise. If you only need single-drone simulation, this tutorial is also a good reference:

Note: Before starting the following steps, ensure you have reliable internet access (with proper network tools if needed), otherwise cloning repositories from GitHub may fail midway.

Downloading & Compiling PX4 Source#

First, clone the PX4 source code from GitHub and update all submodules:

git clone https://github.com/PX4/PX4-Autopilot.git --recursive
bash

Since the subsequent environment setup will install many packages, and it may be difficult to fully clean them up if something goes wrong, it is recommended to back up the ~/PX4-Autopilot directory at this point, so you don’t need to re-clone the entire repository if the environment needs a fresh start:

zip -r PX4-Autopilot.zip PX4-Autopilot/
bash

Next, install the required dependencies:

bash ./PX4-Autopilot/Tools/setup/ubuntu.sh
bash

At this point, the PX4 source code is downloaded and all dependencies are installed. We can now try compiling and launching the simulation:

cd ~/PX4-Autopilot/
make px4_sitl         # Build the SITL firmware first (required!)
make px4_sitl jmavsim # Once built, launch jmavsim
bash

Common error: If you run make px4_sitl jmavsim directly and encounter ninja: error: unknown target 'jmavsim', it means the PX4 CMake/Ninja build system hasn’t generated the jmavsim target yet. You must run make px4_sitl first to complete the initial build, then make px4_sitl jmavsim to launch the simulator. After this first-time setup, make px4_sitl jmavsim will work directly.

You will see the PX4 source code compile and the jmavsim physics simulation engine start up. This works because the ubuntu.sh dependency script already installed jmavsim and Gazebo-classic for us. If you see green ready for takeoff text in the terminal and the jmavsim window appears, compilation is successful. If this step fails, check your network tools.

Now press Enter in the terminal, and at the pxh> prompt, enter PX4 commands:

commander takeoff/land/shutdown
plaintext

These commands control the drone’s takeoff, landing, and shutdown of the simulation. You should see the drone taking off and landing in the jmavsim UI. At this point, the PX4 source download and compilation are complete.

Green ready for takeoff prompt
Figure 2: Green "ready for takeoff" prompt -- press Enter and type takeoff command
Drone taking off in jmavsim UI
Figure 3: Drone taking off in jmavsim UI

We use ROS2 Humble for development. The installation and environment configuration for ROS2 and its dependencies can be somewhat tedious, so I strongly recommend using the “FishROS” one-click installation tool. Many thanks to FishROS for providing this convenience for the ROS community. Simply run the following command in your Ubuntu terminal and follow the on-screen instructions:

wget http://fishros.com/install -O fishros && . fishros
bash

The one-click installation tool also includes options for Docker and other tools — feel free to install them as needed. Again, many thanks. Additionally, developers using the ROS2 Foxy distribution can also use this tool for installation and environment configuration.

Installing Gazebo Sim 8.9.0#

According to the official PX4 documentation, the former Gazebo Ignition has been renamed to Gazebo, and the old Gazebo is now called Gazebo-classic. Ubuntu 22.04 supports the Gazebo (Ignition) series. When we installed PX4 dependencies earlier, ubuntu.sh automatically installed jmavsim and Gazebo-classic, but for multi-drone simulation we need Gazebo Harmonic (v8.x, i.e., Gazebo Sim 8.9.0).

Important: The Gazebo version and the ROS2 bridge package must match. Mixing multiple versions is the primary cause of environment crashes. Gazebo Garden (v7), Harmonic (v8), and Ionic (v9) cannot coexist.

First, add the OSRF repository and install Gazebo Harmonic:

cd ~/PX4-Autopilot
sudo apt install wget
sudo wget https://packages.osrfoundation.org/gazebo.gpg -O /usr/share/keyrings/pkgs-osrf-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/pkgs-osrf-archive-keyring.gpg] http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/gazebo-stable.list > /dev/null
sudo apt update
sudo apt-get install gz-harmonic
bash

Then install the corresponding Gazebo-ROS2 communication bridge (Harmonic maps to gzharmonic):

sudo apt install ros-humble-ros-gzharmonic
bash

After installation, verify version uniqueness (only one version number should appear):

gz sim --versions   # Should only show 8.9.0
bash

Common mistake: Do not install gz-garden or ros-humble-ros-gzgarden. That is Gazebo Garden (v7), which is incompatible with PX4’s current gz-sim8 compilation target.

Gazebo Sim 8 icon in Ubuntu
Figure 4: Once the Gazebo Sim 8 icon appears in Ubuntu, you are good to go

Installing MicroXRCE-DDS Agent#

According to the official documentation, in ROS2, PX4 uses the uXRCE-DDS middleware to allow publishing and subscribing to uORB messages on the companion computer, replacing MAVROS. We follow the official example to download, compile, and install.

uXRCE-DDS communication diagram
Figure 5: uXRCE-DDS communication diagram

Download the source:

git clone -b v2.4.2 https://github.com/eProsima/Micro-XRCE-DDS-Agent.git
bash

Compile:

cd Micro-XRCE-DDS-Agent
mkdir build
cd build
cmake ..
make
bash

There will likely be a build error here. Go to build/fastdds/tmp/fastdds-gitclone.cmake, change 2.12.x to v2.12.1, then re-run make.

The compilation process takes a while, so be patient. After compilation finishes, install:

sudo make install
sudo ldconfig /usr/local/lib/
bash

Installing QGC Ground Station#

When starting the PX4+Gazebo simulation, losing connection to the ground station will prevent PX4 from controlling the drone. Therefore, you need to install QGC Ground Station. Here is a CSDN guide that walks through the steps:

Single Drone Offboard Test and Development Guide#

All development environment components are now set up. Let’s verify PX4 Offboard mode.

Offboard mode is a special flight mode in PX4 that allows external systems (such as companion computers, ROS2 nodes, etc.) to send control commands directly via MAVLink or uXRCE-DDS, enabling real-time control of the drone’s attitude, position, or velocity for autonomous flight or advanced missions.

First, create a ROS2 workspace:

mkdir -p ~/ros2_ws/src
bash

Then download the source code (make sure your network is working):

cd ~/ros2_ws/src
git clone https://github.com/PX4/px4_msgs.git -b release/1.14
git clone https://github.com/PX4/px4_ros_com.git -b release/v1.14
bash

Compile:

cd ~/ros2_ws
colcon build
bash

Update environment and configure environment variables:

echo "source ~/ros2_ws/install/setup.bash" >> ~/.bashrc
echo "export GZ_SIM_RESOURCE_PATH=\$HOME/.simulation-gazebo/models:\$GZ_SIM_RESOURCE_PATH" >> ~/.bashrc
source ~/.bashrc
bash

Launching the Offboard Simulation#

Now we start the Offboard simulation. First, open the already installed QGC Ground Station.

Terminal 1 — Start communication:

MicroXRCEAgent udp4 -p 8888
bash
uXRCE-DDS Agent connected successfully
Figure 6: uXRCE-DDS Agent connected successfully

Terminal 2 — Start simulation:

cd ~/PX4-Autopilot
make px4_sitl gz_x500
bash

At this point, the ground station will connect to PX4, Gazebo will launch, and the x500 drone will appear. When the PX4 terminal shows green ready for takeoff, the simulation has started successfully. We will explain this make-based simulation startup in more detail in the multi-drone simulation section.

Terminal showing QGC connected, green ready for takeoff
Figure 7: Terminal showing successful QGC connection, green "ready for takeoff", PX4 started successfully
Single drone in Gazebo
Figure 8: Single drone appearing in Gazebo

Terminal 3 — Run Offboard control source:

ros2 run px4_ros_com offboard_control
bash

You should see the drone ascend 5 meters in Gazebo, confirming Offboard mode control is successful.

Offboard control mode successful
Figure 9: Offboard control mode successful

Offboard Mode Development Workflow#

In the ~/ros2_ws workspace we just created, navigate to the px4_ros_com directory and open CMakeLists.txt. Find these three lines:

add_executable(offboard_control src/examples/offboard/offboard_control.cpp)
ament_target_dependencies(offboard_control rclcpp px4_msgs)
install(TARGETS offboard_control DESTINATION lib/${PROJECT_NAME})
cmake

This compiles offboard_control.cpp from src/examples/offboard into an executable named offboard_control, with its dependency on px4_msgs. You can open the src/examples/offboard directory to find the offboard_control.cpp source code.

C++ code for Offboard ascent of 5 meters -- use as base for custom control logic
Figure 10: This C++ code implements the Offboard 5-meter ascent -- use it as a base for your own control logic

Therefore, to develop single-drone Offboard mode simulations, follow this workflow:

  1. Inside the already created and configured ~/ros2_ws ROS2 workspace, create a new package (at the same level as the px4_ros_com directory).
  2. In the new package, write your Offboard mode control code (C++/Python) under the /src directory.
  3. In the new package’s CMakeLists.txt, find these lines:
add_executable(offboard_control src/examples/offboard/offboard_control.cpp)
ament_target_dependencies(offboard_control rclcpp px4_msgs)
install(TARGETS offboard_control DESTINATION lib/${PROJECT_NAME})
cmake

Change the path to the location of your C++/Python code, and give it an executable name. Before running the simulation, you must recompile the ROS2 workspace!

cd ~/ros2_ws
colcon build
bash

Finally, following the earlier method, open QGC Ground Station, start communication and simulation, then open a new terminal and run:

ros2 run <package_name> <executable_name>
bash

If you see the drone flying according to your code logic in Gazebo, the simulation is successful.


Supplementary Notes#

Supplement 1: When using the make px4_sitl gz_x500 command to start the simulation, the automatically launched gz sim simulator world is the default world. Its sdf file is no longer in ~/.gz/worlds, but in ./PX4-Autopilot/Tools/simulation/gz/worlds. Similarly, all models are also located under Tools/simulation. Therefore, when building your simulation environment, you should go to these directories to directly modify the sdf files.

Supplement 2: When writing C++/Python code for Offboard mode control, pay attention to coordinate system transformations. In PX4, the coordinate system is NED (North-East-Down), meaning the x-axis points north, the y-axis points east, and the z-axis points down (all altitudes are negative). In Gazebo Ignition (now Gazebo), the coordinate system is ENU (East-North-Up), meaning the x-axis points east, the y-axis points north, and the z-axis points up (altitudes are positive). Make sure to account for coordinate conversions when writing your control logic.

At this point, the basic workflow for ROS2+PX4 single-drone Offboard mode simulation is fully covered. If you have successfully run through the above workflow, you can now proceed with further single-drone simulation development.

Multi-Drone (Formation) Development Workflow#

In the previous section, we completed the single-drone simulation environment setup using ROS2+PX4. Now we proceed to the multi-drone environment setup in preparation for formation control logic simulation.

Reviewing Single-Drone Startup#

Let’s first review the primary command for starting a single-drone simulation:

cd ~/PX4-Autopilot
make px4_sitl gz_x500
bash

This make command actually performs three tasks:

  1. Compiles the PX4 source code
  2. Starts PX4
  3. Launches the Gazebo simulation

However, for multi-drone simulation, we cannot simply run make repeatedly — that would cause each x500 drone to launch its own separate Gazebo instance, which is not what we want. Therefore, for multi-drone simulation in the Gazebo environment, our goals are:

  1. Start Gazebo simulation separately
  2. Launch PX4 instances individually, adding drones to the Gazebo environment
  3. Establish communication

Starting Gazebo Separately#

First, we need to download the Gazebo launch script (simulation-gazebo):

wget https://raw.githubusercontent.com/PX4/PX4-gazebo-models/main/simulation-gazebo
bash

Then, in the directory where the script is located, run:

python3 simulation-gazebo
bash

Troubleshooting: If the Gazebo window fails to open (crash or black screen), it’s usually due to incompatible GPU drivers or a VM without GPU passthrough. Prefix the command with LIBGL_ALWAYS_SOFTWARE=1 to force CPU software rendering:

LIBGL_ALWAYS_SOFTWARE=1 python3 simulation-gazebo
bash

This environment variable tells Mesa/OpenGL to use the LLVMpipe software rasterizer instead of hardware GPU acceleration. The tradeoff is lower frame rate, but simulation functionality is unaffected.

The first time you run the script, it will download some components into .simulation-gazebo (use Ctrl+H in your home directory to reveal hidden folders). The /worlds/default.sdf file inside is the simulation world sdf file — you will modify this file later.

Supplement 3: Note the distinction from Supplement 1 in the single-drone simulation section. This is a significant difference between single-drone and multi-drone setup. When starting a single-drone simulation, we use the make command, and the world sdf file is in ./PX4-Autopilot/Tools/simulation/gz/worlds. However, if you examine the simulation-gazebo.py script we downloaded for multi-drone simulation, you will find that the world sdf file is under .simulation-gazebo. Make sure to distinguish between these two.

Adding Multiple Drones#

After starting the Gazebo environment separately, we add drones to it. This time we do not use the make command, but the following command instead:

cd ~/PX4-Autopilot
PX4_GZ_STANDALONE=1 PX4_SYS_AUTOSTART=4001 PX4_GZ_MODEL_POSE="0,2" PX4_SIM_MODEL=gz_x500 ./build/px4_sitl_default/bin/px4 -i 0
bash

Parameter explanation:

ParameterDescription
PX4_GZ_STANDALONE=1Use standalone mode (start only PX4 without launching its own simulation, connect to the separately started simulation)
PX4_SYS_AUTOSTART=4001Required airframe configuration field
PX4_GZ_MODEL_POSE="0,2"Initial drone position — different drones should have different positions
PX4_SIM_MODEL=gz_x500Drone model is x500
-i 0Drone instance ID (ID 0)

After running this command, you should see a drone appear in the previously launched Gazebo window.

Now add a second drone (ID -i 1, position "0,1"):

PX4_GZ_STANDALONE=1 PX4_SYS_AUTOSTART=4001 PX4_GZ_MODEL_POSE="0,1" PX4_SIM_MODEL=gz_x500 ./build/px4_sitl_default/bin/px4 -i 1
bash

To add more drones, follow the same pattern, or write a unified script to add them all at once.

Now you should see two drones side by side in Gazebo. In each drone’s PX4 terminal, you can enter:

commander takeoff/land
plaintext

to observe each drone’s takeoff and landing. Finally, add the communication:

MicroXRCEAgent udp4 -p 8888
bash
Successfully started Gazebo simulation with two drones and communication, PX4 terminals controlling takeoff and landing
Figure 11: Successfully started Gazebo simulation with two drones, communication established, takeoff and landing controlled via PX4 terminals

At this point, the entire environment setup for ROS2+PX4 single-drone and multi-drone simulation in Gazebo is complete. In the next article, we build on this environment to implement ROS2+PX4 Multi-Drone Offboard Control, achieving dual-drone formation flight using a leader-follower algorithm. Beyond that, you can also pursue target recognition, path planning, and many other projects. The first step is always the hardest — I hope this article can contribute even a small amount to research in this direction.

If you still encounter simulation issues, please refer to the official PX4 documentation and related GitHub projects. Also, if you’re interested in Betaflight, check out the Betaflight + Gazebo SITL Tutorial for an alternative SITL simulation approach. Environment configuration and workflow familiarization is a simple but tedious process. As a beginner, I have provided my personal development workflow, and there are certainly better approaches out there. Corrections and suggestions for better methods are always welcome — they will help those who come after us.

Gazebo Environment Troubleshooting Guide#

Based on bugs reported over the past year, here is a summary of troubleshooting and repair methods for dependency conflicts caused by multiple coexisting Gazebo versions.

1. Check Which Gazebo Versions Are Installed#

# List all Gazebo-related packages
dpkg -l | grep -E "^ii" | awk '{print $2}' | grep -E "^gz-|^libgz-|^sdformat|^libsdformat|python3-gz" | sort

# Check available Gazebo Sim versions (multiple versions = conflict)
gz sim --versions

# Check the current default version
gz sim --version
bash

Healthy state: gz sim --versions should output only one version number (e.g., 8.9.0), and all libgz-*-X should have the same major version (e.g., all 7 or all 8).

2. Typical Symptoms of Version Conflicts#

# Symptom 1: Multiple versions coexist
gz sim --versions
# Output:
# 8.9.0
# 7.9.0        ← Garden and Harmonic coexist -- conflict!

# Symptom 2: CMake finds the wrong version
grep "gz-sim_DIR" ~/PX4-Autopilot/build/px4_sitl_default/CMakeCache.txt
# Should match gz sim --version: Harmonic → gz-sim8, Garden → gz-sim7

# Symptom 3: ROS2 bridge package version mismatch
dpkg -l | grep ros-humble-ros-gz
# Should only have gzharmonic or only gzgarden, not both simultaneously
bash

3. Fix: Unify to a Single Gazebo Version#

Using Harmonic (v8) as an example (recommended for ROS2 Humble, as it has a corresponding bridge package):

# 1. Remove all Garden (v7) packages
sudo apt-get purge -y gz-garden gz-sim7-cli gz-launch6-cli gz-transport12-cli \
  libgz-sim7 libgz-sim7-dev libgz-sim7-plugins \
  libgz-launch6 libgz-launch6-dev \
  libgz-transport12 libgz-transport12-dev \
  libgz-fuel-tools8 libgz-fuel-tools8-dev \
  libgz-gui7 libgz-gui7-dev \
  libgz-msgs9 libgz-msgs9-dev \
  libgz-physics6 libgz-physics6-dev \
  libgz-rendering7 libgz-rendering7-dev \
  libgz-sensors7 libgz-sensors7-dev \
  libsdformat13 libsdformat13-dev sdformat13-sdf \
  python3-gz-sim7

# 2. Remove Garden ROS2 bridge
sudo apt-get purge -y ros-humble-ros-gzgarden*

# 3. Install Harmonic ROS2 bridge
sudo apt-get install -y ros-humble-ros-gzharmonic

# 4. Verify
gz sim --versions  # Should only show 8.9.0
dpkg -l | grep gz-garden    # Should output nothing
dpkg -l | grep gz-harmonic  # Should show as installed
bash

4. Common .bashrc Issues#

# Problem 1: Duplicate source entries (repeated appending inflates PATH)
grep "source.*setup.bash" ~/.bashrc | sort | uniq -c
# If any line appears more than once, manually clean up ~/.bashrc

# Problem 2: Incorrect ROS2 loading order
# Correct order: source /opt/ros/humble/setup.bash first, then source ~/ros2_ws/install/setup.bash
# The workspace overlay must come after the base environment

# Problem 3: Model path variable
# Gazebo Garden/Harmonic use GZ_SIM_RESOURCE_PATH, not GAZEBO_MODEL_PATH
echo $GZ_SIM_RESOURCE_PATH  # Should point to your model directory
bash

5. Check if PX Build Target Matches Gazebo Version#

# PX4 CMake cache records the gz-sim version
grep "gz-sim_DIR" ~/PX4-Autopilot/build/px4_sitl_default/CMakeCache.txt
# gz-sim8 → Harmonic
# gz-sim7 → Garden

# If the version does not match the installed Gazebo, recompile PX4:
cd ~/PX4-Autopilot
make clean
make px4_sitl gz_x500
bash

6. Check ROS2 Bridge Package Dependencies#

# Confirm the bridge package's SDFormat dependency matches the Gazebo version
apt-cache depends ros-humble-ros-gzharmonic | grep sdformat
# Harmonic → libsdformat14-dev

# Confirm no residual Garden bridge packages
dpkg -l ros-humble-ros-gzgarden* 2>/dev/null
# Should show "no packages found" or status "un" (uninstalled)
bash

References#

ROS2+PX4 Drone Formation Simulation Setup Guide
https://duduuu.xyz/en/posts/px4-ros2-gazebo-simulation
Author dudu
Published at 2026年7月09日
阅读
总访问