px4-firmware/EKF/estimator_interface.h

595 lines
26 KiB
C
Raw Normal View History

2015-11-19 13:08:04 -04:00
/****************************************************************************
*
* Copyright (c) 2015 Estimation and Control Library (ECL). All rights reserved.
2015-11-19 13:08:04 -04:00
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name ECL nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file estimator_interface.h
2015-11-19 13:08:04 -04:00
* Definition of base class for attitude estimators
*
* @author Roman Bast <bapstroman@gmail.com>
2015-11-19 13:08:04 -04:00
*
*/
2018-08-30 12:48:38 -03:00
#pragma once
#include <ecl.h>
#include "common.h"
#include "RingBuffer.h"
[ekf] controlMagFusion refactor and mag field strength check (#662) * ekf_control: Inhibit mag fusion when field magnitude is large Move mag inhibition check in separate function * ekf_control: pull out of functionalities out of controlMagFusion - yaw abd mag bias observability checks - mag 3D conditions - load mag covariances - set and clear mag control modes * ekf_control: refactor mag heading/3D start/stop. Move mag declination, mag 3d and mag heading fusion out of the main function * ekf_control: extract mag yaw reset and mag declination fusion requirements * ekf_control: use WMM in isStronMagneticField for mag fusion inhibition - Correct units of WMM strength table * ekf_control: extract mag_state_only functionality of AUTOFW (VTOL custom) Also split inAirYawReset from onGroundYawReset * ekf_control: extract mag automatic selection - transform if-else into switch-case for parameter fusion type selection * ekf_control: extract run3DMagAndDeclFusion, reorganize functions, fix flag naming in Test script * ekf_control: do not run mag fusion if tilt is not aligned. Reset some variables on ground even if mag fusion is not running yet. It could be that it runs later so we need to make sure that those variables are properly set. * ekf_control: move controlMagFusion and related functions to mag_control.cpp * ekf control: check for validity of mag strength from WMM and falls back to average earth mag field with larger gate if not valid * ekf control: remove evyaw check for mag inhibition * ekf control: change nested ternary operator into if-else if * Ekf: create AlphaFilter template class for simple low-pass filtering 0.1/0.9 type low-pass filters are commonly used to smooth data, this class is meant to abstract the computation of this filter * ekf control: reset heading using mag_lpf data to avoid resetting on an outlier fixes ecl issue #525 * ekf control: replace mag_states_only flag with mag_field_disturbed and add parameter to enable or disable mag field strength check * ekf control: remove AUTOFW mag fusion type as not needed This was implemented for VTOL but did not solve the problem and should not be used anymore * ekf control: use start/stop mag functions everywhere instead of setting the flag * ekf control: Run mag fusion depending on yaw_align instead of tilt_align as there is no reason to fuse mag when the ekf isn't aligned * AlphaFilter: add test for float and Vector3f
2019-11-08 11:02:59 -04:00
#include "AlphaFilter.hpp"
#include "imu_down_sampler.hpp"
EKF: Add Emergency yaw recovery using EKF-GSF estimator (#766) * EKF: Use common rate vector calculation for offset corrections * EKF: Remove duplicate matrix entry calculations * EKF: Create a EKF-GSF yaw estimator class * EKF: add emergency yaw reset functionality * EKF: remove un-used function * EKF: Ensure required constants are defined for all builds * EKF: Fix CI build error * Revert "EKF: remove un-used function" This reverts commit 93005309c7f3794414ad99c86218b3062e00bbd3. * EKF: Replace in-lined Tait-Bryan 312 conversions with function call Also remove unnecessary operations * EKF: Remove unnecessary update of external vision rotation matrix * EKF: Use const * EKF: use const * EKF: don't use class variable as a temporary variable * EKF: update comments * EKF: Improve efficiency of yaw reset Use conversion from rotation matrix to Euler angles instead of quaternion to euler angles. * EKF: use const * EKF: remove un-used struct element * EKF: more descriptive function name * EKF: use existing matrix row operator * EKF: remove unnecessary rotation matrix update * EKF: Use square matrix type * EKF: Improve protection for bad innovation covariance * EKF: Use matrix library operations * EKF: Replace memcpy with better alternative memcpy bypasses compiler sanity checks and is unnecessary in this instance. * EKF: Split EKF-GSF yaw reset function Adds a common function to support yaw reset that can be used elsewhere. * EKF: Use common function for quaternion state and covariance yaw reset * EKF: Replace inlined matrix operation * EKF: Use const * EKF: Change accessor function name * EKF: Use const * EKF: Don't create unnecessary duplicate variable locations * EKF: Remove duplicate covariance innovation inverse * EKF: Don't create unnecessary duplicate variable locations * EKF: Rely on geo library to provide gravity * EKF: Improve protection from bad updates * EKF: Reduce effect of vibration on yaw estimator AHRS * EKF: Improve yaw estimator AHRS accuracy during manoeuvre transients
2020-03-05 06:50:52 -04:00
#include "EKFGSF_yaw.h"
Range check cleanup (#782) * EKF: centralize range finder tilt check * Ekf-control: do not double check for terrain estimate validity isRangeAidSuitable can only return true if the terrain estimate is valid so there is no need for an additional check * range_finder_checks: restructure the checks to avoid early returns There is now only one clear path that can lead to the validity being true. Furthermore, if the _rng_hgt_valid is true, we can trust it and we don't need for additional checks such as tilt. The case where we need to provide fake measurements because the drone is on the ground and the range finder data is bad is already handled in "controlHeightFusion" so there is no need to hack the range finder checks with that. * Add Sensor and SensorRangeFinder classes The purpose is to encapsulate the checks for each sensor in a dedicated class with the same interface * SensorRangeFinder: encapsulate in estimator::sensor namespace * EKF: rename _sensor_rng to _range_sensor * Range checks: include limits in valid range * RangeChecks: update comment in the continuity checks * RangeChecks: move more low-level checks in functions Also move setTilt out of the terrain estimator, this is anyway protected internally to not compute cos/sin if the parameter did not change. * Sensor: remove unused virtual functions Those are not required yet but can still be added later * SensorRangeFinder: re-organise member variables Also rename getRangeToEarth to getCosTilt * SensorRangeFinder: split setSensorTilt and setCosMaxTilt functions * SensorRangeFinder: Add a few unit tests - good data - tilt exceeded - max range exceeded * SensorRangeFinder: set hysteresis in us instead of ms * SensorRangeFinder: Add more tests * SensorRangeFinder: update continuity, hysteresis and stuck tests * SensorRangeFinder: rename variables * SensorRangeFinder: get rid of "delayed" specification From the SensorRangeFinder class point of view, it's not relevant to know if the data is delayed or not * SensorRangeFinder: move time_last_valid out of stuck check * SensorRangeFinder: rename file names to sensor_range_finder * SensorRangeFinder: address Kamil's comments * SensorRangeFinder: Add more tilt tests * SensorRangeFinder: store current tilt offset This is to avoid recomputing cos/sin functions at each loop
2020-04-03 03:28:07 -03:00
#include "sensor_range_finder.hpp"
#include <geo/geo.h>
2018-05-03 14:07:56 -03:00
#include <matrix/math.hpp>
#include <mathlib/mathlib.h>
2015-12-26 02:14:57 -04:00
using namespace estimator;
2017-04-24 18:29:54 -03:00
class EstimatorInterface
2015-11-19 13:08:04 -04:00
{
2015-11-19 13:08:04 -04:00
public:
EstimatorInterface():_imu_down_sampler(FILTER_UPDATE_PERIOD_S){};
virtual ~EstimatorInterface() = default;
2015-11-19 13:08:04 -04:00
virtual bool init(uint64_t timestamp) = 0;
virtual void reset() = 0;
virtual bool update() = 0;
2020-02-13 15:51:29 -04:00
virtual void getGpsVelPosInnov(float hvel[2], float &vvel, float hpos[2], float &vpos) const = 0;
virtual void getGpsVelPosInnovVar(float hvel[2], float &vvel, float hpos[2], float &vpos) const = 0;
virtual void getGpsVelPosInnovRatio(float &hvel, float &vvel, float &hpos, float &vpos) const = 0;
2020-02-13 15:51:29 -04:00
virtual void getEvVelPosInnov(float hvel[2], float &vvel, float hpos[2], float &vpos) const = 0;
virtual void getEvVelPosInnovVar(float hvel[2], float &vvel, float hpos[2], float &vpos) const = 0;
virtual void getEvVelPosInnovRatio(float &hvel, float &vvel, float &hpos, float &vpos) const = 0;
2020-02-13 15:51:29 -04:00
virtual void getBaroHgtInnov(float &baro_hgt_innov) const = 0;
virtual void getBaroHgtInnovVar(float &baro_hgt_innov_var) const = 0;
virtual void getBaroHgtInnovRatio(float &baro_hgt_innov_ratio) const = 0;
2019-12-03 07:58:24 -04:00
2020-02-13 15:51:29 -04:00
virtual void getRngHgtInnov(float &rng_hgt_innov) const = 0;
virtual void getRngHgtInnovVar(float &rng_hgt_innov_var) const = 0;
virtual void getRngHgtInnovRatio(float &rng_hgt_innov_ratio) const = 0;
2019-12-03 07:58:24 -04:00
2020-02-13 15:51:29 -04:00
virtual void getAuxVelInnov(float aux_vel_innov[2]) const = 0;
virtual void getAuxVelInnovVar(float aux_vel_innov[2]) const = 0;
virtual void getAuxVelInnovRatio(float &aux_vel_innov_ratio) const = 0;
2019-10-15 09:51:17 -03:00
2020-02-13 15:51:29 -04:00
virtual void getFlowInnov(float flow_innov[2]) const = 0;
virtual void getFlowInnovVar(float flow_innov_var[2]) const = 0;
virtual void getFlowInnovRatio(float &flow_innov_ratio) const = 0;
2019-10-15 09:51:17 -03:00
2020-02-13 15:51:29 -04:00
virtual void getHeadingInnov(float &heading_innov) const = 0;
virtual void getHeadingInnovVar(float &heading_innov_var) const = 0;
virtual void getHeadingInnovRatio(float &heading_innov_ratio) const = 0;
2020-02-13 15:51:29 -04:00
virtual void getMagInnov(float mag_innov[3]) const = 0;
virtual void getMagInnovVar(float mag_innov_var[3]) const = 0;
virtual void getMagInnovRatio(float &mag_innov_ratio) const = 0;
2019-10-15 09:51:17 -03:00
2020-02-13 15:51:29 -04:00
virtual void getDragInnov(float drag_innov[2]) const = 0;
virtual void getDragInnovVar(float drag_innov_var[2]) const = 0;
virtual void getDragInnovRatio(float drag_innov_ratio[2]) const = 0;
2020-02-13 15:51:29 -04:00
virtual void getAirspeedInnov(float &airspeed_innov) const = 0;
virtual void getAirspeedInnovVar(float &get_airspeed_innov_var) const = 0;
virtual void getAirspeedInnovRatio(float &airspeed_innov_ratio) const = 0;
2016-03-11 07:57:14 -04:00
2020-02-13 15:51:29 -04:00
virtual void getBetaInnov(float &beta_innov) const = 0;
virtual void getBetaInnovVar(float &get_beta_innov_var) const = 0;
virtual void getBetaInnovRatio(float &beta_innov_ratio) const = 0;
2016-07-12 13:48:42 -03:00
2020-02-13 15:51:29 -04:00
virtual void getHaglInnov(float &hagl_innov) const = 0;
virtual void getHaglInnovVar(float &hagl_innov_var) const = 0;
virtual void getHaglInnovRatio(float &hagl_innov_ratio) const = 0;
virtual matrix::Vector<float, 24> getStateAtFusionHorizonAsVector() const = 0;
virtual Vector2f getWindVelocity() const = 0;
2017-08-06 20:19:48 -03:00
virtual Vector2f getWindVelocityVariance() const = 0;
2017-08-06 20:19:48 -03:00
virtual void get_true_airspeed(float *tas) = 0;
2016-07-12 06:40:41 -03:00
// return an array containing the output predictor angular, velocity and position tracking
// error magnitudes (rad), (m/s), (m)
virtual Vector3f getOutputTrackingError() const = 0;
/*
Returns following IMU vibration metrics in the following array locations
0 : Gyro delta angle coning metric = filtered length of (delta_angle x prev_delta_angle)
1 : Gyro high frequency vibe = filtered length of (delta_angle - prev_delta_angle)
2 : Accel high frequency vibe = filtered length of (delta_velocity - prev_delta_velocity)
*/
virtual Vector3f getImuVibrationMetrics() const = 0;
/*
First argument returns GPS drift metrics in the following array locations
0 : Horizontal position drift rate (m/s)
1 : Vertical position drift rate (m/s)
2 : Filtered horizontal velocity (m/s)
Second argument returns true when IMU movement is blocking the drift calculation
Function returns true if the metrics have been updated and not returned previously by this function
*/
virtual bool get_gps_drift_metrics(float drift[3], bool *blocked) = 0;
// get the ekf WGS-84 origin position and height and the system time it was last set
// return true if the origin is valid
virtual bool get_ekf_origin(uint64_t *origin_time, map_projection_reference_s *origin_pos, float *origin_alt) = 0;
// get the 1-sigma horizontal and vertical position uncertainty of the ekf WGS-84 position
virtual void get_ekf_gpos_accuracy(float *ekf_eph, float *ekf_epv) = 0;
// get the 1-sigma horizontal and vertical position uncertainty of the ekf local position
virtual void get_ekf_lpos_accuracy(float *ekf_eph, float *ekf_epv) = 0;
// get the 1-sigma horizontal and vertical velocity uncertainty
virtual void get_ekf_vel_accuracy(float *ekf_evh, float *ekf_evv) = 0;
// get the vehicle control limits required by the estimator to keep within sensor limitations
virtual void get_ekf_ctrl_limits(float *vxy_max, float *vz_max, float *hagl_min, float *hagl_max) = 0;
2016-01-31 04:01:44 -04:00
// ask estimator for sensor data collection decision and do any preprocessing if required, returns true if not defined
virtual bool collect_gps(const gps_message &gps) = 0;
void setIMUData(const imuSample &imu_sample);
2015-11-19 13:08:04 -04:00
2020-01-21 09:49:19 -04:00
void setMagData(const magSample &mag_sample);
2015-11-19 13:08:04 -04:00
2020-01-21 09:45:31 -04:00
void setGpsData(const gps_message &gps);
2015-11-19 13:08:04 -04:00
2020-01-21 09:47:43 -04:00
void setBaroData(const baroSample &baro_sample);
2015-11-19 13:08:04 -04:00
2020-01-21 09:48:37 -04:00
void setAirspeedData(const airspeedSample &airspeed_sample);
2015-11-19 13:08:04 -04:00
2020-01-21 09:49:49 -04:00
void setRangeData(const rangeSample& range_sample);
2015-11-19 13:08:04 -04:00
2020-01-23 12:46:21 -04:00
// if optical flow sensor gyro delta angles are not available, set gyro_xyz vector fields to NaN and the EKF will use its internal delta angle data instead
void setOpticalFlowData(const flowSample& flow);
2015-11-19 13:08:04 -04:00
// set external vision position and attitude data
2020-01-20 10:26:07 -04:00
void setExtVisionData(const extVisionSample& evdata);
2020-01-21 09:50:21 -04:00
void setAuxVelData(const auxVelSample& auxvel_sample);
2015-12-26 02:14:57 -04:00
// return a address to the parameters struct
// in order to give access to the application
parameters *getParamHandle() {return &_params;}
2016-01-28 06:52:39 -04:00
// set vehicle landed status data
void set_in_air_status(bool in_air) {_control_status.flags.in_air = in_air;}
/*
Reset all IMU bias states and covariances to initial alignment values.
Use when the IMU sensor has changed.
Returns true if reset performed, false if rejected due to less than 10 seconds lapsed since last reset.
*/
virtual bool reset_imu_bias() = 0;
// return true if the attitude is usable
bool attitude_valid() { return ISFINITE(_output_new.quat_nominal(0)) && _control_status.flags.tilt_align; }
2017-10-03 12:44:11 -03:00
// get vehicle landed status data
bool get_in_air_status() {return _control_status.flags.in_air;}
// get wind estimation status
bool get_wind_status() { return _control_status.flags.wind; }
// set vehicle is fixed wing status
void set_is_fixed_wing(bool is_fixed_wing) {_control_status.flags.fixed_wing = is_fixed_wing;}
2016-07-12 13:48:42 -03:00
// set flag if synthetic sideslip measurement should be fused
void set_fuse_beta_flag(bool fuse_beta) {_control_status.flags.fuse_beta = (fuse_beta && _control_status.flags.in_air);}
2016-07-12 13:48:42 -03:00
// set flag if static pressure rise due to ground effect is expected
// use _params.gnd_effect_deadzone to adjust for expected rise in static pressure
// flag will clear after GNDEFFECT_TIMEOUT uSec
void set_gnd_effect_flag(bool gnd_effect)
{
_control_status.flags.gnd_effect = gnd_effect;
_time_last_gnd_effect_on = _time_last_imu;
}
// set air density used by the multi-rotor specific drag force fusion
void set_air_density(float air_density) {_air_density = air_density;}
// set sensor limitations reported by the rangefinder
void set_rangefinder_limits(float min_distance, float max_distance)
{
Range check cleanup (#782) * EKF: centralize range finder tilt check * Ekf-control: do not double check for terrain estimate validity isRangeAidSuitable can only return true if the terrain estimate is valid so there is no need for an additional check * range_finder_checks: restructure the checks to avoid early returns There is now only one clear path that can lead to the validity being true. Furthermore, if the _rng_hgt_valid is true, we can trust it and we don't need for additional checks such as tilt. The case where we need to provide fake measurements because the drone is on the ground and the range finder data is bad is already handled in "controlHeightFusion" so there is no need to hack the range finder checks with that. * Add Sensor and SensorRangeFinder classes The purpose is to encapsulate the checks for each sensor in a dedicated class with the same interface * SensorRangeFinder: encapsulate in estimator::sensor namespace * EKF: rename _sensor_rng to _range_sensor * Range checks: include limits in valid range * RangeChecks: update comment in the continuity checks * RangeChecks: move more low-level checks in functions Also move setTilt out of the terrain estimator, this is anyway protected internally to not compute cos/sin if the parameter did not change. * Sensor: remove unused virtual functions Those are not required yet but can still be added later * SensorRangeFinder: re-organise member variables Also rename getRangeToEarth to getCosTilt * SensorRangeFinder: split setSensorTilt and setCosMaxTilt functions * SensorRangeFinder: Add a few unit tests - good data - tilt exceeded - max range exceeded * SensorRangeFinder: set hysteresis in us instead of ms * SensorRangeFinder: Add more tests * SensorRangeFinder: update continuity, hysteresis and stuck tests * SensorRangeFinder: rename variables * SensorRangeFinder: get rid of "delayed" specification From the SensorRangeFinder class point of view, it's not relevant to know if the data is delayed or not * SensorRangeFinder: move time_last_valid out of stuck check * SensorRangeFinder: rename file names to sensor_range_finder * SensorRangeFinder: address Kamil's comments * SensorRangeFinder: Add more tilt tests * SensorRangeFinder: store current tilt offset This is to avoid recomputing cos/sin functions at each loop
2020-04-03 03:28:07 -03:00
_range_sensor.setLimits(min_distance, max_distance);
}
// set sensor limitations reported by the optical flow sensor
void set_optical_flow_limits(float max_flow_rate, float min_distance, float max_distance)
{
_flow_max_rate = max_flow_rate;
_flow_min_distance = min_distance;
_flow_max_distance = max_distance;
}
// return true if the global position estimate is valid
virtual bool global_position_is_valid() = 0;
// the flags considered are opt_flow, gps, ev_vel and ev_pos
bool isOnlyActiveSourceOfHorizontalAiding(bool aiding_flag) const;
/*
* Check if there are any other active source of horizontal aiding
* Warning: does not tell if the selected source is
* active, use isOnlyActiveSourceOfHorizontalAiding() for this
*
* The flags considered are opt_flow, gps, ev_vel and ev_pos
*
* @param aiding_flag a flag in _control_status.flags
* @return true if an other source than aiding_flag is active
*/
bool isOtherSourceOfHorizontalAidingThan(bool aiding_flag) const;
// Return true if at least one source of horizontal aiding is active
// the flags considered are opt_flow, gps, ev_vel and ev_pos
bool isHorizontalAidingActive() const;
int getNumberOfActiveHorizontalAidingSources() const;
// return true if the EKF is dead reckoning the position using inertial data only
bool inertial_dead_reckoning() {return _is_dead_reckoning;}
[ekf] controlMagFusion refactor and mag field strength check (#662) * ekf_control: Inhibit mag fusion when field magnitude is large Move mag inhibition check in separate function * ekf_control: pull out of functionalities out of controlMagFusion - yaw abd mag bias observability checks - mag 3D conditions - load mag covariances - set and clear mag control modes * ekf_control: refactor mag heading/3D start/stop. Move mag declination, mag 3d and mag heading fusion out of the main function * ekf_control: extract mag yaw reset and mag declination fusion requirements * ekf_control: use WMM in isStronMagneticField for mag fusion inhibition - Correct units of WMM strength table * ekf_control: extract mag_state_only functionality of AUTOFW (VTOL custom) Also split inAirYawReset from onGroundYawReset * ekf_control: extract mag automatic selection - transform if-else into switch-case for parameter fusion type selection * ekf_control: extract run3DMagAndDeclFusion, reorganize functions, fix flag naming in Test script * ekf_control: do not run mag fusion if tilt is not aligned. Reset some variables on ground even if mag fusion is not running yet. It could be that it runs later so we need to make sure that those variables are properly set. * ekf_control: move controlMagFusion and related functions to mag_control.cpp * ekf control: check for validity of mag strength from WMM and falls back to average earth mag field with larger gate if not valid * ekf control: remove evyaw check for mag inhibition * ekf control: change nested ternary operator into if-else if * Ekf: create AlphaFilter template class for simple low-pass filtering 0.1/0.9 type low-pass filters are commonly used to smooth data, this class is meant to abstract the computation of this filter * ekf control: reset heading using mag_lpf data to avoid resetting on an outlier fixes ecl issue #525 * ekf control: replace mag_states_only flag with mag_field_disturbed and add parameter to enable or disable mag field strength check * ekf control: remove AUTOFW mag fusion type as not needed This was implemented for VTOL but did not solve the problem and should not be used anymore * ekf control: use start/stop mag functions everywhere instead of setting the flag * ekf control: Run mag fusion depending on yaw_align instead of tilt_align as there is no reason to fuse mag when the ekf isn't aligned * AlphaFilter: add test for float and Vector3f
2019-11-08 11:02:59 -04:00
virtual bool isTerrainEstimateValid() const = 0;
//[[deprecated("Replaced by isTerrainEstimateValid")]]
bool get_terrain_valid() { return isTerrainEstimateValid(); }
virtual uint8_t getTerrainEstimateSensorBitfield() const = 0;
// get the estimated terrain vertical position relative to the NED origin
virtual float getTerrainVertPos() const = 0;
// return true if the local position estimate is valid
bool local_position_is_valid();
2015-11-19 13:08:04 -04:00
const matrix::Quatf getQuaternion() const { return _output_new.quat_nominal; }
2018-11-14 15:46:04 -04:00
// return the quaternion defining the rotation from the EKF to the External Vision reference frame
virtual matrix::Quatf getVisionAlignmentQuaternion() const = 0;
2016-04-09 16:46:27 -03:00
// get the velocity of the body frame origin in local NED earth frame
Vector3f getVelocity() const
{
const Vector3f vel_earth = _output_new.vel - _vel_imu_rel_body_ned;
return vel_earth;
}
virtual Vector3f getVelocityVariance() const = 0;
// get the velocity derivative in earth frame
Vector3f getVelocityDerivative() const
{
return _vel_deriv;
}
// get the derivative of the vertical position of the body frame origin in local NED earth frame
float getVerticalPositionDerivative() const
{
return _output_vert_new.vert_vel - _vel_imu_rel_body_ned(2);
}
// get the position of the body frame origin in local earth frame
Vector3f getPosition() const
{
2016-04-09 16:46:27 -03:00
// rotate the position of the IMU relative to the boy origin into earth frame
const Vector3f pos_offset_earth = _R_to_earth_now * _params.imu_pos_body;
2016-04-09 16:46:27 -03:00
// subtract from the EKF position (which is at the IMU) to get position at the body origin
return _output_new.pos - pos_offset_earth;
}
virtual Vector3f getPositionVariance() const = 0;
// Get the value of magnetic declination in degrees to be saved for use at the next startup
// Returns true when the declination can be saved
// At the next startup, set param.mag_declination_deg to the value saved
bool get_mag_decl_deg(float *val)
{
*val = 0.0f;
if (_NED_origin_initialised && (_params.mag_declination_source & MASK_SAVE_GEO_DECL)) {
*val = math::degrees(_mag_declination_gps);
return true;
} else {
return false;
}
}
virtual Vector3f getAccelBias() const = 0;
virtual Vector3f getGyroBias() const = 0;
2016-04-15 23:41:50 -03:00
// get EKF mode status
void get_control_mode(uint32_t *val)
2016-04-15 23:41:50 -03:00
{
*val = _control_status.value;
}
// get EKF internal fault status
void get_filter_fault_status(uint16_t *val)
{
*val = _fault_status.value;
}
2020-02-10 12:14:27 -04:00
bool isVehicleAtRest() const { return _control_status.flags.vehicle_at_rest; }
2016-04-16 00:38:40 -03:00
// get GPS check status
virtual void get_gps_check_status(uint16_t *val) = 0;
// return the amount the local vertical position changed in the last reset and the number of reset events
virtual void get_posD_reset(float *delta, uint8_t *counter) = 0;
// return the amount the local vertical velocity changed in the last reset and the number of reset events
virtual void get_velD_reset(float *delta, uint8_t *counter) = 0;
// return the amount the local horizontal position changed in the last reset and the number of reset events
virtual void get_posNE_reset(float delta[2], uint8_t *counter) = 0;
// return the amount the local horizontal velocity changed in the last reset and the number of reset events
virtual void get_velNE_reset(float delta[2], uint8_t *counter) = 0;
// return the amount the quaternion has changed in the last reset and the number of reset events
virtual void get_quat_reset(float delta_quat[4], uint8_t *counter) = 0;
2016-10-05 02:52:21 -03:00
// get EKF innovation consistency check status information comprising of:
// status - a bitmask integer containing the pass/fail status for each EKF measurement innovation consistency check
// Innovation Test Ratios - these are the ratio of the innovation to the acceptance threshold.
// A value > 1 indicates that the sensor measurement has exceeded the maximum acceptable level and has been rejected by the EKF
// Where a measurement type is a vector quantity, eg magnetometer, GPS position, etc, the maximum value is returned.
2019-11-20 09:33:11 -04:00
virtual void get_innovation_test_status(uint16_t &status, float &mag, float &vel, float &pos, float &hgt, float &tas, float &hagl, float &beta) = 0;
2016-10-05 02:52:21 -03:00
// return a bitmask integer that describes which state estimates can be used for flight control
virtual void get_ekf_soln_status(uint16_t *status) = 0;
// Getter for the average imu update period in s
float get_dt_imu_avg() const { return _dt_imu_avg; }
// Getter for the imu sample on the delayed time horizon
imuSample get_imu_sample_delayed()
{
return _imu_sample_delayed;
}
// Getter for the baro sample on the delayed time horizon
baroSample get_baro_sample_delayed()
{
return _baro_sample_delayed;
}
void print_status();
static constexpr unsigned FILTER_UPDATE_PERIOD_MS{10}; // ekf prediction period in milliseconds - this should ideally be an integer multiple of the IMU time delta
static constexpr float FILTER_UPDATE_PERIOD_S{FILTER_UPDATE_PERIOD_MS * 0.001f};
EKF: Add Emergency yaw recovery using EKF-GSF estimator (#766) * EKF: Use common rate vector calculation for offset corrections * EKF: Remove duplicate matrix entry calculations * EKF: Create a EKF-GSF yaw estimator class * EKF: add emergency yaw reset functionality * EKF: remove un-used function * EKF: Ensure required constants are defined for all builds * EKF: Fix CI build error * Revert "EKF: remove un-used function" This reverts commit 93005309c7f3794414ad99c86218b3062e00bbd3. * EKF: Replace in-lined Tait-Bryan 312 conversions with function call Also remove unnecessary operations * EKF: Remove unnecessary update of external vision rotation matrix * EKF: Use const * EKF: use const * EKF: don't use class variable as a temporary variable * EKF: update comments * EKF: Improve efficiency of yaw reset Use conversion from rotation matrix to Euler angles instead of quaternion to euler angles. * EKF: use const * EKF: remove un-used struct element * EKF: more descriptive function name * EKF: use existing matrix row operator * EKF: remove unnecessary rotation matrix update * EKF: Use square matrix type * EKF: Improve protection for bad innovation covariance * EKF: Use matrix library operations * EKF: Replace memcpy with better alternative memcpy bypasses compiler sanity checks and is unnecessary in this instance. * EKF: Split EKF-GSF yaw reset function Adds a common function to support yaw reset that can be used elsewhere. * EKF: Use common function for quaternion state and covariance yaw reset * EKF: Replace inlined matrix operation * EKF: Use const * EKF: Change accessor function name * EKF: Use const * EKF: Don't create unnecessary duplicate variable locations * EKF: Remove duplicate covariance innovation inverse * EKF: Don't create unnecessary duplicate variable locations * EKF: Rely on geo library to provide gravity * EKF: Improve protection from bad updates * EKF: Reduce effect of vibration on yaw estimator AHRS * EKF: Improve yaw estimator AHRS accuracy during manoeuvre transients
2020-03-05 06:50:52 -04:00
// request the EKF reset the yaw to the estimate from the internal EKF-GSF filter
// argment should be incremented only when a new reset is required
virtual void requestEmergencyNavReset() = 0;
EKF: Add Emergency yaw recovery using EKF-GSF estimator (#766) * EKF: Use common rate vector calculation for offset corrections * EKF: Remove duplicate matrix entry calculations * EKF: Create a EKF-GSF yaw estimator class * EKF: add emergency yaw reset functionality * EKF: remove un-used function * EKF: Ensure required constants are defined for all builds * EKF: Fix CI build error * Revert "EKF: remove un-used function" This reverts commit 93005309c7f3794414ad99c86218b3062e00bbd3. * EKF: Replace in-lined Tait-Bryan 312 conversions with function call Also remove unnecessary operations * EKF: Remove unnecessary update of external vision rotation matrix * EKF: Use const * EKF: use const * EKF: don't use class variable as a temporary variable * EKF: update comments * EKF: Improve efficiency of yaw reset Use conversion from rotation matrix to Euler angles instead of quaternion to euler angles. * EKF: use const * EKF: remove un-used struct element * EKF: more descriptive function name * EKF: use existing matrix row operator * EKF: remove unnecessary rotation matrix update * EKF: Use square matrix type * EKF: Improve protection for bad innovation covariance * EKF: Use matrix library operations * EKF: Replace memcpy with better alternative memcpy bypasses compiler sanity checks and is unnecessary in this instance. * EKF: Split EKF-GSF yaw reset function Adds a common function to support yaw reset that can be used elsewhere. * EKF: Use common function for quaternion state and covariance yaw reset * EKF: Replace inlined matrix operation * EKF: Use const * EKF: Change accessor function name * EKF: Use const * EKF: Don't create unnecessary duplicate variable locations * EKF: Remove duplicate covariance innovation inverse * EKF: Don't create unnecessary duplicate variable locations * EKF: Rely on geo library to provide gravity * EKF: Improve protection from bad updates * EKF: Reduce effect of vibration on yaw estimator AHRS * EKF: Improve yaw estimator AHRS accuracy during manoeuvre transients
2020-03-05 06:50:52 -04:00
// get ekf-gsf debug data
virtual bool getDataEKFGSF(float *yaw_composite, float *yaw_variance, float yaw[N_MODELS_EKFGSF], float innov_VN[N_MODELS_EKFGSF], float innov_VE[N_MODELS_EKFGSF], float weight[N_MODELS_EKFGSF]) = 0;
protected:
2015-11-19 13:08:04 -04:00
parameters _params; // filter parameters
2015-11-19 13:08:04 -04:00
ImuDownSampler _imu_down_sampler;
/*
OBS_BUFFER_LENGTH defines how many observations (non-IMU measurements) we can buffer
which sets the maximum frequency at which we can process non-IMU measurements. Measurements that
arrive too soon after the previous measurement will not be processed.
max freq (Hz) = (OBS_BUFFER_LENGTH - 1) / (IMU_BUFFER_LENGTH * FILTER_UPDATE_PERIOD_S)
This can be adjusted to match the max sensor data rate plus some margin for jitter.
*/
2017-04-24 18:29:54 -03:00
uint8_t _obs_buffer_length{0};
/*
IMU_BUFFER_LENGTH defines how many IMU samples we buffer which sets the time delay from current time to the
EKF fusion time horizon and therefore the maximum sensor time offset relative to the IMU that we can compensate for.
max sensor time offet (msec) = IMU_BUFFER_LENGTH * FILTER_UPDATE_PERIOD_MS
This can be adjusted to a value that is FILTER_UPDATE_PERIOD_MS longer than the maximum observation time delay.
*/
2017-04-24 18:29:54 -03:00
uint8_t _imu_buffer_length{0};
2015-11-19 13:08:04 -04:00
2017-04-24 18:29:54 -03:00
unsigned _min_obs_interval_us{0}; // minimum time interval between observations that will guarantee data is not lost (usec)
2017-04-24 18:29:54 -03:00
float _dt_imu_avg{0.0f}; // average imu update period in s
2015-11-19 13:08:04 -04:00
2017-04-24 18:29:54 -03:00
imuSample _imu_sample_delayed{}; // captures the imu sample on the delayed time horizon
2015-11-19 13:08:04 -04:00
// measurement samples capturing measurements on the delayed time horizon
2017-04-24 18:29:54 -03:00
magSample _mag_sample_delayed{};
baroSample _baro_sample_delayed{};
gpsSample _gps_sample_delayed{};
Range check cleanup (#782) * EKF: centralize range finder tilt check * Ekf-control: do not double check for terrain estimate validity isRangeAidSuitable can only return true if the terrain estimate is valid so there is no need for an additional check * range_finder_checks: restructure the checks to avoid early returns There is now only one clear path that can lead to the validity being true. Furthermore, if the _rng_hgt_valid is true, we can trust it and we don't need for additional checks such as tilt. The case where we need to provide fake measurements because the drone is on the ground and the range finder data is bad is already handled in "controlHeightFusion" so there is no need to hack the range finder checks with that. * Add Sensor and SensorRangeFinder classes The purpose is to encapsulate the checks for each sensor in a dedicated class with the same interface * SensorRangeFinder: encapsulate in estimator::sensor namespace * EKF: rename _sensor_rng to _range_sensor * Range checks: include limits in valid range * RangeChecks: update comment in the continuity checks * RangeChecks: move more low-level checks in functions Also move setTilt out of the terrain estimator, this is anyway protected internally to not compute cos/sin if the parameter did not change. * Sensor: remove unused virtual functions Those are not required yet but can still be added later * SensorRangeFinder: re-organise member variables Also rename getRangeToEarth to getCosTilt * SensorRangeFinder: split setSensorTilt and setCosMaxTilt functions * SensorRangeFinder: Add a few unit tests - good data - tilt exceeded - max range exceeded * SensorRangeFinder: set hysteresis in us instead of ms * SensorRangeFinder: Add more tests * SensorRangeFinder: update continuity, hysteresis and stuck tests * SensorRangeFinder: rename variables * SensorRangeFinder: get rid of "delayed" specification From the SensorRangeFinder class point of view, it's not relevant to know if the data is delayed or not * SensorRangeFinder: move time_last_valid out of stuck check * SensorRangeFinder: rename file names to sensor_range_finder * SensorRangeFinder: address Kamil's comments * SensorRangeFinder: Add more tilt tests * SensorRangeFinder: store current tilt offset This is to avoid recomputing cos/sin functions at each loop
2020-04-03 03:28:07 -03:00
sensor::SensorRangeFinder _range_sensor{};
2017-04-24 18:29:54 -03:00
airspeedSample _airspeed_sample_delayed{};
flowSample _flow_sample_delayed{};
extVisionSample _ev_sample_delayed{};
dragSample _drag_sample_delayed{};
dragSample _drag_down_sampled{}; // down sampled drag specific force data (filter prediction rate -> observation rate)
auxVelSample _auxvel_sample_delayed{};
// Used by the multi-rotor specific drag force fusion
2017-04-24 18:29:54 -03:00
uint8_t _drag_sample_count{0}; // number of drag specific force samples assumulated at the filter prediction rate
float _drag_sample_time_dt{0.0f}; // time integral across all samples used to form _drag_down_sampled (sec)
float _air_density{CONSTANTS_AIR_DENSITY_SEA_LEVEL_15C}; // air density (kg/m**3)
2015-11-19 13:08:04 -04:00
// Sensor limitations
float _flow_max_rate{0.0f}; ///< maximum angular flow rate that the optical flow sensor can measure (rad/s)
float _flow_min_distance{0.0f}; ///< minimum distance that the optical flow sensor can operate at (m)
float _flow_max_distance{0.0f}; ///< maximum distance that the optical flow sensor can operate at (m)
// Output Predictor
2017-04-24 18:29:54 -03:00
outputSample _output_sample_delayed{}; // filter output on the delayed time horizon
outputSample _output_new{}; // filter output on the non-delayed time horizon
outputVert _output_vert_delayed{}; // vertical filter output on the delayed time horizon
outputVert _output_vert_new{}; // vertical filter output on the non-delayed time horizon
imuSample _newest_high_rate_imu_sample{}; // imu sample capturing the newest imu data
Matrix3f _R_to_earth_now; // rotation matrix from body to earth frame at current time
Vector3f _vel_imu_rel_body_ned; // velocity of IMU relative to body origin in NED earth frame
Vector3f _vel_deriv; // velocity derivative at the IMU in NED earth frame (m/s/s)
2017-04-24 18:29:54 -03:00
bool _imu_updated{false}; // true if the ekf should update (completed downsampling process)
bool _initialised{false}; // true if the ekf interface instance (data buffering) is initialized
2017-04-24 18:29:54 -03:00
bool _NED_origin_initialised{false};
bool _gps_speed_valid{false};
float _gps_origin_eph{0.0f}; // horizontal position uncertainty of the GPS origin
float _gps_origin_epv{0.0f}; // vertical position uncertainty of the GPS origin
struct map_projection_reference_s _pos_ref {}; // Contains WGS-84 position latitude and longitude (radians) of the EKF origin
struct map_projection_reference_s _gps_pos_prev {}; // Contains WGS-84 position latitude and longitude (radians) of the previous GPS message
float _gps_alt_prev{0.0f}; // height from the previous GPS message (m)
float _gps_yaw_offset{0.0f}; // Yaw offset angle for dual GPS antennas used for yaw estimation (radians).
2015-11-19 13:08:04 -04:00
// innovation consistency check monitoring ratios
2019-10-15 09:51:17 -03:00
float _yaw_test_ratio{}; // yaw innovation consistency check ratio
float _mag_test_ratio[3] {}; // magnetometer XYZ innovation consistency check ratios
2019-12-09 03:49:33 -04:00
Vector2f _gps_vel_test_ratio; // GPS velocity innovation consistency check ratios
Vector2f _gps_pos_test_ratio; // GPS position innovation consistency check ratios
Vector2f _ev_vel_test_ratio; // EV velocity innovation consistency check ratios
Vector2f _ev_pos_test_ratio ; // EV position innovation consistency check ratios
Vector2f _aux_vel_test_ratio; // Auxiliray horizontal velocity innovation consistency check ratio
Vector2f _baro_hgt_test_ratio; // baro height innovation consistency check ratios
Vector2f _rng_hgt_test_ratio; // range finder height innovation consistency check ratios
float _optflow_test_ratio{}; // Optical flow innovation consistency check ratio
2019-10-15 09:51:17 -03:00
float _tas_test_ratio{}; // tas innovation consistency check ratio
float _hagl_test_ratio{}; // height above terrain measurement innovation consistency check ratio
float _beta_test_ratio{}; // sideslip innovation consistency check ratio
float _drag_test_ratio[2] {}; // drag innovation consistency check ratio
2017-02-05 14:05:10 -04:00
innovation_fault_status_u _innov_check_fail_status{};
bool _is_dead_reckoning{false}; // true if we are no longer fusing measurements that constrain horizontal velocity drift
bool _deadreckon_time_exceeded{true}; // true if the horizontal nav solution has been deadreckoning for too long and is invalid
bool _is_wind_dead_reckoning{false}; // true if we are navigationg reliant on wind relative measurements
2018-05-15 21:31:22 -03:00
// IMU vibration and movement monitoring
Vector3f _delta_ang_prev; // delta angle from the previous IMU measurement
Vector3f _delta_vel_prev; // delta velocity from the previous IMU measurement
Vector3f _vibe_metrics; // IMU vibration metrics
// [0] Level of coning vibration in the IMU delta angles (rad^2)
// [1] high frequency vibration level in the IMU delta angle data (rad)
// [2] high frequency vibration level in the IMU delta velocity data (m/s)
float _gps_drift_metrics[3] {}; // Array containing GPS drift metrics
// [0] Horizontal position drift rate (m/s)
// [1] Vertical position drift rate (m/s)
// [2] Filtered horizontal velocity (m/s)
2018-05-15 21:31:22 -03:00
uint64_t _time_last_move_detect_us{0}; // timestamp of last movement detection event in microseconds
bool _gps_drift_updated{false}; // true when _gps_drift_metrics has been updated and is ready for retrieval
// data buffer instances
2015-11-19 13:08:04 -04:00
RingBuffer<imuSample> _imu_buffer;
RingBuffer<gpsSample> _gps_buffer;
RingBuffer<magSample> _mag_buffer;
RingBuffer<baroSample> _baro_buffer;
RingBuffer<rangeSample> _range_buffer;
RingBuffer<airspeedSample> _airspeed_buffer;
RingBuffer<flowSample> _flow_buffer;
RingBuffer<extVisionSample> _ext_vision_buffer;
2015-11-19 13:08:04 -04:00
RingBuffer<outputSample> _output_buffer;
RingBuffer<outputVert> _output_vert_buffer;
RingBuffer<dragSample> _drag_buffer;
RingBuffer<auxVelSample> _auxvel_buffer;
2015-11-19 13:08:04 -04:00
EKF: Add Emergency yaw recovery using EKF-GSF estimator (#766) * EKF: Use common rate vector calculation for offset corrections * EKF: Remove duplicate matrix entry calculations * EKF: Create a EKF-GSF yaw estimator class * EKF: add emergency yaw reset functionality * EKF: remove un-used function * EKF: Ensure required constants are defined for all builds * EKF: Fix CI build error * Revert "EKF: remove un-used function" This reverts commit 93005309c7f3794414ad99c86218b3062e00bbd3. * EKF: Replace in-lined Tait-Bryan 312 conversions with function call Also remove unnecessary operations * EKF: Remove unnecessary update of external vision rotation matrix * EKF: Use const * EKF: use const * EKF: don't use class variable as a temporary variable * EKF: update comments * EKF: Improve efficiency of yaw reset Use conversion from rotation matrix to Euler angles instead of quaternion to euler angles. * EKF: use const * EKF: remove un-used struct element * EKF: more descriptive function name * EKF: use existing matrix row operator * EKF: remove unnecessary rotation matrix update * EKF: Use square matrix type * EKF: Improve protection for bad innovation covariance * EKF: Use matrix library operations * EKF: Replace memcpy with better alternative memcpy bypasses compiler sanity checks and is unnecessary in this instance. * EKF: Split EKF-GSF yaw reset function Adds a common function to support yaw reset that can be used elsewhere. * EKF: Use common function for quaternion state and covariance yaw reset * EKF: Replace inlined matrix operation * EKF: Use const * EKF: Change accessor function name * EKF: Use const * EKF: Don't create unnecessary duplicate variable locations * EKF: Remove duplicate covariance innovation inverse * EKF: Don't create unnecessary duplicate variable locations * EKF: Rely on geo library to provide gravity * EKF: Improve protection from bad updates * EKF: Reduce effect of vibration on yaw estimator AHRS * EKF: Improve yaw estimator AHRS accuracy during manoeuvre transients
2020-03-05 06:50:52 -04:00
// yaw estimator instance
EKFGSF_yaw yawEstimator;
// observation buffer final allocation failed
bool _gps_buffer_fail{false};
bool _mag_buffer_fail{false};
bool _baro_buffer_fail{false};
bool _range_buffer_fail{false};
bool _airspeed_buffer_fail{false};
bool _flow_buffer_fail{false};
bool _ev_buffer_fail{false};
bool _drag_buffer_fail{false};
bool _auxvel_buffer_fail{false};
2019-12-09 04:39:51 -04:00
// timestamps of latest in buffer saved measurement in microseconds
uint64_t _time_last_imu{0};
uint64_t _time_last_gps{0};
uint64_t _time_last_mag{0}; ///< measurement time of last magnetomter sample (uSec)
2019-12-09 04:39:51 -04:00
uint64_t _time_last_baro{0};
uint64_t _time_last_range{0};
uint64_t _time_last_airspeed{0};
uint64_t _time_last_ext_vision{0};
2017-04-24 18:29:54 -03:00
uint64_t _time_last_optflow{0};
uint64_t _time_last_auxvel{0};
2019-12-09 04:39:51 -04:00
//last time the baro ground effect compensation was turned on externally (uSec)
uint64_t _time_last_gnd_effect_on{0};
2020-01-14 06:14:33 -04:00
// Used to downsample magnetometer data
Vector3f _mag_data_sum;
uint8_t _mag_sample_count {0};
uint64_t _mag_timestamp_sum {0};
2015-11-19 13:08:04 -04:00
// Used to down sample barometer data
float _baro_alt_sum {0.0f}; // summed pressure altitude readings (m)
uint8_t _baro_sample_count {0}; // number of barometric altitude measurements summed
uint64_t _baro_timestamp_sum {0}; // summed timestamp to provide the timestamp of the averaged sample
2017-02-05 14:05:10 -04:00
fault_status_u _fault_status{};
// allocate data buffers and initialize interface variables
bool initialise_interface(uint64_t timestamp);
// free buffer memory
void unallocate_buffers();
2017-04-24 18:29:54 -03:00
float _mag_declination_gps{0.0f}; // magnetic declination returned by the geo library using the last valid GPS position (rad)
float _mag_inclination_gps{0.0f}; // magnetic inclination returned by the geo library using the last valid GPS position (rad)
float _mag_strength_gps{0.0f}; // magnetic strength returned by the geo library using the last valid GPS position (T)
// this is the current status of the filter control modes
2017-02-05 14:05:10 -04:00
filter_control_status_u _control_status{};
// this is the previous status of the filter control modes - used to detect mode transitions
2017-02-05 14:05:10 -04:00
filter_control_status_u _control_status_prev{};
2016-04-09 16:46:27 -03:00
// calculate the inverse rotation matrix from a quaternion rotation
2017-06-19 12:10:01 -03:00
Matrix3f quat_to_invrotmat(const Quatf &quat);
2016-04-09 16:46:27 -03:00
inline void setDragData();
inline void computeVibrationMetric();
inline bool checkIfVehicleAtRest(float dt);
virtual float compensateBaroForDynamicPressure(const float baro_alt_uncompensated) = 0;
void printBufferAllocationFailed(const char * buffer_name);
2015-11-19 13:08:04 -04:00
};