Article

When an offboard command is invalid but the link stays alive

A companion computer can remain connected to a drone, keep transmitting setpoints at the required rate, and still be sending commands that the aircraft must not execute. Link health and command validity are separate properties. Treating a stream of malformed flight commands as proof that external control is healthy can defeat the very failsafe designed to protect against loss of that controller.

An open PX4 change proposed on 18 October 2026 exposes the failure path through MAVLink's SET_ATTITUDE_TARGET message. Its author reports that a non-finite thrust value can pass the incoming-message checks, propagate to a special internal motor-stop representation and keep Offboard mode's liveness indication current. The proposed fix rejects the entire invalid setpoint, including its contribution to the Offboard heartbeat. This is a proposed correction with author-reported simulation evidence, not a released fix or a measured fleet-wide incident rate.

The broader engineering issue is how an autopilot should decide that an external controller is still in control. A stream of packets is necessary evidence. It is not sufficient evidence when the packets contain unusable actuator requests.

The same NaN can mean two different things

A NaN is an IEEE 754 floating-point value indicating that a numerical result is not a valid number. Such a value can arise in software after invalid arithmetic, an uninitialized calculation or failed numerical conditioning. At a protocol boundary, a NaN in a required thrust field is therefore a warning that the requested command cannot be interpreted as a normal finite control input.

Inside PX4, NaN also has an intentionally defined meaning. The VehicleThrustSetpoint message definition specifies a three-element body-axis thrust vector and states that a NaN on an axis stops motors affecting that axis. That is an internal control convention. It allows components such as motor allocation and vehicle-transition logic to express an explicit stop request without inventing a numerical thrust value.

This creates a dangerous ambiguity if an external numerical error is allowed to cross unchanged into that internal interface. The bits can look the same, but their provenance is different:

  • External input: NaN in a thrust field that an external controller was supposed to calculate is an invalid command.
  • Internal instruction: NaN deliberately placed in a particular VehicleThrustSetpoint axis is a defined stop instruction.

The distinction must be established before the flight-control stack translates one representation into the other. Simply banning NaNs everywhere would also break legitimate internal motor-stop semantics. Conversely, replacing an invalid external thrust with zero or a guessed hover value silently gives the aircraft a command its controller never made.

The author of PX4 PR #29328 says the existing attitude and body-rate paths copy non-finite thrust through to the control allocator. For a multicopter, NaN in the body-Z thrust request can stop the lift motors. The immediate concern is the loss of thrust, but the mechanism is more general: the boundary between a wire protocol's invalid numerical value and an internal sentinel was not enforced.

Why a healthy-looking Offboard heartbeat can be misleading

PX4's Offboard mode documentation requires a continuous proof-of-life signal from the external controller, normally at more than 2 Hz. For MAVLink Offboard control, supported setpoint messages provide that evidence. A separate timeout and configured Offboard-loss action govern what happens when the stream stops.

This is a good defense against a disconnected companion computer. It is less useful when the companion remains connected but its application is producing invalid outputs. If the receiver accepts a malformed SET_ATTITUDE_TARGET packet far enough to publish offboard_control_mode, the liveness monitor can continue seeing a working external controller while the downstream motor request has become unusable.

That is the specific interaction described in the PX4 proposal. The author gives a hypothetical application failure, such as division by zero, that repeatedly emits non-finite thrust. While packets continue to arrive, the ordinary Offboard-loss timeout does not expire. The aircraft has not lost its communication link, but it may effectively have lost valid control.

This is not a claim that every autopilot, firmware build or Offboard integration behaves this way. It is a problem identified in one PX4 MAVLink ingestion path and described in an open code review. It also does not imply that any triggered failsafe would guarantee a safe landing. The response still depends on aircraft configuration, available controls, height and the type of vehicle.

A useful design principle follows: control authority should depend on a recent valid command, not merely a recent command packet. The validity rules must follow the active command mode. An ignored field may not need the same checks as a field currently determining thrust.

The message mask makes validation contextual

MAVLink defines SET_ATTITUDE_TARGET as message 82. It can carry an attitude quaternion, body angular rates and collective thrust. Its ATTITUDE_TARGET_TYPEMASK bits select which quantities are ignored; the THRUST_BODY_SET bit selects a three-axis body-thrust field instead of scalar thrust.

This means an input validator cannot reliably scan every floating-point field with a single unconditional rule. It has to know which fields are active in the requested mode. In a rate-control request, the attitude quaternion may be ignored. When three-dimensional body thrust is selected, the individual used components deserve scrutiny. If scalar thrust is in use, it is that scalar which must be finite.

The PX4 proposal explicitly checks the thrust representation being used and discards the entire message when that value is non-finite. The intended safety effect depends on rejecting the liveness signal along with the payload, not merely sanitizing an actuator setpoint after the fact.

A validator should also distinguish three different failure classes. A value can be non-finite, finite but outside a permitted range, or finite and within range but physically inappropriate for the current state. The reported patch addresses the first class on the specified MAVLink path. It does not establish that saturation, stale timestamps, physically inconsistent trajectories, or every other invalid control mode is handled. Those require separate checks and test cases.

Rejecting an invalid packet is not the same as selecting a safe action

Dropping malformed messages avoids interpreting accidental NaNs as motor-stop commands. When a companion sends only malformed setpoints, it also lets the normal Offboard proof-of-life age out. That restores the intended route into the existing loss-of-control state machine.

The distinction matters because the ingest layer and the failsafe layer have different responsibilities. The ingest layer can decide that a request is invalid. It cannot responsibly replace it with an arbitrary thrust or altitude. The flight-mode manager can then use configured vehicle behavior, including whether the pilot has another control link and what loss action is available.

There are limits. A mixed stream containing valid and invalid requests may keep Offboard alive on the valid messages. An invalid packet discarded today may leave an earlier valid command in effect until another controller or timeout takes over. Different airframes may react very differently to a setpoint gap. The proposed behavior must therefore be evaluated through the entire mode transition, not just by checking that the NaN no longer appears in a telemetry field.

PX4's Offboard documentation describes the loss timer and related parameters, including COM_OF_LOSS_T and COM_OBL_RC_ACT. Their configured values and the actual vehicle state matter. A test that shows a timeout fired is not automatically proof that the resulting vehicle action was correct for a given mission.

What the available simulation actually demonstrates

The pull-request author reports a Software-in-the-Loop test using PX4's SIH quadrotor and a pymavlink script. The script sent SET_ATTITUDE_TARGET with NaN scalar thrust at 20 Hz for four seconds after setting up Offboard flight at a nominal 40 m. The author reports that the earlier code passed NaN into vehicle_thrust_setpoint.xyz, while the proposed patch kept the sampled thrust finite and engaged the Offboard-loss failsafe.

The PR contains an important caveat: on the tested mainline build, another relative-altitude defect had already put the simulated vehicle on the ground. Consequently the test did not observe the predicted free fall in that run. Its strongest evidence is about propagation of the NaN and the failsafe state after rejection, not a measured in-flight crash or quantified risk reduction.

That limitation is especially relevant because the same day's PX4 development includes a separate proposal to correct global-relative altitude conversion. The two bugs concern different message types and control surfaces. A simulation contaminated by one fault cannot cleanly quantify the consequences of the other without isolating the setup.

The thrust-validation PR also states that it covers the MAVLink path only. Setpoints published through uXRCE-DDS into VehicleRatesSetpoint, VehicleAttitudeSetpoint or VehicleThrustSetpoint remain governed by their respective existing paths. An external ROS 2 architecture should not be considered protected by a MAVLink-side patch unless its own command ingestion has been reviewed.

A test plan that checks semantics rather than packet counts

The most useful regression tests exercise the boundary between accepting a setpoint, refreshing liveness and producing an actuator request. They should be run in simulation and with motors safely disabled or physically isolated before any controlled flight evaluation.

Start with a finite command stream that produces a stable reference. Then inject NaN and infinity separately into scalar thrust and each active body-thrust component. Check both attitude and body-rate modes, with masks set as the real application sets them. Include packets whose ignored fields contain NaN to confirm the validator does not accidentally discard a usable request because of an irrelevant payload field.

Next examine time. Send valid setpoints until Offboard is established, then switch to only invalid setpoints and record the age of the last accepted command, the Offboard heartbeat, the eventual mode transition and the commanded motor outputs. A mixed stream with occasional valid packets tests a different question: whether the flight controller continues to accept external authority at a frequency that is sufficient but possibly operationally erratic.

Finally test recovery. Restore valid inputs after the timeout and verify whether re-entry to Offboard requires a fresh precondition and explicit mode change. Repeat after a companion application restart and during simulated loss of the ground-station link. Record the actual configured loss action. Vehicle logs should make it possible to correlate the wire message, acceptance decision, control-mode publication and actuator request on a common timeline.

The acceptance criteria should be more precise than “the drone did not crash.” An invalid incoming thrust must not become an unintended internal stop sentinel; an invalid-only stream must not maintain false command liveness; and the configured takeover behavior must be observable and repeatable.

The boundary that still needs review

A MAVLink parser can confirm that a packet is structurally well formed while its numbers remain operationally invalid. A transport connection can stay up while the companion's controller is broken. A failsafe can be correctly configured but never see the condition that would invoke it. Those are three different layers of correctness.

PX4's open October 18 proposal addresses a specific crossing between them. The described simulation supports the immediate code-path diagnosis, while its altitude-confounded result and MAVLink-only scope limit any stronger operational conclusion. Independent tests across airframes, command masks, companion implementations and loss configurations remain necessary.

The lasting engineering lesson is to place validity checks at the point where external commands acquire authority. Otherwise, the system can mistake a stream of unusable numbers for evidence that the controller is still in charge.