MPU6050解算(上)

MPU6050 姿态解算学习笔记

本笔记面向零基础读者,从物理直觉出发,逐步理解 MPU6050 的姿态解算原理。


第一章:基础概念

1.1 什么是姿态?

姿态描述的是物体在三维空间中的朝向。我们用三个角度来描述它,最直观的类比是飞机

角度 英文 飞机动作 生活感受
横滚角 Roll 飞机左右倾斜,像在做桶滚 摩托车过弯时身体倾斜
俯仰角 Pitch 飞机抬头或低头 过山车爬坡或俯冲
偏航角 Yaw 飞机左转或右转(机头指向变化) 汽车转弯时方向盘转动
         抬头 (+Pitch)
              ↑
              |
   左转 ←----[ 飞机 ]----→ 右转
  (+Yaw)      |           (-Yaw)
              ↓
         低头 (-Pitch)

        左倾 (←) Roll (+)  右倾 (→) Roll (-)

1.2 MPU6050 能测什么?

MPU6050 是一颗 6 轴传感器,内部集成了两种传感器:

加速度计(Accelerometer)—— 3 轴

测量线性加速度,包括重力加速度。

输出 含义 单位
ax X 轴方向的加速度 g(重力加速度,1g ≈ 9.8 m/s²)
ay Y 轴方向的加速度 g
az Z 轴方向的加速度 g

静止平放时:ax ≈ 0, ay ≈ 0, az ≈ 1g(重力全部落在 Z 轴)

陀螺仪(Gyroscope)—— 3 轴

测量角速度,即旋转的快慢。

输出 含义 单位
gx 绕 X 轴旋转的角速度 °/s(度每秒)
gy 绕 Y 轴旋转的角速度 °/s
gz 绕 Z 轴旋转的角速度 °/s

静止时:gx ≈ 0, gy ≈ 0, gz ≈ 0(没有旋转)

原始值与物理值

传感器输出的是 16 位原始值(-32768 ~ 32767),需要根据量程换算为物理值:

物理值 = 原始值 / 灵敏度
传感器 量程示例 灵敏度
加速度计 ±2g 16384 LSB/g
加速度计 ±16g 2048 LSB/g
陀螺仪 ±250°/s 131 LSB/(°/s)
陀螺仪 ±2000°/s 16.4 LSB/(°/s)

通信方式

MPU6050 通过 I2C 与 MCU 通信:

  • 默认地址:0x68(AD0 接地)或 0x69(AD0 接高)
  • 数据寄存器从 0x3B 开始,连续 14 字节包含全部传感器数据

1.3 坐标系约定

理解坐标系是正确解算姿态的前提。MPU6050 使用右手坐标系

右手定则

伸出右手,拇指、食指、中指互相垂直:

  • 拇指 → X 轴正方向
  • 食指 → Y 轴正方向
  • 中指 → Z 轴正方向

MPU6050 芯片坐标系

以芯片正面朝上、标识文字正向为参考:

        (芯片顶视图)

          +Y
           ↑
           |
           |
    +X ←---●---→ -X
           |
           |
           ↓
          -Y

    +Z 向上(朝向你)
    -Z 向下(朝向桌面)

    ● = MPU6050 芯片中心

旋转正方向

使用右手螺旋定则:大拇指指向轴的正方向,四指弯曲方向即为该轴旋转的正方向。

旋转 正方向描述
Roll X 轴 从 +X 方向看,逆时针旋转为正
Pitch Y 轴 从 +Y 方向看,逆时针旋转为正
Yaw Z 轴 从 +Z 方向看(俯视),逆时针旋转为正

第二章:加速度计解算

2.1 目标

利用加速度计输出的 ax, ay, az 三个值,计算出传感器的 Roll(横滚角)Pitch(俯仰角)


2.2 常见误区:加速度计测的是"运动"吗?

初学者看到"加速度计"这个名字,很容易产生一个误解:

“加速度计测的是物体运动的加速度,静止时应该没有读数。”

但实际上,当你把 MPU6050 静止平放在桌上时,读数是:

  • ax ≈ 0, ay ≈ 0, az ≈ 1g

明明没动,为什么 Z 轴有读数?

这说明加速度计测的不只是运动,它还能感知重力。要理解这一点,我们需要换一个角度看待加速度计。


2.3 物理模型:盒子与小球

不要把加速度计看作一个复杂的电子芯片,请把它想象成一个物理机械装置:

  • 装置:一个封闭的小盒子(传感器本身)。
  • 核心:盒子中间悬浮着一个有质量的小球(质量块)。
  • 测量原理
    • 盒子内壁有压力感应。
    • 小球压在哪个方向的墙壁上,那个轴就有读数。
    • 读数的大小 = 小球压在墙壁上的力的大小。

现在再想想"静止平放"的情况:

  • 盒子静止,小球受重力作用,死死压在盒底
  • 盒底就是 Z 轴方向 → 所以 az = 1g

核心认知:加速度计本质上是一个测力计,它测的是小球对墙壁的压力。


2.4 静态解算:利用重力算角度

当我们想计算姿态(欧拉角)时,我们利用的是地球重力(g)

前提:物体处于静止匀速直线运动状态。

现象

  • 平放时:重力垂直向下,小球死死压在盒底(Z轴)
    • 读数:Z = 1g, X = 0, Y = 0 → 角度 = 0°
  • 翻滚(Roll)时:我们将盒子转动,重力的方向相对于盒子变了,小球滚向了侧壁(Y轴)
    • 读数:Y 轴读数变大,Z 轴读数变小。
  • 解算逻辑
    • 传感器检测到:“现在重力分量在 Y 轴上有 0.7g,在 Z 轴上有 0.7g。”
    • 结论:“既然重力分配变了,那盒子肯定是歪了 45 度。”

本质:加速度计解算角度,就是测量重力在各个轴上的投影,然后反推倾斜角度。

解算公式

Roll  = atan2(ay, az)
Pitch = atan2(-ax, sqrt(ay² + az²))

代码实现

void mpu6050_calc_attitude_accel(mpu6050_t *data)
{
    data->roll  = atan2f(data->ay, data->az) * RAD_TO_DEG;
    data->pitch = atan2f(-data->ax, sqrtf(data->ay * data->ay + data->az * data->az)) * RAD_TO_DEG;
}

2.5 现实挑战:加速度计是怎么"被骗"的?

这是理解加速度计局限性的最关键一步。

我们通常认为加速度是描述"运动快慢"的,但在传感器内部,"运动"和"重力"表现得一模一样

场景对比

A. 真的转动了(Tilt)

  • 动作:把盒子向后仰 90 度(竖起来)。
  • 物理过程:重力拉着小球,把它压在后壁上。
  • 传感器视角:检测到后壁受压。
  • 解算结果90 度(正确)

实测数据:缓慢倾斜传感器,Roll/Pitch 平稳变化,与实际角度一致。

B. 猛地向前加速(Acceleration)

  • 动作:盒子保持水平(0 度),猛踩油门向前冲(平移)。
  • 物理过程:由于惯性,小球不愿意动,它被甩向了后壁
  • 传感器视角:检测到后壁受压。
  • 解算结果90 度(错误!明明是平移,却算出了角度)

实测数据:突然晃动传感器,角度数据剧烈跳变,完全不可信。


2.6 小结

  1. 加速度计其实是"测力计":它测量的不是纯粹的运动,而是合力(重力 + 惯性力)。
  2. 解算的前提假设
    • 我们假设物体是静止的(忽略惯性力)。
    • 一旦物体产生平移变速运动,惯性力就会混入,破坏这个假设。
    • 传感器无法区分:到底是"歪了"还是"加速了"。
  3. 实际表现
    • 静止时,角度非常准。
    • 一晃动,角度数据就会剧烈抖动。
优势 局限
静止时精准 动态时抖动
无累积漂移 无法测量 Yaw
算法简单 对振动敏感

第三章:一阶互补滤波

3.1 为什么不能只靠加速度计?

正如第二章所述,加速度计在动态下会被骗。

  • 例子:假设你正在做一个平衡小车,电机突然启动。
  • 加速度计:“惯性力把小球甩到后壁了!我认为车子倒了 45 度!”(其实车子还是直的,只是在加速)
  • 后果:如果只听加速度计的,控制器会因为错误的判断而做出错误的补偿。

3.2 陀螺仪:弥补加速度计的"冲动"

陀螺仪测的是角速度(°/s)。它不关心重力,也不关心惯性,它只关心:“我现在转得有多快?”

物理直觉:盲人的步伐

想象你闭着眼睛走在一段楼梯上:

  1. 加速度计(触觉定位):就像你每走一步都用手摸一下台阶(测重力方向)。虽然能确定你在哪,但如果有人推你一下,你的手可能摸错位置(振动干扰)。
  2. 陀螺仪(空间感觉):就像你内耳的平衡觉。即使闭上眼,你也能感觉到"我刚才向左转了 30 度"。

陀螺仪的计算依据:积分

$$角度_{当前} = 角度_{上一时刻} + 角速度 \times dt$$

如果传感器原本在 0°,陀螺仪测到当前正以 10°/s 的速度旋转,过了 0.01 秒,陀螺仪会告诉你:“我现在在 0.1° 的位置”。

陀螺仪的优缺点

优点 缺点
不受平移加速度干扰 零点漂移(积分误差累积)
短期内平滑精准 长期运行会"跑偏"
响应速度快 需要准确的 dt

3.3 互补滤波原理

现在我们把两者的特性放在一起看:

传感器 长期表现 短期(动态)表现 弱点
加速度计 (重力永远向下) (怕振动和加速) 抖动严重
陀螺仪 (累积漂移) (响应快且平滑) 随时间跑偏

核心思想:用陀螺仪提供短期精度,用加速度计提供长期参考。

公式

angle = α * (angle + gyro * dt) + (1 - α) * accel_angle
  • 左边(α = 0.98):98% 信任陀螺仪的"空间感觉"。它说转了 0.1°,我们就加上 0.1°。保证数据平滑,不会因为振动而乱跳。
  • 右边(1-α = 0.02):2% 信任加速度计。虽然它容易受干扰,但它指的方向(重力)长期来看永远是对的。这 2% 的权重像一只微弱的手,不停地把陀螺仪跑偏的角度往重力方向"拽"回来。

3.4 代码实现

#define CF_ALPHA  0.98f

void mpu6050_calc_attitude_cf(mpu6050_t *data, float dt)
{
    float accel_roll, accel_pitch;

    /* 加速度计角度(作为长期参考) */
    accel_roll  = atan2f(data->ay, data->az) * RAD_TO_DEG;
    accel_pitch = atan2f(-data->ax, sqrtf(data->ay * data->ay + data->az * data->az)) * RAD_TO_DEG;

    /* 互补滤波 */
    data->roll  = CF_ALPHA * (data->roll + data->gx * dt) + (1 - CF_ALPHA) * accel_roll;
    data->pitch = CF_ALPHA * (data->pitch + data->gy * dt) + (1 - CF_ALPHA) * accel_pitch;
}

调用时传入采样周期:

mpu6050_calc_attitude_cf(&mpu_data, 0.01f);  // dt = 10ms

3.5 局限性

一阶互补滤波虽然简单有效,但存在以下局限:

欧拉角的固有缺陷

问题 说明
万向节死锁 当 Pitch = ±90° 时,Roll 和 Yaw 轴重合,丢失一个自由度
Pitch ≈ 90° 时数值奇异 Roll = atan2(ay, az),此时 az ≈ 0,分母趋近于零,ay 微小变化导致 Roll 剧烈跳变(如下图)

算法本身的局限

问题 说明
α 值固定 无法根据运动状态自适应调整权重
仍无法解算 Yaw 加速度计无法感知绕 Z 轴旋转
自由落体失效 ax = ay = az ≈ 0 时,加速度计无参考
振动环境 持续振动会污染加速度计的长期均值

解决方向

要彻底解决这些问题,需要:

  • 四元数:避免万向节死锁和奇异点
  • Mahony / Madgwick 算法:更优雅的融合方式
  • 磁力计:解算 Yaw

3.6 小结

角色 传感器 职责
主力军 陀螺仪 提供平滑、实时的角度变化
教官 加速度计 长期纠正陀螺仪的漂移

一阶互补滤波是性价比最高的入门方案:

  • 相比纯加速度计:动态不再抖动
  • 相比纯陀螺仪:长期不再漂移
  • 代码简单,资源占用低

但对于全姿态、高精度场景,需要进阶到四元数方案。