pub struct Recovery {
pub gnss_position: Option<Seconds>,
pub gnss_height: Option<Seconds>,
pub gnss_velocity: Option<Seconds>,
pub baro_altitude: Option<Seconds>,
pub mag_heading: Option<Seconds>,
pub gnss_heading: Option<Seconds>,
pub course: Option<Seconds>,
pub yaw_estimator: Option<Seconds>,
}Expand description
How long each source may be rejected before the filter adopts it again: automatic recovery from
gate lockout, one
switch per source. None turns that source’s recovery off.
A source recovers when the gate rejects one of its measurements and none has been accepted
for at least this long — since initialization, for a source never accepted. That
measurement is then adopted rather than discarded: Fusion::Reset,
counted in SourceHealth::recovered. The state becomes
the measurement and its covariance block the measurement’s, which is what undoes the
overconfidence that locked the gate rather than only moving the estimate. Only a rejection
triggers it: a source that is silent or refused has nothing to adopt, and a stream of NaN
must not step the state.
On by default, because a filter that reports lockout and stops hands every integrator the
same timeout-and-reset loop to write. An application that owns its failsafe policy — a
controller that cannot take a step, an operator alert instead of a reset — turns off the
source it owns, or all of them with Recovery::OFF, and drives
Eskf::reset_position_to itself. The decision is rejection
handling.
Per source, not per quantity, because a source is what the gate rejects: the fields mirror
Gates and Diagnostics.
After a position hold the timeout is waived once: the first GNSS position or velocity the
gate turns down is adopted at once, unless its field here is None; see Hold.
Fields§
§gnss_position: Option<Seconds>GNSS horizontal position: north and east are adopted, height is left alone.
gnss_height: Option<Seconds>GNSS height: the down axis is adopted, and the barometric reference is dropped so that
the next altitude reads it again against the adopted height — unless
Config::baro_reference_from_estimate is off, which leaves the reference the
caller’s and keeps it.
gnss_velocity: Option<Seconds>GNSS velocity: all three axes are adopted.
baro_altitude: Option<Seconds>Barometric altitude: the reference α₀ is read again from the estimate, as the first
one is when a start leaves none, and the state does not move. Needs an established
position to read it against, and Config::baro_reference_from_estimate on: with it
off the reference is the caller’s, and a barometer that disagrees stays rejected.
mag_heading: Option<Seconds>Magnetic heading: adopted as the first heading is, with the R of (36′) — but only
while neither GNSS position nor velocity is fresh
(SourceHealth::is_fresh), since with those arriving
a magnetometer that disagrees for this long is more likely disturbed than right. Nor while a GNSS heading is
accepted, for the same reason.
gnss_heading: Option<Seconds>Dual-antenna GNSS heading: adopted as the first heading is, with the caller’s R. No
guard: it is the absolute heading reference when the vehicle carries one.
course: Option<Seconds>Course constraint: adopted as the first heading is — but only while neither magnetic nor GNSS heading is fresh, since with either arriving a course that disagrees this long is sideslip the caller did not allow for, a crosswind or a multirotor crabbing, rather than a wrong heading.
yaw_estimator: Option<Seconds>The yaw estimator’s heading, adopted in place of one GNSS contradicts: once no GNSS
velocity has been accepted for this long and a second in a row is rejected, while the
estimator of Config::yaw_estimator has converged on a yaw more than 25° from the
filter’s. A magnetometer is then not adopted back until one of its headings passes
the gate.
That velocity, and the first GNSS position the gate turns down after it, are then
adopted at once rather than after their own timeouts, since what they were judged
against was the wrong heading. Not while a dual-antenna
GNSS heading is fresh (SourceHealth::is_fresh): it
measures what the estimator infers. Unlike the fields above it times another source’s
rejections: the estimator’s answer is never gated.
Implementations§
Trait Implementations§
impl Copy for Recovery
Source§impl Default for Recovery
impl Default for Recovery
Source§fn default() -> Self
fn default() -> Self
PX4’s timeouts, at c4e4ef98e9: reset_timeout_max, 7 s, for horizontal position,
velocity and heading, and hgt_fusion_timeout_max, 5 s, for height
(src/modules/ekf2/EKF/common.h:515-517). Each is applied the way PX4 applies it —
position at aid_sources/gnss/gps_control.cpp:204-213, velocity at :146-156, heading
at aid_sources/magnetometer/mag_control.cpp:276-289, whose guard against fresh
horizontal aiding mag_heading keeps — with one departure.
PX4 resets height only when every height source is failing (ekf_helper.cpp:48-57),
and otherwise stops fusing the one that disagrees, whichever EKF2_HGT_REF names the
reference (GNSS by default, module.yaml:87-106). Here GNSS height is always the
absolute and the barometer’s offset is estimated,
equation (30′), so a GNSS height rejected for 5 s is adopted even while the barometer
is accepted, and a barometer rejected for 5 s has its reference read again: the
absolute wins either way.
The two heading sources PX4 either lacks or does not recover take the same 7 s, by the
rule recovery follows everywhere here rather than by a measurement. PX4 stops fusing a
GNSS yaw that has failed for reset_timeout_max and resets nothing
(aid_sources/gnss/gnss_yaw_control.cpp:78-81); ArduPilot realigns it on the ground
after 10 s (AP_NavEKF3_MagFusion.cpp:433-435 at 368dc0c4). PX4 has no course
constraint at all; ArduPilot’s in-flight course realignment is itself a reset
(realignYawGPS, AP_NavEKF3_MagFusion.cpp:145-218).
The yaw estimator’s is PX4’s EKFGSF_reset_delay, 1 s (common.h:395), applied as PX4
applies it to a rejected velocity (gps_control.cpp:113-125, isYawFailure at
:546-562) less its in-air condition, which this filter is not told.
impl StructuralPartialEq for Recovery
Auto Trait Implementations§
impl Freeze for Recovery
impl RefUnwindSafe for Recovery
impl Send for Recovery
impl Sync for Recovery
impl Unpin for Recovery
impl UnsafeUnpin for Recovery
impl UnwindSafe for Recovery
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> Scalar for T
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.