AP_NavEKF : update comments

This commit is contained in:
Paul Riseborough 2014-03-09 07:51:45 +11:00 committed by priseborough
parent c8bd415b00
commit e485b246e7
2 changed files with 67 additions and 45 deletions

View File

@ -255,6 +255,7 @@ NavEKF::NavEKF(const AP_AHRS *ahrs, AP_Baro &baro) :
IMU1_weighting = 0.5f; IMU1_weighting = 0.5f;
} }
// Check basic filter health metrics and return a consolidated health status
bool NavEKF::healthy(void) const bool NavEKF::healthy(void) const
{ {
if (!statesInitialised) { if (!statesInitialised) {
@ -277,18 +278,21 @@ bool NavEKF::healthy(void) const
return true; return true;
} }
// Returns true if height drift is not being constrained
bool NavEKF::HeightDrifting(void) const bool NavEKF::HeightDrifting(void) const
{ {
// Set to true if height measurements are failing the innovation consistency check // Set to true if height measurements are failing the innovation consistency check
return !hgtHealth; return !hgtHealth;
} }
// Returns true if position drift is not being constrained
bool NavEKF::PositionDrifting(void) const bool NavEKF::PositionDrifting(void) const
{ {
// Set to true if position measurements are failing the innovation consistency check // Set to true if position measurements are failing the innovation consistency check
return !posHealth; return !posHealth;
} }
// Resets position states to last GPS measurement or to zero if in static mode
void NavEKF::ResetPosition(void) void NavEKF::ResetPosition(void)
{ {
if (staticMode) { if (staticMode) {
@ -304,6 +308,7 @@ void NavEKF::ResetPosition(void)
} }
} }
// Resets velocity states to last GPS measurement or to zero if in static mode
void NavEKF::ResetVelocity(void) void NavEKF::ResetVelocity(void)
{ {
if (staticMode) { if (staticMode) {
@ -313,19 +318,20 @@ void NavEKF::ResetVelocity(void)
} else if (_ahrs->get_gps()->status() >= GPS::GPS_OK_FIX_3D) { } else if (_ahrs->get_gps()->status() >= GPS::GPS_OK_FIX_3D) {
// read the GPS // read the GPS
readGpsData(); readGpsData();
// write to state vector // reset horizontal velocity states
if (_fusionModeGPS <= 1) { if (_fusionModeGPS <= 1) {
states[4] = velNED[0]; states[4] = velNED[0]; // north velocity from blended accel data
states[5] = velNED[1]; states[5] = velNED[1]; // east velocity from blended accel data
states[23] = velNED[0]; states[23] = velNED[0]; // north velocity from IMU1 accel data
states[24] = velNED[1]; states[24] = velNED[1]; // east velocity from IMU1 accel data
states[27] = velNED[0]; states[27] = velNED[0]; // north velocity from IMU2 accel data
states[28] = velNED[1]; states[28] = velNED[1]; // east velocity from IMU2 accel data
} }
// reset vertical velocity states
if (_fusionModeGPS <= 0) { if (_fusionModeGPS <= 0) {
states[6] = velNED[2]; states[6] = velNED[2]; // down velocity from blended accel data
states[25] = velNED[2]; states[25] = velNED[2]; // down velocity from IMU1 accel data
states[29] = velNED[2]; states[29] = velNED[2]; // down velocity from IMU2 accel data
} }
} }
} }
@ -335,9 +341,9 @@ void NavEKF::ResetHeight(void)
// read the altimeter // read the altimeter
readHgtData(); readHgtData();
// write to state vector // write to state vector
states[9] = -hgtMea; states[9] = -hgtMea; // down position from blended accel data
state.posD1 = -hgtMea; state.posD1 = -hgtMea; // down position from IMU1 accel data
state.posD2 = -hgtMea; state.posD2 = -hgtMea; // down position from IMU2 accel data
} }
// This function is used to initialise the filter whilst moving, using the AHRS DCM solution // This function is used to initialise the filter whilst moving, using the AHRS DCM solution
@ -377,11 +383,11 @@ void NavEKF::InitialiseFilterDynamic(void)
// 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 // calculate initial filter quaternion states
Quaternion initQuat; Quaternion initQuat;
initQuat.from_euler(_ahrs->roll, _ahrs->pitch, yaw); initQuat.from_euler(_ahrs->roll, _ahrs->pitch, yaw);
// 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); initQuat.rotation_matrix(Tbn);
initMagNED = Tbn * magData; initMagNED = Tbn * magData;
@ -398,21 +404,22 @@ void NavEKF::InitialiseFilterDynamic(void)
state.earth_magfield = initMagNED; state.earth_magfield = initMagNED;
state.body_magfield = magBias; state.body_magfield = magBias;
// set to true now that states have be initialised
statesInitialised = true; statesInitialised = true;
// initialise the covariance matrix // initialise the covariance matrix
CovarianceInit(_ahrs->roll, _ahrs->pitch, _ahrs->yaw); CovarianceInit(_ahrs->roll, _ahrs->pitch, _ahrs->yaw);
//Define Earth rotation vector in the NED navigation frame // define Earth rotation vector in the NED navigation frame
calcEarthRateNED(earthRateNED, _ahrs->get_home().lat); calcEarthRateNED(earthRateNED, _ahrs->get_home().lat);
//Initialise IMU pre-processing states // initialise IMU pre-processing states
readIMUData(); readIMUData();
} }
void NavEKF::InitialiseFilterBootstrap(void) void NavEKF::InitialiseFilterBootstrap(void)
{ {
// Set re-used variables to zero // set re-used variables to zero
ZeroVariables(); ZeroVariables();
// acceleration vector in XYZ body axes measured by the IMU (m/s^2) // acceleration vector in XYZ body axes measured by the IMU (m/s^2)
@ -424,10 +431,10 @@ void NavEKF::InitialiseFilterBootstrap(void)
// read the magnetometer data // read the magnetometer data
readMagData(); readMagData();
// Normalise the acceleration vector // normalise the acceleration vector
initAccVec.normalize(); initAccVec.normalize();
// Calculate initial pitch angle // calculate initial pitch angle
float pitch = asinf(initAccVec.x); float pitch = asinf(initAccVec.x);
// calculate initial roll angle // calculate initial roll angle
@ -456,11 +463,11 @@ void NavEKF::InitialiseFilterBootstrap(void)
yaw = 0.0f; yaw = 0.0f;
} }
// Calculate initial filter quaternion states // calculate initial filter quaternion states
Quaternion initQuat; Quaternion initQuat;
initQuat.from_euler(roll, pitch, yaw); initQuat.from_euler(roll, pitch, yaw);
// 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); initQuat.rotation_matrix(Tbn);
initMagNED = Tbn * magData; initMagNED = Tbn * magData;
@ -471,7 +478,7 @@ void NavEKF::InitialiseFilterBootstrap(void)
// read the barometer // read the barometer
readHgtData(); readHgtData();
// set onground flag // check on ground status
OnGroundCheck(); OnGroundCheck();
// write to state vector // write to state vector
@ -483,31 +490,33 @@ void NavEKF::InitialiseFilterBootstrap(void)
state.earth_magfield = initMagNED; state.earth_magfield = initMagNED;
state.body_magfield = magBias; state.body_magfield = magBias;
// set to true now we have intialised the states
statesInitialised = true; statesInitialised = true;
// initialise the covariance matrix // initialise the covariance matrix
CovarianceInit(roll, pitch, yaw); CovarianceInit(roll, pitch, yaw);
//Define Earth rotation vector in the NED navigation frame // define Earth rotation vector in the NED navigation frame
calcEarthRateNED(earthRateNED, _ahrs->get_home().lat); calcEarthRateNED(earthRateNED, _ahrs->get_home().lat);
//Initialise IMU pre-processing states // initialise IMU pre-processing states
readIMUData(); readIMUData();
} }
void NavEKF::UpdateFilter() void NavEKF::UpdateFilter()
{ {
// don't run filter updates if states have not been initialised
if (!statesInitialised) { if (!statesInitialised) {
return; return;
} }
// start the timer used for load measurement
perf_begin(_perf_UpdateFilter); perf_begin(_perf_UpdateFilter);
// This function will be called at 100Hz // read IMU data and convert to delta angles and velocities
//
// Read IMU data and convert to delta angles and velocities
readIMUData(); readIMUData();
// detect if the filter update has been delayed for too long
if (dtIMU > 0.2f) { if (dtIMU > 0.2f) {
// we have stalled for too long - reset states // we have stalled for too long - reset states
ResetVelocity(); ResetVelocity();
@ -516,14 +525,16 @@ void NavEKF::UpdateFilter()
StoreStatesReset(); StoreStatesReset();
//Initialise IMU pre-processing states //Initialise IMU pre-processing states
readIMUData(); readIMUData();
// stop the timer used for load measurement
perf_end(_perf_UpdateFilter); perf_end(_perf_UpdateFilter);
return; return;
} }
// Check if on ground // check if on ground
OnGroundCheck(); OnGroundCheck();
// Define rules used to set staticMode // define rules used to set staticMode
// staticMode enables ground operation without GPS by fusing zeros for position and height measurements
if (onGround && static_mode_demanded()) { if (onGround && static_mode_demanded()) {
staticMode = true; staticMode = true;
} else { } else {
@ -539,7 +550,7 @@ void NavEKF::UpdateFilter()
prevStaticMode = staticMode; prevStaticMode = staticMode;
} }
// Run the strapdown INS equations every IMU update // run the strapdown INS equations every IMU update
UpdateStrapdownEquationsNED(); UpdateStrapdownEquationsNED();
// store the predicted states for subsequent use by measurement fusion // store the predicted states for subsequent use by measurement fusion
@ -552,7 +563,6 @@ void NavEKF::UpdateFilter()
// perform a covariance prediction if the total delta angle has exceeded the limit // perform a covariance prediction if the total delta angle has exceeded the limit
// or the time limit will be exceeded at the next IMU update // or the time limit will be exceeded at the next IMU update
// Do not predict covariance if magnetometer fusion still needs to be performed
if (((dt >= (covTimeStepMax - dtIMU)) || (summedDelAng.length() > covDelAngMax))) { if (((dt >= (covTimeStepMax - dtIMU)) || (summedDelAng.length() > covDelAngMax))) {
CovariancePrediction(); CovariancePrediction();
covPredStep = true; covPredStep = true;
@ -568,24 +578,31 @@ void NavEKF::UpdateFilter()
SelectMagFusion(); SelectMagFusion();
SelectTasFusion(); SelectTasFusion();
// stop the timer used for load measurement
perf_end(_perf_UpdateFilter); perf_end(_perf_UpdateFilter);
} }
// select fusion of velocity, position and height measurements
void NavEKF::SelectVelPosFusion() void NavEKF::SelectVelPosFusion()
{ {
// Calculate ratio of VelPos fusion to state prediction setps // calculate ratio of VelPos fusion to state prediction steps
uint8_t velPosFuseStepRatio = floor(dtVelPos/dtIMU + 0.5f); uint8_t velPosFuseStepRatio = floor(dtVelPos/dtIMU + 0.5f);
// Calculate the scale factor to be applied to the measurement variance to account for // calculate the scale factor to be applied to GPS measurement variance to account for
// the fact we repeat fusion of the same measurement to provide a smoother output // the fact we repeat fusion of the same measurement to provide a smoother output
gpsVarScaler = _msecGpsAvg/(1000.0f*dtVelPos); gpsVarScaler = _msecGpsAvg/(1000.0f*dtVelPos);
// Calculate the scale factor to be applied to the measurement variance to account for
// calculate the scale factor to be applied to height measurement variance to account for
// the fact we repeat fusion of the same measurement to provide a smoother output // the fact we repeat fusion of the same measurement to provide a smoother output
hgtVarScaler = _msecHgtAvg/(1000.0f*dtVelPos); hgtVarScaler = _msecHgtAvg/(1000.0f*dtVelPos);
// check for new data, specify which measurements should be used and check data for freshness
if (!staticMode) { if (!staticMode) {
// Command fusion of GPS measurements if new ones available
// check for and read new GPS data
readGpsData(); readGpsData();
// command fusion of GPS data and reset states as required
if (newDataGps) { if (newDataGps) {
// reset data arrived flag // reset data arrived flag
newDataGps = false; newDataGps = false;
@ -607,10 +624,10 @@ void NavEKF::SelectVelPosFusion()
fusePosData = false; fusePosData = false;
} }
// Read height data // check for and read new height data
readHgtData(); readHgtData();
// Command fusion of height measurements if new ones available // command fusion of height data
if (newDataHgt) if (newDataHgt)
{ {
// reset data arrived flag // reset data arrived flag
@ -618,21 +635,21 @@ void NavEKF::SelectVelPosFusion()
// enable fusion // enable fusion
fuseHgtData = true; fuseHgtData = true;
} else if (hal.scheduler->millis() > lastHgtTime_ms + _msecHgtAvg + 40) { } else if (hal.scheduler->millis() > lastHgtTime_ms + _msecHgtAvg + 40) {
// Timeout fusion of height data if stale. Needed because we repeatedly fuse the same // timeout fusion of height data if stale. Needed because we repeatedly fuse the same
// measurement until the next one arrives to provide a smoother output // measurement until the next one arrives to provide a smoother output
fuseHgtData = false; fuseHgtData = false;
} }
} else { } else {
// we only fuse position and height in static mode // in static mode we only fuse position and height to improve long term numerical stability
fuseVelData = false; fuseVelData = false;
fusePosData = true; fusePosData = true;
fuseHgtData = true; fuseHgtData = true;
} }
// Perform fusion if conditions are met // perform fusion as commanded, and in accordance with specified time intervals
if (fuseVelData || fusePosData || fuseHgtData) { if (fuseVelData || fusePosData || fuseHgtData) {
// Skip fusion as required to maintain ~dtVelPos time interval between corrections // skip fusion as required to maintain ~dtVelPos time interval between corrections
if (skipCounter >= velPosFuseStepRatio) { if (skipCounter >= velPosFuseStepRatio) {
FuseVelPosNED(); FuseVelPosNED();
// reset counter used to skip update frames // reset counter used to skip update frames
@ -645,10 +662,13 @@ void NavEKF::SelectVelPosFusion()
} }
// select fusion of magnetometer data
void NavEKF::SelectMagFusion() void NavEKF::SelectMagFusion()
{ {
// check for and read new magnetometer measurements
readMagData(); readMagData();
// Fuse Magnetometer Measurements
// determine if conditions are right to start a new fusion cycle
bool dataReady = statesInitialised && useCompass && newDataMag; bool dataReady = statesInitialised && useCompass && newDataMag;
if (dataReady) if (dataReady)
{ {
@ -659,11 +679,13 @@ void NavEKF::SelectMagFusion()
{ {
fuseMagData = false; fuseMagData = false;
} }
// Magnetometer fusion is always called if enabled because its fusion is spread across 3 time steps to reduce peak load
// call the function that performs fusion of magnetometer data
FuseMagnetometer(); FuseMagnetometer();
} }
// select fusion of airspeed measurements
void NavEKF::SelectTasFusion() void NavEKF::SelectTasFusion()
{ {
readAirSpdData(); readAirSpdData();

View File

@ -1,6 +1,6 @@
/// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- /// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
/* /*
21 state EKF based on https://github.com/priseborough/InertialNav 22 state EKF based on https://github.com/priseborough/InertialNav
Converted from Matlab to C++ by Paul Riseborough Converted from Matlab to C++ by Paul Riseborough