MEMS 传感器选型指南:加速度计/陀螺仪对比

做嵌入式开发,传感器选型是个绕不开的坎。尤其是 MEMS 传感器——加速度计、陀螺仪、IMU,型号一大堆,价格从几块到几百块不等,新手很容易踩坑。

今天就来聊聊 MEMS 传感器到底怎么选,顺便对比几款热门型号,帮你少走弯路。

MEMS 传感器到底是什么?

MEMS(Micro-Electro-Mechanical Systems)就是微型机电系统。简单说,就是把机械结构(比如悬臂梁、质量块)和电路集成在一块芯片上。

常见的 MEMS 传感器有三类:

  • 加速度计:测量线性加速度,能感知倾斜、振动、冲击
  • 陀螺仪:测量角速度,能感知旋转、转向
  • IMU(惯性测量单元):加速度计 + 陀螺仪的组合,有些还带磁力计

选型第一步:搞清楚你需要测什么。

  • 要做计步器、倾斜检测?→ 加速度计就够了
  • 要做手势识别、姿态控制?→ 需要陀螺仪
  • 要做无人机、平衡车、VR 设备?→ 直接上 IMU

热门型号对比

市面上常见的 MEMS 传感器型号不少,我挑了 5 款常用的来对比:

型号 类型 加速度计量程 陀螺仪量程 接口 价格 适用场景
MPU6050 IMU ±2/4/8/16g ±250/500/1000/2000°/s I2C ¥8-15 入门首选,平衡车、无人机
ICM20948 IMU ±2/4/8/16g ±250/500/1000/2000°/s I2C/SPI ¥25-40 高精度,VR/AR、手势识别
BMI088 IMU ±3/6/12/24g ±125/250/500/1000/2000°/s I2C/SPI ¥30-50 工业级,机器人、振动分析
ADXL345 加速度计 ±2/4/8/16g I2C/SPI ¥10-20 纯加速度测量,倾斜检测
L3GD20H 陀螺仪 ±245/500/2000°/s I2C/SPI ¥12-25 纯角速度测量,转向检测

选型建议:

  • 入门学习:MPU6050,便宜、资料多、库丰富
  • 高精度需求:ICM20948,噪声低、温漂小
  • 工业应用:BMI088,抗冲击、宽温范围
  • 成本敏感:ADXL345 或 L3GD20H,单功能够用就行

硬件连接示例

以 MPU6050 为例,接线非常简单:

MPU6050 ESP32 说明
VCC 3.3V 电源(部分模块支持 5V)
GND GND
SCL GPIO21 I2C 时钟
SDA GPIO22 I2C 数据
INT GPIO15 中断(可选)
ADO GND I2C 地址选择(0x68 或 0x69)

注意:MPU6050 是 3.3V 器件,如果用 5V 单片机(如 Arduino Uno),需要电平转换。

代码实战:读取传感器数据

下面用 ESP32 + MPU6050 演示如何读取加速度和陀螺仪数据。

1. 安装库

# PlatformIO
pio lib install "MPU6050 by Electronic Cats"

# Arduino IDE
# 库管理器搜索 "MPU6050" 安装

2. 基础读取代码

#include 
#include 

MPU6050 mpu;

void setup() {
  Serial.begin(115200);
  Wire.begin();

  // 初始化 MPU6050
  if (!mpu.begin()) {
    Serial.println("MPU6050 初始化失败,检查接线!");
    while (1);
  }

  // 配置量程
  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);

  Serial.println("MPU6050 初始化成功!");
}

void loop() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  // 打印加速度(单位:m/s²)
  Serial.print("加速度 X: "); Serial.print(a.acceleration.x);
  Serial.print(" Y: "); Serial.print(a.acceleration.y);
  Serial.print(" Z: "); Serial.println(a.acceleration.z);

  // 打印角速度(单位:rad/s)
  Serial.print("角速度 X: "); Serial.print(g.gyro.x);
  Serial.print(" Y: "); Serial.print(g.gyro.y);
  Serial.print(" Z: "); Serial.println(g.gyro.z);

  delay(100);
}

3. 计算倾斜角度

加速度计可以计算静态倾斜角:

float getPitch() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  // pitch = atan2(-accX, sqrt(accY² + accZ²))
  float pitch = atan2(-a.acceleration.x, 
                      sqrt(a.acceleration.y * a.acceleration.y + 
                           a.acceleration.z * a.acceleration.z));
  return pitch * 180 / PI;  // 转换为角度
}

float getRoll() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  // roll = atan2(accY, accZ)
  float roll = atan2(a.acceleration.y, a.acceleration.z);
  return roll * 180 / PI;
}

注意:加速度计计算的倾斜角在动态场景下不准确(因为有运动加速度干扰),这时候需要融合陀螺仪数据,用卡尔曼滤波或互补滤波。

常见问题排查

问题 1:读取数据全为 0

可能原因:

  • 接线错误(SCL/SDA 接反)
  • I2C 地址不对(MPU6050 默认 0x68,ADO 接 VCC 变为 0x69)
  • 电源电压不足

解决方法:

// 扫描 I2C 设备
void scanI2C() {
  byte count = 0;
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print("找到设备:0x");
      Serial.println(addr, HEX);
      count++;
    }
  }
  if (count == 0) Serial.println("未找到任何 I2C 设备");
}

问题 2:数据噪声大、跳动明显

可能原因:

  • 机械振动干扰
  • 电源纹波大
  • 滤波器带宽设置过高

解决方法:

// 降低滤波器带宽(牺牲响应速度换稳定性)
mpu.setFilterBandwidth(MPU6050_BAND_5_HZ);

// 软件滤波:滑动平均
#define SAMPLE_COUNT 10
float readAccelerometerX() {
  float sum = 0;
  for (int i = 0; i < SAMPLE_COUNT; i++) {
    sensors_event_t a, g, temp;
    mpu.getEvent(&a, &g, &temp);
    sum += a.acceleration.x;
    delay(2);
  }
  return sum / SAMPLE_COUNT;
}

问题 3:陀螺仪漂移严重

现象:静止时角速度不归零,积分后角度持续偏移。

原因:陀螺仪存在零偏(bias),需要校准。

解决方法

// 校准零偏(设备静止时运行)
float gyroBiasX = 0, gyroBiasY = 0, gyroBiasZ = 0;
void calibrateGyro() {
  Serial.println("校准中... 请保持设备静止");
  delay(1000);

  for (int i = 0; i < 100; i++) {
    sensors_event_t a, g, temp;
    mpu.getEvent(&a, &g, &temp);
    gyroBiasX += g.gyro.x;
    gyroBiasY += g.gyro.y;
    gyroBiasZ += g.gyro.z;
    delay(5);
  }

  gyroBiasX /= 100;
  gyroBiasY /= 100;
  gyroBiasZ /= 100;

  Serial.print("零偏:X="); Serial.print(gyroBiasX);
  Serial.print(" Y="); Serial.print(gyroBiasY);
  Serial.print(" Z="); Serial.println(gyroBiasZ);
}

// 使用时减去零偏
float getGyroX() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);
  return g.gyro.x - gyroBiasX;
}

进阶:传感器融合

单一传感器有局限:

  • 加速度计:静态准,动态受运动干扰
  • 陀螺仪:动态准,长期积分会漂移

解决方案:用互补滤波或卡尔曼滤波融合两者。

互补滤波简单有效:

float pitch = 0;
void updatePitch(float dt) {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  // 加速度计计算的 pitch
  float accPitch = atan2(-a.acceleration.x, 
                         sqrt(a.acceleration.y * a.acceleration.y + 
                              a.acceleration.z * a.acceleration.z)) * 180 / PI;

  // 陀螺仪积分的 pitch
  pitch = pitch + g.gyro.y * dt;

  // 互补滤波:98% 信任陀螺仪,2% 信任加速度计
  pitch = 0.98 * pitch + 0.02 * accPitch;
}

选型总结

最后给个快速选型表:

需求 推荐型号 理由
入门学习、低成本 MPU6050 便宜、资料多、够用
高精度姿态解算 ICM20948 低噪声、9 轴(带磁力计)
工业振动监测 BMI088 高量程、抗冲击、宽温
纯倾斜检测 ADXL345 单功能、低功耗
纯旋转检测 L3GD20H 单功能、性价比高

采购建议

  • 淘宝/1688 买模块(带稳压和电平转换),比裸芯片方便
  • 注意区分「 breakout 板」和「开发板」,前者只是传感器 + 少量外围
  • 批量采购可以找代理商拿芯片,成本能降 30-50%

希望这篇博客文章对您有所帮助!