Skip to content

fix(PlanManager): resend last mission waypoint in case of final ack timeout - #14895

Draft
MaEtUgR wants to merge 1 commit into
masterfrom
maetugr/resend-final-mission-item
Draft

fix(PlanManager): resend last mission waypoint in case of final ack timeout#14895
MaEtUgR wants to merge 1 commit into
masterfrom
maetugr/resend-final-mission-item

Conversation

@MaEtUgR

@MaEtUgR MaEtUgR commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Problem

If the final mission ack is lost on the link the user gets the message "Mission write failed, vehicle failed to send final ack." even though the mission was uploaded succesfully. Based on the message he'll manually reupload the entire mission again.

Solution

PX4 does resend the final ack upon receiving the last waypoint again. So in case the last mission ack times out, we should not immediately give up but retransmit the last waypoint like we do if a waypoint or an ack in the middle of the mission transfer goes missing.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Testing

  • Tested locally
  • Added/updated unit tests
  • Tested with simulator (SITL)
  • Tested with hardware

Platforms Tested

  • Linux
  • Windows
  • macOS
  • Android
  • iOS

Flight Stacks Tested

  • PX4
  • ArduPilot

Checklist

  • I have read the Contribution Guidelines
  • I have read the Code of Conduct
  • My code follows the project's coding standards
  • I have added tests that prove my fix/feature works
  • New and existing unit tests pass locally

By submitting this pull request, I confirm that my contribution is made under the terms of the project's dual license (Apache 2.0 and GPL v3).

Copilot AI balanced review requested due to automatic review settings August 19, 2026 12:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds recovery for lost final mission acknowledgements by resending the last requested mission item.

Changes:

  • Retries final acknowledgements with bounded resend attempts.
  • Extracts mission-item transmission into a reusable helper.
  • Adds mock-link behavior and test coverage for a dropped first final ACK.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/MissionManager/PlanManager.cc Implements final-ACK recovery and item resend helper.
src/MissionManager/PlanManager.h Declares the resend helper.
src/Comms/MockLink/MockLinkMissionItemHandler.cc Simulates dropping the first final ACK.
src/Comms/MockLink/MockLinkMissionItemHandler.h Adds failure-mode state.
test/MissionManager/MissionManagerTest.cc Adds the successful retry test case.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +418 to +422
if (_failureMode == FailWriteFinalAckFirstResponse && _failWriteFinalAckFirstResponse) {
_failWriteFinalAckFirstResponse = false;
qCDebug(MockLinkMissionItemHandlerLog) << "not sending final ack due to failure mode FailWriteFinalAckFirstResponse, first response";
return;
}

MissionItem* item = _writeMissionItems[missionRequestSeq];
qCDebug(PlanManagerLog) << QStringLiteral("_handleMissionRequest %1 sequenceNumber:command").arg(_planTypeString()) << missionRequestSeq << item->command();
_sendMissionItem(missionRequestSeq);
@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Build Results

Platform Status

Platform Status Details
Linux Passed View
Windows Passed View
MacOS Passed View
Android Passed View

All builds passed.

Pre-commit

Check Status Details
pre-commit Failed (non-blocking) View

Pre-commit hooks: 2 passed, 75 failed, 7 skipped.

Test Results

linux-coverage-integration: 48 passed, 0 skipped
linux-coverage-unit: 137 passed, 0 skipped
linux-sanitizers-integration: 28 passed, 0 skipped
linux-sanitizers-unit: 137 passed, 0 skipped
Total: 350 passed, 0 skipped

Code Coverage

Coverage: 70.2%

No baseline available for comparison

Artifact Sizes

Artifact Size
QGroundControl 252.95 MB
QGroundControl-aarch64 176.68 MB
QGroundControl-installer-AMD64 138.43 MB
QGroundControl-installer-AMD64-ARM64 80.70 MB
QGroundControl-installer-ARM64 109.25 MB
QGroundControl-linux 84.65 MB
QGroundControl-mac 84.65 MB
QGroundControl-x86_64 188.92 MB
No baseline available for comparison

Updated: 2026-08-20 17:17:53 UTC • Commit: 9acece2 • Triggered by: Linux

@DronecodeBot

Copy link
Copy Markdown

This pull request has been mentioned on Dronecode Forum | Open Source Drone Development. There might be relevant details there:

https://discuss.px4.io/t/px4-dev-call-aug-19-2026-team-sync-and-community-q-a/49378/1

@MaEtUgR
MaEtUgR marked this pull request as draft August 19, 2026 15:44
@DonLakeFlyer DonLakeFlyer added this to the Release V5.1 milestone Aug 19, 2026
@DonLakeFlyer

DonLakeFlyer commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

FYI: I traced how ArduPilot reacts to this retry mechanism, since the recovery relies on the vehicle re-acking a duplicate final item:

ArduPilot does not resend the final ack. When it sends the final MISSION_ACK, MissionItemProtocol::transfer_is_complete() immediately tears down the upload session (receiving = false, link = nullptr). When the retransmitted last item then arrives, the dispatch layer in GCS_MAVLINK::handle_mission_item() hits:

if (!prot->receiving) {
    send_mission_ack(msg, type, MAV_MISSION_ERROR);
    return;
}

So ArduPilot replies with a MISSION_ACK of MAV_MISSION_ERROR (not MAV_MISSION_INVALID_SEQUENCE, so the existing APM ignore special-case in _handleMissionAck doesn't apply). QGC then fails the transaction with a VehicleAckError.

Net effect on ArduPilot: same false "write failed" outcome as today when the final ack is lost (the mission is actually stored fine), just reached via one retransmit and an error ack instead of a timeout. No regression and no added delay — but the recovery in this PR only benefits PX4. Per the MAVLink mission protocol spec the vehicle is supposed to resend the ack in this situation, so this is arguably an ArduPilot compliance gap worth an upstream issue.

@DonLakeFlyer

Copy link
Copy Markdown
Contributor

@hamishwillee The spec for mission upload seems silent on what to do if the GCS doesn't receive the final item ACK. With this change PX4 kinda makes an assumption on that which ArduPilot doesn't also assume.

@DonLakeFlyer

Copy link
Copy Markdown
Contributor

like we do if a waypoint or an ack in the middle of the mission transfer goes missing.

But that isn't really how upload works. The vehicle side is in control. The GCS side does no retry if it's in the middle I believe. The protocol doesn't really work that way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants