AirspeedSelector: airspeed scale estimation improvements and robustification

- run airspeed scale estimation always, not in dedicated mode
- add option to apply scale automatically, with extra feasibility check
- add airspeed scale for all 3 possible airspeed instances
- clean up parameters
- add check for data stuck (non-changing airspeed data)

Signed-off-by: Silvan Fuhrer <silvan@auterion.com>
This commit is contained in:
Silvan Fuhrer
2021-10-11 15:05:27 +02:00
parent 8e8c6efd66
commit 625f556b0e
7 changed files with 286 additions and 130 deletions
@@ -1,6 +1,6 @@
/****************************************************************************
*
* Copyright (c) 2018 PX4 Development Team. All rights reserved.
* Copyright (c) 2018-2021 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -149,13 +149,14 @@ private:
bool _in_takeoff_situation{true}; /**< in takeoff situation (defined as not yet stall speed reached) */
float _ground_minus_wind_TAS{0.0f}; /**< true airspeed from groundspeed minus windspeed */
float _ground_minus_wind_CAS{0.0f}; /**< calibrated airspeed from groundspeed minus windspeed */
bool _scale_estimation_previously_on{false}; /**< scale_estimation was on in the last cycle */
bool _armed_prev{false};
hrt_abstime _time_last_airspeed_update[MAX_NUM_AIRSPEED_SENSORS] {};
perf_counter_t _perf_elapsed{};
float _param_airspeed_scale[MAX_NUM_AIRSPEED_SENSORS] {}; /** array to save the airspeed scale params in */
DEFINE_PARAMETERS(
(ParamFloat<px4::params::ASPD_W_P_NOISE>) _param_west_w_p_noise,
(ParamFloat<px4::params::ASPD_SC_P_NOISE>) _param_west_sc_p_noise,
@@ -163,8 +164,10 @@ private:
(ParamFloat<px4::params::ASPD_BETA_NOISE>) _param_west_beta_noise,
(ParamInt<px4::params::ASPD_TAS_GATE>) _param_west_tas_gate,
(ParamInt<px4::params::ASPD_BETA_GATE>) _param_west_beta_gate,
(ParamInt<px4::params::ASPD_SCALE_EST>) _param_west_scale_estimation_on,
(ParamFloat<px4::params::ASPD_SCALE>) _param_west_airspeed_scale,
(ParamInt<px4::params::ASPD_SCALE_APPLY>) _param_aspd_scale_apply,
(ParamFloat<px4::params::ASPD_SCALE_1>) _param_airspeed_scale_1,
(ParamFloat<px4::params::ASPD_SCALE_2>) _param_airspeed_scale_2,
(ParamFloat<px4::params::ASPD_SCALE_3>) _param_airspeed_scale_3,
(ParamInt<px4::params::ASPD_PRIMARY>) _param_airspeed_primary_index,
(ParamInt<px4::params::ASPD_DO_CHECKS>) _param_airspeed_checks_on,
(ParamInt<px4::params::ASPD_FALLBACK_GW>) _param_airspeed_fallback_gw,
@@ -291,6 +294,12 @@ AirspeedModule::Run()
if (!_initialized) {
init(); // initialize airspeed validator instances
for (int i = 0; i < MAX_NUM_AIRSPEED_SENSORS; i++) {
_airspeed_validator[i].set_CAS_scale_estimated(_param_airspeed_scale[i]);
_airspeed_validator[i].set_scale_init(_param_airspeed_scale[i]);
}
_initialized = true;
}
@@ -300,7 +309,7 @@ AirspeedModule::Run()
update_params();
}
bool armed = (_vehicle_status.arming_state == vehicle_status_s::ARMING_STATE_ARMED);
const bool armed = (_vehicle_status.arming_state == vehicle_status_s::ARMING_STATE_ARMED);
// check for new connected airspeed sensors as long as we're disarmed
if (!armed) {
@@ -375,11 +384,44 @@ AirspeedModule::Run()
_airspeed_validator[i].reset_airspeed_to_invalid(_time_now_usec);
}
// save estimated airspeed scale after disarm
if (!armed && _armed_prev) {
if (_param_aspd_scale_apply.get() > 1) {
if (fabsf(_airspeed_validator[i].get_CAS_scale_estimated() - _param_airspeed_scale[i]) > 0.01f) {
// apply the new scale if changed more than 0.01
mavlink_log_info(&_mavlink_log_pub, "Airspeed sensor Nr. %d ASPD_SCALE updated: %.2f --> %.2f", i + 1,
(double)_param_airspeed_scale[i],
(double)_airspeed_validator[i].get_CAS_scale_estimated());
switch (i) {
case 0:
_param_airspeed_scale_1.set(_airspeed_validator[i].get_CAS_scale_estimated());
_param_airspeed_scale_1.commit_no_notification();
break;
case 1:
_param_airspeed_scale_2.set(_airspeed_validator[i].get_CAS_scale_estimated());
_param_airspeed_scale_2.commit_no_notification();
break;
case 2:
_param_airspeed_scale_3.set(_airspeed_validator[i].get_CAS_scale_estimated());
_param_airspeed_scale_3.commit_no_notification();
break;
}
}
}
_airspeed_validator[i].set_scale_init(_param_airspeed_scale[i]);
}
}
}
select_airspeed_and_publish();
_armed_prev = armed;
perf_end(_perf_elapsed);
if (should_exit()) {
@@ -391,6 +433,10 @@ void AirspeedModule::update_params()
{
updateParams();
_param_airspeed_scale[0] = _param_airspeed_scale_1.get();
_param_airspeed_scale[1] = _param_airspeed_scale_2.get();
_param_airspeed_scale[2] = _param_airspeed_scale_3.get();
_wind_estimator_sideslip.set_wind_p_noise(_param_west_w_p_noise.get());
_wind_estimator_sideslip.set_tas_scale_p_noise(_param_west_sc_p_noise.get());
_wind_estimator_sideslip.set_tas_noise(_param_west_tas_noise.get());
@@ -398,62 +444,24 @@ void AirspeedModule::update_params()
_wind_estimator_sideslip.set_tas_gate(_param_west_tas_gate.get());
_wind_estimator_sideslip.set_beta_gate(_param_west_beta_gate.get());
for (int i = 0; i < _number_of_airspeed_sensors; i++) {
for (int i = 0; i < MAX_NUM_AIRSPEED_SENSORS; i++) {
_airspeed_validator[i].set_wind_estimator_wind_p_noise(_param_west_w_p_noise.get());
_airspeed_validator[i].set_wind_estimator_tas_scale_p_noise(_param_west_sc_p_noise.get());
_airspeed_validator[i].set_wind_estimator_tas_noise(_param_west_tas_noise.get());
_airspeed_validator[i].set_wind_estimator_beta_noise(_param_west_beta_noise.get());
_airspeed_validator[i].set_wind_estimator_tas_gate(_param_west_tas_gate.get());
_airspeed_validator[i].set_wind_estimator_beta_gate(_param_west_beta_gate.get());
_airspeed_validator[i].set_wind_estimator_scale_estimation_on(_param_west_scale_estimation_on.get());
// only apply manual entered airspeed scale to first airspeed measurement
// TODO: enable multiple airspeed sensors
_airspeed_validator[0].set_airspeed_scale_manual(_param_west_airspeed_scale.get());
_airspeed_validator[i].set_tas_scale_apply(_param_aspd_scale_apply.get());
_airspeed_validator[i].set_wind_estimator_tas_scale_init(_param_airspeed_scale[i]);
_airspeed_validator[i].set_tas_innov_threshold(_tas_innov_threshold.get());
_airspeed_validator[i].set_tas_innov_integ_threshold(_tas_innov_integ_threshold.get());
_airspeed_validator[i].set_checks_fail_delay(_checks_fail_delay.get());
_airspeed_validator[i].set_checks_clear_delay(_checks_clear_delay.get());
_airspeed_validator[i].set_airspeed_stall(_param_fw_airspd_stall.get());
_airspeed_validator[i].set_disable_tas_scale_estimate(_param_aspd_scale_apply.get() == 0);
}
// if the airspeed scale estimation is enabled and the airspeed is valid,
// then set the scale inside the wind estimator to -1 such that it starts to estimate it
if (!_scale_estimation_previously_on && _param_west_scale_estimation_on.get()) {
if (_valid_airspeed_index > 0) {
// set it to a negative value to start estimation inside wind estimator
_airspeed_validator[0].set_airspeed_scale_manual(-1.0f);
} else {
mavlink_log_info(&_mavlink_log_pub, "Airspeed: can't estimate scale as no valid sensor.\t");
events::send(events::ID("airspeed_selector_cannot_est_scale"), events::Log::Error,
"Airspeed: cannot estimate scale as there is no valid sensor");
_param_west_scale_estimation_on.set(0); // reset this param to 0 as estimation was not turned on
_param_west_scale_estimation_on.commit_no_notification();
}
} else if (_scale_estimation_previously_on && !_param_west_scale_estimation_on.get()) {
if (_valid_airspeed_index > 0) {
_param_west_airspeed_scale.set(_airspeed_validator[_valid_airspeed_index - 1].get_CAS_scale());
_param_west_airspeed_scale.commit_no_notification();
_airspeed_validator[_valid_airspeed_index - 1].set_airspeed_scale_manual(_param_west_airspeed_scale.get());
mavlink_log_info(&_mavlink_log_pub, "Airspeed: estimated scale (ASPD_SCALE): %0.2f\t",
(double)_airspeed_validator[_valid_airspeed_index - 1].get_CAS_scale());
events::send<float>(events::ID("airspeed_selector_scale"), events::Log::Info,
"Airspeed: estimated scale (ASPD_SCALE): {1:.2}", _airspeed_validator[_valid_airspeed_index - 1].get_CAS_scale());
} else {
mavlink_log_info(&_mavlink_log_pub, "Airspeed: can't estimate scale as no valid sensor.\t");
events::send(events::ID("airspeed_selector_cannot_est_scale2"), events::Log::Error,
"Airspeed: cannot estimate scale as there is no valid sensor");
}
}
_scale_estimation_previously_on = _param_west_scale_estimation_on.get();
}
void AirspeedModule::poll_topics()
@@ -505,11 +513,12 @@ void AirspeedModule::update_wind_estimator_sideslip()
_wind_estimator_sideslip.get_wind_var(wind_cov);
_wind_estimate_sideslip.variance_north = wind_cov[0];
_wind_estimate_sideslip.variance_east = wind_cov[1];
_wind_estimate_sideslip.tas_innov = _wind_estimator_sideslip.get_tas_innov();
_wind_estimate_sideslip.tas_innov_var = _wind_estimator_sideslip.get_tas_innov_var();
_wind_estimate_sideslip.tas_innov = NAN;
_wind_estimate_sideslip.tas_innov_var = NAN;
_wind_estimate_sideslip.beta_innov = _wind_estimator_sideslip.get_beta_innov();
_wind_estimate_sideslip.beta_innov_var = _wind_estimator_sideslip.get_beta_innov_var();
_wind_estimate_sideslip.tas_scale = _wind_estimator_sideslip.get_tas_scale();
_wind_estimate_sideslip.tas_scale = NAN;
_wind_estimate_sideslip.tas_scale_var = NAN;
_wind_estimate_sideslip.source = airspeed_wind_s::SOURCE_AS_BETA_ONLY;
}