SIM_GPS1_HNSE fault clear trips EKF position lost failsafe

TL;DR: it’s not the GPS fault itself that trips the EKF position lost failsafe, it’s clearing the fault

I was testing how a GPS guided descent handles injected GPS position error in SITL (ArduCopter 4.6.0-beta1, commit 16f9f663) and found something worth sharing.

I used SIM_GPS1_HNSE to inject a fixed position error during a real GUIDED descent, held it for a few seconds, then cleared it. Did this at 1m, 2m, 3m and 8m, three reps each. (SIM_GPS1_FIXTYPE and NUMSATS don’t work for this by the way, they’re just label overrides on GPS_RAW_INT with no coupling to the actual position solution, checked that against SIM_GPS.cpp directly.)

At 1-3m nothing happens onboard. No EKF flag change, no STATUSTEXT, no mode change, every rep. But the real aircraft position (SITL ground truth) gets pulled off course by about the same amount the whole time the fault is active.

At 8m, same thing while the fault is active. Flags just sit at “glitching but still has a position” the whole time, no failsafe. But within about 0.01 to 0.07 seconds of clearing the fault (HNSE stepped back to 0), the flags jump to a state where EKF_POS_HORIZ_REL/ABS and both PRED versions are gone completely. Not degraded, just gone. Mode change to LAND follows about 0.85 to 0.9 seconds later, which lines up with EKF_CHECK_ITERATIONS_MAX being 10 at 10Hz.

Makes sense once you look at ekf_check.cpp lines 52-54:

const bool over_threshold = ekf_over_threshold();

const bool has_position = ekf_has_relative_position() || ekf_has_absolute_position();

const bool checks_passed = !over_threshold && has_position;

Line 157’s condition for over_threshold means position variance alone can never trip that check without velocity or compass variance also being elevated. So a steady position offset never even reaches the variance branch. But an abrupt correction looks to the EKF like a sudden multi meter disagreement, which trips has_position false instead. That’s the “position lost” branch (the STATUSTEXT on line 86), a completely different condition than the variance one.

I also tried a gradual 3 second ramp clear instead of stepping it instantly, figured that might avoid this. It doesn’t. Same failsafe fires about 0.7 to 0.8 seconds after the ramp starts, while HNSE is still around 6m and nowhere close to done clearing. So it’s not really instant vs gradual, it’s how fast the correction is at any point during the clear.

Curious if this is intended behavior for has_position. Basically, is a fast but legitimate GPS recovery supposed to look the same as a real EKF fault here? And is there a recommended way to handle a GPS signal that’s degrading and recovering quickly (like from RF interference) without tripping this, or is the answer just don’t clear a GPS fault fast.

Put together a reproducible test harness if anyone wants to try it themselves, it’s generic and not tied to any specific vehicle setup: GitHub - austingmuer2/ardupilot-sitl-fault-injection: Generic ArduCopter SITL fault-injection tools: GPS-position and link-degradation faults, with runnable demo scenarios. · GitHub