MPU6050 加速度 + 陀螺仪传感器完整教程:从接线到姿态解算

一、前言

MPU6050 是一款集成三轴加速度计、三轴陀螺仪的 6 轴运动传感器,凭借低成本、小体积、高集成度,成为物联网、机器人、穿戴设备开发的首选。它支持 I2C 通信,可输出高精度运动数据,不仅能检测加速度、角速度,还能通过姿态解算得到设备的俯仰角、滚转角,适用于体感控制、姿态监测、计步器等场景。

本文基于 Arduino 平台,从硬件基础、接线方法、库函数使用、原生寄存器驱动到姿态解算,全方位讲解 MPU6050 的使用,兼顾新手入门和进阶需求。

二、MPU6050 核心参数与硬件解析

1. 关键参数

特性 规格参数
加速度计范围 ±2G/±4G/±8G/±16G(可配置)
陀螺仪范围 ±250°/s/±500°/s/±1000°/s/±2000°/s(可配置)
输出数据率 4Hz~1kHz
供电电压 3.3V(绝对最大值 3.9V)
通信协议 I2C(默认地址 0x68/0x69)
工作温度 -40℃~85℃
内置传感器 加速度计(16 位 ADC)、陀螺仪(16 位 ADC)、温度传感器

2. 引脚定义(传感器模块)

引脚标识 功能说明 注意事项
VCC 电源输入 仅支持 3.3V,接 5V 直接烧毁
GND 接地 必须与主控板共地,否则信号干扰
SDA I2C 数据引脚 接主控板 SDA 引脚(Arduino A4)
SCL I2C 时钟引脚 接主控板 SCL 引脚(Arduino A5)
AD0 地址选择引脚 接地 = 0x68(默认),接 VCC=0x69
INT 中断输出引脚(可选) 数据就绪时输出高电平,可用于中断触发

三、硬件准备与接线方法

1. 必备组件

  • 主控板:Arduino UNO/Nano(或 ESP32、STM32)

  • MPU6050 模块(带电压转换的模块更稳定)

  • 杜邦线(公对母):4-6 根

  • 面包板(可选):方便接线测试

  • 5V 电源(可选):若需独立供电,需确保 3.3V 输出稳定

2. 接线表(Arduino UNO 为例)

MPU6050 引脚 Arduino 引脚 接线说明
VCC 3.3V 严禁接 5V!模块无 LDO 时必烧
GND GND 共地连接,减少数据噪声
SDA A4 I2C 数据线,Arduino 默认引脚
SCL A5 I2C 时钟线,Arduino 默认引脚
AD0 GND 选择默认地址 0x68,多传感器时接 VCC
INT 不接 / 任意数字引脚 不用中断功能可悬空

接线技巧:若使用 ESP32,SDA=GPIO21,SCL=GPIO22;STM32 需根据型号确认 I2C 引脚(如 STM32F103c8t6:SDA=PB7,SCL=PB6)。

四、驱动代码实现(3 种方案,从易到难)

方案 1:Adafruit 库快速实现(新手首选)

步骤 1:安装依赖库

打开 Arduino IDE → 项目 → 加载库 → 管理库:

  • 搜索「Adafruit MPU6050」安装(核心库)

  • 搜索「Adafruit Unified Sensor」安装(依赖库)

步骤 2:完整代码(读取加速度、陀螺仪、温度)

\#include ruit\_MPU6050.h>

\#include \<Adafruit\_Sensor.h>

\#include >

Adafruit\_MPU6050 mpu;  // 实例化传感器对象

void setup() {

&#x20; Serial.begin(115200);  // 串口波特率115200(比9600更流畅)

&#x20; while (!Serial) delay(10);  // 等待串口连接(USB模式)

&#x20; // 初始化MPU6050

&#x20; if (!mpu.begin()) {

&#x20;   Serial.println("找不到MPU6050传感器!检查:");

&#x20;   Serial.println("1. 接线是否正确(VCC必须3.3V)");

&#x20;   Serial.println("2. 地址是否为0x68(AD0接地)");

&#x20;   while (1) {

&#x20;     delay(500);

&#x20;     digitalWrite(LED\_BUILTIN, !digitalRead(LED\_BUILTIN));  // 指示灯闪烁报警

&#x20;   }

&#x20; }

&#x20; Serial.println("MPU6050初始化成功!");

&#x20; // 配置传感器参数(按需调整)

&#x20; mpu.setAccelerometerRange(MPU6050\_RANGE\_8\_G);  // 加速度范围±8G(灵敏度更高)

&#x20; mpu.setGyroRange(MPU6050\_RANGE\_500\_DEG);       // 陀螺仪范围±500°/s

&#x20; mpu.setFilterBandwidth(MPU6050\_BAND\_44\_HZ);    // 滤波带宽44Hz(减少数据噪声)

&#x20; delay(100);  // 传感器稳定时间

}

void loop() {

&#x20; sensors\_event\_t a, g, temp;  // 存储加速度、陀螺仪、温度数据

&#x20; mpu.getEvent(\&a, \&g, \&temp);  // 读取所有传感器数据

&#x20; // 打印加速度数据(单位:m/s²)

&#x20; Serial.print("加速度 \[m/s²]:");

&#x20; Serial.print("X: "); Serial.print(a.acceleration.x, 2);  // 保留2位小数

&#x20; Serial.print(", Y: "); Serial.print(a.acceleration.y, 2);

&#x20; Serial.print(", Z: "); Serial.print(a.acceleration.z, 2);

&#x20; // 打印陀螺仪数据(单位:rad/s,转角度需×(180/PI))

&#x20; Serial.print(" | 陀螺仪 \[rad/s]:");

&#x20; Serial.print("X: "); Serial.print(g.gyro.x, 2);

&#x20; Serial.print(", Y: "); Serial.print(g.gyro.y, 2);

&#x20; Serial.print(", Z: "); Serial.print(g.gyro.z, 2);

&#x20; // 打印内置温度(单位:℃)

&#x20; Serial.print(" | 温度:"); Serial.print(temp.temperature, 1); Serial.println("℃");

&#x20; delay(200);  // 控制数据输出频率(5Hz)

}

步骤 3:测试与验证

  • 上传代码后打开串口监视器(波特率 115200);

  • 晃动传感器,观察加速度 / 陀螺仪数值变化;

  • 静止时 Z 轴加速度约 9.81m/s²(重力加速度),陀螺仪数值接近 0。

方案 2:原生寄存器驱动(理解底层原理)

无需第三方库,直接操作 MPU6050 寄存器,适合深入学习 I2C 通信和传感器底层逻辑。

核心代码(读取原始数据)

\#include >

\#define MPU6050\_ADDR 0x68  // 传感器地址

\#define PWR\_MGMT\_1 0x6B    // 电源管理寄存器

\#define ACCEL\_XOUT\_H 0x3B  // 加速度X轴高位寄存器

\#define GYRO\_XOUT\_H 0x43   // 陀螺仪X轴高位寄存器

// 存储传感器数据

int16\_t ax, ay, az;  // 加速度原始值

int16\_t gx, gy, gz;  // 陀螺仪原始值

float temp;          // 温度

// 初始化MPU6050

void mpu6050\_init() {

&#x20; Wire.begin();

&#x20; Wire.beginTransmission(MPU6050\_ADDR);

&#x20; Wire.write(PWR\_MGMT\_1);

&#x20; Wire.write(0x00);  // 唤醒传感器(默认睡眠模式)

&#x20; Wire.endTransmission();

&#x20; // 配置加速度范围±8G(0x10对应±8G)

&#x20; Wire.beginTransmission(MPU6050\_ADDR);

&#x20; Wire.write(0x1C);  // 加速度配置寄存器

&#x20; Wire.write(0x10);

&#x20; Wire.endTransmission();

&#x20; // 配置陀螺仪范围±500°/s(0x08对应±500°/s)

&#x20; Wire.beginTransmission(MPU6050\_ADDR);

&#x20; Wire.write(0x1B);  // 陀螺仪配置寄存器

&#x20; Wire.write(0x08);

&#x20; Wire.endTransmission();

}

// 读取传感器数据

void mpu6050\_read() {

&#x20; Wire.beginTransmission(MPU6050\_ADDR);

&#x20; Wire.write(ACCEL\_XOUT\_H);  // 从加速度X轴高位寄存器开始读取

&#x20; Wire.endTransmission(false);

&#x20; Wire.requestFrom(MPU6050\_ADDR, 14);  // 连续读取14字节数据

&#x20; // 解析加速度数据(16位,高字节在前)

&#x20; ax = Wire.read() << 8 | Wire.read();

&#x20; ay = Wire.read() <.read();

&#x20; az = Wire.read() < | Wire.read();

&#x20; // 解析温度数据

&#x20; temp = (Wire.read() <.read()) / 340.0 + 36.53;

&#x20; // 解析陀螺仪数据

&#x20; gx = Wire.read() < Wire.read();

&#x20; gy = Wire.read() <8 | Wire.read();

&#x20; gz = Wire.read() <.read();

&#x20; // 转换为实际物理量

&#x20; float ax\_real = ax / 4096.0;  // ±8G时,灵敏度4096 LSB/g

&#x20; float ay\_real = ay / 4096.0;

&#x20; float az\_real = az / 4096.0;

&#x20; float gx\_real = gx / 65.5;    // ±500°/s时,灵敏度65.5 LSB/(°/s)

&#x20; float gy\_real = gy / 65.5;

&#x20; float gz\_real = gz / 65.5;

&#x20; // 打印数据

&#x20; Serial.print("加速度 \[g]:X: "); Serial.print(ax\_real, 2);

&#x20; Serial.print(", Y: "); Serial.print(ay\_real, 2);

&#x20; Serial.print(", Z: "); Serial.print(az\_real, 2);

&#x20; Serial.print(" | 陀螺仪 \[°/s]:X: "); Serial.print(gx\_real, 2);

&#x20; Serial.print(", Y: "); Serial.print(gy\_real, 2);

&#x20; Serial.print(", Z: "); Serial.print(gz\_real, 2);

&#x20; Serial.print(" | 温度:"); Serial.print(temp, 1); Serial.println("℃");

}

void setup() {

&#x20; Serial.begin(115200);

&#x20; mpu6050\_init();

&#x20; Serial.println("MPU6050原生寄存器驱动初始化成功!");

}

void loop() {

&#x20; mpu6050\_read();

&#x20; delay(200);

}

方案 3:姿态解算(卡尔曼滤波求俯仰角 / 滚转角)

MPU6050 的原始数据含噪声,通过卡尔曼滤波融合加速度和陀螺仪数据,可得到稳定的姿态角(俯仰角 Pitch、滚转角 Roll)。

核心代码(添加卡尔曼滤波)

\#include 6050.h>

\#include \_Sensor.h>

\#include afruit\_MPU6050 mpu;

sensors\_event\_t a, g, temp;

// 卡尔曼滤波参数

float Q\_angle = 0.001;    // 角度噪声方差

float Q\_gyro = 0.003;     // 角速度噪声方差

float R\_angle = 0.5;      // 测量噪声方差

float angle = 0.0;        // 滤波后的角度

float bias = 0.0;         // 陀螺仪零偏

float P\[2]\[2] = {{1, 0}, {0, 1}};  // 协方差矩阵

// 卡尔曼滤波更新函数

float kalman\_filter(float angle\_measured, float gyro\_measured, float dt) {

&#x20; // 预测阶段

&#x20; float angle\_pred = angle - bias \* dt;

&#x20; float P\_pred\[2]\[2] = {

&#x20;   {P\[0]\[0] + Q\_angle - P\[0]\[1] \* P\[1]\[0] / (P\[1]\[1] + Q\_gyro), -P\[0]\[1] / (P\[1]\[1] + Q\_gyro)},

&#x20;   {-P\[1]\[0] / (P\[1]\[1] + Q\_gyro), P\[1]\[1] + Q\_gyro}

&#x20; };

&#x20; // 更新阶段

&#x20; float K\[2] = {

&#x20;   P\_pred\[0]\[0] / (P\_pred\[0]\[0] + R\_angle),

&#x20;   P\_pred\[1]\[0] / (P\_pred\[0]\[0] + R\_angle)

&#x20; };

&#x20; angle = angle\_pred + K\[0] \* (angle\_measured - angle\_pred);

&#x20; bias = bias + K\[1] \* (angle\_measured - angle\_pred);

&#x20; float P\_update\[2]\[2] = {

&#x20;   {(1 - K\[0]) \* P\_pred\[0]\[0], (1 - K\[0]) \* P\_pred\[0]\[1]},

&#x20;   {(1 - K\[1]) \* P\_pred\[1]\[0], P\_pred\[1]\[1] + K\[1] \* P\_pred\[0]\[0]}

&#x20; };

&#x20; P\[0]\[0] = P\_update\[0]\[0];

&#x20; P\[0]\[1] = P\_update\[0]\[1];

&#x20; P\[1]\[0] = P\_update\[1]\[0];

&#x20; P\[1]\[1] = P\_update\[1]\[1];

&#x20; return angle;

}

void setup() {

&#x20; Serial.begin(115200);

&#x20; while (!Serial) delay(10);

&#x20; if (!mpu.begin()) {

&#x20;   Serial.println("找不到MPU6050!");

&#x20;   while (1) delay(500);

&#x20; }

&#x20; mpu.setAccelerometerRange(MPU6050\_RANGE\_8\_G);

&#x20; mpu.setGyroRange(MPU6050\_RANGE\_500\_DEG);

&#x20; mpu.setFilterBandwidth(MPU6050\_BAND\_44\_HZ);

&#x20; delay(100);

}

void loop() {

&#x20; static unsigned long last\_time = millis();

&#x20; unsigned long current\_time = millis();

&#x20; float dt = (current\_time - last\_time) / 1000.0;  // 时间间隔(秒)

&#x20; last\_time = current\_time;

&#x20; mpu.getEvent(\&a, \&g, \&temp);

&#x20; // 从加速度计算俯仰角(Pitch):arctan2(ax, az)

&#x20; float pitch\_measured = atan2(a.acceleration.x, a.acceleration.z) \* 180 / PI;

&#x20; // 陀螺仪角速度转换为角度增量(°)

&#x20; float gyro\_pitch = g.gyro.y \* dt;  // Y轴陀螺仪对应俯仰角变化

&#x20; // 卡尔曼滤波得到稳定的俯仰角

&#x20; float pitch\_filtered = kalman\_filter(pitch\_measured, gyro\_pitch, dt);

&#x20; // 打印结果

&#x20; Serial.print("原始俯仰角:"); Serial.print(pitch\_measured, 1);

&#x20; Serial.print("° | 滤波后俯仰角:"); Serial.print(pitch\_filtered, 1);

&#x20; Serial.println("°");

&#x20; delay(50);

}

五、常见问题与调试技巧

1. 传感器找不到(串口打印 “找不到 MPU6050”)

  • 排查 VCC 电压:必须接 3.3V,用万用表测量模块供电是否稳定;

  • 检查 I2C 引脚:Arduino UNO 是 A4(SDA)、A5(SCL),ESP32 是 21/22,STM32 需确认 I2C 总线是否使能;

  • 地址冲突:若多个 I2C 设备,将 MPU6050 的 AD0 接 VCC,代码中改为mpu.begin(0x69)

  • 模块损坏:若接错 5V,传感器可能已烧毁,更换模块测试。

2. 数据跳变严重(数值波动大)

  • 启用滤波:通过setFilterBandwidth设置更低的带宽(如 21Hz),或在代码中添加滑动平均滤波;

  • 固定传感器:将模块粘贴在硬纸板上,避免晃动导致的噪声;

  • 减少干扰:远离电机、蓝牙模块等强电磁干扰源,供电线尽量短;

  • 校准陀螺仪:静止时读取陀螺仪原始值,计算零偏并在代码中补偿。

3. 加速度 Z 轴数值异常(静止时≠9.81m/s²)

  • 传感器校准:将模块水平放置,读取 ax、ay、az 的静止值,在代码中减去偏移量;

  • 范围配置错误:若配置为 ±2G,灵敏度是 16384 LSB/g,转换时需用 ax/16384.0,而非 4096.0。

4. 中断功能无法使用

  • 确认 INT 引脚接线:接 Arduino 数字引脚(如 D2);

  • 配置中断寄存器:通过寄存器 0x38 设置中断触发方式(如数据就绪触发);

  • 启用中断响应:在代码中编写中断服务函数,处理传感器数据。

六、进阶应用场景与扩展

1. 典型应用

  • 姿态监测:无人机、机器人的姿态控制(需融合磁力计的 9 轴数据);

  • 体感控制:通过俯仰角、滚转角遥控小车、LED 灯亮度;

  • 计步器:通过加速度变化检测步数(阈值法或峰值检测);

  • 振动检测:监测设备运行状态,振动超标时触发报警。

2. 平台移植

  • ESP32 适配:接线 SDA=21、SCL=22,代码无需修改(Wire 库兼容),可结合 WiFi 上传数据到云平台;

  • STM32 适配:使用 HAL 库的 I2C 函数,替换 Wire 库,寄存器操作逻辑一致;

  • Raspberry Pi 适配:使用 smbus2 库操作 I2C,代码结构与 Arduino 类似。

3. 功能扩展

  • 9 轴融合:搭配 HMC5883L 磁力计,实现航向角(Yaw)测量;

  • 数据存储:将传感器数据存储到 SD 卡,或通过蓝牙、LoRa 传输;

  • 低功耗优化:配置 MPU6050 的睡眠模式,定时唤醒采集数据,延长电池寿命。

posted @ 2026-01-06 23:06  wo是个狠人  阅读(1040)  评论(0)    收藏  举报