Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions boards/holybro/kakutef7/default.px4board
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ CONFIG_MODULES_EKF2=y
# CONFIG_EKF2_GNSS_YAW is not set
# CONFIG_EKF2_MAGNETOMETER is not set
# CONFIG_EKF2_RANGE_FINDER is not set
# CONFIG_EKF2_OPTICAL_FLOW is not set
# CONFIG_EKF2_SIDESLIP is not set
CONFIG_MODULES_FLIGHT_MODE_MANAGER=y
CONFIG_MODULES_LAND_DETECTOR=y
Expand Down
1 change: 1 addition & 0 deletions msg/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ set(msg_files
EstimatorBias.msg
EstimatorBias3d.msg
EstimatorEventFlags.msg
EstimatorFusionControl.msg
EstimatorGpsStatus.msg
EstimatorInnovations.msg
EstimatorSelectorStatus.msg
Expand Down
23 changes: 23 additions & 0 deletions msg/EstimatorFusionControl.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
uint64 timestamp # time since system start (microseconds)

# sensor intended for fusion (enabled via EKF2_SENS_EN AND CTRL param != disabled)
bool[2] gps_intended
bool of_intended
bool ev_intended
bool[4] agp_intended
bool baro_intended
bool rng_intended
bool mag_intended
bool aspd_intended
bool rngbcn_intended

# whether the estimator is actively fusing data from each source
bool[2] gps_active
bool of_active
bool ev_active
bool[4] agp_active
bool baro_active
bool rng_active
bool mag_active
bool aspd_active
bool rngbcn_active
11 changes: 11 additions & 0 deletions msg/versioned/VehicleCommand.msg
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@ uint16 VEHICLE_CMD_DO_WINCH = 42600 # Command to operate winch.

uint16 VEHICLE_CMD_EXTERNAL_POSITION_ESTIMATE = 43003 # External reset of estimator global position when dead reckoning.
uint16 VEHICLE_CMD_EXTERNAL_WIND_ESTIMATE = 43004
uint16 VEHICLE_CMD_ESTIMATOR_SENSOR_ENABLE = 43006 # Enable/disable estimator sensor fusion. |Source (FUSION_SOURCE_*)|Sensor instance (0-based)|Enable (1) or Disable (0)|Estimator Instance (NaN: not used)|Empty|Empty|Empty|
# Sensor fusion source types for VEHICLE_CMD_ESTIMATOR_SENSOR_ENABLE
uint8 FUSION_SOURCE_GPS = 0 # GNSS (EKF2_GPS{i}_CTRL, use instance param)
uint8 FUSION_SOURCE_OF = 1 # Optical Flow (EKF2_OF_CTRL)
uint8 FUSION_SOURCE_EV = 2 # External Vision (EKF2_EV_CTRL)
uint8 FUSION_SOURCE_AGP = 3 # Auxiliary Global Position (EKF2_AGP{i}_CTRL, use instance param)
uint8 FUSION_SOURCE_BARO = 4 # Barometer (EKF2_BARO_CTRL)
uint8 FUSION_SOURCE_RNG = 5 # Range Finder (EKF2_RNG_CTRL)
uint8 FUSION_SOURCE_MAG = 6 # Magnetometer (EKF2_MAG_TYPE)
uint8 FUSION_SOURCE_ASPD = 7 # Airspeed (EKF2_ARSP_THR)
uint8 FUSION_SOURCE_RNGBCN = 8 # Ranging Beacon

# PX4 vehicle commands (beyond 16 bit MAVLink commands).
uint32 VEHICLE_CMD_PX4_INTERNAL_START = 65537 # Start of PX4 internal only vehicle commands (> UINT16_MAX).
Expand Down
1 change: 1 addition & 0 deletions src/modules/commander/Commander.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1613,6 +1613,7 @@ Commander::handle_command(const vehicle_command_s &cmd)
case vehicle_command_s::VEHICLE_CMD_REQUEST_CAMERA_INFORMATION:
case vehicle_command_s::VEHICLE_CMD_EXTERNAL_ATTITUDE_ESTIMATE:
case vehicle_command_s::VEHICLE_CMD_DO_AUTOTUNE_ENABLE:
case vehicle_command_s::VEHICLE_CMD_ESTIMATOR_SENSOR_ENABLE:
/* ignore commands that are handled by other parts of the system */
break;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ void Ekf::controlAirDataFusion(const imuSample &imu_delayed)

#endif // CONFIG_EKF2_GNSS

if (_params.ekf2_arsp_thr <= 0.f) {
_fc.aspd.available = (_params.ekf2_arsp_thr > 0.f);

if (!_fc.aspd.intended()) {
stopAirspeedFusion();
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,19 @@ bool AuxGlobalPosition::anySourceFusing() const
return false;
}

uint8_t AuxGlobalPosition::sourceFusingBitmask() const
{
uint8_t mask = 0;

for (int i = 0; i < MAX_AGP_IDS; i++) {
if (_sources[i] && _sources[i]->isFusing()) {
mask |= (1u << i);
}
}

return mask;
}

int32_t AuxGlobalPosition::getAgpParamInt32(const char *param_suffix, int instance) const
{
char param_name[20] {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class AuxGlobalPosition : public ModuleParams
*/
float testRatioFiltered() const;
bool anySourceFusing() const;
uint8_t sourceFusingBitmask() const;
int32_t getIdParam(int instance);
void setIdParam(int instance, int32_t sensor_id);
int mapSensorIdToSlot(int32_t sensor_id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,13 @@ void AgpSource::bufferData(const aux_global_position_s &msg, const estimator::im

bool AgpSource::update(Ekf &ekf, const estimator::imuSample &imu_delayed)
{
ekf._fc.agp[_slot].available = (_params.ctrl != 0);

AuxGlobalPositionSample sample;

if (_buffer.pop_first_older_than(imu_delayed.time_us, &sample)) {

if (!(_params.ctrl & static_cast<int32_t>(Ctrl::kHPos))) {
if (!ekf._fc.agp[_slot].intended()) {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@

void Ekf::controlBaroHeightFusion(const imuSample &imu_sample)
{
_fc.baro.available = (_params.ekf2_baro_ctrl != 0);

static constexpr const char *HGT_SRC_NAME = "baro";

auto &aid_src = _aid_src_baro_hgt;
Expand Down Expand Up @@ -111,7 +113,7 @@ void Ekf::controlBaroHeightFusion(const imuSample &imu_sample)
}

// determine if we should use height aiding
const bool continuing_conditions_passing = (_params.ekf2_baro_ctrl == 1)
const bool continuing_conditions_passing = _fc.baro.intended()
&& measurement_valid
&& (_baro_counter > _obs_buffer_length)
&& !_control_status.flags.baro_fault;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@

void Ekf::controlExternalVisionFusion(const imuSample &imu_sample)
{
_fc.ev.available = (_params.ekf2_ev_ctrl != 0);

_ev_pos_b_est.predict(_dt_ekf_avg);
_ev_hgt_b_est.predict(_dt_ekf_avg);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ void Ekf::controlEvHeightFusion(const imuSample &imu_sample, const extVisionSamp
bias_est.fuseBias(measurement + _gpos.altitude(), measurement_var + P(State::pos.idx + 2, State::pos.idx + 2));
}

const bool continuing_conditions_passing = (_params.ekf2_ev_ctrl & static_cast<int32_t>(EvCtrl::VPOS))
const bool continuing_conditions_passing = _fc.ev.enabled && (_params.ekf2_ev_ctrl & static_cast<int32_t>(EvCtrl::VPOS))
&& measurement_valid;

const bool starting_conditions_passing = common_starting_conditions_passing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ void Ekf::controlEvPosFusion(const imuSample &imu_sample, const extVisionSample
|| (_control_status_prev.flags.yaw_align != _control_status.flags.yaw_align);

// determine if we should use EV position aiding
bool continuing_conditions_passing = (_params.ekf2_ev_ctrl & static_cast<int32_t>(EvCtrl::HPOS))
bool continuing_conditions_passing = _fc.ev.enabled && (_params.ekf2_ev_ctrl & static_cast<int32_t>(EvCtrl::HPOS))
&& _control_status.flags.tilt_align
&& PX4_ISFINITE(ev_sample.pos(0))
&& PX4_ISFINITE(ev_sample.pos(1));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void Ekf::controlEvVelFusion(ExternalVisionVel &ev, const bool common_starting_c
|| (_control_status_prev.flags.yaw_align != _control_status.flags.yaw_align);

// determine if we should use EV velocity aiding
bool continuing_conditions_passing = (_params.ekf2_ev_ctrl & static_cast<int32_t>(EvCtrl::VEL))
bool continuing_conditions_passing = _fc.ev.enabled && (_params.ekf2_ev_ctrl & static_cast<int32_t>(EvCtrl::VEL))
&& _control_status.flags.tilt_align
&& ev._sample.vel.isAllFinite()
&& !ev._sample.vel.longerThan(_params.ekf2_vel_lim);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void Ekf::controlEvYawFusion(const imuSample &imu_sample, const extVisionSample
}

// determine if we should use EV yaw aiding
bool continuing_conditions_passing = (_params.ekf2_ev_ctrl & static_cast<int32_t>(EvCtrl::YAW))
bool continuing_conditions_passing = _fc.ev.enabled && (_params.ekf2_ev_ctrl & static_cast<int32_t>(EvCtrl::YAW))
&& _control_status.flags.tilt_align
&& !_control_status.flags.ev_yaw_fault
&& PX4_ISFINITE(aid_src.observation)
Expand Down
4 changes: 3 additions & 1 deletion src/modules/ekf2/EKF/aid_sources/gnss/gps_control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@

void Ekf::controlGpsFusion(const imuSample &imu_delayed)
{
if (!_gps_buffer || (_params.ekf2_gps_ctrl == 0)) {
_fc.gps.available = (_params.ekf2_gps_ctrl != 0);

if (!_gps_buffer || !_fc.gps.intended()) {
stopGnssFusion();
return;
}
Expand Down
16 changes: 9 additions & 7 deletions src/modules/ekf2/EKF/aid_sources/magnetometer/mag_control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ void Ekf::controlMagFusion(const imuSample &imu_sample)
_control_status.flags.mag_aligned_in_flight = false;
}

if (_params.ekf2_mag_type == MagFuseType::NONE) {
_fc.mag.available = _params.ekf2_mag_type != static_cast<int32_t>(MagFuseType::NONE);

if (!_fc.mag.intended()) {
stopMagFusion();
return;
}
Expand Down Expand Up @@ -150,9 +152,9 @@ void Ekf::controlMagFusion(const imuSample &imu_sample)
math::max(_params.ekf2_mag_gate, 1.f)); // innovation gate

// determine if we should use mag fusion
bool continuing_conditions_passing = ((_params.ekf2_mag_type == MagFuseType::INIT)
|| (_params.ekf2_mag_type == MagFuseType::AUTO)
|| (_params.ekf2_mag_type == MagFuseType::HEADING))
bool continuing_conditions_passing = ((_params.ekf2_mag_type == static_cast<int32_t>(MagFuseType::INIT))
|| (_params.ekf2_mag_type == static_cast<int32_t>(MagFuseType::AUTO))
|| (_params.ekf2_mag_type == static_cast<int32_t>(MagFuseType::HEADING)))
&& _control_status.flags.tilt_align
&& (_control_status.flags.yaw_align || (!_control_status.flags.ev_yaw && !_control_status.flags.yaw_align))
&& mag_sample.mag.longerThan(0.f)
Expand Down Expand Up @@ -187,12 +189,12 @@ void Ekf::controlMagFusion(const imuSample &imu_sample)
&& (!_control_status.flags.yaw_manual || _control_status.flags.mag_aligned_in_flight);

_control_status.flags.mag_3D = common_conditions_passing
&& (_params.ekf2_mag_type == MagFuseType::AUTO)
&& (_params.ekf2_mag_type == static_cast<int32_t>(MagFuseType::AUTO))
&& _control_status.flags.mag_aligned_in_flight;

_control_status.flags.mag_hdg = common_conditions_passing
&& ((_params.ekf2_mag_type == MagFuseType::HEADING)
|| (_params.ekf2_mag_type == MagFuseType::AUTO && !_control_status.flags.mag_3D));
&& ((_params.ekf2_mag_type == static_cast<int32_t>(MagFuseType::HEADING))
|| (_params.ekf2_mag_type == static_cast<int32_t>(MagFuseType::AUTO) && !_control_status.flags.mag_3D));
}

if (_control_status.flags.mag_3D && !_control_status_prev.flags.mag_3D) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@

void Ekf::controlOpticalFlowFusion(const imuSample &imu_delayed)
{
if (!_flow_buffer || (_params.ekf2_of_ctrl != 1)) {
_fc.of.available = (_params.ekf2_of_ctrl != 0);

if (!_flow_buffer || !_fc.of.intended()) {
stopFlowFusion();
return;
}
Expand Down Expand Up @@ -146,7 +148,7 @@ void Ekf::controlOpticalFlowFusion(const imuSample &imu_delayed)
&& !flow_sample.flow_rate.longerThan(_flow_max_rate)
&& !flow_compensated.longerThan(_flow_max_rate);

const bool continuing_conditions_passing = (_params.ekf2_of_ctrl == 1)
const bool continuing_conditions_passing = _fc.of.intended()
&& _control_status.flags.tilt_align
&& is_within_sensor_dist;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@

void Ekf::controlRangeHaglFusion(const imuSample &imu_sample)
{
_fc.rng.available = (_params.ekf2_rng_ctrl != static_cast<int32_t>(RngCtrl::DISABLED));

static constexpr const char *HGT_SRC_NAME = "RNG";

bool rng_data_ready = false;
Expand Down Expand Up @@ -127,8 +129,7 @@ void Ekf::controlRangeHaglFusion(const imuSample &imu_sample)
aid_src.innovation_rejected = false;
}

const bool continuing_conditions_passing = ((_params.ekf2_rng_ctrl == static_cast<int32_t>(RngCtrl::ENABLED))
|| (_params.ekf2_rng_ctrl == static_cast<int32_t>(RngCtrl::CONDITIONAL)))
const bool continuing_conditions_passing = _fc.rng.intended()
&& _control_status.flags.tilt_align
&& measurement_valid;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@

void Ekf::controlRangingBeaconFusion(const imuSample &imu_delayed)
{
if (!_ranging_beacon_buffer || (_params.ekf2_rngbc_ctrl == 0)) {
_fc.rngbcn.available = (_params.ekf2_rngbc_ctrl != 0);

if (!_ranging_beacon_buffer || !_fc.rngbcn.intended()) {
stopRangingBeaconFusion();
return;
}
Expand Down
24 changes: 23 additions & 1 deletion src/modules/ekf2/EKF/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,27 @@ struct systemFlagUpdate {
bool in_transition{false};
};

// Runtime fusion control. Populated by EKF2 module, read by EKF core.
static constexpr uint8_t MAX_AGP_INSTANCES = 4;

struct FusionSensor {
bool enabled{false}; // runtime toggleable via MAVLink
bool available{false}; // CTRL-param != disabled-value (functions as factory-setting)
bool intended() const { return enabled && available; }
};

struct FusionControl {
FusionSensor gps;
FusionSensor of;
FusionSensor ev;
FusionSensor agp[MAX_AGP_INSTANCES];
FusionSensor baro;
FusionSensor rng;
FusionSensor mag;
FusionSensor aspd;
FusionSensor rngbcn;
};

struct parameters {

int32_t ekf2_predict_us{10000}; ///< filter update interval in microseconds
Expand All @@ -293,6 +314,7 @@ struct parameters {
float ekf2_vel_lim{100.f}; ///< velocity state limit (m/s)

// measurement source control
int32_t ekf2_sens_en{8191}; ///< sensor fusion enable bitmask (EKF2_SENS_EN)
int32_t ekf2_hgt_ref{static_cast<int32_t>(HeightSensor::BARO)};
int32_t position_sensor_ref{static_cast<int32_t>(PositionSensor::GNSS)};

Expand All @@ -319,7 +341,7 @@ struct parameters {

#if defined(CONFIG_EKF2_BAROMETER)
int32_t ekf2_baro_ctrl {1};
float ekf2_baro_delay{0.0f}; ///< barometer height measurement delay relative to the IMU (mSec)
float ekf2_baro_delay {0.0f}; ///< barometer height measurement delay relative to the IMU (mSec)
float ekf2_baro_noise{2.0f}; ///< observation noise for barometric height fusion (m)
float baro_bias_nsd{0.13f}; ///< process noise for barometric height bias estimation (m/s/sqrt(Hz))
float ekf2_baro_gate{5.0f}; ///< barometric and GPS height innovation consistency gate size (STD)
Expand Down
4 changes: 4 additions & 0 deletions src/modules/ekf2/EKF/ekf.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ class Ekf final : public EstimatorInterface
const Vector3f &getFlowRefBodyRate() const { return _ref_body_rate; }
#endif // CONFIG_EKF2_OPTICAL_FLOW

#if defined(CONFIG_EKF2_AUX_GLOBAL_POSITION) && defined(MODULE_NAME)
uint8_t getAgpFusingBitmask() const { return _aux_global_position.sourceFusingBitmask(); }
#endif // CONFIG_EKF2_AUX_GLOBAL_POSITION

float getHeadingInnov() const;
float getHeadingInnovVar() const;
float getHeadingInnovRatio() const;
Expand Down
4 changes: 2 additions & 2 deletions src/modules/ekf2/EKF/ekf_helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ void Ekf::updateHorizontalDeadReckoningstatus()
inertial_dead_reckoning = false;

} else {
if (!_control_status.flags.in_air && (_params.ekf2_of_ctrl == 1)
if (!_control_status.flags.in_air && _fc.of.intended()
&& isRecent(_aid_src_optical_flow.timestamp_sample, _params.no_aid_timeout_max)
) {
// currently landed, but optical flow aiding should be possible once in air
Expand All @@ -853,7 +853,7 @@ void Ekf::updateHorizontalDeadReckoningstatus()

if (!_control_status.flags.in_air && _control_status.flags.fixed_wing
&& (_params.ekf2_fuse_beta == 1)
&& (_params.ekf2_arsp_thr > 0.f) && isRecent(_aid_src_airspeed.timestamp_sample, _params.no_aid_timeout_max)
&& _fc.aspd.intended() && isRecent(_aid_src_airspeed.timestamp_sample, _params.no_aid_timeout_max)
) {
// currently landed, but air data aiding should be possible once in air
aiding_expected_in_air = true;
Expand Down
2 changes: 2 additions & 0 deletions src/modules/ekf2/EKF/estimator_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class EstimatorInterface
// return a address to the parameters struct
// in order to give access to the application
parameters *getParamHandle() { return &_params; }
FusionControl *getFusionControlHandle() { return &_fc; }

// set vehicle landed status data
void set_in_air_status(bool in_air)
Expand Down Expand Up @@ -336,6 +337,7 @@ class EstimatorInterface
virtual bool init(uint64_t timestamp) = 0;

parameters _params{}; // filter parameters
FusionControl _fc{};

/*
OBS_BUFFER_LENGTH defines how many observations (non-IMU measurements) we can buffer
Expand Down
Loading
Loading