A robust, standalone 6-Axis (Gyroscope + Accelerometer) Attitude and Heading Reference System (AHRS) implementation. This library provides two algorithms: the original Madgwick-based fusion and an advanced Extended Kalman Filter (EKF) with adaptive filtering for challenging environments.
├── optimized_mcu/ # MCU-optimized version (C-style)
│ ├── Fusion_AHRS.h
│ └── Fusion_AHRS.cpp
├── readable_cpp/ # Modern C++ version (better readability)
│ ├── Fusion_AHRS.hpp
│ └── Fusion_AHRS.cpp
└── EKF_Version/ # Extended Kalman Filter with adaptive features
├── Fusion_AHRS.h # Base AHRS (same as optimized_mcu)
├── Fusion_AHRS.cpp
├── Tactical_Fusion.h
└── Tactical_Fusion.cpp # Advanced EKF implementation
| Directory | Description | Best For |
|---|---|---|
optimized_mcu/ |
C-style, highly optimized | Embedded systems (STM32, ESP32) |
readable_cpp/ |
Modern C++17, OOP | Desktop, simulation, learning |
EKF_Version/ |
EKF + adaptive filtering | High-precision, impact-prone applications |
Based on Sebastian Madgwick's PhD thesis, Chapter 7.
Quaternion Gradient Descent:
Where:
-
$q = [q_0, q_1, q_2, q_3]$ is the quaternion -
$\omega = [0, \omega_x, \omega_y, \omega_z]$ is the angular velocity -
$\beta$ is the gain parameter -
$\nabla f$ is the gradient of the objective function
Objective Function:
-
$f_d = 2(q_1q_3 - q_0q_2) - d_x$ (direction cosine matrix error) -
$f_g = 2(q_0q_1 + q_2q_3) - d_y$ (gyroscope error) -
$\lambda$ balances the two constraints
Discrete Update (Sample Rate
Adaptive Weighting:
The fusion weight
Where
A 6-state EKF that estimates attitude quaternion and gyroscope bias.
Where:
-
$q$ : attitude quaternion -
$b$ : gyroscope bias (rad/s)
Jacobian Matrix
Covariance Prediction:
Where
The accelerometer measures gravity direction in body frame:
Innovation:
Kalman Gain:
Where
State Update:
Covariance Update:
Detects high-acceleration events and rapidly recovers orientation estimation.
if (accDelta > accThreshold || gyroDelta > gyroThreshold) {
impactDetected = true;
}- Immediately reduce accelerometer weight to ignore false readings during impact
- Ramp up gain during recovery for fast convergence
Weight(t) = w_impact + (w_normal - w_impact) * (t / recovery_duration)
Process Noise Scaling:
During impact, process noise
This makes the EKF rely more on gyro integration vs. accelerometer correction.
| Parameter | Default | Description |
|---|---|---|
impactAccThreshold |
0.5g | Acceleration change threshold |
impactGyroThreshold |
100°/s | Gyro rate change threshold |
impactRecoveryDuration |
0.5s | Recovery time |
accWeightImpact |
5% | Weight during impact |
Detects and compensates for linear acceleration (translation) interference.
The key insight: static acceleration magnitude ≈ 1g, linear motion causes deviation.
If deviation > threshold, linear motion is detected.
During linear motion, accelerometer weight is further reduced:
| Parameter | Default | Description |
|---|---|---|
linearAccThreshold |
0.15g | Deviation threshold |
linearMotionDecay |
0.95 | State decay rate |
accCompensationEnabled |
1 | Feature toggle |
#include "Fusion_AHRS.h"
FusionAhrs ahrs;
FusionOffset offset;
void main() {
FusionAhrsInitialise(&ahrs);
FusionOffsetInitialise(&offset, 100); // 100 Hz
while (1) {
FusionVector gyro = {gx, gy, gz}; // deg/s
FusionVector acc = {ax, ay, az}; // g
// Gyroscope bias correction
gyro = FusionOffsetUpdate(&offset, gyro);
// Update AHRS
FusionAhrsUpdate(&ahrs, gyro, acc, 0.01f);
// Get result
FusionQuaternion q = FusionAhrsGetQuaternion(&ahrs);
FusionEuler euler = FusionQuaternionToEuler(q);
}
}#include "Tactical_Fusion.h"
TacticalSystem sys;
void main() {
Tactical_Init(&sys, 100.0f, 0.1f); // 100 Hz, 0.1 Hz heave cutoff
while (1) {
FusionVector gyro = {gx, gy, gz}; // deg/s
FusionVector acc = {ax, ay, az}; // g
Tactical_Update(&sys, gyro, acc);
FusionQuaternion q = sys.quaternion;
}
}| Parameter | Default | Range | Description |
|---|---|---|---|
gain |
0.5 | 0-1 | Algorithm gain |
beta |
0.1 | 0-1 | Gradient descent rate |
gyroscopeRange |
2000°/s | - | Gyro range limit |
accelerationRejection |
30° | - | Accel rejection threshold |
| Parameter | Default | Description |
|---|---|---|
processNoiseAngle |
1e-5 | Angle process noise |
processNoiseBias |
1e-7 | Bias process noise |
measureNoiseAcc |
1e-2 | Accel measurement noise |
accStaticThreshold |
0.02g | Static detection threshold |
gyroStaticThreshold |
0.5°/s | Static gyro threshold |
| Feature | Madgwick | EKF (Tactical) |
|---|---|---|
| Algorithm | Gradient Descent | Extended Kalman Filter |
| Complexity | Low | Medium |
| Accuracy | Good | Excellent |
| Impact Recovery | Basic | Advanced |
| Linear Motion Filter | No | Yes |
| Heave Estimation | No | Yes |
| MCU Friendly | ✅ | ✅ |
| Mode | Convergence | Static Noise |
|---|---|---|
| GD ON (default) | ⚡ Very Fast | 🔊 Slightly Higher |
| GD OFF | 🚗 Fast | 🔇 Minimal |
| Motion State | Behavior |
|---|---|
| Static | High accel weight, ZUPT for bias correction |
| Linear Motion | Reduced accel weight, rely on gyro |
| Impact | Minimal accel weight, fast recovery |
MIT License - See LICENSE file.
Original Implementation: T-DT Lab, Northeastern University This algorithm has been used in the RoboMaster Super Confrontation Competition since the 2024 season