AP_NavEKF2: remember mag field states between flight on same power cycle

Remember the mag bias and earth field states learned during flight when the vehicle  lands.
This improves performance for vehicles that do multiple flight on one power cycle
This commit is contained in:
priseborough 2016-07-02 18:46:42 +10:00
parent 136df7cb5c
commit 51dbed2338
4 changed files with 76 additions and 41 deletions

View File

@ -111,9 +111,19 @@ void NavEKF2_core::setWindMagStateLearningMode()
inhibitMagStates = true; inhibitMagStates = true;
} else if (inhibitMagStates && !setMagInhibit) { } else if (inhibitMagStates && !setMagInhibit) {
inhibitMagStates = false; inhibitMagStates = false;
// when commencing use of magnetic field states, set the variances equal to the observation uncertainty if (magFieldLearned) {
for (uint8_t index=16; index<=21; index++) { // if we have already learned the field states, then retain the learned variances
P[index][index] = sq(frontend->_magNoise); P[16][16] = earthMagFieldVar.x;
P[17][17] = earthMagFieldVar.y;
P[18][18] = earthMagFieldVar.z;
P[19][19] = bodyMagFieldVar.x;
P[20][20] = bodyMagFieldVar.y;
P[21][21] = bodyMagFieldVar.z;
} else {
// set the variances equal to the observation variances
for (uint8_t index=16; index<=21; index++) {
P[index][index] = sq(frontend->_magNoise);
}
} }
// request a reset of the yaw and magnetic field states if not done before // request a reset of the yaw and magnetic field states if not done before
if (!magStateInitComplete || (!finalInflightMagInit && inFlight)) { if (!magStateInitComplete || (!finalInflightMagInit && inFlight)) {

View File

@ -265,6 +265,26 @@ void NavEKF2_core::SelectMagFusion()
} }
} }
// If the final yaw reset has been performed and the state variances are sufficiently low
// record that the earth field has been learned.
bool earthMagFieldConverged = false;
if (!magFieldLearned && finalInflightMagInit) {
earthMagFieldConverged = (P[16][16] < sq(0.01f)) && (P[17][17] < sq(0.01f)) && (P[18][18] < sq(0.01f));
}
if (magFieldLearned || earthMagFieldConverged) {
magFieldLearned = true;
}
// record the last learned field variances
if (magFieldLearned && !inhibitMagStates) {
earthMagFieldVar.x = P[16][16];
earthMagFieldVar.y = P[17][17];
earthMagFieldVar.z = P[18][18];
bodyMagFieldVar.x = P[19][19];
bodyMagFieldVar.y = P[20][20];
bodyMagFieldVar.z = P[21][21];
}
// stop performance timer // stop performance timer
hal.util->perf_end(_perf_FuseMagnetometer); hal.util->perf_end(_perf_FuseMagnetometer);
} }
@ -1062,6 +1082,11 @@ void NavEKF2_core::FuseDeclination(float declErr)
// align the NE earth magnetic field states with the published declination // align the NE earth magnetic field states with the published declination
void NavEKF2_core::alignMagStateDeclination() void NavEKF2_core::alignMagStateDeclination()
{ {
// don't do this if we already have a learned magnetic field
if (magFieldLearned) {
return;
}
// get the magnetic declination // get the magnetic declination
float magDecAng = use_compass() ? _ahrs->get_compass()->get_declination() : 0; float magDecAng = use_compass() ? _ahrs->get_compass()->get_declination() : 0;

View File

@ -261,6 +261,7 @@ void NavEKF2_core::InitialiseVariables()
posDownAtLastMagReset = stateStruct.position.z; posDownAtLastMagReset = stateStruct.position.z;
yawInnovAtLastMagReset = 0.0f; yawInnovAtLastMagReset = 0.0f;
quatAtLastMagReset = stateStruct.quat; quatAtLastMagReset = stateStruct.quat;
magFieldLearned = false;
// zero data buffers // zero data buffers
storedIMU.reset(); storedIMU.reset();
@ -1374,55 +1375,51 @@ Quaternion NavEKF2_core::calcQuatAndFieldStates(float roll, float pitch)
// calculate yaw angle rel to true north // calculate yaw angle rel to true north
yaw = magDecAng - magHeading; yaw = magDecAng - magHeading;
// calculate initial filter quaternion states using yaw from magnetometer if mag heading healthy // calculate initial filter quaternion states using yaw from magnetometer
// otherwise use existing heading // store the yaw change so that it can be retrieved externally for use by the control loops to prevent yaw disturbances following a reset
if (!badMagYaw) { Vector3f tempEuler;
// store the yaw change so that it can be retrieved externally for use by the control loops to prevent yaw disturbances following a reset stateStruct.quat.to_euler(tempEuler.x, tempEuler.y, tempEuler.z);
Vector3f tempEuler; // this check ensures we accumulate the resets that occur within a single iteration of the EKF
stateStruct.quat.to_euler(tempEuler.x, tempEuler.y, tempEuler.z); if (imuSampleTime_ms != lastYawReset_ms) {
// this check ensures we accumulate the resets that occur within a single iteration of the EKF yawResetAngle = 0.0f;
if (imuSampleTime_ms != lastYawReset_ms) {
yawResetAngle = 0.0f;
}
yawResetAngle += wrap_PI(yaw - tempEuler.z);
lastYawReset_ms = imuSampleTime_ms;
// calculate an initial quaternion using the new yaw value
initQuat.from_euler(roll, pitch, yaw);
// zero the attitude covariances becasue the corelations will now be invalid
zeroAttCovOnly();
} else {
initQuat = stateStruct.quat;
} }
yawResetAngle += wrap_PI(yaw - tempEuler.z);
lastYawReset_ms = imuSampleTime_ms;
// calculate an initial quaternion using the new yaw value
initQuat.from_euler(roll, pitch, yaw);
// zero the attitude covariances becasue the corelations will now be invalid
zeroAttCovOnly();
// calculate initial Tbn matrix and rotate Mag measurements into NED // calculate initial Tbn matrix and rotate Mag measurements into NED
// to set initial NED magnetic field states // to set initial NED magnetic field states
initQuat.rotation_matrix(Tbn); // don't do this if the earth field has already been learned
stateStruct.earth_magfield = Tbn * magDataDelayed.mag; if (!magFieldLearned) {
initQuat.rotation_matrix(Tbn);
stateStruct.earth_magfield = Tbn * magDataDelayed.mag;
// align the NE earth magnetic field states with the published declination // align the NE earth magnetic field states with the published declination
alignMagStateDeclination(); alignMagStateDeclination();
// zero the magnetic field state associated covariances // zero the magnetic field state associated covariances
zeroRows(P,16,21); zeroRows(P,16,21);
zeroCols(P,16,21); zeroCols(P,16,21);
// set initial earth magnetic field variances // set initial earth magnetic field variances
P[16][16] = sq(frontend->_magNoise); P[16][16] = sq(frontend->_magNoise);
P[17][17] = P[16][16]; P[17][17] = P[16][16];
P[18][18] = P[16][16]; P[18][18] = P[16][16];
// set initial body magnetic field variances // set initial body magnetic field variances
P[19][19] = sq(frontend->_magNoise); P[19][19] = sq(frontend->_magNoise);
P[20][20] = P[19][19]; P[20][20] = P[19][19];
P[21][21] = P[19][19]; P[21][21] = P[19][19];
// clear bad magnetic yaw status }
badMagYaw = false;
// clear mag state reset request
magStateResetRequest = false;
// record the fact we have initialised the magnetic field states // record the fact we have initialised the magnetic field states
recordMagReset(); recordMagReset();
// clear mag state reset request
magStateResetRequest = false;
} else { } else {
// this function should not be called if there is no compass data but if is is, return the // this function should not be called if there is no compass data but if is is, return the
// current attitude // current attitude

View File

@ -795,6 +795,9 @@ private:
float posDownObsNoise; // observation noise variance on the vertical position used by the state and covariance update step (m^2) float posDownObsNoise; // observation noise variance on the vertical position used by the state and covariance update step (m^2)
Vector3f delAngCorrected; // corrected IMU delta angle vector at the EKF time horizon (rad) Vector3f delAngCorrected; // corrected IMU delta angle vector at the EKF time horizon (rad)
Vector3f delVelCorrected; // corrected IMU delta velocity vector at the EKF time horizon (m/s) Vector3f delVelCorrected; // corrected IMU delta velocity vector at the EKF time horizon (m/s)
bool magFieldLearned; // true when the magnetic field has been learned
Vector3f earthMagFieldVar; // NED earth mag field variances for last learned field (mGauss^2)
Vector3f bodyMagFieldVar; // XYZ body mag field variances for last learned field (mGauss^2)
Vector3f outputTrackError; Vector3f outputTrackError;