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_cmpl.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2013 The Paparazzi Team
3 *
4 * This file is part of paparazzi.
5 *
6 * paparazzi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with paparazzi; see the file COPYING. If not, write to
18 * the Free Software Foundation, 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
35#include "generated/airframe.h"
36#if USE_GPS
37#include "modules/gps/gps.h"
38#endif
39
40//#include "../../test/pprz_algebra_print.h"
41
42#if AHRS_PROPAGATE_RMAT && AHRS_PROPAGATE_QUAT
43#error "You can only define either AHRS_PROPAGATE_RMAT or AHRS_PROPAGATE_QUAT, not both!"
44#endif
45#if !AHRS_PROPAGATE_RMAT && !AHRS_PROPAGATE_QUAT
46#error "You have to define either AHRS_PROPAGATE_RMAT or AHRS_PROPAGATE_QUAT"
47#endif
48
49#if USE_MAGNETOMETER && AHRS_USE_GPS_HEADING
50#warning "Using magnetometer _and_ GPS course to update heading. Probably better to <configure name="USE_MAGNETOMETER" value="0"/> if you want to use GPS course."
51#endif
52
53/*
54 * default gains for correcting attitude and bias from accel/mag
55 */
56#ifndef AHRS_ACCEL_OMEGA
57#define AHRS_ACCEL_OMEGA 0.063
58#endif
59#ifndef AHRS_ACCEL_ZETA
60#define AHRS_ACCEL_ZETA 0.9
61#endif
62
63#ifndef AHRS_MAG_OMEGA
64#define AHRS_MAG_OMEGA 0.04
65#endif
66#ifndef AHRS_MAG_ZETA
67#define AHRS_MAG_ZETA 0.9
68#endif
69
71#ifndef AHRS_GRAVITY_HEURISTIC_FACTOR
72#define AHRS_GRAVITY_HEURISTIC_FACTOR 30
73#endif
74
75
76void ahrs_fc_update_mag_full(struct FloatVect3 *mag, float dt);
77void ahrs_fc_update_mag_2d(struct FloatVect3 *mag, float dt);
79
81
82void ahrs_fc_init(void)
83{
85 ahrs_fc.is_aligned = false;
86
89
90 /* init ltp_to_body quaternion as zero/identity rotation */
94
95 /* set default filter cut-off frequency and damping */
100
101#if AHRS_GRAVITY_UPDATE_COORDINATED_TURN
103#else
104 ahrs_fc.correct_gravity = false;
105#endif
106
108
110
111 ahrs_fc.accel_cnt = 0;
112 ahrs_fc.mag_cnt = 0;
113}
114
115bool ahrs_fc_align(struct FloatRates *lp_gyro, struct FloatVect3 *lp_accel,
116 struct FloatVect3 *lp_mag __attribute__((unused)))
117{
118
119#if USE_MAGNETOMETER
120 /* Compute an initial orientation from accel and mag directly as quaternion */
123#else
124 /* Compute an initial orientation from accel and just set heading to zero */
126 ahrs_fc.heading_aligned = false;
127#endif
128
129 /* Convert initial orientation from quat to rotation matrix representations. */
131
132 /* used averaged gyro as initial value for bias */
133 ahrs_fc.gyro_bias = *lp_gyro;
134
136 ahrs_fc.is_aligned = true;
137
138 return true;
139}
140
141
142void ahrs_fc_propagate(struct FloatRates *gyro, float dt)
143{
144
145 struct FloatRates rates = *gyro;
146 /* unbias measurement */
148
149#ifdef AHRS_PROPAGATE_LOW_PASS_RATES
150 const float alpha = 0.1;
152#else
154#endif
155
156 /* add correction */
157 struct FloatRates omega;
158 RATES_SUM(omega, rates, ahrs_fc.rate_correction);
159 /* and zeros it */
161
162#if AHRS_PROPAGATE_RMAT
166#endif
167#if AHRS_PROPAGATE_QUAT
171#endif
172
173 // increase accel and mag propagation counters
176}
177
178void ahrs_fc_update_accel(struct FloatVect3 *accel, float dt)
179{
180 // check if we had at least one propagation since last update
181 if (ahrs_fc.accel_cnt == 0) {
182 return;
183 }
184
185 /* last column of roation matrix = ltp z-axis in body-frame */
189 };
190
191 struct FloatVect3 imu_accel = *accel;
192 struct FloatVect3 residual;
194
196 /*
197 * centrifugal acceleration in body frame
198 * a_c_body = omega x (omega x r)
199 * (omega x r) = tangential velocity in body frame
200 * a_c_body = omega x vel_tangential_body
201 * assumption: tangential velocity only along body x-axis (or negative z-axis)
202 */
203 const struct FloatVect3 vel_tangential_body =
204#if AHRS_GPS_SPEED_IN_NEGATIVE_Z_DIRECTION
205 /* AHRS_GRAVITY_UPDATE_COORDINATED_TURN assumes the GPS speed is in the X axis direction.
206 * Quadshot, DelftaCopter and other hybrids can have the GPS speed in the negative Z direction
207 */
208 {0.0, 0.0, -ahrs_fc.ltp_vel_norm);
209#else
210 /* assume tangential velocity along body x-axis */
211 {ahrs_fc.ltp_vel_norm, 0.0, 0.0};
212#endif
213 struct FloatVect3 acc_c_body;
215
216 /* centrifugal acceleration subtract it from imu measurement to get a corrected measurement of the gravity vector */
218
219 } else {
221 }
222
224
225 /* FIR filtered pseudo_gravity_measurement */
226#define FIR_FILTER_SIZE 8
227 static struct FloatVect3 filtered_gravity_measurement = {0., 0., 0.};
231
233 /* heuristic on acceleration (gravity estimate) norm */
234 /* Factor how strongly to change the weight.
235 * e.g. for gravity_heuristic_factor 30:
236 * <0.66G = 0, 1G = 1.0, >1.33G = 0
237 */
238
241 Bound(ahrs_fc.weight, 0.15, 1.0);
242 } else {
243 ahrs_fc.weight = 1.0;
244 }
245
246 /* Complementary filter proportional gain.
247 * Kp = 2 * zeta * omega * weight * ahrs_fc.accel_cnt
248 * with ahrs_fc.accel_cnt beeing the number of propagations since last update
249 */
253
254 // reset accel propagation counter
255 ahrs_fc.accel_cnt = 0;
256
257 /* Complementary filter integral gain
258 * Correct the gyro bias.
259 * Ki = (omega*weight)^2 * dt
260 */
262 ahrs_fc.weight * ahrs_fc.weight * dt / 9.81;
264
265 /* FIXME: saturate bias */
266}
267
268
269void ahrs_fc_update_mag(struct FloatVect3 *mag __attribute__((unused)), float dt __attribute__((unused)))
270{
271#if USE_MAGNETOMETER
272 // check if we had at least one propagation since last update
273 if (ahrs_fc.mag_cnt == 0) {
274 return;
275 }
276#if AHRS_MAG_UPDATE_ALL_AXES
278#else
279 ahrs_fc_update_mag_2d(mag, dt);
280#endif
281 // reset mag propagation counter
282 ahrs_fc.mag_cnt = 0;
283#endif
284}
285
286void ahrs_fc_update_mag_full(struct FloatVect3 *mag, float dt)
287{
288
291
292 struct FloatVect3 measured_imu = *mag;
295 // DISPLAY_FLOAT_VECT3("# expected", expected_imu);
296 // DISPLAY_FLOAT_VECT3("# measured", measured_imu);
297 // DISPLAY_FLOAT_VECT3("# residual", residual);
298
299 /* Complementary filter proportional gain.
300 * Kp = 2 * zeta * omega * weight * ahrs_fc.mag_cnt
301 * with ahrs_fc.mag_cnt beeing the number of propagations since last update
302 */
303
306
307 /* Complementary filter integral gain
308 * Correct the gyro bias.
309 * Ki = (omega*weight)^2 * dt
310 */
313
314}
315
316void ahrs_fc_update_mag_2d(struct FloatVect3 *mag, float dt)
317{
318
321 // normalize expected ltp in 2D (x,y)
323
324 struct FloatVect3 measured_imu = *mag;
327
329
330 // normalize measured ltp in 2D (x,y)
332
333 struct FloatVect3 residual_ltp = {
334 0,
335 0,
337 };
338
339 // printf("res : %f\n", residual_ltp.z);
340
343
344
345 /* Complementary filter proportional gain.
346 * Kp = 2 * zeta * omega * weight * ahrs_fc.mag_cnt
347 * with ahrs_fc.mag_cnt beeing the number of propagations since last update
348 */
351
352 /* Complementary filter integral gain
353 * Correct the gyro bias.
354 * Ki = (omega*weight)^2 * dt
355 */
358}
359
360
362{
363
364 /* project mag on local tangeant plane */
365 struct FloatEulers ltp_to_body_euler;
366 float_eulers_of_rmat(&ltp_to_body_euler, &ahrs_fc.ltp_to_body_rmat);
367
368 const float cphi = cosf(ltp_to_body_euler.phi);
369 const float sphi = sinf(ltp_to_body_euler.phi);
370 const float ctheta = cosf(ltp_to_body_euler.theta);
371 const float stheta = sinf(ltp_to_body_euler.theta);
372 const float mn = ctheta * mag->x + sphi * stheta * mag->y + cphi * stheta * mag->z;
373 const float me = 0. * mag->x + cphi * mag->y - sphi * mag->z;
374
375 const float res_norm = -RMAT_ELMT(ahrs_fc.ltp_to_body_rmat, 0, 0) * me +
377 const struct FloatVect3 r2 = {RMAT_ELMT(ahrs_fc.ltp_to_body_rmat, 2, 0),
380 };
381 const float mag_rate_update_gain = 2.5;
383 const float mag_bias_update_gain = -mag_rate_update_gain * 1e-4;
385
386}
387
389{
390#if AHRS_GRAVITY_UPDATE_COORDINATED_TURN && USE_GPS
391 if (gps_s->fix >= GPS_FIX_3D) {
392 ahrs_fc.ltp_vel_norm = gps_s->speed_3d / 100.;
394 } else {
396 }
397#endif
398
399#if AHRS_USE_GPS_HEADING && USE_GPS
400 //got a 3d fix, ground speed > 0.5 m/s and course accuracy is better than 10deg
401 if (gps_s->fix >= GPS_FIX_3D && gps_s->gspeed >= 500 &&
402 gps_s->cacc <= RadOfDeg(10 * 1e7)) {
403
404 // gps_s->course is in rad * 1e7, we need it in rad
405 float course = gps_s->course / 1e7;
406
408 /* the assumption here is that there is no side-slip, so heading=course */
410 } else {
411 /* hard reset the heading if this is the first measurement */
413 }
414 }
415#endif
416}
417
418
420{
421
423
424 // row 0 of ltp_to_body_rmat = body x-axis in ltp frame
425 // we only consider x and y
426 struct FloatVect2 expected_ltp = {
429 };
430
431 // expected_heading cross measured_heading
432 struct FloatVect3 residual_ltp = {
433 0,
434 0,
436 };
437
440
441 const float heading_rate_update_gain = 2.5;
443
445 /* crude attempt to only update bias if deviation is small
446 * e.g. needed when you only have gps providing heading
447 * and the inital heading is totally different from
448 * the gps course information you get once you have a gps fix.
449 * Otherwise the bias will be falsely "corrected".
450 */
451 if (fabs(residual_ltp.z) < sinf(RadOfDeg(5.))) {
453 } else {
455 }
457}
458
459
461{
463
464 /* quaternion representing only the heading rotation from ltp to body */
465 struct FloatQuat q_h_new;
466 q_h_new.qx = 0.0;
467 q_h_new.qy = 0.0;
468 q_h_new.qz = sinf(heading / 2.0);
469 q_h_new.qi = cosf(heading / 2.0);
470
471 struct FloatQuat ltp_to_body_quat;
472 QUAT_COPY(ltp_to_body_quat, ahrs_fc.ltp_to_body_quat);
473
474 /* quaternion representing current heading only */
475 struct FloatQuat q_h = ltp_to_body_quat;
476 q_h.qx = 0.;
477 q_h.qy = 0.;
479
480 /* quaternion representing rotation from current to new heading */
481 struct FloatQuat q_c;
483
484 /* correct current heading in body frame */
486
487 /* compute ltp to imu rotation quaternion and matrix */
489
491}
#define AHRS_MAG_OMEGA
struct AhrsFloatCmpl ahrs_fc
void ahrs_fc_update_mag_2d(struct FloatVect3 *mag, float dt)
#define AHRS_MAG_ZETA
void ahrs_fc_init(void)
void ahrs_fc_update_mag_full(struct FloatVect3 *mag, float dt)
void ahrs_fc_update_mag(struct FloatVect3 *mag, float dt)
#define AHRS_GRAVITY_HEURISTIC_FACTOR
by default use the gravity heuristic to reduce gain
bool ahrs_fc_align(struct FloatRates *lp_gyro, struct FloatVect3 *lp_accel, struct FloatVect3 *lp_mag)
void ahrs_fc_update_mag_2d_dumb(struct FloatVect3 *mag)
void ahrs_fc_propagate(struct FloatRates *gyro, float dt)
void ahrs_fc_realign_heading(float heading)
Hard reset yaw to a heading.
#define FIR_FILTER_SIZE
#define AHRS_ACCEL_OMEGA
void ahrs_fc_update_accel(struct FloatVect3 *accel, float dt)
void ahrs_fc_update_gps(struct GpsState *gps_s)
#define AHRS_ACCEL_ZETA
void ahrs_fc_update_heading(float heading)
Update yaw based on a heading measurement.
Complementary filter in float to estimate the attitude, heading and gyro bias.
struct FloatRates gyro_bias
struct FloatRates body_rate
@ AHRS_FC_UNINIT
@ AHRS_FC_RUNNING
uint16_t mag_cnt
number of propagations since last mag update
enum AhrsFCStatus status
bool correct_gravity
enable gravity correction during coordinated turns
float mag_zeta
filter damping for correcting the gyro bias from magnetometer
struct FloatVect3 mag_h
struct FloatRMat ltp_to_body_rmat
struct FloatRates rate_correction
float ltp_vel_norm
velocity norm for gravity correction during coordinated turns
float mag_omega
filter cut-off frequency for correcting the attitude (heading) from magnetometer
float accel_zeta
filter damping for correcting the gyro-bias from accels (pseudo-gravity measurement)
uint8_t gravity_heuristic_factor
sets how strongly the gravity heuristic reduces accel correction.
float accel_omega
filter cut-off frequency for correcting the attitude from accels (pseudo-gravity measurement)
uint16_t accel_cnt
number of propagations since last accel update
struct FloatQuat ltp_to_body_quat
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)
static void ahrs_float_get_quat_from_accel(struct FloatQuat *q, struct FloatVect3 *accel)
Compute a quaternion representing roll and pitch from an accelerometer measurement.
static int16_t course[3]
static uint16_t c2
Device independent GPS code (interface)
#define GPS_FIX_3D
3D GPS fix
Definition gps.h:44
data structure for GPS information
Definition gps.h:87
float phi
in radians
float theta
in radians
static void float_quat_normalize(struct FloatQuat *q)
#define FLOAT_ANGLE_NORMALIZE(_a)
static void float_quat_identity(struct FloatQuat *q)
initialises a quaternion to identity
float float_rmat_reorthogonalize(struct FloatRMat *rm)
void float_quat_comp_norm_shortest(struct FloatQuat *a2c, struct FloatQuat *a2b, struct FloatQuat *b2c)
Composition (multiplication) of two quaternions with normalization.
void float_quat_inv_comp_norm_shortest(struct FloatQuat *b2c, struct FloatQuat *a2b, struct FloatQuat *a2c)
Composition (multiplication) of two quaternions with normalization.
void float_quat_of_rmat(struct FloatQuat *q, struct FloatRMat *rm)
Quaternion from rotation matrix.
static void float_rmat_identity(struct FloatRMat *rm)
initialises a rotation matrix to identity
void float_rmat_of_quat(struct FloatRMat *rm, struct FloatQuat *q)
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_rmat_integrate_fi(struct FloatRMat *rm, struct FloatRates *omega, float dt)
in place first order integration of a rotation matrix
static void float_vect2_normalize(struct FloatVect2 *v)
normalize 2D vector in place
void float_eulers_of_rmat(struct FloatEulers *e, struct FloatRMat *rm)
void float_rmat_transp_vmult(struct FloatVect3 *vb, struct FloatRMat *m_b2a, struct FloatVect3 *va)
rotate 3D vector by transposed rotation matrix.
static float float_vect3_norm(struct FloatVect3 *v)
#define FLOAT_RATES_ZERO(_r)
void float_rmat_vmult(struct FloatVect3 *vb, struct FloatRMat *m_a2b, struct FloatVect3 *va)
rotate 3D vector by rotation matrix.
euler angles
Roation quaternion.
angular rates
#define VECT3_SDIV(_vo, _vi, _s)
#define VECT3_RATES_CROSS_VECT3(_vo, _r1, _v2)
#define RATES_COPY(_a, _b)
#define RATES_ADD_SCALED_VECT(_ro, _v, _s)
#define VECT2_COPY(_a, _b)
#define RATES_SUB(_a, _b)
#define VECT3_CROSS_PRODUCT(_vo, _v1, _v2)
#define VECT3_SMUL(_vo, _vi, _s)
#define VECT3_ASSIGN(_a, _x, _y, _z)
#define QUAT_COPY(_qo, _qi)
#define RATES_SUM(_c, _a, _b)
#define RMAT_ELMT(_rm, _row, _col)
#define VECT3_COPY(_a, _b)
#define VECT3_DIFF(_c, _a, _b)
#define VECT3_ADD(_a, _b)
uint16_t foo
Definition main_demo5.c:58
Paparazzi floating point algebra.
Paparazzi fixed point algebra.
Simple matrix helper macros.
float alpha
Definition textons.c:133
float heading
Definition wedgebug.c:258