mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-07-18 23:40:35 +08:00
ekf2: allow filter init with only IMU (#21041)
- if mag enabled heading init is now pushed to controlMagFusion()
This commit is contained in:
@@ -556,6 +556,12 @@ void Ekf::resetQuatCov()
|
||||
rot_vec_var.setAll(sq(_params.initial_tilt_err));
|
||||
|
||||
initialiseQuatCovariances(rot_vec_var);
|
||||
|
||||
// update the yaw angle variance using the variance of the measurement
|
||||
if (_params.mag_fusion_type <= MagFuseType::MAG_3D) {
|
||||
// using magnetic heading tuning parameter
|
||||
increaseQuatYawErrVariance(sq(fmaxf(_params.mag_heading_noise, 1.0e-2f)));
|
||||
}
|
||||
}
|
||||
|
||||
void Ekf::zeroQuatCov()
|
||||
|
||||
@@ -52,6 +52,8 @@ bool Ekf::init(uint64_t timestamp)
|
||||
|
||||
void Ekf::reset()
|
||||
{
|
||||
ECL_INFO("reset");
|
||||
|
||||
_state.vel.setZero();
|
||||
_state.pos.setZero();
|
||||
_state.delta_ang_bias.setZero();
|
||||
@@ -196,61 +198,13 @@ bool Ekf::initialiseFilter()
|
||||
_gyro_lpf.update(imu_init.delta_ang / imu_init.delta_ang_dt);
|
||||
}
|
||||
|
||||
// Sum the magnetometer measurements
|
||||
if (_mag_buffer) {
|
||||
magSample mag_sample;
|
||||
|
||||
if (_mag_buffer->pop_first_older_than(_time_delayed_us, &mag_sample)) {
|
||||
if (mag_sample.time_us != 0) {
|
||||
if (_mag_counter == 0) {
|
||||
_mag_lpf.reset(mag_sample.mag);
|
||||
|
||||
} else {
|
||||
_mag_lpf.update(mag_sample.mag);
|
||||
}
|
||||
|
||||
_mag_counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!initialiseTilt()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// calculate the initial magnetic field and yaw alignment
|
||||
// but do not mark the yaw alignement complete as it needs to be
|
||||
// reset once the leveling phase is done
|
||||
if (_params.mag_fusion_type <= MagFuseType::MAG_3D) {
|
||||
if (_mag_counter > 1) {
|
||||
// rotate the magnetometer measurements into earth frame using a zero yaw angle
|
||||
// the angle of the projection onto the horizontal gives the yaw angle
|
||||
const Vector3f mag_earth_pred = updateYawInRotMat(0.f, _R_to_earth) * _mag_lpf.getState();
|
||||
float yaw_new = -atan2f(mag_earth_pred(1), mag_earth_pred(0)) + getMagDeclination();
|
||||
|
||||
// update the rotation matrix using the new yaw value
|
||||
_R_to_earth = updateYawInRotMat(yaw_new, Dcmf(_state.quat_nominal));
|
||||
_state.quat_nominal = _R_to_earth;
|
||||
|
||||
// set the earth magnetic field states using the updated rotation
|
||||
_state.mag_I = _R_to_earth * _mag_lpf.getState();
|
||||
_state.mag_B.zero();
|
||||
|
||||
} else {
|
||||
// not enough mag samples accumulated
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// initialise the state covariance matrix now we have starting values for all the states
|
||||
initialiseCovariance();
|
||||
|
||||
// update the yaw angle variance using the variance of the measurement
|
||||
if (_params.mag_fusion_type <= MagFuseType::MAG_3D) {
|
||||
// using magnetic heading tuning parameter
|
||||
increaseQuatYawErrVariance(sq(fmaxf(_params.mag_heading_noise, 1.0e-2f)));
|
||||
}
|
||||
|
||||
// Initialise the terrain estimator
|
||||
initHagl();
|
||||
|
||||
|
||||
@@ -222,8 +222,7 @@ bool Ekf::resetMagHeading()
|
||||
|
||||
const Vector3f mag_init = _mag_lpf.getState();
|
||||
|
||||
const bool mag_available = (_mag_counter != 0) && isNewestSampleRecent(_time_last_mag_buffer_push, 500'000)
|
||||
&& !magFieldStrengthDisturbed(mag_init);
|
||||
const bool mag_available = (_mag_counter > 1) && !magFieldStrengthDisturbed(mag_init);
|
||||
|
||||
// low pass filtered mag required
|
||||
if (!mag_available) {
|
||||
@@ -244,7 +243,7 @@ bool Ekf::resetMagHeading()
|
||||
float yaw_new = -atan2f(mag_earth_pred(1), mag_earth_pred(0)) + getMagDeclination();
|
||||
float yaw_new_variance = sq(fmaxf(_params.mag_heading_noise, 1.e-2f));
|
||||
|
||||
ECL_INFO("reset mag heading %.3f -> %.3f rad", (double)getEulerYaw(_R_to_earth), (double)yaw_new);
|
||||
ECL_INFO("reset mag heading %.3f -> %.3f rad (declination %.1f)", (double)getEulerYaw(_R_to_earth), (double)yaw_new, (double)getMagDeclination());
|
||||
|
||||
// update quaternion states and corresponding covarainces
|
||||
resetQuatStateYaw(yaw_new, yaw_new_variance);
|
||||
|
||||
@@ -95,7 +95,7 @@ void Ekf::controlMagFusion()
|
||||
|
||||
resetEstimatorAidStatus(_aid_src_mag_heading);
|
||||
_aid_src_mag_heading.timestamp_sample = mag_sample.time_us;
|
||||
_aid_src_mag_heading.observation = -atan2f(mag_earth_pred(1), mag_earth_pred(0)) + getMagDeclination();;
|
||||
_aid_src_mag_heading.observation = -atan2f(mag_earth_pred(1), mag_earth_pred(0)) + getMagDeclination();
|
||||
_aid_src_mag_heading.innovation = wrap_pi(getEulerYaw(_R_to_earth) - _aid_src_mag_heading.observation);
|
||||
|
||||
// compute magnetometer innovations (for estimator_aid_src_mag logging)
|
||||
@@ -116,6 +116,45 @@ void Ekf::controlMagFusion()
|
||||
_control_status.flags.mag_aligned_in_flight = false;
|
||||
}
|
||||
|
||||
if (mag_data_ready && !_control_status.flags.tilt_align && !_control_status.flags.yaw_align) {
|
||||
// calculate the initial magnetic field and yaw alignment
|
||||
// but do not mark the yaw alignement complete as it needs to be
|
||||
// reset once the leveling phase is done
|
||||
if (_params.mag_fusion_type <= MagFuseType::MAG_3D) {
|
||||
if ((_mag_counter > 1) && isTimedOut(_aid_src_mag_heading.time_last_fuse, (uint64_t)100'000)) {
|
||||
// rotate the magnetometer measurements into earth frame using a zero yaw angle
|
||||
// the angle of the projection onto the horizontal gives the yaw angle
|
||||
const Vector3f mag_earth_pred = updateYawInRotMat(0.f, _R_to_earth) * _mag_lpf.getState();
|
||||
const float yaw_new = -atan2f(mag_earth_pred(1), mag_earth_pred(0)) + getMagDeclination();
|
||||
|
||||
const float yaw_prev = getEulerYaw(_R_to_earth);
|
||||
|
||||
if (fabsf(yaw_new - yaw_prev) > math::radians(1.f)) {
|
||||
|
||||
ECL_INFO("mag heading init %.3f -> %.3f rad (declination %.1f)", (double)yaw_prev, (double)yaw_new, (double)getMagDeclination());
|
||||
|
||||
// update the rotation matrix using the new yaw value
|
||||
_R_to_earth = updateYawInRotMat(yaw_new, Dcmf(_state.quat_nominal));
|
||||
_state.quat_nominal = _R_to_earth;
|
||||
|
||||
// reset the output predictor state history to match the EKF initial values
|
||||
_output_predictor.alignOutputFilter(_state.quat_nominal, _state.vel, _state.pos);
|
||||
|
||||
// set the earth magnetic field states using the updated rotation
|
||||
_state.mag_I = _R_to_earth * _mag_lpf.getState();
|
||||
_state.mag_B.zero();
|
||||
|
||||
_aid_src_mag_heading.time_last_fuse = _time_delayed_us;
|
||||
_time_last_heading_fuse = _time_delayed_us;
|
||||
|
||||
_last_static_yaw = NAN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (_params.mag_fusion_type >= MagFuseType::NONE
|
||||
|| _control_status.flags.mag_fault
|
||||
|| !_control_status.flags.tilt_align) {
|
||||
@@ -225,9 +264,9 @@ void Ekf::runInAirYawReset()
|
||||
bool has_realigned_yaw = false;
|
||||
|
||||
// use yaw estimator if available
|
||||
if (_control_status.flags.gps && isYawEmergencyEstimateAvailable() &&
|
||||
(_mag_counter != 0) && isNewestSampleRecent(_time_last_mag_buffer_push, 500'000) // mag LPF available
|
||||
) {
|
||||
if (_control_status.flags.gps && isYawEmergencyEstimateAvailable()
|
||||
&& (_mag_counter > 1) // mag LPF available
|
||||
) {
|
||||
|
||||
resetQuatStateYaw(_yawEstimator.getYaw(), _yawEstimator.getYawVar());
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ void Ekf::controlZeroInnovationHeadingUpdate()
|
||||
float obs_var = _control_status.flags.vehicle_at_rest ? 0.001f : 0.1f;
|
||||
estimator_aid_source1d_s unused;
|
||||
fuseYaw(innovation, obs_var, unused);
|
||||
|
||||
_time_last_heading_fuse = 0;
|
||||
_last_static_yaw = NAN;
|
||||
|
||||
} else if (_control_status.flags.vehicle_at_rest) {
|
||||
|
||||
Reference in New Issue
Block a user