Paparazzi UAS v7.0_unstable
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
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
49static inline void propagate_ref(struct FloatRates *gyro, float dt);
50static inline void propagate_state(float dt);
51static inline void update_state(const struct FloatVect3 *i_expected,
52 struct FloatVect3 *b_measured,
53 struct FloatVect3 *noise);
54static inline void update_state_heading(const struct FloatVect3 *i_expected,
55 struct FloatVect3 *b_measured,
56 struct FloatVect3 *noise);
57static inline void reset_state(void);
58
60
61
63{
64
65 ahrs_mlkf.is_aligned = false;
66
67 /* init ltp_to_body quaternion as zero/identity rotation */
70
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
91bool ahrs_mlkf_align(struct FloatRates *lp_gyro, struct FloatVect3 *lp_accel,
92 struct FloatVect3 *lp_mag)
93{
94
95 /* Compute an initial orientation from accel and mag directly as quaternion */
97
98 /* used averaged gyro as initial value for bias */
99 ahrs_mlkf.gyro_bias = *lp_gyro;
100
101 ahrs_mlkf.is_aligned = true;
102
103 return true;
104}
105
106void ahrs_mlkf_propagate(struct FloatRates *gyro, float dt)
107{
108 propagate_ref(gyro, dt);
109 propagate_state(dt);
110}
111
113{
114 struct FloatVect3 imu_g = *accel;
115 const float alpha = 0.92;
117 (1. - alpha) * (float_vect3_norm(&imu_g) - 9.81);
118 const struct FloatVect3 earth_g = {0., 0., -9.81 };
119 const float dn = 250 * fabs(ahrs_mlkf.lp_accel);
120 struct FloatVect3 g_noise = {1. + dn, 1. + dn, 1. + dn};
122 reset_state();
123}
124
126{
127#if AHRS_MAG_UPDATE_ALL_AXES
129#else
131#endif
132}
133
139
145
146
147static inline void propagate_ref(struct FloatRates *gyro, float dt)
148{
149 struct FloatRates rates = *gyro;
150
151 /* unbias measurement */
153
154#ifdef AHRS_PROPAGATE_LOW_PASS_RATES
155 /* lowpass angular rates */
156 const float alpha = 0.1;
158 (1. - alpha), rates, alpha);
159#else
161#endif
162
163 /* propagate reference quaternion */
165
166}
167
172static inline void propagate_state(float dt)
173{
174
175 /* predict covariance */
176 const float dp = ahrs_mlkf.body_rate.p * dt;
177 const float dq = ahrs_mlkf.body_rate.q * dt;
178 const float dr = ahrs_mlkf.body_rate.r * dt;
179
180 float F[6][6] = {{ 1., dr, -dq, -dt, 0., 0. },
181 { -dr, 1., dp, 0., -dt, 0. },
182 { dq, -dp, 1., 0., 0., -dt },
183 { 0., 0., 0., 1., 0., 0. },
184 { 0., 0., 0., 0., 1., 0. },
185 { 0., 0., 0., 0., 0., 1. }
186 };
187 // P = FPF' + GQG
188 float tmp[6][6];
189 MAT_MUL(6, 6, 6, tmp, F, ahrs_mlkf.P);
190 MAT_MUL_T(6, 6, 6, ahrs_mlkf.P, tmp, F);
191 const float dt2 = dt * dt;
192 const float GQG[6] = {dt2 * 10e-3, dt2 * 10e-3, dt2 * 10e-3, dt2 * 9e-6, dt2 * 9e-6, dt2 * 9e-6 };
193 for (int i = 0; i < 6; i++) {
194 ahrs_mlkf.P[i][i] += GQG[i];
195 }
196
197}
198
199
206static inline void update_state(const struct FloatVect3 *i_expected, struct FloatVect3 *b_measured,
207 struct FloatVect3 *noise)
208{
209
210 /* converted expected measurement from inertial to body frame */
211 struct FloatVect3 b_expected;
213
214 // S = HPH' + JRJ
215 float H[3][6] = {{ 0., -b_expected.z, b_expected.y, 0., 0., 0.},
216 { b_expected.z, 0., -b_expected.x, 0., 0., 0.},
217 { -b_expected.y, b_expected.x, 0., 0., 0., 0.}
218 };
219 float tmp[3][6];
220 MAT_MUL(3, 6, 6, tmp, H, ahrs_mlkf.P);
221 float S[3][3];
222 MAT_MUL_T(3, 6, 3, S, tmp, H);
223
224 /* add the measurement noise */
225 S[0][0] += noise->x;
226 S[1][1] += noise->y;
227 S[2][2] += noise->z;
228
229 float invS[3][3];
230 MAT_INV33(invS, S);
231
232 // K = PH'invS
233 float tmp2[6][3];
234 MAT_MUL_T(6, 6, 3, tmp2, ahrs_mlkf.P, H);
235 float K[6][3];
236 MAT_MUL(6, 3, 3, K, tmp2, invS);
237
238 // P = (I-KH)P
239 float tmp3[6][6];
240 MAT_MUL(6, 3, 6, tmp3, K, H);
241 float I6[6][6] = {{ 1., 0., 0., 0., 0., 0. },
242 { 0., 1., 0., 0., 0., 0. },
243 { 0., 0., 1., 0., 0., 0. },
244 { 0., 0., 0., 1., 0., 0. },
245 { 0., 0., 0., 0., 1., 0. },
246 { 0., 0., 0., 0., 0., 1. }
247 };
248 float tmp4[6][6];
249 MAT_SUB(6, 6, tmp4, I6, tmp3);
250 float tmp5[6][6];
251 MAT_MUL(6, 6, 6, tmp5, tmp4, ahrs_mlkf.P);
252 memcpy(ahrs_mlkf.P, tmp5, sizeof(ahrs_mlkf.P));
253
254 // X = X + Ke
255 struct FloatVect3 e;
257 ahrs_mlkf.gibbs_cor.qx += K[0][0] * e.x + K[0][1] * e.y + K[0][2] * e.z;
258 ahrs_mlkf.gibbs_cor.qy += K[1][0] * e.x + K[1][1] * e.y + K[1][2] * e.z;
259 ahrs_mlkf.gibbs_cor.qz += K[2][0] * e.x + K[2][1] * e.y + K[2][2] * e.z;
260 ahrs_mlkf.gyro_bias.p += K[3][0] * e.x + K[3][1] * e.y + K[3][2] * e.z;
261 ahrs_mlkf.gyro_bias.q += K[4][0] * e.x + K[4][1] * e.y + K[4][2] * e.z;
262 ahrs_mlkf.gyro_bias.r += K[5][0] * e.x + K[5][1] * e.y + K[5][2] * e.z;
263
264}
265
266
274static inline void update_state_heading(const struct FloatVect3 *i_expected,
275 struct FloatVect3 *b_measured,
276 struct FloatVect3 *noise)
277{
278
279 /* converted expected measurement from inertial to body frame */
280 struct FloatVect3 b_expected;
282
283 /* set roll/pitch errors to zero to only correct heading */
284 struct FloatVect3 i_h_2d = {i_expected->y, -i_expected->x, 0.f};
285 struct FloatVect3 b_yaw;
287 // S = HPH' + JRJ
288 float H[3][6] = {{ 0., 0., b_yaw.x, 0., 0., 0.},
289 { 0., 0., b_yaw.y, 0., 0., 0.},
290 { 0., 0., b_yaw.z, 0., 0., 0.}
291 };
292 float tmp[3][6];
293 MAT_MUL(3, 6, 6, tmp, H, ahrs_mlkf.P);
294 float S[3][3];
295 MAT_MUL_T(3, 6, 3, S, tmp, H);
296
297 /* add the measurement noise */
298 S[0][0] += noise->x;
299 S[1][1] += noise->y;
300 S[2][2] += noise->z;
301
302 float invS[3][3];
303 MAT_INV33(invS, S);
304
305 // K = PH'invS
306 float tmp2[6][3];
307 MAT_MUL_T(6, 6, 3, tmp2, ahrs_mlkf.P, H);
308 float K[6][3];
309 MAT_MUL(6, 3, 3, K, tmp2, invS);
310
311 // P = (I-KH)P
312 float tmp3[6][6];
313 MAT_MUL(6, 3, 6, tmp3, K, H);
314 float I6[6][6] = {{ 1., 0., 0., 0., 0., 0. },
315 { 0., 1., 0., 0., 0., 0. },
316 { 0., 0., 1., 0., 0., 0. },
317 { 0., 0., 0., 1., 0., 0. },
318 { 0., 0., 0., 0., 1., 0. },
319 { 0., 0., 0., 0., 0., 1. }
320 };
321 float tmp4[6][6];
322 MAT_SUB(6, 6, tmp4, I6, tmp3);
323 float tmp5[6][6];
324 MAT_MUL(6, 6, 6, tmp5, tmp4, ahrs_mlkf.P);
325 memcpy(ahrs_mlkf.P, tmp5, sizeof(ahrs_mlkf.P));
326
327 // X = X + Ke
328 struct FloatVect3 e;
330 ahrs_mlkf.gibbs_cor.qx += K[0][0] * e.x + K[0][1] * e.y + K[0][2] * e.z;
331 ahrs_mlkf.gibbs_cor.qy += K[1][0] * e.x + K[1][1] * e.y + K[1][2] * e.z;
332 ahrs_mlkf.gibbs_cor.qz += K[2][0] * e.x + K[2][1] * e.y + K[2][2] * e.z;
333 ahrs_mlkf.gyro_bias.p += K[3][0] * e.x + K[3][1] * e.y + K[3][2] * e.z;
334 ahrs_mlkf.gyro_bias.q += K[4][0] * e.x + K[4][1] * e.y + K[4][2] * e.z;
335 ahrs_mlkf.gyro_bias.r += K[5][0] * e.x + K[5][1] * e.y + K[5][2] * e.z;
336
337}
void ahrs_mlkf_update_mag(struct FloatVect3 *mag)
static void propagate_state(float dt)
Progagate filter's covariance We don't propagate state as we assume to have reseted.
void ahrs_mlkf_update_accel(struct FloatVect3 *accel)
void ahrs_mlkf_init(void)
bool ahrs_mlkf_align(struct FloatRates *lp_gyro, struct FloatVect3 *lp_accel, struct FloatVect3 *lp_mag)
#define AHRS_MAG_NOISE_Z
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.
void ahrs_mlkf_update_mag_full(struct FloatVect3 *mag)
static void propagate_ref(struct FloatRates *gyro, float dt)
#define AHRS_MAG_NOISE_X
static void update_state(const struct FloatVect3 *i_expected, struct FloatVect3 *b_measured, struct FloatVect3 *noise)
Incorporate one 3D vector measurement.
static void reset_state(void)
Incorporate errors to reference and zeros state.
struct AhrsMlkf ahrs_mlkf
void ahrs_mlkf_propagate(struct FloatRates *gyro, float dt)
void ahrs_mlkf_update_mag_2d(struct FloatVect3 *mag)
#define AHRS_MAG_NOISE_Y
Multiplicative linearized Kalman Filter in quaternion formulation.
float P[6][6]
struct FloatVect3 mag_h
struct FloatQuat gibbs_cor
struct FloatRates gyro_bias
struct FloatVect3 mag_noise
struct FloatQuat ltp_to_body_quat
Rotation from LocalTangentPlane to body frame as unit quaternion.
struct FloatRates body_rate
Rotational velocity in body frame.
Utility functions for floating point AHRS implementations.
static void ahrs_float_get_quat_from_accel_mag(struct FloatQuat *q, struct FloatVect3 *accel, struct FloatVect3 *mag)
float q
in rad/s
float p
in rad/s
float r
in rad/s
static void float_quat_normalize(struct FloatQuat *q)
static void float_quat_identity(struct FloatQuat *q)
initialises a quaternion to identity
void float_quat_integrate(struct FloatQuat *q, struct FloatRates *omega, float dt)
in place quaternion integration with constant rotational velocity
#define FLOAT_RATES_LIN_CMB(_ro, _r1, _s1, _r2, _s2)
void float_quat_vmult(struct FloatVect3 *v_out, struct FloatQuat *q, const struct FloatVect3 *v_in)
rotate 3D vector by quaternion.
static float float_vect3_norm(struct FloatVect3 *v)
#define FLOAT_RATES_ZERO(_r)
void float_quat_comp(struct FloatQuat *a2c, struct FloatQuat *a2b, struct FloatQuat *b2c)
Composition (multiplication) of two quaternions.
Roation quaternion.
angular rates
#define RATES_COPY(_a, _b)
#define RATES_SUB(_a, _b)
#define VECT3_ASSIGN(_a, _x, _y, _z)
#define VECT3_DIFF(_c, _a, _b)
uint16_t dn[LIGHT_NB]
Definition light_solar.c:48
static struct FloatVect3 H
uint16_t foo
Definition main_demo5.c:58
Paparazzi floating point algebra.
Paparazzi fixed point algebra.
Simple matrix helper macros.
#define MAT_MUL_T(_i, _k, _j, C, A, B)
#define MAT_MUL(_i, _k, _j, C, A, B)
#define MAT_SUB(_i, _j, C, A, B)
#define MAT_INV33(_invS, _S)
float alpha
Definition textons.c:133
static float K[9]