Skip to content

Commit

Permalink
ekf2: improve attitude estimation without horizontal aiding
Browse files Browse the repository at this point in the history
 - fake_pos only if at rest or tilt variances becomes large
 - fake pos: don't run when grav fusion is enabled
 - gravity fusion enabled by default
 - gravity: only fuse when accel norm and lpf norm are consistent

Co-authored-by: bresch <brescianimathieu@gmail.com>
  • Loading branch information
dagar and bresch committed Jan 17, 2024
1 parent 8158a14 commit ed0d26d
Show file tree
Hide file tree
Showing 9 changed files with 648 additions and 629 deletions.
6 changes: 2 additions & 4 deletions src/modules/ekf2/EKF/control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,9 @@ void Ekf::controlFusionModes(const imuSample &imu_delayed)
// monitor the tilt alignment
if (!_control_status.flags.tilt_align) {
// whilst we are aligning the tilt, monitor the variances
const Vector3f angle_err_var_vec = getQuaternionVariance();

// Once the tilt variances have reduced to equivalent of 3deg uncertainty
// Once the tilt variances have reduced to equivalent of 3 deg uncertainty
// and declare the tilt alignment complete
if ((angle_err_var_vec(0) + angle_err_var_vec(1)) < sq(math::radians(3.0f))) {
if (getTiltVariance() < sq(math::radians(3.f))) {
_control_status.flags.tilt_align = true;

// send alignment status message to the console
Expand Down
3 changes: 3 additions & 0 deletions src/modules/ekf2/EKF/ekf.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,10 @@ class Ekf final : public EstimatorInterface
matrix::Vector<float, State::size> covariances_diagonal() const { return P.diag(); }

matrix::Vector<float, State::quat_nominal.dof> getQuaternionVariance() const { return getStateVariance<State::quat_nominal>(); }
float getTiltVariance() const { return getStateVariance<State::quat_nominal>()(0) + getStateVariance<State::quat_nominal>()(1); };

Vector3f getVelocityVariance() const { return getStateVariance<State::vel>(); };

Vector3f getPositionVariance() const { return getStateVariance<State::pos>(); }

// get the ekf WGS-84 origin position and height and the system time it was last set
Expand Down
11 changes: 7 additions & 4 deletions src/modules/ekf2/EKF/fake_pos_control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ void Ekf::controlFakePosFusion()
auto &aid_src = _aid_src_fake_pos;

// If we aren't doing any aiding, fake position measurements at the last known position to constrain drift
// During intial tilt aligment, fake position is used to perform a "quasi-stationary" leveling of the EKF
// During initial tilt alignment, fake position is used to perform a "quasi-stationary" leveling of the EKF
const bool fake_pos_data_ready = !isHorizontalAidingActive()
&& isTimedOut(aid_src.time_last_fuse, (uint64_t)2e5); // Fuse fake position at a limited rate

Expand All @@ -68,7 +68,10 @@ void Ekf::controlFakePosFusion()
updateHorizontalPositionAidSrcStatus(_time_delayed_us, Vector2f(_last_known_pos), obs_var, innov_gate, aid_src);


const bool continuing_conditions_passing = !isHorizontalAidingActive();
const bool continuing_conditions_passing = !isHorizontalAidingActive()
&& ((getTiltVariance() > sq(math::radians(3.f))) || _control_status.flags.vehicle_at_rest)
&& (!(_params.imu_ctrl & static_cast<int32_t>(ImuCtrl::GravityVector)) || _control_status.flags.vehicle_at_rest);

const bool starting_conditions_passing = continuing_conditions_passing
&& _horizontal_deadreckon_time_exceeded;

Expand All @@ -77,8 +80,8 @@ void Ekf::controlFakePosFusion()

// always protect against extreme values that could result in a NaN
if ((aid_src.test_ratio[0] < sq(100.0f / innov_gate))
&& (aid_src.test_ratio[1] < sq(100.0f / innov_gate))
) {
&& (aid_src.test_ratio[1] < sq(100.0f / innov_gate))
) {
fuseHorizontalPosition(aid_src);
}

Expand Down
19 changes: 12 additions & 7 deletions src/modules/ekf2/EKF/gravity_fusion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,22 @@

void Ekf::controlGravityFusion(const imuSample &imu)
{
// fuse gravity observation if our overall acceleration isn't too big
const float gravity_scale = _accel_vec_filt.norm() / CONSTANTS_ONE_G;
// get raw accelerometer reading at delayed horizon and expected measurement noise (gaussian)
const Vector3f measurement = imu.delta_vel / imu.delta_vel_dt - _state.accel_bias;
const float measurement_var = math::max(sq(_params.gravity_noise), sq(0.01f));

const float accel_lpf_norm_sq = _accel_vec_filt.norm_squared();
const float accel_norm_sq = measurement.norm_squared();
const float upper_accel_limit = CONSTANTS_ONE_G * 1.1f;
const float lower_accel_limit = CONSTANTS_ONE_G * 0.9f;
const bool accel_lpf_norm_good = (accel_lpf_norm_sq > sq(lower_accel_limit)) && (accel_lpf_norm_sq < sq(upper_accel_limit));
const bool accel_norm_good = (accel_norm_sq > sq(lower_accel_limit)) && (accel_norm_sq < sq(upper_accel_limit));

// fuse gravity observation if our overall acceleration isn't too big
_control_status.flags.gravity_vector = (_params.imu_ctrl & static_cast<int32_t>(ImuCtrl::GravityVector))
&& (((gravity_scale >= 0.9f && gravity_scale <= 1.1f)) || _control_status.flags.vehicle_at_rest)
&& ((accel_lpf_norm_good && accel_norm_good) || _control_status.flags.vehicle_at_rest)
&& !isHorizontalAidingActive();

// get raw accelerometer reading at delayed horizon and expected measurement noise (gaussian)
const Vector3f measurement = imu.delta_vel / imu.delta_vel_dt - getAccelBias();
const float measurement_var = sq(_params.gravity_noise);

// calculate kalman gains and innovation variances
Vector3f innovation; // innovation of the last gravity fusion observation (m/s**2)
Vector3f innovation_variance;
Expand Down
9 changes: 9 additions & 0 deletions src/modules/ekf2/EKF2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ bool EKF2::multi_init(int imu, int mag)
_estimator_states_pub.advertise();
_estimator_status_flags_pub.advertise();
_estimator_status_pub.advertise();

#if defined(CONFIG_EKF2_GNSS)
_yaw_est_pub.advertise();
#endif // CONFIG_EKF2_GNSS
Expand Down Expand Up @@ -313,6 +314,14 @@ bool EKF2::multi_init(int imu, int mag)
# endif // CONFIG_EKF2_GNSS_YAW
#endif // CONFIG_EKF2_GNSS

#if defined(CONFIG_EKF2_GRAVITY_FUSION)

if (_param_ekf2_imu_ctrl.get() & static_cast<int32_t>(ImuCtrl::GravityVector)) {
_estimator_aid_src_gravity_pub.advertise();
}

#endif // CONFIG_EKF2_GRAVITY_FUSION

#if defined(CONFIG_EKF2_RANGE_FINDER)

// RNG advertise
Expand Down
4 changes: 2 additions & 2 deletions src/modules/ekf2/ekf2_params.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ PARAM_DEFINE_INT32(EKF2_PREDICT_US, 10000);
* @bit 1 Accel Bias
* @bit 2 Gravity vector fusion
*/
PARAM_DEFINE_INT32(EKF2_IMU_CTRL, 3);
PARAM_DEFINE_INT32(EKF2_IMU_CTRL, 7);

/**
* Magnetometer measurement delay relative to IMU measurements
Expand Down Expand Up @@ -829,7 +829,7 @@ PARAM_DEFINE_FLOAT(EKF2_EVA_NOISE, 0.1f);
* @unit m/s^2
* @decimal 2
*/
PARAM_DEFINE_FLOAT(EKF2_GRAV_NOISE, 1.0f);
PARAM_DEFINE_FLOAT(EKF2_GRAV_NOISE, 5.0f);

/**
* Optical flow aiding
Expand Down
Loading

0 comments on commit ed0d26d

Please sign in to comment.