ACwing FC firmware
STM32WB55: attitude IEKF, altitude Kalman filter, flight core, protocol v2
Loading...
Searching...
No Matches
alt_est.c
Go to the documentation of this file.
1
5#include "alt_est.h"
6#include <math.h>
7#include <string.h>
8
9#define G0 9.80665f
10#define BARO_INIT_N 25u /* 0.5 s of samples to set the reference pressure */
11#define TOF_GATE_S 3.0f /* innovation gate, sigmas */
12#define TOF_REANCHOR 15u /* consecutive rejects (0.5 s at 30 Hz) */
13
15{
16 c->sigma_acc = 0.5f;
17 c->sigma_acc_bias = 0.01f;
18 c->sigma_baro_bias = 0.05f;
19 c->sigma_baro = 0.30f;
20 c->sigma_tof = 0.02f;
21 c->tof_min_m = 0.04f;
22 c->tof_max_m = 4.0f;
23 c->tof_max_tilt_cos = 0.866f; /* 30 deg */
24 c->tof_offset_m = 0.0113f; /* frame C2: lens 11.3 mm above the floor */
25}
26
28{
29 memset(e, 0, sizeof *e);
30 e->c = *c;
31 e->P[0][0] = 0.01f; e->P[1][1] = 0.01f; e->P[2][2] = 1.0f; e->P[3][3] = 0.04f;
32 e->tof_age_s = 1e3f;
33}
34
35float alt_est_accel_up(const float q[4], const float f[3], float nom_g)
36{
37 /* third row of R(q), body -> world (NWU, z up), q = [w x y z] */
38 const float w = q[0], x = q[1], y = q[2], z = q[3];
39 const float r20 = 2.0f * (x*z - w*y);
40 const float r21 = 2.0f * (y*z + w*x);
41 const float r22 = 1.0f - 2.0f * (x*x + y*y);
42 const float fz = r20*f[0] + r21*f[1] + r22*f[2];
43 const float n = (nom_g > 0.5f) ? nom_g : 1.0f;
44 return (fz / n - 1.0f) * G0;
45}
46
47void alt_est_predict(alt_est_t *e, float a, float dt)
48{
49 if (dt <= 0.0f || dt > 0.1f) return;
50 float *x = e->x;
51 const float u = a - x[3];
52 x[0] += x[1]*dt + 0.5f*u*dt*dt;
53 x[1] += u*dt;
54
55 /* P = F P F' + Q, F = [1 dt 0 -dt2/2; 0 1 0 -dt; 0 0 1 0; 0 0 0 1] */
56 const float h2 = 0.5f*dt*dt;
57 float F[4][4] = { { 1, dt, 0, -h2 }, { 0, 1, 0, -dt }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
58 float T[4][4], N[4][4];
59 for (int i = 0; i < 4; ++i)
60 for (int j = 0; j < 4; ++j) {
61 float s = 0.0f;
62 for (int k = 0; k < 4; ++k) s += F[i][k] * e->P[k][j];
63 T[i][j] = s;
64 }
65 for (int i = 0; i < 4; ++i)
66 for (int j = 0; j < 4; ++j) {
67 float s = 0.0f;
68 for (int k = 0; k < 4; ++k) s += T[i][k] * F[j][k];
69 N[i][j] = s;
70 }
71 const float qa = e->c.sigma_acc * e->c.sigma_acc;
72 const float G[2] = { h2, dt };
73 for (int i = 0; i < 2; ++i) for (int j = 0; j < 2; ++j) N[i][j] += G[i]*G[j]*qa;
74 /* baro bias random walk only while it is observable (ToF in the last 1 s) */
75 if (e->tof_age_s < 1.0f) N[2][2] += e->c.sigma_baro_bias * e->c.sigma_baro_bias * dt;
76 N[3][3] += e->c.sigma_acc_bias * e->c.sigma_acc_bias * dt;
77 for (int i = 0; i < 4; ++i)
78 for (int j = 0; j < 4; ++j) e->P[i][j] = 0.5f * (N[i][j] + N[j][i]);
79 e->tof_age_s += dt;
80}
81
82/* scalar update with H = [h0 0 h2 0]; returns 0 if applied, -1 if gated */
83static int update(alt_est_t *e, float h0, float h2, float z, float r, float gate)
84{
85 const float pred = h0*e->x[0] + h2*e->x[2];
86 float PH[4];
87 for (int i = 0; i < 4; ++i) PH[i] = e->P[i][0]*h0 + e->P[i][2]*h2;
88 const float S = h0*PH[0] + h2*PH[2] + r;
89 if (S <= 0.0f) return -1;
90 const float y = z - pred;
91 if (gate > 0.0f && y*y > gate*gate*S) return -1;
92 float K[4];
93 for (int i = 0; i < 4; ++i) K[i] = PH[i] / S;
94 for (int i = 0; i < 4; ++i) e->x[i] += K[i] * y;
95 for (int i = 0; i < 4; ++i)
96 for (int j = 0; j < 4; ++j) e->P[i][j] -= K[i] * PH[j];
97 for (int i = 0; i < 4; ++i)
98 for (int j = i + 1; j < 4; ++j) { const float m = 0.5f*(e->P[i][j] + e->P[j][i]); e->P[i][j] = e->P[j][i] = m; }
99 return 0;
100}
101
102void alt_est_baro(alt_est_t *e, float pa)
103{
104 if (!(pa > 30000.0f && pa < 120000.0f)) return; /* also rejects NaN */
105 e->pressure = pa;
106 if (!e->baro_ok) {
107 e->p_sum += pa;
108 if (++e->p_n < BARO_INIT_N) return;
109 e->p_ref = e->p_sum / (float)e->p_n;
110 e->baro_ok = 1;
111 /* bias such that the baro agrees with the current h */
112 e->x[2] = -e->x[0];
113 e->valid = 1;
114 return;
115 }
116 e->baro_alt = 44330.0f * (1.0f - powf(pa / e->p_ref, 0.190295f));
117 (void)update(e, 1.0f, 1.0f, e->baro_alt, e->c.sigma_baro * e->c.sigma_baro, 0.0f);
118}
119
120void alt_est_tof(alt_est_t *e, float range, uint8_t ok, float ct)
121{
122 const alt_est_cfg_t *c = &e->c;
123 e->tof_valid = 0;
124 /* below the minimum range, or no return right after a short reading: on the floor */
125 const uint8_t short_rd = (range < c->tof_min_m + 0.02f) || (!ok && e->have_tof && e->tof_h < 0.15f);
126 e->tof_ground = (uint8_t)(short_rd && ct > c->tof_max_tilt_cos);
127 float hm;
128 float r;
129 if (e->tof_ground) {
130 hm = 0.0f; /* the floor: h = ground */
131 r = 0.03f * 0.03f;
132 } else {
133 if (!ok || range > c->tof_max_m || ct < c->tof_max_tilt_cos) return;
134 hm = range * ct - c->tof_offset_m;
135 const float s = c->sigma_tof + 0.01f * range;
136 r = s * s;
137 }
138 if (!e->have_tof) {
139 /* first ToF: the floor sits under the current h */
140 e->ground = e->x[0] - hm;
141 e->have_tof = 1;
142 }
143 if (update(e, 1.0f, 0.0f, hm + e->ground, r, TOF_GATE_S) != 0) {
144 if (++e->tof_rejects >= TOF_REANCHOR) { /* the floor moved: re-anchor */
145 e->ground = e->x[0] - hm;
146 e->tof_rejects = 0;
147 } else {
148 return;
149 }
150 } else {
151 e->tof_rejects = 0;
152 }
153 e->tof_h = hm;
154 e->tof_valid = 1;
155 e->tof_age_s = 0.0f;
156 e->valid = 1;
157}
158
160{
161 const float h0 = e->x[0];
162 e->x[0] = 0.0f;
163 e->x[2] += h0; /* baro: z = h + b keeps its prediction */
164 e->ground -= h0;
165}
void alt_est_baro(alt_est_t *e, float pa)
Definition alt_est.c:102
void alt_est_tof(alt_est_t *e, float range, uint8_t ok, float ct)
range_m: raw ToF range; status_ok: range status valid; cos_tilt: R33
Definition alt_est.c:120
#define TOF_REANCHOR
Definition alt_est.c:12
void alt_est_default_cfg(alt_est_cfg_t *c)
Definition alt_est.c:14
#define TOF_GATE_S
Definition alt_est.c:11
static int update(alt_est_t *e, float h0, float h2, float z, float r, float gate)
Definition alt_est.c:83
#define G0
Definition alt_est.c:9
#define BARO_INIT_N
Definition alt_est.c:10
void alt_est_init(alt_est_t *e, const alt_est_cfg_t *c)
Definition alt_est.c:27
float alt_est_accel_up(const float q[4], const float f[3], float nom_g)
vertical acceleration (m/s^2, + up, gravity removed) from the attitude and the specific force in body...
Definition alt_est.c:35
void alt_est_zero(alt_est_t *e)
Definition alt_est.c:159
void alt_est_predict(alt_est_t *e, float a, float dt)
Definition alt_est.c:47
Vertical estimator: height, climb rate, baro bias, accelerometer bias.
static batt_state_t s
Definition battery.c:21
uint32_t n
Definition calib_mgr.c:35
static struct @9 G
double N[6][6]
Definition calib_mgr.c:53
static const log_flash_t * F
Definition log_store.c:8
float tof_offset_m
lens height above the floor when landed
Definition alt_est.h:37
float tof_max_tilt_cos
cos of the largest usable tilt
Definition alt_est.h:36
float tof_min_m
Definition alt_est.h:35
float sigma_acc_bias
m/s^2/sqrt(s), random walk
Definition alt_est.h:31
float sigma_acc
m/s^2, vertical acceleration noise
Definition alt_est.h:30
float sigma_baro
m, baro altitude noise
Definition alt_est.h:33
float sigma_tof
m, ToF noise at 0 m (+1 % of the range)
Definition alt_est.h:34
float tof_max_m
Definition alt_est.h:35
float sigma_baro_bias
m/sqrt(s), random walk (while ToF is valid)
Definition alt_est.h:32
alt_est_cfg_t c
Definition alt_est.h:41
uint8_t baro_ok
Definition alt_est.h:47
uint8_t tof_valid
last ToF sample used
Definition alt_est.h:53
uint8_t valid
an altitude source is initialised
Definition alt_est.h:58
float p_sum
Definition alt_est.h:46
uint16_t p_n
Definition alt_est.h:46
float baro_alt
last baro altitude (m, p_ref based)
Definition alt_est.h:48
uint8_t have_tof
a ToF sample was used at least once
Definition alt_est.h:57
uint8_t tof_ground
below the minimum range: on the floor
Definition alt_est.h:54
float tof_h
last height above the floor (m)
Definition alt_est.h:52
float P[4][4]
Definition alt_est.h:43
float ground
ToF.
Definition alt_est.h:51
float tof_age_s
since the last valid ToF sample
Definition alt_est.h:56
float pressure
last Pa
Definition alt_est.h:49
float p_ref
baro
Definition alt_est.h:45
uint8_t tof_rejects
Definition alt_est.h:55
float x[4]
Definition alt_est.h:42