/sw/airborne/subsystems/ahrs/ahrs_float_ekf.c
https://bitbucket.org/tamasszabo/paparazzi_mavlink · C · 164 lines · 52 code · 20 blank · 92 comment · 0 complexity · 4a1323d9906a5594f2895829ce3f47b7 MD5 · raw file
- /*
- * Copyright (C) 2008-2009 Antoine Drouin <poinix@gmail.com>
- *
- * This file is part of paparazzi.
- *
- * paparazzi is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * paparazzi is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with paparazzi; see the file COPYING. If not, write to
- * the Free Software Foundation, 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
- #include "math/pprz_algebra_float.h"
- /* our estimated attitude */
- struct FloatQuat bafe_quat;
- /* our estimated gyro biases */
- struct FloatRates bafe_bias;
- /* we get unbiased body rates as byproduct */
- struct FloatRates bafe_rates;
- /* maintain a euler angles representation */
- struct FloatEulers bafe_eulers;
- /* maintains a rotation matrix representation */
- struct FloatEulers bafe_dcm;
- /* time derivative of our quaternion */
- struct FloatQuat bafe_qdot;
- #define BAFE_SSIZE 7
- /* covariance matrix and its time derivative */
- float bafe_P[BAFE_SSIZE][BAFE_SSIZE];
- float bafe_Pdot[BAFE_SSIZE][BAFE_SSIZE];
- /*
- * F represents the Jacobian of the derivative of the system with respect
- * its states. We do not allocate the bottom three rows since we know that
- * the derivatives of bias_dot are all zero.
- */
- float bafe_F[4][7];
- /*
- * Kalman filter variables.
- */
- float bafe_PHt[7];
- float bafe_K[7];
- float bafe_E;
- /*
- * H represents the Jacobian of the measurements of the attitude
- * with respect to the states of the filter. We do not allocate the bottom
- * three rows since we know that the attitude measurements have no
- * relationship to gyro bias.
- */
- float bafe_H[4];
- /* temporary variable used during state covariance update */
- float bafe_FP[4][7];
- /*
- * Q is our estimate noise variance. It is supposed to be an NxN
- * matrix, but with elements only on the diagonals. Additionally,
- * since the quaternion has no expected noise (we can't directly measure
- * it), those are zero. For the gyro, we expect around 5 deg/sec noise,
- * which is 0.08 rad/sec. The variance is then 0.08^2 ~= 0.0075.
- */
- /* I measured about 0.009 rad/s noise */
- #define bafe_Q_gyro 8e-03
- /*
- * R is our measurement noise estimate. Like Q, it is supposed to be
- * an NxN matrix with elements on the diagonals. However, since we can
- * not directly measure the gyro bias, we have no estimate for it.
- * We only have an expected noise in the pitch and roll accelerometers
- * and in the compass.
- */
- #define BAFE_R_PHI 1.3 * 1.3
- #define BAFE_R_THETA 1.3 * 1.3
- #define BAFE_R_PSI 2.5 * 2.5
- #ifndef BAFE_DT
- #define BAFE_DT (1./512.)
- #endif
- extern void ahrs_init(void);
- extern void ahrs_align(void);
- /*
- * Propagate our dynamic system
- *
- * quat_dot = Wxq(pqr) * quat
- * bias_dot = 0
- *
- * Wxq is the quaternion omega matrix:
- *
- * [ 0, -p, -q, -r ]
- * 1/2 * [ p, 0, r, -q ]
- * [ q, -r, 0, p ]
- * [ r, q, -p, 0 ]
- *
- *
- *
- *
- * [ 0 -p -q -r q1 q2 q3]
- * F = 1/2 * [ p 0 r -q -q0 q3 -q2]
- * [ q -r 0 p -q3 -q0 q1]
- * [ r q -p 0 q2 -q1 -q0]
- * [ 0 0 0 0 0 0 0]
- * [ 0 0 0 0 0 0 0]
- * [ 0 0 0 0 0 0 0]
- *
- */
- void ahrs_propagate(void) {
- /* compute unbiased rates */
- RATES_FLOAT_OF_BFP(bafe_rates, imu.gyro);
- RATES_SUB(bafe_rates, bafe_bias);
- /* compute F
- F is only needed later on to update the state covariance P.
- However, its [0:3][0:3] region is actually the Wxq(pqr) which is needed to
- compute the time derivative of the quaternion, so we compute F now
- */
- /* Fill in Wxq(pqr) into F */
- bafe_F[0][0] = bafe_F[1][1] = bafe_F[2][2] = bafe_F[3][3] = 0;
- bafe_F[1][0] = bafe_F[2][3] = bafe_rates.p * 0.5;
- bafe_F[2][0] = bafe_F[3][1] = bafe_rates.q * 0.5;
- bafe_F[3][0] = bafe_F[1][2] = bafe_rates.r * 0.5;
- bafe_F[0][1] = bafe_F[3][2] = -bafe_F[1][0];
- bafe_F[0][2] = bafe_F[1][3] = -bafe_F[2][0];
- bafe_F[0][3] = bafe_F[2][1] = -bafe_F[3][0];
- /* Fill in [4:6][0:3] region */
- bafe_F[0][4] = bafe_F[2][6] = bafe_quat.qx * 0.5;
- bafe_F[0][5] = bafe_F[3][4] = bafe_quat.qy * 0.5;
- bafe_F[0][6] = bafe_F[1][5] = bafe_quat.qz * 0.5;
- bafe_F[1][4] = bafe_F[2][5] = bafe_F[3][6] = bafe_quat.qi * -0.5;
- bafe_F[3][5] = -bafe_F[0][4];
- bafe_F[1][6] = -bafe_F[0][5];
- bafe_F[2][4] = -bafe_F[0][6];
- /* quat_dot = Wxq(pqr) * quat */
- bafe_qdot.qi= bafe_F[0][1]*bafe_quat.qx+bafe_F[0][2]*bafe_quat.qy+bafe_F[0][3] * bafe_quat.qz;
- bafe_qdot.qx= bafe_F[1][0]*bafe_quat.qi +bafe_F[1][2]*bafe_quat.qy+bafe_F[1][3] * bafe_quat.qz;
- bafe_qdot.qy= bafe_F[2][0]*bafe_quat.qi+bafe_F[2][1]*bafe_quat.qx +bafe_F[2][3] * bafe_quat.qz;
- bafe_qdot.qz= bafe_F[3][0]*bafe_quat.qi+bafe_F[3][1]*bafe_quat.qx+bafe_F[3][2]*bafe_quat.qy ;
- /* propagate quaternion */
- bafe_quat.qi += bafe_qdot.qi * BAFE_DT;
- bafe_quat.qx += bafe_qdot.qx * BAFE_DT;
- bafe_quat.qy += bafe_qdot.qy * BAFE_DT;
- bafe_quat.qz += bafe_qdot.qz * BAFE_DT;
- }
- extern void ahrs_update(void);