Skip to content

Commit 4a697d0

Browse files
committed
ekf2: stop GNSS altittude and velocity aiding when gnss_fault is set
1 parent db3f337 commit 4a697d0

File tree

5 files changed

+73
-10
lines changed

5 files changed

+73
-10
lines changed

src/modules/ekf2/EKF/aid_sources/gnss/gnss_height_control.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,11 @@ void Ekf::controlGnssHeightFusion(const gnssSample &gps_sample)
7676
measurement_var + bias_est.getBiasVar(),
7777
math::max(_params.ekf2_gps_p_gate, 1.f));
7878

79-
// update the bias estimator before updating the main filter but after
80-
// using its current state to compute the vertical position innovation
81-
if (measurement_valid) {
82-
bias_est.setMaxStateNoise(sqrtf(measurement_var));
83-
bias_est.setProcessNoiseSpectralDensity(_params.gps_hgt_bias_nsd);
84-
bias_est.fuseBias(measurement - _gpos.altitude(), measurement_var + P(State::pos.idx + 2, State::pos.idx + 2));
85-
}
86-
8779
// determine if we should use height aiding
8880
const bool common_conditions_passing = measurement_valid
8981
&& _local_origin_lat_lon.isInitialized()
90-
&& _gnss_checks.passed();
82+
&& _gnss_checks.passed()
83+
&& !_control_status.flags.gnss_fault;
9184

9285
const bool continuing_conditions_passing = (_params.ekf2_gps_ctrl & static_cast<int32_t>(GnssCtrl::VPOS))
9386
&& common_conditions_passing;
@@ -103,6 +96,12 @@ void Ekf::controlGnssHeightFusion(const gnssSample &gps_sample)
10396
if (_control_status.flags.gps_hgt) {
10497
if (continuing_conditions_passing) {
10598

99+
// update the bias estimator before updating the main filter but after
100+
// using its current state to compute the vertical position innovation
101+
bias_est.setMaxStateNoise(sqrtf(measurement_var));
102+
bias_est.setProcessNoiseSpectralDensity(_params.gps_hgt_bias_nsd);
103+
bias_est.fuseBias(measurement - _gpos.altitude(), measurement_var + P(State::pos.idx + 2, State::pos.idx + 2));
104+
106105
fuseVerticalPosition(aid_src);
107106

108107
const bool is_fusion_failing = isTimedOut(aid_src.time_last_fuse, _params.hgt_fusion_timeout_max);

src/modules/ekf2/EKF/aid_sources/gnss/gps_control.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ void Ekf::controlGnssVelFusion(estimator_aid_source3d_s &aid_src, const bool for
123123
{
124124
const bool continuing_conditions_passing = (_params.ekf2_gps_ctrl & static_cast<int32_t>(GnssCtrl::VEL))
125125
&& _control_status.flags.tilt_align
126-
&& _control_status.flags.yaw_align;
126+
&& _control_status.flags.yaw_align
127+
&& !_control_status.flags.gnss_fault;
127128
const bool starting_conditions_passing = continuing_conditions_passing && _gnss_checks.passed();
128129

129130
if (_control_status.flags.gnss_vel) {

src/modules/ekf2/test/sensor_simulator/ekf_wrapper.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,16 @@ bool EkfWrapper::isIntendingGpsFusion() const
120120
return _ekf->control_status_flags().gnss_vel || _ekf->control_status_flags().gnss_pos;
121121
}
122122

123+
bool EkfWrapper::isGnssFaultDetected() const
124+
{
125+
return _ekf->control_status_flags().gnss_fault;
126+
}
127+
128+
void EkfWrapper::setGnssDeadReckonMode()
129+
{
130+
_ekf_params->ekf2_gps_mode = static_cast<int32_t>(GnssMode::kDeadReckoning);
131+
}
132+
123133
void EkfWrapper::enableGpsHeadingFusion()
124134
{
125135
_ekf_params->ekf2_gps_ctrl |= static_cast<int32_t>(GnssCtrl::YAW);

src/modules/ekf2/test/sensor_simulator/ekf_wrapper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ class EkfWrapper
7878
void enableGpsFusion();
7979
void disableGpsFusion();
8080
bool isIntendingGpsFusion() const;
81+
bool isGnssFaultDetected() const;
82+
void setGnssDeadReckonMode();
8183

8284
void enableGpsHeadingFusion();
8385
void disableGpsHeadingFusion();

src/modules/ekf2/test/test_EKF_gps.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,54 @@ TEST_F(EkfGpsTest, altitudeDrift)
228228
// THEN: the baro and local position should follow it
229229
EXPECT_LT(fabsf(baro_innov), 0.1f);
230230
}
231+
232+
TEST_F(EkfGpsTest, gnssJumpDetectionDRMode)
233+
{
234+
// Dead-reckoning mode allows the EKF to reject GNSS data if another source
235+
// of horizontal aiding is used (e.g.: airspped)
236+
_ekf_wrapper.setGnssDeadReckonMode();
237+
_ekf_wrapper.enableGpsHeightFusion();
238+
239+
// GIVEN:EKF that fuses GNSS and airspeed
240+
const Vector3f previous_position = _ekf->getPosition();
241+
const Vector3f simulated_velocity_earth(1.f, 0.5f, 0.0f);
242+
const Vector2f airspeed_body(15.f, 0.0f);
243+
_sensor_simulator._gps.setVelocity(simulated_velocity_earth);
244+
245+
_ekf->set_in_air_status(true);
246+
_ekf->set_vehicle_at_rest(false);
247+
_ekf->set_is_fixed_wing(true);
248+
249+
_sensor_simulator.startAirspeedSensor();
250+
_sensor_simulator._airspeed.setData(airspeed_body(0), airspeed_body(0));
251+
_sensor_simulator.runSeconds(1);
252+
253+
EXPECT_TRUE(_ekf_wrapper.isWindVelocityEstimated());
254+
255+
// AND: simulate jump in position
256+
const Vector3f simulated_position_change(500.0f, -1.0f, 0.f);
257+
_sensor_simulator._gps.stepHorizontalPositionByMeters(
258+
Vector2f(simulated_position_change));
259+
_sensor_simulator.runSeconds(15);
260+
261+
// THEN: the GNSS jump should trigger the fault detection
262+
// and stop the fusion (including height and velocity)
263+
const Vector3f estimated_position = _ekf->getPosition();
264+
EXPECT_FALSE(_ekf_wrapper.isIntendingGpsHeightFusion());
265+
EXPECT_FALSE(_ekf_wrapper.isIntendingGpsFusion());
266+
EXPECT_TRUE(_ekf_wrapper.isGnssFaultDetected());
267+
268+
// The position is obtained through dead-reckoning
269+
EXPECT_TRUE(isEqual(estimated_position,
270+
previous_position, 25.f));
271+
272+
// BUT WHEN: the position data goes back to normal
273+
_sensor_simulator._gps.stepHorizontalPositionByMeters(
274+
-Vector2f(simulated_position_change) + Vector2f(20.f, 10.f));
275+
_sensor_simulator.runSeconds(1);
276+
277+
// THEN: the fault is cleared an dfusion restarts
278+
EXPECT_FALSE(_ekf_wrapper.isGnssFaultDetected());
279+
EXPECT_TRUE(_ekf_wrapper.isIntendingGpsHeightFusion());
280+
EXPECT_TRUE(_ekf_wrapper.isIntendingGpsFusion());
281+
}

0 commit comments

Comments
 (0)