aero-safe-rl
Drone fault recovery · PX4 + Isaac Sim

A motor weakens. PX4 doesn't notice. A learned policy flies it home.

A quadcopter loses thrust on one rotor in the middle of a mission. This project trained a recovery policy on simulated drones at once in NVIDIA Isaac Sim, then tested it where it counts: inside the real PX4 autopilot, on evaluated flights in Gazebo.

of missions finished by the learned policy when a rotor is 20–35% weaker
rule-based controller:
points
more missions finished right below the physics limit, 40% weaker
against with no recovery
of
comparisons fixed before the first flight hold up
the ones that don't are reported too
flights analysed, all flown by PX4 in Gazebo
planned, in runs
The problem

A weak rotor is a quiet failure

Propellers chip, motors wear, connectors loosen. The rotor keeps spinning, only weaker. PX4, the open-source autopilot flown here, keeps the drone level by driving that rotor harder, and its own failure detector stays silent: it raised nothing on any of the 178 weak-fault flights in this project's fault dataset (details).

front rightback leftfront leftback right

Each bar is the most thrust a rotor can still give. Hovering level takes about 59% from each, so once the weak rotor drops below the line (about 41% lost) no controller can hold the drone level (derivation).

How those flights ended, in PX4

How it works

PX4 flies the drone. The policy is the navigator.

Nothing inside PX4 is changed. A fault detector reads its telemetry, and a recovery policy turns that into three high-level commands. It never touches a motor.

in Gazebo

Rotor-fault plugin

Weakens one rotor, suddenly or over a few seconds, at a random moment of the mission.

250–1000 times a second

PX4 autopilot

Stock and unmodified. Mixes the motors and keeps the drone level, as on a real flight controller.

10 times a second

Telemetry over ROS 2

Attitude, body rates, motor outputs and position, exactly as PX4 publishes them.

10 times a second

Fault detector

Five small neural networks reading the last few seconds: is there a fault, which rotor, how weak.

decisions a second

Recovery policy

Trained with reinforcement learning. Sees the telemetry and the detector's estimate, never the true fault.

Back to PX4 as ordinary setpoints: speed: altitude: land now, and it can't be undone
Two simulators

Train in the gym, sit the exam in PX4

Reinforcement learning needs millions of flights, and PX4 in Gazebo flies one drone in real time. So the policy trains in Isaac Sim, where drones fly at once on one graphics card against a PyTorch copy of PX4's controller that passes all 16 agreement checks with the real one (details). The two sides share only files. Every reported number comes from PX4.

Architecture: Isaac Lab trains the recovery policy on thousands of parallel drones; the two environments exchange only files; the PX4-in-the-loop stack of Gazebo, stock PX4, ROS 2, the fault detector and the recovery policy produces every reported number.
Results

What flights say

Every condition flew the same schedule of faults (the same rotor, severity and moment, drawn once from seed ), so any two conditions can be compared fault by fault. Rates carry 95% intervals. Ten comparisons were written down before the first flight.

How flights ended, by how weak the rotor was

The learned policy finishes almost every mild-fault mission, and some right below the physics limit where the others finish almost none. Past the limit, everything comes down.

Finished the mission

Crashed

Dots are rates, bars their 95% intervals; hover for flight counts. Source: results/m10/results.json, main.

Ten comparisons fixed before flying: hold

A difference holds when its whole 95% interval sits on one side of zero. All three that hold are about finishing the mission; none of the crash comparisons does.

Difference in percentage points, first condition minus second. Source: comparisons.

Does the fault detector matter?

Barely. A perfect detector, a late one and none at all give the same rates. On the identical fault, the policy's flight ends the same way with a perfect detector of the time, and with no detector .

Finished, rotor 40% weaker

Crashed, rotor 45% weaker

Source: delay_curve, detector_use.

Did Isaac Sim predict PX4?

Mostly. Isaac's rate falls inside PX4's interval in of cells for finishing and of for crashing. Where it misses, PX4 was kinder.

Finished

Crashed

One dot per policy and severity; hollow = outside the PX4 interval. Source: transfer.

How hard it came down

Every recovery method lands more softly than PX4 alone at 40%. From 45% up, every method's median is past the crash line.

Median touchdown speed of flights that came down. Source: descriptive.

Training in Isaac Sim

The three training seeds flown on PX4, each updates on drones, and in grey seven more trained the same way to check they are typical (below). The three curves end within a few points of each other, yet on PX4 at 40% they finish , and . A training curve alone does not say which policy will do best.

Isaac Lab training curve, not a result Source: results/m9_train/*/metrics.csv.

More than flying slower?

Holding the policy's own average commands for the whole flight finishes at 40%, against for the policy. Its gain comes from reacting in flight.

Longer training

One policy trained for 600 updates crashes at 35–50%, against with no recovery: . The only one that cuts crashes.

No panic on healthy flights

The learned policy commanded a landing on of healthy flights. A recovery method that lands good drones is worse than none.

Honest limits

What it does not do

A method that wins everywhere mostly means it was not tested hard enough. These are the results that did not go the policy's way.

It does not reduce crashes

With the rotor 40–50% weaker the learned policy crashes , no recovery , rule-based . Neither difference holds.

At mild faults it only matches doing nothing

PX4 alone finishes of those missions; the policy . Its big win is over the rule-based controller, not over PX4.

The detector makes no measurable difference

With perfect fault information the policy finishes at 40%; with the real detector . It raises the alarm on almost every fault, and the policy barely reacts to it.

Past the limit, everyone comes down hard

At 45%, the median touchdown is , above the m/s crash line for every method. Physics wins there.

Isaac is not always right

finishing cells fall outside PX4's interval, nearly all at 40%, where PX4 finished more missions than Isaac predicted.

Four flights never got their fault

Found while building this site: in 4 flights the fault never began. Re-flown with the fault applied, three ended the same way and one crashed; no verdict changes (details).

Generalization

Where it stops working

more flights in settings the policy never trained on. It is never worse than no recovery on mild faults or crashes. Its edge right below the limit survives some shifts and vanishes in others.

Finishing right below the limit: learned against no recovery

Each setting's pre-registered check that the learned policy finishes more missions than no recovery right below the limit (settings that tested only "not worse" are left out). Source: results/m11/results.json, settings.

The detector does not generalize either: in 2 newtons of wind it raised an alarm on of healthy flights, against of without wind. The policy still landed none of them.

Checked again

Before the paper, every verdict was re-tested

None of these checks was fixed before flying, so none is a new verdict. Each asks whether the results above survive a harder look.

A stricter bar

Ten comparisons tested at once deserve a stricter standard. Held to intervals instead of 95%, still hold. At 40% the corrected intervals start just above zero: and points.

Where the crash line is drawn

At the m/s line fixed in advance, the learned policy does not crash less than no recovery. Count every touchdown above 1.5 m/s as a crash and it does, , because it comes down more softly. At 2.5 m/s it does not.

PX4's silence, recounted

Counting only faults the plugin confirmed had begun, PX4's own failure detector stayed silent on of flights with the rotor 20–40% weaker, and still on of at 80–100%.

Every number regenerates

One command re-derives every number in the paper from the archived flight logs, on a fresh copy of the code, and compares each with the published files. Every one matched (how to reproduce).

Are the three flown seeds typical?

seeds trained with the same recipe, of them passing the check a policy must pass before it may fly on PX4. Rotor 40% weaker, they finish of missions on average in Isaac; the three flown on PX4, .

Isaac Lab diagnostic, not a result Dots: each seed, the three flown on PX4 in colour. Ticks: the mean of all seeds (grey) and of the flown three (colour). Rule fixed before training: configs/rl/diagnostics_v1.yaml. Source: results/m13/results.json, isaac.seed_spread.

What does the policy sense the fault from?

The policy barely uses the fault detector, so it must read the fault from how the drone flies. To find which inputs, each group was blanked in turn and the three flown seeds flown again in Isaac.

Isaac Lab diagnostic, not a result Bars: the three seeds' mean; ticks: each seed. Red: carries the fault signal; amber: needed to fly at all; grey: neither. Solid line: nothing blanked; dashed: half of that. Rule fixed before any run: configs/rl/diagnostics_v1.yaml. Source: results/m13/results.json, isaac.blanking.

Engineering

Built to be trusted

One simulator per drone

Every worker gets its own Gazebo server, clock and identity file. Nobody shares a world, so one crash never poisons another flight. A test kills one autopilot mid-flight and checks the other flies on.

planned flights

Flown on a laptop and spot cloud machines, two simulators each. were lost to worker restarts and are reported, not hidden.

Frozen before flying

Each sweep file was fingerprinted before its first flight; changing it means a new version, never an edit. Trials ran on their own seeds first.

Explore every flight Read the code The bug bestiary