IMU 原理:加速度计与陀螺仪

运动传感系列开篇。传感器是嵌入式系统感知物理世界的窗口,IMU(Inertial Measurement Unit)是最常用的一类。这篇文章不讲高深理论,只讲 MEMS 传感器怎么工作、怎么接线、怎么读数、读出来的数据长什么样。

IMU 坐标系

下图定义了 IMU 的三轴方向,后续所有公式和讨论都基于此坐标系:

mermaid
flowchart TD
    subgraph 设备坐标系
        X["X 轴 → 右倾/翻滚 Roll"]
        Y["Y 轴 → 前倾/俯仰 Pitch"]
        Z["Z 轴 ↑ 偏航 Yaw"]
    end

    classDef axis fill:#9C27B0,color:#fff
    class X,Y,Z axis

除了上面这个示意图,还可以看看下面的 3D 旋转坐标系——红绿蓝三色分别对应 Roll/Pitch/Yaw,旋转展示三轴的空间关系:

Y → Pitch
X → Roll
Z → Yaw
X → Roll Y → Pitch Z → Yaw

MEMS 加速度计

加速度计测量的是物体受到的加速度,包含重力分量。MEMS 加速度计内部有一个微小的检测质量块(proof mass),通过硅悬臂梁悬挂在固定电极之间。当芯片整体加速时,质量块因惯性产生微小位移,两侧电容发生变化——一侧增大、一侧减小。通过测量差分电容的变化量,就能推算出加速度。

这里有个容易搞混的点:静止放在桌面上时,加速度计读到的不是 0,而是 1g(约 9.8 m/s²)指向地心。因为重力对质量块产生的效果和加速度完全等价——这就是等效原理。所以加速度计可以用来计算设备的倾角,但前提是没有线加速度干扰。

倾角计算

加速度计测量重力在三个轴上的分量,通过三角函数可以反推出设备的倾角:

$\theta = \text{atan2}(a_x, a_z)$

mermaid
flowchart TD
    A["设备水平放置<br/>θ=0°"] -->|"az=1g, ax=ay=0"| B["设备倾斜 θ°<br/>az=cos(θ)g<br/>ax=sin(θ)g"]
    B --> C["atan2(ax, az)<br/>→ 倾角 θ"]

    classDef state fill:#2196F3,color:#fff
    classDef calc fill:#4CAF50,color:#fff
    class A,B state
    class C calc

参数说明:

  • ax: X 轴加速度读数(g)
  • az: Z 轴加速度读数(g)
  • atan2: 反正切函数,自动处理象限(比 atan 更安全)

数值例子: 设备倾斜 45° → ax=0.707g, az=0.707g → atan2(0.707, 0.707) = 45°

下面这个动图直观展示了设备从水平倾斜到 60° 的过程中,ax、az 和角度 θ 的变化:

↑ Z
θ = 0.0 °
ax = 0.000 g
az = 1.000 g
θ = atan2(ax, az)

⚠️ 注意:只有静止时才准确!有运动加速度时会污染测量。

输出格式

加速度计输出 X/Y/Z 三轴原始值,单位通常是 gm/s²。数据手册会给出每个量程对应的灵敏度( Sensitivity),单位是 LSB/g。

量程灵敏度
±2g16384 LSB/g
±4g8192 LSB/g
±8g4096 LSB/g
±16g2048 LSB/g

灵敏度转换

原始 ADC 读数转物理单位的公式:

$$a_g = \frac{\text{raw}}{\text{LSB_per_g}}$$

参数说明:

  • raw: ADC 原始读数(int16,范围 -32768~32767)
  • LSB_per_g: 灵敏度,±2g 量程下 = 16384 LSB/g

数值例子: raw=8192 → a_g = 8192 / 16384 = 0.5g

💡 温度变化时零偏会漂移,建议上电后静止 1 秒采集 1000 个样本做零偏校准。

关键参数

  • 量程(Range):可测量的最大加速度范围。选型取决于应用场景——手持设备 ±2g 足够,无人机或机器人可能需要 ±8g 以上。
  • 灵敏度(Sensitivity):数字输出每 g 对应的 LSB 数。灵敏度越高,分辨率越好。
  • 噪声密度(Noise Density):单位是 µg/√Hz。决定了你能分辨的最小加速度变化。
  • 零偏(Offset/Zero-g Bias):静止 0g 输入时的输出值。每颗芯片都不同,通常可以在上电后校准消除。

MEMS 陀螺仪

陀螺仪测量的是角速度,即物体绕某个轴旋转的快慢。MEMS 陀螺仪的工作原理比加速度计复杂一点儿:内部有一个持续振动的质量块(drive mode),当芯片绕敏感轴旋转时,哥里奥利力(Coriolis force)会将振动能量耦合到垂直于振动方向的检测方向(sense mode),产生位移,同样通过电容变化测量。

哥里奥利力的大小正比于角速度,所以测到的电容变化量直接反映了旋转速度。

输出格式

三轴角速度,单位 °/s(度每秒)或 rad/s。陀螺仪也按量程分档:

量程灵敏度
±250 °/s131 LSB/(°/s)
±500 °/s65.5 LSB/(°/s)
±1000 °/s32.8 LSB/(°/s)
±2000 °/s16.4 LSB/(°/s)

关键参数

  • 量程:能测量的最大角速度。人手持设备 ±250 °/s 够用,但快速旋转的物体需要更大量程。
  • 灵敏度:每 °/s 对应的 LSB 数。
  • 零偏稳定性(Bias Stability):陀螺仪静止时输出的稳定性,单位 °/h(度每小时)或 °/s。这是衡量陀螺仪品质的核心指标——消费级的在 5-20 °/h 左右,工业级可以做到 1 °/h 以下。
  • 温漂(Temperature Drift)陀螺仪零偏随温度变化非常显著,这是实际项目里最头疼的问题之一。即使芯片静止,温度变了输出也跟着变。解决办法是温漂补偿:在电路板上靠近传感器的位置放温度传感器,建立零偏-温度曲线。

常见传感器型号

市面上常见的消费级 IMU 芯片:

型号轴数接口特点
MPU6050六轴(三轴加速度 + 三轴陀螺仪)I2C/SPI最经典,资料最多,DMP 内置融合算法
MPU9250九轴(六轴 + 磁力计 AK8963)I2C/SPIMPU6050 升级版,多加一个磁力计
ICM-20948九轴I2C/SPIMPU9250 的继任者,更低功耗
BMI160六轴I2C/SPIBosch 出品,功耗极低,适合电池设备
LSM6DS3六轴I2C/SPIST 产品,带有限状态机,适合简单动作识别

接口方面,I2C 接线最少(SDA + SCL),但速度有限,适合低频读取。SPI 更快,适合需要高输出速率的场景。MPU6050 的 I2C 默认地址是 0x68,如果 AD0 引脚拉高则变为 0x69

原始数据读取

下面是用 I2C 读取 MPU6050 加速度和陀螺仪原始值的代码片段。MPU6050 的寄存器是按顺序排列的——加速度 X 高字节从 0x3B 开始,连续读 14 个字节就能拿到加速度(6B)+ 温度(2B)+ 陀螺仪(6B)全部数据。

c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// I2C 读取 MPU6050 加速度和陀螺仪原始值
#define MPU6050_ADDR  0x68
#define ACCEL_XOUT_H  0x3B
#define GYRO_XOUT_H   0x43

int16_t ax, ay, az, gx, gy, gz;

// 读取 14 字节(加速度6 + 温度2 + 陀螺仪6)
uint8_t buf[14];
i2c_read(MPU6050_ADDR, ACCEL_XOUT_H, buf, 14);

ax = (buf[0] << 8) | buf[1];
ay = (buf[2] << 8) | buf[3];
az = (buf[4] << 8) | buf[5];
// buf[6], buf[7] 是温度
gx = (buf[8] << 8) | buf[9];
gy = (buf[10] << 8) | buf[11];
gz = (buf[12] << 8) | buf[13];

// 转换到物理单位(以 ±2g 和 ±250°/s 为例)
float ax_g = ax / 16384.0f;  // LSB/g
float gx_dps = gx / 131.0f;  // LSB/(°/s)

读取到的原始值是有符号 16 位整数,范围取决于量程设置。要转成物理单位,除以对应量程的灵敏度系数即可。

原始数据的局限

拿到原始数据之后,千万别觉得可以直接用了。加速度计和陀螺仪各有各的毛病:

加速度计对振动敏感。走路、电机转动、甚至敲击桌面都会在读数上叠加很大的噪声。如果直接用加速度计数据算角度,得到的是一堆毛刺——必须过一遍低通滤波。但滤波又会引入延迟,这是一个需要权衡的地方。

陀螺仪有零偏和漂移。即使静止不动,陀螺仪输出也不完全是 0,总有一个小偏置。更麻烦的是,这个偏置会随时间缓慢变化(零偏不稳定性)和随温度变化(温漂)。对角速度积分得到角度时,零偏会不断累加——静止放一分钟,角度可能已经飘了好几度。

积分漂移问题

mermaid
flowchart TD
    A["陀螺仪原始角速度<br/>ω(t)"] --> B["积分<br/>θ = ∫ω dt"]
    B --> C["角度输出"]
    A -.->|"零偏误差 Δω"| D["积分后<br/>Δθ = Δω × t"]
    D --> E["t=60s, Δω=0.01°/s<br/>→ Δθ=0.6° 漂移"]
    E --> F["需要传感器融合修正<br/>(下篇展开)"]

    classDef proc fill:#2196F3,color:#fff
    classDef problem fill:#f44336,color:#fff
    classDef solution fill:#4CAF50,color:#fff
    class A,B,C proc
    class D,E problem
    class F solution

下面的可视化演示了零偏累积的过程——静止 1 分钟,0.01 °/s 的微小零偏就能积分出 0.6° 的漂移:

积分漂移累积 陀螺仪零偏 Δω = 0.01 °/s
0.6°
0.00 °
经时 0 s
漂移 0.00 °
静止 1 分钟,陀螺仪积分漂移可达 0.6°

正因为这两个传感器各有短板,实际项目里几乎不用单一传感器推算姿态。把加速度计的低频可靠性和陀螺仪的高频响应结合起来,就是传感器融合要做的事——后面单独开一篇展开。