Paparazzi UAS  v5.8.2_stable-0-g6260b7c
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
ahrs_float_mlkf.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011-2012 Antoine Drouin <poinix@gmail.com>
3  * Copyright (C) 2013 Felix Ruess <felix.ruess@gmail.com>
4  *
5  * This file is part of paparazzi.
6  *
7  * paparazzi is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * paparazzi is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with paparazzi; see the file COPYING. If not, write to
19  * the Free Software Foundation, 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 
33 
34 #include <string.h> /* for memcpy */
35 
37 #include "math/pprz_algebra_int.h"
39 #include "generated/airframe.h"
40 
41 //#include <stdio.h>
42 
43 #ifndef AHRS_MAG_NOISE_X
44 #define AHRS_MAG_NOISE_X 0.2
45 #define AHRS_MAG_NOISE_Y 0.2
46 #define AHRS_MAG_NOISE_Z 0.2
47 #endif
48 
49 static inline void propagate_ref(struct Int32Rates *gyro, float dt);
50 static inline void propagate_state(float dt);
51 static inline void update_state(const struct FloatVect3 *i_expected,
52  struct FloatVect3 *b_measured,
53  struct FloatVect3 *noise);
54 static inline void update_state_heading(const struct FloatVect3 *i_expected,
55  struct FloatVect3 *b_measured,
56  struct FloatVect3 *noise);
57 static inline void reset_state(void);
58 
60 
61 
62 void ahrs_mlkf_init(void)
63 {
64 
66 
67  /* init ltp_to_imu quaternion as zero/identity rotation */
70 
71  VECT3_ASSIGN(ahrs_mlkf.mag_h, AHRS_H_X, AHRS_H_Y, AHRS_H_Z);
72 
73  /*
74  * Initialises our state
75  */
77  const float P0_a = 1.;
78  const float P0_b = 1e-4;
79  float P0[6][6] = {{ P0_a, 0., 0., 0., 0., 0. },
80  { 0., P0_a, 0., 0., 0., 0. },
81  { 0., 0., P0_a, 0., 0., 0. },
82  { 0., 0., 0., P0_b, 0., 0. },
83  { 0., 0., 0., 0., P0_b, 0. },
84  { 0., 0., 0., 0., 0., P0_b}
85  };
86  memcpy(ahrs_mlkf.P, P0, sizeof(P0));
87 
89 }
90 
92 {
94 }
95 
97 {
99 
100  if (!ahrs_mlkf.is_aligned) {
101  /* Set ltp_to_imu so that body is zero */
103  }
104 }
105 
106 
107 bool_t ahrs_mlkf_align(struct Int32Rates *lp_gyro, struct Int32Vect3 *lp_accel,
108  struct Int32Vect3 *lp_mag)
109 {
110 
111  /* Compute an initial orientation from accel and mag directly as quaternion */
113 
114  /* used averaged gyro as initial value for bias */
115  struct Int32Rates bias0;
116  RATES_COPY(bias0, *lp_gyro);
118 
120 
121  return TRUE;
122 }
123 
124 void ahrs_mlkf_propagate(struct Int32Rates *gyro, float dt)
125 {
126  propagate_ref(gyro, dt);
127  propagate_state(dt);
128 }
129 
131 {
132  struct FloatVect3 imu_g;
133  ACCELS_FLOAT_OF_BFP(imu_g, *accel);
134  const float alpha = 0.92;
136  (1. - alpha) * (float_vect3_norm(&imu_g) - 9.81);
137  const struct FloatVect3 earth_g = {0., 0., -9.81 };
138  const float dn = 250 * fabs(ahrs_mlkf.lp_accel);
139  struct FloatVect3 g_noise = {1. + dn, 1. + dn, 1. + dn};
140  update_state(&earth_g, &imu_g, &g_noise);
141  reset_state();
142 }
143 
145 {
146 #if AHRS_MAG_UPDATE_ALL_AXES
148 #else
150 #endif
151 }
152 
154 {
155  struct FloatVect3 imu_h;
156  MAGS_FLOAT_OF_BFP(imu_h, *mag);
158  reset_state();
159 }
160 
162 {
163  struct FloatVect3 imu_h;
164  MAGS_FLOAT_OF_BFP(imu_h, *mag);
166  reset_state();
167 }
168 
169 
170 static inline void propagate_ref(struct Int32Rates *gyro, float dt)
171 {
172  /* converts gyro to floating point */
173  struct FloatRates gyro_float;
174  RATES_FLOAT_OF_BFP(gyro_float, *gyro);
175 
176  /* unbias measurement */
177  RATES_SUB(gyro_float, ahrs_mlkf.gyro_bias);
178 
179 #ifdef AHRS_PROPAGATE_LOW_PASS_RATES
180  /* lowpass angular rates */
181  const float alpha = 0.1;
183  (1. - alpha), gyro_float, alpha);
184 #else
185  RATES_COPY(ahrs_mlkf.imu_rate, gyro_float);
186 #endif
187 
188  /* propagate reference quaternion */
190 
191 }
192 
197 static inline void propagate_state(float dt)
198 {
199 
200  /* predict covariance */
201  const float dp = ahrs_mlkf.imu_rate.p * dt;
202  const float dq = ahrs_mlkf.imu_rate.q * dt;
203  const float dr = ahrs_mlkf.imu_rate.r * dt;
204 
205  float F[6][6] = {{ 1., dr, -dq, -dt, 0., 0. },
206  { -dr, 1., dp, 0., -dt, 0. },
207  { dq, -dp, 1., 0., 0., -dt },
208  { 0., 0., 0., 1., 0., 0. },
209  { 0., 0., 0., 0., 1., 0. },
210  { 0., 0., 0., 0., 0., 1. }
211  };
212  // P = FPF' + GQG
213  float tmp[6][6];
214  MAT_MUL(6, 6, 6, tmp, F, ahrs_mlkf.P);
215  MAT_MUL_T(6, 6, 6, ahrs_mlkf.P, tmp, F);
216  const float dt2 = dt * dt;
217  const float GQG[6] = {dt2 * 10e-3, dt2 * 10e-3, dt2 * 10e-3, dt2 * 9e-6, dt2 * 9e-6, dt2 * 9e-6 };
218  for (int i = 0; i < 6; i++) {
219  ahrs_mlkf.P[i][i] += GQG[i];
220  }
221 
222 }
223 
224 
231 static inline void update_state(const struct FloatVect3 *i_expected, struct FloatVect3 *b_measured,
232  struct FloatVect3 *noise)
233 {
234 
235  /* converted expected measurement from inertial to body frame */
236  struct FloatVect3 b_expected;
237  float_quat_vmult(&b_expected, &ahrs_mlkf.ltp_to_imu_quat, i_expected);
238 
239  // S = HPH' + JRJ
240  float H[3][6] = {{ 0., -b_expected.z, b_expected.y, 0., 0., 0.},
241  { b_expected.z, 0., -b_expected.x, 0., 0., 0.},
242  { -b_expected.y, b_expected.x, 0., 0., 0., 0.}
243  };
244  float tmp[3][6];
245  MAT_MUL(3, 6, 6, tmp, H, ahrs_mlkf.P);
246  float S[3][3];
247  MAT_MUL_T(3, 6, 3, S, tmp, H);
248 
249  /* add the measurement noise */
250  S[0][0] += noise->x;
251  S[1][1] += noise->y;
252  S[2][2] += noise->z;
253 
254  float invS[3][3];
255  MAT_INV33(invS, S);
256 
257  // K = PH'invS
258  float tmp2[6][3];
259  MAT_MUL_T(6, 6, 3, tmp2, ahrs_mlkf.P, H);
260  float K[6][3];
261  MAT_MUL(6, 3, 3, K, tmp2, invS);
262 
263  // P = (I-KH)P
264  float tmp3[6][6];
265  MAT_MUL(6, 3, 6, tmp3, K, H);
266  float I6[6][6] = {{ 1., 0., 0., 0., 0., 0. },
267  { 0., 1., 0., 0., 0., 0. },
268  { 0., 0., 1., 0., 0., 0. },
269  { 0., 0., 0., 1., 0., 0. },
270  { 0., 0., 0., 0., 1., 0. },
271  { 0., 0., 0., 0., 0., 1. }
272  };
273  float tmp4[6][6];
274  MAT_SUB(6, 6, tmp4, I6, tmp3);
275  float tmp5[6][6];
276  MAT_MUL(6, 6, 6, tmp5, tmp4, ahrs_mlkf.P);
277  memcpy(ahrs_mlkf.P, tmp5, sizeof(ahrs_mlkf.P));
278 
279  // X = X + Ke
280  struct FloatVect3 e;
281  VECT3_DIFF(e, *b_measured, b_expected);
282  ahrs_mlkf.gibbs_cor.qx += K[0][0] * e.x + K[0][1] * e.y + K[0][2] * e.z;
283  ahrs_mlkf.gibbs_cor.qy += K[1][0] * e.x + K[1][1] * e.y + K[1][2] * e.z;
284  ahrs_mlkf.gibbs_cor.qz += K[2][0] * e.x + K[2][1] * e.y + K[2][2] * e.z;
285  ahrs_mlkf.gyro_bias.p += K[3][0] * e.x + K[3][1] * e.y + K[3][2] * e.z;
286  ahrs_mlkf.gyro_bias.q += K[4][0] * e.x + K[4][1] * e.y + K[4][2] * e.z;
287  ahrs_mlkf.gyro_bias.r += K[5][0] * e.x + K[5][1] * e.y + K[5][2] * e.z;
288 
289 }
290 
291 
299 static inline void update_state_heading(const struct FloatVect3 *i_expected,
300  struct FloatVect3 *b_measured,
301  struct FloatVect3 *noise)
302 {
303 
304  /* converted expected measurement from inertial to body frame */
305  struct FloatVect3 b_expected;
306  float_quat_vmult(&b_expected, &ahrs_mlkf.ltp_to_imu_quat, i_expected);
307 
308  /* set roll/pitch errors to zero to only correct heading */
309  struct FloatVect3 i_h_2d = {i_expected->y, -i_expected->x, 0.f};
310  struct FloatVect3 b_yaw;
311  float_quat_vmult(&b_yaw, &ahrs_mlkf.ltp_to_imu_quat, &i_h_2d);
312  // S = HPH' + JRJ
313  float H[3][6] = {{ 0., 0., b_yaw.x, 0., 0., 0.},
314  { 0., 0., b_yaw.y, 0., 0., 0.},
315  { 0., 0., b_yaw.z, 0., 0., 0.}
316  };
317  float tmp[3][6];
318  MAT_MUL(3, 6, 6, tmp, H, ahrs_mlkf.P);
319  float S[3][3];
320  MAT_MUL_T(3, 6, 3, S, tmp, H);
321 
322  /* add the measurement noise */
323  S[0][0] += noise->x;
324  S[1][1] += noise->y;
325  S[2][2] += noise->z;
326 
327  float invS[3][3];
328  MAT_INV33(invS, S);
329 
330  // K = PH'invS
331  float tmp2[6][3];
332  MAT_MUL_T(6, 6, 3, tmp2, ahrs_mlkf.P, H);
333  float K[6][3];
334  MAT_MUL(6, 3, 3, K, tmp2, invS);
335 
336  // P = (I-KH)P
337  float tmp3[6][6];
338  MAT_MUL(6, 3, 6, tmp3, K, H);
339  float I6[6][6] = {{ 1., 0., 0., 0., 0., 0. },
340  { 0., 1., 0., 0., 0., 0. },
341  { 0., 0., 1., 0., 0., 0. },
342  { 0., 0., 0., 1., 0., 0. },
343  { 0., 0., 0., 0., 1., 0. },
344  { 0., 0., 0., 0., 0., 1. }
345  };
346  float tmp4[6][6];
347  MAT_SUB(6, 6, tmp4, I6, tmp3);
348  float tmp5[6][6];
349  MAT_MUL(6, 6, 6, tmp5, tmp4, ahrs_mlkf.P);
350  memcpy(ahrs_mlkf.P, tmp5, sizeof(ahrs_mlkf.P));
351 
352  // X = X + Ke
353  struct FloatVect3 e;
354  VECT3_DIFF(e, *b_measured, b_expected);
355  ahrs_mlkf.gibbs_cor.qx += K[0][0] * e.x + K[0][1] * e.y + K[0][2] * e.z;
356  ahrs_mlkf.gibbs_cor.qy += K[1][0] * e.x + K[1][1] * e.y + K[1][2] * e.z;
357  ahrs_mlkf.gibbs_cor.qz += K[2][0] * e.x + K[2][1] * e.y + K[2][2] * e.z;
358  ahrs_mlkf.gyro_bias.p += K[3][0] * e.x + K[3][1] * e.y + K[3][2] * e.z;
359  ahrs_mlkf.gyro_bias.q += K[4][0] * e.x + K[4][1] * e.y + K[4][2] * e.z;
360  ahrs_mlkf.gyro_bias.r += K[5][0] * e.x + K[5][1] * e.y + K[5][2] * e.z;
361 
362 }
366 static inline void reset_state(void)
367 {
368 
369  ahrs_mlkf.gibbs_cor.qi = 2.;
370  struct FloatQuat q_tmp;
372  float_quat_normalize(&q_tmp);
373  ahrs_mlkf.ltp_to_imu_quat = q_tmp;
375 
376 }
bool_t ahrs_mlkf_align(struct Int32Rates *lp_gyro, struct Int32Vect3 *lp_accel, struct Int32Vect3 *lp_mag)
angular rates
struct FloatQuat gibbs_cor
static void orientationSetQuat_f(struct OrientationReps *orientation, struct FloatQuat *quat)
Set vehicle body attitude from quaternion (float).
Simple matrix helper macros.
#define AHRS_MAG_NOISE_Z
void float_quat_comp(struct FloatQuat *a2c, struct FloatQuat *a2b, struct FloatQuat *b2c)
Composition (multiplication) of two quaternions.
#define AHRS_MAG_NOISE_Y
struct FloatVect3 mag_noise
#define AHRS_MAG_NOISE_X
static void float_quat_identity(struct FloatQuat *q)
initialises a quaternion to identity
struct FloatVect3 mag_h
float r
in rad/s
struct FloatRates imu_rate
Rotational velocity in IMU frame.
#define VECT3_DIFF(_c, _a, _b)
Definition: pprz_algebra.h:181
#define VECT3_ASSIGN(_a, _x, _y, _z)
Definition: pprz_algebra.h:124
float P[6][6]
Utility functions for floating point AHRS implementations.
#define FLOAT_RATES_ZERO(_r)
void ahrs_mlkf_update_mag_2d(struct Int32Vect3 *mag)
void ahrs_mlkf_set_body_to_imu(struct OrientationReps *body_to_imu)
float lp_accel
void ahrs_mlkf_update_mag_full(struct Int32Vect3 *mag)
struct FloatRates gyro_bias
#define RATES_SUB(_a, _b)
Definition: pprz_algebra.h:350
void ahrs_mlkf_update_accel(struct Int32Vect3 *accel)
float q
in rad/s
float p
in rad/s
#define MAT_MUL_T(_i, _k, _j, C, A, B)
Multiplicative linearized Kalman Filter in quaternion formulation.
#define FALSE
Definition: std.h:5
Roation quaternion.
static float float_vect3_norm(struct FloatVect3 *v)
static void update_state_heading(const struct FloatVect3 *i_expected, struct FloatVect3 *b_measured, struct FloatVect3 *noise)
Incorporate one 3D vector measurement, only correcting heading.
static void update_state(const struct FloatVect3 *i_expected, struct FloatVect3 *b_measured, struct FloatVect3 *noise)
Incorporate one 3D vector measurement.
#define TRUE
Definition: std.h:4
#define FLOAT_RATES_LIN_CMB(_ro, _r1, _s1, _r2, _s2)
#define RATES_FLOAT_OF_BFP(_rf, _ri)
Definition: pprz_algebra.h:692
Paparazzi floating point algebra.
static void propagate_ref(struct Int32Rates *gyro, float dt)
void ahrs_mlkf_set_body_to_imu_quat(struct FloatQuat *q_b2i)
uint16_t dn[LIGHT_NB]
Definition: light_solar.c:48
void float_quat_integrate(struct FloatQuat *q, struct FloatRates *omega, float dt)
in place quaternion integration with constant rotational velocity
static void ahrs_float_get_quat_from_accel_mag(struct FloatQuat *q, struct Int32Vect3 *accel, struct Int32Vect3 *mag)
void ahrs_mlkf_propagate(struct Int32Rates *gyro, float dt)
void float_quat_vmult(struct FloatVect3 *v_out, struct FloatQuat *q, const struct FloatVect3 *v_in)
rotate 3D vector by quaternion.
static void float_quat_normalize(struct FloatQuat *q)
void ahrs_mlkf_init(void)
#define ACCELS_FLOAT_OF_BFP(_ef, _ei)
Definition: pprz_algebra.h:728
struct AhrsMlkf ahrs_mlkf
bool_t is_aligned
static void reset_state(void)
Incorporate errors to reference and zeros state.
#define MAT_INV33(_invS, _S)
void ahrs_mlkf_update_mag(struct Int32Vect3 *mag)
struct OrientationReps body_to_imu
body_to_imu rotation
#define MAT_SUB(_i, _j, C, A, B)
struct FloatQuat ltp_to_imu_quat
Rotation from LocalTangentPlane to IMU frame as unit quaternion.
#define MAGS_FLOAT_OF_BFP(_ef, _ei)
Definition: pprz_algebra.h:740
static void propagate_state(float dt)
Progagate filter's covariance We don't propagate state as we assume to have reseted.
static struct OrientationReps body_to_imu
Definition: ins_alt_float.c:77
#define RATES_COPY(_a, _b)
Definition: pprz_algebra.h:336
angular rates
static struct FloatQuat * orientationGetQuat_f(struct OrientationReps *orientation)
Get vehicle body attitude quaternion (float).
Paparazzi fixed point algebra.
#define MAT_MUL(_i, _k, _j, C, A, B)