DMP库下载:https://invensense.tdk.com/developers/
https://invensense.tdk.com/developers/login/?message=software-downloads&redirect_to=developers/software-downloads/
一、MPU6050 芯片的基本功能
(一)集成多种传感器
-
3 轴陀螺仪:可测量物体在 X、Y、Z 三个轴向的角速度。其量程具有多种可调节选项,分别为 ±250°/s、±500°/s、±1000°/s、±2000°/s 。比如在小车转弯时,陀螺仪能够精确感知小车旋转的速度,为控制转弯角度和速度提供依据。其线性误差仅为 0.1°/ 秒,输出频率最高可达 8000Hz,且通过集成的 16 位 ADC 可同时对陀螺仪进行采样 ,有着较高的精度和响应速度。
-
3 轴加速度计:用于检测物体在三个轴向的加速度,量程同样可以调整,范围是 ±2g、±4g、±8g、±16g 。当小车加速、减速或者上下坡时,加速度计能实时监测到加速度的变化。其线性误差为 0.1g,输出频率最高 1000Hz ,通过 16 位 ADC 实现同时采样。
-
温度传感器:芯片内部还集成了数字输出温度传感器,可用于测量环境温度,在一些对温度敏感的应用场景中,能够为系统提供环境温度数据作为参考 。
(二)数字运动处理器(DMP)
MPU6050 自带的 DMP 硬件加速引擎可对陀螺仪和加速度计采集到的数据进行处理。例如,在小车姿态解算方面,如果不使用 DMP,就需要主控制器(如 STM32)花费大量资源对原始的加速度和角速度数据进行复杂的融合解算来得到小车的姿态(偏航角、横滚角、俯仰角) 。而借助 DMP,它可以直接对采样得到的加速度及角速度进行姿态解算,解算结果再输出给主控制器,DMP 每秒可输出 200 次姿态解算,大大减轻了主控制器的运算负担。
(三)通信接口
MPU6050 支持标准的 I2C 通信协议 ,通过 SCL(时钟线)和 SDA(数据线)与主控制器进行通信,例如与 STM32 单片机连接时,就是通过 I2C 接口进行数据传输和指令交互 。并且它还有一个辅助 I2C 接口(XCL 和 XDA),可用于连接外部从设备,如磁传感器,若在小车上需要实现更精准的导航等功能,可外接磁传感器组成九轴传感器系统 。此外,AD0 引脚用于控制 I2C 从属地址,接地时,地址为 0x68;接 VCC 时,地址为 0x69 。
二、MPU6050 芯片的使用方法
(一)硬件连接
假设使用 STM32 作为主控制器与 MPU6050 连接,连接方式如下:
MPU6050 引脚连接至 STM32 引脚
VCC
电源正极
3.3V(确保电压符合芯片要求,范围一般为 2.5V - 3.3V)'
GND
电源地
SCL
I2C 的时钟线
例如 PB6(具体引脚根据 STM32 型号和硬件设计确定)
SDA
I2C 的数据线
例如 PB7
AD0
控制 I2C 从属地址
若希望地址为 0x68,接 GND;若为 0x69,接 VCC
INT
中断数字输出
可连接至 STM32 的中断引脚,用于数据准备好等中断通知(若使用中断方式读取数据)
(二)软件配置
-
初始化 I2C 接口:在主控制器中,首先要对与 MPU6050 通信的 I2C 外设进行初始化。以 STM32 为例,使用 HAL 库初始化 I2C1(假设连接到 PB6 和 PB7)的代码如下:
// 使能GPIOB和I2C1时钟
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_I2C1_CLK_ENABLE();
// 配置PB6为SCL,PB7为SDA
GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// 配置I2C
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000; // 400kHz
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
// 初始化错误处理
Error_Handler();
}
}
-
MPU6050 初始化:
uint8_t check;
HAL_I2C_Mem_Read(&hi2c1, MPU6050_ADDR, 0x75, 1, &check, 1, 1000);
if(check != 0x68)
{
// 初始化失败处理
return 1;
}
uint8_t Data = 0x00;
HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, 0x6B, 1, &Data, 1, 1000);
Data = 0x18;
HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, 0x1B, 1, &Data, 1, 1000);
Data = 0x00;
HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, 0x1C, 1, &Data, 1, 1000);
-
检查设备 ID:通过 I2C 读取 MPU6050 的设备 ID 寄存器(地址 0x75),其值应该为 0x68(若 AD0 接地),以确认设备连接正常。
-
唤醒 MPU6050:向电源管理寄存器 1(0x6B)写入 0x00,将设备从默认的睡眠模式唤醒,进入正常工作状态。
-
设置陀螺仪量程:一般设置为 ±2000°/s,通过向陀螺仪配置寄存器(0x1B)写入对应值(0x18)实现。
-
设置加速度计量程:通常设置为 ±2g,向加速度传感器配置寄存器(0x1C)写入对应值(0x00)。
-
设置其他参数:如设置采样率分频寄存器(0x19)来确定陀螺仪采样率(例如设置为 50),设置配置寄存器(0x1A)来调整数字低通滤波器等 。
-
读取数据:初始化完成后,就可以通过 I2C 接口读取 MPU6050 的寄存器数据。例如,加速度数据存储在地址 0x3B - 0x40(X 轴低字节、X 轴高字节、Y 轴低字节、Y 轴高字节、Z 轴低字节、Z 轴高字节),陀螺仪数据存储在地址 0x43 - 0x48 。以读取加速度数据为例,代码如下:
uint8_t accel_data[6];
HAL_I2C_Mem_Read(&hi2c1, MPU6050_ADDR, 0x3B, 1, accel_data, 6, 1000);
int16_t accel_x = (int16_t)(accel_data[0] | (accel_data[1] << 8));
int16_t accel_y = (int16_t)(accel_data[2] | (accel_data[3] << 8));
int16_t accel_z = (int16_t)(accel_data[4] | (accel_data[5] << 8));
一、先搞懂:为什么不能直接用原始数据?
在解算前,得先明白加速度计和陀螺仪的 “优缺点”—— 融合的本质就是 “取长补短”。
传感器能测什么?优点缺点直接用的问题加速度计3 轴加速度(含重力加速度)无漂移,长期稳定易受 “运动加速度” 干扰(比如小车加速时)小车移动时数据乱跳,无法反映真实姿态陀螺仪3 轴角速度(旋转速度)响应快,短期精度高有 “零漂”(静止时也会慢慢累计误差)时间一长,角度偏差会越来越大
举个小车例子:
-
当小车匀速直线行驶时,加速度计只测到重力加速度,能算出横滚 / 俯仰角,但一旦小车加速,加速度计会把 “行驶加速度” 和 “重力加速度” 混在一起,算出的角度就错了;
-
陀螺仪能实时测小车转弯的角速度(偏航方向),但如果只靠陀螺仪积分算角度,1 分钟后可能就偏差 10° 以上,导致小车 “跑偏”。
所以,必须把两者的数据融合:用加速度计的 “长期稳定性” 修正陀螺仪的 “漂移”,用陀螺仪的 “短期高精度” 弥补加速度计的 “动态干扰”。
二、核心概念:姿态角到底是什么?
解算前先明确 3 个姿态角的定义(以小车为参考系),避免后续混淆:
姿态角旋转轴物理意义(小车场景)示例横滚角(Roll)绕小车前后轴(X 轴)小车左右倾斜程度(比如侧翻风险)小车压到路边石子,左侧抬高 5°俯仰角(Pitch)绕小车左右轴(Y 轴)小车前后倾斜程度(比如上下坡)小车爬上 30° 斜坡,车头抬高 30°偏航角(Yaw)绕小车垂直轴(Z 轴)小车转向角度(比如转弯方向和幅度)小车右转 90°,偏航角增加 90°
⚠️ 关键提醒:
-
加速度计无法直接测偏航角(因为重力是垂直向下的,偏航旋转时重力方向不变,加速度计感知不到),所以偏航角主要靠陀螺仪积分,再结合其他传感器(如磁传感器)修正;
-
横滚角和俯仰角可通过加速度计的重力分量计算,但需要排除运动加速度干扰。
三、融合解算的 “两步走”:先处理原始数据,再融合
整个解算过程分两大步:原始数据预处理(去噪、校准)→ 数据融合(用算法结合两种数据)。
第一步:原始数据预处理 ——“干净的数据才有用”
MPU6050 的原始数据会有 “噪声” 和 “系统误差”,不处理直接用会导致解算结果偏差很大,必须先做 3 件事:
1. 数据校准:消除传感器自身误差
传感器出厂时会有 “零偏”(静止时输出非零值)和 “灵敏度误差”,比如陀螺仪静止时 X 轴输出 10°/s(实际应为 0),这就是零偏。
校准方法(以陀螺仪为例):
-
把 MPU6050 固定在水平台上,保持完全静止;
-
连续采集 1000 组陀螺仪数据,计算每组数据的平均值(比如 X 轴平均 10°/s,Y 轴平均 - 5°/s);
-
后续采集到的陀螺仪数据,减去对应轴的平均值(比如 X 轴原始数据 - 10°/s),得到 “校准后的数据”。
加速度计校准类似:水平静止时,Z 轴加速度应为 1g(重力加速度,约 9.8m/s²),X/Y 轴应为 0,若有偏差则减去零偏。
2. 单位转换:把 “原始数值” 转成 “物理单位”
MPU6050 输出的是 16 位二进制原始数据(比如加速度计输出 0x1234),需要转成实际的物理单位(m/s² 或 °/s)。
转换公式参考 MPU6050 手册:
-
加速度计(假设量程 ±2g):1g = 16384 LSB(手册规定),所以 实际加速度(m/s²)= 原始数据 × 9.8 / 16384;
-
陀螺仪(假设量程 ±2000°/s):1°/s = 16.4 LSB(手册规定),所以 实际角速度(°/s)= 原始数据 × 2000 / 32768(32768 是 16 位数据的最大值)。
例:加速度计 X 轴原始数据为 16384 → 实际加速度 = 16384×9.8/16384=9.8m/s²(符合重力方向)。
3. 滤波去噪:消除环境干扰
采集数据时会有 “高频噪声”(比如小车电机震动导致的数据波动),可用滑动平均滤波或卡尔曼滤波(简单版) 去噪:
-
滑动平均滤波(小白首选):比如取最近 10 组数据的平均值作为当前值,能快速平滑噪声(缺点是响应稍慢,适合小车这种低速场景);
-
代码思路(滑动平均):
c
运行
#define FILTER_NUM 10 // 取10组数据平均float accel_x_filtered; // 滤波后的X轴加速度float accel_x_buf[FILTER_NUM] = {0}; // 缓存数组int buf_index = 0;// 滑动平均滤波函数float slide_filter(float new_data) { float sum = 0; accel_x_buf[buf_index] = new_data; // 新数据存入缓存 buf_index = (buf_index + 1) % FILTER_NUM; // 循环更新索引 // 计算缓存中所有数据的平均值 for (int i = 0; i < FILTER_NUM; i++) { sum += accel_x_buf[i]; } return sum / FILTER_NUM;}
第二步:数据融合算法 ——“取长补短” 的关键
预处理后的数据,需要通过算法融合。小白入门推荐两种算法:互补滤波(简单易实现) 和 卡尔曼滤波(精度更高)。这里重点讲 “互补滤波”(适合小车项目,代码量少,效果足够)。
1. 互补滤波:用 “权重” 分配两者的贡献
核心思想:
-
陀螺仪短期精度高:用陀螺仪的角速度积分得到 “短期姿态角”(积分:角速度 × 时间,比如角速度 10°/s,0.1 秒后角度增加 1°);
-
加速度计长期稳定:用加速度计的重力分量计算得到 “长期姿态角”;
-
用 “互补系数”(通常取 0.98 和 0.02)融合:
最终姿态角 = 0.98×(陀螺仪积分角) + 0.02×(加速度计计算角)
(0.98 让陀螺仪主导短期,0.02 让加速度计修正长期漂移)。
2. 具体计算步骤(以横滚角和俯仰角为例)
(1)用加速度计计算 “长期姿态角”
当小车静止或匀速运动时,加速度计的输出主要是重力加速度(g=9.8m/s²)。通过重力在 X、Y、Z 轴的分量,可以用三角函数算出横滚角和俯仰角。
假设加速度计校准后的 3 轴数据为:Ax(X 轴加速度)、Ay(Y 轴加速度)、Az(Z 轴加速度),则:
-
横滚角(Roll_acc):绕 X 轴旋转,由 Ay 和 Az 计算
Roll_acc = arctan2(Ay, sqrt(Ax² + Az²)) × (180/π)(转成角度制) -
俯仰角(Pitch_acc):绕 Y 轴旋转,由 Ax 和 Az 计算
Pitch_acc = arctan2(-Ax, sqrt(Ay² + Az²)) × (180/π)
⚠️ 为什么用 arctan2?因为它能区分角度的正负(比如小车左侧抬高为正,右侧抬高为负),比普通 arctan 更准确。
(2)用陀螺仪计算 “短期姿态角”
陀螺仪输出的是角速度(ωx:绕 X 轴角速度,ωy:绕 Y 轴角速度,ωz:绕 Z 轴角速度),需要通过 “积分” 得到角度(角度 = 角速度 × 时间间隔)。
假设两次数据采集的时间间隔为 Δt(比如 10ms=0.01s),则:
-
横滚角(Roll_gyro):
Roll_gyro = 上一时刻的Roll + ωx × Δt -
俯仰角(Pitch_gyro):
Pitch_gyro = 上一时刻的Pitch + ωy × Δt -
偏航角(Yaw_gyro):
Yaw_gyro = 上一时刻的Yaw + ωz × Δt
⚠️ 时间间隔 Δt 怎么算?
在 STM32 中,可通过定时器或系统滴答定时器(SysTick)计算,比如每 10ms 采集一次数据,Δt 就设为 0.01s。
(3)互补融合:得到最终姿态角
用互补系数 α(通常取 0.98,可根据实际调整)融合两者:
-
最终横滚角:
Roll = α × Roll_gyro + (1-α) × Roll_acc -
最终俯仰角:
Pitch = α × Pitch_gyro + (1-α) × Pitch_acc -
最终偏航角:
Yaw = Yaw_gyro(加速度计无法修正偏航,若要提高精度,需加磁传感器)
3. 代码思路(STM32 HAL 库为例)
假设已完成 MPU6050 初始化和数据校准,核心代码如下:
c
运行
#include "math.h"// 全局变量:姿态角(初始为0)float Roll = 0.0f, Pitch = 0.0f, Yaw = 0.0f;// 互补系数(可调整,推荐0.98)#define ALPHA 0.98f// 数据采集时间间隔(10ms = 0.01s)#define DT 0.01f// 加速度计计算横滚角和俯仰角void accel_calc_angle(float Ax, float Ay, float Az, float *Roll_acc, float *Pitch_acc) { // 计算横滚角(Roll):arctan2(Ay, sqrt(Ax²+Az²)) *Roll_acc = atan2(Ay, sqrt(Ax*Ax + Az*Az)) * (180.0f / M_PI); // 计算俯仰角(Pitch):arctan2(-Ax, sqrt(Ay²+Az²)) *Pitch_acc = atan2(-Ax, sqrt(Ay*Ay + Az*Az)) * (180.0f / M_PI);}// 互补滤波融合姿态角void complementary_filter(float Ax, float Ay, float Az, float ωx, float ωy, float ωz) { float Roll_acc, Pitch_acc; // 1. 加速度计计算角度 accel_calc_angle(Ax, Ay, Az, &Roll_acc, &Pitch_acc); // 2. 陀螺仪积分计算角度(ωx单位:°/s,DT单位:s) float Roll_gyro = Roll + ωx * DT; float Pitch_gyro = Pitch + ωy * DT; float Yaw_gyro = Yaw + ωz * DT; // 3. 互补融合 Roll = ALPHA * Roll_gyro + (1 - ALPHA) * Roll_acc; Pitch = ALPHA * Pitch_gyro + (1 - ALPHA) * Pitch_acc; Yaw = Yaw_gyro; // 暂用陀螺仪积分(无磁传感器时)}// 主循环中调用:每10ms采集一次数据并融合int main(void) { HAL_Init(); SystemClock_Config(); MPU6050_Init(); // 自定义的MPU6050初始化(含校准) while (1) { float Ax, Ay, Az; // 校准后的加速度(单位:m/s²) float ωx, ωy, ωz; // 校准后的角速度(单位:°/s) // 1. 读取MPU6050校准后的数据 MPU6050_Read_Calibrated_Data(&Ax, &Ay, &Az, &ωx, &ωy, &ωz); // 2. 互补滤波融合姿态角 complementary_filter(Ax, Ay, Az, ωx, ωy, ωz); // 3. 打印姿态角(供调试,比如用串口输出) printf("Roll: %.1f° Pitch: %.1f° Yaw: %.1f°\r\n", Roll, Pitch, Yaw); // 4. 延时10ms(保证DT=0.01s) HAL_Delay(10); }}
四、进阶:偏航角怎么修正?(解决陀螺仪漂移)
前面提到,加速度计无法修正偏航角,长期使用陀螺仪会导致偏航角漂移(比如小车静止时,偏航角慢慢从 0° 变成 10°)。若小车需要精确转向(比如自主导航),必须加磁传感器(如 HMC5883L) 组成 “6 轴 + 磁传感器 = 9 轴” 系统。
磁传感器的作用:提供 “绝对方向”
磁传感器能测地球磁场的方向(类似指南针),可以得到 “绝对偏航角”(比如相对于正北方向的角度),用这个角度修正陀螺仪的漂移。
融合思路(以互补滤波为例):
-
磁传感器校准(消除周围磁场干扰,比如小车电机的磁场);
-
用磁传感器数据计算 “绝对偏航角(Yaw_mag)”;
-
融合公式:
Yaw = ALPHA * Yaw_gyro + (1 - ALPHA) * Yaw_mag(α 仍取 0.98)。
五、实战注意事项(小车项目避坑)
-
安装位置要稳定:MPU6050 尽量远离小车电机(避免电磁干扰)和震动源(比如车轮),否则噪声会导致解算误差;
-
校准要准确:每次上电后最好重新校准(尤其是陀螺仪零偏,受温度影响大);
-
时间间隔要固定:陀螺仪积分对 Δt 敏感,若 Δt 不稳定(比如主循环有其他耗时操作),会导致角度漂移,建议用定时器中断采集数据;
-
互补系数调整:若小车运动剧烈(比如越野小车),可适当减小 α(比如 0.95),让加速度计修正更频繁;若小车平稳(比如循迹小车),α 取 0.98 即可。
17万+

被折叠的 条评论
为什么被折叠?



