ekf2: split resetMagCov() and skip mag reset if negligible change

This commit is contained in:
Daniel Agar
2024-08-27 16:16:55 +02:00
committed by Mathieu Bresciani
parent bbcf741e9e
commit 9d57a3c02f
4 changed files with 56 additions and 34 deletions
@@ -68,7 +68,9 @@ void Ekf::controlMagFusion(const imuSample &imu_sample)
_control_status.flags.mag_fault = false; _control_status.flags.mag_fault = false;
_state.mag_B.zero(); _state.mag_B.zero();
resetMagCov(); resetMagBiasCov();
stopMagFusion();
_mag_lpf.reset(mag_sample.mag); _mag_lpf.reset(mag_sample.mag);
_mag_counter = 1; _mag_counter = 1;
@@ -210,7 +212,7 @@ void Ekf::controlMagFusion(const imuSample &imu_sample)
if (continuing_conditions_passing && _control_status.flags.yaw_align) { if (continuing_conditions_passing && _control_status.flags.yaw_align) {
if (mag_sample.reset || checkHaglYawResetReq() || (wmm_updated && no_ne_aiding_or_pre_takeoff)) { if (checkHaglYawResetReq() || (wmm_updated && no_ne_aiding_or_pre_takeoff)) {
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;
@@ -313,6 +315,9 @@ void Ekf::stopMagFusion()
if (_control_status.flags.mag) { if (_control_status.flags.mag) {
ECL_INFO("stopping mag fusion"); ECL_INFO("stopping mag fusion");
resetMagEarthCov();
resetMagBiasCov();
if (_control_status.flags.yaw_align && (_control_status.flags.mag_3D || _control_status.flags.mag_hdg)) { if (_control_status.flags.yaw_align && (_control_status.flags.mag_3D || _control_status.flags.mag_hdg)) {
// reset yaw alignment from mag unless using GNSS aiding // reset yaw alignment from mag unless using GNSS aiding
const bool using_ne_aiding = _control_status.flags.gps || _control_status.flags.aux_gpos; const bool using_ne_aiding = _control_status.flags.gps || _control_status.flags.aux_gpos;
@@ -371,26 +376,36 @@ void Ekf::resetMagStates(const Vector3f &mag, bool reset_heading)
const Vector3f mag_I_before_reset = _state.mag_I; const Vector3f mag_I_before_reset = _state.mag_I;
const Vector3f mag_B_before_reset = _state.mag_B; const Vector3f mag_B_before_reset = _state.mag_B;
// reset covariances to default static constexpr float kMagEarthMinGauss = 0.01f; // minimum difference in mag earth field strength for reset (Gauss)
resetMagCov();
// if world magnetic model (inclination, declination, strength) available then use it to reset mag states // if world magnetic model (inclination, declination, strength) available then use it to reset mag states
if (_wmm_earth_field_gauss.longerThan(0.f) && _wmm_earth_field_gauss.isAllFinite()) { if (_wmm_earth_field_gauss.longerThan(0.f) && _wmm_earth_field_gauss.isAllFinite()) {
// use expected earth field to reset states // use expected earth field to reset states
// mag_B: reset // mag_I: reset, skipped if negligible change in state
const Vector3f mag_I = _wmm_earth_field_gauss;
bool mag_I_reset = false;
if ((_state.mag_I - mag_I).longerThan(kMagEarthMinGauss)) {
_state.mag_I = mag_I;
resetMagEarthCov();
mag_I_reset = true;
}
// mag_B: reset, skipped if mag_I didn't change
if (!reset_heading && _control_status.flags.yaw_align) { if (!reset_heading && _control_status.flags.yaw_align) {
// mag_B: reset using WMM if (mag_I_reset) {
const Dcmf R_to_body = quatToInverseRotMat(_state.quat_nominal); // mag_B: reset using WMM
_state.mag_B = mag - (R_to_body * _wmm_earth_field_gauss); const Dcmf R_to_body = quatToInverseRotMat(_state.quat_nominal);
_state.mag_B = mag - (R_to_body * _wmm_earth_field_gauss);
resetMagBiasCov();
} // otherwise keep existing mag_B state (!mag_I_reset)
} else { } else {
_state.mag_B.zero(); _state.mag_B.zero();
resetMagBiasCov();
} }
// mag_I: reset, skipped if no change in state and variance good
_state.mag_I = _wmm_earth_field_gauss;
if (reset_heading) { if (reset_heading) {
resetMagHeading(mag); resetMagHeading(mag);
} }
@@ -398,34 +413,32 @@ void Ekf::resetMagStates(const Vector3f &mag, bool reset_heading)
} else { } else {
// mag_B: reset // mag_B: reset
_state.mag_B.zero(); _state.mag_B.zero();
resetMagBiasCov();
// Use the magnetometer measurement to reset the field states // Use the magnetometer measurement to reset the heading
if (reset_heading) { if (reset_heading) {
resetMagHeading(mag); resetMagHeading(mag);
} }
// mag_I: use the last magnetometer measurements to reset the field states // mag_I: use the last magnetometer measurement to reset the field states
_state.mag_I = _R_to_earth * mag; const Vector3f mag_I = _R_to_earth * mag;
if ((_state.mag_I - mag_I).longerThan(kMagEarthMinGauss)) {
_state.mag_I = mag_I;
resetMagEarthCov();
}
} }
if (!mag_I_before_reset.longerThan(0.f)) { if ((_state.mag_I - mag_I_before_reset).longerThan(0.f)) {
ECL_INFO("initializing mag I [%.3f, %.3f, %.3f], mag B [%.3f, %.3f, %.3f]",
(double)_state.mag_I(0), (double)_state.mag_I(1), (double)_state.mag_I(2),
(double)_state.mag_B(0), (double)_state.mag_B(1), (double)_state.mag_B(2)
);
} else {
ECL_INFO("resetting mag I [%.3f, %.3f, %.3f] -> [%.3f, %.3f, %.3f]", ECL_INFO("resetting mag I [%.3f, %.3f, %.3f] -> [%.3f, %.3f, %.3f]",
(double)mag_I_before_reset(0), (double)mag_I_before_reset(1), (double)mag_I_before_reset(2), (double)mag_I_before_reset(0), (double)mag_I_before_reset(1), (double)mag_I_before_reset(2),
(double)_state.mag_I(0), (double)_state.mag_I(1), (double)_state.mag_I(2) (double)_state.mag_I(0), (double)_state.mag_I(1), (double)_state.mag_I(2));
); }
if (mag_B_before_reset.longerThan(0.f) || _state.mag_B.longerThan(0.f)) { if ((_state.mag_B - mag_B_before_reset).longerThan(0.f)) {
ECL_INFO("resetting mag B [%.3f, %.3f, %.3f] -> [%.3f, %.3f, %.3f]", ECL_INFO("resetting mag B [%.3f, %.3f, %.3f] -> [%.3f, %.3f, %.3f]",
(double)mag_B_before_reset(0), (double)mag_B_before_reset(1), (double)mag_B_before_reset(2), (double)mag_B_before_reset(0), (double)mag_B_before_reset(1), (double)mag_B_before_reset(2),
(double)_state.mag_B(0), (double)_state.mag_B(1), (double)_state.mag_B(2) (double)_state.mag_B(0), (double)_state.mag_B(1), (double)_state.mag_B(2));
);
}
} }
// record the start time for the magnetic field alignment // record the start time for the magnetic field alignment
@@ -99,7 +99,8 @@ bool Ekf::fuseMag(const Vector3f &mag, const float R_MAG, VectorState &H, estima
resetQuatCov(_params.mag_heading_noise); resetQuatCov(_params.mag_heading_noise);
} }
resetMagCov(); resetMagEarthCov();
resetMagBiasCov();
return false; return false;
} }
+10 -3
View File
@@ -96,7 +96,8 @@ void Ekf::initialiseCovariance()
resetAccelBiasCov(); resetAccelBiasCov();
#if defined(CONFIG_EKF2_MAGNETOMETER) #if defined(CONFIG_EKF2_MAGNETOMETER)
resetMagCov(); resetMagEarthCov();
resetMagBiasCov();
#endif // CONFIG_EKF2_MAGNETOMETER #endif // CONFIG_EKF2_MAGNETOMETER
#if defined(CONFIG_EKF2_WIND) #if defined(CONFIG_EKF2_WIND)
@@ -340,11 +341,17 @@ void Ekf::resetAccelBiasCov()
} }
#if defined(CONFIG_EKF2_MAGNETOMETER) #if defined(CONFIG_EKF2_MAGNETOMETER)
void Ekf::resetMagCov() void Ekf::resetMagEarthCov()
{ {
ECL_INFO("reset mag covariance"); ECL_INFO("reset mag earth covariance");
P.uncorrelateCovarianceSetVariance<State::mag_I.dof>(State::mag_I.idx, sq(_params.mag_noise)); P.uncorrelateCovarianceSetVariance<State::mag_I.dof>(State::mag_I.idx, sq(_params.mag_noise));
}
void Ekf::resetMagBiasCov()
{
ECL_INFO("reset mag bias covariance");
P.uncorrelateCovarianceSetVariance<State::mag_B.dof>(State::mag_B.idx, sq(_params.mag_noise)); P.uncorrelateCovarianceSetVariance<State::mag_B.dof>(State::mag_B.idx, sq(_params.mag_noise));
} }
#endif // CONFIG_EKF2_MAGNETOMETER #endif // CONFIG_EKF2_MAGNETOMETER
+2 -1
View File
@@ -1108,7 +1108,8 @@ private:
void resetQuatCov(const Vector3f &rot_var_ned); void resetQuatCov(const Vector3f &rot_var_ned);
#if defined(CONFIG_EKF2_MAGNETOMETER) #if defined(CONFIG_EKF2_MAGNETOMETER)
void resetMagCov(); void resetMagEarthCov();
void resetMagBiasCov();
#endif // CONFIG_EKF2_MAGNETOMETER #endif // CONFIG_EKF2_MAGNETOMETER
#if defined(CONFIG_EKF2_WIND) #if defined(CONFIG_EKF2_WIND)