Ardupilot EKF is failing on a health check,
value reported as EKF3 - IPD is the cause, if this value goes above 1 while ardupilot is disarmed a “Bad AHRS” error will be given.
This issue will not occur if the ardupilot is armed
How i got to the answer
So im going to walk through the EKF health check to find out what is the cause to “Bad AHRS”
Test 1: Passed
so in my previous out i checked the Fault Status code, which was 0 so test 1 passed
Test 2: Passed
again in a previous post I check my variances, the height variance was a bit erratic compared to other values but they were all below 1, so test 2 passed.
Im not sure what the value of _fallback but either way it doesnt matter, if its false the test wont run so this test doesnt matter, if its true then the test would pass because ive checked the other values
Test 3: Failed
Test 3.1: So next tests run (if armed then Test3 as a whole passes)
!vehicleArmed
Quadcopter not armed so next tests run
Test 3.2: Failed
fabsf(innovVelPos[5]) > 1.0f
innovVelPos[5] = Log Review EKF3 - IPD = 1.4 (highest value, and this value is normally below 1 but spikes above every now and then)
so this value value has gone above 1, so this test failed causing routine to return false (Unhealthy EFK, which is also Unhealthy AHRS “Bad AHRS”)
Test 3.3: Passed
float horizErrSq = sq(innovVelPos[3]) + sq(innovVelPos[4]);
horizErrSq > 1.0f
innovVelPos[3] = Log Review EKF3 - IPN = -0.08 (highest value)
innovVelPos[4] = Log Review EKF3 - IPE = -0.05 (matching row, but also the highest value)
horizErrSq = sq(-0.08) + sp(-0.05)
-0.0089 = -0.0064 + -0.0025
So -0.0089 is less than 1 so this test Passed
Im modified the source below, ive only added comments
bool NavEKF::healthy(void) const
{
// Test 1 : get the FilterFault code status, if its greater than 1 then EKF unhealthy
uint8_t faultInt;
getFilterFaults(faultInt);
if (faultInt > 0) {
return false;
}
//Test2: Check Fallback and variances
if (_fallback && velTestRatio > 1 && posTestRatio > 1 && hgtTestRatio > 1) {
// all three metrics being above 1 means the filter is
// extremely unhealthy.
return false;
}
// Give the filter a second to settle before use
if ((imuSampleTime_ms - ekfStartTime_ms) < 1000 ) {
return false;
}
//Test 3: when not armed (when every seems to have this issue??)
// barometer and position innovations must be within limits when on-ground
float horizErrSq = sq(innovVelPos[3]) + sq(innovVelPos[4]);
if (!vehicleArmed && (fabsf(innovVelPos[5]) > 1.0f || horizErrSq > 1.0f)) {
return false;
}
// all OK
return true;
}