Starting PX4 SITL with a separate Gazebo Sim

I’m trying to start the px4_sitl after running the gazebo sim separately, either through gz sim or ros2 launch ros_gz_sim. I want to do it so that I could launch it with other robots, not only px4-enabled ones.

I’m using Ubuntu 24.04, ROS Jazzy, Gazebo Harmonic and the main branch of PX4-Autopilot.

I changed two environment variables so that other errors would be resolved:

export GZ_SIM_RESOURCE_PATH=$GZ_SIM_RESOURCE_PATH:$HOME/PX4-Autopilot/Tools/simulation/gz/models:
export GZ_SIM_SYSTEM_PLUGIN_PATH=$GZ_SIM_SYSTEM_PLUGIN_PATH:$HOME/PX4-Autopilot/build/px4_sitl_default/src/modules/simulation/gz_plugins

The drone spawns on the world, but doesn’t pass health checks, probably due to a lack of working sensor links.

Output from make px4_sitl gz_x500:

[0/1] cd /home/igorazevedo/PX4-Autopil...topilot/build/px4_sitl_default/bin/px4

______  __   __    ___ 
| ___ \ \ \ / /   /   |
| |_/ /  \ V /   / /| |
|  __/   /   \  / /_| |
| |     / /^\ \ \___  |
\_|     \/   \/     |_/

px4 starting.

INFO  [px4] startup script: /bin/sh etc/init.d-posix/rcS 0
INFO  [init] found model autostart file as SYS_AUTOSTART=4001
INFO  [param] selected parameter default file parameters.bson
INFO  [param] importing from 'parameters.bson'
INFO  [parameters] BSON document size 464 bytes, decoded 464 bytes (INT32:17, FLOAT:6)
INFO  [param] selected parameter backup file parameters_backup.bson
  SYS_AUTOCONFIG: curr: 0 -> new: 1
+ SYS_AUTOSTART: curr: 4014 -> new: 4001
  SENS_BOARD_X_OFF: curr: 0.0000 -> new: 0.0000
  SENS_DPRES_OFF: curr: 0.0000 -> new: 0.0010
INFO  [dataman] data manager file './dataman' size is 1208528 bytes
INFO  [init] Gazebo simulator 8.10.0
INFO  [init] gazebo already running world: empty
INFO  [init] Gazebo world is ready
INFO  [init] Spawning Gazebo model
INFO  [gz_bridge] world: empty, model: x500_0
INFO  [commander] LED: open /dev/led0 failed (22)
INFO  [uxrce_dds_client] init UDP agent IP:127.0.0.1, port:8888
INFO  [mavlink] mode: Normal, data rate: 4000000 B/s on udp port 18570 remote port 14550
INFO  [mavlink] mode: Onboard, data rate: 4000000 B/s on udp port 14580 remote port 14540
INFO  [mavlink] mode: Onboard, data rate: 4000 B/s on udp port 14280 remote port 14030
INFO  [mavlink] mode: Gimbal, data rate: 400000 B/s on udp port 13030 remote port 13280
INFO  [logger] logger started (mode=all)
INFO  [logger] Start file log (type: full)
INFO  [logger] [logger] ./log/2025-11-25/18_08_25.ulg	
INFO  [logger] Opened full log file: ./log/2025-11-25/18_08_25.ulg
INFO  [mavlink] MAVLink only on localhost (set param MAV_{i}_BROADCAST = 1 to enable network)
INFO  [mavlink] MAVLink only on localhost (set param MAV_{i}_BROADCAST = 1 to enable network)
INFO  [px4] Startup script returned successfully
pxh> commander arm
pxh> WARN  [commander] Arming denied: Resolve system health failures first	
INFO  [mavlink] partner IP: 127.0.0.1
ERROR [mavlink] vehicle_command_ack lost, generation 3 -> 16
ERROR [mavlink] vehicle_command_ack lost, generation 3 -> 27
ERROR [mavlink] vehicle_command_ack lost, generation 3 -> 27
ERROR [mavlink] vehicle_command_ack lost, generation 20 -> 27
ERROR [mavlink] vehicle_command_ack lost, generation 3 -> 27
WARN  [health_and_arming_checks] Too many arming check events (1, 14 > 14). Not reporting all
WARN  [health_and_arming_checks] Preflight Fail: Accel Sensor 0 missing
WARN  [health_and_arming_checks] Preflight Fail: barometer 0 missing
WARN  [health_and_arming_checks] Preflight Fail: ekf2 missing data
WARN  [health_and_arming_checks] Preflight Fail: Gyro Sensor 0 missing
WARN  [health_and_arming_checks] Preflight Fail: Found 0 compass (required: 1)
WARN  [health_and_arming_checks] Preflight Fail: system power unavailable
WARN  [health_and_arming_checks] Preflight Fail: No connection to the GCS

Output from ros2 launch ros_gz_sim gz_sim.launch.py gz_args:=empty.sdf, after px4_sitl is started:

[INFO] [launch]: All log files can be found below /home/igorazevedo/.ros/log/2025-11-25-15-08-12-363450-RazorCedra-95147
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [gazebo-1]: process started with pid [95150]
[gazebo-1] libEGL warning: egl: failed to create dri2 screen
[gazebo-1] Warning [Utils.cc:132] [/sdf/model[@name="x500_base"]/link[@name="base_link"]/sensor[@name="air_pressure_sensor"]/gz_frame_id:/home/igorazevedo/PX4-Autopilot/Tools/simulation/gz/models/x500_base/model.sdf:L219]: XML Element[gz_frame_id], child of element[sensor], not defined in SDF. Copying[gz_frame_id] as children of [sensor].
[gazebo-1] Warning [Utils.cc:132] [/sdf/model[@name="x500_base"]/link[@name="base_link"]/sensor[@name="magnetometer_sensor"]/gz_frame_id:/home/igorazevedo/PX4-Autopilot/Tools/simulation/gz/models/x500_base/model.sdf:L233]: XML Element[gz_frame_id], child of element[sensor], not defined in SDF. Copying[gz_frame_id] as children of [sensor].
[gazebo-1] Warning [Utils.cc:132] [/sdf/model[@name="x500_base"]/link[@name="base_link"]/sensor[@name="imu_sensor"]/gz_frame_id:/home/igorazevedo/PX4-Autopilot/Tools/simulation/gz/models/x500_base/model.sdf:L259]: XML Element[gz_frame_id], child of element[sensor], not defined in SDF. Copying[gz_frame_id] as children of [sensor].
[gazebo-1] Warning [Utils.cc:132] [/sdf/model[@name="x500_base"]/link[@name="base_link"]/sensor[@name="navsat_sensor"]/gz_frame_id:/home/igorazevedo/PX4-Autopilot/Tools/simulation/gz/models/x500_base/model.sdf:L311]: XML Element[gz_frame_id], child of element[sensor], not defined in SDF. Copying[gz_frame_id] as children of [sensor].
[gazebo-1] Warning [Utils.cc:132] [/sdf/model[@name="x500"]/link[@name="base_link"]/sensor[@name="air_pressure_sensor"]/gz_frame_id:<data-string>:L232]: XML Element[gz_frame_id], child of element[sensor], not defined in SDF. Copying[gz_frame_id] as children of [sensor].
[gazebo-1] Warning [Utils.cc:132] [/sdf/model[@name="x500"]/link[@name="base_link"]/sensor[@name="magnetometer_sensor"]/gz_frame_id:<data-string>:L254]: XML Element[gz_frame_id], child of element[sensor], not defined in SDF. Copying[gz_frame_id] as children of [sensor].
[gazebo-1] Warning [Utils.cc:132] [/sdf/model[@name="x500"]/link[@name="base_link"]/sensor[@name="imu_sensor"]/gz_frame_id:<data-string>:L301]: XML Element[gz_frame_id], child of element[sensor], not defined in SDF. Copying[gz_frame_id] as children of [sensor].
[gazebo-1] Warning [Utils.cc:132] [/sdf/model[@name="x500"]/link[@name="base_link"]/sensor[@name="navsat_sensor"]/gz_frame_id:<data-string>:L306]: XML Element[gz_frame_id], child of element[sensor], not defined in SDF. Copying[gz_frame_id] as children of [sensor].

On QGroundControl, it says the drone is “Not Ready” and this message pops up after trying to inspect it:

It looks like the sensors aren’t getting initialized properly, but I’m not sure if I should source some file or add some config from the px4 to the gazebo launch.

So my question is: Is it possible to setup the px4_sitl configuration so that a completely separate gazebo simulation is able to access the files and configurations?

Hi Igor, you can use the standalone mode launch in the PX4 software.

You are seeing the COM_DL_LOSS_T and Not Ready errors in QGroundControl. This usually happens because the generic Gazebo instance (launched via ROS 2) can’t see the specific PX4 MAVLink plugins, so PX4 never connects to the the drone model.

Even though you manually exported the paths, it is much safer to source the simulation setup script provided by PX4 inside the terminal where you launch ROS.

Here is the workflow that should help you:

  1. Build PX4 once (to generate the environment scripts) If you haven’t already built the target at least once, run this:
cd ~/PX4-Autopilot
make px4_sitl gz_x500
# You can Ctrl+C to stop it once Gazebo launches successfully.
  1. Terminal 1: ROS 2 / Gazebo

We need to setup the environment variables here so Gazebo can find the libgz-sim-mavlink-system.so plugin when ROS launches it.

cd ~/PX4-Autopilot
# Source the generated environment file
source build/px4_sitl_default/rootfs/gz_env.sh

# Now launch your ROS/Gazebo instance
ros2 launch ros_gz_sim gz_sim.launch.py gz_args:="-r empty.sdf"
  1. Terminal 2: PX4 SITL

Now we launch PX4 in “Standalone” mode so it connects to the simulation running in Terminal 1 instead of trying to start a new one.

cd ~/PX4-Autopilot
export PX4_GZ_STANDALONE=1
make px4_sitl gz_x500

The PX4_GZ_STANDALONE=1 variable prevents the make command from killing your ROS simulation. Sourcing the setup_gz.bash ensures that when the drone spawns, the sensors and MAVLink interface load correctly, which should clear up the “health check” errors you are seeing.

Hope this helps.

1 Like

Hello Rodrigo, thank you for your reply.

It worked! But I had to change the world I was using.

By using the empty.sdf world,a different problem appeared. When starting the px4_sitl in standalone mode, it gets stuck trying to connect to the Gazebo world. Here’s the output:

INFO  [px4] startup script: /bin/sh etc/init.d-posix/rcS 0
INFO  [init] found model autostart file as SYS_AUTOSTART=4001
INFO  [param] selected parameter default file parameters.bson
INFO  [param] importing from 'parameters.bson'
INFO  [parameters] BSON document size 444 bytes, decoded 444 bytes (INT32:16, FLOAT:6)
INFO  [param] selected parameter backup file parameters_backup.bson
  SYS_AUTOCONFIG: curr: 0 -> new: 1
+ SYS_AUTOSTART: curr: 4014 -> new: 4001
  SENS_BOARD_X_OFF: curr: 0.0000 -> new: 0.0000
  SENS_DPRES_OFF: curr: 0.0000 -> new: 0.0010
INFO  [dataman] data manager file './dataman' size is 1208528 bytes
INFO  [init] Gazebo simulator 8.10.0
INFO  [init] Standalone PX4 launch, waiting for Gazebo
INFO  [init] Waiting for Gazebo world...
INFO  [init] Waiting for Gazebo world...
 .
 .
 .
INFO  [init] Waiting for Gazebo world...
INFO  [init] Waiting for Gazebo world...
ERROR [init] Timed out waiting for Gazebo world
ERROR [px4] Startup script returned with return value: 256
FAILED: src/modules/simulation/gz_bridge/CMakeFiles/gz_x500 /home/igorazevedo/PX4-Autopilot/build/px4_sitl_default/src/modules/simulation/gz_bridge/CMakeFiles/gz_x500 
cd /home/igorazevedo/PX4-Autopilot/build/px4_sitl_default/src/modules/simulation/gz_bridge && /usr/bin/cmake -E env PX4_SIM_MODEL=gz_x500 GZ_IP=127.0.0.1 /home/igorazevedo/PX4-Autopilot/build/px4_sitl_default/bin/px4
ninja: build stopped: subcommand failed.
make: *** [Makefile:227: px4_sitl] Error 1

But by changing it to a different world, like default.sdf, it works!

I’m not sure why px4_sitl won’t spawn the drone in an empty world, maybe cause it would just fall infinitely, but that’s beside the problem I was trying to solve.

Thank you very much!

After testing with the default.sdf world, I thought all others would work the same, but I was wrong. I tried both the aruco.sdf and a custom world, and both end up in the same situation as the empty.sdf.

I’ll try and look into what’s different between them in the .sdf files.

I found out why the PX4 SITL wasn’t finding the running Gazebo simulation.

The reason is, when starting the SITL in standalone mode, it looks for the Gazebo service “/world/PX4_GZ_WORLD/scene/info”, where PX4_GZ_WORLD is the world name.

Previously it worked only for the default.sdf because that’s the default world the px4_sitl runs, so I guess it would find it by default, but the variable PX4_GZ_WORLD would be empty.

This all happens in the file located in ${HOME}/PX4-Autopilot/ROMFS/px4fmu_common/init.d-posix/px4-rc.gzsim, lines 67-90.

To fix it then, all we need to do is tell the px4_sitl command the world we want to open.

For the aruco case, that would be ros2 launch ros_gz_sim gz_sim.launch.py gz_args:=aruco.sdf on the first terminal, and PX4_GZ_STANDALONE=1 PX4_GZ_WORLD=aruco make px4_sitl gz_x500_mono_cam_down in another one.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.