ekf2: stop GNSS altittude and velocity aiding when gnss_fault is set
Build all targets / Scan for Board Targets (push) Has been cancelled
Checks / build (NO_NINJA_BUILD=1 px4_fmu-v5_default) (push) Has been cancelled
Checks / build (NO_NINJA_BUILD=1 px4_sitl_default) (push) Has been cancelled
Checks / build (check_format) (push) Has been cancelled
Checks / build (check_newlines) (push) Has been cancelled
Checks / build (module_documentation) (push) Has been cancelled
Checks / build (px4_fmu-v2_default stack_check) (push) Has been cancelled
Checks / build (px4_sitl_allyes) (push) Has been cancelled
Checks / build (shellcheck_all) (push) Has been cancelled
Checks / build (tests) (push) Has been cancelled
Checks / build (tests_coverage) (push) Has been cancelled
Checks / build (validate_module_configs) (push) Has been cancelled
Clang Tidy / build (push) Has been cancelled
MacOS build / build (px4_fmu-v5_default) (push) Has been cancelled
MacOS build / build (px4_sitl) (push) Has been cancelled
Ubuntu environment build / Build and Test (ubuntu:22.04) (push) Has been cancelled
Ubuntu environment build / Build and Test (ubuntu:24.04) (push) Has been cancelled
Container build / Set Tags and Variables (push) Has been cancelled
Docs - Crowdin - Upload Guide sources (en) / upload-to-crowdin (push) Has been cancelled
Docs - Deploy PX4 User Guide / build (push) Has been cancelled
Docs - Deploy PX4 User Guide to AWS / build (push) Has been cancelled
EKF Update Change Indicator / unit_tests (push) Has been cancelled
Failsafe Simulator Build / build (failsafe_web) (push) Has been cancelled
FLASH usage analysis / Analyzing px4_fmu-v5x (push) Has been cancelled
FLASH usage analysis / Analyzing px4_fmu-v6x (push) Has been cancelled
ITCM check / Checking nxp_tropic-community (push) Has been cancelled
ITCM check / Checking px4_fmu-v5x (push) Has been cancelled
ITCM check / Checking px4_fmu-v6xrt (push) Has been cancelled
MAVROS Mission Tests / build (map[mission:MC_mission_box vehicle:iris]) (push) Has been cancelled
MAVROS Offboard Tests / build (map[test_file:mavros_posix_tests_offboard_posctl.test vehicle:iris]) (push) Has been cancelled
Nuttx Target with extra env config / build (px4_fmu-v5_default) (push) Has been cancelled
Python CI Checks / build (push) Has been cancelled
ROS Integration Tests / build (push) Has been cancelled
ROS Translation Node Tests / Build and test (map[ros_version:humble ubuntu:jammy]) (push) Has been cancelled
ROS Translation Node Tests / Build and test (map[ros_version:jazzy ubuntu:noble]) (push) Has been cancelled
SITL Tests / Testing PX4 tailsitter (push) Has been cancelled
SITL Tests / Testing PX4 iris (push) Has been cancelled
SITL Tests / Testing PX4 standard_vtol (push) Has been cancelled
Build all targets / Build Group [${{ matrix.group }}][${{ matrix.arch == 'nuttx' && 'x86' || 'arm64' }}] (push) Has been cancelled
Build all targets / Upload Artifacts to S3 (push) Has been cancelled
Build all targets / Create Release and Upload Artifacts (push) Has been cancelled
Container build / Build Container (amd64) (push) Has been cancelled
Container build / Build Container (arm64) (push) Has been cancelled
Container build / Deploy To Registry (push) Has been cancelled
Docs - Deploy PX4 User Guide / deploy (push) Has been cancelled
Docs - Deploy PX4 User Guide to AWS / deploy (push) Has been cancelled
FLASH usage analysis / Publish Results (push) Has been cancelled
Handle stale issues and PRs / stale (push) Has been cancelled
Fuzzing / Fuzzing (push) Has been cancelled

This commit is contained in:
bresch
2025-08-19 11:59:59 +02:00
committed by Mathieu Bresciani
parent db3f33760e
commit 4a697d0191
5 changed files with 73 additions and 10 deletions
@@ -76,18 +76,11 @@ void Ekf::controlGnssHeightFusion(const gnssSample &gps_sample)
measurement_var + bias_est.getBiasVar(),
math::max(_params.ekf2_gps_p_gate, 1.f));
// update the bias estimator before updating the main filter but after
// using its current state to compute the vertical position innovation
if (measurement_valid) {
bias_est.setMaxStateNoise(sqrtf(measurement_var));
bias_est.setProcessNoiseSpectralDensity(_params.gps_hgt_bias_nsd);
bias_est.fuseBias(measurement - _gpos.altitude(), measurement_var + P(State::pos.idx + 2, State::pos.idx + 2));
}
// determine if we should use height aiding
const bool common_conditions_passing = measurement_valid
&& _local_origin_lat_lon.isInitialized()
&& _gnss_checks.passed();
&& _gnss_checks.passed()
&& !_control_status.flags.gnss_fault;
const bool continuing_conditions_passing = (_params.ekf2_gps_ctrl & static_cast<int32_t>(GnssCtrl::VPOS))
&& common_conditions_passing;
@@ -103,6 +96,12 @@ void Ekf::controlGnssHeightFusion(const gnssSample &gps_sample)
if (_control_status.flags.gps_hgt) {
if (continuing_conditions_passing) {
// update the bias estimator before updating the main filter but after
// using its current state to compute the vertical position innovation
bias_est.setMaxStateNoise(sqrtf(measurement_var));
bias_est.setProcessNoiseSpectralDensity(_params.gps_hgt_bias_nsd);
bias_est.fuseBias(measurement - _gpos.altitude(), measurement_var + P(State::pos.idx + 2, State::pos.idx + 2));
fuseVerticalPosition(aid_src);
const bool is_fusion_failing = isTimedOut(aid_src.time_last_fuse, _params.hgt_fusion_timeout_max);
@@ -123,7 +123,8 @@ void Ekf::controlGnssVelFusion(estimator_aid_source3d_s &aid_src, const bool for
{
const bool continuing_conditions_passing = (_params.ekf2_gps_ctrl & static_cast<int32_t>(GnssCtrl::VEL))
&& _control_status.flags.tilt_align
&& _control_status.flags.yaw_align;
&& _control_status.flags.yaw_align
&& !_control_status.flags.gnss_fault;
const bool starting_conditions_passing = continuing_conditions_passing && _gnss_checks.passed();
if (_control_status.flags.gnss_vel) {
@@ -120,6 +120,16 @@ bool EkfWrapper::isIntendingGpsFusion() const
return _ekf->control_status_flags().gnss_vel || _ekf->control_status_flags().gnss_pos;
}
bool EkfWrapper::isGnssFaultDetected() const
{
return _ekf->control_status_flags().gnss_fault;
}
void EkfWrapper::setGnssDeadReckonMode()
{
_ekf_params->ekf2_gps_mode = static_cast<int32_t>(GnssMode::kDeadReckoning);
}
void EkfWrapper::enableGpsHeadingFusion()
{
_ekf_params->ekf2_gps_ctrl |= static_cast<int32_t>(GnssCtrl::YAW);
@@ -78,6 +78,8 @@ public:
void enableGpsFusion();
void disableGpsFusion();
bool isIntendingGpsFusion() const;
bool isGnssFaultDetected() const;
void setGnssDeadReckonMode();
void enableGpsHeadingFusion();
void disableGpsHeadingFusion();
+51
View File
@@ -228,3 +228,54 @@ TEST_F(EkfGpsTest, altitudeDrift)
// THEN: the baro and local position should follow it
EXPECT_LT(fabsf(baro_innov), 0.1f);
}
TEST_F(EkfGpsTest, gnssJumpDetectionDRMode)
{
// Dead-reckoning mode allows the EKF to reject GNSS data if another source
// of horizontal aiding is used (e.g.: airspped)
_ekf_wrapper.setGnssDeadReckonMode();
_ekf_wrapper.enableGpsHeightFusion();
// GIVEN:EKF that fuses GNSS and airspeed
const Vector3f previous_position = _ekf->getPosition();
const Vector3f simulated_velocity_earth(1.f, 0.5f, 0.0f);
const Vector2f airspeed_body(15.f, 0.0f);
_sensor_simulator._gps.setVelocity(simulated_velocity_earth);
_ekf->set_in_air_status(true);
_ekf->set_vehicle_at_rest(false);
_ekf->set_is_fixed_wing(true);
_sensor_simulator.startAirspeedSensor();
_sensor_simulator._airspeed.setData(airspeed_body(0), airspeed_body(0));
_sensor_simulator.runSeconds(1);
EXPECT_TRUE(_ekf_wrapper.isWindVelocityEstimated());
// AND: simulate jump in position
const Vector3f simulated_position_change(500.0f, -1.0f, 0.f);
_sensor_simulator._gps.stepHorizontalPositionByMeters(
Vector2f(simulated_position_change));
_sensor_simulator.runSeconds(15);
// THEN: the GNSS jump should trigger the fault detection
// and stop the fusion (including height and velocity)
const Vector3f estimated_position = _ekf->getPosition();
EXPECT_FALSE(_ekf_wrapper.isIntendingGpsHeightFusion());
EXPECT_FALSE(_ekf_wrapper.isIntendingGpsFusion());
EXPECT_TRUE(_ekf_wrapper.isGnssFaultDetected());
// The position is obtained through dead-reckoning
EXPECT_TRUE(isEqual(estimated_position,
previous_position, 25.f));
// BUT WHEN: the position data goes back to normal
_sensor_simulator._gps.stepHorizontalPositionByMeters(
-Vector2f(simulated_position_change) + Vector2f(20.f, 10.f));
_sensor_simulator.runSeconds(1);
// THEN: the fault is cleared an dfusion restarts
EXPECT_FALSE(_ekf_wrapper.isGnssFaultDetected());
EXPECT_TRUE(_ekf_wrapper.isIntendingGpsHeightFusion());
EXPECT_TRUE(_ekf_wrapper.isIntendingGpsFusion());
}