/** ****************************************************************************** * @addtogroup AHRS * @{ * @addtogroup INSGPS * @{ * @brief INSGPS is a joint attitude and position estimation EKF * * @file insgps.c * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @brief An INS/GPS algorithm implemented with an EKF. * * @see The GNU Public License (GPL) Version 3 * *****************************************************************************/ /* * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "insgps.h" #include #include #include // constants/macros/typdefs #define NUMX 13 // number of states, X is the state vector #define NUMW 9 // number of plant noise inputs, w is disturbance noise vector #define NUMV 10 // number of measurements, v is the measurement noise vector #define NUMU 6 // number of deterministic inputs, U is the input vector // Private functions void CovariancePrediction(float F[NUMX][NUMX], float G[NUMX][NUMW], float Q[NUMW], float dT, float P[NUMX][NUMX]); void SerialUpdate(float H[NUMV][NUMX], float R[NUMV], float Z[NUMV], float Y[NUMV], float P[NUMX][NUMX], float X[NUMX], float K[NUMX][NUMV], uint16_t SensorsUsed); void RungeKutta(float X[NUMX], float U[NUMU], float dT); void StateEq(float X[NUMX], float U[NUMU], float Xdot[NUMX]); void LinearizeFG(float X[NUMX], float U[NUMU], float F[NUMX][NUMX], float G[NUMX][NUMW]); void MeasurementEq(float X[NUMX], float Be[3], float Y[NUMV]); void LinearizeH(float X[NUMX], float Be[3], float H[NUMV][NUMX]); // Private variables // speed optimizations, describe matrix sparsity // derived from state equations in // LinearizeFG() and LinearizeH(): // // usage F: usage G: usage H: // 0123456789abc 012345678 0123456789abc // 0...X......... ......... X............ // 1....X........ ......... .X........... // 2.....X....... ......... ..X.......... // 3......XXXX... ...XXX... ...X......... // 4......XXXX... ...XXX... ....X........ // 5......XXXX... ...XXX... .....X....... // 6.......XXXXXX XXX...... ......XXXX... // 7......X.XXXXX XXX...... ......XXXX... // 8......XX.XXXX XXX...... ......XXXX... // 9......XXX.XXX XXX...... ..X.......... // a............. ......X.. // b............. .......X. // c............. ........X static const int8_t FrowMin[NUMX] = { 3, 4, 5, 6, 6, 6, 7, 6, 6, 6,13,13,13 }; static const int8_t FrowMax[NUMX] = { 3, 4, 5, 9, 9, 9,12,12,12,12,-1,-1,-1 }; static const int8_t GrowMin[NUMX] = { 9, 9, 9, 3, 3, 3, 0, 0, 0, 0, 6, 7, 8 }; static const int8_t GrowMax[NUMX] = { -1,-1,-1, 5, 5, 5, 2, 2, 2, 2, 6, 7, 8 }; static const int8_t HrowMin[NUMV] = { 0, 1, 2, 3, 4, 5, 6, 6, 6, 2 }; static const int8_t HrowMax[NUMV] = { 0, 1, 2, 3, 4, 5, 9, 9, 9, 2 }; static struct EKFData { // linearized system matrices float F[NUMX][NUMX]; float G[NUMX][NUMW]; float H[NUMV][NUMX]; // local magnetic unit vector in NED frame float Be[3]; // covariance matrix and state vector float P[NUMX][NUMX]; float X[NUMX]; // input noise and measurement noise variances float Q[NUMW]; float R[NUMV]; float K[NUMX][NUMV]; // feedback gain matrix } ekf; // Global variables struct NavStruct Nav; // ************* Exposed Functions **************** // ************************************************* uint16_t ins_get_num_states() { return NUMX; } void INSGPSInit() //pretty much just a place holder for now { ekf.Be[0] = 1.0f; ekf.Be[1] = 0.0f; ekf.Be[2] = 0.0f; // local magnetic unit vector for (int i = 0; i < NUMX; i++) { for (int j = 0; j < NUMX; j++) { ekf.P[i][j] = 0.0f; // zero all terms ekf.F[i][j] = 0.0f; } for (int j = 0; j < NUMW; j++) ekf.G[i][j] = 0.0f; for (int j = 0; j < NUMV; j++) { ekf.H[j][i] = 0.0f; ekf.K[i][j] = 0.0f; } ekf.X[i] = 0.0f; } for (int i = 0; i < NUMW; i++) ekf.Q[i] = 0.0f; for (int i = 0; i < NUMV; i++) ekf.R[i] = 0.0f; ekf.P[0][0] = ekf.P[1][1] = ekf.P[2][2] = 25.0f; // initial position variance (m^2) ekf.P[3][3] = ekf.P[4][4] = ekf.P[5][5] = 5.0f; // initial velocity variance (m/s)^2 ekf.P[6][6] = ekf.P[7][7] = ekf.P[8][8] = ekf.P[9][9] = 1e-5f; // initial quaternion variance ekf.P[10][10] = ekf.P[11][11] = ekf.P[12][12] = 1e-9f; // initial gyro bias variance (rad/s)^2 ekf.X[0] = ekf.X[1] = ekf.X[2] = ekf.X[3] = ekf.X[4] = ekf.X[5] = 0.0f; // initial pos and vel (m) ekf.X[6] = 1.0f; ekf.X[7] = ekf.X[8] = ekf.X[9] = 0.0f; // initial quaternion (level and North) (m/s) ekf.X[10] = ekf.X[11] = ekf.X[12] = 0.0f; // initial gyro bias (rad/s) ekf.Q[0] = ekf.Q[1] = ekf.Q[2] = 50e-4f; // gyro noise variance (rad/s)^2 ekf.Q[3] = ekf.Q[4] = ekf.Q[5] = 0.00001f; // accelerometer noise variance (m/s^2)^2 ekf.Q[6] = ekf.Q[7] = ekf.Q[8] = 2e-8f; // gyro bias random walk variance (rad/s^2)^2 ekf.R[0] = ekf.R[1] = 0.004f; // High freq GPS horizontal position noise variance (m^2) ekf.R[2] = 0.036f; // High freq GPS vertical position noise variance (m^2) ekf.R[3] = ekf.R[4] = 0.004f; // High freq GPS horizontal velocity noise variance (m/s)^2 ekf.R[5] = 100.0f; // High freq GPS vertical velocity noise variance (m/s)^2 ekf.R[6] = ekf.R[7] = ekf.R[8] = 0.005f; // magnetometer unit vector noise variance ekf.R[9] = .25f; // High freq altimeter noise variance (m^2) } void INSResetP(float PDiag[NUMX]) { uint8_t i,j; // if PDiag[i] nonzero then clear row and column and set diagonal element for (i=0;i