PX4 command ACK and mission-completion mismatches in MAVLink handling

This report covers MAVLink command-handling cases where PX4 accepts or completes a command path even though the downstream execution result is missing or rejected.

Tested environment:

PX4 SITL: sihsim_quadx
PX4 version: v1.14.0-6-g33aca30c93-dirty
PX4 git hash: 33aca30c93863efb0a73991c391756876663bb72

A. Payload mission command completion without execution confirmation

A1. MAV_CMD_DO_GRIPPER: mission advances after timeout when no payload executor/ack is present

Reproduction:

  • Start PX4 SITL with the default sihsim_quadx configuration.
  • Upload a mission containing:
seq 0: MAV_CMD_NAV_TAKEOFF
seq 1: MAV_CMD_DO_GRIPPER
seq 2: MAV_CMD_DO_WINCH
seq 3: MAV_CMD_NAV_WAYPOINT
  • Start the mission and observe mission progress.
  • Check payload_deliverer status in the PX4 shell.

Observed mission upload result:

MISSION_ACK: MAV_MISSION_ACCEPTED

Observed mission download:

seq 1: command=211   (MAV_CMD_DO_GRIPPER)
seq 2: command=42600 (MAV_CMD_DO_WINCH)

During execution, PX4 advanced through the payload items:

MISSION_CURRENT seq=1
MISSION_ITEM_REACHED seq=1
MISSION_CURRENT seq=2
MISSION_ITEM_REACHED seq=2
MISSION_CURRENT seq=3

PX4 shell output after the mission:

INFO  [navigator] Mission finished, loitering
INFO  [payload_deliverer] not running

In this configuration, no payload executor was running, but the mission still advanced past the MAV_CMD_DO_GRIPPER item after the payload timeout.

Expected behavior: if PX4 cannot execute a payload mission item or cannot obtain a successful execution acknowledgement, the mission should expose a failure state or keep the failure visible to the mission/GCS layer.

Actual behavior: the mission item is accepted and later treated as complete after a timeout, even though no payload execution acknowledgement was observed.

Relevant source in the tested PX4 version:

// mission_block.cpp
if (item.nav_cmd == NAV_CMD_DO_WINCH ||
    item.nav_cmd == NAV_CMD_DO_GRIPPER) {
    vehicle_command_s vcmd = {};
    vcmd.command = item.nav_cmd;
    ...
    _navigator->publish_vehicle_cmd(&vcmd);

    _payload_deploy_ack_successful = false;
    _payload_deployed_time = hrt_absolute_time();
}

Completion for DO_GRIPPER accepts either a successful payload ack or timeout:

// mission_block.cpp
case NAV_CMD_DO_GRIPPER: {
    const float payload_deploy_elasped_time_s = (now - _payload_deployed_time) * 1E-6f;

    if (_payload_deploy_ack_successful) {
        return true;

    } else if (payload_deploy_elasped_time_s > _payload_deploy_timeout_s) {
        return true;
    }

    return false;
}

The class comment for the mission payload state also describes timeout-driven continuation:

// mission_block.h
// If the payload deployment takes longer than timeout, mission will
// continue into the next item automatically.

Impact:

  • A mission can continue after a payload step even when the payload action did not execute.
  • For gripper-based delivery or pickup missions, the vehicle can proceed to later waypoints or return-to-launch while the payload state is different from the mission plan.
  • From the mission/GCS view, the mission step has completed; the missing executor or missing successful ack is not exposed as a mission failure.

A2. MAV_CMD_DO_WINCH: accepted mission item has no implemented winch executor and still completes by timeout

The same mission run also reproduced the winch path.

Observed mission upload and download:

MISSION_ACK: MAV_MISSION_ACCEPTED
seq 2: command=42600 (MAV_CMD_DO_WINCH)

Observed mission execution:

MISSION_CURRENT seq=2
MISSION_ITEM_REACHED seq=2
MISSION_CURRENT seq=3
INFO  [navigator] Mission finished, loitering

The DO_WINCH mission item was accepted, stored, dispatched as a vehicle command, and later treated as complete. However, the payload deliverer implementation in this version only processes VEHICLE_CMD_DO_GRIPPER.

Relevant source:

// payload_deliverer.cpp
// Process DO_GRIPPER vehicle command
if (vehicle_command->command == vehicle_command_s::VEHICLE_CMD_DO_GRIPPER) {
    ...
}

The module documentation advertises winch support:

// payload_deliverer.h
// Activates a winch / gripper when the DO_WINCH or DO_GRIPPER vehicle command is received,
// after which the vehicle_command_ack command gets sent upon successful confirmation

The CLI description also mentions winch support:

// payload_deliverer.cpp
Handles payload delivery with either Gripper or a Winch with an appropriate timeout / feedback sensor setting

But no DO_WINCH command branch exists in payload_deliverer.cpp.

Mission completion for DO_WINCH also falls back to timeout:

// mission_block.cpp
case NAV_CMD_DO_WINCH: {
    const float payload_deploy_elasped_time_s = (now - _payload_deployed_time) * 1E-6f;

    if (_payload_deploy_ack_successful) {
        return true;

    } else if (payload_deploy_elasped_time_s > _payload_deploy_timeout_s) {
        return true;
    }

    return false;
}

Expected behavior: PX4 should reject unsupported winch mission items, or provide an implemented executor and report execution failure when the winch action cannot be confirmed.

Actual behavior: PX4 accepts the winch mission item and advances after timeout even though the advertised winch executor path is not implemented in payload_deliverer.

Impact:

  • A cargo/delivery mission can appear to complete a winch step while no winch action occurred.
  • Later mission phases can run under the assumption that payload deployment succeeded.
  • The documentation/implementation mismatch can cause operators to configure missions around a capability that is accepted by the mission layer but not actually executed.

B. Command ACK/mode result decoupled from Navigator rejection

B1. MAV_CMD_DO_REPOSITION: geofence-rejected destination returns MAV_RESULT_ACCEPTED and switches to Hold/Loiter

Reproduction:

  • Configure geofence action and source:
GF_ACTION=2
GF_SOURCE=0
  • Upload a four-vertex inclusion fence around the current vehicle position.
  • Arm and run a short mission to get airborne.
  • Send MAV_CMD_DO_REPOSITION with param2=1 and a target location outside the inclusion fence.

Observed command result:

COMMAND_ACK command=192 result=0 MAV_RESULT_ACCEPTED

PX4 shell output:

WARN  [navigator] Reposition is outside geofence

The vehicle mode changed to Hold/Loiter after the command while the requested reposition target was rejected by Navigator.

Relevant source behavior:

In Commander.cpp, VEHICLE_CMD_DO_REPOSITION validates the mode-switch flag in param2, requests NAVIGATION_STATE_AUTO_LOITER, and sets the command result to VEHICLE_CMD_RESULT_ACCEPTED when that mode request succeeds. Commander does not validate the target coordinates against the active geofence before returning the ACK.

Navigator later checks the target position against the geofence:

// navigator_main.cpp
if (have_geofence_position_data) {
    reposition_valid = geofence_allows_position(position_setpoint);
}

if (reposition_valid) {
    ...
} else {
    mavlink_log_critical(&_mavlink_log_pub, "Reposition is outside geofence\t");
}

// CMD_DO_REPOSITION is acknowledged by commander

Expected behavior: if the requested reposition setpoint is rejected by Navigator, the MAVLink result should not indicate full command acceptance without exposing the downstream rejection.

Actual behavior: the command returns MAV_RESULT_ACCEPTED and changes the vehicle mode, but Navigator rejects the requested destination due to geofence.

Impact:

  • The geofence itself is enforced, but the command result is misleading.
  • A ground station or companion computer can believe the reposition command succeeded while PX4 only changed mode and discarded the requested destination.
  • The vehicle can be taken out of its previous navigation state into Hold/Loiter even though the requested reposition cannot be executed.

Suggested fixes

  • For payload mission items, do not treat timeout as successful completion when no successful payload execution acknowledgement was received.
  • Reject unsupported payload mission commands during mission upload, or require an available executor before accepting them.
  • Either implement the advertised DO_WINCH executor path or remove/reject winch support consistently across mission upload, documentation, and payload deliverer status.
  • For MAV_CMD_DO_REPOSITION, include Navigator’s geofence/setpoint validation result in the command outcome, or send a later negative result when the accepted command cannot be applied.
  • Avoid changing the vehicle mode for a reposition request when the requested setpoint is known to be invalid or geofence-rejected.