diff --git a/src/modules/ekf2/EKF2.cpp b/src/modules/ekf2/EKF2.cpp index fe62cdf0b3..be1dfe6762 100644 --- a/src/modules/ekf2/EKF2.cpp +++ b/src/modules/ekf2/EKF2.cpp @@ -1557,10 +1557,10 @@ int EKF2::task_spawn(int argc, char *argv[]) if (inst) { _ekf2_selector.store(inst); - inst->Start(); } else { - PX4_ERR("Failed to start EKF2 selector"); + PX4_ERR("Failed to create EKF2 selector"); + return PX4_ERROR; } } @@ -1604,6 +1604,7 @@ int EKF2::task_spawn(int argc, char *argv[]) ekf2_inst->ScheduleNow(); success = true; multi_instances_allocated++; + _ekf2_selector.load()->ScheduleNow(); } else { PX4_ERR("instance %d alloc failed", instance); diff --git a/src/modules/ekf2/EKF2Selector.cpp b/src/modules/ekf2/EKF2Selector.cpp index d1991cba25..1b1b2b7832 100644 --- a/src/modules/ekf2/EKF2Selector.cpp +++ b/src/modules/ekf2/EKF2Selector.cpp @@ -55,20 +55,7 @@ EKF2Selector::~EKF2Selector() bool EKF2Selector::Start() { - // default to first instance - _selected_instance = 0; - - if (!_instance[0].estimator_status_sub.registerCallback()) { - PX4_ERR("estimator status callback registration failed"); - } - - if (!_instance[0].estimator_attitude_sub.registerCallback()) { - PX4_ERR("estimator attitude callback registration failed"); - } - - // backup schedule - ScheduleDelayed(10_ms); - + ScheduleNow(); return true; } @@ -82,7 +69,7 @@ void EKF2Selector::Stop() ScheduleClear(); } -void EKF2Selector::SelectInstance(uint8_t ekf_instance) +bool EKF2Selector::SelectInstance(uint8_t ekf_instance) { if (ekf_instance != _selected_instance) { @@ -112,21 +99,23 @@ void EKF2Selector::SelectInstance(uint8_t ekf_instance) _instance[ekf_instance].time_last_selected = _last_instance_change; // reset all relative test ratios - for (auto &inst : _instance) { - inst.relative_test_ratio = 0; + for (uint8_t i = 0; i < _available_instances; i++) { + _instance[i].relative_test_ratio = 0; } // publish new data immediately with resets PublishVehicleAttitude(true); PublishVehicleLocalPosition(true); PublishVehicleGlobalPosition(true); + + return true; } + + return false; } bool EKF2Selector::UpdateErrorScores() { - bool updated = false; - // first check imu inconsistencies _gyro_fault_detected = false; uint32_t faulty_gyro_id = 0; @@ -137,97 +126,107 @@ bool EKF2Selector::UpdateErrorScores() sensors_status_imu_s sensors_status_imu; if (_sensors_status_imu.copy(&sensors_status_imu)) { - const float angle_rate_threshold = radians(_param_ekf2_sel_imu_angle_rate.get()); - const float angle_threshold = radians(_param_ekf2_sel_imu_angle.get()); - const float accel_threshold = _param_ekf2_sel_imu_accel.get(); - const float velocity_threshold = _param_ekf2_sel_imu_velocity.get(); + const float time_step_s = constrain((sensors_status_imu.timestamp - _last_update_us) * 1e-6f, 0.f, 0.02f); _last_update_us = sensors_status_imu.timestamp; - uint8_t n_gyros = 0; - uint8_t n_accels = 0; - uint8_t n_gyro_exceedances = 0; - uint8_t n_accel_exceedances = 0; - float largest_accumulated_gyro_error = 0.0f; - float largest_accumulated_accel_error = 0.0f; - uint8_t largest_gyro_error_index = 0; - uint8_t largest_accel_error_index = 0; - - for (unsigned i = 0; i < IMU_STATUS_SIZE; i++) { - // check for gyros with excessive difference to mean using accumulated error - if (sensors_status_imu.gyro_device_ids[i] != 0) { - n_gyros++; - _accumulated_gyro_error[i] += (sensors_status_imu.gyro_inconsistency_rad_s[i] - angle_rate_threshold) * time_step_s; - _accumulated_gyro_error[i] = fmaxf(_accumulated_gyro_error[i], 0.f); - - if (_accumulated_gyro_error[i] > angle_threshold) { - n_gyro_exceedances++; - } - - if (_accumulated_gyro_error[i] > largest_accumulated_gyro_error) { - largest_accumulated_gyro_error = _accumulated_gyro_error[i]; - largest_gyro_error_index = i; + { + const float angle_rate_threshold = radians(_param_ekf2_sel_imu_angle_rate.get()); + const float angle_threshold = radians(_param_ekf2_sel_imu_angle.get()); + uint8_t n_gyros = 0; + uint8_t n_gyro_exceedances = 0; + float largest_accumulated_gyro_error = 0.0f; + uint8_t largest_gyro_error_index = 0; + + for (unsigned i = 0; i < IMU_STATUS_SIZE; i++) { + // check for gyros with excessive difference to mean using accumulated error + if (sensors_status_imu.gyro_device_ids[i] != 0) { + n_gyros++; + _accumulated_gyro_error[i] += (sensors_status_imu.gyro_inconsistency_rad_s[i] - angle_rate_threshold) * time_step_s; + _accumulated_gyro_error[i] = fmaxf(_accumulated_gyro_error[i], 0.f); + + if (_accumulated_gyro_error[i] > angle_threshold) { + n_gyro_exceedances++; + } + + if (_accumulated_gyro_error[i] > largest_accumulated_gyro_error) { + largest_accumulated_gyro_error = _accumulated_gyro_error[i]; + largest_gyro_error_index = i; + } + + } else { + // no sensor + _accumulated_gyro_error[i] = NAN; } - - } else { - // no sensor - _accumulated_gyro_error[i] = 0.f; } - // check for accelerometers with excessive difference to mean using accumulated error - if (sensors_status_imu.accel_device_ids[i] != 0) { - n_accels++; - _accumulated_accel_error[i] += (sensors_status_imu.accel_inconsistency_m_s_s[i] - accel_threshold) * time_step_s; - _accumulated_accel_error[i] = fmaxf(_accumulated_accel_error[i], 0.f); - - if (_accumulated_accel_error[i] > velocity_threshold) { - n_accel_exceedances++; - } + if (n_gyro_exceedances > 0) { + if (n_gyros >= 3) { + // If there are 3 or more sensors, the one with the largest accumulated error is faulty + _gyro_fault_detected = true; + faulty_gyro_id = sensors_status_imu.gyro_device_ids[largest_gyro_error_index]; - if (_accumulated_accel_error[i] > largest_accumulated_accel_error) { - largest_accumulated_accel_error = _accumulated_accel_error[i]; - largest_accel_error_index = i; + } else if (n_gyros == 2) { + // A fault is present, but the faulty sensor identity cannot be determined + _gyro_fault_detected = true; } - - } else { - // no sensor - _accumulated_accel_error[i] = 0.f; } } - if (n_gyro_exceedances > 0) { - if (n_gyros >= 3) { - // If there are 3 or more sensors, the one with the largest accumulated error is faulty - _gyro_fault_detected = true; - faulty_gyro_id = _instance[largest_gyro_error_index].estimator_status.gyro_device_id; - - } else if (n_gyros == 2) { - // A fault is present, but the faulty sensor identity cannot be determined - _gyro_fault_detected = true; + { + const float accel_threshold = _param_ekf2_sel_imu_accel.get(); + const float velocity_threshold = _param_ekf2_sel_imu_velocity.get(); + uint8_t n_accels = 0; + uint8_t n_accel_exceedances = 0; + float largest_accumulated_accel_error = 0.0f; + uint8_t largest_accel_error_index = 0; + + for (unsigned i = 0; i < IMU_STATUS_SIZE; i++) { + // check for accelerometers with excessive difference to mean using accumulated error + if (sensors_status_imu.accel_device_ids[i] != 0) { + n_accels++; + _accumulated_accel_error[i] += (sensors_status_imu.accel_inconsistency_m_s_s[i] - accel_threshold) * time_step_s; + _accumulated_accel_error[i] = fmaxf(_accumulated_accel_error[i], 0.f); + + if (_accumulated_accel_error[i] > velocity_threshold) { + n_accel_exceedances++; + } + + if (_accumulated_accel_error[i] > largest_accumulated_accel_error) { + largest_accumulated_accel_error = _accumulated_accel_error[i]; + largest_accel_error_index = i; + } + + } else { + // no sensor + _accumulated_accel_error[i] = NAN; + } } - } - if (n_accel_exceedances > 0) { - if (n_accels >= 3) { - // If there are 3 or more sensors, the one with the largest accumulated error is faulty - _accel_fault_detected = true; - faulty_accel_id = _instance[largest_accel_error_index].estimator_status.accel_device_id; + if (n_accel_exceedances > 0) { + if (n_accels >= 3) { + // If there are 3 or more sensors, the one with the largest accumulated error is faulty + _accel_fault_detected = true; + faulty_accel_id = sensors_status_imu.accel_device_ids[largest_accel_error_index]; - } else if (n_accels == 2) { - // A fault is present, but the faulty sensor identity cannot be determined - _accel_fault_detected = true; + } else if (n_accels == 2) { + // A fault is present, but the faulty sensor identity cannot be determined + _accel_fault_detected = true; + } } } } } - + bool updated = false; bool primary_updated = false; // calculate individual error scores for (uint8_t i = 0; i < EKF2_MAX_INSTANCES; i++) { const bool prev_healthy = _instance[i].healthy; + const estimator_status_s &status = _instance[i].estimator_status; + if (_instance[i].estimator_status_sub.update(&_instance[i].estimator_status)) { if ((i + 1) > _available_instances) { @@ -239,32 +238,34 @@ bool EKF2Selector::UpdateErrorScores() primary_updated = true; } - const estimator_status_s &status = _instance[i].estimator_status; - const bool tilt_align = status.control_mode_flags & (1 << estimator_status_s::CS_TILT_ALIGN); const bool yaw_align = status.control_mode_flags & (1 << estimator_status_s::CS_YAW_ALIGN); - _instance[i].combined_test_ratio = 0.0f; + float combined_test_ratio = 0; if (tilt_align && yaw_align) { - _instance[i].combined_test_ratio = fmaxf(_instance[i].combined_test_ratio, - 0.5f * (status.vel_test_ratio + status.pos_test_ratio)); - _instance[i].combined_test_ratio = fmaxf(_instance[i].combined_test_ratio, status.hgt_test_ratio); + combined_test_ratio = fmaxf(0.f, 0.5f * (status.vel_test_ratio + status.pos_test_ratio)); + combined_test_ratio = fmaxf(combined_test_ratio, status.hgt_test_ratio); } + _instance[i].combined_test_ratio = combined_test_ratio; _instance[i].healthy = tilt_align && yaw_align && (status.filter_fault_flags == 0); - } else if (hrt_elapsed_time(&_instance[i].estimator_status.timestamp) > 20_ms) { + if (!PX4_ISFINITE(_instance[i].relative_test_ratio)) { + _instance[i].relative_test_ratio = 0; + } + + } else if (hrt_elapsed_time(&status.timestamp) > 20_ms) { _instance[i].healthy = false; } // if the gyro used by the EKF is faulty, declare the EKF unhealthy without delay - if (_gyro_fault_detected && _instance[i].estimator_status.gyro_device_id == faulty_gyro_id) { + if (_gyro_fault_detected && (faulty_gyro_id != 0) && (status.gyro_device_id == faulty_gyro_id)) { _instance[i].healthy = false; } // if the accelerometer used by the EKF is faulty, declare the EKF unhealthy without delay - if (_accel_fault_detected && _instance[i].estimator_status.accel_device_id == faulty_accel_id) { + if (_accel_fault_detected && (faulty_accel_id != 0) && (status.accel_device_id == faulty_accel_id)) { _instance[i].healthy = false; } @@ -484,6 +485,24 @@ void EKF2Selector::Run() // update combined test ratio for all estimators const bool updated = UpdateErrorScores(); + // if no valid instance selected then select instance with valid IMU + if (_selected_instance == INVALID_INSTANCE) { + for (uint8_t i = 0; i < EKF2_MAX_INSTANCES; i++) { + if ((_instance[i].estimator_status.accel_device_id != 0) + && (_instance[i].estimator_status.gyro_device_id != 0)) { + + if (SelectInstance(i)) { + break; + } + } + } + + // if still invalid return early and check again on next scheduled run + if (_selected_instance == INVALID_INSTANCE) { + return; + } + } + if (updated) { bool lower_error_available = false; float alternative_error = 0.f; // looking for instances that have error lower than the current primary @@ -513,10 +532,8 @@ void EKF2Selector::Run() } } - if ((_selected_instance == INVALID_INSTANCE) - || (!_instance[_selected_instance].healthy && (best_ekf_instance == _selected_instance))) { - - // force initial selection + if (!_instance[_selected_instance].healthy && (best_ekf_instance == _selected_instance)) { + // force selection to best healthy instance uint8_t best_instance = _selected_instance; float best_test_ratio = FLT_MAX; diff --git a/src/modules/ekf2/EKF2Selector.hpp b/src/modules/ekf2/EKF2Selector.hpp index 61c4f40e1c..d402bf2164 100644 --- a/src/modules/ekf2/EKF2Selector.hpp +++ b/src/modules/ekf2/EKF2Selector.hpp @@ -73,7 +73,7 @@ private: void PublishVehicleAttitude(bool reset = false); void PublishVehicleLocalPosition(bool reset = false); void PublishVehicleGlobalPosition(bool reset = false); - void SelectInstance(uint8_t instance); + bool SelectInstance(uint8_t instance); // Update the error scores for all available instances bool UpdateErrorScores(); @@ -100,8 +100,8 @@ private: hrt_abstime time_last_selected{0}; - float combined_test_ratio{0.f}; - float relative_test_ratio{0.f}; + float combined_test_ratio{NAN}; + float relative_test_ratio{NAN}; bool healthy{false};