<alp/ahrs.h> — Attitude & Heading Reference
A caller-owned Madgwick orientation filter that fuses a 3-axis gyroscope with a 3-axis accelerometer into a drift-corrected orientation quaternion. The accelerometer pins roll/pitch against gravity, so the estimate does not drift the way a raw gyro integrator does.
Only the IMU variant (gyro + accel) ships today. A magnetometer-aided MARG variant may be added later — without a magnetometer, yaw is not absolute and will drift about the gravity axis.
Header
#include <alp/ahrs.h>
board.yaml
The filter is opt-in — it compiles only when the madgwick_ahrs library knob is selected, which emits CONFIG_ALP_SDK_AHRS:
libraries:
- madgwick_ahrs
The implementation is pure C (libm only) and builds on every OS target. Faster hardware paths (ALP_MADGWICK_FPU, ALP_MADGWICK_TMU for the GD32 TMU CORDIC) bind transparently on SoMs that expose them; ALP_MADGWICK_LIBM is the always-available software floor.
Run the filter
Like <alp/pid.h>, this needs no pool and no handle — allocate an alp_ahrs_t (static or on the stack), initialise it once, then drive it every sample:
static alp_ahrs_t ahrs;
alp_ahrs_init(&ahrs, &(alp_ahrs_config_t){ .beta = 0.1f });
for (;;) {
// gyro in rad/s; accel in any consistent unit (the vector is normalised)
alp_ahrs_update_imu(&ahrs, gx, gy, gz, ax, ay, az, dt_s);
float roll, pitch, yaw;
alp_ahrs_euler(&ahrs, &roll, &pitch, &yaw); // degrees
}
Config struct
| Field | Type | Notes |
|---|---|---|
beta | float | Madgwick filter gain, rad/s. Pass <= 0 to use ALP_AHRS_DEFAULT_BETA (0.1f). Raise for faster accelerometer correction (more noise); lower for smoother output (slower drift correction). |
Passing a NULL config to alp_ahrs_init is legal — it uses ALP_AHRS_DEFAULT_BETA.
Functions
| Call | Returns |
|---|---|
alp_ahrs_init(alp_ahrs_t *ahrs, const alp_ahrs_config_t *cfg) | ALP_OK / ALP_ERR_INVAL (NULL ahrs). Sets the quaternion to identity (1,0,0,0) — level, facing +x — and copies the gain. Safe to call again to re-seed. |
alp_ahrs_update_imu(ahrs, gx, gy, gz, ax, ay, az, dt_s) | void. One Madgwick IMU update: integrates the gyro, applies a gradient-descent correction toward the measured gravity direction, renormalises the quaternion. |
alp_ahrs_euler(const alp_ahrs_t *ahrs, float *roll_deg, float *pitch_deg, float *yaw_deg) | void. Converts the quaternion to intrinsic Z-Y-X (yaw-pitch-roll) Euler angles in degrees. Any output pointer may be NULL to skip it; a NULL ahrs leaves the outputs untouched. |
alp_ahrs_reset(alp_ahrs_t *ahrs) | void. Resets the orientation to identity, keeping the gain. NULL is a no-op. |
Units and edge cases
- Gyro is rad/s. Accelerometer may be in any consistent unit — the vector is normalised internally, so raw counts are fine.
dt_sis the time since the previous update, in seconds, and must be> 0. A non-positivedt_sis ignored (the sample is dropped).- If the accelerometer vector is zero (free-fall, or a sensor dropout) the update falls back to gyro-only integration for that sample.
pitch_degis bounded to[-90, 90]; roll and yaw are unbounded.
State struct
alp_ahrs_t is caller-owned and transparent (so it is stack-allocatable), holding the orientation as a unit quaternion (q0, q1, q2, q3) mapping the sensor frame to the earth frame, plus the filter gain. Treat it as opaque — do not read or write the fields directly; the layout is [ABI-EXPERIMENTAL] and may gain fields before v1.0. Read the orientation through alp_ahrs_euler.
ABI status
[ABI-EXPERIMENTAL] — new in v0.10. The struct layout may change before v1.0; pin your SDK to a specific commit if you depend on it.
See also
<alp/pid.h>— the other caller-owned control/math library, same no-handle shape<alp/dsp.h>— filter chains and summary statisticsboard.yaml:libraries: