Quaternion: go back to the full update_MARG()

the separate drift controller is too erratic on yaw hold to be usable
at the moment
This commit is contained in:
Andrew Tridgell 2012-03-09 09:02:04 +11:00
parent c8189c80d4
commit 3989fe2c2c
2 changed files with 42 additions and 31 deletions

View File

@ -310,11 +310,11 @@ void AP_Quaternion::update_MARG(float deltat, Vector3f &gyro, Vector3f &accel, V
// Function to update our gyro_bias drift estimate using the accelerometer // Function to update our gyro_bias drift estimate using the accelerometer
// and magnetometer. This is a cut-down version of update_MARG(), but // and magnetometer. This is a cut-down version of update_MARG(), but
// without the quaternion update. // without the quaternion update.
void AP_Quaternion::update_drift(float deltat, Vector3f &gyro, Vector3f &accel, Vector3f &mag) void AP_Quaternion::update_drift(float deltat, Vector3f &mag)
{ {
// local system variables // local system variables
float norm; // vector norm float norm; // vector norm
float f_1, f_2, f_3, f_4, f_5, f_6; // objective function elements float f_4, f_5, f_6; // objective function elements
float J_11or24, J_12or23, J_13or22, J_14or21, J_32, J_33, // objective function Jacobian elements float J_11or24, J_12or23, J_13or22, J_14or21, J_32, J_33, // objective function Jacobian elements
J_41, J_42, J_43, J_44, J_51, J_52, J_53, J_54, J_61, J_62, J_63, J_64; // J_41, J_42, J_43, J_44, J_51, J_52, J_53, J_54, J_61, J_62, J_63, J_64; //
float SEqHatDot_1, SEqHatDot_2, SEqHatDot_3, SEqHatDot_4; // estimated direction of the gyroscope error float SEqHatDot_1, SEqHatDot_2, SEqHatDot_3, SEqHatDot_4; // estimated direction of the gyroscope error
@ -325,14 +325,6 @@ void AP_Quaternion::update_drift(float deltat, Vector3f &gyro, Vector3f &accel,
// estimated direction of the gyroscope error (radians) // estimated direction of the gyroscope error (radians)
Vector3f w_err; Vector3f w_err;
// normalise accelerometer vector
accel.normalize();
if (accel.is_inf()) {
// discard this data point
renorm_range_count++;
return;
}
// normalise the magnetometer measurement // normalise the magnetometer measurement
mag.normalize(); mag.normalize();
if (mag.is_inf()) { if (mag.is_inf()) {
@ -365,9 +357,6 @@ void AP_Quaternion::update_drift(float deltat, Vector3f &gyro, Vector3f &accel,
Vector3f twom = mag * 2.0; Vector3f twom = mag * 2.0;
// compute the objective function and Jacobian // compute the objective function and Jacobian
f_1 = twoSEq_2 * SEq_4 - twoSEq_1 * SEq_3 - accel.x;
f_2 = twoSEq_1 * SEq_2 + twoSEq_3 * SEq_4 - accel.y;
f_3 = 1.0f - twoSEq_2 * SEq_2 - twoSEq_3 * SEq_3 - accel.z;
f_4 = twob_x * (0.5f - SEq_3 * SEq_3 - SEq_4 * SEq_4) + twob_z * (SEq_2SEq_4 - SEq_1SEq_3) - mag.x; f_4 = twob_x * (0.5f - SEq_3 * SEq_3 - SEq_4 * SEq_4) + twob_z * (SEq_2SEq_4 - SEq_1SEq_3) - mag.x;
f_5 = twob_x * (SEq_2 * SEq_3 - SEq_1 * SEq_4) + twob_z * (SEq_1 * SEq_2 + SEq_3 * SEq_4) - mag.y; f_5 = twob_x * (SEq_2 * SEq_3 - SEq_1 * SEq_4) + twob_z * (SEq_1 * SEq_2 + SEq_3 * SEq_4) - mag.y;
f_6 = twob_x * (SEq_1SEq_3 + SEq_2SEq_4) + twob_z * (0.5f - SEq_2 * SEq_2 - SEq_3 * SEq_3) - mag.z; f_6 = twob_x * (SEq_1SEq_3 + SEq_2SEq_4) + twob_z * (0.5f - SEq_2 * SEq_2 - SEq_3 * SEq_3) - mag.z;
@ -391,10 +380,10 @@ void AP_Quaternion::update_drift(float deltat, Vector3f &gyro, Vector3f &accel,
J_64 = twob_xSEq_2; J_64 = twob_xSEq_2;
// compute the gradient (matrix multiplication) // compute the gradient (matrix multiplication)
SEqHatDot_1 = J_14or21 * f_2 - J_11or24 * f_1 - J_41 * f_4 - J_51 * f_5 + J_61 * f_6; SEqHatDot_1 = - J_41 * f_4 - J_51 * f_5 + J_61 * f_6;
SEqHatDot_2 = J_12or23 * f_1 + J_13or22 * f_2 - J_32 * f_3 + J_42 * f_4 + J_52 * f_5 + J_62 * f_6; SEqHatDot_2 = + J_42 * f_4 + J_52 * f_5 + J_62 * f_6;
SEqHatDot_3 = J_12or23 * f_2 - J_33 * f_3 - J_13or22 * f_1 - J_43 * f_4 + J_53 * f_5 + J_63 * f_6; SEqHatDot_3 = - J_43 * f_4 + J_53 * f_5 + J_63 * f_6;
SEqHatDot_4 = J_14or21 * f_1 + J_11or24 * f_2 - J_44 * f_4 - J_54 * f_5 + J_64 * f_6; SEqHatDot_4 = - J_44 * f_4 - J_54 * f_5 + J_64 * f_6;
// normalise the gradient to estimate direction of the gyroscope error // normalise the gradient to estimate direction of the gyroscope error
norm = 1.0 / safe_sqrt(SEqHatDot_1 * SEqHatDot_1 + SEqHatDot_2 * SEqHatDot_2 + SEqHatDot_3 * SEqHatDot_3 + SEqHatDot_4 * SEqHatDot_4); norm = 1.0 / safe_sqrt(SEqHatDot_1 * SEqHatDot_1 + SEqHatDot_2 * SEqHatDot_2 + SEqHatDot_3 * SEqHatDot_3 + SEqHatDot_4 * SEqHatDot_4);
@ -430,6 +419,28 @@ void AP_Quaternion::update_drift(float deltat, Vector3f &gyro, Vector3f &accel,
drift_delta.z = constrain(drift_delta.z, -max_change, max_change); drift_delta.z = constrain(drift_delta.z, -max_change, max_change);
gyro_bias += drift_delta; gyro_bias += drift_delta;
// compute then integrate the estimated quaternion rate
SEq_1 -= (beta * SEqHatDot_1) * deltat;
SEq_2 -= (beta * SEqHatDot_2) * deltat;
SEq_3 -= (beta * SEqHatDot_3) * deltat;
SEq_4 -= (beta * SEqHatDot_4) * deltat;
// normalise quaternion
norm = 1.0/safe_sqrt(SEq_1 * SEq_1 + SEq_2 * SEq_2 + SEq_3 * SEq_3 + SEq_4 * SEq_4);
if (isinf(norm)) {
// our quaternion is bad! Reset based on roll/pitch/yaw
// and hope for the best ...
renorm_blowup_count++;
_compass->null_offsets_disable();
quaternion_from_euler(q, roll, pitch, yaw);
_compass->null_offsets_disable();
return;
}
SEq_1 *= norm;
SEq_2 *= norm;
SEq_3 *= norm;
SEq_4 *= norm;
// compute flux in the earth frame // compute flux in the earth frame
// recompute axulirary variables // recompute axulirary variables
SEq_1SEq_2 = SEq_1 * SEq_2; SEq_1SEq_2 = SEq_1 * SEq_2;
@ -506,10 +517,8 @@ void AP_Quaternion::update(void)
accel.z += (gyro.y - gyro_bias.y) * veloc; accel.z += (gyro.y - gyro_bias.y) * veloc;
} }
_gyro_sum += gyro; #define SEPARATE_DRIFT 0
_accel_sum += accel; #if SEPARATE_DRIFT
_sum_count++;
/* /*
The full Madgwick quaternion 'MARG' system assumes you get The full Madgwick quaternion 'MARG' system assumes you get
gyro, accel and magnetometer updates at the same rate. On gyro, accel and magnetometer updates at the same rate. On
@ -521,24 +530,28 @@ void AP_Quaternion::update(void)
new magnetometer point, and use the much simpler new magnetometer point, and use the much simpler
update_IMU() as the main quaternion update function. update_IMU() as the main quaternion update function.
*/ */
_gyro_sum += gyro;
_accel_sum += accel;
_sum_count++;
if (_compass != NULL && _compass->use_for_yaw() && if (_compass != NULL && _compass->use_for_yaw() &&
_compass->last_update != _compass_last_update && _compass->last_update != _compass_last_update &&
_sum_count != 0) { _sum_count != 0) {
// use new compass sample for drift correction // use new compass sample for drift correction
float mag_deltat = 1.0e-6*(_compass->last_update - _compass_last_update); float mag_deltat = 1.0e-6*(_compass->last_update - _compass_last_update);
Vector3f mag = Vector3f(_compass->mag_x, _compass->mag_y, - _compass->mag_z); Vector3f mag = Vector3f(_compass->mag_x, _compass->mag_y, - _compass->mag_z);
Vector3f drift_accel = _accel_sum / _sum_count;
Vector3f drift_gyro = _gyro_sum / _sum_count;
_accel_sum.zero();
_gyro_sum.zero();
_sum_count = 0; _sum_count = 0;
update_drift(mag_deltat, drift_gyro, drift_accel, mag); update_drift(mag_deltat, mag);
_compass_last_update = _compass->last_update; _compass_last_update = _compass->last_update;
} }
// step the quaternion solution using just gyros and accels // step the quaternion solution using just gyros and accels
gyro -= gyro_bias; gyro -= gyro_bias;
update_IMU(deltat, gyro, accel); update_IMU(deltat, gyro, accel);
#else
Vector3f mag = Vector3f(_compass->mag_x, _compass->mag_y, - _compass->mag_z);
update_MARG(deltat, gyro, accel, mag);
#endif
#ifdef DESKTOP_BUILD #ifdef DESKTOP_BUILD
if (q.is_nan()) { if (q.is_nan()) {

View File

@ -78,7 +78,7 @@ public:
private: private:
void update_IMU(float deltat, Vector3f &gyro, Vector3f &accel); void update_IMU(float deltat, Vector3f &gyro, Vector3f &accel);
void update_MARG(float deltat, Vector3f &gyro, Vector3f &accel, Vector3f &mag); void update_MARG(float deltat, Vector3f &gyro, Vector3f &accel, Vector3f &mag);
void update_drift(float deltat, Vector3f &gyro, Vector3f &accel, Vector3f &mag); void update_drift(float deltat, Vector3f &mag);
bool _have_initial_yaw; bool _have_initial_yaw;
@ -99,11 +99,9 @@ private:
bool _centripetal; bool _centripetal;
// maximum gyroscope measurement error in rad/s (set to 7 degrees/second) // maximum gyroscope measurement error in rad/s (set to 7 degrees/second)
static const float gyroMeasError = 7.0 * (M_PI/180.0); static const float gyroMeasError = 20.0 * (M_PI/180.0);
// maximum gyroscope drift rate in radians/s/s (set to 0.005 float gyroMeasDrift;
// degrees/s/s, which is 0.3 degrees/s/minute)
static const float gyroMeasDrift = 0.04 * (PI/180.0);
float beta; float beta;
float zeta; float zeta;