Skip to content

Drone Mission Governance

ProjectWyvern, the autonomy plane I built to sit between the people who approve drone missions and the drone's own flight controller. It checks a mission before take-off, then flies it while a safety guard watches telemetry. This page rebuilds that logic and tests which faults end a flight.

Original built with Python · FastAPI

What I found

6 of 6 waypoints

flown with no telemetry at all, after the pre-flight check passes with two warnings. The mission said: if the link is lost, return to launch.

3 of 5 faults

bring the flight home when they start mid-flight. The other two, stale or missing telemetry, are only logged, and the flight goes on.

0 checks

of the drone after an operator pauses and resumes a mission: the loop that watches the flight ends at the pause, and nothing restarts it.

Try it

Every mission must declare what the drone does if its link is lost; the sample mission says return to launch. Nothing in the code reads that field. With no telemetry at all, the mission passes its pre-flight check with two warnings and flies all 6 waypoints; when telemetry goes stale or stops mid-flight, the safety guard logs it and the flight goes on.

This is Wyvern's software layer, not an aircraft: the vehicle here is the original project's mock, and a real PX4 flight controller has its own link-loss failsafe.

Telemetry is the drone's live status: battery, link quality, position estimate. Each row is one telemetry fault, either present at the pre-flight check or starting after waypoint 2. The route is the original's sample, a triangle of 3 waypoints flown twice (6 in all), so a fault that starts mid-flight still has a flight left to change. Pick a cell to fly it on the map below.

home after waypoint N: the guard workedstopped at the pre-flight check: the check workedflew the whole route while the guard could not see the drone

FaultPresent at the pre-flight checkStarts after waypoint 2
Healthy telemetry
Battery below the floor
Weak link
Estimator fault
Stale telemetry
No telemetry

Two more to try: set the fault after a pause and resume, and nothing watches the flight again; pick the notched fence, and a leg crosses the fence the check passed.

Fault
When
Route
Fence and route: 6 of 6 waypoints flown flown not flown yetZoomed to the route; the fence is far outside this view.

flew all 6 waypointsmission completed

Pre-flight check

  • geofence containmentpassed
  • altitude limitpassed
  • battery thresholdwarning · no telemetry to check
  • telemetry freshnesswarning · no telemetry to check
  • remote id compliancepassed
  • airspace authorizationpassed
The event log, with the original's codes

Event log, on a simulated clock

  1. 0.0 svalidatedwyvern_validator · mission.validated
  2. 0.0 sawaiting_approvalwyvern_validator · mission.awaiting_approval
  3. 0.0 sapprovedoperator:chimera · mission.approved
  4. 0.0 sstagingwyvern_executor · mission.staging
  5. 0.0 sexecutingwyvern_executor · mission.executing
  6. 0.0 slogged 5×safety_guard · blocked.no_telemetry, and nothing else
  7. 0.5 scompletedwyvern_executor · mission.completed
Contents

Who decides a flight should end?

ProjectWyvern governs drone missions between a control plane that approves them and a flight controller that flies them. A mission is validated before flight, approved by an operator, then executed by a loop that polls the vehicle and asks a safety guard whether to keep going. Its contract makes every mission declare what to do when the link is lost: hold, return to launch, or land. The sample mission says return.

The question this page asks the code is simple: when the guard cannot see the vehicle, what happens to the flight? The answer comes from Wyvern's own validator, guard and executor, run against its own sample mission. It is about Wyvern's software layer, not an aircraft: a real PX4 flight controller has its own link-loss failsafe, which this page does not model.

What each fault does

The guard names six kinds of trouble and sorts them by prefix. A battery under the 25 percent floor, a link quality under 0.3 and an estimator (the flight controller's estimate of the drone's position) that is not nominal are “degraded”; a mission past its 600-second timeout is “timeout”. The executor returns to launch on those. No telemetry at all, or telemetry older than 1500 milliseconds, is “blocked”, and the executor only logs it. Nothing in the code reads the declared link-loss policy.

So the faults split. Started after waypoint 2 of the sample route flown twice, three bring the flight home at the next waypoint, and two, stale or missing telemetry, are logged while the flight finishes all 6 waypoints. Before flight it is worse for the case that matters most: with no telemetry at all, the battery and freshness checks become warnings rather than failures, the mission passes, and it flies. The link and the estimator are not checked before flight at all.

Two more gaps. The pre-flight fence check tests the waypoints, not the legs between them, so a straight leg can cross a concave fence between two waypoints inside it; pick the notched fence, this page's own example, in the demo. And the resume route sets a paused mission back to executing without restarting the executor, whose loop ended at the pause: after a resume, a battery failure goes unseen and the mission stays executing at waypoint 2, with nothing polling, guarding or completing it.

Status: a simulation-phase build. ProjectWyvern's roadmap puts it in phase 1, a simulation-only MVP, in progress, with battery and link-loss handling planned for phase 3, the hardware MVP. These gaps are what a simulation-phase build has not wired yet.

What this page is not

A flight test. It runs Wyvern's own lifecycle logic on one sample mission with a mock vehicle: no aircraft, simulator or flight controller, and nothing here is airworthiness or regulatory evidence.

For engineers

The state graph, the validator and the executor loop, the check against Wyvern running in Python, and how to reproduce it.

How the lifecycle runs

Fifteen states, one graph. The 15 states run from draft through validation, approval, staging and execution to completed, with branches to pause, resume, return to launch, abort, fail and hand over to a pilot. Every transition is checked against the graph and recorded with its actor and reason.

Before flight. The validator checks that every waypoint is inside the fence and under 30 metres, that the cached battery is above its floor and the telemetry fresh, that Remote ID is active when required, and that a Part 107 flight has an airspace authorization reference. A failure stops the mission before approval; a warning does not.

In flight. The executor uploads the route, arms and starts the vehicle, then polls every 100 milliseconds: if the vehicle has reached its last waypoint the mission completes, and otherwise the guard runs. Completion is checked first, so a fault on the final waypoint is never seen.

Checked against the original

The graph, the validator, the guard and the executor loop are ported from state_machine.py, validation.py, safety_guard.py and executor.py, with the vehicle as the source's mock, which reaches one waypoint per poll, on a virtual clock. To check it, Wyvern itself was run in Python on its sample mission: its validator, then its executor with its guard and mock vehicle, for every fault at the pre-flight check and mid-flight, a stalled flight past its timeout, and a pause and resume. The port matches 14 of 14 recorded runs: the same checks, the same final state, the same waypoint, the same reason.

Where this comes from

ProjectWyvern is the autonomy plane of my Chimera ecosystem: a FastAPI service that owns mission validation, command arbitration, execution, telemetry normalization and replay, between the Chimera control plane and a PX4 or ArduPilot flight controller. Its design puts the flight controller's own failsafes at the top of its authority hierarchy, above the pilot, the operator and Wyvern itself. A real PX4 has its own link-loss failsafe, so what this page shows is Wyvern's layer not acting on the policy it asks every mission to declare, not what a particular aircraft would do.

Limits in detail

The vehicle is the source's mock, which reaches a waypoint per poll and has no failsafes of its own. Telemetry is the cached record the guard reads, set per scenario. The fence and route are the source's synthetic sample, and the notched fence is this page's own example. The leg check is this page's addition; the source does not make it.

Reproduce it

Pick cells in the table and fly them on the map; set the fault after a pause and resume and watch the mission stay executing; pick the notched fence and see the leg leave it. The event log, with the source's own codes, is under the hood. The port, the recorded Python runs and the tests are in the code for this page. From the site's Next.js app:

npx vitest run src/lib/projects/mission-governance src/components/projects/mission-governance