做嵌入式开发,传感器选型是个绕不开的坎。尤其是 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%
希望这篇博客文章对您有所帮助!