1274 字
6 分钟
高精度 IMU 姿态解算:基于 ICM-20602 的四元数 Mahony 滤波实现

1. 姿态解算概述#

姿态解算是平衡车、无人机、四足机器人及穿戴设备的核心技术。ICM-20602 是一款高性价比的 6 轴运动跟踪传感器,内置三轴陀螺仪与三轴加速度计,输出速率最高可达 8kHz。

单纯的陀螺仪积分会产生累积漂移,而单纯依赖加速度计又易受高频振动干扰。本方案采用四元数表示姿态,结合 Mahony AHRS 滤波算法(PI 控制器补偿重力误差),实现陀螺仪高动态响应与加速度计静态精度的完美融合,最终输出稳定且精准的欧拉角(Pitch、Roll、Yaw)。


2. 算法核心步骤#

  1. 零偏校准:开机静态采集并计算陀螺仪偏移量。
  2. 数据预处理:加速度归一化 + 限幅滤波。
  3. 四元数更新:利用角速度对四元数进行一阶积分。
  4. 误差补偿:通过加速度计重力向量与四元数预测向量的叉积,构造误差信号,再用 PI 控制器修正陀螺仪输入。
  5. 欧拉角转换:将四元数转换为直观的 Pitch/Roll/Yaw 角度。

3. 核心代码实现#

3.1 结构体定义与全局变量#

typedef struct {
float x, y, z;
} _xyz_f_st;
typedef struct {
_xyz_f_st gyro; // 角速度 (rad/s)
_xyz_f_st acc; // 加速度 (g)
_xyz_f_st gyro_offset;
uint8_t offset_flag;
} GYRO_VAR;
GYRO_VAR imu = {0};
// Mahony 滤波参数(需根据实际调试)
#define Kp 0.8f
#define Ki 0.001f
static float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f;
static float exInt = 0.0f, eyInt = 0.0f, ezInt = 0.0f;

3.2 零偏校正#

#define OFFSET_COUNT 500
void IMU_Offset(GYRO_VAR *imu) {
int32_t temp_gx = 0, temp_gy = 0, temp_gz = 0;
for (uint16_t i = 0; i < OFFSET_COUNT; i++) {
icm20602_get_data(imu); // 读取原始数据
temp_gx += imu->gyro.x;
temp_gy += imu->gyro.y;
temp_gz += imu->gyro.z;
delay_ms(2);
}
imu->gyro_offset.x = (float)temp_gx / OFFSET_COUNT;
imu->gyro_offset.y = (float)temp_gy / OFFSET_COUNT;
imu->gyro_offset.z = (float)temp_gz / OFFSET_COUNT;
imu->offset_flag = 1;
Serial.println("✅ 陀螺仪零偏校准完成");
}

3.3 快速平方根倒数(经典魔法数)#

float InvSqrt(float x) {
float halfx = 0.5f * x;
long i = *(long*)&x;
i = 0x5f3759df - (i >> 1); // 雷神之锤经典常数
x = *(float*)&i;
x = x * (1.5f - halfx * x * x); // 一次牛顿迭代
return x;
}

3.4 Mahony 四元数姿态融合(核心函数)#

void Mahony_AHRS_Update(GYRO_VAR *imu, float dt) {
float norm;
float vx, vy, vz;
float ex, ey, ez;
float q0q0 = q0 * q0;
// 1. 加速度归一化
norm = InvSqrt(imu->acc.x * imu->acc.x +
imu->acc.y * imu->acc.y +
imu->acc.z * imu->acc.z);
float ax = imu->acc.x * norm;
float ay = imu->acc.y * norm;
float az = imu->acc.z * norm;
// 2. 四元数计算的重力分量(机体坐标系下)
vx = 2.0f * (q1 * q3 - q0 * q2);
vy = 2.0f * (q0 * q1 + q2 * q3);
vz = q0q0 - q1 * q1 - q2 * q2 + q3 * q3;
// 3. 误差 = 测量重力 × 预测重力(叉积)
ex = (ay * vz - az * vy);
ey = (az * vx - ax * vz);
ez = (ax * vy - ay * vx);
// 4. PI 控制器积分
exInt += ex * Ki * dt;
eyInt += ey * Ki * dt;
ezInt += ez * Ki * dt;
// 5. 修正角速度
imu->gyro.x += Kp * ex + exInt;
imu->gyro.y += Kp * ey + eyInt;
imu->gyro.z += Kp * ez + ezInt;
// 6. 四元数一阶积分(Runge-Kutta 简化)
float q0_last = q0, q1_last = q1, q2_last = q2, q3_last = q3;
q0 += (-q1_last * imu->gyro.x - q2_last * imu->gyro.y - q3_last * imu->gyro.z) * dt * 0.5f;
q1 += ( q0_last * imu->gyro.x + q2_last * imu->gyro.z - q3_last * imu->gyro.y) * dt * 0.5f;
q2 += ( q0_last * imu->gyro.y - q1_last * imu->gyro.z + q3_last * imu->gyro.x) * dt * 0.5f;
q3 += ( q0_last * imu->gyro.z + q1_last * imu->gyro.y - q2_last * imu->gyro.x) * dt * 0.5f;
// 7. 四元数归一化
norm = InvSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
q0 *= norm; q1 *= norm; q2 *= norm; q3 *= norm;
// 8. 转换为欧拉角(单位:°)
imu->euler.pitch = asin(2.0f * (q0 * q2 - q3 * q1)) * 57.29578f;
imu->euler.roll = atan2(2.0f * (q0 * q1 + q2 * q3), 1.0f - 2.0f * (q1 * q1 + q2 * q2)) * 57.29578f;
imu->euler.yaw = atan2(2.0f * (q1 * q3 + q0 * q2), 1.0f - 2.0f * (q2 * q2 + q3 * q3)) * 57.29578f;
}

4. 使用示例(主循环 / 中断)#

void loop() {
static uint32_t lastTime = 0;
uint32_t now = millis();
float dt = (now - lastTime) * 0.001f;
lastTime = now;
icm20602_get_data(&imu); // 读取 ICM-20602 数据
if (imu.offset_flag == 0) IMU_Offset(&imu);
// 减去零偏
imu.gyro.x -= imu.gyro_offset.x;
imu.gyro.y -= imu.gyro_offset.y;
imu.gyro.z -= imu.gyro_offset.z;
Mahony_AHRS_Update(&imu, dt);
// 输出调试
Serial.printf("Pitch:%.2f Roll:%.2f Yaw:%.2f\n",
imu.euler.pitch, imu.euler.roll, imu.euler.yaw);
}

5. 调试经验与注意事项#

  1. 采样频率:强烈建议在定时器中断中以 200~500Hz 固定频率调用更新函数,保证 dt 恒定。
  2. 参数调优Kp 影响动态响应(0.52.0),Ki 影响静态漂移抑制(0.00050.005),从零开始慢慢增大。
  3. 加速度限幅:剧烈震动时可临时降低加速度权重,或增加低通滤波。
  4. 安装方向:确保传感器坐标系与机体坐标系一致,否则 Roll/Pitch 会出现正负颠倒。
  5. Yaw 漂移:纯 6 轴无法完全消除 Yaw 漂移,建议后续加入磁力计(HMC5883L / QMC5883L)进行九轴融合。

6. 总结#

本方案在 STM32F1/F4、K60 等平台上均已验证通过,静态精度可达 ±0.5°,动态响应快速平滑,是性价比极高的 IMU 姿态解算实现。核心优势在于 Mahony 算法计算量小、易于单片机实时运行。

高精度 IMU 姿态解算:基于 ICM-20602 的四元数 Mahony 滤波实现
https://hw.rscclub.website/posts/icm20602/
作者
杨月昌
发布于
2017-01-23
许可协议
CC BY-NC-SA 4.0