diff --git a/EKF/ekf.cpp b/EKF/ekf.cpp index 9e7862ff83..4bac4bdd63 100644 --- a/EKF/ekf.cpp +++ b/EKF/ekf.cpp @@ -303,6 +303,15 @@ bool Ekf::update() } + // If we are using external vision aiding and data has fallen behind the fusion time horizon then fuse it + if (_ext_vision_buffer.pop_first_older_than(_imu_sample_delayed.time_us, &_ev_sample_delayed)) { + // use external vision posiiton and height observations + if (_control_status.flags.ev_pos) { + _fuse_pos = true; + _fuse_height = true; + } + } + // If we are using optical flow aiding and data has fallen behind the fusion time horizon, then fuse it if (_flow_buffer.pop_first_older_than(_imu_sample_delayed.time_us, &_flow_sample_delayed) && _control_status.flags.opt_flow && (_time_last_imu - _time_last_optflow) < 2e5 @@ -315,8 +324,6 @@ bool Ekf::update() if (!_control_status.flags.gps && !_control_status.flags.opt_flow && ((_time_last_imu - _time_last_fake_gps > 2e5) || _fuse_height)) { _fuse_pos = true; - _gps_sample_delayed.pos(0) = _last_known_posNE(0); - _gps_sample_delayed.pos(1) = _last_known_posNE(1); _time_last_fake_gps = _time_last_imu; } diff --git a/EKF/vel_pos_fusion.cpp b/EKF/vel_pos_fusion.cpp index 433b6eeb1a..c71e014b7d 100644 --- a/EKF/vel_pos_fusion.cpp +++ b/EKF/vel_pos_fusion.cpp @@ -83,24 +83,31 @@ void Ekf::fuseVelPosHeight() if (_fuse_pos) { fuse_map[3] = fuse_map[4] = true; - // horizontal position innovations - _vel_pos_innov[3] = _state.pos(0) - _gps_sample_delayed.pos(0); - _vel_pos_innov[4] = _state.pos(1) - _gps_sample_delayed.pos(1); - // observation variance - user parameter defined - // if we are in flight and not using GPS, then use a specific parameter - if (!_control_status.flags.gps) { + // Calculate innovations and observation variance depending on type of observations + // being used + if (!_control_status.flags.gps && !_control_status.flags.ev_pos) { + // No observations - use a static position to constrain drift if (_control_status.flags.in_air) { R[3] = fmaxf(_params.pos_noaid_noise, _params.gps_pos_noise); } else { R[3] = _params.gps_pos_noise; } + _vel_pos_innov[3] = _state.pos(0) - _last_known_posNE(0); + _vel_pos_innov[4] = _state.pos(1) - _last_known_posNE(1); - } else { + } else if (_control_status.flags.gps) { float lower_limit = fmaxf(_params.gps_pos_noise, 0.01f); float upper_limit = fmaxf(_params.pos_noaid_noise, lower_limit); R[3] = math::constrain(_gps_sample_delayed.hacc, lower_limit, upper_limit); + _vel_pos_innov[3] = _state.pos(0) - _gps_sample_delayed.pos(0); + _vel_pos_innov[4] = _state.pos(1) - _gps_sample_delayed.pos(1); + + } else if (_control_status.flags.ev_pos) { + R[3] = fmaxf(_ev_sample_delayed.posErr, 0.01f); + _vel_pos_innov[3] = _state.pos(0) - _ev_sample_delayed.posNED(0); + _vel_pos_innov[4] = _state.pos(1) - _ev_sample_delayed.posNED(1); } @@ -145,6 +152,15 @@ void Ekf::fuseVelPosHeight() R[5] = R[5] * R[5]; // innovation gate size gate_size[5] = fmaxf(_params.range_innov_gate, 1.0f); + } else if (_control_status.flags.ev_pos) { + fuse_map[5] = true; + // calculate the innovation assuming the external vision observaton is in local NED frame + _vel_pos_innov[5] = _state.pos(2) - _ev_sample_delayed.posNED(2); + // observation variance - defined externally + R[5] = fmaxf(_ev_sample_delayed.posErr, 0.01f); + R[5] = R[5] * R[5]; + // innovation gate size + gate_size[5] = fmaxf(_params.baro_innov_gate, 1.0f); } }