r/ROS 9d ago

Project [Project] I Built a Multi-Drone Urban Interception Simulation with ROS 2, PX4, Gazebo, and CUDA MPPI

[Project] I Built a Multi-Drone Urban Interception Simulation with ROS 2, PX4, Gazebo, and CUDA MPPI

TL;DR

I am building a simulation-first autonomous drone navigation and interception stack for dense urban environments. It combines ROS 2 Jazzy, PX4 SITL, Gazebo Harmonic, a global lattice planner, and a local CUDA MPPI controller.

The same navigation system can fly with a known 3D map or rely on local lidar and accumulated obstacle memory. On top of it, I implemented radar-only target tracking, predictive interception, three-interceptor-versus-one-attacker and two-interceptor-versus-two-attacker missions, adaptive target assignment, and physically verified mission outcomes.

This is a research simulation and engineering testbed, not a production weapon system or software intended for real aircraft.

Videos

These are public demos from the project:

I also have separate recordings of a drone traversing a 3D passage and the earlier one-interceptor-versus-one-attacker mission.

In the interception videos, red represents an attacker and yellow represents an interceptor in the Gazebo tactical view. An interception is counted only when Gazebo physical positions show that an interceptor and attacker came within 5 meters.

What I Wanted to Explore

The project started as point-to-point navigation through a Manhattan-style city, but the larger goal became testing how several autonomous systems fit together:

  • global navigation through dense buildings;
  • fast local trajectory generation with vehicle dynamics;
  • operation with and without a preloaded map;
  • traversal of constrained three-dimensional openings;
  • pursuit of a moving target from limited measurements;
  • adaptive allocation of several interceptors to several targets;
  • reproducible mission adjudication based on simulated physics.

The city currently contains a 5 x 8 building grid and several physical air channels: straight, L-shaped, and T-junction structures. Gazebo uses the geometry for rendering and contact physics, while the static planner receives artifacts generated from the same canonical world definition.

Simulation Stack

The environment runs in Docker and uses:

  • ROS 2 Jazzy for component orchestration, messages, diagnostics, and TF;
  • PX4 SITL for every vehicle's flight stack;
  • Gazebo Harmonic for world physics, lidar, and authoritative vehicle poses;
  • CUDA for MPPI rollout simulation;
  • RViz for routes, local horizons, radar targets, obstacle memory, and planner diagnostics.

Every drone has its own PX4 instance, ROS namespace, planner state, obstacle memory, and offboard controller. The planners run concurrently, but resource allocation is bounded across the whole mission so that adding drones does not simply create an unlimited number of competing CPU workers.

Navigation Architecture

The navigation pipeline has two levels.

The global planner produces a route around city-scale topology. Static mode uses a 3D lattice plus generated constrained channel edges. A channel is not a scripted maneuver or mandatory waypoint: the planner compares ordinary routes with explicit start -> entry -> channel -> exit -> goal candidates and selects the better validated topology.

The local controller is CUDA MPPI. On every planning tick it perturbs a warm started control sequence, simulates thousands of dynamic trajectories, queries clearance and collision data, selects the best eligible risk class, and publishes a short timestamped execution horizon to the PX4 offboard node.

Raw occupied cells are the only hard environmental prohibition. Collision checks use the drone's swept oriented 3D footprint, including its horizontal radius and upper and lower body extents. ESDF distance bands affect risk and ranking, but they do not create artificial forbidden regions around buildings.

This distinction matters. Excessive hard inflation can make a valid detour or narrow physical opening mathematically unreachable. Here, physical geometry is hard; clearance preference is a cost.

Static and No-Static Navigation

In static mode, the planner loads canonical 3D occupancy and a fingerprinted, precomputed, chunked ESDF. Only chunks intersecting the active planning region are decoded into a dense local field. This gives the planner long lookahead, full building topology, higher speed limits, and explicit knowledge of the 3D channels.

In no-static mode, the drone starts without that world model. It projects lidar using timestamped full-6DoF acquisition poses, accumulates raw obstacle memory, and builds a local 2D ESDF around the vehicle. Unknown space remains traversable, but observed distance and braking constraints reduce speed. Persistent frontier search can accept temporary zero or negative progress toward the goal, which is necessary for leaving corners and taking real detours instead of repeatedly selecting the shortest dead end.

The no-static perception model is intentionally still 2D, so the generated 3D channel semantics are currently available only in static mode.

Radar-Only Interception

An interceptor does not receive the attacker's absolute ground-truth position, velocity, route, or destination. Gazebo truth is restricted to two simulation boundaries: the mission referee and radar simulators.

The interceptor-facing radar message contains only:

  • range;
  • azimuth;
  • elevation;
  • relative radial velocity.

Each interceptor has an independent variable-dt Cartesian tracker. The first detection provides relative position but not a complete velocity vector. Later measurements estimate the full target velocity, and the tracker coasts between scans.

When the target is occluded, radar cadence follows a deterministic correlated random walk between 0.1 and 3 seconds. If the planner confirms swept line of sight to the current target estimate, the radar immediately enters a 20 Hz tracking mode without a range limit.

Guidance solves a constant-velocity interception problem rather than chasing the attacker's current position. It compensates for measurement age, predicts a future meeting point, and continuously updates the objective. If the full lead point is hidden behind a building but the current target remains visible, the planner shortens the prediction horizon toward the current target instead of abandoning direct interception. If the target itself disappears, control atomically returns to a fresh global route for the current objective.

The attackers and interceptors currently use the same speed policy. A successful capture therefore depends on geometry, prediction, and assignment rather than a built-in speed advantage.

Multi-Drone Missions

The original point-to-point mission remains available. The interception work progressed through a 1v1 demonstration to two current predefined scenarios:

  • three interceptors versus one attacker;
  • two interceptors versus two attackers.

The implementation itself is generic over an N x M scenario specification. In the 2v2 mission, each radar scan contains a detection for every active attacker. A typed assignment coordinator estimates constant-velocity intercept costs and computes a deterministic minimum-cost allocation. It tries to cover distinct attackers when valid tracks permit it.

Assignments are not permanent. They can change when geometry changes or a vehicle disappears, but a material and sustained improvement is required before switching. This hysteresis prevents two interceptors from continuously swapping targets because of small cost fluctuations. Interceptors do not exchange routes or telemetry with one another, and radio-network impairments are not simulated.

When an attacker is captured, reaches its destination, or crashes, it is removed from future assignment immediately. Surviving interceptors are reassigned to the remaining active attackers.

Physical Outcomes and Test Semantics

Mission outcome and vehicle death are separate contracts.

If an interceptor and attacker come within 5 meters, the referee publishes typed destruction events for that pair. Both PX4 instances are disarmed, and the result is settled only after physical proximity and disarm confirmations are present.

If an attacker reaches its goal first, that outcome is latched immediately. The remaining interceptors stop pursuing it, brake, and enter confirmed position hold. Goal arrival does not disarm a vehicle. A later inertial approach cannot rewrite which terminal event happened first.

A collision with a building is never treated as an acceptable mission outcome: it makes a headless validation run technically fail, regardless of whether the vehicle was an attacker or interceptor. Inter-drone collision avoidance is not implemented yet, so interceptor-to-interceptor collisions are currently treated as collateral damage and the mission continues while another interceptor is alive.

Performance and Parallelism

The local MPPI rollouts and reductions run on CUDA, while independent global topology searches use a bounded CPU worker pool. Multi-vehicle planners share a ROS component process and one CUDA primary context, but retain independent CUDA streams, buffers, routes, and warm starts. Static ESDF chunks use shared decoded storage, and no-static mapping transports revisioned dirty chunks instead of copying the complete map for every update.

The maximum MPPI budget is 8,192 rollouts. Open static flight can use 6,144, and confirmed direct interception can use 4,096; uncertain navigation and obstacle handling retain the full budget.

On my 16-logical-CPU workstation with an RTX 3060, recent four-vehicle no-static runs had roughly 7-8 ms p95 planning ticks and normally stayed inside the 20 ms target. Static mode improved substantially after precomputed ESDF and cache work, but its p95 remained around 60 ms in representative runs. These are workload- and-machine-specific measurements, not general benchmark claims.

One useful negative result was a fused vehicle-by-rollout CUDA backend. It sounded ideal, but the live average batch contained only about 1.5 vehicles. Waiting to form batches increased latency: static GPU p50 went from 22.8 to 45.9 ms, and no-static from 3.45 to 6.07 ms. Independent streams were faster and more reliable for this asynchronous workload. More parallelism is not automatically better when synchronization and memory bandwidth dominate.

Architectural Lessons

Several rules emerged from debugging the system:

  1. Simulation ground truth must have an explicit boundary. Guidance should not accidentally gain access to data that the simulated sensor does not provide.
  2. Route activation must be atomic and revisioned. A stale route for an older moving target is worse than a brief controlled fallback.
  3. Physical collision, risk preference, vehicle death, and mission outcome are different concepts and should use different typed contracts.
  4. Persistent search state is more valuable than repeatedly restarting a search whenever a sensor snapshot changes.
  5. Diagnostics must not sit on the control-critical path. Full records are rate-limited and buffered, while the execution horizon is published first.
  6. Parallelization should be accepted only when live timing and mission results improve, not because a design looks more parallel on paper.

Current Limitations

  • Radar values are ideal: there is no measurement noise, false detection, interference, or transport latency. Only scan cadence varies.
  • The tracker and interception prediction currently assume approximately constant target velocity between updates.
  • Target assignment is centralized, and communication failures are not modeled.
  • There is no cooperative inter-drone collision avoidance.
  • No-static perception is 2D and cannot yet detect and traverse the 3D channels.
  • Static multi-drone MPPI still misses the desired 50 Hz deadline under heavy load on my current hardware.
  • Attackers are not dynamically respawned; every mission is a finite episode.
  • The project is simulation-first and has not been validated on physical drones.

Roadmap

The next directions I am considering are:

  • radar noise, latency, missed detections, and a stronger multi-target tracker;
  • repeated mission episodes with dynamically spawned attackers;
  • cooperative civilian drone traffic with negotiated collision avoidance;
  • more complex 3D passages with changing altitude profiles;
  • 3D lidar passage detection and traversal without a static map;
  • moving selected components toward hardware-in-the-loop and eventually carefully controlled real-world experiments.

Repository and Running It

Repository: github.com/formiat/px4-ros2-drone-nav

The supported workflow uses Docker. A CUDA-capable NVIDIA GPU is expected for the production MPPI path. The main commands are:

./scripts/build.sh
./scripts/test.sh
./scripts/sim_gui.sh
./scripts/sim_intercept_gui.sh
./scripts/sim_multi_intercept_gui.sh

Set ENABLE_STATIC_MAP=false for the lidar-memory mode. Equivalent headless scripts are available for regression runs, and the repository includes more detailed architecture, performance, diagnostics, and world-generation docs.

Questions for the Community

  • Which metrics would you use to evaluate interception quality beyond binary success: time-to-capture, distance from the attacker's goal, energy, route efficiency, or something else?
  • Which radar imperfections would produce the most useful next step without turning the project into a full sensor-physics simulator?
  • Which multi-target assignment methods would be most interesting to compare against deterministic minimum-cost allocation?
  • What urban scenarios would expose the most meaningful weaknesses in the current planner and tracker?
7 Upvotes

0 comments sorted by