Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve EKF core IMU failover logic - WIP #11139

Closed
wants to merge 12 commits into from

Conversation

jschall
Copy link
Contributor

@jschall jschall commented Apr 18, 2019

This patch

  • Only improves the IMU failover logic within an EKF core - it does not change the logic for EKF core switching
  • Moves the core IMU selection logic from AP_NavEKF_core to AP_NavEKF
  • Resets the IMU bias states and covariances when an EKF core switches IMUs
  • Uses the following logic to select a new accelerometer and gyro for an EKF core when its accelerometer and gyro become unhealthy:
    Try to find a paired gyro and accel that are both healthy w/ INS_USE=1 and configured to be used in EK2_IMU_MASK
    If that failed, try to find a paired gyro and accel that are both healthy w/ INS_USE=1
    If that failed, fall back on ins.get_primary_gyro and ins.get_primary_accel

TODO:

  • Implement for EKF3
  • Trigger a primary core change when the primary core's IMU becomes unhealthy - no change in functionality here
  • Implement switching back to the initial IMU if the initial IMU becomes healthy for some period of time
  • Pre-arm check for consistency between EK2_IMU_MASK and INS_USE*
  • SITL test for failed IMU

@tridge
Copy link
Contributor

tridge commented Apr 18, 2019

small issue. Resetting the biases means if we get a single-frame bad health on an IMU we lose all biases when we recover.

@jschall
Copy link
Contributor Author

jschall commented Apr 18, 2019

small issue. Resetting the biases means if we get a single-frame bad health on an IMU we lose all biases when we recover.

Actually, at the moment, it wouldn't "recover". The core would stay with the IMU we switched to, provided it remains healthy.

The EKF core could potentially store the current estimated gyro bias for each IMU and switch them rather than resetting.

if (ekf_type() != 0) {
return get_primary_IMU_index();
int8_t imu = -1;
switch (ekf_type()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be active_EKF_type() ? ie. if we are failed onto DCM in plane, then I think we shouldn't be asking the failed EKF which IMU to use

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, I didn't modify the function I copied.

@@ -1464,6 +1464,10 @@ void AP_InertialSensor::wait_for_sample(void)
*/
bool AP_InertialSensor::get_delta_angle(uint8_t i, Vector3f &delta_angle) const
{
if (i >= INS_MAX_INSTANCES) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be get_gyro_count() not INS_MAX_INSTANCES I think

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds wrong to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a minimum change as it moves the i < INS_MAX_INSTANCES check from the EKF into AP_InertialSensor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, never mind, it was checking get_accel_count. Are you sure that is correct? Why would get_accel_count and get_gyro_count be different? In the case where they are different, are the gyros and accels guaranteed to be assigned contiguous indices?

@@ -1481,6 +1485,10 @@ bool AP_InertialSensor::get_delta_angle(uint8_t i, Vector3f &delta_angle) const
*/
bool AP_InertialSensor::get_delta_velocity(uint8_t i, Vector3f &delta_velocity) const
{
if (i >= INS_MAX_INSTANCES) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be get_accel_count()

@@ -1497,7 +1505,7 @@ bool AP_InertialSensor::get_delta_velocity(uint8_t i, Vector3f &delta_velocity)
float AP_InertialSensor::get_delta_velocity_dt(uint8_t i) const
{
float ret;
if (_delta_velocity_valid[i]) {
if (i < INS_MAX_INSTANCES && _delta_velocity_valid[i]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_accel_count()

@@ -1512,7 +1520,7 @@ float AP_InertialSensor::get_delta_velocity_dt(uint8_t i) const
float AP_InertialSensor::get_delta_angle_dt(uint8_t i) const
{
float ret;
if (_delta_angle_valid[i] && _delta_angle_dt[i] > 0) {
if (i < INS_MAX_INSTANCES && _delta_angle_valid[i] && _delta_angle_dt[i] > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_gyro_count()

const AP_InertialSensor &ins = AP::ins();

if (ins_index < ins.get_gyro_count()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep bool return here

@@ -42,10 +42,11 @@ NavEKF2_core::NavEKF2_core(void) :
}

// setup this core backend
bool NavEKF2_core::setup_core(NavEKF2 *_frontend, uint8_t _imu_index, uint8_t _core_index)
bool NavEKF2_core::setup_core(NavEKF2 *_frontend, uint8_t _gyro_index, uint8_t _accel_index, uint8_t _core_index)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think changing setup_core() API is needed? the selections get overwritten anyway

{
if (gyro_index != _new_gyro_index) {
// NOTE: theoretically, we should wait until we reach the end of the IMU buffer prior to resetting these
stateStruct.gyro_bias.zero();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned about a very short IMU outage (1 ms timeout for example) causing biases to reset

P[13][13] = P[12][12];
P[14][14] = P[12][12];

gcs().send_text(MAV_SEVERITY_ERROR, "EKF2 %u (g%u a%u) switched to gyro %u", (unsigned)core_index, (unsigned)gyro_index, (unsigned)accel_index, _new_gyro_index);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to rate limit this msg I think

// Z delta velocity bias
P[15][15] = sq(INIT_ACCEL_BIAS_UNCERTAINTY * dtEkfAvg);

gcs().send_text(MAV_SEVERITY_ERROR, "EKF2 %u (g%u a%u) switched to accel %u", (unsigned)core_index, (unsigned)gyro_index, (unsigned)accel_index, _new_accel_index);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should zero accel biases, and we should rate limit the msg

@jschall
Copy link
Contributor Author

jschall commented Apr 18, 2019

I have pushed changes to switch EKF cores back to their original IMU if the original IMU becomes healthy. This required a change to AP_InertialSensor to remove latching of IMU health to false. Biases are now preserved (bias covariance is not).

@proficnc
Copy link
Contributor

proficnc commented Apr 19, 2019 via email

@priseborough
Copy link
Contributor

This has ended up modifying more lines of code inside the estimator than I originally envisioned would be necessary, so will need a bit longer to review the changes properly. It does however raise the question as to how this is going to be tested, otherwise we could be swapping an unknown bug for a known one.

@@ -485,4 +493,9 @@ class NavEKF2 {
// new_primary - index of the ekf instance that we are about to switch to as the primary
// old_primary - index of the ekf instance that we are currently using as the primary
void updateLaneSwitchPosDownResetData(uint8_t new_primary, uint8_t old_primary);

uint8_t core_initial_imu[8];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please make sure when adding new class variables that there is s description in the comments as per the rest of the code. As a minimum it should indicate what that block of variable is used for.

@tridge tridge added the WIP label May 6, 2019
@rmackay9 rmackay9 changed the title Improve EKF core IMU failover logic Improve EKF core IMU failover logic - WIP May 6, 2019
@tridge
Copy link
Contributor

tridge commented May 6, 2019

I think the work in here could still be merged with some work between Paul and Jon, marked as WIP

@tridge
Copy link
Contributor

tridge commented Aug 5, 2019

this has been obsoleted by other changes to master to address the same issue

@tridge tridge closed this Aug 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants