diff --git a/libraries/AP_Quaternion/AP_Quaternion.cpp b/libraries/AP_Quaternion/AP_Quaternion.cpp index d86c7268b3..3a297d5798 100644 --- a/libraries/AP_Quaternion/AP_Quaternion.cpp +++ b/libraries/AP_Quaternion/AP_Quaternion.cpp @@ -307,7 +307,9 @@ void AP_Quaternion::update_MARG(float deltat, Vector3f &gyro, Vector3f &accel, V } -// Function to compute one quaternion iteration including magnetometer +// Function to update our gyro_bias drift estimate using the accelerometer +// and magnetometer. This is a cut-down version of update_MARG(), but +// without the quaternion update. void AP_Quaternion::update_drift(float deltat, Vector3f &gyro, Vector3f &accel, Vector3f &mag) { // local system variables @@ -458,11 +460,6 @@ void AP_Quaternion::update(void) Vector3f gyro, accel; float deltat; -#ifdef DESKTOP_BUILD - Quaternion q_saved = q; - Vector3f bias_saved = gyro_bias; -#endif - _imu->update(); deltat = _imu->get_delta_time(); @@ -513,11 +510,21 @@ void AP_Quaternion::update(void) accel.z += (gyro.y - gyro_bias.y) * veloc; } -#if 1 _gyro_sum += gyro; _accel_sum += accel; _sum_count++; + /* + The full Madgwick quaternion 'MARG' system assumes you get + gyro, accel and magnetometer updates at the same rate. On + APM we get them at very different rates, and re-calculating + our drift due to the magnetometer in the fast loop is very + wasteful of CPU. + + Instead, we only update the gyro_bias vector when we get a + new magnetometer point, and use the much simpler + update_IMU() as the main quaternion update function. + */ if (_compass != NULL && _compass->use_for_yaw() && _compass->last_update != _compass_last_update && _sum_count != 0) { @@ -533,64 +540,28 @@ void AP_Quaternion::update(void) _compass_last_update = _compass->last_update; } - // step the quaternion solution + // step the quaternion solution using just gyros and accels gyro -= gyro_bias; update_IMU(deltat, gyro, accel); -#else - if (_compass != NULL && _compass->use_for_yaw()) { - // use new compass sample for drift correction - Vector3f mag = Vector3f(_compass->mag_x, _compass->mag_y, - _compass->mag_z); - update_MARG(deltat, gyro, accel, mag); - } else { - // step the quaternion without drift correction - gyro -= gyro_bias; - _gyro_sum += gyro; - _accel_sum += accel; - _sum_count++; - update_IMU(deltat, gyro, accel); - } -#endif #ifdef DESKTOP_BUILD if (q.is_nan()) { - SITL_debug("QUAT NAN: deltat=%f roll=%f pitch=%f yaw=%f q0=[%f %f %f %f] q=[%f %f %f %f] a=[%f %f %f] g=(%f %f %f)\n", + SITL_debug("QUAT NAN: deltat=%f roll=%f pitch=%f yaw=%f q=[%f %f %f %f] a=[%f %f %f] g=(%f %f %f)\n", deltat, roll, pitch, yaw, - q_saved.q1, q_saved.q2, q_saved.q3, q_saved.q4, q.q1, q.q2, q.q3, q.q4, accel.x, accel.y, accel.z, gyro.x, gyro.y, gyro.z); - q = q_saved; - gyro_bias = bias_saved; - update_IMU(deltat, gyro, accel); } #endif // keep the corrected gyro for reporting _gyro_corrected = gyro; - // compute the Eulers - float test = (SEq_1*SEq_3 - SEq_4*SEq_2); - const float singularity = 0.499; // 86.3 degrees? - if (test > singularity) { - // singularity at south pole - // this one is ok.. - yaw = 2.0 * atan2(SEq_4, SEq_1); - pitch = ToRad(-90.0); - roll = 0.0; - } else if (test < -singularity) { - // singularity at north pole - // this one is invalid :( .. fix it. - yaw = -2.0 * atan2(SEq_4, SEq_1); - pitch = ToRad(90.0); - roll = 0.0; - } else { - roll = -(atan2(2.0*(SEq_1*SEq_2 + SEq_3*SEq_4), - 1 - 2.0*(SEq_2*SEq_2 + SEq_3*SEq_3))); - pitch = -safe_asin(2.0*test); - yaw = atan2(2.0*(SEq_1*SEq_4 + SEq_2*SEq_3), - 1 - 2.0*(SEq_3*SEq_3 + SEq_4*SEq_4)); - } + // calculate our euler angles for high level control and navigation + euler_from_quaternion(q, &roll, &pitch, &yaw); + // the code above assumes zero magnetic declination, so offset + // the yaw here if (_compass != NULL) { yaw += _compass->get_declination(); }