Skip to content

Commit

Permalink
ekf2: consolidate GNSS yaw in gnss_yaw_control.cpp and fix naming (GP…
Browse files Browse the repository at this point in the history
…S->GNSS)

Co-authored-by: Mathieu Bresciani <[email protected]>
  • Loading branch information
dagar and bresch authored Jul 15, 2024
1 parent 9d6c2ba commit 1cd7d54
Show file tree
Hide file tree
Showing 18 changed files with 144 additions and 146 deletions.
4 changes: 2 additions & 2 deletions msg/EstimatorStatusFlags.msg
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ bool cs_mag_fault # 18 - true when the magnetometer has been declare
bool cs_fuse_aspd # 19 - true when airspeed measurements are being fused
bool cs_gnd_effect # 20 - true when protection from ground effect induced static pressure rise is active
bool cs_rng_stuck # 21 - true when rng data wasn't ready for more than 10s and new rng values haven't changed enough
bool cs_gps_yaw # 22 - true when yaw (not ground course) data fusion from a GPS receiver is intended
bool cs_gnss_yaw # 22 - true when yaw (not ground course) data fusion from a GPS receiver is intended
bool cs_mag_aligned_in_flight # 23 - true when the in-flight mag field alignment has been completed
bool cs_ev_vel # 24 - true when local frame velocity data fusion from external vision measurements is intended
bool cs_synthetic_mag_z # 25 - true when we are using a synthesized measurement for the magnetometer Z component
bool cs_vehicle_at_rest # 26 - true when the vehicle is at rest
bool cs_gps_yaw_fault # 27 - true when the GNSS heading has been declared faulty and is no longer being used
bool cs_gnss_yaw_fault # 27 - true when the GNSS heading has been declared faulty and is no longer being used
bool cs_rng_fault # 28 - true when the range finder has been declared faulty and is no longer being used
bool cs_inertial_dead_reckoning # 29 - true if we are no longer fusing measurements that constrain horizontal velocity drift
bool cs_wind_dead_reckoning # 30 - true if we are navigationg reliant on wind relative measurements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ void EstimatorChecks::checkEstimatorStatusFlags(const Context &context, Report &
}
}

if (estimator_status_flags.cs_gps_yaw_fault) {
if (estimator_status_flags.cs_gnss_yaw_fault) {
/* EVENT
* @description
* Land now
Expand Down
2 changes: 1 addition & 1 deletion src/modules/ekf2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ if(CONFIG_EKF2_GNSS)
)

if(CONFIG_EKF2_GNSS_YAW)
list(APPEND EKF_SRCS EKF/aid_sources/gnss/gps_yaw_fusion.cpp)
list(APPEND EKF_SRCS EKF/aid_sources/gnss/gnss_yaw_control.cpp)
endif()

list(APPEND EKF_LIBS yaw_estimator)
Expand Down
2 changes: 1 addition & 1 deletion src/modules/ekf2/EKF/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ if(CONFIG_EKF2_GNSS)
)

if(CONFIG_EKF2_GNSS_YAW)
list(APPEND EKF_SRCS aid_sources/gnss/gps_yaw_fusion.cpp)
list(APPEND EKF_SRCS aid_sources/gnss/gnss_yaw_control.cpp)
endif()

add_subdirectory(yaw_estimator)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,45 +32,130 @@
****************************************************************************/

/**
* @file gps_yaw_fusion.cpp
* Definition of functions required to use yaw obtained from GPS dual antenna measurements.
* Equations generated using EKF/python/ekf_derivation/main.py
*
* @author Paul Riseborough <[email protected]>
* @file gnss_yaw_control.cpp
* Definition of functions required to use yaw obtained from GNSS dual antenna measurements.
* Equations generated using src/modules/ekf2/EKF/python/ekf_derivation/derivation.py
*
*/

#include "ekf.h"
#include <ekf_derivation/generated/compute_gnss_yaw_pred_innov_var_and_h.h>

#include <mathlib/mathlib.h>
#include <cstdlib>

void Ekf::updateGpsYaw(const gnssSample &gps_sample)
#include <ekf_derivation/generated/compute_gnss_yaw_pred_innov_var_and_h.h>

void Ekf::controlGnssYawFusion(const gnssSample &gnss_sample)
{
if (!(_params.gnss_ctrl & static_cast<int32_t>(GnssCtrl::YAW))
|| _control_status.flags.gnss_yaw_fault) {

stopGnssYawFusion();
return;
}

const bool is_new_data_available = PX4_ISFINITE(gnss_sample.yaw);

if (is_new_data_available) {

updateGnssYaw(gnss_sample);

const bool continuing_conditions_passing = _control_status.flags.tilt_align;

const bool is_gnss_yaw_data_intermittent = !isNewestSampleRecent(_time_last_gnss_yaw_buffer_push,
2 * GNSS_YAW_MAX_INTERVAL);

const bool starting_conditions_passing = continuing_conditions_passing
&& _gps_checks_passed
&& !is_gnss_yaw_data_intermittent
&& !_gps_intermittent;

if (_control_status.flags.gnss_yaw) {
if (continuing_conditions_passing) {

fuseGnssYaw(gnss_sample.yaw_offset);

const bool is_fusion_failing = isTimedOut(_aid_src_gnss_yaw.time_last_fuse, _params.reset_timeout_max);

if (is_fusion_failing) {
stopGnssYawFusion();

// Before takeoff, we do not want to continue to rely on the current heading
// if we had to stop the fusion
if (!_control_status.flags.in_air) {
ECL_INFO("clearing yaw alignment");
_control_status.flags.yaw_align = false;
}
}

} else {
// Stop GNSS yaw fusion but do not declare it faulty
stopGnssYawFusion();
}

} else {
if (starting_conditions_passing) {
// Try to activate GNSS yaw fusion
const bool not_using_ne_aiding = !_control_status.flags.gps && !_control_status.flags.aux_gpos;

if (!_control_status.flags.in_air
|| !_control_status.flags.yaw_align
|| not_using_ne_aiding) {

// Reset before starting the fusion
if (resetYawToGnss(gnss_sample.yaw, gnss_sample.yaw_offset)) {

resetAidSourceStatusZeroInnovation(_aid_src_gnss_yaw);

_control_status.flags.gnss_yaw = true;
_control_status.flags.yaw_align = true;
}

} else if (!_aid_src_gnss_yaw.innovation_rejected) {
// Do not force a reset but wait for the consistency check to pass
_control_status.flags.gnss_yaw = true;
fuseGnssYaw(gnss_sample.yaw_offset);
}

if (_control_status.flags.gnss_yaw) {
ECL_INFO("starting GNSS yaw fusion");
}
}
}

} else if (_control_status.flags.gnss_yaw
&& !isNewestSampleRecent(_time_last_gnss_yaw_buffer_push, _params.reset_timeout_max)) {

// No yaw data in the message anymore. Stop until it comes back.
stopGnssYawFusion();
}
}

void Ekf::updateGnssYaw(const gnssSample &gnss_sample)
{
// calculate the observed yaw angle of antenna array, converting a from body to antenna yaw measurement
const float measured_hdg = wrap_pi(gps_sample.yaw + gps_sample.yaw_offset);
const float measured_hdg = wrap_pi(gnss_sample.yaw + gnss_sample.yaw_offset);

const float yaw_acc = PX4_ISFINITE(gps_sample.yaw_acc) ? gps_sample.yaw_acc : 0.f;
const float R_YAW = sq(fmaxf(yaw_acc, _params.gps_heading_noise));
const float yaw_acc = PX4_ISFINITE(gnss_sample.yaw_acc) ? gnss_sample.yaw_acc : 0.f;
const float R_YAW = sq(fmaxf(yaw_acc, _params.gnss_heading_noise));

float heading_pred;
float heading_innov_var;

VectorState H;
sym::ComputeGnssYawPredInnovVarAndH(_state.vector(), P, gps_sample.yaw_offset, R_YAW, FLT_EPSILON,
sym::ComputeGnssYawPredInnovVarAndH(_state.vector(), P, gnss_sample.yaw_offset, R_YAW, FLT_EPSILON,
&heading_pred, &heading_innov_var, &H);

updateAidSourceStatus(_aid_src_gnss_yaw,
gps_sample.time_us, // sample timestamp
gnss_sample.time_us, // sample timestamp
measured_hdg, // observation
R_YAW, // observation variance
wrap_pi(heading_pred - measured_hdg), // innovation
heading_innov_var, // innovation variance
math::max(_params.heading_innov_gate, 1.f)); // innovation gate
}

void Ekf::fuseGpsYaw(float antenna_yaw_offset)
void Ekf::fuseGnssYaw(float antenna_yaw_offset)
{
auto &aid_src = _aid_src_gnss_yaw;

Expand Down Expand Up @@ -99,7 +184,8 @@ void Ekf::fuseGpsYaw(float antenna_yaw_offset)

// we reinitialise the covariance matrix and abort this fusion step
initialiseCovariance();
ECL_ERR("GPS yaw numerical error - covariance reset");
ECL_ERR("GNSS yaw numerical error - covariance reset");
stopGnssYawFusion();
return;
}

Expand Down Expand Up @@ -129,7 +215,7 @@ void Ekf::fuseGpsYaw(float antenna_yaw_offset)
}
}

bool Ekf::resetYawToGps(const float gnss_yaw, const float gnss_yaw_offset)
bool Ekf::resetYawToGnss(const float gnss_yaw, const float gnss_yaw_offset)
{
// define the predicted antenna array vector and rotate into earth frame
const Vector3f ant_vec_bf = {cosf(gnss_yaw_offset), sinf(gnss_yaw_offset), 0.0f};
Expand All @@ -140,11 +226,21 @@ bool Ekf::resetYawToGps(const float gnss_yaw, const float gnss_yaw_offset)
return false;
}

// GPS yaw measurement is alreday compensated for antenna offset in the driver
// GNSS yaw measurement is already compensated for antenna offset in the driver
const float measured_yaw = gnss_yaw;

const float yaw_variance = sq(fmaxf(_params.gps_heading_noise, 1.e-2f));
const float yaw_variance = sq(fmaxf(_params.gnss_heading_noise, 1.e-2f));
resetQuatStateYaw(measured_yaw, yaw_variance);

return true;
}

void Ekf::stopGnssYawFusion()
{
if (_control_status.flags.gnss_yaw) {

_control_status.flags.gnss_yaw = false;

ECL_INFO("stopping GNSS yaw fusion");
}
}
106 changes: 4 additions & 102 deletions src/modules/ekf2/EKF/aid_sources/gnss/gps_control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ void Ekf::controlGpsFusion(const imuSample &imu_delayed)
if (_gps_data_ready) {
#if defined(CONFIG_EKF2_GNSS_YAW)
const gnssSample &gnss_sample = _gps_sample_delayed;
controlGpsYawFusion(gnss_sample);
controlGnssYawFusion(gnss_sample);
#endif // CONFIG_EKF2_GNSS_YAW

controlGnssYawEstimator(_aid_src_gnss_vel);
Expand Down Expand Up @@ -285,8 +285,8 @@ bool Ekf::tryYawEmergencyReset()

#if defined(CONFIG_EKF2_GNSS_YAW)

if (_control_status.flags.gps_yaw) {
_control_status.flags.gps_yaw_fault = true;
if (_control_status.flags.gnss_yaw) {
_control_status.flags.gnss_yaw_fault = true;
}

#endif // CONFIG_EKF2_GNSS_YAW
Expand Down Expand Up @@ -354,104 +354,6 @@ bool Ekf::shouldResetGpsFusion() const
return (is_reset_required || is_inflight_nav_failure);
}

#if defined(CONFIG_EKF2_GNSS_YAW)
void Ekf::controlGpsYawFusion(const gnssSample &gps_sample)
{
if (!(_params.gnss_ctrl & static_cast<int32_t>(GnssCtrl::YAW))
|| _control_status.flags.gps_yaw_fault) {

stopGpsYawFusion();
return;
}

const bool is_new_data_available = PX4_ISFINITE(gps_sample.yaw);

if (is_new_data_available) {

updateGpsYaw(gps_sample);

const bool continuing_conditions_passing = _control_status.flags.tilt_align;

const bool is_gps_yaw_data_intermittent = !isNewestSampleRecent(_time_last_gps_yaw_buffer_push,
2 * GNSS_YAW_MAX_INTERVAL);

const bool starting_conditions_passing = continuing_conditions_passing
&& _gps_checks_passed
&& !is_gps_yaw_data_intermittent
&& !_gps_intermittent;

if (_control_status.flags.gps_yaw) {
if (continuing_conditions_passing) {

fuseGpsYaw(gps_sample.yaw_offset);

const bool is_fusion_failing = isTimedOut(_aid_src_gnss_yaw.time_last_fuse, _params.reset_timeout_max);

if (is_fusion_failing) {
stopGpsYawFusion();

// Before takeoff, we do not want to continue to rely on the current heading
// if we had to stop the fusion
if (!_control_status.flags.in_air) {
ECL_INFO("clearing yaw alignment");
_control_status.flags.yaw_align = false;
}
}

} else {
// Stop GPS yaw fusion but do not declare it faulty
stopGpsYawFusion();
}

} else {
if (starting_conditions_passing) {
// Try to activate GPS yaw fusion
const bool not_using_ne_aiding = !_control_status.flags.gps && !_control_status.flags.aux_gpos;

if (!_control_status.flags.in_air
|| !_control_status.flags.yaw_align
|| not_using_ne_aiding) {

// Reset before starting the fusion
if (resetYawToGps(gps_sample.yaw, gps_sample.yaw_offset)) {

resetAidSourceStatusZeroInnovation(_aid_src_gnss_yaw);

_control_status.flags.gps_yaw = true;
_control_status.flags.yaw_align = true;
}

} else if (!_aid_src_gnss_yaw.innovation_rejected) {
// Do not force a reset but wait for the consistency check to pass
_control_status.flags.gps_yaw = true;
fuseGpsYaw(gps_sample.yaw_offset);
}

if (_control_status.flags.gps_yaw) {
ECL_INFO("starting GPS yaw fusion");
}
}
}

} else if (_control_status.flags.gps_yaw
&& !isNewestSampleRecent(_time_last_gps_yaw_buffer_push, _params.reset_timeout_max)) {

// No yaw data in the message anymore. Stop until it comes back.
stopGpsYawFusion();
}
}

void Ekf::stopGpsYawFusion()
{
if (_control_status.flags.gps_yaw) {

_control_status.flags.gps_yaw = false;

ECL_INFO("stopping GPS yaw fusion");
}
}
#endif // CONFIG_EKF2_GNSS_YAW

void Ekf::stopGpsFusion()
{
if (_control_status.flags.gps) {
Expand All @@ -465,7 +367,7 @@ void Ekf::stopGpsFusion()

stopGpsHgtFusion();
#if defined(CONFIG_EKF2_GNSS_YAW)
stopGpsYawFusion();
stopGnssYawFusion();
#endif // CONFIG_EKF2_GNSS_YAW

_yawEstimator.reset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ void Ekf::controlMagFusion(const imuSample &imu_sample)
&& !_control_status.flags.mag_fault
&& !_control_status.flags.mag_field_disturbed
&& !_control_status.flags.ev_yaw
&& !_control_status.flags.gps_yaw;
&& !_control_status.flags.gnss_yaw;

_control_status.flags.mag_3D = common_conditions_passing
&& (_params.mag_fusion_type == MagFuseType::AUTO)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
void Ekf::controlZeroInnovationHeadingUpdate()
{
const bool yaw_aiding = _control_status.flags.mag_hdg || _control_status.flags.mag_3D
|| _control_status.flags.ev_yaw || _control_status.flags.gps_yaw;
|| _control_status.flags.ev_yaw || _control_status.flags.gnss_yaw;

// fuse zero innovation at a limited rate if the yaw variance is too large
if (!yaw_aiding
Expand Down
Loading

0 comments on commit 1cd7d54

Please sign in to comment.