Skip to content

Reset height and position data indoors from last known location#31177

Merged
rmackay9 merged 13 commits intoArduPilot:masterfrom
andyp1per:pr-height-baro-reset-rng
Feb 5, 2026
Merged

Reset height and position data indoors from last known location#31177
rmackay9 merged 13 commits intoArduPilot:masterfrom
andyp1per:pr-height-baro-reset-rng

Conversation

@andyp1per
Copy link
Contributor

@andyp1per andyp1per commented Sep 28, 2025

Summary

This PR enables reliable indoor flight using non-GPS position sources (optical flow, external navigation/motion capture, etc.) by refactoring how flight modes declare their position requirements and adding persistent origin storage.

Problem

Currently, many Copter flight modes declare requires_GPS() which causes issues when flying indoors with alternative position sources like optical flow or external navigation systems. The EKF can provide valid position estimates from these sources, but the mode requirements and arming checks still demand GPS specifically. This can lead to:

  1. Inability to arm or enter position-controlled modes when position is valid but GPS is unavailable
  2. Incorrect failsafe triggers when the position source is working correctly
  3. No way to restore the EKF origin after a reboot when flying indoors without GPS

Solution

1. Mode Requirement Refactoring: requires_GPS()requires_position()

All Copter flight modes now declare whether they need position rather than specifically GPS. The AHRS/EKF is then consulted to determine if the position requirement can be satisfied by the current sensor suite (GPS, optical flow, external nav, etc.).

2. GPS Usage Detection

New using_gps() methods added to AP_AHRS, NavEKF2, and NavEKF3 allow the system to distinguish between:

  • Modes that need position (satisfied by any valid position source)
  • Checks that specifically require GPS (fence, supersimple mode, etc.)

3. Persistent Origin Storage

New AHRS parameters for saving/restoring the EKF origin:

  • AHRS_ORIGIN_LAT - Last known origin latitude
  • AHRS_ORIGIN_LNG - Last known origin longitude
  • AHRS_ORIGIN_ALT - Last known origin altitude

New AHRS_OPTIONS bit (3): AutoRecordOrigin - Automatically saves the origin to parameters when it becomes valid.

4. Origin Restoration on Startup/Arming

New ARMING_OPTIONS bits allow the origin to be restored from saved parameters:

  • Bit for setting origin from AHRS params at startup (1Hz check when disarmed)
  • Bit for setting origin from AHRS params on arming (last-ditch attempt)

This allows indoor flights to resume with a valid origin after power cycles.

5. Updated Arming Checks

Arming checks now properly handle position-only scenarios:

  • If a mode requires position and position is valid, GPS-specific checks are relaxed
  • If position is not valid or GPS is actually being used, full GPS checks apply
  • Origin availability is checked when modes require position

Affected Vehicles

  • Copter: Primary target - all flight modes updated
  • Rover: Arming checks updated for consistency
  • Blimp: Arming checks updated for consistency

Testing

Autotest updates included for optical flow scenarios to validate the new behavior.

Usage

For indoor flight with optical flow or external nav:

  1. Fly outdoors first to establish a valid origin (or set AHRS_ORIGIN_* parameters manually)
  2. Enable AHRS_OPTIONS bit 3 to auto-record the origin
  3. Enable appropriate ARMING_OPTIONS bit for origin restoration
  4. On subsequent indoor flights, the origin will be restored from parameters

This allows position-controlled modes (Loiter, Auto, etc.) to work indoors without GPS when a valid position estimate is available from alternative sources.

@andyp1per andyp1per added the WIP label Sep 28, 2025
@peterbarker
Copy link
Contributor

... also, we probably don't need extra parameters for this storage, we persist home already.

@andyp1per
Copy link
Contributor Author

... also, we probably don't need extra parameters for this storage, we persist home already.

Where is that?

@andyp1per andyp1per force-pushed the pr-height-baro-reset-rng branch from ff82426 to 726d213 Compare September 30, 2025 11:09
@peterbarker
Copy link
Contributor

peterbarker commented Oct 31, 2025

... also, we probably don't need extra parameters for this storage, we persist home already.

Where is that?

mission-slot-0.

Yeah this is not user friendly and in discussion with others we don't want this associated with a mission. I think what is in the PR is still the best way of doing this.

@andyp1per andyp1per marked this pull request as ready for review November 10, 2025 14:08
@andyp1per
Copy link
Contributor Author

I have been using this a lot and it is great!

Copy link
Contributor

@peterbarker peterbarker left a comment

Choose a reason for hiding this comment

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

I think I quite like this as a concept now. Yes, I've changed my mind on the parameters :-)

@andyp1per andyp1per force-pushed the pr-height-baro-reset-rng branch 2 times, most recently from b4bf319 to f020dbf Compare November 11, 2025 19:08
Copy link
Contributor

@peterbarker peterbarker left a comment

Choose a reason for hiding this comment

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

Spams

LOITER> Received 1366 parameters
Saved 1344 parameters to mav.parm
AP: Field Elevation Set: 0m
AP: Field Elevation Set: 0m
AP: Field Elevation Set: 0m

LOITER> AP: Field Elevation Set: 0m
AP: EKF3 IMU0 is using GPS

LOITER> AP: EKF3 IMU1 is using GPS

LOITER> aAP: Field Elevation Set: 0m

@andyp1per
Copy link
Contributor Author

Spams

LOITER> Received 1366 parameters
Saved 1344 parameters to mav.parm
AP: Field Elevation Set: 0m
AP: Field Elevation Set: 0m
AP: Field Elevation Set: 0m

LOITER> AP: Field Elevation Set: 0m
AP: EKF3 IMU0 is using GPS

LOITER> AP: EKF3 IMU1 is using GPS

LOITER> aAP: Field Elevation Set: 0m

Ah-ha! So that's where the spam is coming from! Okay, need to figure that out because it was annoying me as well.

@andyp1per andyp1per removed the WIP label Nov 12, 2025
@andyp1per
Copy link
Contributor Author

Spam is pre-existing

void run() override;

bool requires_GPS() const override { return true; }
bool requires_GPS() const override { return false; }
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for this, it would definitely be nice if users didn't need to turn off arming checks when using optical flow (or other non-GPS based position estimation).

I think "requires_GPS" and "requires_position()" should always be the same. The "requires_GPS" is just a hang-over from when GPS was the only viable option. If we agree on this then let's just rename, "requires_GPS" to "requires_position".

Copy link
Contributor

Choose a reason for hiding this comment

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

Andy and I have discussed this elsewhere.

I was pushing for requires_location and requires_position, using the same terms we use elsewhere - Location as in absolute lat/lon object and "position" as in offsets-from-origin.

requires_absolute_location and requires_position_relative_to_origin could also work :-)

... or requires_latitude_longitude_altitude?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am unconvinced about this. requires_GPS() causes GPS checks to be run - they shouldn't be run if the vehicle only requires position and the EKF is ok. Or for instance follow mode requires GPS because position (in the way we mean here) is not good enough. So I don't think there can only be a single function, but I am not fussed about what the two functions are called. FWIW I prefer the current naming - absolute position is pretty much only provided by the GPS.

fence_requires_gps = (copter.fence.get_enabled_fences() & (AC_FENCE_TYPE_CIRCLE | AC_FENCE_TYPE_POLYGON)) > 0;
#endif

// check if we only require position and the EKF thinks we are ok
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should instead rename "gps_checks" to "position_checks" or maybe just add add a comment to explain that they're synonymous. Then within this function we should put the position checks at the top and GPS checks at the bottom. Just above the GPS checks we should ask the AHRS if it's using GPS as its position, velocity or yaw source and if "no" we can skip the GPS checks. The AHRS doesn't currently have an accessor to ask which sensor it is using but we have similar functions like, "using_extnav_for_yaw" so around the same area we could have add a "using_gps_for_position_or_velocity". I'm not sure immediately how we should implement this function but perhaps DCM would always return "true" and perhaps EKF3 could re-use the logic in AP_NavEKF_Source's pre-arm check

Copy link
Contributor

Choose a reason for hiding this comment

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

We should not care how the EKF is getting the data it is using to supply us with stuff. Well, as much as possible, anyway. Asking the EKF how it is getting the data is a layering violation and unnecessary AFAICS (and @andyp1per 's PR here doesn't require it!) Examples of where doing that will stuff you up - beacons which are rooted at a lat/lon, external AHRS of any sort and visual odometry input to the EKF supply lat/lng/alt (e.g. from a google-maps-image-mapping external source).

Copy link
Contributor

Choose a reason for hiding this comment

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

Hi @peterbarker, unfortunately we do care about the EKF's sources if we only want to check those sources that the EKF is currently using. So whether that's the GPS or visual odometry or whatever, if we only want to check that the currently used source is healthy, then we need to know what the source is.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hi @peterbarker, unfortunately we do care about the EKF's sources if we only want to check those sources that the EKF is currently using. So whether that's the GPS or visual odometry or whatever, if we only want to check that the currently used source is healthy, then we need to know what the source is.

I can see that for some use cases.

But I don't think it's the case for optical flow; we don't (or shouldn't, thus this PR) actually need GPS to be healthy in Copter to arm and fly in loiter if you have good optical flow.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rmackay9 this does check the sources via the EKF. If you try this indoors with sources requiring GPS you will get an error "EKF sources require GPS". So I think it behaves in the way you want, its just that the function is a little subtle.

Copy link
Contributor

@rmackay9 rmackay9 Nov 17, 2025

Choose a reason for hiding this comment

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

@andyp1per,

And if the user is flying indoors and the EKF pos/vel source is not GPS it doesn't raise the GPS pre-arm failures?

Copy link
Contributor Author

@andyp1per andyp1per Nov 26, 2025

Choose a reason for hiding this comment

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

@rmackay9 correct, the code as written only gives a GPS pre-arm check if the sources require the GPS and the mode only requires "position" and not "GPS". This is another reason why we need two functions. Note that I think we have to delegate a bunch of this to the EKF - the EKF check is in some ways stricter and in other ways looser as it not only looks at what has been configured but also whether its good enough as a source for whatever.

@andyp1per andyp1per force-pushed the pr-height-baro-reset-rng branch from 7427e7d to 8c4fd7a Compare November 26, 2025 19:24
@andyp1per andyp1per force-pushed the pr-height-baro-reset-rng branch 3 times, most recently from ef73e05 to bc8b9f9 Compare December 7, 2025 20:03
@andyp1per andyp1per requested a review from rmackay9 December 7, 2025 20:03
@andyp1per
Copy link
Contributor Author

@rmackay9 this is clean now and I have updated the tests to appropriately check that we can't arm without GPS where necessary

@andyp1per
Copy link
Contributor Author

@rmackay9 @peterbarker and I have reached agreement, branch updated to reflect

@rmackay9 rmackay9 dismissed tridge’s stale review January 29, 2026 23:31

Tridge's request to add an option bit has been added

@andyp1per andyp1per force-pushed the pr-height-baro-reset-rng branch from 8ad6da0 to 182166c Compare January 30, 2026 13:03
Copy link
Contributor

@rmackay9 rmackay9 left a comment

Choose a reason for hiding this comment

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

I've tested this fairly well in SITL to confirm it works as expected. Below are some screen shots of the testing

Tested that the origin is recorded and used when EKF sources do not include GPS
Image

Tested that the AHRS_OPTIONS bit for "RecordOrigin" works.
Image

Tested that the AHRS_OPTIONS bit for "UseRecordedOrigin" works
Image

Tested that the AHRS_OPTIONS bit for "UseRecordedOrigin" has no effect if EK3_SRC1_POSXY or EK3_SRC1_VELXY is set to GPS
Image

Confirmed that the Sub parameter conversions from ORIGIN_LAT/LON/ALT to AHRS_ORIGIN_LAT/LON/ALT works
sub-origin-params-before-vs-after

@rmackay9
Copy link
Contributor

rmackay9 commented Feb 2, 2026

We discussed on the dev call and agreed that once @Williangalvani has had a chance to test and approve we will merge (assuming that WillianG is happy of course)

@andyp1per andyp1per force-pushed the pr-height-baro-reset-rng branch from 182166c to 784a1a1 Compare February 4, 2026 07:25
@andyp1per
Copy link
Contributor Author

@Williangalvani ready to go when you approve from the sub side

Copy link
Contributor

@Williangalvani Williangalvani left a comment

Choose a reason for hiding this comment

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

I am happy with the Sub changes.
Also just tested on real hw.

@rmackay9 rmackay9 merged commit 2a26d3c into ArduPilot:master Feb 5, 2026
107 checks passed
@andyp1per andyp1per deleted the pr-height-baro-reset-rng branch February 5, 2026 20:32
@andyp1per
Copy link
Contributor Author

Thanks @Williangalvani and @rmackay9 !

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.

7 participants