surveillance_monitoring_operations implements the seven ASTM F3623 SDSP service-performance metrics (heartbeat rate, delivery probability, MTTR, MTBF, etc.) โ it does not compute RF-propagation coverage geometry. The coverage-zone concept fills a real, currently-unimplemented field in the standard's own HealthMessage struct.SET_POSITION_TARGET_GLOBAL_INT), not ADS-B injection into ArduPilot's native AP_Avoidance โ though both remain operator-configurable per deployment.DefaultAvoidanceEngine doesn't just pick a rule โ it generates five candidate maneuvers, forward-simulates each against the intruder's projected track, and selects whichever candidate produces the best predicted post-maneuver separation that isn't geofence-blocked. This is what "rich avoidance" means in practice.fly_to_point DRC method accepts an explicit target altitude (WGS84 ellipsoidal or dock-relative), wayline missions support breakpoint resume after a DRC interruption (hardware-gated, and DJI's own dock explicitly warns against auto-resuming after an obstacle event), Edge SDK is confirmed video/AI-only with no flight-command surface, and FlightHub 2 cannot run alongside a self-hosted Cloud API binding โ it's strictly either/or at the dock.The hybrid DAA architecture spans three components. Each has exactly one job, and none of them duplicates another's reasoning โ this separation is what keeps the system auditable and lets any one layer degrade without silently corrupting the others.
This section is grounded directly in the am-flyrtm-blender repository (a Flight Blender / InterUSS derivative), not just the whiteboard. Four subsystems carry the pipeline from a live telemetry frame through to a delivered avoidance command.
conflict_detection.py)Analytical closest-point-of-approach (CPA) time is computed between ownship and each intruder, backed by a discrete trajectory-sampling check (_sample_min_separation) over a time horizon as a secondary verification. Separation is then mapped straight onto ASTM F3442 alert tiers:
| Alert Level | Trigger | Meaning |
|---|---|---|
| WARNING | Horizontal & vertical separation below NMAC thresholds | Near mid-air collision predicted |
| CAUTION | Separation below Well-Clear thresholds | Well-Clear breach predicted |
| ADVISORY | Separation below 1.5ร Well-Clear thresholds | Approaching Well-Clear |
| NON_ALERT | Separation above all thresholds | No conflict |
alert_lifecycle.py implements ASTM F3442 ยง8.2 alert creation/escalation/resolution and ยง10.2.3 periodic logging, with latency instrumentation at every hop (processing latency, sensor latency, alert-notify latency โ all measured, not assumed). Once an alert escalates, avoidance.engine's DefaultAvoidanceEngine selects a maneuver per ASTM F3442 ยง9.2, and avoidance.ground_risk filters that maneuver against geofence exclusion zones before it's ever sent anywhere โ the Runner never receives a maneuver that hasn't already been checked against ground risk.
This is the part that makes it rich avoidance rather than a fixed rule: DefaultAvoidanceEngine.compute_maneuver() doesn't just apply a lookup table, it generates several candidate maneuvers and predicts the outcome of each one before picking a winner.
_sample_min_separation trajectory sampler used for detection, producing a predicted post-maneuver minimum separation for that specific candidate.avoidance.ground_risk.trajectory_enters_geofence checks each candidate's projected path against the active geofence set. Any candidate that would enter a geofence is penalised to near-zero in the scoring โ it can still be selected only if literally nothing else is better, and even then it's flagged infeasible.insufficient_time, ground_risk_conflict, or envelope_limit when it isn't โ rather than silently commanding a maneuver that can't achieve well-clear._send_avoidance_command() and maps directly onto both the DJI DRC live-control channel and MAVLink's streamed SET_POSITION_TARGET_GLOBAL_INT loop described in ยง5 โ the Runner translates the maneuver into protocol-native commands, it never re-derives where to go.
surveillance_monitoring_operations was initially assumed to compute RF-propagation coverage volumes. It does not. It implements the seven ASTM F3623 SDSP service performance metrics via SurveillanceMetricCalculator: heartbeat rate, heartbeat delivery probability, track update probability, per-sensor MTTR, auto-recovery time, MTBF (with/without auto recovery), and failure notifications. This is about whether the surveillance service is performing to spec over time โ not where it can physically see.
HealthMessage dataclass already carries a field: machine_readable_file_of_estimated_coverage: str โ currently an unused placeholder in the repo. ASTM F3623 itself anticipates exactly the RF-propagation coverage model under discussion. Building it fills a real, existing hook rather than bolting on an unrequired feature.
| Concept | What it measures | Status |
|---|---|---|
Seven SDSP metrics (SurveillanceMetricCalculator) | Service reliability over time โ is the sensor delivering heartbeats/tracks at the required rate | Implemented |
Sensor health (SurveillanceSensor, SurveillanceSensorHealth) | Operational / degraded / outage status per registered sensor | Implemented |
| Coverage Propagation Model (new) | Spatial geometry โ where the sensor can physically see | Planned โ fills HealthMessage.machine_readable_file_of_estimated_coverage |
These are two distinct, legitimate axes of SDSP health per the standard โ reliability and geometry โ not competing designs. Both feed the same HealthMessage published up through the notification path.
This mirrors TCAS-style monitoring rather than gating: the safety-critical path (RTM โ Runner) has no extra hop that can add latency or become a silent single point of failure, and the Custodian becomes a true independent check rather than a relay that could itself fail to pass something along.
Grounded in notification_helpers.py: the avoidance command and the proximity alert are not delivered identically.
| Message | Channel | Priority |
|---|---|---|
Avoidance command (_send_avoidance_command) | AMQP only โ flight declaration's own queue | critical |
Proximity alert, active or resolved (_send_proximity_notification) | AMQP and MQTT topic daa_alerts | info / warning / critical by alert level |
On the MAVLink side, the Runner has two mechanisms available to actually cause an avoidance maneuver. Which one runs is an operator-configurable deployment setting โ FLYsafe's default deployment uses Guided Mode.
| Path A โ ADS-B Injection Alternative | Path B โ Guided Mode FLYsafe Default | |
|---|---|---|
| Mechanism | Runner synthesizes an ADSB_VEHICLE message from intruder position and injects it into the MAVLink stream as a sensor contact. | Runner receives RTM's already-computed maneuver and streams SET_POSITION_TARGET_GLOBAL_INT at heartbeat rate โ not the one-shot DO_REPOSITION. |
| Who decides the maneuver | ArduPilot's own AP_Avoidance library, using its tuned AVD_* parameters (action, warn/fail distances). | RTM โ the maneuver was already checked against ground risk and geofences before the Runner ever sees it. |
| Runner's role after the trigger | Ends at injection. No further command sent. Lower runner control, lower latency. | Continuous โ keeps re-asserting the setpoint, watches live telemetry (GLOBAL_POSITION_INT, TERRAIN_REPORT) to confirm actual execution, commands climb-back once RTM signals the conflict is clear. |
| Known risk | Depends entirely on ArduPilot's own tuning being correct for the deployment. | GUIDED setpoints outside a loaded fence can be silently rejected โ COMMAND_ACK alone is not trustworthy; telemetry confirmation is mandatory. |
ยง5 describes the two MAVLink-side mechanisms as an either/or operator setting. In practice they stack โ along with a hardware floor below both of them โ into a three-tier fallback ladder that runs from "always on, no intelligence" up to "richest available, requires the cloud." This reframes the Runner's role: it isn't only a translator for RTM's commands, it's also a local sensor-aggregation and injection layer that keeps functioning when RTM isn't reachable at all.
| Tier | DJI | MAVLink / ArduPilot | Requires RTM link? | Who decides |
|---|---|---|---|---|
| 1 โ Hardware floor | Native onboard vision/infrared obstacle detection. Universal, always on, independent of Runner or RTM. | Optional Only present if the airframe has physical proximity sensors (Lidar, sonar, RealSense) wired to ArduPilot's own PRX parameters. |
No | Flight-controller firmware itself โ physical-object stopgap only, no traffic awareness |
| 2 โ Local sensor injection | Runner aggregates whatever's wired to the companion computer (1090/978 ADS-B receiver, camera, acoustic sensor, etc.) and synthesizes a sensor-contact injection feeding the onboard avoidance logic locally. | Same mechanism โ Runner synthesizes an ADSB_VEHICLE message from aggregated sensor data and injects it into the MAVLink stream; AP_Avoidance reacts via its tuned AVD_* parameters. This is ยง5's "Path A." |
No โ this is the no-connectivity fallback | Onboard avoidance logic (DJI) / AP_Avoidance (ArduPilot), reacting to Runner-fed sensor data |
| 3 โ Cloud DAA | RTM's forward-simulated, geofence-checked maneuver from ยง2, delivered over the DRC channel (DJI) or streamed Guided Mode setpoints (MAVLink โ ยง5's "Path B"). Definitive when available. | Yes | RTM (DefaultAvoidanceEngine) |
|
"Rich avoidance" in ยง2 means every candidate maneuver RTM considers is already checked against active geofences before it's ever published. That check is only the cloud-side half of the picture. The same fence set is distributed in parallel to more than just RTM's own filter:
FENCE_TYPE, ArduPilot-onlyThe reason to push the fence set all the way onto the autopilot, and not only hold it cloud-side, is Tier 2. A Tier-2 local-injection maneuver never touches RTM โ there's no cloud ground-risk filter in that loop by definition, since it's the fallback for exactly the case where RTM isn't reachable. If the onboard fence is loaded natively on the ArduPilot flight controller, the airframe itself refuses to fly into excluded airspace regardless of which tier triggered the maneuver โ ground-risk enforcement becomes a property of the aircraft, not just a property of the cloud reasoning. DJI and Custodian/Runner-held copies serve the equivalent purpose one layer up: the Custodian can flag a Runner action that ignored a fence as a verification failure even without an onboard native fence to fall back on.
MISSION_TYPE_FENCE upload protocol code exists today, and the reference airframe's own parameters show FENCE_TOTAL -103 โ no fence points loaded. RTM's own ground-risk filter (ยง2) and the Custodian/Runner-held copies are real today; the autopilot-native leg of the fence-distribution diagram above is the piece that still needs to be built.
Both protocol implementations follow the same shape: automatic entry, automatic exit โ no manual confirmation gate on either end by default. This matches the precedent already set by UAvionix Casia, which today automatically pushes ArduPilot back into AUTO once its onboard DAA logic clears, relying on operator training rather than a manual resume step.
| Stage | MAVLink / ArduPilot | DJI / Cloud API DRC Channel |
|---|---|---|
| Automatic entry | Runner commands GUIDED mode directly โ no operator confirmation required. | Cloud sends cloud_control_auth_request; RC authorizes; aircraft reports is_cloud_control_auth = true. |
| Command delivery | Streamed SET_POSITION_TARGET_GLOBAL_INT at heartbeat rate โ deterministic descent and hold. | Joystick-style near-real-time commands over the DRC live-control MQTT channel. |
| Mission handling | GUIDED holds the setpoint continuously while the Runner keeps re-asserting it. | Waypoint mission is canceled while cloud control is active โ native DJI behavior, not FLYsafe-specific. |
| Operator visibility | Runner sends STATUSTEXT directly into the Mission Planner messages panel โ "entering DAA mode." | FlightHub 2 control-status and mode flags only โ Gap no free-text HUD equivalent today. |
| Automatic exit | Once RTM signals the conflict cleared, Runner commands mode back to AUTO and sends a second STATUSTEXT. | Runner automatically releases DRC authority. |
| Mission resumption | Resumes AUTO mission directly. | DJI Dock's native "Resume Flight From Breakpoint" resumes rather than restarting โ Caveat hardware-gated (confirmed M30/30T, Mavic 3E/3T/3M only) and DJI's own dock explicitly warns against auto-resuming after an obstacle-triggered stop. See ยง13. |
| Manual override | Optional configurable fallback โ manual resume gate for operators who want tighter control. Not the default. | Not modeled โ automatic release is DJI-native behavior. |
STATUSTEXT message bus straight into the GCS HUD. DJI has no equivalent today โ the operator relies entirely on FlightHub 2's own UI state. Operator training therefore differs by platform: "watch Mission Planner's message log" vs. "watch FlightHub 2's control-status indicator." This asymmetry is closed at the tooling layer, not the protocol layer โ see ยง9.
Worth being precise about this, since it's the actual differentiation story.
AP_Avoidance reacting to injected ADSB_VEHICLE messagesDAA_* parameter set (DAA_AVD_ACTION, DAA_AVD_ALERT, DAA_AVD_ALT, DAA_MARGIN_FENCE)FENCE_TYPE, FENCE_TOTAL, mission-protocol polygon uploadThe honest boundary: ArduPilot is the muscle โ dumb and reactive, doing exactly what any operator's ArduPilot does. FLYsafe's differentiation is the orchestration layer above it: cloud DAA reasoning, delivery-and-trust verification through the Custodian, and the Runner's translation-and-confirmation logic that turns a cloud-level "avoid this" into a reliable, provably-executed action on a stock autopilot โ without modifying the autopilot itself. That's a strength: it works on any ArduPilot airframe without custom firmware.
The same RTM message and status stream branches out to two thin, surface-specific injection points โ closing the DJI visibility gap identified in ยง7.
| Mission Planner Plugin | FLYsafe.live RTM Chrome Extension | |
|---|---|---|
| Status | Already built | New, planned |
| Host | Mission Planner desktop GCS (MAVLink) | Any browser-based GCS โ FlightHub 2 today, extensible to Skydio or other web consoles |
| Mechanism | Native plugin injecting STATUSTEXT-style messages directly into Mission Planner's messages panel | Browser extension augmenting the web page UI directly โ not a DJI API integration |
| What it surfaces | DAA mode entry, DAA mode exit, avoidance maneuver status | DAA messages, status changes, and control-state updates as an in-page overlay or banner |
| Why it matters | Operator's existing tool, no new install | Fills the DJI visibility gap โ no native STATUSTEXT equivalent exists in FlightHub 2 itself |
ยง3 and ยง9 describe the Autopilot Runner as software living inside the operator's existing GCS session โ the Mission Planner Plugin, the Chrome GCS Plugin. That covers the attended case, where a human is at a laptop running Mission Planner or a browser for the duration of the flight. It does not cover unattended, dock-based operations โ a DJI Dock cycling missions with nobody at a console, or a fixed MAVLink installation with no GCS laptop physically present. The intent going forward is to standardize the Runner's deployment for exactly that case onto a small, dedicated piece of onboard/dock hardware, so the Runner becomes a physical unit that ships once and works the same way regardless of airframe or dock vendor.
Wiring an SBC to the autopilot (or to the dock's internal network switch) over RJ45/Ethernet rather than USB, serial, or a vendor-specific breakout cable keeps the hardware side of the Runner drone-agnostic: Ethernet is already the physical layer DJI Dock installations use internally, and it's a standard, shielded, long-run-tolerant connector that any MAVLink companion-computer carrier board can expose as well. A single cable class means the same mounting kit and cable run works whether the target is a dock-side network port or an onboard companion-computer Ethernet header โ no per-airframe adapter cables to stock, qualify, or lose in the field. Where the candidate hardware also supports Power-over-Ethernet (see below), the same single cable carries both data and power, which materially simplifies onboard wiring compared to running a separate power rail alongside a data cable.
Two small-form-factor SBCs are under evaluation as the standard Runner hardware unit. Neither has been bench-tested or committed to yet โ this is a candidate list, not a finalized BOM.
DefaultAvoidanceEngine outputs a heading change and a target vertical rate, held for a duration โ a rate command, not a position. Neither execution path can consume that directly: MAVLink Guided Mode needs a projected lat/lon/alt target (streamed via SET_POSITION_TARGET_GLOBAL_INT), and DJI's DRC channel needs joystick-style stick-equivalent commands. Someone has to own the translation from "heading delta + vertical rate + duration" into each protocol's native input. Open design question: does RTM itself compute and publish the projected lat/lon (so the maneuver message already carries a position target), or does the Runner own that projection locally from RTM's heading/rate output? Whoever owns it needs to be decided before the Runner-side execution work (below) can be built against a stable contract. Flag as unresolved โ needs a decision, not just implementation.aircraftagent.py โ note: this codebase is actively in fluxmavlink_do_reposition, mavlink_nav_loiter_time, mavlink_nav_loiter_turns, mavlink_set_mode) exist but are one-shot position commands, not a streamed rate/setpoint loop, and none of them are called anywhere today. Once the translation question above is settled, need a real heartbeat-maintained SET_POSITION_TARGET_GLOBAL_INT loop, telemetry-based confirmation against silent fence rejection, and an AMQP consumer for command_type == "avoidance_maneuver". This snapshot reflects the runner repo at time of writing โ expect it to move.MISSION_TYPE_FENCE protocol code exists yet. FENCE_TYPE 4 is set in drones/dellvostro/mav.parm but FENCE_TOTAL -103 โ no fence points loaded. This is the concrete implementation gap behind the geofence-distribution model in ยง6: the architecture calls for the same fence set to reach the onboard autopilot for ArduPilot airframes, but the upload path itself doesn't exist in code yet.send_rtl_to_rtm()) โ needs an equivalent for avoidance-command-issued / acked / rejected and fence-upload-status, feeding the Custodian's verification loop described in ยง4.The six diagrams below are recreated directly from the "FLS - Architecture Sept 2026" FigJam board (source: figma.com/board/gO1lwj33cuJpnsw0fdSI7U), box for box and label for label, so the board's full detail is permanently part of this document rather than a link or a screenshot that can drift out of sync. Each diagram links back to its exact spot on the live board and notes which section of this document it backs up.
HealthMessage coverage fieldADSB_VEHICLE injection, guided setpointFlightDeclaration โ operational intent, volumescustom_volume_generation โ operational and contingency volumesdeconfliction_engine and protocol โ strategic deconfliction vs. other declared flightsscd_operations / dss_scd_helper โ DSS submission and federation, ASTM F3548conformance_monitoring_operations โ state machine: accepted, activated, nonconforming, contingent, withdrawnFlightObservation โ telemetry ingestionrid_telemetry_helper โ Remote ID telemetry normalizationrid_operations โ ASTM F3411 network Remote ID complianceflight_stream_helper โ live feed distributionaircraft_state โ ownship and intruder state, track_cacheconflict_detection โ analytical CPA time, discrete trajectory sampling, alert level: NON_ALERT / ADVISORY / CAUTION / WARNINGalert_lifecycle โ alert creation, escalation, resolution, periodic logging (ยง8.2, ยง10.2.3)avoidance.engine โ DefaultAvoidanceEngine, maneuver selection (ยง9.2 โ see ยง2 candidate-generation detail)avoidance.ground_risk โ geofence-aware maneuver filteringnotification_helpers โ builds AMQP and MQTT payloadsdaa_notifications โ DAAConformanceNotification wrapperSurveillanceSensor / SurveillanceSensorHealth โ registered sensors: operational, degraded, outageSurveillanceMetricCalculator โ 7 SDSP metrics: heartbeat rate, heartbeat delivery probability, track update probability, MTTR, auto-recovery time, MTBF, failure notificationsHealthMessage โ current_status, scheduled_degradations, machine_readable_file_of_estimated_coverageHealthMessagegeo_fence_operations โ exclusion zone geometrynotification_operations โ NotificationFactory, AMQP deliverygeo_fence_operations) โ Cloud DAA: exclusion geometrycommand_type: avoidance_maneuver, critical, AMQP onlydaa_alertsADSB_VEHICLE message from intruder positionAP_Avoidance evaluates threat using AVD_* parameters โ action, warn/fail distancesSET_POSITION_TARGET_GLOBAL_INT at heartbeat rate โ not one-shot DO_REPOSITIONGLOBAL_POSITION_INT, TERRAIN_REPORT) to confirm actual executionCOMMAND_ACK alone is not trustworthySET_POSITION_TARGET_GLOBAL_INT at heartbeat rate โ deterministic descent and holdSTATUSTEXT to Mission Planner's messages panel โ "entering DAA mode"GLOBAL_POSITION_INT, TERRAIN_REPORT) โ confirms actual execution, doesn't trust COMMAND_ACK aloneSTATUSTEXT โ "DAA mode cleared, resuming mission"cloud_control_auth_request, RC authorizes, aircraft reports is_cloud_control_auth = trueSTATUSTEXT-equivalent free-text HUD message todaySTATUSTEXT-style messages directly into Mission Planner's messages panelSTATUSTEXT equivalent exists in FlightHub 2 itselfThis board diagram documents the same fanout/topic-exchange redesign already fully diagrammed as Fig. 2 in ยง4 โ RTM Core, the AMQP fanout exchange, Custodian's and Runner's own bound queues, verification, and tiered DAA status reporting back to RTM โ down to the same two callouts captured there: Custodian previously relayed the command to the Runner as a middle hop; now Custodian and Runner are parallel, independent subscribers to the same exchange, and AMQP queues are competing-consumer by default, so both must bind their own queue to a fanout or topic exchange to each receive every message. Not redrawn a second time here to avoid duplicating Fig. 2 pixel-for-pixel โ see ยง4 directly.
This section corrects and expands the DJI framing used earlier in this document (ยง5โยง7), based on a direct read of DJI's Cloud API and Edge SDK documentation. The short version: DJI avoidance execution is not limited to raw joystick-style stick input as originally framed, and the "put compute on the dock to skip the cloud" idea does not hold up against DJI's actual SDK boundaries. Everything below is grounded in DJI's own public docs (dji-sdk/Cloud-API-Doc, dji-sdk/Edge-SDK, and DJI's developer/enterprise-insights sites) โ flagged where something is a named feature versus a confirmed field-level schema.
fly_to_point method, not just joystick inputDJI's live flight control feature set, reached only after seizing DRC control authority, includes flight direction control, gimbal rotation control, and one-key taking off and flyto โ a single-point "fly to" command sitting alongside pure directional stick control, not a replacement for the whole DRC concept. The fly_to_point method's payload carries a points array, and each point includes latitude, longitude, and height โ so altitude is an explicit, settable field, not inferred. DJI's docs describe this height as the target point height using the ellipsoidal height, WGS84 model, with the aircraft hovering at the point by default once it arrives. A second, separate altitude reference is also available: relative altitude to the takeoff point (the dock), where the aircraft ascends to a specific height before flying to the target point.
fly_to_point lets you set either a WGS84 ellipsoidal absolute height or a dock-relative (AGL-style) height. Given the NRCan HRDEM/MRDEM AGL/MSL compliance work already established elsewhere in this project, whichever field the Runner populates for a DJI avoidance maneuver needs to be deliberate, not defaulted โ the two are not interchangeable and mixing them up would silently corrupt containment math.
The command is not fire-and-forget: a companion fly_to_point_stop method exists, and DJI's documentation notes the target point can be updated mid-flight without leaving the flyto/DRC process. There's also a minimum-altitude safety floor built into the aircraft itself โ a 20-meter minimum flight altitude safety mechanism, so the aircraft will first rise to 20 meters if commanded below that relative to the takeoff point.
DJI's wayline management system does support pausing and resuming a mission, including resuming flight from a breakpoint: the dock provides breakpoint information to the drone, the drone flies back to that point, and continues the wayline mission from there. The flighttask_resume-style call includes an optional field specifically for resuming from a specified breakpoint. This makes a clean DRC-interrupt-then-resume recovery model plausible: Runner enters DRC, executes fly_to_point as the avoidance maneuver, exits DRC, then calls wayline resume with the breakpoint reference.
| Caveat | What DJI's docs actually say |
|---|---|
| Hardware gate | Breakpoint resume is confirmed supported on Matrice 30/30T and Mavic 3 Enterprise/3T/3M. Not a guaranteed capability across every DJI airframe. |
| Obstacle-triggered stop | A real DJI dock error code (321517) reads: "obstacle detected; task stopped; to ensure flight safety, do not resume task from breakpoint." DJI itself builds in a safety guard against blind breakpoint-resume specifically after an obstacle-triggered interruption โ which is exactly our avoidance scenario. |
For a docked, unmanned deployment (our case), yes โ functionally. DJI's documented sequence is device-to-device: the web/cloud side sends cloud_control_auth_request, and the "Pilot" side (DJI Pilot 2, running as the dock's own software agent, not a human holding a physical remote) agrees and reports back is_cloud_control_auth = true. There is no human-in-the-loop approval dialog inherent to a docked aircraft the way there would be for a handheld RC. Unconfirmed DJI's docs don't spell out "zero human involvement" in plain language for the dock case โ this is an inference from the architecture and sequence diagram, not an explicit guarantee, and should be sanity-checked against DJI support before being treated as load-bearing.
DJI Dock 2 does support integration of an edge computing module, and DJI ships a real product for it: Edge SDK, described consistently across every source as an edge computing development kit for DJI Dock, allowing real-time video recognition and other AI processes for aircraft-transmitted data streams on the local system. DJI frames its whole Cloud API around a device-edge-cloud layered architecture similar to IoT โ but the "edge" tier in DJI's own model is about local data/video processing, not a flight-command bypass.
Conclusion: putting our own compute on the dock does not get us a local bypass around the cloud-mediated DRC authority handshake for flight control. Edge SDK is a legitimate, useful product for local perception/AI workloads at the dock, but it is not an alternate flight-control channel.
Confirming the deployment model: yes, this is a self-hosted server we stand up ourselves (Java backend + EMQX broker are the typical reference stack), and it can run in our own Kubernetes cluster. DJI Cloud API can adapt to any network as long as the DJI Pilot 2 or DJI Dock is allowed to access the third-party platform server, over standard MQTT/HTTPS/WebSocket protocols.
One adjacent, non-real-time bridge is worth noting: FlightHub Sync 2.0 (the successor to the old Cloud Interconnect Beta) adds real telemetry forwarding โ real-time drone telemetry data can now be forwarded to external systems via MQTT โ plus an MQTT Bridge supporting forwarding of the dock's MQTT information to third-party systems as "a collaborative task solution." This means a FlightHub 2-bound dock can still stream telemetry to us. It does not change the control conclusion below.
No, checked and re-checked across three separate research passes. FlightHub 2 has grown its own separate OpenAPI (distinct from the raw dock-to-cloud Cloud API), now expanded to 300-plus endpoints in the on-premises version, covering livestream management, wayline/route management, custom flight zones (create/read/update/delete), device management, and โ via FlightHub Sync 2.0 โ telemetry forwarding out to third parties. Across every source found, FlightHub 2's "FlyTo" and "Live Flight Controls" capability is described purely as a human-facing UI feature inside its browser-based Virtual Cockpit โ a person clicking a FlyTo destination on the map, or using keyboard/mouse to fly the aircraft โ never as a REST/MQTT method a third-party system can call programmatically. One DJI source states this outright: "This function is also available through the Cloud API for developers" โ explicitly marking FlyTo-as-callable-API as a Cloud API/DRC thing, not a FlightHub 2 OpenAPI thing.
Conclusion: the real-time avoidance command surface lives only behind the raw dock-to-cloud DRC channel, which requires our own Cloud API server to hold the seized control authority. FlightHub 2's OpenAPI, however large it grows, does not appear to expose that same capability to third parties.
Raised as a fallback: could a browser extension synthesize input into FlightHub 2's Virtual Cockpit UI to mimic an operator issuing a FlyTo command? Technically plausible โ Virtual Cockpit is browser-based, and DJI's own FAQ confirms third-party controllers work today by mapping joystick buttons to keyboard keys, meaning the UI already accepts synthesized keyboard input as a control path.
| Concern | Why it matters |
|---|---|
| Unsupported automation surface | This automates a human-facing manual-override UI that DJI never documented as an integration point. Any DOM/UI change on DJI's side silently breaks it, with no deprecation notice the way a documented API would get. |
| Requires a live rendered session | Needs an actual browser tab actively running Virtual Cockpit and connected per aircraft โ not a clean headless service the way our other Runner/Custodian agents work. |
| Overlaps existing planned work | This is conceptually the same territory as the Chrome GCS Plugin for DJI FlightHub 2 already in this architecture (ยง9) โ an extension question, not a new component question. |
Worth stating plainly since it's easy to conflate: DJI Cloud API is the protocol layer โ the MQTT topics, methods, and schemas (fly_to_point, flighttask_resume, the DRC channel) that any third-party developer implements against to build their own cloud service talking directly to a DJI Dock. DJI FlightHub 2 is DJI's own first-party application built on that same dock-to-cloud layer โ their reference fleet-management product. FLYsafe is not building on top of FlightHub 2 as a platform; it implements the same Cloud API that FlightHub 2 implements, connecting directly to the dock. The two are alternate implementations of the same interface, not a required stack โ and per ยง13.5, they cannot both be bound to the same dock at once.
No โ checked directly, and this closes off the idea cleanly. FlightHub 2 has no plugin, app-store, or SDK-extension model that allows third-party code to run inside it. Every DJI source describes its OpenAPI the same way: "designed to enable developers to interact with third-party cloud platforms and DJI FlightHub 2" โ the integration direction is FlightHub 2 exposing data and accepting configuration out to external systems, not external code being hosted inside FlightHub 2's own runtime. There is no marketplace or "install this module" pattern anywhere in DJI's developer documentation, for DAA or anything else.
No โ On-Premises is a hosting/data-residency choice, not a different control architecture. It's the same DJI product: DJI is explicit that FlightHub 2 On-Premises delivers the same capabilities as the public cloud version, deployable on private cloud, physical servers, or DJI's pre-packaged AIO appliance instead of DJI-managed AWS, while continuing to work toward full feature parity between the two editions.
Conclusion: On-Premises may be worth adopting on its own data-sovereignty merits, but it doesn't create a path for the Runner to inject avoidance maneuvers into FlightHub 2. Whether public cloud or On-Premises, FlightHub 2 owning the dock's binding excludes our own Cloud API server from holding DRC authority at the same time (ยง13.5) โ the hosting model doesn't change which side owns control.