FIG. 01
RECORD DATA
Category
Software
TARİH
Here is how a field test day goes: you are up at 7 AM, you drive two hours, and if you remembered to charge the battery packs, setup takes 40 minutes. Then, on the very first AUTO mission, instead of flying to the second waypoint the aircraft switches to RTL (Return To Launch). The reason? The altitude reference in the mission file is wrong. Working that out costs you 20 minutes; fixing it and trying again costs another battery.
What all of these failures have in common is that none of them needed a flight to find. Mission planning logic, mode transitions, failsafe thresholds, parameter sets — every one of them can be caught at a desk. Clearing them out beforehand leaves the field day for the things that genuinely have to be flown.
In this post we cover ArduPilot SITL, how we tie it together with Gazebo, and which tests we run at the desk. At the end comes the part that matters just as much: what simulation cannot test.
What is SITL, and how is it different from HITL?
SITL (Software In The Loop) is the ArduPilot flight software built for a PC with an ordinary C++ compiler — a native executable that lets you test how the code behaves with no hardware at all. Sensor data comes from a flight dynamics model instead of real sensors; everything else in the code is exactly what runs in a real flight.
HITL (Hardware In The Loop) uses the real flight controller: the normal firmware runs on the Pixhawk and sensor data is fed in from the simulator over a cable. More realistic in theory, but on the ArduPilot side this path is no longer the recommended one in practice.
SITL | HITL | |
|---|---|---|
What runs | ArduPilot compiled for a PC | Firmware on the actual FC |
Hardware required | No | Yes (FC + cable) |
Time scaling | Can be sped up with | Real time only |
Debugger, static analysis | Available | Difficult |
ArduPilot support | Active, the primary path | Via X-Plane and FlightGear, Plane only; the documentation marks it as archived and no longer supported |
When to pick it | Almost always | When you suspect an FC-specific driver or hardware timing problem — and even for that, ArduPilot now points you at the "Simulation on Hardware" path instead |
Short version: start with SITL. That is what we did.
Installing and running SITL
Setup is the same as setting up a normal ArduPilot development environment. You clone the repository with its submodules and run the prerequisites script:
Note: this script does not work on Ubuntu releases that are past end of standard support (20.04 LTS, for example). Use a current LTS.
Building and running:
The flags here matter:
Flag | What it does |
|---|---|
| Vehicle type |
| Frame type |
| MAVProxy status console |
| Map window |
| Wipes the virtual EEPROM and starts from default parameters |
| Start location, taken from |
| Starts without MAVProxy (for when you are attaching your own client) |
Use the -w flag only on the first run, or when you actually want to reset parameters; pass it every time and everything you set up is gone.
Bringing Gazebo into the loop
SITL's own built-in physics model is enough for most mission logic testing. We add Gazebo when we want to see the environment visually and stream video off a camera.
The ardupilot_gazebo plugin is what bridges the two. As of 2026 the plugin supports Gazebo Garden, Harmonic (LTS), Ionic and Jetty (LTS); the repository recommends Harmonic.
Then two environment variables:
And then, in two terminals:
The critical detail is --model JSON: data exchange between SITL and Gazebo runs over the JSON interface, and the frame name has to start with gazebo-. The plugin's gimbal camera streams video over GStreamer to UDP 127.0.0.1:5600 by default — that became our stand-in test source for the RTSP stream we get from the SIYI A8 mini.
The connection layer: which port goes where
SITL maps its serial ports onto TCP ports: serial 0–3 become 5760–5763 respectively. The default for a ground control station connection is 5760. When sim_vehicle.py also launches MAVProxy, MAVProxy takes that connection and fans it out to local UDP ports.
Client | Connection | Notes |
|---|---|---|
Mission Planner | TCP | If MAVProxy is not running, connect straight to this port |
Mission Planner (with MAVProxy running) | UDP | One of MAVProxy's default local outputs |
pymavlink script | UDP | The second local output; does not collide with the GCS |
Remote machine |
| A second station over the network |
A typical takeoff-and-mission sequence from the MAVProxy console:
On the pymavlink side, the connection pattern is plain:
On our side, this script is the same code that feeds FastMosaic's telemetry input. In other words, the only difference between the code that talks to SITL and the code that talks to the real aircraft is the connection string.
What we test
Scenario | How to trigger it | What it tells us |
|---|---|---|
Waypoint order and altitude reference |
| Whether the mission file is right, and whether the aircraft follows the expected sequence |
RC loss failsafe |
| Whether the failsafe action is correct, and how long it takes to fire |
GPS loss |
| EKF behavior, mode fallback |
Wind |
| Position hold error, mission duration |
Sensor noise |
| Filter behavior on a vibration-prone aircraft |
PID tuning | Change the gain parameters and repeat the same mission | A rough sense of which way stability is trending |
Time acceleration |
| 5x real time; for burning through long missions quickly |
One caveat on SIM_SPEEDUP: the documentation notes that at high speedup values MAVProxy may not keep up with the network traffic, and that you can see errors like "Set RC override timeout" or a GCS failsafe. The fix is simple — lower the multiplier.
What simulation CANNOT test
Do not skip this section; over-trusting SITL costs you at least as much as never using it.
Detection performance. The Gazebo camera produces synthetic imagery. Our mAP50 of 0.950 on the aerial-only validation set came from real flight frames; a score measured on synthetic imagery means nothing in the field. Model validation is done with real data.
Companion computer load. The 15-20 FPS inference rate on the Jetson Orin NX, thermal throttling and RTSP latency cannot be measured on a desktop.
Vibration, EMI, real sensor imperfections.
SIM_ACC_RNDadds noise, but it knows nothing about your airframe's resonant frequency.Mechanics. The release servo, the gimbal mount, cable strain — none of it exists in simulation. All that simulation reproduces of the autonomous airdrop test we ran from ~20 m in the field is the question "did the servo command go out at the right moment".
Radio range and real link quality. There is no packet loss on localhost.
Common pitfalls
Forgetting to carry the parameters over to the field. The good failsafe setting you found in SITL does not migrate to the real aircraft on its own. Keep the parameter file under version control.
-won every single run. The virtual EEPROM gets wiped and everything you set up in the previous session is gone.The wrong frame name. With Gazebo, the frame name has to start with
gazebo-and you have to pass--model JSON; otherwise SITL flies with its own internal model, the vehicle in Gazebo never moves, and you spend a long time hunting for why nothing works.Not making the environment variables persistent.
GZ_SIM_SYSTEM_PLUGIN_PATHandGZ_SIM_RESOURCE_PATHdisappear in a new terminal. Write them into.bashrc.Port collisions. Trying to connect both Mission Planner and your own script to 14550 on the same machine. Move the second one to 14551.
Counting a test that passed in simulation as "verified". Passing in SITL does not mean you are ready to fly; it means you are ready to go out to the field.
The practical summary
Plain SITL first, Gazebo second. Most mission logic, mode transition and failsafe testing does not need Gazebo; do not take on the setup overhead for nothing.
Change nothing but the connection string. If your ground software connects to SITL with
udpin:localhost:14551, it should connect to the real aircraft with that same code. Two code paths that drift apart will produce surprises in the field.Write the failsafe scenarios down as a checklist. Repeat the
SIM_RC_FAIL, GPS-disabled and wind tests after every firmware update — it is a five-minute job.Manage the parameter set from a single source. The values you tune in SITL and then fly in the field should come out of the same file.
Keep the limits of simulation in writing. The "this test cannot be done in SITL" list is the document that actually decides where your field day time goes.
