Skip to content

Simulation Module

ArduPilot SITL + Gazebo Harmonic simulation for Nectar drone development and testing, over either transport (MAVROS or direct MAVLink).

How It Works

ArduPilot SITL runs the full ArduCopter firmware on the host machine. Gazebo Harmonic provides physics and sensor simulation. The ArduPilotPlugin bridges Gazebo physics to SITL via JSON over UDP (port 9002). SITL exposes two MAVLink endpoints: TCP 5760 (SERIAL0, for MAVROS) and TCP 5762 (SERIAL1, for a direct pymavlink client / MavlinkDrone) — so both transports can run against the same simulator. The ros_gz_bridge converts Gazebo sensor data to ROS 2 messages.

flowchart LR
    subgraph sitl [ArduPilot SITL]
        ArduCopter["arducopter binary"]
    end

    subgraph gazebo [Gazebo Harmonic]
        Physics["Physics + Sensors"]
        ArduPlugin["ArduPilotPlugin"]
        GUI["GUI: 3D + ImageDisplay + TopicEcho"]
    end

    subgraph bridge [ros_gz_bridge]
        SensorBridge["Cameras + Lidar"]
        PoseBridge["Pose bridge (indoor)"]
    end

    subgraph ros2 [ROS 2]
        MAVROS["MAVROS"]
        VisionSource["gz_vision_source (indoor)"]
        VisionNode["vision_pose_node (mavros)"]
        SDK["Nectar SDK / MavrosDrone | MavlinkDrone"]
    end

    ArduPlugin -->|"JSON UDP:9002"| ArduCopter
    ArduCopter -->|"TCP:5760 (MAVROS)"| MAVROS
    ArduCopter -->|"TCP:5762 (direct MAVLink)"| SDK
    Physics --> SensorBridge
    SensorBridge --> SDK
    PoseBridge --> VisionSource
    VisionSource -->|"/visual_slam/tracking/vo_pose_covariance"| VisionNode
    VisionSource -->|"/visual_slam/tracking/vo_pose_covariance"| SDK
    VisionNode -->|"/mavros/vision_pose/pose_cov"| MAVROS
    MAVROS --> SDK

Two Environments

Outdoor (GPS)

  • World: outdoor_field.sdf -- open field with obstacle zone at x=13..18, fly-through gate
  • GPS via gz-sim-navsat-system plugin with WGS84 coordinates (Canberra default)
  • ArduPilot params: copter.parm + gazebo.parm (rangefinder enabled)
  • Config preset: SITL_GAZEBO_CONFIG (PoseSource.GPS)

Indoor (Vision)

  • World: indoor_room.sdf — 20x20x12m room, drone at x=-5
  • No GPS; EKF3 ExternalNav via the same vision bridges as hardware (details: localization README — SITL)
  • Params: copter.parm + gazebo.parm + indoor.parm
  • Config: SITL_VISION_CONFIG (PoseSource.VISION)

Simulated Sensors

Real sensor Gazebo sensor Topic (ROS 2) Notes
RealSense D435i (front) rgbd_camera /front_camera/image, /front_camera/depth_image, /front_camera/points 640x480, RGB + depth + point cloud
Arducam (down) camera /down_camera 640x480 RGB, downward-facing
TFLuna lidar (down) SITL simulated sonar /mavros/rangefinder/rangefinder RNGFND1_TYPE=1, ground distance from physics
TFLuna lidar (down) gpu_lidar /lidar/range Direct LaserScan via Gazebo, 1-sample rangefinder

The table above is the ArduPilot world. On both firmwares the SDK reads the downward rangefinder from /mavros/rangefinder/rangefinder: ArduPilot derives it from the SITL sonar, while PX4 fuses the x500_nectar gz gpu_lidar into a distance_sensor and streams it as MAVLink DISTANCE_SENSOR (see simulation/config/px4_config_sitl.yaml). ArduPilot additionally exposes the raw Gazebo gpu_lidar LaserScan on /lidar/range.

Gazebo GUI

Both world SDFs include built-in GUI plugins (no extra windows needed):

  • ImageDisplay panels for front RGB, front depth, and down camera (start collapsed, click to expand)
  • TopicEcho for viewing any Gazebo transport topic live
  • WorldStats showing sim time, real time, RTF

Installation

ArduPilot — clones ~/ardupilot + builds ArduCopter SITL, then installs Gazebo Harmonic + ArduPilotPlugin + ros_gz_bridge:

make sim-install FIRMWARE=ardupilot

PX4 — clones ~/PX4-Autopilot + builds px4_sitl + Gazebo, and symlinks the Nectar shared assets (x500_nectar, outdoor_field_scenery, outdoor_field_px4) into the PX4 tree. Add ARGS=--native for the uXRCE-DDS path:

make sim-install FIRMWARE=px4

Both:

make sim-install FIRMWARE=all

Then reload your shell: source ~/.bashrc.

Usage

One pattern for both firmwares. The two-terminal split is unavoidable (the autopilot SITL and the ROS stack are separate processes), so it is symmetric:

  • Terminal 1 — sim-start: the simulator (ArduPilot SITL; for PX4 also Gazebo).
  • Terminal 2 — sim-bridge: the ROS stack (Gazebo + bridges for ArduPilot; for PX4, MAVROS, MicroXRCE-DDS, or camera-only depending on PROTOCOL).

Choose the scenario with three variables (defaults ardupilot / outdoor / mavlink, so bare make sim-start + make sim-bridge = ArduPilot outdoor over direct MAVLink). ENV must match between the two terminals.

  • FIRMWARE = ardupilot | px4
  • ENV = outdoor | indoor
  • PROTOCOL = mavlink (direct pymavlink, default) | mavros. For PX4, dds selects the native uXRCE-DDS agent.
Scenario Terminal 1 Terminal 2 Mission config
ArduPilot outdoor, direct MAVLink make sim-start FIRMWARE=ardupilot ENV=outdoor make sim-bridge FIRMWARE=ardupilot ENV=outdoor MavlinkDrone / MAVLINK_SITL_GAZEBO_CONFIG
ArduPilot outdoor, MAVROS (same Terminal 1) make sim-bridge FIRMWARE=ardupilot ENV=outdoor PROTOCOL=mavros MavrosDrone / SITL_GAZEBO_CONFIG
ArduPilot indoor, direct MAVLink make sim-start FIRMWARE=ardupilot ENV=indoor make sim-bridge FIRMWARE=ardupilot ENV=indoor MavlinkDrone / MAVLINK_SITL_VISION_CONFIG
ArduPilot indoor, MAVROS (same Terminal 1) make sim-bridge FIRMWARE=ardupilot ENV=indoor PROTOCOL=mavros MavrosDrone / SITL_VISION_CONFIG
PX4 outdoor, direct MAVLink make sim-start FIRMWARE=px4 ENV=outdoor make sim-bridge FIRMWARE=px4 ENV=outdoor Px4MavlinkDrone / PX4_MAVLINK_SITL_GAZEBO_CONFIG
PX4 outdoor, MAVROS (same Terminal 1) make sim-bridge FIRMWARE=px4 ENV=outdoor PROTOCOL=mavros Px4MavrosDrone / PX4_SITL_GAZEBO_CONFIG
PX4 outdoor, uXRCE-DDS (same Terminal 1) make sim-bridge FIRMWARE=px4 ENV=outdoor PROTOCOL=dds Px4DdsDrone / PX4_DDS_SITL_CONFIG
PX4 indoor, direct MAVLink make sim-start FIRMWARE=px4 ENV=indoor make sim-bridge FIRMWARE=px4 ENV=indoor Px4MavlinkDrone / PX4_MAVLINK_SITL_VISION_CONFIG
PX4 indoor, MAVROS (external-nav) (same Terminal 1) make sim-bridge FIRMWARE=px4 ENV=indoor PROTOCOL=mavros Px4MavrosDrone / PX4_SITL_VISION_CONFIG
PX4 indoor, uXRCE-DDS (same Terminal 1) make sim-bridge FIRMWARE=px4 ENV=indoor PROTOCOL=dds Px4DdsDrone / PX4_DDS_SITL_VISION_CONFIG
  • ArduPilot: Terminal 1 runs the SITL physics; Terminal 2 launches Gazebo + ros_gz_bridge. Default PROTOCOL=mavlink starts vision_pose_node on SERIAL0 (tcp 5760) indoors; the mission uses SERIAL1 (tcp 5762). Activate the nectar venv (nectar-activate) before Terminal 2 so pymavlink is available — otherwise the feeder exits and 5762 stays closed. PROTOCOL=mavros adds MAVROS on SERIAL0 plus vision_pose_node.
  • Connection strings differ by transport: MAVROS uses a URL (tcp://host:port, udp://...); the direct-MAVLink MavlinkDrone (pymavlink) uses a bare string (tcp:127.0.0.1:5762, udp:host:port, or a serial path like /dev/ttyUSB0). The tcp:// URL form is also accepted for MavlinkDrone and normalized.
  • PX4: Terminal 1 (start_px4.sh) runs PX4 and its Gazebo. Terminal 2 runs bridges. Offboard API is UDP 14540. Indoor PROTOCOL=mavlink uses mission-owned feed (auto_vision_feed on PX4_MAVLINK_SITL_VISION_CONFIG) because SITL exposes a single offboard endpoint.
  • PX4 uXRCE-DDS (PROTOCOL=dds): Terminal 2 runs MicroXRCEAgent (udp4 :8888); outdoor leaves the agent in the foreground. Indoor also starts px4_sitl.launch.py vision:=true backend:=dds so GT→VSLAMVehicleOdometry reaches EKF2. One-time setup: make sim-install FIRMWARE=px4 ARGS=--native (builds px4_msgs + the agent). px4_msgs must match the PX4 firmware (topics are versioned, e.g. vehicle_status_v4).
  • Indoor: both firmwares use gz_vision_source → vision bridges (see localization SITL).
  • Forward extra launch/script args with ARGS=..., e.g. a one-off mavros toggle or rangefinder test world:
make sim-bridge FIRMWARE=ardupilot ARGS="world:=rangefinder_test.sdf mavros:=false"
  • Custom mission arenas (recommended): competition packages ship scenery only (model.config + model.sdf + meshes). Nectar composes the vehicle stack (plugins, iris, cameras, lidar). ENV selects indoor ExternalNav vs outdoor GPS; map and spawn are launch args:
make sim-start  FIRMWARE=ardupilot ENV=indoor
make sim-bridge FIRMWARE=ardupilot ENV=indoor \
  ARGS='scenery:=model://my_arena spawn_pose:="-5 0 0.195 0 0 0" resource_path:=/path/to/pkg/simulation/models'
Arg Role
world:=outdoor\|indoor Compose from Nectar vehicle template (+ stock scenery if scenery empty)
scenery:=model://name Replace stock scenery with a mission model
spawn_pose:="x y z r p y" Iris pose (degrees); empty = template default
resource_path:=a:b Extra dirs on GZ_SIM_RESOURCE_PATH (mission simulation/models)
world:=/abs/path.sdf Escape hatch: full custom world (must embed drone/sensors yourself). Pass vision:=true for indoor ExternalNav — path worlds do not auto-enable vision.

Composed worlds use fixed names nectar_indoor / nectar_outdoor (pose topic /world/<name>/dynamic_pose/info). Full custom worlds use the SDF <world name="...">. Mission packages that only supply scenery must not hard-code iris/cameras in their SDF.

  • Headless ArduPilot without Gazebo (pure MAVROS): run ./scripts/simulation/start_sitl.sh then ros2 launch nectar sitl.launch.py directly.

Run make sim-stop before relaunching Terminal 2 — it clears every simulation process for both firmwares (arducopter/px4, Gazebo, MAVROS, bridges, vision nodes).

Shared-world architecture

Nectar owns the vehicle stack; missions own scenery.

  • simulation/templates/{indoor,outdoor}_vehicle.sdf.in — ArduPilot compose templates (plugins, iris, Nectar cameras/lidar). Launch substitutes scenery + spawn.
  • simulation/models/indoor_room_scenery/ — stock 20×20×12 m indoor room + obstacles.
  • simulation/models/outdoor_field_scenery/ — outdoor gate + obstacles. Also used by outdoor_field.sdf / outdoor_field_px4.sdf.
  • simulation/models/x500_nectar/ — PX4 x500 + matched sensors. Outdoor/indoor PX4 use shared scenery via include.
  • simulation/worlds/outdoor_field_px4.sdf — scenery-only world for PX4 (no world <plugin> tags; PX4's server.config injects systems). GPS origin near-zero declination (lat 0, lon 40), not ArduPilot's Canberra — see magnetometer notes in prior docs (gz-sim#2536).
  • simulation/worlds/indoor_room_px4.sdf — indoor scenery-only world for PX4 (same indoor_room_scenery). GT pose comes from PosePublisher on x500_nectar (Gazebo 8 requires model-level attachment; 50 Hz; spawned as x500_nectar_0).

Mission package layout:

my_mission/simulation/models/<arena>/{model.config,model.sdf,meshes/}

No iris, cameras, or Gazebo world plugins in the mission package.

install_px4.sh symlinks Nectar assets (x500_nectar, outdoor/indoor scenery + worlds) into PX4's Tools/simulation/gz/{models,worlds} so PX4's launcher can find them while the source of truth stays in nectar-sdk/. start_px4.sh --autostart reuses PX4's existing 4001 (x500) airframe via PX4_SYS_AUTOSTART, so no PX4-tree airframe file is added. Indoor auto-loads params/px4_indoor.env and spawns at PX4_GZ_MODEL_POSE=-5,0,0.2. Outdoor auto-loads params/px4_outdoor.env (restores GNSS EKF after indoor EKF2_* values persist in SITL parameters.bson). Outdoor SITL also exports NAV_DLL_ACT=0, NAV_RCL_ACT=0, and COM_RCL_EXCEPT=4 so headless OFFBOARD can arm without RC/GCS (PX4 offboard SITL).

Stop all

make sim-stop

One stop for both firmwares: kills arducopter, PX4 (px4_sitl/bin/px4), MicroXRCEAgent, Gazebo, MAVROS, ros_gz_bridge, gz_vision_source, and vision_pose_node processes.

Verify sensors

Check Command
State ros2 topic echo /mavros/state --once
GPS (outdoor) ros2 topic echo /mavros/global_position/global --once --qos-reliability best_effort
Vision pose (indoor) ros2 topic echo /mavros/vision_pose/pose_cov --once
Rangefinder ros2 topic echo /mavros/rangefinder/rangefinder --once
Front camera ros2 topic echo /front_camera/image --once
Depth ros2 topic echo /front_camera/depth_image --once

Multi-orientation rangefinders

rangefinder_test.sdf places an iris with front and back single-ray lidars between two walls. The iris_with_rangefinders model forwards the front/back lidars to ArduPilot as rng_2/rng_3, and rangefinder_test.parm exposes them as RNGFND2/3 (orientations forward/back). The downward rangefinder (RNGFND1, orientation down) stays on the analog SITL sonar from gazebo.parm: on the ground the airframe is only ~0.2 m tall, so a downward GPU lidar reads below its minimum range, while the sonar reports vehicle height above terrain reliably. ArduPilot emits one DISTANCE_SENSOR per instance, accessible through drone.distance_sensors and drone.get_distance(orientation).

Terminal 1 — SITL with the three rangefinders:

./scripts/simulation/start_sitl.sh --gazebo \
    --params nectar/simulation/params/rangefinder_test.parm

Terminal 2 — Gazebo (and MAVROS) with the test world:

ros2 launch nectar sitl_gazebo.launch.py world:=rangefinder_test.sdf

Terminal 3 — inspect the readings (MAVROS topics):

ros2 topic echo /mavros/rangefinder/rangefinder --once
ros2 topic echo /mavros/distance_sensor/rangefinder/front --once

In code, both transports expose every reported unit via drone.distance_sensors and drone.get_distance(orientation) (the downward unit also updates drone.rangefinder); see the vehicle core README. The MAVROS path relies on the distance_sensor plugin entries in config/apm_config_sitl.yaml (rangefinder/rangefinder, rangefinder/front, rangefinder/back) mapped to orientations.

Configuration Presets

Defined in nectar/control/config.py:

Preset Transport Port PoseSource Lidar Use case
SITL_CONFIG mavros 5760 GPS No Headless SITL, no sensors
SITL_GPS_CONFIG mavros 5760 GPS No Headless SITL with GPS
SITL_GAZEBO_CONFIG mavros 5760 GPS Yes Gazebo outdoor
SITL_VISION_CONFIG mavros 5760 VISION Yes Gazebo indoor
MAVLINK_SITL_CONFIG mavlink 5760 GPS No Headless SITL, direct pymavlink
MAVLINK_SITL_GAZEBO_CONFIG mavlink 5762 GPS No Gazebo outdoor, direct (SERIAL1, alongside MAVROS)
MAVLINK_SITL_VISION_CONFIG mavlink 5762 VISION No Gazebo indoor; feeder SERIAL0 / 5760
PX4_SITL_CONFIG px4 14540 GPS No PX4 SITL headless (offboard over MAVROS)
PX4_SITL_GAZEBO_CONFIG px4 14540 GPS Yes PX4 SITL + Gazebo (x500_nectar, outdoor)
PX4_SITL_VISION_CONFIG px4 14540 VISION Yes PX4 SITL indoor (indoor_room_px4 + gz_vision_source → EKF2)
PX4_MAVLINK_SITL_CONFIG px4_mavlink 14540 GPS No PX4 SITL headless, direct pymavlink
PX4_MAVLINK_SITL_GAZEBO_CONFIG px4_mavlink 14540 GPS Yes PX4 SITL + Gazebo (x500_nectar, outdoor), direct pymavlink
PX4_MAVLINK_SITL_VISION_CONFIG px4_mavlink 14540 VISION Yes PX4 SITL indoor; mission-owned vision feed (single offboard UDP)
PX4_DDS_SITL_CONFIG px4_dds 8888 GPS Yes PX4 SITL native uXRCE-DDS (MicroXRCEAgent on 8888), outdoor
PX4_DDS_SITL_VISION_CONFIG px4_dds 8888 VISION No PX4 SITL indoor uXRCE-DDS (VehicleOdometry EV)
from nectar.control import (
    DroneFactory,
    SITL_GAZEBO_CONFIG,
    MAVLINK_SITL_GAZEBO_CONFIG,
    PX4_SITL_GAZEBO_CONFIG,
    PX4_MAVLINK_SITL_GAZEBO_CONFIG,
)

Outdoor over MAVROS (port 5760):

drone = DroneFactory.create("mavros", SITL_GAZEBO_CONFIG)

Outdoor over direct MAVLink (port 5762, sim-bridge ... PROTOCOL=mavlink):

drone = DroneFactory.create("mavlink", MAVLINK_SITL_GAZEBO_CONFIG)

PX4 over MAVROS (offboard UDP 14540, sim-start/sim-bridge FIRMWARE=px4 ENV=outdoor):

drone = DroneFactory.create("px4", PX4_SITL_GAZEBO_CONFIG)

PX4 over direct pymavlink (offboard UDP 14540, sim-bridge ... PROTOCOL=mavlink):

drone = DroneFactory.create("px4_mavlink", PX4_MAVLINK_SITL_GAZEBO_CONFIG)

Test Suite

Per-distro outdoor protocol status lives in docs/COMPATIBILITY.md (Simulation section). Tier-3 gate per protocol: make verify-sitl FIRMWARE=<ardupilot|px4> PROTOCOL=<mavros|mavlink|dds> — maps to the scenario rows below.

sitl_test.py runs atomic navigation tests. Each test starts from a clean hover and verifies a specific capability.

Usage

# All outdoor tests over MAVROS (37 tests, tcp 5760)
python3 nectar/nectar/examples/simulation/sitl_test.py

# Same suite over direct pymavlink (MavlinkDrone, tcp 5762)
python3 nectar/nectar/examples/simulation/sitl_test.py --mavlink

# Indoor-compatible subset (vision config, skips the 5 GPS-only tests -> 32 tests)
python3 nectar/nectar/examples/simulation/sitl_test.py --indoor

# Land between tests for a full reset
python3 nectar/nectar/examples/simulation/sitl_test.py --fresh pid_fwd

# Specific tests / a group / list everything
python3 nectar/nectar/examples/simulation/sitl_test.py pid_fwd setpoint_fwd
python3 nectar/nectar/examples/simulation/sitl_test.py --group vel
python3 nectar/nectar/examples/simulation/sitl_test.py --list

Flags: --mavlink (direct pymavlink on tcp 5762), --px4 (PX4 over MAVROS, offboard on udp 14540), --indoor (vision config, skip GPS-only tests), --fresh (land between tests).

Test groups

Group Tests Description
vel vel_fwd, vel_lat, vel_up, vel_yaw, vel_takeoff, vel_world, vel_world_north, vel_world_rotated, brake Velocity in BODY/WORLD/TAKEOFF frames
pid pid_fwd, pid_lat, pid_alt, pid_yaw PID navigation with raw GPS
pid_local pid_local_fwd, pid_local_lat, pid_local_yaw PID navigation with EKF local position
setpoint setpoint_fwd, setpoint_lat, setpoint_yaw Local position setpoint publishing
setpoint_global setpoint_global, setpoint_global_yaw GPS global setpoint (outdoor only)
wpnav setpoint_wpnav AC_WPNav waypoint setpoint
rtl rtl_pid, rtl_ardupilot Return to launch
yaw vel_yaw, pid_yaw, pid_local_yaw, setpoint_yaw, setpoint_global_yaw, yaw_direction, yaw_takeoff_ref Yaw handling across methods
world vel_world, vel_world_north, vel_world_rotated WORLD-frame velocity
nav pid_fwd, pid_lat, pid_local_fwd, pid_local_lat Core PID navigation
compound sequential, takeoff_ref Multi-step sequences
square sq_pid, sq_pid_takeoff, sq_pid_local, sq_setpoint, sq_setpoint_global, sq_wpnav 3m square patterns

Pre-flight tests (sensors, heading_enu) run without takeoff. GPS-only tests (skipped with --indoor): heading_enu, setpoint_global, setpoint_global_yaw, sq_setpoint_global, rtl_ardupilot.

The set_speed test exercises MAV_CMD_DO_CHANGE_SPEED (horizontal/climb/descent). It is not in the pre-flight set because ArduCopter accepts that command only in a nav-capable mode (GUIDED), so it must run airborne.

ArduPilot Parameters

gazebo.parm (loaded for all Gazebo sessions)

Parameter Value Purpose
SIM_SONAR_SCALE 10 SITL sonar scaling factor
RNGFND1_TYPE 1 Analog rangefinder driven by SIM_SONAR
RNGFND1_SCALING 10 Voltage-to-distance scaling
RNGFND1_PIN 0 Analog pin
RNGFND1_MAX 40 Max range (m)
RNGFND1_MIN 0.10 Min range (m)

indoor.parm (loaded additionally for ArduPilot indoor)

Parameter Value Purpose
GPS1_TYPE 0 Disable GPS
EK3_SRC1_POSXY 6 ExternalNav for XY position
EK3_SRC1_VELXY 6 ExternalNav for XY velocity
EK3_SRC1_POSZ 1 Barometer for Z (default)
EK3_SRC1_YAW 6 ExternalNav for yaw
VISO_TYPE 1 Enable visual odometry input
ARMING_CHECK 388598 Disable GPS-related arming checks

px4_indoor.env / px4_outdoor.env (via PX4_PARAM_*)

Indoor (indoor_room_px4):

Parameter Value Purpose
EKF2_GPS_CTRL 0 Disable GNSS aiding
EKF2_EV_CTRL 11 EV h-pos + v-pos + yaw (no velocity)
EKF2_HGT_REF 3 Height reference = Vision
EKF2_MAG_TYPE 5 None (yaw from vision)
COM_ARM_WO_GPS 1 Allow arming without GPS (SITL)

Outdoor (outdoor_field_px4) restores stock GNSS defaults so a prior indoor run cannot leave EKF2_GPS_CTRL=0 in parameters.bson (PX4 env overrides):

Parameter Value Purpose
EKF2_GPS_CTRL 7 Lon/lat + alt + 3D velocity
EKF2_EV_CTRL 0 No external vision
EKF2_HGT_REF 1 Height reference = GPS
EKF2_MAG_TYPE 0 Automatic magnetometer fusion
COM_ARM_WO_GPS 1 PX4 default (allow with warning)

Indoor vision

Ground-truth pose/twist → canonical VSLAM topics via gz_vision_source.py, then the same vision_pose_node backends as hardware. Full notes (sim time, velocity, send_speed): localization README — SITL.

On Jazzy, ros_gz may strip child_frame_id; the source falls back to model_index (default 0).

Layout

Simulation assets (nectar/simulation/):

  • params/SITL parameter files: gazebo.parm / indoor.parm (ArduPilot), px4_indoor.env / px4_outdoor.env (PX4 EKF2), rangefinder_test.parm
  • config/MAVROS bridge profiles: apm_config_sitl.yaml / apm_pluginlists_sitl.yaml (ArduPilot), px4_config_sitl.yaml / px4_pluginlists_sitl.yaml (PX4)
  • models/indoor_room_scenery, outdoor_field_scenery, iris_with_rangefinders, x500_nectar
  • templates/indoor_vehicle.sdf.in, outdoor_vehicle.sdf.in (composed by sitl_gazebo.launch.py)
  • worlds/outdoor_field.sdf, outdoor_field_px4.sdf, indoor_room.sdf, indoor_room_px4.sdf, rangefinder_test.sdf

Install and start scripts (scripts/simulation/): install_sitl.sh, install_gazebo.sh, install_px4.sh, start_sitl.sh, start_px4.sh, and gz_vision_source.py.

Launch files (nectar/launch/): sitl.launch.py (MAVROS-only), sitl_gazebo.launch.py (ArduPilot Gazebo + ros_gz_bridge), px4_sitl.launch.py (PX4 bridge). The navigation test suite is examples/simulation/sitl_test.py.

References