ekf2: simplify names of scoped variables

This commit is contained in:
bresch
2025-05-23 09:59:33 +02:00
committed by Mathieu Bresciani
parent c33d79cfb4
commit 0e32b155f3
3 changed files with 96 additions and 101 deletions
@@ -40,93 +40,92 @@
namespace estimator
{
bool GnssChecks::runGnssChecks(const gnssSample &gnss, uint64_t time_us)
bool GnssChecks::run(const gnssSample &gnss, uint64_t time_us)
{
// assume failed first time through
if (_last_gps_fail_us == 0) {
_last_gps_fail_us = time_us;
if (_time_last_fail_us == 0) {
_time_last_fail_us = time_us;
}
bool passed = false;
if (_initial_checks_passed) {
if (runInitialFixChecks(gnss)) {
_last_gps_pass_us = time_us;
passed = isTimedOut(_last_gps_fail_us, time_us, math::max((uint64_t)1e6, (uint64_t)_min_gps_health_time_us / 10));
_time_last_pass_us = time_us;
passed = isTimedOut(_time_last_fail_us, time_us, math::max((uint64_t)1e6, (uint64_t)_params.min_health_time_us / 10));
} else {
_last_gps_fail_us = time_us;
_time_last_fail_us = time_us;
}
} else {
if (runInitialFixChecks(gnss)) {
_last_gps_pass_us = time_us;
_time_last_pass_us = time_us;
if (isTimedOut(_last_gps_fail_us, time_us, (uint64_t)_min_gps_health_time_us)) {
if (isTimedOut(_time_last_fail_us, time_us, (uint64_t)_params.min_health_time_us)) {
_initial_checks_passed = true;
passed = true;
}
} else {
_last_gps_fail_us = time_us;
_time_last_fail_us = time_us;
}
}
// save GPS fix for next time
_gnss_pos_prev.initReference(gnss.lat, gnss.lon, gnss.time_us);
_gnss_alt_prev = gnss.alt;
lat_lon_prev.initReference(gnss.lat, gnss.lon, gnss.time_us);
_alt_prev = gnss.alt;
_checks_passed = passed;
_passed = passed;
return passed;
}
bool GnssChecks::runInitialFixChecks(const gnssSample &gnss)
{
// Check the fix type
_gps_check_fail_status.flags.fix = (gnss.fix_type < 3);
_check_fail_status.flags.fix = (gnss.fix_type < 3);
// Check the number of satellites
_gps_check_fail_status.flags.nsats = (gnss.nsats < _params.req_nsats);
_check_fail_status.flags.nsats = (gnss.nsats < _params.req_nsats);
// Check the position dilution of precision
_gps_check_fail_status.flags.pdop = (gnss.pdop > _params.req_pdop);
_check_fail_status.flags.pdop = (gnss.pdop > _params.req_pdop);
// Check the reported horizontal and vertical position accuracy
_gps_check_fail_status.flags.hacc = (gnss.hacc > _params.req_hacc);
_gps_check_fail_status.flags.vacc = (gnss.vacc > _params.req_vacc);
_check_fail_status.flags.hacc = (gnss.hacc > _params.req_hacc);
_check_fail_status.flags.vacc = (gnss.vacc > _params.req_vacc);
// Check the reported speed accuracy
_gps_check_fail_status.flags.sacc = (gnss.sacc > _params.req_sacc);
_check_fail_status.flags.sacc = (gnss.sacc > _params.req_sacc);
_gps_check_fail_status.flags.spoofed = gnss.spoofed;
_check_fail_status.flags.spoofed = gnss.spoofed;
runOnGroundGnssChecks(gnss);
// force horizontal speed failure if above the limit
if (gnss.vel.xy().longerThan(_params.velocity_limit)) {
_gps_check_fail_status.flags.hspeed = true;
_check_fail_status.flags.hspeed = true;
}
// force vertical speed failure if above the limit
if (fabsf(gnss.vel(2)) > _params.velocity_limit) {
_gps_check_fail_status.flags.vspeed = true;
_check_fail_status.flags.vspeed = true;
}
bool passed = true;
// if any user selected checks have failed, record the fail time
if (
_gps_check_fail_status.flags.fix ||
(_gps_check_fail_status.flags.nsats && isGnssCheckEnabled(GnssChecksMask::kNsats)) ||
(_gps_check_fail_status.flags.pdop && isGnssCheckEnabled(GnssChecksMask::kPdop)) ||
(_gps_check_fail_status.flags.hacc && isGnssCheckEnabled(GnssChecksMask::kHacc)) ||
(_gps_check_fail_status.flags.vacc && isGnssCheckEnabled(GnssChecksMask::kVacc)) ||
(_gps_check_fail_status.flags.sacc && isGnssCheckEnabled(GnssChecksMask::kSacc)) ||
(_gps_check_fail_status.flags.hdrift && isGnssCheckEnabled(GnssChecksMask::kHdrift)) ||
(_gps_check_fail_status.flags.vdrift && isGnssCheckEnabled(GnssChecksMask::kVdrift)) ||
(_gps_check_fail_status.flags.hspeed && isGnssCheckEnabled(GnssChecksMask::kHspd)) ||
(_gps_check_fail_status.flags.vspeed && isGnssCheckEnabled(GnssChecksMask::kVspd)) ||
(_gps_check_fail_status.flags.spoofed && isGnssCheckEnabled(GnssChecksMask::kSpoofed))
_check_fail_status.flags.fix ||
(_check_fail_status.flags.nsats && isCheckEnabled(GnssChecksMask::kNsats)) ||
(_check_fail_status.flags.pdop && isCheckEnabled(GnssChecksMask::kPdop)) ||
(_check_fail_status.flags.hacc && isCheckEnabled(GnssChecksMask::kHacc)) ||
(_check_fail_status.flags.vacc && isCheckEnabled(GnssChecksMask::kVacc)) ||
(_check_fail_status.flags.sacc && isCheckEnabled(GnssChecksMask::kSacc)) ||
(_check_fail_status.flags.hdrift && isCheckEnabled(GnssChecksMask::kHdrift)) ||
(_check_fail_status.flags.vdrift && isCheckEnabled(GnssChecksMask::kVdrift)) ||
(_check_fail_status.flags.hspeed && isCheckEnabled(GnssChecksMask::kHspd)) ||
(_check_fail_status.flags.vspeed && isCheckEnabled(GnssChecksMask::kVspd)) ||
(_check_fail_status.flags.spoofed && isCheckEnabled(GnssChecksMask::kSpoofed))
) {
passed = false;
}
@@ -139,12 +138,12 @@ void GnssChecks::runOnGroundGnssChecks(const gnssSample &gnss)
if (_control_status.flags.in_air) {
// These checks are always declared as passed when flying
// If on ground and moving, the last result before movement commenced is kept
_gps_check_fail_status.flags.hdrift = false;
_gps_check_fail_status.flags.vdrift = false;
_gps_check_fail_status.flags.hspeed = false;
_gps_check_fail_status.flags.vspeed = false;
_check_fail_status.flags.hdrift = false;
_check_fail_status.flags.vdrift = false;
_check_fail_status.flags.hspeed = false;
_check_fail_status.flags.vspeed = false;
resetGpsDriftCheckFilters();
resetDriftFilters();
return;
}
@@ -152,7 +151,7 @@ void GnssChecks::runOnGroundGnssChecks(const gnssSample &gnss)
// Calculate time lapsed since last update, limit to prevent numerical errors and calculate a lowpass filter coefficient
constexpr float filt_time_const = 10.0f;
const float dt = math::constrain(float(int64_t(gnss.time_us) - int64_t(
_gnss_pos_prev.getProjectionReferenceTimestamp()))
lat_lon_prev.getProjectionReferenceTimestamp()))
* 1e-6f, 0.001f, filt_time_const);
const float filter_coef = dt / filt_time_const;
@@ -160,64 +159,64 @@ void GnssChecks::runOnGroundGnssChecks(const gnssSample &gnss)
float delta_pos_n = 0.0f;
float delta_pos_e = 0.0f;
// calculate position movement since last GPS fix
if (_gnss_pos_prev.getProjectionReferenceTimestamp() > 0) {
_gnss_pos_prev.project(gnss.lat, gnss.lon, delta_pos_n, delta_pos_e);
// calculate position movement since last fix
if (lat_lon_prev.getProjectionReferenceTimestamp() > 0) {
lat_lon_prev.project(gnss.lat, gnss.lon, delta_pos_n, delta_pos_e);
} else {
// no previous position has been set
_gnss_pos_prev.initReference(gnss.lat, gnss.lon, gnss.time_us);
_gnss_alt_prev = gnss.alt;
lat_lon_prev.initReference(gnss.lat, gnss.lon, gnss.time_us);
_alt_prev = gnss.alt;
}
// Calculate the horizontal and vertical drift velocity components and limit to 10x the threshold
const Vector3f vel_limit(_params.req_hdrift, _params.req_hdrift, _params.req_vdrift);
Vector3f delta_pos(delta_pos_n, delta_pos_e, (_gnss_alt_prev - gnss.alt));
Vector3f delta_pos(delta_pos_n, delta_pos_e, (_alt_prev - gnss.alt));
// Apply a low pass filter
_gps_pos_deriv_filt = delta_pos / dt * filter_coef + _gps_pos_deriv_filt * (1.0f - filter_coef);
_lat_lon_alt_deriv_filt = delta_pos / dt * filter_coef + _lat_lon_alt_deriv_filt * (1.0f - filter_coef);
// Apply anti-windup to the state instead of the input to avoid generating a bias on asymmetric signals
_gps_pos_deriv_filt = matrix::constrain(_gps_pos_deriv_filt, -10.0f * vel_limit, 10.0f * vel_limit);
_lat_lon_alt_deriv_filt = matrix::constrain(_lat_lon_alt_deriv_filt, -10.0f * vel_limit, 10.0f * vel_limit);
// hdrift: calculate the horizontal drift speed and fail if too high
_gps_horizontal_position_drift_rate_m_s = Vector2f(_gps_pos_deriv_filt.xy()).norm();
_gps_check_fail_status.flags.hdrift = (_gps_horizontal_position_drift_rate_m_s > _params.req_hdrift);
_horizontal_position_drift_rate_m_s = Vector2f(_lat_lon_alt_deriv_filt.xy()).norm();
_check_fail_status.flags.hdrift = (_horizontal_position_drift_rate_m_s > _params.req_hdrift);
// vdrift: fail if the vertical drift speed is too high
_gps_vertical_position_drift_rate_m_s = fabsf(_gps_pos_deriv_filt(2));
_gps_check_fail_status.flags.vdrift = (_gps_vertical_position_drift_rate_m_s > _params.req_vdrift);
_vertical_position_drift_rate_m_s = fabsf(_lat_lon_alt_deriv_filt(2));
_check_fail_status.flags.vdrift = (_vertical_position_drift_rate_m_s > _params.req_vdrift);
// hspeed: check the magnitude of the filtered horizontal GNSS velocity
const Vector2f gps_velNE = matrix::constrain(Vector2f(gnss.vel.xy()),
-10.0f * _params.req_hdrift,
10.0f * _params.req_hdrift);
_gps_velNE_filt = gps_velNE * filter_coef + _gps_velNE_filt * (1.0f - filter_coef);
_gps_filtered_horizontal_velocity_m_s = _gps_velNE_filt.norm();
_gps_check_fail_status.flags.hspeed = (_gps_filtered_horizontal_velocity_m_s > _params.req_hdrift);
const Vector2f vel_ne = matrix::constrain(Vector2f(gnss.vel.xy()),
-10.0f * _params.req_hdrift,
10.0f * _params.req_hdrift);
_vel_ne_filt = vel_ne * filter_coef + _vel_ne_filt * (1.0f - filter_coef);
_filtered_horizontal_velocity_m_s = _vel_ne_filt.norm();
_check_fail_status.flags.hspeed = (_filtered_horizontal_velocity_m_s > _params.req_hdrift);
// vspeed: check the magnitude of the filtered vertical GNSS velocity
const float gnss_vz_limit = 10.f * _params.req_vdrift;
const float gnss_vz = math::constrain(gnss.vel(2), -gnss_vz_limit, gnss_vz_limit);
_gps_vel_d_filt = gnss_vz * filter_coef + _gps_vel_d_filt * (1.f - filter_coef);
_vel_d_filt = gnss_vz * filter_coef + _vel_d_filt * (1.f - filter_coef);
_gps_check_fail_status.flags.vspeed = (fabsf(_gps_vel_d_filt) > _params.req_vdrift);
_check_fail_status.flags.vspeed = (fabsf(_vel_d_filt) > _params.req_vdrift);
} else {
// This is the case where the vehicle is on ground and IMU movement is blocking the drift calculation
resetGpsDriftCheckFilters();
resetDriftFilters();
}
}
void GnssChecks::resetGpsDriftCheckFilters()
void GnssChecks::resetDriftFilters()
{
_gps_velNE_filt.setZero();
_gps_vel_d_filt = 0.f;
_vel_ne_filt.setZero();
_vel_d_filt = 0.f;
_gps_pos_deriv_filt.setZero();
_lat_lon_alt_deriv_filt.setZero();
_gps_horizontal_position_drift_rate_m_s = NAN;
_gps_vertical_position_drift_rate_m_s = NAN;
_gps_filtered_horizontal_velocity_m_s = NAN;
_horizontal_position_drift_rate_m_s = NAN;
_vertical_position_drift_rate_m_s = NAN;
_filtered_horizontal_velocity_m_s = NAN;
}
}; // namespace estimator
@@ -46,8 +46,7 @@ public:
GnssChecks(int32_t &check_mask, int32_t &req_nsats, float &req_pdop, float &req_hacc, float &req_vacc, float &req_sacc,
float &req_hdrift, float &req_vdrift, float &velocity_limit, uint32_t &min_health_time_us,
filter_control_status_u &control_status):
_params{check_mask, req_nsats, req_pdop, req_hacc, req_vacc, req_sacc, req_hdrift, req_vdrift, velocity_limit},
_min_gps_health_time_us(min_health_time_us),
_params{check_mask, req_nsats, req_pdop, req_hacc, req_vacc, req_sacc, req_hdrift, req_vdrift, velocity_limit, min_health_time_us},
_control_status(control_status)
{};
@@ -76,28 +75,26 @@ public:
void reset()
{
_checks_passed = false;
_last_gps_pass_us = 0;
_last_gps_fail_us = 0;
resetGpsDriftCheckFilters();
_passed = false;
_time_last_pass_us = 0;
_time_last_fail_us = 0;
resetDriftFilters();
}
/*
* Return true if the GPS solution quality is adequate.
* Checks are activated using the EKF2_GPS_CHECK bitmask parameter
* Checks are adjusted using the EKF2_REQ_* parameters
* Return true if the GNSS solution quality is adequate.
*/
bool runGnssChecks(const gnssSample &gps, uint64_t time_us);
bool passed() const { return _checks_passed; }
bool run(const gnssSample &gnss, uint64_t time_us);
bool passed() const { return _passed; }
bool initialChecksPassed() const { return _initial_checks_passed; }
uint64_t getLastPassUs() const { return _last_gps_pass_us; }
uint64_t getLastFailUs() const { return _last_gps_fail_us; }
uint64_t getLastPassUs() const { return _time_last_pass_us; }
uint64_t getLastFailUs() const { return _time_last_fail_us; }
const gps_check_fail_status_u &getFailStatus() const { return _gps_check_fail_status; }
const gps_check_fail_status_u &getFailStatus() const { return _check_fail_status; }
float horizontal_position_drift_rate_m_s() const { return _gps_horizontal_position_drift_rate_m_s; }
float vertical_position_drift_rate_m_s() const { return _gps_vertical_position_drift_rate_m_s; }
float filtered_horizontal_velocity_m_s() const { return _gps_filtered_horizontal_velocity_m_s; }
float horizontal_position_drift_rate_m_s() const { return _horizontal_position_drift_rate_m_s; }
float vertical_position_drift_rate_m_s() const { return _vertical_position_drift_rate_m_s; }
float filtered_horizontal_velocity_m_s() const { return _filtered_horizontal_velocity_m_s; }
private:
enum class GnssChecksMask : int32_t {
@@ -113,36 +110,35 @@ private:
kSpoofed = (1 << 9)
};
bool isGnssCheckEnabled(GnssChecksMask check) { return (_params.check_mask & static_cast<int32_t>(check)); }
bool isCheckEnabled(GnssChecksMask check) { return (_params.check_mask & static_cast<int32_t>(check)); }
bool runInitialFixChecks(const gnssSample &gnss);
void runOnGroundGnssChecks(const gnssSample &gnss);
void resetGpsDriftCheckFilters();
void resetDriftFilters();
bool isTimedOut(uint64_t timestamp_to_check_us, uint64_t now_us, uint64_t timeout_period) const
{
return (timestamp_to_check_us == 0) || (timestamp_to_check_us + timeout_period < now_us);
}
gps_check_fail_status_u _gps_check_fail_status{};
gps_check_fail_status_u _check_fail_status{};
float _gps_horizontal_position_drift_rate_m_s{NAN}; // Horizontal position drift rate (m/s)
float _gps_vertical_position_drift_rate_m_s{NAN}; // Vertical position drift rate (m/s)
float _gps_filtered_horizontal_velocity_m_s{NAN}; // Filtered horizontal velocity (m/s)
float _horizontal_position_drift_rate_m_s{NAN};
float _vertical_position_drift_rate_m_s{NAN};
float _filtered_horizontal_velocity_m_s{NAN};
MapProjection _gnss_pos_prev{}; // Contains WGS-84 position latitude and longitude of the previous GPS message
float _gnss_alt_prev{0.0f}; // height from the previous GPS message (m)
MapProjection lat_lon_prev{};
float _alt_prev{0.0f};
// variables used for the GPS quality checks
Vector3f _gps_pos_deriv_filt{};
Vector2f _gps_velNE_filt{}; ///< filtered GPS North and East velocity (m/sec)
Vector3f _lat_lon_alt_deriv_filt{};
Vector2f _vel_ne_filt{};
float _gps_vel_d_filt{0.0f}; ///< GNSS filtered Down velocity (m/sec)
uint64_t _last_gps_fail_us{0};
uint64_t _last_gps_pass_us{0};
float _vel_d_filt{0.0f}; ///< GNSS filtered Down velocity (m/sec)
uint64_t _time_last_fail_us{0};
uint64_t _time_last_pass_us{0};
bool _initial_checks_passed{false};
bool _checks_passed{false};
bool _passed{false};
struct Params {
const int32_t &check_mask;
@@ -154,10 +150,10 @@ private:
const float &req_hdrift;
const float &req_vdrift;
const float &velocity_limit;
const uint32_t &min_health_time_us;
};
const Params _params;
const uint32_t &_min_gps_health_time_us; ///< GPS is marked as healthy only after this amount of time
const filter_control_status_u &_control_status;
};
}; // namespace estimator
@@ -65,7 +65,7 @@ void Ekf::controlGpsFusion(const imuSample &imu_delayed)
const bool initial_checks_passed_prev = _gnss_checks.initialChecksPassed();
if (_gnss_checks.runGnssChecks(gnss_sample, _time_delayed_us)) {
if (_gnss_checks.run(gnss_sample, _time_delayed_us)) {
if (_gnss_checks.initialChecksPassed() && !initial_checks_passed_prev) {
// First time checks are passing, latching.
_information_events.flags.gps_checks_passed = true;