mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-05-31 18:47:21 +08:00
ekf2: selector improve status reporting
- publish estimator_selector_status at minimal rate or immediately on change - log all estimator_selector_status updates
This commit is contained in:
committed by
Lorenz Meier
parent
2fc212e064
commit
f73d93ef6c
@@ -69,12 +69,12 @@ void EKF2Selector::Stop()
|
|||||||
|
|
||||||
bool EKF2Selector::SelectInstance(uint8_t ekf_instance)
|
bool EKF2Selector::SelectInstance(uint8_t ekf_instance)
|
||||||
{
|
{
|
||||||
if (ekf_instance != _selected_instance) {
|
if ((ekf_instance != INVALID_INSTANCE) && (ekf_instance != _selected_instance)) {
|
||||||
|
|
||||||
// update sensor_selection immediately
|
// update sensor_selection immediately
|
||||||
sensor_selection_s sensor_selection{};
|
sensor_selection_s sensor_selection{};
|
||||||
sensor_selection.accel_device_id = _instance[ekf_instance].estimator_status.accel_device_id;
|
sensor_selection.accel_device_id = _instance[ekf_instance].status.accel_device_id;
|
||||||
sensor_selection.gyro_device_id = _instance[ekf_instance].estimator_status.gyro_device_id;
|
sensor_selection.gyro_device_id = _instance[ekf_instance].status.gyro_device_id;
|
||||||
sensor_selection.timestamp = hrt_absolute_time();
|
sensor_selection.timestamp = hrt_absolute_time();
|
||||||
_sensor_selection_pub.publish(sensor_selection);
|
_sensor_selection_pub.publish(sensor_selection);
|
||||||
|
|
||||||
@@ -84,7 +84,8 @@ bool EKF2Selector::SelectInstance(uint8_t ekf_instance)
|
|||||||
_instance[_selected_instance].estimator_status_sub.unregisterCallback();
|
_instance[_selected_instance].estimator_status_sub.unregisterCallback();
|
||||||
|
|
||||||
if (!_instance[_selected_instance].healthy) {
|
if (!_instance[_selected_instance].healthy) {
|
||||||
PX4_WARN("primary EKF changed %d (unhealthy) -> %d", _selected_instance, ekf_instance);
|
PX4_WARN("primary EKF changed %d (%s) -> %d", _selected_instance,
|
||||||
|
_instance[_selected_instance].filter_fault ? "filter fault" : "unhealthy", ekf_instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,9 +224,9 @@ bool EKF2Selector::UpdateErrorScores()
|
|||||||
for (uint8_t i = 0; i < EKF2_MAX_INSTANCES; i++) {
|
for (uint8_t i = 0; i < EKF2_MAX_INSTANCES; i++) {
|
||||||
const bool prev_healthy = _instance[i].healthy;
|
const bool prev_healthy = _instance[i].healthy;
|
||||||
|
|
||||||
const estimator_status_s &status = _instance[i].estimator_status;
|
const estimator_status_s &status = _instance[i].status;
|
||||||
|
|
||||||
if (_instance[i].estimator_status_sub.update(&_instance[i].estimator_status)) {
|
if (_instance[i].estimator_status_sub.update(&_instance[i].status)) {
|
||||||
|
|
||||||
if ((i + 1) > _available_instances) {
|
if ((i + 1) > _available_instances) {
|
||||||
_available_instances = i + 1;
|
_available_instances = i + 1;
|
||||||
@@ -248,12 +249,13 @@ bool EKF2Selector::UpdateErrorScores()
|
|||||||
|
|
||||||
_instance[i].combined_test_ratio = combined_test_ratio;
|
_instance[i].combined_test_ratio = combined_test_ratio;
|
||||||
_instance[i].healthy = tilt_align && yaw_align && (status.filter_fault_flags == 0);
|
_instance[i].healthy = tilt_align && yaw_align && (status.filter_fault_flags == 0);
|
||||||
|
_instance[i].filter_fault = (status.filter_fault_flags != 0);
|
||||||
|
|
||||||
if (!PX4_ISFINITE(_instance[i].relative_test_ratio)) {
|
if (!PX4_ISFINITE(_instance[i].relative_test_ratio)) {
|
||||||
_instance[i].relative_test_ratio = 0;
|
_instance[i].relative_test_ratio = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (hrt_elapsed_time(&status.timestamp) > 20_ms) {
|
} else if (hrt_elapsed_time(&status.timestamp) > (FILTER_UPDATE_PERIOD * 2)) {
|
||||||
_instance[i].healthy = false;
|
_instance[i].healthy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,6 +271,7 @@ bool EKF2Selector::UpdateErrorScores()
|
|||||||
|
|
||||||
if (prev_healthy != _instance[i].healthy) {
|
if (prev_healthy != _instance[i].healthy) {
|
||||||
updated = true;
|
updated = true;
|
||||||
|
_selector_status_publish = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,7 +391,7 @@ void EKF2Selector::PublishVehicleLocalPosition(bool reset)
|
|||||||
_local_position_last = local_position;
|
_local_position_last = local_position;
|
||||||
|
|
||||||
// publish estimator's local position for system (vehicle_local_position) unless it's stale
|
// publish estimator's local position for system (vehicle_local_position) unless it's stale
|
||||||
if (local_position.timestamp >= _instance[_selected_instance].estimator_status.timestamp_sample) {
|
if (local_position.timestamp >= _instance[_selected_instance].status.timestamp_sample) {
|
||||||
// republish with total reset count and current timestamp
|
// republish with total reset count and current timestamp
|
||||||
local_position.xy_reset_counter = _xy_reset_counter;
|
local_position.xy_reset_counter = _xy_reset_counter;
|
||||||
local_position.z_reset_counter = _z_reset_counter;
|
local_position.z_reset_counter = _z_reset_counter;
|
||||||
@@ -448,7 +451,7 @@ void EKF2Selector::PublishVehicleGlobalPosition(bool reset)
|
|||||||
_global_position_last = global_position;
|
_global_position_last = global_position;
|
||||||
|
|
||||||
// publish estimator's global position for system (vehicle_global_position) unless it's stale
|
// publish estimator's global position for system (vehicle_global_position) unless it's stale
|
||||||
if (global_position.timestamp >= _instance[_selected_instance].estimator_status.timestamp_sample) {
|
if (global_position.timestamp >= _instance[_selected_instance].status.timestamp_sample) {
|
||||||
// republish with total reset count and current timestamp
|
// republish with total reset count and current timestamp
|
||||||
global_position.lat_lon_reset_counter = _lat_lon_reset_counter;
|
global_position.lat_lon_reset_counter = _lat_lon_reset_counter;
|
||||||
global_position.alt_reset_counter = _alt_reset_counter;
|
global_position.alt_reset_counter = _alt_reset_counter;
|
||||||
@@ -463,7 +466,7 @@ void EKF2Selector::PublishVehicleGlobalPosition(bool reset)
|
|||||||
void EKF2Selector::Run()
|
void EKF2Selector::Run()
|
||||||
{
|
{
|
||||||
// re-schedule as backup timeout
|
// re-schedule as backup timeout
|
||||||
ScheduleDelayed(10_ms);
|
ScheduleDelayed(FILTER_UPDATE_PERIOD);
|
||||||
|
|
||||||
// check for parameter updates
|
// check for parameter updates
|
||||||
if (_parameter_update_sub.updated()) {
|
if (_parameter_update_sub.updated()) {
|
||||||
@@ -478,11 +481,11 @@ void EKF2Selector::Run()
|
|||||||
// update combined test ratio for all estimators
|
// update combined test ratio for all estimators
|
||||||
const bool updated = UpdateErrorScores();
|
const bool updated = UpdateErrorScores();
|
||||||
|
|
||||||
// if no valid instance selected then select instance with valid IMU
|
// if no valid instance then force select first instance with valid IMU
|
||||||
if (_selected_instance == INVALID_INSTANCE) {
|
if (_selected_instance == INVALID_INSTANCE) {
|
||||||
for (uint8_t i = 0; i < EKF2_MAX_INSTANCES; i++) {
|
for (uint8_t i = 0; i < EKF2_MAX_INSTANCES; i++) {
|
||||||
if ((_instance[i].estimator_status.accel_device_id != 0)
|
if ((_instance[i].status.accel_device_id != 0)
|
||||||
&& (_instance[i].estimator_status.gyro_device_id != 0)) {
|
&& (_instance[i].status.gyro_device_id != 0)) {
|
||||||
|
|
||||||
if (SelectInstance(i)) {
|
if (SelectInstance(i)) {
|
||||||
break;
|
break;
|
||||||
@@ -497,6 +500,12 @@ void EKF2Selector::Run()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (updated) {
|
if (updated) {
|
||||||
|
|
||||||
|
const uint8_t available_instances_prev = _available_instances;
|
||||||
|
const uint8_t selected_instance_prev = _selected_instance;
|
||||||
|
const uint32_t instance_changed_count_prev = _instance_changed_count;
|
||||||
|
const hrt_abstime last_instance_change_prev = _last_instance_change;
|
||||||
|
|
||||||
bool lower_error_available = false;
|
bool lower_error_available = false;
|
||||||
float alternative_error = 0.f; // looking for instances that have error lower than the current primary
|
float alternative_error = 0.f; // looking for instances that have error lower than the current primary
|
||||||
uint8_t best_ekf_instance = _selected_instance;
|
uint8_t best_ekf_instance = _selected_instance;
|
||||||
@@ -554,16 +563,23 @@ void EKF2Selector::Run()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish selector status
|
// publish selector status at ~1 Hz or immediately on any change
|
||||||
|
if (_selector_status_publish || (hrt_elapsed_time(&_last_status_publish) > 1_s)
|
||||||
|
|| (available_instances_prev != _available_instances)
|
||||||
|
|| (selected_instance_prev != _selected_instance)
|
||||||
|
|| (instance_changed_count_prev != _instance_changed_count)
|
||||||
|
|| (last_instance_change_prev != _last_instance_change)
|
||||||
|
|| _accel_fault_detected || _gyro_fault_detected) {
|
||||||
|
|
||||||
estimator_selector_status_s selector_status{};
|
estimator_selector_status_s selector_status{};
|
||||||
selector_status.primary_instance = _selected_instance;
|
selector_status.primary_instance = _selected_instance;
|
||||||
selector_status.instances_available = _available_instances;
|
selector_status.instances_available = _available_instances;
|
||||||
selector_status.instance_changed_count = _instance_changed_count;
|
selector_status.instance_changed_count = _instance_changed_count;
|
||||||
selector_status.last_instance_change = _last_instance_change;
|
selector_status.last_instance_change = _last_instance_change;
|
||||||
selector_status.accel_device_id = _instance[_selected_instance].estimator_status.accel_device_id;
|
selector_status.accel_device_id = _instance[_selected_instance].status.accel_device_id;
|
||||||
selector_status.baro_device_id = _instance[_selected_instance].estimator_status.baro_device_id;
|
selector_status.baro_device_id = _instance[_selected_instance].status.baro_device_id;
|
||||||
selector_status.gyro_device_id = _instance[_selected_instance].estimator_status.gyro_device_id;
|
selector_status.gyro_device_id = _instance[_selected_instance].status.gyro_device_id;
|
||||||
selector_status.mag_device_id = _instance[_selected_instance].estimator_status.mag_device_id;
|
selector_status.mag_device_id = _instance[_selected_instance].status.mag_device_id;
|
||||||
selector_status.gyro_fault_detected = _gyro_fault_detected;
|
selector_status.gyro_fault_detected = _gyro_fault_detected;
|
||||||
selector_status.accel_fault_detected = _accel_fault_detected;
|
selector_status.accel_fault_detected = _accel_fault_detected;
|
||||||
|
|
||||||
@@ -580,10 +596,13 @@ void EKF2Selector::Run()
|
|||||||
|
|
||||||
selector_status.timestamp = hrt_absolute_time();
|
selector_status.timestamp = hrt_absolute_time();
|
||||||
_estimator_selector_status_pub.publish(selector_status);
|
_estimator_selector_status_pub.publish(selector_status);
|
||||||
|
_last_status_publish = selector_status.timestamp;
|
||||||
|
_selector_status_publish = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// republish selected estimator data for system
|
// republish selected estimator data for system
|
||||||
if (_selected_instance != INVALID_INSTANCE) {
|
|
||||||
// selected estimator_attitude -> vehicle_attitude
|
// selected estimator_attitude -> vehicle_attitude
|
||||||
if (_instance[_selected_instance].estimator_attitude_sub.updated()) {
|
if (_instance[_selected_instance].estimator_attitude_sub.updated()) {
|
||||||
PublishVehicleAttitude();
|
PublishVehicleAttitude();
|
||||||
@@ -604,14 +623,13 @@ void EKF2Selector::Run()
|
|||||||
vehicle_odometry_s vehicle_odometry;
|
vehicle_odometry_s vehicle_odometry;
|
||||||
|
|
||||||
if (_instance[_selected_instance].estimator_odometry_sub.update(&vehicle_odometry)) {
|
if (_instance[_selected_instance].estimator_odometry_sub.update(&vehicle_odometry)) {
|
||||||
if (vehicle_odometry.timestamp >= _instance[_selected_instance].estimator_status.timestamp_sample) {
|
if (vehicle_odometry.timestamp >= _instance[_selected_instance].status.timestamp_sample) {
|
||||||
vehicle_odometry.timestamp = hrt_absolute_time();
|
vehicle_odometry.timestamp = hrt_absolute_time();
|
||||||
_vehicle_odometry_pub.publish(vehicle_odometry);
|
_vehicle_odometry_pub.publish(vehicle_odometry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void EKF2Selector::PrintStatus()
|
void EKF2Selector::PrintStatus()
|
||||||
{
|
{
|
||||||
@@ -625,8 +643,8 @@ void EKF2Selector::PrintStatus()
|
|||||||
const EstimatorInstance &inst = _instance[i];
|
const EstimatorInstance &inst = _instance[i];
|
||||||
|
|
||||||
PX4_INFO("%d: ACC: %d, GYRO: %d, MAG: %d, %s, test ratio: %.7f (%.5f) %s",
|
PX4_INFO("%d: ACC: %d, GYRO: %d, MAG: %d, %s, test ratio: %.7f (%.5f) %s",
|
||||||
inst.instance, inst.estimator_status.accel_device_id, inst.estimator_status.gyro_device_id,
|
inst.instance, inst.status.accel_device_id, inst.status.gyro_device_id,
|
||||||
inst.estimator_status.mag_device_id,
|
inst.status.mag_device_id,
|
||||||
inst.healthy ? "healthy" : "unhealthy",
|
inst.healthy ? "healthy" : "unhealthy",
|
||||||
(double)inst.combined_test_ratio, (double)inst.relative_test_ratio,
|
(double)inst.combined_test_ratio, (double)inst.relative_test_ratio,
|
||||||
(_selected_instance == i) ? "*" : "");
|
(_selected_instance == i) ? "*" : "");
|
||||||
|
|||||||
@@ -56,6 +56,8 @@
|
|||||||
static constexpr uint8_t EKF2_MAX_INSTANCES{9};
|
static constexpr uint8_t EKF2_MAX_INSTANCES{9};
|
||||||
static_assert(EKF2_MAX_INSTANCES <= ORB_MULTI_MAX_INSTANCES, "EKF2_MAX_INSTANCES must be <= ORB_MULTI_MAX_INSTANCES");
|
static_assert(EKF2_MAX_INSTANCES <= ORB_MULTI_MAX_INSTANCES, "EKF2_MAX_INSTANCES must be <= ORB_MULTI_MAX_INSTANCES");
|
||||||
|
|
||||||
|
using namespace time_literals;
|
||||||
|
|
||||||
class EKF2Selector : public ModuleParams, public px4::ScheduledWorkItem
|
class EKF2Selector : public ModuleParams, public px4::ScheduledWorkItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -68,7 +70,9 @@ public:
|
|||||||
void PrintStatus();
|
void PrintStatus();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint8_t INVALID_INSTANCE = UINT8_MAX;
|
static constexpr uint8_t INVALID_INSTANCE{UINT8_MAX};
|
||||||
|
static constexpr uint64_t FILTER_UPDATE_PERIOD{10_ms};
|
||||||
|
|
||||||
void Run() override;
|
void Run() override;
|
||||||
void PublishVehicleAttitude(bool reset = false);
|
void PublishVehicleAttitude(bool reset = false);
|
||||||
void PublishVehicleLocalPosition(bool reset = false);
|
void PublishVehicleLocalPosition(bool reset = false);
|
||||||
@@ -96,7 +100,7 @@ private:
|
|||||||
uORB::Subscription estimator_global_position_sub;
|
uORB::Subscription estimator_global_position_sub;
|
||||||
uORB::Subscription estimator_odometry_sub;
|
uORB::Subscription estimator_odometry_sub;
|
||||||
|
|
||||||
estimator_status_s estimator_status{};
|
estimator_status_s status{};
|
||||||
|
|
||||||
hrt_abstime time_last_selected{0};
|
hrt_abstime time_last_selected{0};
|
||||||
|
|
||||||
@@ -104,6 +108,7 @@ private:
|
|||||||
float relative_test_ratio{NAN};
|
float relative_test_ratio{NAN};
|
||||||
|
|
||||||
bool healthy{false};
|
bool healthy{false};
|
||||||
|
bool filter_fault{false};
|
||||||
|
|
||||||
const uint8_t instance;
|
const uint8_t instance;
|
||||||
};
|
};
|
||||||
@@ -147,6 +152,9 @@ private:
|
|||||||
uint32_t _instance_changed_count{0};
|
uint32_t _instance_changed_count{0};
|
||||||
hrt_abstime _last_instance_change{0};
|
hrt_abstime _last_instance_change{0};
|
||||||
|
|
||||||
|
hrt_abstime _last_status_publish{0};
|
||||||
|
bool _selector_status_publish{false};
|
||||||
|
|
||||||
// vehicle_attitude: reset counters
|
// vehicle_attitude: reset counters
|
||||||
vehicle_attitude_s _attitude_last{};
|
vehicle_attitude_s _attitude_last{};
|
||||||
matrix::Quatf _delta_q_reset{};
|
matrix::Quatf _delta_q_reset{};
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ void LoggedTopics::add_default_topics()
|
|||||||
|
|
||||||
// EKF multi topics (currently max 9 estimators)
|
// EKF multi topics (currently max 9 estimators)
|
||||||
static constexpr uint8_t MAX_ESTIMATOR_INSTANCES = 4;
|
static constexpr uint8_t MAX_ESTIMATOR_INSTANCES = 4;
|
||||||
add_topic("estimator_selector_status", 200);
|
add_topic("estimator_selector_status");
|
||||||
add_topic_multi("ekf_gps_drift", 1000, MAX_ESTIMATOR_INSTANCES);
|
add_topic_multi("ekf_gps_drift", 1000, MAX_ESTIMATOR_INSTANCES);
|
||||||
add_topic_multi("estimator_attitude", 500, MAX_ESTIMATOR_INSTANCES);
|
add_topic_multi("estimator_attitude", 500, MAX_ESTIMATOR_INSTANCES);
|
||||||
add_topic_multi("estimator_global_position", 1000, MAX_ESTIMATOR_INSTANCES);
|
add_topic_multi("estimator_global_position", 1000, MAX_ESTIMATOR_INSTANCES);
|
||||||
|
|||||||
Reference in New Issue
Block a user