AP_NavEKF3: continuously update gpsGoodToAlign

use it to determine how to handle a height datum reset
This commit is contained in:
Andrew Tridgell 2019-07-02 13:42:52 +10:00
parent 9372073f63
commit f3fc910abe
5 changed files with 37 additions and 26 deletions

View File

@ -576,13 +576,8 @@ void NavEKF3_core::readGpsData()
useGpsVertVel = false; useGpsVertVel = false;
} }
// Monitor quality of the GPS velocity data before and after alignment using separate checks // Monitor quality of the GPS velocity data before and after alignment
if (PV_AidingMode != AID_ABSOLUTE) { calcGpsGoodToAlign();
// Pre-alignment checks
gpsGoodToAlign = calcGpsGoodToAlign();
} else {
gpsGoodToAlign = false;
}
// Post-alignment checks // Post-alignment checks
calcGpsGoodForFlight(); calcGpsGoodForFlight();

View File

@ -607,7 +607,7 @@ void NavEKF3_core::send_status_report(mavlink_channel_t chan)
// report the reason for why the backend is refusing to initialise // report the reason for why the backend is refusing to initialise
const char *NavEKF3_core::prearm_failure_reason(void) const const char *NavEKF3_core::prearm_failure_reason(void) const
{ {
if (imuSampleTime_ms - lastGpsVelFail_ms > 10000) { if (gpsGoodToAlign) {
// we are not failing // we are not failing
return nullptr; return nullptr;
} }

View File

@ -212,21 +212,21 @@ bool NavEKF3_core::resetHeightDatum(void)
// reset the height state // reset the height state
stateStruct.position.z = 0.0f; stateStruct.position.z = 0.0f;
// adjust the height of the EKF origin so that the origin plus baro height before and after the reset is the same // adjust the height of the EKF origin so that the origin plus baro height before and after the reset is the same
if (validOrigin) { if (validOrigin && !inFlight) {
const AP_GPS &gps = AP::gps(); if (!gpsGoodToAlign) {
if (gps.status() >= AP_GPS::GPS_OK_FIX_3D) { // if we don't have GPS lock then we shouldn't be doing a
// resetHeightDatum, but if we do then the best option is
// to maintain the old error
ekfGpsRefHgt += (int32_t)(100.0f * oldHgt);
} else {
// if we have a good GPS lock then reset to the GPS // if we have a good GPS lock then reset to the GPS
// altitude. This ensures the reported AMSL alt from // altitude. This ensures the reported AMSL alt from
// getLLH() is equal to GPS altitude, while also ensuring // getLLH() is equal to GPS altitude, while also ensuring
// that the relative alt is zero // that the relative alt is zero
ekfGpsRefHgt = gps.location().alt*0.01; ekfGpsRefHgt = AP::gps().location().alt*0.01;
} else {
// if we don't have GPS lock then we shouldn't be doing a
// resetHeightDatum, but if we do then the best option is
// to maintain the old error
ekfGpsRefHgt += oldHgt;
} }
} }
// adjust the terrain state // adjust the terrain state
terrainState += oldHgt; terrainState += oldHgt;
return true; return true;

View File

@ -17,17 +17,28 @@ extern const AP_HAL::HAL& hal;
We also record the failure reason so that prearm_failure_reason() We also record the failure reason so that prearm_failure_reason()
can give a good report to the user on why arming is failing can give a good report to the user on why arming is failing
*/ */
bool NavEKF3_core::calcGpsGoodToAlign(void) void NavEKF3_core::calcGpsGoodToAlign(void)
{ {
if (inFlight && assume_zero_sideslip() && !use_compass()) { if (inFlight && assume_zero_sideslip() && !use_compass()) {
// this is a special case where a plane has launched without magnetometer // this is a special case where a plane has launched without magnetometer
// is now in the air and needs to align yaw to the GPS and start navigating as soon as possible // is now in the air and needs to align yaw to the GPS and start navigating as soon as possible
return true; gpsGoodToAlign = true;
return;
} }
// User defined multiplier to be applied to check thresholds // User defined multiplier to be applied to check thresholds
float checkScaler = 0.01f*(float)frontend->_gpsCheckScaler; float checkScaler = 0.01f*(float)frontend->_gpsCheckScaler;
if (gpsGoodToAlign) {
/*
if we have already passed GPS alignment checks then raise
the check threshold so that we have some hysterisis and
don't continuously change from able to arm to not able to
arm
*/
checkScaler *= 1.3f;
}
// If we have good magnetometer consistency and bad innovations for longer than 5 seconds then we reset heading and field states // If we have good magnetometer consistency and bad innovations for longer than 5 seconds then we reset heading and field states
// This enables us to handle large changes to the external magnetic field environment that occur before arming // This enables us to handle large changes to the external magnetic field environment that occur before arming
if ((magTestRatio.x <= 1.0f && magTestRatio.y <= 1.0f && yawTestRatio <= 1.0f) || !consistentMagData) { if ((magTestRatio.x <= 1.0f && magTestRatio.y <= 1.0f && yawTestRatio <= 1.0f) || !consistentMagData) {
@ -222,16 +233,20 @@ bool NavEKF3_core::calcGpsGoodToAlign(void)
lastGpsVelFail_ms = imuSampleTime_ms; lastGpsVelFail_ms = imuSampleTime_ms;
} }
// record time of fail // record time of pass or fail
if (gpsSpdAccFail || numSatsFail || hdopFail || hAccFail || vAccFail || yawFail || gpsDriftFail || gpsVertVelFail || gpsHorizVelFail) { if (gpsSpdAccFail || numSatsFail || hdopFail || hAccFail || vAccFail || yawFail || gpsDriftFail || gpsVertVelFail || gpsHorizVelFail) {
lastGpsVelFail_ms = imuSampleTime_ms; lastGpsVelFail_ms = imuSampleTime_ms;
} else {
lastGpsVelPass_ms = imuSampleTime_ms;
} }
// continuous period without fail required to return a healthy status // continuous period of 10s without fail required to set healthy
if (imuSampleTime_ms - lastGpsVelFail_ms > 10000) { // continuous period of 5s without pass required to set unhealthy
return true; if (!gpsGoodToAlign && imuSampleTime_ms - lastGpsVelFail_ms > 10000) {
gpsGoodToAlign = true;
} else if (gpsGoodToAlign && imuSampleTime_ms - lastGpsVelPass_ms > 5000) {
gpsGoodToAlign = false;
} }
return false;
} }
// update inflight calculaton that determines if GPS data is good enough for reliable navigation // update inflight calculaton that determines if GPS data is good enough for reliable navigation

View File

@ -751,8 +751,8 @@ private:
// determine if a touchdown is expected so that we can compensate for expected barometer errors due to ground effect // determine if a touchdown is expected so that we can compensate for expected barometer errors due to ground effect
bool getTouchdownExpected(); bool getTouchdownExpected();
// Assess GPS data quality and return true if good enough to align the EKF // Assess GPS data quality and set gpsGoodToAlign
bool calcGpsGoodToAlign(void); void calcGpsGoodToAlign(void);
// set the class variable true if the delta angle bias variances are sufficiently small // set the class variable true if the delta angle bias variances are sufficiently small
void checkGyroCalStatus(void); void checkGyroCalStatus(void);
@ -905,6 +905,7 @@ private:
float gpsPosAccuracy; // estimated position accuracy in m returned by the GPS receiver float gpsPosAccuracy; // estimated position accuracy in m returned by the GPS receiver
float gpsHgtAccuracy; // estimated height accuracy in m returned by the GPS receiver float gpsHgtAccuracy; // estimated height accuracy in m returned by the GPS receiver
uint32_t lastGpsVelFail_ms; // time of last GPS vertical velocity consistency check fail uint32_t lastGpsVelFail_ms; // time of last GPS vertical velocity consistency check fail
uint32_t lastGpsVelPass_ms; // time of last GPS vertical velocity consistency check pass
uint32_t lastGpsAidBadTime_ms; // time in msec gps aiding was last detected to be bad uint32_t lastGpsAidBadTime_ms; // time in msec gps aiding was last detected to be bad
float posDownAtTakeoff; // flight vehicle vertical position sampled at transition from on-ground to in-air and used as a reference (m) float posDownAtTakeoff; // flight vehicle vertical position sampled at transition from on-ground to in-air and used as a reference (m)
bool useGpsVertVel; // true if GPS vertical velocity should be used bool useGpsVertVel; // true if GPS vertical velocity should be used