A fleet of three drones patrolling one route is a manageable airspace problem. A fleet of 100 drones running four parallel sector patrols from a shared base, with takeoffs, transit corridors, patrol loops, return paths, and landing approaches all happening concurrently, is a collision problem that needs to be designed away, not monitored for. Overwatch treats drone-to-drone separation as a first-class orchestration feature — not a side-effect of good scheduling. Three pre-allocated layers plus a runtime safety net.

Why this matters more as fleets grow

A three-drone relay has two airborne drones at most: one patrolling, one in transit during handoff. They rendezvous at exactly one point in space (the handoff waypoint) and otherwise are separated by minutes of cycle time. Even naive altitude assignment works.

A four-sector patrol with eight drones is already four parallel relays running simultaneously. Now you have up to four drones patrolling at once, plus up to four more in transit during simultaneous handoffs, plus multiple drones landing at the same bay cluster. Without explicit deconfliction the probability that two drones occupy similar airspace at the same moment is no longer vanishingly small — it’s the default.

Scale that to a 100-drone fleet across 16 sectors and the airspace is never empty. Collisions are an inevitability to be engineered against, not an edge case to be hoped away. Overwatch is built for this.

Layer 1: intra-sector altitude stagger

Within each sector’s sub-fleet, drones are assigned staggered patrol altitudes — 5 m apart, clamped to ±10 m from the base patrol altitude. A three-drone sector with a nominal 30 m patrol altitude has drones at 25 m, 30 m, 35 m. Handoff waypoints are physically the same GPS coordinate, but the outgoing drone is 5 m above (or below) the incoming drone, so they never share vertical airspace even at the handoff moment. This is the oldest layer in Overwatch — it predates sectors — and still carries most of the intra-sector load.

Layer 2: per-sector transit bands

The moment sectors arrived, we had a new problem: drones from different sectors share the base. Every sector’s returning drone flies home through the same physical airspace. Intra-sector altitude stagger doesn’t help — two returning drones from different sectors could easily be at the same altitude.

Fix: each sector gets its own transit-altitude band. Sector N’s returning drones climb to base_altitude + 10 m + N × 5 m. For four sectors with a 30 m base, that’s transit altitudes of 40 m / 45 m / 50 m / 55 m. Every sector’s transit corridor lives in its own 5 m vertical slice, so returning drones from different sectors cross over each other in Z rather than colliding in XY. Patrol altitudes stay the same across sectors (the patrol zones don’t overlap horizontally, so they don’t need vertical separation), but transit corridors do overlap (everyone heads home to the same base), so the bands separate them in Z.

With 16 sectors at 5 m per band, the top band sits 75 m above base — still well within operating envelopes for both ANAFI UKR (120 m max) and X500 / PX4 (configurable geofence, typically 120 m for commercial work). At 100-drone / 16-sector scale this remains feasible.

Layer 3: takeoff stagger

When a multi-sector patrol starts, all N sectors want to launch their first drone simultaneously. With the shared base and close-packed bays, that’s N drones leaving the ground at the same instant, each transitioning from 0 m to their per-sector transit altitude, crossing each other’s flight paths during the vertical climb phase. Vertically, they’d all be in the same slice — altitude bands only separate drones after they’ve reached cruise altitude.

The fix is time, not altitude. Sector 0 launches at elapsed = 0 s. Sector 1 launches 5 sim-seconds later. Sector 2 at +10 s. Each drone has a clear window to climb through lower altitudes before the next neighbour clears its bay. The visual result in the simulator is a staggered unfurling — drones leave bay-by-bay like a rolling release — instead of a simultaneous swarm.

5 seconds per sector × 16 sectors = 80 s to get the whole fleet airborne. A small upfront cost for a patrol that will run for hours or days, and it cleanly removes the most conflict-rich moment in the mission.

Layer 4: runtime proximity sweep

The three layers above are pre-allocated — altitudes and timings are computed before flight and never change. That’s fine while every drone behaves as expected. But in the real world:

  • Wind pushes a returning drone off its transit corridor.
  • An operator manually overrides a sector count mid-planning and the altitude band allocation doesn’t re-run.
  • Two sectors’ drawn sub-polygons happen to have their patrol loops bringing drones close in XY at similar altitudes for a few seconds.
  • A drone on emergency RTH ignores its transit band and descends fast.

For these, Overwatch runs a runtime proximity sweep every 200 ms as part of the orchestrator tick. It scans every pair of airborne drones (patrol + returning states; drones on the ground or in transit to handoff are not airborne hazards to patrol drones at cruise altitude). For each pair, it computes horizontal distance (haversine) and vertical separation. If both fall below the safety thresholds — 20 m horizontally and 4 m vertically — the orchestrator applies a dynamic altitude adjustment.

Priority-based resolution decides who yields:

  • Patrolling drones (priority 3) keep their assigned altitude.
  • Returning drones (priority 2) yield to patrolling.
  • Transit (in-transit to handoff or initial WP, priority 1) yield to both.

The yielding drone climbs 6 m above the holding drone’s current altitude — enough to clear the vertical safety threshold with margin, small enough to stay well within envelope. An event fires (collisionAvoided) with a 10-sim-second cooldown per pair so the alert log doesn’t flood while two drones are still separating. The alert engine surfaces it to the operator for audit.

In normal operation, this layer should never fire — the first three layers handle everything. If the runtime sweep does fire, that’s a signal: the pre-allocated bands had a gap, the operator should review the patrol setup, and the audit log captures exactly which pair, when, and what separation was restored.

Platform caveat: this layer is MAVLink-only

The first three layers (altitude stagger, transit bands, takeoff stagger) are pre-flight allocations — baked into the mission before any drone leaves the ground. They work equally on MAVLink (PX4) and AirSDK (ANAFI).

The runtime proximity sweep needs to command the yielding drone to climb mid-flight. That requires a mid-flight ground-to-drone command channel — which MAVLink has (COMMAND_LONG, PARAM_SET, altitude setpoints) and AirSDK does not. AirSDK missions are sealed at upload time. On AirSDK the runtime sweep still runs in the ground station, still emits alerts, and still records the audit trail — but it cannot actually command a climb. Altitude bands and takeoff stagger have to be sized with enough margin to avoid ever needing a runtime intervention.

This is another item in the MAVLink-leading, AirSDK-bridged product strategy: every pre-allocated safety feature ships on both platforms; runtime-dynamic safety is a MAVLink-only capability.

GPS-denied interaction

The runtime proximity sweep uses the best position estimate the ground station has for each drone. With a clean GPS fix that’s accurate to a few metres. During GPS loss, the drone falls back to VIO (visual-inertial odometry), and its reported position drifts linearly with flight distance — maybe 0.1–0.3% of distance flown. A drone that’s been flying for 30 minutes on VIO could be tens of metres off its reported position. During heavy GPS loss the runtime sweep gets fuzzier.

This is why the pre-allocated altitude bands carry the real load. They’re computed at mission plan time from GPS-anchored waypoints and don’t depend on live position reporting. A drone on VIO knows its assigned altitude from the mission upload; it stays in its band regardless of GPS state. The runtime sweep is a refinement for clean-GPS operation, not the primary safety layer.

Observability

Every collision-avoidance action is logged with:

  • The two drone IDs involved
  • Horizontal distance at detection
  • Vertical separation at detection
  • New altitude assigned to the yielder
  • Elapsed mission time

The operator sees this in the alert stream in real time. Post-mission, the full log is exportable — useful for debriefs, for demonstrating to regulators that the fleet is operating within spec, and for tuning the altitude-band allocation in future missions (a sector that repeatedly triggers runtime interventions suggests its pre-allocated band is too tight).

Try it

Launch the Simulator →

Set fleet size to 16, draw a rectangle, hit Run Demo. The Sectors card recommends 4 sectors × 4 drones each (on ANAFI XLR, discontinuous — but the takeoff animation is what matters here). Watch the launch sequence: sector by sector, 5 seconds apart, each drone climbing to its own transit altitude before the next sector clears its bays. Open the alert panel after a few relay cycles — in normal operation you won’t see any collisionAvoided events, because the bands worked. That’s the point.