diff --git a/libraries/AP_NavEKF2/AP_NavEKF2_MagFusion.cpp b/libraries/AP_NavEKF2/AP_NavEKF2_MagFusion.cpp index ba22669f93..3c81dfc471 100644 --- a/libraries/AP_NavEKF2/AP_NavEKF2_MagFusion.cpp +++ b/libraries/AP_NavEKF2/AP_NavEKF2_MagFusion.cpp @@ -346,7 +346,7 @@ void NavEKF2_core::FuseMagnetometer() } // scale magnetometer observation error with total angular rate to allow for timing errors - R_MAG = sq(constrain_float(frontend->_magNoise, 0.01f, 0.5f)) + sq(frontend->magVarRateScale*imuDataDelayed.delAng.length() / imuDataDelayed.delAngDT); + R_MAG = sq(constrain_float(frontend->_magNoise, 0.01f, 0.5f)) + sq(frontend->magVarRateScale*delAngCorrected.length() / imuDataDelayed.delAngDT); // calculate common expressions used to calculate observation jacobians an innovation variance for each component SH_MAG[0] = sq(q0) - sq(q1) + sq(q2) - sq(q3); diff --git a/libraries/AP_NavEKF2/AP_NavEKF2_Measurements.cpp b/libraries/AP_NavEKF2/AP_NavEKF2_Measurements.cpp index fb407cad12..826208e5ee 100644 --- a/libraries/AP_NavEKF2/AP_NavEKF2_Measurements.cpp +++ b/libraries/AP_NavEKF2/AP_NavEKF2_Measurements.cpp @@ -282,12 +282,16 @@ void NavEKF2_core::readIMUData() // If 10msec has elapsed, and the frontend has allowed us to start a new predict cycle, then store the accumulated IMU data // to be used by the state prediction, ignoring the frontend permission if more than 20msec has lapsed if ((dtIMUavg*(float)framesSincePredict >= 0.01f && startPredictEnabled) || (dtIMUavg*(float)framesSincePredict >= 0.02f)) { + // convert the accumulated quaternion to an equivalent delta angle imuQuatDownSampleNew.to_axis_angle(imuDataDownSampledNew.delAng); + // Time stamp the data imuDataDownSampledNew.time_ms = imuSampleTime_ms; + // Write data to the FIFO IMU buffer storedIMU.push_youngest_element(imuDataDownSampledNew); + // zero the accumulated IMU data and quaternion imuDataDownSampledNew.delAng.zero(); imuDataDownSampledNew.delVel.zero(); @@ -295,18 +299,28 @@ void NavEKF2_core::readIMUData() imuDataDownSampledNew.delVelDT = 0.0f; imuQuatDownSampleNew[0] = 1.0f; imuQuatDownSampleNew[3] = imuQuatDownSampleNew[2] = imuQuatDownSampleNew[1] = 0.0f; + // reset the counter used to let the frontend know how many frames have elapsed since we started a new update cycle framesSincePredict = 0; + // set the flag to let the filter know it has new IMU data nad needs to run runUpdates = true; + // extract the oldest available data from the FIFO buffer imuDataDelayed = storedIMU.pop_oldest_element(); + + // protect against delta time going to zero + // TODO - check if calculations can tolerate 0 float minDT = 0.1f*dtEkfAvg; imuDataDelayed.delAngDT = MAX(imuDataDelayed.delAngDT,minDT); imuDataDelayed.delVelDT = MAX(imuDataDelayed.delVelDT,minDT); + // correct the extracted IMU data for sensor errors - correctDeltaAngle(imuDataDelayed.delAng, imuDataDelayed.delAngDT); - correctDeltaVelocity(imuDataDelayed.delVel, imuDataDelayed.delVelDT); + delAngCorrected = imuDataDelayed.delAng; + delVelCorrected = imuDataDelayed.delVel; + correctDeltaAngle(delAngCorrected, imuDataDelayed.delAngDT); + correctDeltaVelocity(delVelCorrected, imuDataDelayed.delVelDT); + } else { // we don't have new IMU data in the buffer so don't run filter updates on this time step runUpdates = false; diff --git a/libraries/AP_NavEKF2/AP_NavEKF2_core.cpp b/libraries/AP_NavEKF2/AP_NavEKF2_core.cpp index fcb0ea7373..a0faa4d6db 100644 --- a/libraries/AP_NavEKF2/AP_NavEKF2_core.cpp +++ b/libraries/AP_NavEKF2/AP_NavEKF2_core.cpp @@ -493,13 +493,11 @@ void NavEKF2_core::correctDeltaVelocity(Vector3f &delVel, float delVelDT) */ void NavEKF2_core::UpdateStrapdownEquationsNED() { - // apply correction for earth's rotation rate - // % * - and + operators have been overloaded - imuDataDelayed.delAng -= prevTnb * earthRateNED*imuDataDelayed.delAngDT; - // update the quaternion states by rotating from the previous attitude through // the delta angle rotation quaternion and normalise - stateStruct.quat.rotate(imuDataDelayed.delAng); + // apply correction for earth's rotation rate + // % * - and + operators have been overloaded + stateStruct.quat.rotate(delAngCorrected - prevTnb * earthRateNED*imuDataDelayed.delAngDT); stateStruct.quat.normalize(); // transform body delta velocities to delta velocities in the nav frame @@ -507,7 +505,7 @@ void NavEKF2_core::UpdateStrapdownEquationsNED() // have been rotated into that frame // * and + operators have been overloaded Vector3f delVelNav; // delta velocity vector in earth axes - delVelNav = prevTnb.mul_transpose(imuDataDelayed.delVel); + delVelNav = prevTnb.mul_transpose(delVelCorrected); delVelNav.z += GRAVITY_MSS*imuDataDelayed.delVelDT; // calculate the body to nav cosine matrix @@ -542,7 +540,7 @@ void NavEKF2_core::UpdateStrapdownEquationsNED() stateStruct.position += (stateStruct.velocity + lastVelocity) * (imuDataDelayed.delVelDT*0.5f); // accumulate the bias delta angle and time since last reset by an OF measurement arrival - delAngBodyOF += imuDataDelayed.delAng - stateStruct.gyro_bias; + delAngBodyOF += delAngCorrected; delTimeOF += imuDataDelayed.delAngDT; // limit states to protect against divergence diff --git a/libraries/AP_NavEKF2/AP_NavEKF2_core.h b/libraries/AP_NavEKF2/AP_NavEKF2_core.h index 3480e00913..a22bf1e3df 100644 --- a/libraries/AP_NavEKF2/AP_NavEKF2_core.h +++ b/libraries/AP_NavEKF2/AP_NavEKF2_core.h @@ -787,6 +787,8 @@ private: bool startPredictEnabled; // boolean true when the frontend has given permission to start a new state prediciton cycele uint8_t localFilterTimeStep_ms; // average number of msec between filter updates 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 delVelCorrected; // corrected IMU delta velocity vector at the EKF time horizon (m/s) // variables used to calculate a vertical velocity that is kinematically consistent with the verical position float posDownDerivative; // Rate of chage of vertical position (dPosD/dt) in m/s. This is the first time derivative of PosD.