10static void trace_put(est_t *e, uint8_t op,
const float *v,
int nf,
int trusted)
12 if (!e->trace_enable || !e->running)
return;
14 const uint16_t need = (uint16_t)(1u + 4u*(
unsigned)nf + (op ==
EST_OP_ACC ? 1u : 0u));
17 memcpy(&t->
buf[t->
len], v, 4u*(
unsigned)nf);
18 t->
len = (uint16_t)(t->
len + 4u*(
unsigned)nf);
25 memset(e, 0,
sizeof *e);
37 const float inv = 1.0f / (float)e->k;
38 for (
int i = 0; i < 3; ++i) {
39 gm[i] = e->gsum[i] * inv;
40 e->gwin_sum[i] += gm[i];
45 const float pv[4] = { e->dth[0], e->dth[1], e->dth[2], h };
52 for (
int i = 0; i < 3; ++i) in.
gyro[i] = e->omega[i] = gm[i] - e->f.b[i];
53 in.
dt = h; in.
step = e->step;
57 memset(e->dth, 0,
sizeof e->dth);
58 memset(e->gsum, 0,
sizeof e->gsum);
64 if (
accwin_mean(&e->win, e->acc_mean) == 0) e->have_acc_mean = 1;
67 for (
int i = 0; i < 3; ++i) e->gyro_mean[i] = e->gwin_sum[i] / (
float)e->gwin_n;
69 memset(e->gwin_sum, 0,
sizeof e->gwin_sum);
72 if (!e->running || !e->have_acc_mean)
return;
74 if (e->cfg.still_time_s > 0.0f) {
78 const float *w = e->gyro_mean;
79 const float dev = fabsf(
vec3_norm(e->acc_mean) - e->f.nom_acc) / e->f.nom_acc;
80 if (dev < e->cfg.still_acc_tol &&
vec3_norm(w) < e->cfg.still_gyro_thr)
84 if (e->still_t >= e->cfg.still_time_s) {
95 in.
dt = h_win; in.
step = e->step;
99 if (e->on_state) e->on_state(e, e->user);
101 memset(&e->trace, 0,
sizeof e->trace);
105static void on_mag(est_t *e,
const float m_sensor[3])
107 const float *M = e->cfg.mag_map;
108 for (
int i = 0; i < 3; ++i) {
109 const float k = (e->cfg.mag_scale[i] > 0.0f) ? e->cfg.mag_scale[i] : 1.0f;
110 e->mag[i] = k * (M[3*i]*m_sensor[0] + M[3*i + 1]*m_sensor[1] + M[3*i + 2]*m_sensor[2]
111 - e->cfg.mag_hard_iron[i]);
119 for (
int i = 0; i < 3; ++i) y[i] = e->mag[i] - e->cfg.mag_latency_s * wxy[i];
121 const float wxu = (nm > 1e-6f) ?
vec3_norm(wxy) / nm : 0.0f;
122 const float sd = wxu * e->cfg.mag_latency_std_s;
124 const float mv[4] = { y[0], y[1], y[2], sd*sd };
131 if (!e->have_acc_mean)
return;
132 if (
calib_add(&e->cal, e->acc_mean, e->gyro_mean, e->mag, e->cfg.calib_gyro_still) != 0) {
136 if (
calib_count(&e->cal) < e->cfg.calib_samples)
return;
138 if (
calib_finish(&e->cal, e->cfg.sigma_vec_min, &e->calres) != 0) {
151 memset(&e->trace, 0,
sizeof e->trace);
152 if (e->on_init) e->on_init(e, e->user);
157 for (
size_t j = 0; j <
n; ++j) {
158 switch (ev[j].type) {
160 for (
int i = 0; i < 3; ++i) {
161 e->dth[i] += ev[j].
v[i] * dt;
162 e->gsum[i] += ev[j].
v[i];
164 if (++e->k >= e->cfg.gyro_per_step) {
165 const float h = (float)e->k * dt;
167 if ((e->step % e->cfg.steps_per_acc) == 0)
void accwin_rotate(accwin_t *w, const float E[9])
after every propagation
void accwin_add(accwin_t *w, const float acc[3])
sample in the current body
int accwin_mean(const accwin_t *w, float out[3])
in the current body, 0 = OK
void accwin_reset(accwin_t *w)
static void on_init(const est_t *e, void *user)
static void on_state(const est_t *e, void *user)
void calib_reset(calib_t *c)
int calib_finish(const calib_t *c, float sigma_min, calib_result_t *out)
int calib_add(calib_t *c, const float acc[3], const float gyro[3], const float mag[3], float gyro_still_thr)
Returns 0 if the sample is compatible with "still", -1 if moving.
uint32_t calib_count(const calib_t *c)
void ctrl_attitude_step(const ctrl_att_in_t *in)
240 Hz
void ctrl_rate_step(const ctrl_rate_in_t *in)
960 Hz
Control hook points, already called by the estimation task at the right rates.
static void on_mag(est_t *e, const float m_sensor[3])
static void on_step(est_t *e, float h)
void est_init(est_t *e, const est_config_t *cfg, est_cb_t on_state, est_cb_t on_init, void *user)
void est_process(est_t *e, const imu_event_t *ev, size_t n, float dt)
dt_sample: IMU sample period measured by the MCU (s)
static void trace_put(est_t *e, uint8_t op, const float *v, int nf, int trusted)
static void on_acc_window(est_t *e, float h_win)
Multi-rate estimation pipeline, WITHOUT any HAL or RTOS dependency.
void(* est_cb_t)(const est_t *e, void *user)
#define EST_F_STILL
stillness detector active
int iekf_update_mag_ex(iekf_t *f, const float mag[3], float extra_var)
As above, with an additional per-component variance (e.g.
void iekf_propagate_dtheta(iekf_t *f, const float dtheta[3], float h)
Propagation with a measured angle increment (bias NOT yet removed): phi = dtheta - b*dt.
void iekf_init(iekf_t *f, const iekf_config_t *cfg, const iekf_seed_t *s)
void iekf_get_quat(const iekf_t *f, float q[4])
int iekf_update_acc(iekf_t *f, const float acc[3])
Return 1 if the measurement was "gated" (de-weighted), 0 otherwise.
void vec3_cross(const float a[3], const float b[3], float c[3])
float vec3_norm(const float v[3])
Single-precision SO(3) Lie-group utilities (port of expSO3.m / skewSym.m + firmware helpers).
float q[4]
IEKF attitude, body->world NWU, [w x y z].
float gyro[3]
rad/s: mean of the step samples, estimated bias removed
uint8_t buf[EST_TRACE_MAX]
float sigma_acc
per-component std of the normalised vector