Simple example to show how to get an estimation of the attitude with a 9DOF IMU and the Kalman filter
Dependencies: L3GD20 LSM303DLHC mbed-dsp mbed
Fork of minimu-9v2 by
Revision 1:ba2d31e3112d, committed 2017-03-25
- Comitter:
- capriele
- Date:
- Sat Mar 25 16:48:32 2017 +0000
- Parent:
- 0:4b3d36de811a
- Commit message:
- Simple example to get an estimation of the attitude thought a 9DOF IMU and the Kalman filter
Changed in this revision
diff -r 4b3d36de811a -r ba2d31e3112d LSM303DLHC.lib --- a/LSM303DLHC.lib Thu Feb 21 00:24:06 2013 +0000 +++ b/LSM303DLHC.lib Sat Mar 25 16:48:32 2017 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/bclaus/code/LSM303DLHC/#612f7d5a822d +https://developer.mbed.org/users/capriele/code/LSM303DLHC/#8b1fada3fc6d
diff -r 4b3d36de811a -r ba2d31e3112d main.cpp --- a/main.cpp Thu Feb 21 00:24:06 2013 +0000 +++ b/main.cpp Sat Mar 25 16:48:32 2017 +0000 @@ -1,26 +1,42 @@ #include "mbed.h" #include "L3GD20.h" #include "LSM303DLHC.h" - -L3GD20 gyro(p28, p27); +#include "math.h" +#include "arm_math.h" +#include "sensfusion9.h" +L3GD20 gyro(D14, D15); Serial debug(USBTX,USBRX); -LSM303DLHC compass(p28, p27); +LSM303DLHC compass(D14, D15); +float ax, ay, az; +float mx, my, mz; +float gx, gy, gz; +float roll, pitch, yaw; +Ticker kalmanTimer; +float dt = 0.01; +void attitudeUpdate(void) { +} - int main() { - float ax, ay, az; - float mx, my, mz; - float gx, gy, gz; - debug.format(8,Serial::None,1); +int main() { + //inizializzo filtro di kalman + sensfusion9Init(); + //kalmanTimer.attach(&attitudeUpdate, dt); + + debug.format(8, Serial::None, 1); debug.baud(115200); - debug.printf("miniimu-9 v2 Test"); - + + //lunghezza asta + float l = 1.0f; while(1) { - - compass.read(&ax, &ay, &az, &mx, &my, &mz); - gyro.read(&gx, &gy, &gz); - debug.printf("a %.4f %.4f %.4f m %.4f %.4f %.4f m %.4f %.4f %.4f\n\r",ax,ay,az,mx,my,mz,gx,gy,gz); - wait(0.05); + compass.read(&ax, &ay, &az, &mx, &my, &mz); + gyro.read(&gx, &gy, &gz); + sensfusion9UpdateQ(gx+(ax/l)*dt, gy+(ay/l)*dt, gz+(az/l)*dt, ax, ay, az, mx, my, mz, dt); + sensfusion9GetEulerRPY(&roll, &pitch, &yaw); + //debug.printf("%.10f %.10f %.10f\n\r", mx, my, mz); + //debug.printf("a %.4f %.4f %.4f m %.4f %.4f %.4f m %.4f %.4f %.4f R:%.4f P:%.4f Y:%.4f\n\r",ax,ay,az,mx,my,mz,gx,gy,gz,roll, pitch, yaw); + //debug.printf("R:%.4f P:%.4f Y:%.4f\n\r", roll, pitch, yaw); + debug.printf("%.4f %.4f %.4f\n\r", roll, pitch+3, yaw); + wait(dt); } - } \ No newline at end of file +} \ No newline at end of file
diff -r 4b3d36de811a -r ba2d31e3112d mbed-dsp.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-dsp.lib Sat Mar 25 16:48:32 2017 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/mbed_official/code/mbed-dsp/#3762170b6d4d
diff -r 4b3d36de811a -r ba2d31e3112d mbed.bld --- a/mbed.bld Thu Feb 21 00:24:06 2013 +0000 +++ b/mbed.bld Sat Mar 25 16:48:32 2017 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/mbed_official/code/mbed/builds/3d0ef94e36ec \ No newline at end of file +http://mbed.org/users/mbed_official/code/mbed/builds/e1686b8d5b90 \ No newline at end of file
diff -r 4b3d36de811a -r ba2d31e3112d sensfusion9.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sensfusion9.c Sat Mar 25 16:48:32 2017 +0000 @@ -0,0 +1,595 @@ +#include "sensfusion9.h" +#include "math.h" +#include "arm_math.h" + +#define M_PI_F 3.14159265358979323846f /* pi */ + +static inline void mat_trans(const arm_matrix_instance_f32 * pSrc, arm_matrix_instance_f32 * pDst) +{ + arm_mat_trans_f32(pSrc, pDst); +} +static inline void mat_inv(const arm_matrix_instance_f32 * pSrc, arm_matrix_instance_f32 * pDst) +{ + arm_mat_inverse_f32(pSrc, pDst); +} +static inline void mat_mult(const arm_matrix_instance_f32 * pSrcA, const arm_matrix_instance_f32 * pSrcB, arm_matrix_instance_f32 * pDst) +{ + arm_mat_mult_f32(pSrcA, pSrcB, pDst); +} +static inline float arm_sqrt(float32_t in) +{ + float pOut = 0; + arm_status result = arm_sqrt_f32(in, &pOut); + return pOut; +} + +#define STATE_SIZE 4 +#define OUTPUT_SIZE 6 +static float Q_VARIANCE = 0.01f; +static float R_VARIANCE_ACC = 25.0f; +static float R_VARIANCE_MAG = 50.0f; + +// The covariance matrix +static float P[STATE_SIZE][STATE_SIZE] = {{0}}; +static float R[OUTPUT_SIZE] = {0}; +static arm_matrix_instance_f32 Pm = {STATE_SIZE, STATE_SIZE, (float *)P}; + +// The state update matrix +static float A[STATE_SIZE][STATE_SIZE]; +static arm_matrix_instance_f32 Am = {STATE_SIZE, STATE_SIZE, (float *)A}; // linearized dynamics for covariance update; + +// Temporary matrices for the covariance updates +static float tmpNN1d[STATE_SIZE][STATE_SIZE]; +static arm_matrix_instance_f32 tmpNN1m = { STATE_SIZE, STATE_SIZE, (float *)tmpNN1d}; + +static float tmpNN2d[STATE_SIZE][STATE_SIZE]; +static arm_matrix_instance_f32 tmpNN2m = { STATE_SIZE, STATE_SIZE, (float *)tmpNN2d}; + +// quaternion of sensor frame relative to auxiliary frame +static float q0 = 1.0f; +static float q1 = 0.0f; +static float q2 = 0.0f; +static float q3 = 0.0f; + +// Unit vector in the estimated gravity direction +static float gravX, gravY, gravZ; + +// The acc in Z for static position (g) +// Set on first update, assuming we are in a static position since the sensors were just calibrates. +// This value will be better the more level the copter is at calibration time +static float baseZacc = 1.0; + +static bool isInit; + +static bool isCalibrated = false; + +static void sensfusion9UpdateQImpl(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz, float dt); +static float sensfusion9GetAccZ(const float ax, const float ay, const float az); +static void estimatedGravityDirection(float* gx, float* gy, float* gz); + +// TODO: Make math util file +static float invSqrt(float x); + +void sensfusion9Init() +{ + if(isInit) + return; + for(int i = 0; i < STATE_SIZE; ++i) + P[i][i] = Q_VARIANCE; + R[0] = R_VARIANCE_ACC; + R[1] = R_VARIANCE_ACC; + R[2] = R_VARIANCE_ACC; + R[3] = R_VARIANCE_MAG; + R[4] = R_VARIANCE_MAG; + R[5] = R_VARIANCE_MAG; + isInit = true; +} + +bool sensfusion9Test(void) +{ + return isInit; +} + +void sensfusion9UpdateQ(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz, float dt) +{ + //Cambio gli assi del magnetometro perchè rispetto a quelli del gyro/acc sono diversi: + //In particolare: + //Mx = (Gy = Ay) + //My = (Gx = Ax) + //-Mz = (Gz = Az) + sensfusion9UpdateQImpl(gx, gy, gz, ax, ay, az, mx, my, mz, dt); + estimatedGravityDirection(&gravX, &gravY, &gravZ); + if (!isCalibrated) { + baseZacc = sensfusion9GetAccZ(ax, ay, az); + isCalibrated = true; + } +} + +/* +static void sensfusion9UpdateQImpl(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz, float dt) +{ + float recipNorm; + + gx = gx * M_PI_F / 180.0f; + gy = gy * M_PI_F / 180.0f; + gz = gz * M_PI_F / 180.0f; + + // Normalise accelerometer measurement + recipNorm = invSqrt(ax*ax + ay*ay + az*az); + ax *= recipNorm; + ay *= recipNorm; + az *= recipNorm; + + // Normalise magnetometer measurement + recipNorm = invSqrt(mx*mx + my*my + mz*mz); + mx *= recipNorm; + my *= recipNorm; + mz *= recipNorm; + + A[0][0] = 1.0f; + A[0][1] = gz*dt; + A[0][2] = -gy*dt; + A[1][0] = -gz*dt; + A[1][1] = 1.0f; + A[1][2] = gx*dt; + A[2][0] = gy*dt; + A[2][1] = -gx*dt; + A[2][2] = 1.0f; + + float q[4][1]; + arm_matrix_instance_f32 qm = {4, 1, (float *)q}; + q[0][0] = q0; + q[1][0] = q1; + q[2][0] = q2; + q[3][0] = q3; + + float W[4][4]; + arm_matrix_instance_f32 Wm = {4, 4, (float *)W}; + W[0][0] = 0.0f; + W[0][1] = -gx; + W[0][2] = -gy; + W[0][3] = -gz; + W[1][0] = gx; + W[1][1] = 0.0f; + W[1][2] = gz; + W[1][3] = -gy; + W[2][0] = gy; + W[2][1] = -gz; + W[2][2] = 0.0f; + W[2][3] = gx; + W[3][0] = gz; + W[3][1] = gy; + W[3][2] = -gx; + W[3][3] = 0.0f; + + //Aggiorno lo stato con runge kutta 4 + float m1[4][1]; + float m2[4][1]; + float m3[4][1]; + float x1[4][1]; + float x2[4][1]; + arm_matrix_instance_f32 m1m = {4, 1, (float *)m1}; + arm_matrix_instance_f32 m2m = {4, 1, (float *)m2}; + arm_matrix_instance_f32 m3m = {4, 1, (float *)m3}; + arm_matrix_instance_f32 x1m = {4, 1, (float *)x1}; + arm_matrix_instance_f32 x2m = {4, 1, (float *)x2}; + + //Primo step + mat_mult(&Wm, &qm, &m1m); + for(int i = 0; i < 4; ++i){ + x1[i][0] = q[i][0] + 0.5f*m1[i][0]*dt; + } + + //Secondo step + mat_mult(&Wm, &x1m, &m2m); + for(int i = 0; i < 4; ++i){ + x2[i][0] = q[i][0] + 0.5f*(m1[i][0] + m2[i][0])*dt/4.0f; + } + + //Terzo step + mat_mult(&Wm, &x2m, &m3m); + for(int i = 0; i < 4; ++i){ + q[i][0] = q[i][0] + 0.5f*(m1[i][0] + m2[i][0] + 4.0f*m3[i][0])*(dt/6.0f); + } + + //Normalizzo la stima dei quaternioni + recipNorm = invSqrt(q[0][0]*q[0][0] + q[1][0]*q[1][0] + q[2][0]*q[2][0] + q[3][0]*q[3][0]); + for(int i = 0; i < 4; ++i){ + q[i][0] *= recipNorm; + } + + q0 = q[0][0]; + q1 = q[1][0]; + q2 = q[2][0]; + q3 = q[3][0]; + + //Matrice di rotazione + float QuaternionDCM[3][3]; + arm_matrix_instance_f32 QuaternionDCMm = {3, 3, (float *)QuaternionDCM}; + QuaternionDCM[0][0] = 2*q0*q0-1+2*q1*q1; + QuaternionDCM[0][1] = 2*(q1*q2+q0*q3); + QuaternionDCM[0][2] = 2*(q1*q3-q0*q2); + QuaternionDCM[1][0] = 2*(q1*q2-q0*q3); + QuaternionDCM[1][1] = 2*q0*q0-1+2*q2*q2; + QuaternionDCM[1][2] = 2*(q2*q3+q0*q1); + QuaternionDCM[2][0] = 2*(q1*q3+q0*q2); + QuaternionDCM[2][1] = 2*(q2*q3-q0*q1); + QuaternionDCM[2][2] = 2*q0*q0-1+2*q3*q3; + + //Gravity Reference + float G[3][1]; + float Gr[3][1]; + arm_matrix_instance_f32 Gm = {3, 1, (float *)G}; + arm_matrix_instance_f32 Grm = {3, 1, (float *)Gr}; + G[0][0] = 0; + G[1][0] = 0; + G[2][0] = 1; + mat_mult(&QuaternionDCMm, &Gm, &Grm); + + //Magnetic field Reference + float M[3][1]; + float Mr[3][1]; + arm_matrix_instance_f32 Mm = {3, 1, (float *)M}; + arm_matrix_instance_f32 Mrm = {3, 1, (float *)Mr}; + float hx = mx*q0*q0 + 2.0f*mz*q0*q2 - 2.0f*my*q0*q3 + mx*q1*q1 + 2.0f*my*q1*q2 + 2.0f*mz*q1*q3 - mx*q2*q2 - mx*q3*q3; + float hy = my*q0*q0 - 2.0f*mz*q0*q1 + 2.0f*mx*q0*q3 - my*q1*q1 + 2.0f*mx*q1*q2 + my*q2*q2 + 2.0f*mz*q2*q3 - my*q3*q3; + float hz = mz*q0*q0 + 2.0f*my*q0*q1 - 2.0f*mx*q0*q2 - mz*q1*q1 + 2.0f*mx*q1*q3 - mz*q2*q1 + 2.0f*my*q2*q3 + mz*q3*q3; + M[0][0] = arm_sqrt(hx*hx + hy*hy); + M[1][0] = 0; + M[2][0] = hz; + mat_mult(&QuaternionDCMm, &Mm, &Mrm); + + // Aggiorno la Covarianza + float P0[STATE_SIZE][STATE_SIZE]; + arm_matrix_instance_f32 P0m = {STATE_SIZE, STATE_SIZE, (float *)P0}; + + mat_mult(&Am, &Pm, &tmpNN1m); // A P + mat_trans(&Am, &tmpNN2m); // A' + mat_mult(&tmpNN1m, &tmpNN2m, &P0m); // A P A' + for(int i = 0; i < STATE_SIZE; ++i){ + P0[i][i] += Q_VARIANCE; + } + + // Calcolo il guadagno + float K[STATE_SIZE][OUTPUT_SIZE]; + arm_matrix_instance_f32 Km = {STATE_SIZE, OUTPUT_SIZE, (float *)K}; + + float h[OUTPUT_SIZE][STATE_SIZE]; + arm_matrix_instance_f32 Hm = {OUTPUT_SIZE, STATE_SIZE, (float *)h}; + + float hT[STATE_SIZE][OUTPUT_SIZE]; + arm_matrix_instance_f32 HTm = {STATE_SIZE, OUTPUT_SIZE, (float *)hT}; + + float P0hT[STATE_SIZE][OUTPUT_SIZE]; + arm_matrix_instance_f32 P0HTm = {STATE_SIZE, OUTPUT_SIZE, (float *)P0hT}; + + float hP0hT[OUTPUT_SIZE][OUTPUT_SIZE]; + arm_matrix_instance_f32 HP0HTm = {OUTPUT_SIZE, OUTPUT_SIZE, (float *)hP0hT}; + + float hP0hT_inv[OUTPUT_SIZE][OUTPUT_SIZE]; + arm_matrix_instance_f32 HP0HT_INVm = {OUTPUT_SIZE, OUTPUT_SIZE, (float *)hP0hT_inv}; + + //Accelerometer + h[0][0] = 0; + h[0][1] = -Gr[2][0]; + h[0][2] = Gr[1][0]; + h[1][0] = Gr[2][0]; + h[1][1] = 0; + h[1][2] = -Gr[0][0]; + h[2][0] = -Gr[1][0]; + h[2][1] = Gr[0][0]; + h[2][2] = 0; + + //Magnetometer + h[3][0] = 0; + h[3][1] = -Mr[2][0]; + h[3][2] = Mr[1][0]; + h[4][0] = Mr[2][0]; + h[4][1] = 0; + h[4][2] = -Mr[0][0]; + h[5][0] = -Mr[1][0]; + h[5][1] = Mr[0][0]; + h[5][2] = 0; + + + // ====== INNOVATION COVARIANCE ====== + mat_trans(&Hm, &HTm); + mat_mult(&P0m, &HTm, &P0HTm); // P0*H' + mat_mult(&Hm, &P0HTm, &HP0HTm); // H*P0*H' + for (int i = 0; i < OUTPUT_SIZE; ++i) { // Add the element of HPH' to the above + hP0hT[i][i] += R[i]; + } + mat_inv(&HP0HTm, &HP0HT_INVm); // (H*P0*H' + R)^(-1) + mat_mult(&P0HTm, &HP0HT_INVm, &Km); // K = P0*H'*(H*P0*H' + R)^(-1) + + //Aggiorno la P + mat_mult(&Km, &Hm, &tmpNN1m); // KH + for (int i = 0; i < STATE_SIZE; ++i) { + tmpNN1d[i][i] -= 1.0f; + for (int j = 0; j < STATE_SIZE; ++j) { + tmpNN1d[i][j] *= -1.0f; + } + } // -(KH - I) + mat_mult(&tmpNN1m, &P0m, &Pm); // -(KH - I)*P0 + + float Error[OUTPUT_SIZE][1]; + arm_matrix_instance_f32 Errorm = {STATE_SIZE, 1, (float *)Error}; + float ae[STATE_SIZE][1]; + arm_matrix_instance_f32 aem = {STATE_SIZE, 1, (float *)ae}; + Error[0][0] = ax - Gr[0][0]; + Error[1][0] = ay - Gr[1][0]; + Error[2][0] = az - Gr[2][0]; + Error[3][0] = mx - Mr[0][0]; + Error[4][0] = my - Mr[1][0]; + Error[5][0] = mz - Mr[2][0]; + mat_mult(&Km, &Errorm, &aem); // K*error(k) + + float qe0 = 1; + float qe1 = ae[0][0]/2; + float qe2 = ae[1][0]/2; + float qe3 = ae[2][0]/2; + + float q0tmp = q0; + float q1tmp = q1; + float q2tmp = q2; + float q3tmp = q3; + q0 = q0tmp*qe0 - q1tmp*qe1 - q2tmp*qe2 - q3tmp*qe3; + q1 = q0tmp*qe1 + q1tmp*qe0 + q2tmp*qe3 - q3tmp*qe2; + q2 = q0tmp*qe2 + q2tmp*qe0 - q1tmp*qe3 + q3tmp*qe1; + q3 = q0tmp*qe3 + q1tmp*qe2 - q2tmp*qe1 + q3tmp*qe0; + + // Normalise quaternion + recipNorm = invSqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3); + q0 *= recipNorm; + q1 *= recipNorm; + q2 *= recipNorm; + q3 *= recipNorm; +} +*/ +static void sensfusion9UpdateQImpl(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz, float dt) +{ + float recipNorm; + + gx = gx * M_PI_F / 180.0f; + gy = gy * M_PI_F / 180.0f; + gz = gz * M_PI_F / 180.0f; + + // Normalise accelerometer measurement + recipNorm = invSqrt(ax*ax + ay*ay + az*az); + ax *= recipNorm; + ay *= recipNorm; + az *= recipNorm; + + // Normalise magnetometer measurement + recipNorm = invSqrt(mx*mx + my*my + mz*mz); + mx *= recipNorm; + my *= recipNorm; + mz *= recipNorm; + + //Converto il vettore intensità campo magnetico + //float h1 = mx*q1 + my*q2 + mz*q3; + //float h2 = mx*q0 - my*q3 + mz*q2; + //float h3 = mx*q3 + my*q0 - mz*q1; + //float h4 = -mx*q2 + my*q1 + mz*q0; + //float n2 = q0*h2 + q1*h1 + q2*h4 - q3*h3; + //float n3 = q0*h3 - q1*h4 + q2*h1 + q3*h2; + //float n4 = q0*h4 + q1*h3 - q2*h2 + q3*h1; + //float b2 = arm_sqrt(n2*n2 + n3*n3); + //float b4 = n4; + //float b2 = mx; + //float b4 = mz; + float hx = mx*q0*q0 + 2.0f*mz*q0*q2 - 2.0f*my*q0*q3 + mx*q1*q1 + 2.0f*my*q1*q2 + 2.0f*mz*q1*q3 - mx*q2*q2 - mx*q3*q3; + float hy = my*q0*q0 - 2.0f*mz*q0*q1 + 2.0f*mx*q0*q3 - my*q1*q1 + 2.0f*mx*q1*q2 + my*q2*q2 + 2.0f*mz*q2*q3 - my*q3*q3; + float hz = mz*q0*q0 + 2.0f*my*q0*q1 - 2.0f*mx*q0*q2 - mz*q1*q1 + 2.0f*mx*q1*q3 - mz*q2*q1 + 2.0f*my*q2*q3 + mz*q3*q3; + float b2 = arm_sqrt(hx*hx + hy*hy); + float b4 = hz; + + A[0][0] = 1.0f; + A[0][1] = -gx*dt*0.5f; + A[0][2] = -gy*dt*0.5f; + A[0][3] = -gz*dt*0.5f; + A[1][0] = gx*dt*0.5f; + A[1][1] = 1.0f; + A[1][2] = gz*dt*0.5f; + A[1][3] = -gy*dt*0.5f; + A[2][0] = gy*dt*0.5f; + A[2][1] = -gz*dt*0.5f; + A[2][2] = 1.0f; + A[2][3] = gx*dt*0.5f; + A[3][0] = gz*dt*0.5f; + A[3][1] = gy*dt*0.5f; + A[3][2] = -gx*dt*0.5f; + A[3][3] = 1.0f; + + // Aggiorno la Covarianza + float P0[STATE_SIZE][STATE_SIZE]; + arm_matrix_instance_f32 P0m = {STATE_SIZE, STATE_SIZE, (float *)P0}; + + mat_mult(&Am, &Pm, &tmpNN1m); // A P + mat_trans(&Am, &tmpNN2m); // A' + mat_mult(&tmpNN1m, &tmpNN2m, &P0m); // A P A' + for(int i = 0; i < STATE_SIZE; ++i){ + P0[i][i] += Q_VARIANCE; + } + + // Calcolo il guadagno + float K[STATE_SIZE][OUTPUT_SIZE]; + arm_matrix_instance_f32 Km = {STATE_SIZE, OUTPUT_SIZE, (float *)K}; + + float h[OUTPUT_SIZE][STATE_SIZE]; + arm_matrix_instance_f32 Hm = {OUTPUT_SIZE, STATE_SIZE, (float *)h}; + + float hT[STATE_SIZE][OUTPUT_SIZE]; + arm_matrix_instance_f32 HTm = {STATE_SIZE, OUTPUT_SIZE, (float *)hT}; + + float P0hT[STATE_SIZE][OUTPUT_SIZE]; + arm_matrix_instance_f32 P0HTm = {STATE_SIZE, OUTPUT_SIZE, (float *)P0hT}; + + float hP0hT[OUTPUT_SIZE][OUTPUT_SIZE]; + arm_matrix_instance_f32 HP0HTm = {OUTPUT_SIZE, OUTPUT_SIZE, (float *)hP0hT}; + + float hP0hT_inv[OUTPUT_SIZE][OUTPUT_SIZE]; + arm_matrix_instance_f32 HP0HT_INVm = {OUTPUT_SIZE, OUTPUT_SIZE, (float *)hP0hT_inv}; + + //Accelerometer + h[0][0] = -2.0f*q2; + h[0][1] = 2.0f*q3; + h[0][2] = -2.0f*q0; + h[0][3] = 2.0f*q1; + h[1][0] = 2.0f*q1; + h[1][1] = 2.0f*q0; + h[1][2] = 2.0f*q3; + h[1][3] = 2.0f*q2; + h[2][0] = 4.0f*q0; + h[2][1] = 0.0f; + h[2][2] = 0.0f; + h[2][3] = 4.0f*q3; + //h[2][0] = 2.0f*q0; + //h[2][1] = -2.0f*q1; + //h[2][2] = -2.0f*q2; + //h[2][3] = 2.0f*q3; + + //Magnetometer + h[3][0] = 4.0f*b2*q0 - 2.0f*b4*q2; + h[3][1] = 4.0f*b2*q1 + 2.0f*b4*q3; + h[3][2] = -2.0f*b4*q0; + h[3][3] = 2.0f*b4*q1; + h[4][0] = 2.0f*b4*q1 - 2.0f*b2*q3; + h[4][1] = 2.0f*b2*q2 + 2.0f*b4*q0; + h[4][2] = 2.0f*b2*q1 + 2.0f*b4*q3; + h[4][3] = 2.0f*b4*q2 - 2.0f*b2*q0; + h[5][0] = 2.0f*b2*q2 + 4.0f*b4*q0; + h[5][1] = 2.0f*b2*q3; + h[5][2] = 2.0f*b2*q0; + h[5][3] = 2.0f*b2*q1 + 4.0f*b4*q3; + + //h[3][0] = -2.0f*b4*q2; + //h[3][1] = 2.0f*b4*q3; + //h[3][2] = -4.0f*b2*q2 - 2.0f*b4*q0; + //h[3][3] = -4.0f*b2*q3 + 2.0f*b4*q1; + //h[4][0] = -2.0f*b2*q3 + 2.0f*b4*q1; + //h[4][1] = 2.0f*b2*q2 + 2.0f*b4*q0; + //h[4][2] = 2.0f*b2*q1 + 2.0f*b4*q3; + //h[4][3] = -2.0f*b2*q0 + 2.0f*b4*q2; + //h[5][0] = 2.0f*b2*q2; + //h[5][1] = 2.0f*b2*q3 - 4.0f*b4*q1; + //h[5][2] = 2.0f*b2*q0 - 4.0f*b4*q2; + //h[5][3] = 2.0f*b2*q1; + + + // ====== INNOVATION COVARIANCE ====== + mat_trans(&Hm, &HTm); + mat_mult(&P0m, &HTm, &P0HTm); // P0*H' + mat_mult(&Hm, &P0HTm, &HP0HTm); // H*P0*H' + for (int i = 0; i < OUTPUT_SIZE; ++i) { // Add the element of HPH' to the above + hP0hT[i][i] += R[i]; + } + mat_inv(&HP0HTm, &HP0HT_INVm); // (H*P0*H' + R)^(-1) + mat_mult(&P0HTm, &HP0HT_INVm, &Km); // K = P0*H'*(H*P0*H' + R)^(-1) + + //Aggiorno Stato + float State[STATE_SIZE][1]; + arm_matrix_instance_f32 Statem = {STATE_SIZE, 1, (float *)State}; + float StateTMP[STATE_SIZE][1]; + arm_matrix_instance_f32 StateTMPm = {STATE_SIZE, 1, (float *)StateTMP}; + float Error[OUTPUT_SIZE][1]; + arm_matrix_instance_f32 Errorm = {STATE_SIZE, 1, (float *)Error}; + float ErrorTMP[OUTPUT_SIZE][1]; + arm_matrix_instance_f32 ErrorTMPm = {STATE_SIZE, 1, (float *)ErrorTMP}; + State[0][0] = q0; + State[1][0] = q1; + State[2][0] = q2; + State[3][0] = q3; + mat_mult(&Am, &Statem, &StateTMPm); // A*x(k) + + Error[0][0] = ax - 2.0f*(q1*q3 - q0*q2); + Error[1][0] = ay - 2.0f*(q0*q1 + q2*q3); + Error[2][0] = az - 2.0f*(q0*q0 + q3*q3 - 0.5f); + Error[3][0] = mx - 2.0f*(b2*(q0*q0 + q1*q1 - 0.5f) - b4*(q0*q2 - q1*q3)); + Error[4][0] = my - 2.0f*(b4*(q0*q1 + q2*q3) - b2*(q0*q3 - q1*q2)); + Error[5][0] = mz - 2.0f*(b4*(q0*q0 + q3*q3 - 0.5f) + b2*(q0*q2 + q1*q3)); + mat_mult(&Km, &Errorm, &ErrorTMPm); // K*error(k) + + q0 = StateTMP[0][0] + ErrorTMP[0][0]; + q1 = StateTMP[1][0] + ErrorTMP[1][0]; + q2 = StateTMP[2][0] + ErrorTMP[2][0]; + q3 = StateTMP[3][0] + ErrorTMP[3][0]; + + //Aggiorno la P + mat_mult(&Km, &Hm, &tmpNN1m); // KH + for (int i = 0; i < STATE_SIZE; ++i) { + tmpNN1d[i][i] -= 1.0f; + for (int j = 0; j < STATE_SIZE; ++j) { + tmpNN1d[i][j] *= -1.0f; + } + } // -(KH - I) + mat_mult(&tmpNN1m, &P0m, &Pm); // -(KH - I)*P0 + + // Normalise quaternion + recipNorm = invSqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3); + q0 *= recipNorm; + q1 *= recipNorm; + q2 *= recipNorm; + q3 *= recipNorm; +} + +void sensfusion9GetEulerRPY(float* roll, float* pitch, float* yaw) +{ + float gx = gravX; + float gy = gravY; + float gz = gravZ; + + if (gx > 1) gx = 1; + if (gx < -1) gx = -1; + + *yaw = atan2f(2.0f*(q0*q3 + q1*q2), q0*q0 + q1*q1 - q2*q2 - q3*q3) * 180.0f / M_PI_F; + *pitch = asinf(gx) * 180.0f / M_PI_F; //Pitch seems to be inverted + *roll = atan2f(gy, gz) * 180.0f / M_PI_F; +} +void sensfusion9GetQuaternion(float* Q0, float* Q1, float* Q2, float* Q3) +{ + *Q0 = q0; + *Q1 = q1; + *Q2 = q2; + *Q3 = q3; +} + +float sensfusion9GetAccZWithoutGravity(const float ax, const float ay, const float az) +{ + return sensfusion9GetAccZ(ax, ay, az) - baseZacc; +} + +float sensfusion9GetInvThrustCompensationForTilt() +{ + // Return the z component of the estimated gravity direction + // (0, 0, 1) dot G + return gravZ; +} + +//--------------------------------------------------------------------------------------------------- +// Fast inverse square-root +// See: http://en.wikipedia.org/wiki/Fast_inverse_square_root +float invSqrt(float x) +{ + float halfx = 0.5f * x; + float y = x; + long i = *(long*)&y; + i = 0x5f3759df - (i>>1); + y = *(float*)&i; + y = y * (1.5f - (halfx * y * y)); + return y; +} + +static float sensfusion9GetAccZ(const float ax, const float ay, const float az) +{ + // return vertical acceleration + // (A dot G) / |G|, (|G| = 1) -> (A dot G) + return (ax * gravX + ay * gravY + az * gravZ); +} + +static void estimatedGravityDirection(float* gx, float* gy, float* gz) +{ + *gx = 2 * (q1 * q3 - q0 * q2); + *gy = 2 * (q0 * q1 + q2 * q3); + *gz = q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3; +} \ No newline at end of file
diff -r 4b3d36de811a -r ba2d31e3112d sensfusion9.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sensfusion9.h Sat Mar 25 16:48:32 2017 +0000 @@ -0,0 +1,48 @@ +/** + * || ____ _ __ ______ + * +------+ / __ )(_) /_/ ____/_________ _____ ___ + * | 0xBC | / __ / / __/ / / ___/ __ `/_ / / _ \ + * +------+ / /_/ / / /_/ /___ / / / /_/ / / /_/ __/ + * || || /_____/_/\__/\____//_/ \__,_/ /___/\___/ + * + * Crazyflie control firmware + * + * Copyright (C) 2011-2012 Bitcraze AB + * + * 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, in version 3. + * + * 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, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef SENSORFUSION9_H_ +#define SENSORFUSION9_H_ +#include <stdbool.h> + + +#ifdef __cplusplus +extern "C" { +#endif + +void sensfusion9Init(void); +bool sensfusion9Test(void); + +void sensfusion9UpdateQ(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz, float dt); +void sensfusion9GetEulerRPY(float* roll, float* pitch, float* yaw); +void sensfusion9GetQuaternion(float* Q0, float* Q1, float* Q2, float* Q3); +float sensfusion9GetAccZWithoutGravity(const float ax, const float ay, const float az); +float sensfusion9GetInvThrustCompensationForTilt(); + +#ifdef __cplusplus +} +#endif + +#endif /* SENSORFUSION9_H_ */