AP_AHRS: make AP_AHRS_DCM an AP_AHRS backend
This commit is contained in:
parent
2b402ed2d7
commit
44d56854be
@ -179,7 +179,6 @@ extern const AP_HAL::HAL& hal;
|
||||
|
||||
// constructor
|
||||
AP_AHRS::AP_AHRS(uint8_t flags) :
|
||||
AP_AHRS_DCM(),
|
||||
_ekf_flags(flags)
|
||||
{
|
||||
_singleton = this;
|
||||
@ -220,8 +219,8 @@ void AP_AHRS::init()
|
||||
|
||||
last_active_ekf_type = (EKFType)_ekf_type.get();
|
||||
|
||||
// init parent class
|
||||
AP_AHRS_DCM::init();
|
||||
// init backends
|
||||
dcm.init();
|
||||
|
||||
#if HAL_NMEA_OUTPUT_ENABLED
|
||||
_nmea_out = AP_NMEA_Output::probe();
|
||||
@ -245,25 +244,16 @@ void AP_AHRS::update_trim_rotation_matrices()
|
||||
// return the smoothed gyro vector corrected for drift
|
||||
const Vector3f &AP_AHRS::get_gyro(void) const
|
||||
{
|
||||
if (active_EKF_type() == EKFType::NONE) {
|
||||
return AP_AHRS_DCM::get_gyro();
|
||||
}
|
||||
return _gyro_estimate;
|
||||
}
|
||||
|
||||
const Matrix3f &AP_AHRS::get_rotation_body_to_ned(void) const
|
||||
{
|
||||
if (active_EKF_type() == EKFType::NONE) {
|
||||
return AP_AHRS_DCM::get_rotation_body_to_ned();
|
||||
}
|
||||
return _dcm_matrix;
|
||||
}
|
||||
|
||||
const Vector3f &AP_AHRS::get_gyro_drift(void) const
|
||||
{
|
||||
if (active_EKF_type() == EKFType::NONE) {
|
||||
return AP_AHRS_DCM::get_gyro_drift();
|
||||
}
|
||||
return _gyro_drift;
|
||||
}
|
||||
|
||||
@ -275,7 +265,7 @@ void AP_AHRS::reset_gyro_drift(void)
|
||||
WITH_SEMAPHORE(_rsem);
|
||||
|
||||
// update DCM
|
||||
AP_AHRS_DCM::reset_gyro_drift();
|
||||
dcm.reset_gyro_drift();
|
||||
|
||||
// reset the EKF gyro bias states
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
@ -400,20 +390,45 @@ void AP_AHRS::update(bool skip_ins_update)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* copy results from a backend over AP_AHRS canonical results.
|
||||
* This updates member variables like roll and pitch, as well as
|
||||
* updating derived values like sin_roll and sin_pitch.
|
||||
*/
|
||||
void AP_AHRS::copy_estimates_from_backend_estimates(const AP_AHRS_Backend::Estimates &results)
|
||||
{
|
||||
roll = results.roll_rad;
|
||||
pitch = results.pitch_rad;
|
||||
yaw = results.yaw_rad;
|
||||
|
||||
_dcm_matrix = results.dcm_matrix;
|
||||
|
||||
_gyro_estimate = results.gyro_estimate;
|
||||
_gyro_drift = results.gyro_drift;
|
||||
|
||||
// copy earth-frame accelerometer estimates:
|
||||
for (uint8_t i=0; i<INS_MAX_INSTANCES; i++) {
|
||||
_accel_ef_ekf[i] = results.accel_ef[i];
|
||||
}
|
||||
_accel_ef_ekf_blended = results.accel_ef_blended;
|
||||
|
||||
update_cd_values();
|
||||
update_trig();
|
||||
}
|
||||
|
||||
void AP_AHRS::update_DCM()
|
||||
{
|
||||
// we need to restore the old DCM attitude values as these are
|
||||
// used internally in DCM to calculate error values for gyro drift
|
||||
// correction
|
||||
roll = _dcm_attitude.x;
|
||||
pitch = _dcm_attitude.y;
|
||||
yaw = _dcm_attitude.z;
|
||||
update_cd_values();
|
||||
dcm.update();
|
||||
dcm.get_results(dcm_estimates);
|
||||
|
||||
AP_AHRS_DCM::_update();
|
||||
// we always update the vehicle's canonical roll/pitch/yaw from
|
||||
// DCM. In normal operation this will usually be over-written by
|
||||
// an EKF or external AHRS. This is long-held behaviour, but this
|
||||
// really shouldn't be doing this.
|
||||
|
||||
// keep DCM attitude available for get_secondary_attitude()
|
||||
_dcm_attitude = {roll, pitch, yaw};
|
||||
// if (active_EKF_type() == EKFType::NONE) {
|
||||
copy_estimates_from_backend_estimates(dcm_estimates);
|
||||
// }
|
||||
}
|
||||
|
||||
void AP_AHRS::update_notify_from_filter_status(const nav_filter_status &status)
|
||||
@ -673,28 +688,21 @@ void AP_AHRS::update_external(void)
|
||||
// accelerometer values in the earth frame in m/s/s
|
||||
const Vector3f &AP_AHRS::get_accel_ef(uint8_t i) const
|
||||
{
|
||||
if (active_EKF_type() == EKFType::NONE) {
|
||||
return AP_AHRS_DCM::get_accel_ef(i);
|
||||
}
|
||||
return _accel_ef_ekf[i];
|
||||
}
|
||||
|
||||
// blended accelerometer values in the earth frame in m/s/s
|
||||
const Vector3f &AP_AHRS::get_accel_ef_blended(void) const
|
||||
{
|
||||
if (active_EKF_type() == EKFType::NONE) {
|
||||
return AP_AHRS_DCM::get_accel_ef_blended();
|
||||
}
|
||||
return _accel_ef_ekf_blended;
|
||||
}
|
||||
|
||||
void AP_AHRS::reset(bool recover_eulers)
|
||||
void AP_AHRS::reset()
|
||||
{
|
||||
// support locked access functions to AHRS data
|
||||
WITH_SEMAPHORE(_rsem);
|
||||
|
||||
AP_AHRS_DCM::reset(recover_eulers);
|
||||
_dcm_attitude = {roll, pitch, yaw};
|
||||
dcm.reset();
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
if (_ekf2_started) {
|
||||
@ -713,7 +721,7 @@ bool AP_AHRS::get_position(struct Location &loc) const
|
||||
{
|
||||
switch (active_EKF_type()) {
|
||||
case EKFType::NONE:
|
||||
return AP_AHRS_DCM::get_position(loc);
|
||||
return dcm.get_position(loc);
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
case EKFType::TWO:
|
||||
@ -754,7 +762,7 @@ bool AP_AHRS::get_position(struct Location &loc) const
|
||||
|
||||
// fall back to position from DCM
|
||||
if (!always_use_EKF()) {
|
||||
return AP_AHRS_DCM::get_position(loc);
|
||||
return dcm.get_position(loc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -762,12 +770,12 @@ bool AP_AHRS::get_position(struct Location &loc) const
|
||||
// status reporting of estimated errors
|
||||
float AP_AHRS::get_error_rp(void) const
|
||||
{
|
||||
return AP_AHRS_DCM::get_error_rp();
|
||||
return dcm.get_error_rp();
|
||||
}
|
||||
|
||||
float AP_AHRS::get_error_yaw(void) const
|
||||
{
|
||||
return AP_AHRS_DCM::get_error_yaw();
|
||||
return dcm.get_error_yaw();
|
||||
}
|
||||
|
||||
// return a wind estimation vector, in m/s
|
||||
@ -776,7 +784,7 @@ Vector3f AP_AHRS::wind_estimate(void) const
|
||||
Vector3f wind;
|
||||
switch (active_EKF_type()) {
|
||||
case EKFType::NONE:
|
||||
wind = AP_AHRS_DCM::wind_estimate();
|
||||
wind = dcm.wind_estimate();
|
||||
break;
|
||||
|
||||
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
|
||||
@ -839,7 +847,7 @@ bool AP_AHRS::airspeed_estimate(float &airspeed_ret) const
|
||||
Vector3f wind_vel;
|
||||
switch (active_EKF_type()) {
|
||||
case EKFType::NONE:
|
||||
return AP_AHRS_DCM::airspeed_estimate(get_active_airspeed_index(), airspeed_ret);
|
||||
return dcm.airspeed_estimate(get_active_airspeed_index(), airspeed_ret);
|
||||
|
||||
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
|
||||
case EKFType::SIM:
|
||||
@ -852,7 +860,7 @@ bool AP_AHRS::airspeed_estimate(float &airspeed_ret) const
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
case EKFType::TWO:
|
||||
return AP_AHRS_DCM::airspeed_estimate(get_active_airspeed_index(), airspeed_ret);
|
||||
return dcm.airspeed_estimate(get_active_airspeed_index(), airspeed_ret);
|
||||
#endif
|
||||
|
||||
#if HAL_NAVEKF3_AVAILABLE
|
||||
@ -884,12 +892,39 @@ bool AP_AHRS::airspeed_estimate(float &airspeed_ret) const
|
||||
airspeed_ret = true_airspeed / get_EAS2TAS();
|
||||
} else {
|
||||
// fallback to DCM if airspeed estimate if EKF has wind but no velocity estimate
|
||||
ret = AP_AHRS_DCM::airspeed_estimate(get_active_airspeed_index(), airspeed_ret);
|
||||
ret = dcm.airspeed_estimate(get_active_airspeed_index(), airspeed_ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AP_AHRS::airspeed_estimate_true(float &airspeed_ret) const
|
||||
{
|
||||
switch (active_EKF_type()) {
|
||||
case EKFType::NONE:
|
||||
return dcm.airspeed_estimate_true(airspeed_ret);
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
case EKFType::TWO:
|
||||
#endif
|
||||
#if HAL_NAVEKF3_AVAILABLE
|
||||
case EKFType::THREE:
|
||||
#endif
|
||||
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
|
||||
case EKFType::SIM:
|
||||
#endif
|
||||
#if HAL_EXTERNAL_AHRS_ENABLED
|
||||
case EKFType::EXTERNAL:
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (!airspeed_estimate(airspeed_ret)) {
|
||||
return false;
|
||||
}
|
||||
airspeed_ret *= get_EAS2TAS();
|
||||
return true;
|
||||
}
|
||||
|
||||
// return estimate of true airspeed vector in body frame in m/s
|
||||
// returns false if estimate is unavailable
|
||||
bool AP_AHRS::airspeed_vector_true(Vector3f &vec) const
|
||||
@ -920,6 +955,15 @@ bool AP_AHRS::airspeed_vector_true(Vector3f &vec) const
|
||||
return false;
|
||||
}
|
||||
|
||||
// return a synthetic airspeed estimate (one derived from sensors
|
||||
// other than an actual airspeed sensor), if available. return
|
||||
// true if we have a synthetic airspeed. ret will not be modified
|
||||
// on failure.
|
||||
bool AP_AHRS::synthetic_airspeed(float &ret) const
|
||||
{
|
||||
return dcm.synthetic_airspeed(ret);
|
||||
}
|
||||
|
||||
// true if compass is being used
|
||||
bool AP_AHRS::use_compass(void)
|
||||
{
|
||||
@ -947,7 +991,7 @@ bool AP_AHRS::use_compass(void)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return AP_AHRS_DCM::use_compass();
|
||||
return dcm.use_compass();
|
||||
}
|
||||
|
||||
// return the quaternion defining the rotation from NED to XYZ (body) axes
|
||||
@ -957,7 +1001,7 @@ bool AP_AHRS::get_quaternion(Quaternion &quat) const
|
||||
// according to trim
|
||||
switch (active_EKF_type()) {
|
||||
case EKFType::NONE:
|
||||
if (!AP_AHRS_DCM::get_quaternion(quat)) {
|
||||
if (!dcm.get_quaternion(quat)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@ -1011,7 +1055,9 @@ bool AP_AHRS::get_secondary_attitude(Vector3f &eulers) const
|
||||
|
||||
case EKFType::NONE:
|
||||
// DCM is secondary
|
||||
eulers = _dcm_attitude;
|
||||
eulers[0] = dcm_estimates.roll_rad;
|
||||
eulers[1] = dcm_estimates.pitch_rad;
|
||||
eulers[2] = dcm_estimates.yaw_rad;
|
||||
return true;
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
@ -1064,7 +1110,7 @@ bool AP_AHRS::get_secondary_quaternion(Quaternion &quat) const
|
||||
|
||||
case EKFType::NONE:
|
||||
// DCM is secondary
|
||||
if (!AP_AHRS_DCM::get_quaternion(quat)) {
|
||||
if (!dcm.get_quaternion(quat)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@ -1119,7 +1165,7 @@ bool AP_AHRS::get_secondary_position(struct Location &loc) const
|
||||
|
||||
case EKFType::NONE:
|
||||
// return DCM position
|
||||
AP_AHRS_DCM::get_position(loc);
|
||||
dcm.get_position(loc);
|
||||
return true;
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
@ -1189,7 +1235,32 @@ Vector2f AP_AHRS::groundspeed_vector(void)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return AP_AHRS_DCM::groundspeed_vector();
|
||||
return dcm.groundspeed_vector();
|
||||
}
|
||||
|
||||
float AP_AHRS::groundspeed(void)
|
||||
{
|
||||
switch (active_EKF_type()) {
|
||||
case EKFType::NONE:
|
||||
return dcm.groundspeed();
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
case EKFType::TWO:
|
||||
#endif
|
||||
|
||||
#if HAL_NAVEKF3_AVAILABLE
|
||||
case EKFType::THREE:
|
||||
#endif
|
||||
|
||||
#if HAL_EXTERNAL_AHRS_ENABLED
|
||||
case EKFType::EXTERNAL:
|
||||
#endif
|
||||
|
||||
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
|
||||
case EKFType::SIM:
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
return groundspeed_vector().length();
|
||||
}
|
||||
|
||||
// set the EKF's origin location in 10e7 degrees. This should only
|
||||
@ -1277,7 +1348,7 @@ bool AP_AHRS::get_velocity_NED(Vector3f &vec) const
|
||||
return AP::externalAHRS().get_velocity_NED(vec);
|
||||
#endif
|
||||
}
|
||||
return AP_AHRS_DCM::get_velocity_NED(vec);
|
||||
return dcm.get_velocity_NED(vec);
|
||||
}
|
||||
|
||||
// returns the expected NED magnetic field
|
||||
@ -1348,14 +1419,8 @@ bool AP_AHRS::get_mag_field_correction(Vector3f &vec) const
|
||||
bool AP_AHRS::get_vert_pos_rate(float &velocity) const
|
||||
{
|
||||
switch (active_EKF_type()) {
|
||||
case EKFType::NONE: {
|
||||
Vector3f velned;
|
||||
if (!AP_AHRS_DCM::get_velocity_NED(velned)) {
|
||||
return false;
|
||||
}
|
||||
velocity = velned.z;
|
||||
return true;
|
||||
}
|
||||
case EKFType::NONE:
|
||||
return dcm.get_vert_pos_rate(velocity);
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
case EKFType::TWO:
|
||||
@ -1431,7 +1496,7 @@ bool AP_AHRS::get_relative_position_NED_origin(Vector3f &vec) const
|
||||
{
|
||||
switch (active_EKF_type()) {
|
||||
case EKFType::NONE:
|
||||
return AP_AHRS_DCM::get_relative_position_NED_origin(vec);
|
||||
return dcm.get_relative_position_NED_origin(vec);
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
case EKFType::TWO: {
|
||||
@ -1524,7 +1589,7 @@ bool AP_AHRS::get_relative_position_NE_origin(Vector2f &posNE) const
|
||||
{
|
||||
switch (active_EKF_type()) {
|
||||
case EKFType::NONE:
|
||||
return AP_AHRS_DCM::get_relative_position_NE_origin(posNE);
|
||||
return dcm.get_relative_position_NE_origin(posNE);
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
case EKFType::TWO: {
|
||||
@ -1594,7 +1659,7 @@ bool AP_AHRS::get_relative_position_D_origin(float &posD) const
|
||||
{
|
||||
switch (active_EKF_type()) {
|
||||
case EKFType::NONE:
|
||||
return AP_AHRS_DCM::get_relative_position_D_origin(posD);
|
||||
return dcm.get_relative_position_D_origin(posD);
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
case EKFType::TWO: {
|
||||
@ -1899,7 +1964,7 @@ bool AP_AHRS::healthy(void) const
|
||||
// an internal processing error, but not for bad sensor data.
|
||||
switch (ekf_type()) {
|
||||
case EKFType::NONE:
|
||||
return AP_AHRS_DCM::healthy();
|
||||
return dcm.healthy();
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
case EKFType::TWO: {
|
||||
@ -1945,7 +2010,7 @@ bool AP_AHRS::healthy(void) const
|
||||
#endif
|
||||
}
|
||||
|
||||
return AP_AHRS_DCM::healthy();
|
||||
return dcm.healthy();
|
||||
}
|
||||
|
||||
// returns false if we fail arming checks, in which case the buffer will be populated with a failure message
|
||||
@ -1963,9 +2028,10 @@ bool AP_AHRS::pre_arm_check(bool requires_position, char *failure_msg, uint8_t f
|
||||
switch (ekf_type()) {
|
||||
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
|
||||
case EKFType::SIM:
|
||||
return ret;
|
||||
#endif
|
||||
case EKFType::NONE:
|
||||
return ret;
|
||||
return dcm.pre_arm_check(requires_position, failure_msg, failure_msg_len);
|
||||
|
||||
#if HAL_EXTERNAL_AHRS_ENABLED
|
||||
case EKFType::EXTERNAL:
|
||||
@ -2032,7 +2098,7 @@ bool AP_AHRS::get_filter_status(nav_filter_status &status) const
|
||||
{
|
||||
switch (ekf_type()) {
|
||||
case EKFType::NONE:
|
||||
return false;
|
||||
return dcm.get_filter_status(status);
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
case EKFType::TWO:
|
||||
@ -2236,7 +2302,7 @@ void AP_AHRS::getCorrectedDeltaVelocityNED(Vector3f& ret, float& dt) const
|
||||
#endif
|
||||
}
|
||||
if (imu_idx == -1) {
|
||||
AP_AHRS_DCM::getCorrectedDeltaVelocityNED(ret, dt);
|
||||
dcm.getCorrectedDeltaVelocityNED(ret, dt);
|
||||
return;
|
||||
}
|
||||
ret.zero();
|
||||
@ -2345,7 +2411,7 @@ uint32_t AP_AHRS::getLastYawResetAngle(float &yawAng)
|
||||
switch (active_EKF_type()) {
|
||||
|
||||
case EKFType::NONE:
|
||||
return 0;
|
||||
return dcm.getLastYawResetAngle(yawAng);
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
case EKFType::TWO:
|
||||
@ -2517,7 +2583,7 @@ void AP_AHRS::send_ekf_status_report(mavlink_channel_t chan) const
|
||||
switch (ekf_type()) {
|
||||
case EKFType::NONE:
|
||||
// send zero status report
|
||||
mavlink_msg_ekf_status_report_send(chan, 0, 0, 0, 0, 0, 0, 0);
|
||||
dcm.send_ekf_status_report(chan);
|
||||
break;
|
||||
|
||||
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
|
||||
@ -2567,7 +2633,7 @@ bool AP_AHRS::get_origin(Location &ret) const
|
||||
{
|
||||
switch (ekf_type()) {
|
||||
case EKFType::NONE:
|
||||
return AP_AHRS_DCM::get_origin_fallback(ret);
|
||||
return dcm.get_origin(ret);
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
case EKFType::TWO:
|
||||
|
@ -53,7 +53,7 @@ class AP_AHRS_View;
|
||||
|
||||
#include <AP_NMEA_Output/AP_NMEA_Output.h>
|
||||
|
||||
class AP_AHRS : public AP_AHRS_DCM {
|
||||
class AP_AHRS {
|
||||
friend class AP_AHRS_View;
|
||||
public:
|
||||
|
||||
@ -65,7 +65,7 @@ public:
|
||||
AP_AHRS(uint8_t flags = 0);
|
||||
|
||||
// initialise
|
||||
void init(void) override;
|
||||
void init(void);
|
||||
|
||||
/* Do not allow copies */
|
||||
CLASS_NO_COPY(AP_AHRS);
|
||||
@ -79,29 +79,33 @@ public:
|
||||
// this makes initial config easier
|
||||
void update_orientation();
|
||||
|
||||
// allow threads to lock against AHRS update
|
||||
HAL_Semaphore &get_semaphore(void) {
|
||||
return _rsem;
|
||||
}
|
||||
|
||||
// return the smoothed gyro vector corrected for drift
|
||||
const Vector3f &get_gyro(void) const override;
|
||||
const Matrix3f &get_rotation_body_to_ned(void) const override;
|
||||
const Vector3f &get_gyro(void) const;
|
||||
|
||||
// return the current drift correction integrator value
|
||||
const Vector3f &get_gyro_drift(void) const override;
|
||||
const Vector3f &get_gyro_drift(void) const;
|
||||
|
||||
// reset the current gyro drift estimate
|
||||
// should be called if gyro offsets are recalculated
|
||||
void reset_gyro_drift() override;
|
||||
void reset_gyro_drift();
|
||||
|
||||
void update(bool skip_ins_update=false);
|
||||
void reset(bool recover_eulers = false) override;
|
||||
void reset();
|
||||
|
||||
// dead-reckoning support
|
||||
bool get_position(struct Location &loc) const override;
|
||||
bool get_position(struct Location &loc) const;
|
||||
|
||||
// get latest altitude estimate above ground level in meters and validity flag
|
||||
bool get_hagl(float &hagl) const override WARN_IF_UNUSED;
|
||||
bool get_hagl(float &hagl) const WARN_IF_UNUSED;
|
||||
|
||||
// status reporting of estimated error
|
||||
float get_error_rp() const override;
|
||||
float get_error_yaw() const override;
|
||||
float get_error_rp() const;
|
||||
float get_error_yaw() const;
|
||||
|
||||
/*
|
||||
* wind estimation support
|
||||
@ -114,7 +118,10 @@ public:
|
||||
bool get_wind_estimation_enabled() const { return wind_estimation_enabled; }
|
||||
|
||||
// return a wind estimation vector, in m/s
|
||||
Vector3f wind_estimate() const override;
|
||||
Vector3f wind_estimate() const;
|
||||
|
||||
// instruct DCM to update its wind estimate:
|
||||
void estimate_wind() { dcm.estimate_wind(); }
|
||||
|
||||
// return the parameter AHRS_WIND_MAX in metres per second
|
||||
uint8_t get_max_wind() const {
|
||||
@ -125,40 +132,72 @@ public:
|
||||
* airspeed support
|
||||
*/
|
||||
|
||||
// get apparent to true airspeed ratio
|
||||
float get_EAS2TAS(void) const {
|
||||
// FIXME: make this is a method on the active backend
|
||||
return dcm.get_EAS2TAS();
|
||||
}
|
||||
|
||||
// return an airspeed estimate if available. return true
|
||||
// if we have an estimate
|
||||
bool airspeed_estimate(float &airspeed_ret) const override;
|
||||
bool airspeed_estimate(float &airspeed_ret) const;
|
||||
// return a true airspeed estimate (navigation airspeed) if
|
||||
// available. return true if we have an estimate
|
||||
bool airspeed_estimate_true(float &airspeed_ret) const;
|
||||
|
||||
// return estimate of true airspeed vector in body frame in m/s
|
||||
// returns false if estimate is unavailable
|
||||
bool airspeed_vector_true(Vector3f &vec) const override;
|
||||
bool airspeed_vector_true(Vector3f &vec) const;
|
||||
|
||||
// return true if airspeed comes from an airspeed sensor, as
|
||||
// opposed to an IMU estimate
|
||||
bool airspeed_sensor_enabled(void) const {
|
||||
// FIXME: make this "using_airspeed_sensor"?
|
||||
return dcm.airspeed_sensor_enabled();
|
||||
}
|
||||
|
||||
// return true if airspeed comes from a specific airspeed sensor, as
|
||||
// opposed to an IMU estimate
|
||||
bool airspeed_sensor_enabled(uint8_t airspeed_index) const {
|
||||
// FIXME: make this a method on the active backend
|
||||
return dcm.airspeed_sensor_enabled(airspeed_index);
|
||||
}
|
||||
|
||||
// return a synthetic airspeed estimate (one derived from sensors
|
||||
// other than an actual airspeed sensor), if available. return
|
||||
// true if we have a synthetic airspeed. ret will not be modified
|
||||
// on failure.
|
||||
bool synthetic_airspeed(float &ret) const WARN_IF_UNUSED;
|
||||
|
||||
// true if compass is being used
|
||||
bool use_compass() override;
|
||||
bool use_compass();
|
||||
|
||||
// return the quaternion defining the rotation from NED to XYZ (body) axes
|
||||
bool get_quaternion(Quaternion &quat) const override WARN_IF_UNUSED;
|
||||
bool get_quaternion(Quaternion &quat) const WARN_IF_UNUSED;
|
||||
|
||||
// return secondary attitude solution if available, as eulers in radians
|
||||
bool get_secondary_attitude(Vector3f &eulers) const override;
|
||||
bool get_secondary_attitude(Vector3f &eulers) const;
|
||||
|
||||
// return secondary attitude solution if available, as quaternion
|
||||
bool get_secondary_quaternion(Quaternion &quat) const override;
|
||||
bool get_secondary_quaternion(Quaternion &quat) const;
|
||||
|
||||
// return secondary position solution if available
|
||||
bool get_secondary_position(struct Location &loc) const override;
|
||||
bool get_secondary_position(struct Location &loc) const;
|
||||
|
||||
// EKF has a better ground speed vector estimate
|
||||
Vector2f groundspeed_vector() override;
|
||||
Vector2f groundspeed_vector();
|
||||
|
||||
const Vector3f &get_accel_ef(uint8_t i) const override;
|
||||
const Vector3f &get_accel_ef() const override;
|
||||
// return ground speed estimate in meters/second. Used by ground vehicles.
|
||||
float groundspeed(void);
|
||||
|
||||
const Vector3f &get_accel_ef(uint8_t i) const;
|
||||
const Vector3f &get_accel_ef() const;
|
||||
|
||||
// Retrieves the corrected NED delta velocity in use by the inertial navigation
|
||||
void getCorrectedDeltaVelocityNED(Vector3f& ret, float& dt) const override;
|
||||
void getCorrectedDeltaVelocityNED(Vector3f& ret, float& dt) const;
|
||||
|
||||
// blended accelerometer values in the earth frame in m/s/s
|
||||
const Vector3f &get_accel_ef_blended() const override;
|
||||
const Vector3f &get_accel_ef_blended() const;
|
||||
|
||||
// set the EKF's origin location in 10e7 degrees. This should only
|
||||
// be called when the EKF has no absolute position reference (i.e. GPS)
|
||||
@ -168,24 +207,24 @@ public:
|
||||
// returns the inertial navigation origin in lat/lon/alt
|
||||
bool get_origin(Location &ret) const WARN_IF_UNUSED;
|
||||
|
||||
bool have_inertial_nav() const override;
|
||||
bool have_inertial_nav() const;
|
||||
|
||||
bool get_velocity_NED(Vector3f &vec) const override;
|
||||
bool get_velocity_NED(Vector3f &vec) const;
|
||||
|
||||
// return the relative position NED to either home or origin
|
||||
// return true if the estimate is valid
|
||||
bool get_relative_position_NED_home(Vector3f &vec) const;
|
||||
bool get_relative_position_NED_origin(Vector3f &vec) const override;
|
||||
bool get_relative_position_NED_origin(Vector3f &vec) const;
|
||||
|
||||
// return the relative position NE to either home or origin
|
||||
// return true if the estimate is valid
|
||||
bool get_relative_position_NE_home(Vector2f &posNE) const;
|
||||
bool get_relative_position_NE_origin(Vector2f &posNE) const override;
|
||||
bool get_relative_position_NE_origin(Vector2f &posNE) const;
|
||||
|
||||
// return the relative position down to either home or origin
|
||||
// baro will be used for the _home relative one if the EKF isn't
|
||||
void get_relative_position_D_home(float &posD) const;
|
||||
bool get_relative_position_D_origin(float &posD) const override;
|
||||
bool get_relative_position_D_origin(float &posD) const;
|
||||
|
||||
// Get a derivative of the vertical position in m/s which is kinematically consistent with the vertical position is required by some control loops.
|
||||
// This is different to the vertical velocity from the EKF which is not always consistent with the vertical position due to the various errors that are being corrected for.
|
||||
@ -201,28 +240,28 @@ public:
|
||||
void writeDefaultAirSpeed(float airspeed, float uncertainty);
|
||||
|
||||
// Write position and quaternion data from an external navigation system
|
||||
void writeExtNavData(const Vector3f &pos, const Quaternion &quat, float posErr, float angErr, uint32_t timeStamp_ms, uint16_t delay_ms, uint32_t resetTime_ms) override;
|
||||
void writeExtNavData(const Vector3f &pos, const Quaternion &quat, float posErr, float angErr, uint32_t timeStamp_ms, uint16_t delay_ms, uint32_t resetTime_ms);
|
||||
|
||||
// Write velocity data from an external navigation system
|
||||
void writeExtNavVelData(const Vector3f &vel, float err, uint32_t timeStamp_ms, uint16_t delay_ms) override;
|
||||
void writeExtNavVelData(const Vector3f &vel, float err, uint32_t timeStamp_ms, uint16_t delay_ms);
|
||||
|
||||
// get speed limit
|
||||
void getControlLimits(float &ekfGndSpdLimit, float &controlScaleXY) const;
|
||||
float getControlScaleZ(void) const;
|
||||
|
||||
// is the AHRS subsystem healthy?
|
||||
bool healthy() const override;
|
||||
bool healthy() const;
|
||||
|
||||
// returns false if we fail arming checks, in which case the buffer will be populated with a failure message
|
||||
// requires_position should be true if horizontal position configuration should be checked
|
||||
bool pre_arm_check(bool requires_position, char *failure_msg, uint8_t failure_msg_len) const override;
|
||||
bool pre_arm_check(bool requires_position, char *failure_msg, uint8_t failure_msg_len) const;
|
||||
|
||||
// true if the AHRS has completed initialisation
|
||||
bool initialised() const override;
|
||||
bool initialised() const;
|
||||
|
||||
// return true if *DCM* yaw has been initialised
|
||||
bool dcm_yaw_initialised(void) const {
|
||||
return AP_AHRS_DCM::yaw_initialised();
|
||||
return dcm.yaw_initialised();
|
||||
}
|
||||
|
||||
// get_filter_status - returns filter status as a series of flags
|
||||
@ -233,30 +272,30 @@ public:
|
||||
bool getMagOffsets(uint8_t mag_idx, Vector3f &magOffsets) const;
|
||||
|
||||
// check all cores providing consistent attitudes for prearm checks
|
||||
bool attitudes_consistent(char *failure_msg, const uint8_t failure_msg_len) const override;
|
||||
bool attitudes_consistent(char *failure_msg, const uint8_t failure_msg_len) const;
|
||||
|
||||
// return the amount of yaw angle change due to the last yaw angle reset in radians
|
||||
// returns the time of the last yaw angle reset or 0 if no reset has ever occurred
|
||||
uint32_t getLastYawResetAngle(float &yawAng) override;
|
||||
uint32_t getLastYawResetAngle(float &yawAng);
|
||||
|
||||
// return the amount of NE position change in meters due to the last reset
|
||||
// returns the time of the last reset or 0 if no reset has ever occurred
|
||||
uint32_t getLastPosNorthEastReset(Vector2f &pos) override;
|
||||
uint32_t getLastPosNorthEastReset(Vector2f &pos);
|
||||
|
||||
// return the amount of NE velocity change in meters/sec due to the last reset
|
||||
// returns the time of the last reset or 0 if no reset has ever occurred
|
||||
uint32_t getLastVelNorthEastReset(Vector2f &vel) const override;
|
||||
uint32_t getLastVelNorthEastReset(Vector2f &vel) const;
|
||||
|
||||
// return the amount of vertical position change due to the last reset in meters
|
||||
// returns the time of the last reset or 0 if no reset has ever occurred
|
||||
uint32_t getLastPosDownReset(float &posDelta) override;
|
||||
uint32_t getLastPosDownReset(float &posDelta);
|
||||
|
||||
// Resets the baro so that it reads zero at the current height
|
||||
// Resets the EKF height to zero
|
||||
// Adjusts the EKf origin height so that the EKF height + origin height is the same as before
|
||||
// Returns true if the height datum reset has been performed
|
||||
// If using a range finder for height no reset is performed and it returns false
|
||||
bool resetHeightDatum() override;
|
||||
bool resetHeightDatum();
|
||||
|
||||
// send a EKF_STATUS_REPORT for current EKF
|
||||
void send_ekf_status_report(mavlink_channel_t chan) const;
|
||||
@ -264,15 +303,15 @@ public:
|
||||
// get_hgt_ctrl_limit - get maximum height to be observed by the control loops in meters and a validity flag
|
||||
// this is used to limit height during optical flow navigation
|
||||
// it will return invalid when no limiting is required
|
||||
bool get_hgt_ctrl_limit(float &limit) const override;
|
||||
bool get_hgt_ctrl_limit(float &limit) const;
|
||||
|
||||
// Set to true if the terrain underneath is stable enough to be used as a height reference
|
||||
// this is not related to terrain following
|
||||
void set_terrain_hgt_stable(bool stable) override;
|
||||
void set_terrain_hgt_stable(bool stable);
|
||||
|
||||
// return the innovations for the specified instance
|
||||
// An out of range instance (eg -1) returns data for the primary instance
|
||||
bool get_innovations(Vector3f &velInnov, Vector3f &posInnov, Vector3f &magInnov, float &tasInnov, float &yawInnov) const override;
|
||||
bool get_innovations(Vector3f &velInnov, Vector3f &posInnov, Vector3f &magInnov, float &tasInnov, float &yawInnov) const;
|
||||
|
||||
// returns true when the state estimates are significantly degraded by vibration
|
||||
bool is_vibration_affected() const;
|
||||
@ -281,17 +320,17 @@ public:
|
||||
// indicates perfect consistency between the measurement and the EKF solution and a value of of 1 is the maximum
|
||||
// inconsistency that will be accepted by the filter
|
||||
// boolean false is returned if variances are not available
|
||||
bool get_variances(float &velVar, float &posVar, float &hgtVar, Vector3f &magVar, float &tasVar) const override;
|
||||
bool get_variances(float &velVar, float &posVar, float &hgtVar, Vector3f &magVar, float &tasVar) const;
|
||||
|
||||
// get a source's velocity innovations
|
||||
// returns true on success and results are placed in innovations and variances arguments
|
||||
bool get_vel_innovations_and_variances_for_source(uint8_t source, Vector3f &innovations, Vector3f &variances) const override WARN_IF_UNUSED;
|
||||
bool get_vel_innovations_and_variances_for_source(uint8_t source, Vector3f &innovations, Vector3f &variances) const WARN_IF_UNUSED;
|
||||
|
||||
// returns the expected NED magnetic field
|
||||
bool get_mag_field_NED(Vector3f& ret) const;
|
||||
|
||||
// returns the estimated magnetic field offsets in body frame
|
||||
bool get_mag_field_correction(Vector3f &ret) const override;
|
||||
bool get_mag_field_correction(Vector3f &ret) const;
|
||||
|
||||
// return the index of the airspeed we should use for airspeed measurements
|
||||
// with multiple airspeed sensors and airspeed affinity in EKF3, it is possible to have switched
|
||||
@ -301,33 +340,33 @@ public:
|
||||
uint8_t get_active_airspeed_index() const;
|
||||
|
||||
// return the index of the primary core or -1 if no primary core selected
|
||||
int8_t get_primary_core_index() const override;
|
||||
int8_t get_primary_core_index() const;
|
||||
|
||||
// get the index of the current primary accelerometer sensor
|
||||
uint8_t get_primary_accel_index(void) const override;
|
||||
uint8_t get_primary_accel_index(void) const;
|
||||
|
||||
// get the index of the current primary gyro sensor
|
||||
uint8_t get_primary_gyro_index(void) const override;
|
||||
uint8_t get_primary_gyro_index(void) const;
|
||||
|
||||
// see if EKF lane switching is possible to avoid EKF failsafe
|
||||
void check_lane_switch(void) override;
|
||||
void check_lane_switch(void);
|
||||
|
||||
// request EKF yaw reset to try and avoid the need for an EKF lane switch or failsafe
|
||||
void request_yaw_reset(void) override;
|
||||
void request_yaw_reset(void);
|
||||
|
||||
// set position, velocity and yaw sources to either 0=primary, 1=secondary, 2=tertiary
|
||||
void set_posvelyaw_source_set(uint8_t source_set_idx) override;
|
||||
void set_posvelyaw_source_set(uint8_t source_set_idx);
|
||||
|
||||
void Log_Write();
|
||||
|
||||
// check if non-compass sensor is providing yaw. Allows compass pre-arm checks to be bypassed
|
||||
bool using_noncompass_for_yaw(void) const override;
|
||||
bool using_noncompass_for_yaw(void) const;
|
||||
|
||||
// check if external nav is providing yaw
|
||||
bool using_extnav_for_yaw(void) const override;
|
||||
bool using_extnav_for_yaw(void) const;
|
||||
|
||||
// set and save the ALT_M_NSE parameter value
|
||||
void set_alt_measurement_noise(float noise) override;
|
||||
void set_alt_measurement_noise(float noise);
|
||||
|
||||
// active EKF type for logging
|
||||
uint8_t get_active_AHRS_type(void) const {
|
||||
@ -379,6 +418,23 @@ public:
|
||||
const Matrix3f& get_rotation_autopilot_body_to_vehicle_body(void) const { return _rotation_autopilot_body_to_vehicle_body; }
|
||||
const Matrix3f& get_rotation_vehicle_body_to_autopilot_body(void) const { return _rotation_vehicle_body_to_autopilot_body; }
|
||||
|
||||
// Logging functions
|
||||
void Log_Write_Home_And_Origin();
|
||||
void Write_AHRS2(void) const;
|
||||
void Write_Attitude(const Vector3f &targets) const;
|
||||
void Write_Origin(uint8_t origin_type, const Location &loc) const;
|
||||
void Write_POS(void) const;
|
||||
|
||||
// return a smoothed and corrected gyro vector in radians/second
|
||||
// using the latest ins data (which may not have been consumed by
|
||||
// the EKF yet)
|
||||
Vector3f get_gyro_latest(void) const;
|
||||
|
||||
// get yaw rate in earth frame in radians/sec
|
||||
float get_yaw_rate_earth(void) const {
|
||||
return get_gyro() * get_rotation_body_to_ned().c;
|
||||
}
|
||||
|
||||
/*
|
||||
* home-related functionality
|
||||
*/
|
||||
@ -408,7 +464,85 @@ public:
|
||||
// current barometer and GPS altitudes correspond to this altitude
|
||||
bool set_home(const Location &loc) WARN_IF_UNUSED;
|
||||
|
||||
void Log_Write_Home_And_Origin();
|
||||
/*
|
||||
* Attitude-related public methods and attributes:
|
||||
*/
|
||||
|
||||
// roll/pitch/yaw euler angles, all in radians
|
||||
float roll;
|
||||
float pitch;
|
||||
float yaw;
|
||||
|
||||
float get_roll() const { return roll; }
|
||||
float get_pitch() const { return pitch; }
|
||||
float get_yaw() const { return yaw; }
|
||||
|
||||
// helper trig value accessors
|
||||
float cos_roll() const {
|
||||
return _cos_roll;
|
||||
}
|
||||
float cos_pitch() const {
|
||||
return _cos_pitch;
|
||||
}
|
||||
float cos_yaw() const {
|
||||
return _cos_yaw;
|
||||
}
|
||||
float sin_roll() const {
|
||||
return _sin_roll;
|
||||
}
|
||||
float sin_pitch() const {
|
||||
return _sin_pitch;
|
||||
}
|
||||
float sin_yaw() const {
|
||||
return _sin_yaw;
|
||||
}
|
||||
|
||||
// integer Euler angles (Degrees * 100)
|
||||
int32_t roll_sensor;
|
||||
int32_t pitch_sensor;
|
||||
int32_t yaw_sensor;
|
||||
|
||||
const Matrix3f &get_rotation_body_to_ned(void) const;
|
||||
|
||||
// return a Quaternion representing our current attitude in NED frame
|
||||
void get_quat_body_to_ned(Quaternion &quat) const {
|
||||
quat.from_rotation_matrix(get_rotation_body_to_ned());
|
||||
}
|
||||
|
||||
// get rotation matrix specifically from DCM backend (used for
|
||||
// compass calibrator)
|
||||
const Matrix3f &get_DCM_rotation_body_to_ned(void) const {
|
||||
return dcm_estimates.dcm_matrix;
|
||||
}
|
||||
|
||||
// rotate a 2D vector from earth frame to body frame
|
||||
// in result, x is forward, y is right
|
||||
Vector2f earth_to_body2D(const Vector2f &ef_vector) const;
|
||||
|
||||
// rotate a 2D vector from earth frame to body frame
|
||||
// in input, x is forward, y is right
|
||||
Vector2f body_to_earth2D(const Vector2f &bf) const;
|
||||
|
||||
// convert a vector from body to earth frame
|
||||
Vector3f body_to_earth(const Vector3f &v) const {
|
||||
return v * get_rotation_body_to_ned();
|
||||
}
|
||||
|
||||
// convert a vector from earth to body frame
|
||||
Vector3f earth_to_body(const Vector3f &v) const {
|
||||
return get_rotation_body_to_ned().mul_transpose(v);
|
||||
}
|
||||
|
||||
/*
|
||||
* methods for the benefit of LUA bindings
|
||||
*/
|
||||
// return current vibration vector for primary IMU
|
||||
Vector3f get_vibration(void) const;
|
||||
|
||||
// return primary accels, for lua
|
||||
const Vector3f &get_accel(void) const {
|
||||
return AP::ins().get_accel();
|
||||
}
|
||||
|
||||
/*
|
||||
* AHRS is used as a transport for vehicle-takeoff-expected and
|
||||
@ -460,11 +594,11 @@ public:
|
||||
// get the view's rotation, or ROTATION_NONE
|
||||
enum Rotation get_view_rotation(void) const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
|
||||
// optional view class
|
||||
AP_AHRS_View *_view;
|
||||
|
||||
private:
|
||||
static AP_AHRS *_singleton;
|
||||
|
||||
/* we modify our behaviour based on what sort of vehicle the
|
||||
@ -473,6 +607,9 @@ private:
|
||||
*/
|
||||
VehicleClass _vehicle_class{VehicleClass::UNKNOWN};
|
||||
|
||||
// multi-thread access support
|
||||
HAL_Semaphore _rsem;
|
||||
|
||||
/*
|
||||
* Parameters
|
||||
*/
|
||||
@ -488,6 +625,19 @@ private:
|
||||
*/
|
||||
Matrix3f _custom_rotation;
|
||||
|
||||
/*
|
||||
* DCM-backend parameters; it takes references to these
|
||||
*/
|
||||
// settable parameters
|
||||
AP_Float _kp_yaw;
|
||||
AP_Float _kp;
|
||||
AP_Float gps_gain;
|
||||
|
||||
AP_Float beta;
|
||||
|
||||
AP_Enum<GPSUse> _gps_use;
|
||||
AP_Int8 _gps_minsats;
|
||||
|
||||
enum class EKFType {
|
||||
NONE = 0
|
||||
#if HAL_NAVEKF3_AVAILABLE
|
||||
@ -513,6 +663,29 @@ private:
|
||||
return _ekf_flags & FLAG_ALWAYS_USE_EKF;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attitude-related private methods and attributes:
|
||||
*/
|
||||
// calculate sin/cos of roll/pitch/yaw from rotation
|
||||
void calc_trig(const Matrix3f &rot,
|
||||
float &cr, float &cp, float &cy,
|
||||
float &sr, float &sp, float &sy) const;
|
||||
|
||||
// update_trig - recalculates _cos_roll, _cos_pitch, etc based on latest attitude
|
||||
// should be called after _dcm_matrix is updated
|
||||
void update_trig(void);
|
||||
|
||||
// update roll_sensor, pitch_sensor and yaw_sensor
|
||||
void update_cd_values(void);
|
||||
|
||||
// helper trig variables
|
||||
float _cos_roll{1.0f};
|
||||
float _cos_pitch{1.0f};
|
||||
float _cos_yaw{1.0f};
|
||||
float _sin_roll;
|
||||
float _sin_pitch;
|
||||
float _sin_yaw;
|
||||
|
||||
#if HAL_NAVEKF2_AVAILABLE
|
||||
void update_EKF2(void);
|
||||
bool _ekf2_started;
|
||||
@ -524,8 +697,7 @@ private:
|
||||
|
||||
// rotation from vehicle body to NED frame
|
||||
Matrix3f _dcm_matrix;
|
||||
Vector3f _dcm_attitude;
|
||||
|
||||
|
||||
Vector3f _gyro_drift;
|
||||
Vector3f _gyro_estimate;
|
||||
Vector3f _accel_ef_ekf[INS_MAX_INSTANCES];
|
||||
@ -621,6 +793,19 @@ private:
|
||||
// poke AP_Notify based on values from status
|
||||
void update_notify_from_filter_status(const nav_filter_status &status);
|
||||
|
||||
/*
|
||||
* backends (and their results)
|
||||
*/
|
||||
AP_AHRS_DCM dcm{_kp_yaw, _kp, gps_gain, beta, _gps_use, _gps_minsats};
|
||||
struct AP_AHRS_Backend::Estimates dcm_estimates;
|
||||
|
||||
/*
|
||||
* copy results from a backend over AP_AHRS canonical results.
|
||||
* This updates member variables like roll and pitch, as well as
|
||||
* updating derived values like sin_roll and sin_pitch.
|
||||
*/
|
||||
void copy_estimates_from_backend_estimates(const AP_AHRS_Backend::Estimates &results);
|
||||
|
||||
#if HAL_NMEA_OUTPUT_ENABLED
|
||||
class AP_NMEA_Output* _nmea_out;
|
||||
#endif
|
||||
|
@ -23,13 +23,12 @@
|
||||
|
||||
extern const AP_HAL::HAL& hal;
|
||||
|
||||
// init sets up INS board orientation
|
||||
void AP_AHRS_Backend::init()
|
||||
{
|
||||
}
|
||||
|
||||
// return a smoothed and corrected gyro vector using the latest ins data (which may not have been consumed by the EKF yet)
|
||||
Vector3f AP_AHRS_Backend::get_gyro_latest(void) const
|
||||
Vector3f AP_AHRS::get_gyro_latest(void) const
|
||||
{
|
||||
const uint8_t primary_gyro = get_primary_gyro_index();
|
||||
return AP::ins().get_gyro(primary_gyro) + get_gyro_drift();
|
||||
@ -90,7 +89,7 @@ Vector2f AP_AHRS_DCM::groundspeed_vector(void)
|
||||
if (gotAirspeed) {
|
||||
const Vector3f wind = wind_estimate();
|
||||
const Vector2f wind2d(wind.x, wind.y);
|
||||
const Vector2f airspeed_vector(_cos_yaw * airspeed, _sin_yaw * airspeed);
|
||||
const Vector2f airspeed_vector{cosf(yaw) * airspeed, sinf(yaw) * airspeed};
|
||||
gndVelADS = airspeed_vector + wind2d;
|
||||
}
|
||||
|
||||
@ -148,7 +147,7 @@ Vector2f AP_AHRS_DCM::groundspeed_vector(void)
|
||||
/*
|
||||
calculate sin and cos of roll/pitch/yaw from a body_to_ned rotation matrix
|
||||
*/
|
||||
void AP_AHRS_Backend::calc_trig(const Matrix3f &rot,
|
||||
void AP_AHRS::calc_trig(const Matrix3f &rot,
|
||||
float &cr, float &cp, float &cy,
|
||||
float &sr, float &sp, float &sy) const
|
||||
{
|
||||
@ -194,7 +193,7 @@ void AP_AHRS_Backend::calc_trig(const Matrix3f &rot,
|
||||
|
||||
// update_trig - recalculates _cos_roll, _cos_pitch, etc based on latest attitude
|
||||
// should be called after _dcm_matrix is updated
|
||||
void AP_AHRS_Backend::update_trig(void)
|
||||
void AP_AHRS::update_trig(void)
|
||||
{
|
||||
calc_trig(get_rotation_body_to_ned(),
|
||||
_cos_roll, _cos_pitch, _cos_yaw,
|
||||
@ -204,7 +203,7 @@ void AP_AHRS_Backend::update_trig(void)
|
||||
/*
|
||||
update the centi-degree values
|
||||
*/
|
||||
void AP_AHRS_Backend::update_cd_values(void)
|
||||
void AP_AHRS::update_cd_values(void)
|
||||
{
|
||||
roll_sensor = degrees(roll) * 100;
|
||||
pitch_sensor = degrees(pitch) * 100;
|
||||
@ -286,14 +285,14 @@ void AP_AHRS::update_AOA_SSA(void)
|
||||
}
|
||||
|
||||
// rotate a 2D vector from earth frame to body frame
|
||||
Vector2f AP_AHRS_Backend::earth_to_body2D(const Vector2f &ef) const
|
||||
Vector2f AP_AHRS::earth_to_body2D(const Vector2f &ef) const
|
||||
{
|
||||
return Vector2f(ef.x * _cos_yaw + ef.y * _sin_yaw,
|
||||
-ef.x * _sin_yaw + ef.y * _cos_yaw);
|
||||
}
|
||||
|
||||
// rotate a 2D vector from earth frame to body frame
|
||||
Vector2f AP_AHRS_Backend::body_to_earth2D(const Vector2f &bf) const
|
||||
Vector2f AP_AHRS::body_to_earth2D(const Vector2f &bf) const
|
||||
{
|
||||
return Vector2f(bf.x * _cos_yaw - bf.y * _sin_yaw,
|
||||
bf.x * _sin_yaw + bf.y * _cos_yaw);
|
||||
@ -322,7 +321,7 @@ float AP_AHRS_Backend::get_EAS2TAS(void) const {
|
||||
}
|
||||
|
||||
// return current vibration vector for primary IMU
|
||||
Vector3f AP_AHRS_Backend::get_vibration(void) const
|
||||
Vector3f AP_AHRS::get_vibration(void) const
|
||||
{
|
||||
return AP::ins().get_vibration_levels();
|
||||
}
|
||||
|
@ -33,6 +33,12 @@ class OpticalFlow;
|
||||
#define AP_AHRS_RP_P_MIN 0.05f // minimum value for AHRS_RP_P parameter
|
||||
#define AP_AHRS_YAW_P_MIN 0.05f // minimum value for AHRS_YAW_P parameter
|
||||
|
||||
enum class GPSUse : uint8_t {
|
||||
Disable = 0,
|
||||
Enable = 1,
|
||||
EnableWithHeight = 2,
|
||||
};
|
||||
|
||||
class AP_AHRS_Backend
|
||||
{
|
||||
public:
|
||||
@ -43,6 +49,20 @@ public:
|
||||
// empty virtual destructor
|
||||
virtual ~AP_AHRS_Backend() {}
|
||||
|
||||
CLASS_NO_COPY(AP_AHRS_Backend);
|
||||
|
||||
// structure to retrieve results from backends:
|
||||
struct Estimates {
|
||||
float roll_rad;
|
||||
float pitch_rad;
|
||||
float yaw_rad;
|
||||
Matrix3f dcm_matrix;
|
||||
Vector3f gyro_estimate;
|
||||
Vector3f gyro_drift;
|
||||
Vector3f accel_ef[INS_MAX_INSTANCES]; // must be INS_MAX_INSTANCES
|
||||
Vector3f accel_ef_blended;
|
||||
};
|
||||
|
||||
// init sets up INS board orientation
|
||||
virtual void init();
|
||||
|
||||
@ -59,26 +79,10 @@ public:
|
||||
return AP::ins().get_primary_gyro();
|
||||
}
|
||||
|
||||
// accelerometer values in the earth frame in m/s/s
|
||||
virtual const Vector3f &get_accel_ef(uint8_t i) const {
|
||||
return _accel_ef[i];
|
||||
}
|
||||
virtual const Vector3f &get_accel_ef(void) const {
|
||||
return get_accel_ef(AP::ins().get_primary_accel());
|
||||
}
|
||||
|
||||
// blended accelerometer values in the earth frame in m/s/s
|
||||
virtual const Vector3f &get_accel_ef_blended(void) const {
|
||||
return _accel_ef_blended;
|
||||
}
|
||||
|
||||
// get yaw rate in earth frame in radians/sec
|
||||
float get_yaw_rate_earth(void) const {
|
||||
return get_gyro() * get_rotation_body_to_ned().c;
|
||||
}
|
||||
|
||||
// Methods
|
||||
virtual void _update() = 0;
|
||||
virtual void update() = 0;
|
||||
|
||||
virtual void get_results(Estimates &results) = 0;
|
||||
|
||||
// returns false if we fail arming checks, in which case the buffer will be populated with a failure message
|
||||
// requires_position should be true if horizontal position configuration should be checked
|
||||
@ -102,59 +106,12 @@ public:
|
||||
// set position, velocity and yaw sources to either 0=primary, 1=secondary, 2=tertiary
|
||||
virtual void set_posvelyaw_source_set(uint8_t source_set_idx) {}
|
||||
|
||||
// Euler angles (radians)
|
||||
float roll;
|
||||
float pitch;
|
||||
float yaw;
|
||||
|
||||
float get_roll() const { return roll; }
|
||||
float get_pitch() const { return pitch; }
|
||||
float get_yaw() const { return yaw; }
|
||||
|
||||
// integer Euler angles (Degrees * 100)
|
||||
int32_t roll_sensor;
|
||||
int32_t pitch_sensor;
|
||||
int32_t yaw_sensor;
|
||||
|
||||
// return a smoothed and corrected gyro vector in radians/second
|
||||
virtual const Vector3f &get_gyro(void) const = 0;
|
||||
|
||||
// return primary accels, for lua
|
||||
const Vector3f &get_accel(void) const {
|
||||
return AP::ins().get_accel();
|
||||
}
|
||||
|
||||
// return a smoothed and corrected gyro vector in radians/second using the latest ins data (which may not have been consumed by the EKF yet)
|
||||
Vector3f get_gyro_latest(void) const;
|
||||
|
||||
// return the current estimate of the gyro drift
|
||||
virtual const Vector3f &get_gyro_drift(void) const = 0;
|
||||
|
||||
// reset the current gyro drift estimate
|
||||
// should be called if gyro offsets are recalculated
|
||||
virtual void reset_gyro_drift(void) = 0;
|
||||
|
||||
// reset the current attitude, used on new IMU calibration
|
||||
virtual void reset(bool recover_eulers=false) = 0;
|
||||
|
||||
// return the average size of the roll/pitch error estimate
|
||||
// since last call
|
||||
virtual float get_error_rp(void) const = 0;
|
||||
|
||||
// return the average size of the yaw error estimate
|
||||
// since last call
|
||||
virtual float get_error_yaw(void) const = 0;
|
||||
|
||||
// return a DCM rotation matrix representing our current attitude in NED frame
|
||||
virtual const Matrix3f &get_rotation_body_to_ned(void) const = 0;
|
||||
|
||||
// return a Quaternion representing our current attitude in NED frame
|
||||
void get_quat_body_to_ned(Quaternion &quat) const {
|
||||
quat.from_rotation_matrix(get_rotation_body_to_ned());
|
||||
}
|
||||
|
||||
// get rotation matrix specifically from DCM backend (used for compass calibrator)
|
||||
virtual const Matrix3f &get_DCM_rotation_body_to_ned(void) const = 0;
|
||||
virtual void reset() = 0;
|
||||
|
||||
// get our current position estimate. Return true if a position is available,
|
||||
// otherwise false. This call fills in lat, lng and alt
|
||||
@ -168,7 +125,8 @@ public:
|
||||
|
||||
// return an airspeed estimate if available. return true
|
||||
// if we have an estimate
|
||||
virtual bool airspeed_estimate(float &airspeed_ret) const WARN_IF_UNUSED = 0;
|
||||
virtual bool airspeed_estimate(float &airspeed_ret) const WARN_IF_UNUSED { return false; }
|
||||
virtual bool airspeed_estimate(uint8_t airspeed_index, float &airspeed_ret) const { return false; }
|
||||
|
||||
// return a true airspeed estimate (navigation airspeed) if
|
||||
// available. return true if we have an estimate
|
||||
@ -219,11 +177,29 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get a derivative of the vertical position in m/s which is kinematically consistent with the vertical position is required by some control loops.
|
||||
// This is different to the vertical velocity from the EKF which is not always consistent with the vertical position due to the various errors that are being corrected for.
|
||||
virtual bool get_vert_pos_rate(float &velocity) const = 0;
|
||||
|
||||
// returns the estimated magnetic field offsets in body frame
|
||||
virtual bool get_mag_field_correction(Vector3f &ret) const WARN_IF_UNUSED {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool get_mag_field_NED(Vector3f &vec) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool get_mag_offsets(uint8_t mag_idx, Vector3f &magOffsets) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
virtual bool set_origin(const Location &loc) {
|
||||
return false;
|
||||
}
|
||||
virtual bool get_origin(Location &ret) const = 0;
|
||||
|
||||
// return a position relative to origin in meters, North/East/Down
|
||||
// order. This will only be accurate if have_inertial_nav() is
|
||||
// true
|
||||
@ -251,44 +227,9 @@ public:
|
||||
// return true if we will use compass for yaw
|
||||
virtual bool use_compass(void) = 0;
|
||||
|
||||
// helper trig value accessors
|
||||
float cos_roll() const {
|
||||
return _cos_roll;
|
||||
}
|
||||
float cos_pitch() const {
|
||||
return _cos_pitch;
|
||||
}
|
||||
float cos_yaw() const {
|
||||
return _cos_yaw;
|
||||
}
|
||||
float sin_roll() const {
|
||||
return _sin_roll;
|
||||
}
|
||||
float sin_pitch() const {
|
||||
return _sin_pitch;
|
||||
}
|
||||
float sin_yaw() const {
|
||||
return _sin_yaw;
|
||||
}
|
||||
|
||||
// return the quaternion defining the rotation from NED to XYZ (body) axes
|
||||
virtual bool get_quaternion(Quaternion &quat) const WARN_IF_UNUSED = 0;
|
||||
|
||||
// return secondary attitude solution if available, as eulers in radians
|
||||
virtual bool get_secondary_attitude(Vector3f &eulers) const WARN_IF_UNUSED {
|
||||
return false;
|
||||
}
|
||||
|
||||
// return secondary attitude solution if available, as quaternion
|
||||
virtual bool get_secondary_quaternion(Quaternion &quat) const WARN_IF_UNUSED {
|
||||
return false;
|
||||
}
|
||||
|
||||
// return secondary position solution if available
|
||||
virtual bool get_secondary_position(struct Location &loc) const WARN_IF_UNUSED {
|
||||
return false;
|
||||
}
|
||||
|
||||
// return true if the AHRS object supports inertial navigation,
|
||||
// with very accurate position and velocity
|
||||
virtual bool have_inertial_nav(void) const {
|
||||
@ -302,6 +243,9 @@ public:
|
||||
virtual bool initialised(void) const {
|
||||
return true;
|
||||
};
|
||||
virtual bool started(void) const {
|
||||
return initialised();
|
||||
};
|
||||
|
||||
// return the amount of yaw angle change due to the last yaw angle reset in radians
|
||||
// returns the time of the last yaw angle reset or 0 if no reset has ever occurred
|
||||
@ -342,6 +286,10 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool get_filter_status(nav_filter_status &status) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get_variances - provides the innovations normalised using the innovation variance where a value of 0
|
||||
// indicates perfect consistency between the measurement and the EKF solution and a value of of 1 is the maximum
|
||||
// inconsistency that will be accepted by the filter
|
||||
@ -356,30 +304,14 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void send_ekf_status_report(mavlink_channel_t chan) const = 0;
|
||||
|
||||
// Retrieves the corrected NED delta velocity in use by the inertial navigation
|
||||
virtual void getCorrectedDeltaVelocityNED(Vector3f& ret, float& dt) const {
|
||||
ret.zero();
|
||||
AP::ins().get_delta_velocity(ret, dt);
|
||||
}
|
||||
|
||||
// rotate a 2D vector from earth frame to body frame
|
||||
// in result, x is forward, y is right
|
||||
Vector2f earth_to_body2D(const Vector2f &ef_vector) const;
|
||||
|
||||
// rotate a 2D vector from earth frame to body frame
|
||||
// in input, x is forward, y is right
|
||||
Vector2f body_to_earth2D(const Vector2f &bf) const;
|
||||
|
||||
// convert a vector from body to earth frame
|
||||
Vector3f body_to_earth(const Vector3f &v) const {
|
||||
return v * get_rotation_body_to_ned();
|
||||
}
|
||||
|
||||
// convert a vector from earth to body frame
|
||||
Vector3f earth_to_body(const Vector3f &v) const {
|
||||
return get_rotation_body_to_ned().mul_transpose(v);
|
||||
}
|
||||
|
||||
// get_hgt_ctrl_limit - get maximum height to be observed by the
|
||||
// control loops in meters and a validity flag. It will return
|
||||
// false when no limiting is required
|
||||
@ -389,63 +321,4 @@ public:
|
||||
// this is not related to terrain following
|
||||
virtual void set_terrain_hgt_stable(bool stable) {}
|
||||
|
||||
// Write position and quaternion data from an external navigation system
|
||||
virtual void writeExtNavData(const Vector3f &pos, const Quaternion &quat, float posErr, float angErr, uint32_t timeStamp_ms, uint16_t delay_ms, uint32_t resetTime_ms) { }
|
||||
|
||||
// Write velocity data from an external navigation system
|
||||
virtual void writeExtNavVelData(const Vector3f &vel, float err, uint32_t timeStamp_ms, uint16_t delay_ms) { }
|
||||
|
||||
// return current vibration vector for primary IMU
|
||||
Vector3f get_vibration(void) const;
|
||||
|
||||
// set and save the alt noise parameter value
|
||||
virtual void set_alt_measurement_noise(float noise) {};
|
||||
|
||||
// allow threads to lock against AHRS update
|
||||
HAL_Semaphore &get_semaphore(void) {
|
||||
return _rsem;
|
||||
}
|
||||
|
||||
// Logging to disk functions
|
||||
void Write_AHRS2(void) const;
|
||||
void Write_Attitude(const Vector3f &targets) const;
|
||||
void Write_Origin(uint8_t origin_type, const Location &loc) const;
|
||||
void Write_POS(void) const;
|
||||
|
||||
protected:
|
||||
|
||||
enum class GPSUse : uint8_t {
|
||||
Disable = 0,
|
||||
Enable = 1,
|
||||
EnableWithHeight = 2,
|
||||
};
|
||||
|
||||
AP_Enum<GPSUse> _gps_use;
|
||||
|
||||
// multi-thread access support
|
||||
HAL_Semaphore _rsem;
|
||||
|
||||
// calculate sin/cos of roll/pitch/yaw from rotation
|
||||
void calc_trig(const Matrix3f &rot,
|
||||
float &cr, float &cp, float &cy,
|
||||
float &sr, float &sp, float &sy) const;
|
||||
|
||||
// update_trig - recalculates _cos_roll, _cos_pitch, etc based on latest attitude
|
||||
// should be called after _dcm_matrix is updated
|
||||
void update_trig(void);
|
||||
|
||||
// update roll_sensor, pitch_sensor and yaw_sensor
|
||||
void update_cd_values(void);
|
||||
|
||||
// accelerometer values in the earth frame in m/s/s
|
||||
Vector3f _accel_ef[INS_MAX_INSTANCES];
|
||||
Vector3f _accel_ef_blended;
|
||||
|
||||
// helper trig variables
|
||||
float _cos_roll{1.0f};
|
||||
float _cos_pitch{1.0f};
|
||||
float _cos_yaw{1.0f};
|
||||
float _sin_roll;
|
||||
float _sin_pitch;
|
||||
float _sin_yaw;
|
||||
};
|
||||
|
@ -63,9 +63,10 @@ void AP_AHRS::load_watchdog_home()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// run a full DCM update round
|
||||
void
|
||||
AP_AHRS_DCM::_update()
|
||||
AP_AHRS_DCM::update()
|
||||
{
|
||||
AP_InertialSensor &_ins = AP::ins();
|
||||
|
||||
@ -93,11 +94,12 @@ AP_AHRS_DCM::_update()
|
||||
// paranoid check for bad values in the DCM matrix
|
||||
check_matrix();
|
||||
|
||||
// Calculate pitch, roll, yaw for stabilization and navigation
|
||||
euler_angles();
|
||||
|
||||
// update trig values including _cos_roll, cos_pitch
|
||||
update_trig();
|
||||
// calculate the euler angles and DCM matrix which will be used
|
||||
// for high level navigation control. Apply trim such that a
|
||||
// positive trim value results in a positive vehicle rotation
|
||||
// about that axis (ie a negative offset)
|
||||
_body_dcm_matrix = _dcm_matrix * AP::ahrs().get_rotation_vehicle_body_to_autopilot_body();
|
||||
_body_dcm_matrix.to_euler(&roll, &pitch, &yaw);
|
||||
|
||||
backup_attitude();
|
||||
|
||||
@ -105,6 +107,21 @@ AP_AHRS_DCM::_update()
|
||||
IGNORE_RETURN(AP::ahrs().get_origin(last_origin));
|
||||
}
|
||||
|
||||
void AP_AHRS_DCM::get_results(AP_AHRS_Backend::Estimates &results)
|
||||
{
|
||||
results.roll_rad = roll;
|
||||
results.pitch_rad = pitch;
|
||||
results.yaw_rad = yaw;
|
||||
|
||||
results.dcm_matrix = _body_dcm_matrix;
|
||||
results.gyro_estimate = _omega;
|
||||
results.gyro_drift = _omega_I;
|
||||
|
||||
const uint8_t to_copy = MIN(sizeof(results.accel_ef), sizeof(_accel_ef));
|
||||
memcpy(results.accel_ef, _accel_ef, to_copy);
|
||||
results.accel_ef_blended = _accel_ef_blended;
|
||||
}
|
||||
|
||||
/*
|
||||
backup attitude to persistent_data for use in watchdog reset
|
||||
*/
|
||||
@ -162,9 +179,6 @@ AP_AHRS_DCM::matrix_update(float _G_Dt)
|
||||
void
|
||||
AP_AHRS_DCM::reset(bool recover_eulers)
|
||||
{
|
||||
// support locked access functions to AHRS data
|
||||
WITH_SEMAPHORE(_rsem);
|
||||
|
||||
// reset the integration terms
|
||||
_omega_I.zero();
|
||||
_omega_P.zero();
|
||||
@ -437,8 +451,8 @@ bool AP_AHRS_DCM::use_compass(void)
|
||||
// degrees and the estimated wind speed is less than 80% of the
|
||||
// ground speed, then switch to GPS navigation. This will help
|
||||
// prevent flyaways with very bad compass offsets
|
||||
const int32_t error = labs(wrap_180_cd(yaw_sensor - AP::gps().ground_course_cd()));
|
||||
if (error > 4500 && _wind.length() < AP::gps().ground_speed()*0.8f) {
|
||||
const float error = fabsf(wrap_180(degrees(yaw) - AP::gps().ground_course()));
|
||||
if (error > 45 && _wind.length() < AP::gps().ground_speed()*0.8f) {
|
||||
if (AP_HAL::millis() - _last_consistent_heading > 2000) {
|
||||
// start using the GPS for heading if the compass has been
|
||||
// inconsistent with the GPS for 2 seconds
|
||||
@ -727,8 +741,7 @@ AP_AHRS_DCM::drift_correction(float deltat)
|
||||
Vector3f airspeed = velocity - _wind;
|
||||
|
||||
// rotate vector to body frame
|
||||
const Matrix3f &rot = get_rotation_body_to_ned();
|
||||
airspeed = rot.mul_transpose(airspeed);
|
||||
airspeed = _body_dcm_matrix.mul_transpose(airspeed);
|
||||
|
||||
// take positive component in X direction. This mimics a pitot
|
||||
// tube
|
||||
@ -913,7 +926,7 @@ AP_AHRS_DCM::drift_correction(float deltat)
|
||||
if (fly_forward && _gps.status() >= AP_GPS::GPS_OK_FIX_2D &&
|
||||
_gps.ground_speed() < GPS_SPEED_MIN &&
|
||||
_ins.get_accel().x >= 7 &&
|
||||
pitch_sensor > -3000 && pitch_sensor < 3000) {
|
||||
pitch > radians(-30) && pitch < radians(30)) {
|
||||
// assume we are in a launch acceleration, and reduce the
|
||||
// rp gain by 50% to reduce the impact of GPS lag on
|
||||
// takeoff attitude when using a catapult
|
||||
@ -1013,19 +1026,6 @@ void AP_AHRS_DCM::estimate_wind(void)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// calculate the euler angles and DCM matrix which will be used for high level
|
||||
// navigation control. Apply trim such that a positive trim value results in a
|
||||
// positive vehicle rotation about that axis (ie a negative offset)
|
||||
void
|
||||
AP_AHRS_DCM::euler_angles(void)
|
||||
{
|
||||
_body_dcm_matrix = _dcm_matrix * AP::ahrs().get_rotation_vehicle_body_to_autopilot_body();
|
||||
_body_dcm_matrix.to_euler(&roll, &pitch, &yaw);
|
||||
|
||||
update_cd_values();
|
||||
}
|
||||
|
||||
// return our current position estimate using
|
||||
// dead-reckoning or GPS
|
||||
bool AP_AHRS_DCM::get_position(struct Location &loc) const
|
||||
@ -1155,6 +1155,18 @@ bool AP_AHRS_DCM::get_velocity_NED(Vector3f &vec) const
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get a derivative of the vertical position in m/s which is kinematically consistent with the vertical position is required by some control loops.
|
||||
// This is different to the vertical velocity from the EKF which is not always consistent with the vertical position due to the various errors that are being corrected for.
|
||||
bool AP_AHRS_DCM::get_vert_pos_rate(float &velocity) const
|
||||
{
|
||||
Vector3f velned;
|
||||
if (!get_velocity_NED(velned)) {
|
||||
return false;
|
||||
}
|
||||
velocity = velned.z;
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns false if we fail arming checks, in which case the buffer will be populated with a failure message
|
||||
// requires_position should be true if horizontal position configuration should be checked (not used)
|
||||
bool AP_AHRS_DCM::pre_arm_check(bool requires_position, char *failure_msg, uint8_t failure_msg_len) const
|
||||
@ -1169,7 +1181,7 @@ bool AP_AHRS_DCM::pre_arm_check(bool requires_position, char *failure_msg, uint8
|
||||
/*
|
||||
relative-origin functions for fallback in AP_InertialNav
|
||||
*/
|
||||
bool AP_AHRS_DCM::get_origin_fallback(Location &ret) const
|
||||
bool AP_AHRS_DCM::get_origin(Location &ret) const
|
||||
{
|
||||
ret = last_origin;
|
||||
if (ret.is_zero()) {
|
||||
@ -1182,7 +1194,7 @@ bool AP_AHRS_DCM::get_origin_fallback(Location &ret) const
|
||||
bool AP_AHRS_DCM::get_relative_position_NED_origin(Vector3f &posNED) const
|
||||
{
|
||||
Location origin;
|
||||
if (!AP_AHRS_DCM::get_origin_fallback(origin)) {
|
||||
if (!AP_AHRS_DCM::get_origin(origin)) {
|
||||
return false;
|
||||
}
|
||||
Location loc;
|
||||
@ -1212,3 +1224,9 @@ bool AP_AHRS_DCM::get_relative_position_D_origin(float &posD) const
|
||||
posD = posNED.z;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AP_AHRS_DCM::send_ekf_status_report(mavlink_channel_t chan) const
|
||||
{
|
||||
// send zero status report
|
||||
mavlink_msg_ekf_status_report_send(chan, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
@ -25,8 +25,20 @@
|
||||
|
||||
class AP_AHRS_DCM : public AP_AHRS_Backend {
|
||||
public:
|
||||
AP_AHRS_DCM()
|
||||
: AP_AHRS_Backend()
|
||||
|
||||
AP_AHRS_DCM(AP_Float &kp_yaw,
|
||||
AP_Float &kp,
|
||||
AP_Float &_gps_gain,
|
||||
AP_Float &_beta,
|
||||
AP_Enum<GPSUse> &gps_use,
|
||||
AP_Int8 &gps_minsats)
|
||||
: AP_AHRS_Backend(),
|
||||
_kp_yaw(kp_yaw),
|
||||
_kp(kp),
|
||||
gps_gain(_gps_gain),
|
||||
beta(_beta),
|
||||
_gps_use(gps_use),
|
||||
_gps_minsats(gps_minsats)
|
||||
{
|
||||
_dcm_matrix.identity();
|
||||
}
|
||||
@ -35,31 +47,14 @@ public:
|
||||
AP_AHRS_DCM(const AP_AHRS_DCM &other) = delete;
|
||||
AP_AHRS_DCM &operator=(const AP_AHRS_DCM&) = delete;
|
||||
|
||||
// return the smoothed gyro vector corrected for drift
|
||||
const Vector3f &get_gyro() const override {
|
||||
return _omega;
|
||||
}
|
||||
|
||||
// return rotation matrix representing rotaton from body to earth axes
|
||||
const Matrix3f &get_rotation_body_to_ned() const override {
|
||||
return _body_dcm_matrix;
|
||||
}
|
||||
|
||||
// get rotation matrix specifically from DCM backend (used for compass calibrator)
|
||||
const Matrix3f &get_DCM_rotation_body_to_ned(void) const override { return _body_dcm_matrix; }
|
||||
|
||||
// return the current drift correction integrator value
|
||||
const Vector3f &get_gyro_drift() const override {
|
||||
return _omega_I;
|
||||
}
|
||||
|
||||
// reset the current gyro drift estimate
|
||||
// should be called if gyro offsets are recalculated
|
||||
void reset_gyro_drift() override;
|
||||
|
||||
// Methods
|
||||
void _update() override;
|
||||
void reset(bool recover_eulers = false) override;
|
||||
void update() override;
|
||||
void get_results(Estimates &results) override;
|
||||
void reset() override { reset(false); }
|
||||
|
||||
// return true if yaw has been initialised
|
||||
bool yaw_initialised(void) const {
|
||||
@ -70,10 +65,10 @@ public:
|
||||
virtual bool get_position(struct Location &loc) const override;
|
||||
|
||||
// status reporting
|
||||
float get_error_rp() const override {
|
||||
float get_error_rp() const {
|
||||
return _error_rp;
|
||||
}
|
||||
float get_error_yaw() const override {
|
||||
float get_error_yaw() const {
|
||||
return _error_yaw;
|
||||
}
|
||||
|
||||
@ -88,7 +83,7 @@ public:
|
||||
|
||||
// return an airspeed estimate if available. return true
|
||||
// if we have an estimate from a specific sensor index
|
||||
bool airspeed_estimate(uint8_t airspeed_index, float &airspeed_ret) const;
|
||||
bool airspeed_estimate(uint8_t airspeed_index, float &airspeed_ret) const override;
|
||||
|
||||
// return a synthetic airspeed estimate (one derived from sensors
|
||||
// other than an actual airspeed sensor), if available. return
|
||||
@ -114,34 +109,44 @@ public:
|
||||
|
||||
bool get_velocity_NED(Vector3f &vec) const override;
|
||||
|
||||
// Get a derivative of the vertical position in m/s which is kinematically consistent with the vertical position is required by some control loops.
|
||||
// This is different to the vertical velocity from the EKF which is not always consistent with the vertical position due to the various errors that are being corrected for.
|
||||
bool get_vert_pos_rate(float &velocity) const override;
|
||||
|
||||
// returns false if we fail arming checks, in which case the buffer will be populated with a failure message
|
||||
// requires_position should be true if horizontal position configuration should be checked (not used)
|
||||
bool pre_arm_check(bool requires_position, char *failure_msg, uint8_t failure_msg_len) const override;
|
||||
|
||||
// relative-origin functions for fallback in AP_InertialNav
|
||||
bool get_origin_fallback(Location &ret) const;
|
||||
bool get_origin(Location &ret) const override;
|
||||
bool get_relative_position_NED_origin(Vector3f &vec) const override;
|
||||
bool get_relative_position_NE_origin(Vector2f &posNE) const override;
|
||||
bool get_relative_position_D_origin(float &posD) const override;
|
||||
|
||||
protected:
|
||||
|
||||
// settable parameters
|
||||
AP_Float _kp_yaw;
|
||||
AP_Float _kp;
|
||||
AP_Float gps_gain;
|
||||
|
||||
AP_Float beta;
|
||||
|
||||
AP_Int8 _gps_minsats;
|
||||
void send_ekf_status_report(mavlink_channel_t chan) const override;
|
||||
|
||||
private:
|
||||
|
||||
// settable parameters
|
||||
AP_Float &_kp_yaw;
|
||||
AP_Float &_kp;
|
||||
AP_Float &gps_gain;
|
||||
|
||||
AP_Float β
|
||||
|
||||
AP_Int8 &_gps_minsats;
|
||||
|
||||
AP_Enum<GPSUse> &_gps_use;
|
||||
|
||||
// these are experimentally derived from the simulator
|
||||
// with large drift levels
|
||||
static constexpr float _ki = 0.0087f;
|
||||
static constexpr float _ki_yaw = 0.01f;
|
||||
|
||||
// accelerometer values in the earth frame in m/s/s
|
||||
Vector3f _accel_ef[INS_MAX_INSTANCES];
|
||||
Vector3f _accel_ef_blended;
|
||||
|
||||
// Methods
|
||||
void matrix_update(float _G_Dt);
|
||||
void normalize(void);
|
||||
@ -150,17 +155,26 @@ private:
|
||||
void drift_correction(float deltat);
|
||||
void drift_correction_yaw(void);
|
||||
float yaw_error_compass(class Compass &compass);
|
||||
void euler_angles(void);
|
||||
bool have_gps(void) const;
|
||||
bool use_fast_gains(void) const;
|
||||
void backup_attitude(void);
|
||||
|
||||
// internal reset function. Called externally, we never reset the
|
||||
// DCM matrix from the eulers. Called internally we may.
|
||||
void reset(bool recover_eulers);
|
||||
|
||||
// primary representation of attitude of board used for all inertial calculations
|
||||
Matrix3f _dcm_matrix;
|
||||
|
||||
// primary representation of attitude of flight vehicle body
|
||||
Matrix3f _body_dcm_matrix;
|
||||
|
||||
// euler angles - used for recovering if the DCM
|
||||
// matrix becomes ill-conditioned and watchdog storage
|
||||
float roll;
|
||||
float pitch;
|
||||
float yaw;
|
||||
|
||||
Vector3f _omega_P; // accel Omega proportional correction
|
||||
Vector3f _omega_yaw_P; // proportional yaw correction
|
||||
Vector3f _omega_I; // Omega Integrator correction
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
|
||||
// Write an AHRS2 packet
|
||||
void AP_AHRS_Backend::Write_AHRS2() const
|
||||
void AP_AHRS::Write_AHRS2() const
|
||||
{
|
||||
Vector3f euler;
|
||||
struct Location loc;
|
||||
@ -45,7 +45,7 @@ void AP_AHRS::Write_AOA_SSA(void) const
|
||||
}
|
||||
|
||||
// Write an attitude packet
|
||||
void AP_AHRS_Backend::Write_Attitude(const Vector3f &targets) const
|
||||
void AP_AHRS::Write_Attitude(const Vector3f &targets) const
|
||||
{
|
||||
const struct log_Attitude pkt{
|
||||
LOG_PACKET_HEADER_INIT(LOG_ATTITUDE_MSG),
|
||||
@ -63,7 +63,7 @@ void AP_AHRS_Backend::Write_Attitude(const Vector3f &targets) const
|
||||
AP::logger().WriteBlock(&pkt, sizeof(pkt));
|
||||
}
|
||||
|
||||
void AP_AHRS_Backend::Write_Origin(uint8_t origin_type, const Location &loc) const
|
||||
void AP_AHRS::Write_Origin(uint8_t origin_type, const Location &loc) const
|
||||
{
|
||||
const struct log_ORGN pkt{
|
||||
LOG_PACKET_HEADER_INIT(LOG_ORGN_MSG),
|
||||
@ -77,7 +77,7 @@ void AP_AHRS_Backend::Write_Origin(uint8_t origin_type, const Location &loc) con
|
||||
}
|
||||
|
||||
// Write a POS packet
|
||||
void AP_AHRS_Backend::Write_POS() const
|
||||
void AP_AHRS::Write_POS() const
|
||||
{
|
||||
Location loc;
|
||||
if (!get_position(loc)) {
|
||||
|
Loading…
Reference in New Issue
Block a user