ekf2: mag declination fusion always if there is no aiding

This commit is contained in:
Daniel Agar
2024-08-27 16:16:55 +02:00
committed by Mathieu Bresciani
parent 2a9e205442
commit ac48b8b51d
4 changed files with 21 additions and 16 deletions
@@ -205,14 +205,14 @@ void Ekf::controlMagFusion(const imuSample &imu_sample)
// if we are using 3-axis magnetometer fusion, but without external NE aiding, // if we are using 3-axis magnetometer fusion, but without external NE aiding,
// then the declination must be fused as an observation to prevent long term heading drift // then the declination must be fused as an observation to prevent long term heading drift
const bool no_ne_aiding_or_pre_takeoff = !using_ne_aiding || !_control_status.flags.in_air; const bool no_ne_aiding_or_not_moving = !using_ne_aiding || _control_status.flags.vehicle_at_rest;
_control_status.flags.mag_dec = _control_status.flags.mag && no_ne_aiding_or_pre_takeoff; _control_status.flags.mag_dec = _control_status.flags.mag && no_ne_aiding_or_not_moving;
if (_control_status.flags.mag) { if (_control_status.flags.mag) {
if (continuing_conditions_passing && _control_status.flags.yaw_align) { if (continuing_conditions_passing && _control_status.flags.yaw_align) {
if (checkHaglYawResetReq() || (wmm_updated && no_ne_aiding_or_pre_takeoff)) { if (checkHaglYawResetReq() || (wmm_updated && no_ne_aiding_or_not_moving)) {
ECL_INFO("reset to %s", AID_SRC_NAME); ECL_INFO("reset to %s", AID_SRC_NAME);
resetMagStates(_mag_lpf.getState(), _control_status.flags.mag_hdg || _control_status.flags.mag_3D); resetMagStates(_mag_lpf.getState(), _control_status.flags.mag_hdg || _control_status.flags.mag_3D);
aid_src.time_last_fuse = imu_sample.time_us; aid_src.time_last_fuse = imu_sample.time_us;
@@ -234,19 +234,26 @@ void Ekf::controlMagFusion(const imuSample &imu_sample)
if (_control_status.flags.mag_dec) { if (_control_status.flags.mag_dec) {
// observation variance (rad**2)
const float R_DECL = sq(0.5f);
if ((_params.mag_declination_source & GeoDeclinationMask::USE_GEO_DECL) if ((_params.mag_declination_source & GeoDeclinationMask::USE_GEO_DECL)
&& PX4_ISFINITE(_wmm_declination_rad) && PX4_ISFINITE(_wmm_declination_rad)
) { ) {
// using declination from the world magnetic model
fuseDeclination(_wmm_declination_rad, 0.5f, update_all_states); fuseDeclination(_wmm_declination_rad, 0.5f, update_all_states);
} else if ((_params.mag_declination_source & GeoDeclinationMask::SAVE_GEO_DECL) } else if ((_params.mag_declination_source & GeoDeclinationMask::SAVE_GEO_DECL)
&& PX4_ISFINITE(_params.mag_declination_deg) && (fabsf(_params.mag_declination_deg) > 0.f) && PX4_ISFINITE(_params.mag_declination_deg) && (fabsf(_params.mag_declination_deg) > 0.f)
) { ) {
// using previously saved declination
fuseDeclination(math::radians(_params.mag_declination_deg), 0.5f, update_all_states); fuseDeclination(math::radians(_params.mag_declination_deg), R_DECL, update_all_states);
} else { } else {
_control_status.flags.mag_dec = false; // if there is no aiding coming from an inertial frame we need to fuse some declination
// even if we don't know the value, it's better to fuse 0 than nothing
float declination_rad = 0.f;
fuseDeclination(declination_rad, R_DECL);
} }
} }
} }
@@ -254,7 +261,7 @@ void Ekf::controlMagFusion(const imuSample &imu_sample)
const bool is_fusion_failing = isTimedOut(aid_src.time_last_fuse, _params.reset_timeout_max); const bool is_fusion_failing = isTimedOut(aid_src.time_last_fuse, _params.reset_timeout_max);
if (is_fusion_failing) { if (is_fusion_failing) {
if (no_ne_aiding_or_pre_takeoff) { if (no_ne_aiding_or_not_moving) {
ECL_WARN("%s fusion failing, resetting", AID_SRC_NAME); ECL_WARN("%s fusion failing, resetting", AID_SRC_NAME);
resetMagStates(_mag_lpf.getState(), _control_status.flags.mag_hdg || _control_status.flags.mag_3D); resetMagStates(_mag_lpf.getState(), _control_status.flags.mag_hdg || _control_status.flags.mag_3D);
aid_src.time_last_fuse = imu_sample.time_us; aid_src.time_last_fuse = imu_sample.time_us;
@@ -151,21 +151,18 @@ bool Ekf::fuseMag(const Vector3f &mag, const float R_MAG, VectorState &H, estima
return false; return false;
} }
bool Ekf::fuseDeclination(float decl_measurement_rad, float decl_sigma, bool update_all_states) bool Ekf::fuseDeclination(float decl_measurement_rad, float R, bool update_all_states)
{ {
// observation variance (rad**2)
const float R_DECL = sq(decl_sigma);
VectorState H; VectorState H;
float decl_pred; float decl_pred;
float innovation_variance; float innovation_variance;
sym::ComputeMagDeclinationPredInnovVarAndH(_state.vector(), P, R_DECL, FLT_EPSILON, sym::ComputeMagDeclinationPredInnovVarAndH(_state.vector(), P, R, FLT_EPSILON,
&decl_pred, &innovation_variance, &H); &decl_pred, &innovation_variance, &H);
const float innovation = wrap_pi(decl_pred - decl_measurement_rad); const float innovation = wrap_pi(decl_pred - decl_measurement_rad);
if (innovation_variance < R_DECL) { if (innovation_variance < R) {
// variance calculation is badly conditioned // variance calculation is badly conditioned
_fault_status.flags.bad_mag_decl = true; _fault_status.flags.bad_mag_decl = true;
return false; return false;
@@ -187,7 +184,7 @@ bool Ekf::fuseDeclination(float decl_measurement_rad, float decl_sigma, bool upd
Kfusion.slice<State::mag_B.dof, 1>(State::mag_B.idx, 0) = K_mag_B; Kfusion.slice<State::mag_B.dof, 1>(State::mag_B.idx, 0) = K_mag_B;
} }
const bool is_fused = measurementUpdate(Kfusion, H, R_DECL, innovation); const bool is_fused = measurementUpdate(Kfusion, H, R, innovation);
_fault_status.flags.bad_mag_decl = !is_fused; _fault_status.flags.bad_mag_decl = !is_fused;
+2 -2
View File
@@ -772,8 +772,8 @@ private:
bool update_all_states = false, bool update_tilt = false); bool update_all_states = false, bool update_tilt = false);
// fuse magnetometer declination measurement // fuse magnetometer declination measurement
// declination uncertainty in radians // R: declination observation variance (rad**2)
bool fuseDeclination(float decl_measurement_rad, float decl_sigma, bool update_all_states = false); bool fuseDeclination(const float decl_measurement_rad, const float R, bool update_all_states = false);
#endif // CONFIG_EKF2_MAGNETOMETER #endif // CONFIG_EKF2_MAGNETOMETER
@@ -108,6 +108,7 @@ TEST_F(EkfBasicsTest, initialControlMode)
EXPECT_EQ(1, (int) _ekf->control_status_flags().mag_hdg); EXPECT_EQ(1, (int) _ekf->control_status_flags().mag_hdg);
EXPECT_EQ(0, (int) _ekf->control_status_flags().mag_3D); EXPECT_EQ(0, (int) _ekf->control_status_flags().mag_3D);
EXPECT_EQ(1, (int) _ekf->control_status_flags().mag); EXPECT_EQ(1, (int) _ekf->control_status_flags().mag);
EXPECT_EQ(1, (int) _ekf->control_status_flags().mag_dec);
EXPECT_EQ(0, (int) _ekf->control_status_flags().in_air); EXPECT_EQ(0, (int) _ekf->control_status_flags().in_air);
EXPECT_EQ(0, (int) _ekf->control_status_flags().wind); EXPECT_EQ(0, (int) _ekf->control_status_flags().wind);
EXPECT_EQ(1, (int) _ekf->control_status_flags().baro_hgt); EXPECT_EQ(1, (int) _ekf->control_status_flags().baro_hgt);