做自平衡小车、双足机器人或者无人机姿态控制,第一个要搞定的传感器基本就是IMU。这两年用的最多、资料最全、板子最便宜的就是MPU6050——一块六轴的小芯片,集成三轴加速度计加三轴陀螺仪,十几块钱就能买到一块带稳压的GY-521模块,接Arduino就四颗线。
这玩意儿说起来简单,但新手第一次接经常踩坑:I2C地址不对、忘了接共地、量程没设、输出出来一堆数字不知道怎么读。这篇把接线、装库、烧代码、看串口输出全串一遍,接线图和示例代码都来自Adafruit官方教程,参数对得上官方库的定义,可以直接抄。

MPU6050是什么东西
MPU6050是InvenSense(现在被TDK收购了)出的六轴MEMS传感器芯片,里面塞了一个三轴加速度计、一个三轴陀螺仪,还有一个温度传感器。加速度计量三个轴向上的加速度,静止的时候能读出重力方向,从而推算倾斜角;陀螺量三个轴向的角速度,知道转了多快;两者数据做融合就能得到比较稳定的姿态角,也就是自平衡机器人里用来"知道自己倒没倒"的那个核心信号。
模块上自带3.3V稳压器和电平转换,所以VCC可以直接接Arduino的5V,SDA和SCL也能直接连5V逻辑的板子,不用另外做电平转换。I2C默认地址是0x68,AD0引脚接高电平会变成0x69,方便一根总线上挂两个。这几点是官方datasheet和Adafruit的板子说明里都写死的,买板子的时候看一下是不是自带稳压就行,有些裸板是3.3V直连,接5V会烧。

接线
接线就四根线,用Adafruit官方的面包板示意图为准:VCC接5V,GND接GND,SCL接Arduino上的SCL(UNO上是A5),SDA接SDA(UNO上是A4)。如果用的是带STEMMA QT/Qwiic接口的Adafruit原版板,一根4Pin的线插到对应的Qwiic扩展板上更省事,不用在面包板上跳线。
有两个容易踩的坑要提前说一下。第一是共地,MPU6050不管是单独供电还是从Arduino取电,GND必须和主控板连到一起,不然I2C通信会乱。第二是I2C上拉电阻,GY-521模块和Adafruit的板子上一般都已经焊了10K的上拉,如果同一根I2C总线上面挂了三四个模块都带上拉,等效电阻会太小,波形变形导致通信失败。这种情况拆掉其中一两个模块上的上拉电阻就行。
装库
直接用Arduino IDE的库管理器装三个库:Adafruit MPU6050、Adafruit Unified Sensor、Adafruit BusIO。三个都装,少一个编译报错。库管理器里搜名字找Adafruit官方版本,作者是Adafruit的那个就行,不要装第三方同名库,API对不上后面跑不通。
装完之后在IDE里能看到 File → Examples → Adafruit MPU6050 → basic_readings 这个示例,这个就是官方验证过的读取示例,我们下面贴的代码就是这个文件的原样搬运——代码这种东西逐字符准确才是最要紧的,按发布规范头文件尖括号改了一下双引号,其他一行不动。
烧代码
把下面这段代码贴到IDE里,选好板子型号和串口,直接上传。注意要把三个include都换成双引号的形式(站点的标签过滤会把尖括号头文件剥掉,换成引号在Arduino里编译是等价的),其他全部原封不动:
// Basic demo for accelerometer readings from Adafruit MPU6050
#include "Adafruit_MPU6050.h"
#include "Adafruit_Sensor.h"
#include "Wire.h"
Adafruit_MPU6050 mpu;
void setup(void) {
Serial.begin(115200);
while (!Serial)
delay(10); // will pause Zero, Leonardo, etc until serial console opens
Serial.println("Adafruit MPU6050 test!");
// Try to initialize!
if (!mpu.begin()) {
Serial.println("Failed to find MPU6050 chip");
while (1) {
delay(10);
}
}
Serial.println("MPU6050 Found!");
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
Serial.print("Accelerometer range set to: ");
switch (mpu.getAccelerometerRange()) {
case MPU6050_RANGE_2_G:
Serial.println("+-2G");
break;
case MPU6050_RANGE_4_G:
Serial.println("+-4G");
break;
case MPU6050_RANGE_8_G:
Serial.println("+-8G");
break;
case MPU6050_RANGE_16_G:
Serial.println("+-16G");
break;
}
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
Serial.print("Gyro range set to: ");
switch (mpu.getGyroRange()) {
case MPU6050_RANGE_250_DEG:
Serial.println("+- 250 deg/s");
break;
case MPU6050_RANGE_500_DEG:
Serial.println("+- 500 deg/s");
break;
case MPU6050_RANGE_1000_DEG:
Serial.println("+- 1000 deg/s");
break;
case MPU6050_RANGE_2000_DEG:
Serial.println("+- 2000 deg/s");
break;
}
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
Serial.print("Filter bandwidth set to: ");
switch (mpu.getFilterBandwidth()) {
case MPU6050_BAND_260_HZ:
Serial.println("260 Hz");
break;
case MPU6050_BAND_184_HZ:
Serial.println("184 Hz");
break;
case MPU6050_BAND_94_HZ:
Serial.println("94 Hz");
break;
case MPU6050_BAND_44_HZ:
Serial.println("44 Hz");
break;
case MPU6050_BAND_21_HZ:
Serial.println("21 Hz");
break;
case MPU6050_BAND_10_HZ:
Serial.println("10 Hz");
break;
case MPU6050_BAND_5_HZ:
Serial.println("5 Hz");
break;
}
Serial.println("");
delay(100);
}
void loop() {
/* Get new sensor events with the readings */
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
/* Print out the values */
Serial.print("Acceleration X: ");
Serial.print(a.acceleration.x);
Serial.print(", Y: ");
Serial.print(a.acceleration.y);
Serial.print(", Z: ");
Serial.print(a.acceleration.z);
Serial.println(" m/s^2");
Serial.print("Rotation X: ");
Serial.print(g.gyro.x);
Serial.print(", Y: ");
Serial.print(g.gyro.y);
Serial.print(", Z: ");
Serial.print(g.gyro.z);
Serial.println(" rad/s");
Serial.print("Temperature: ");
Serial.print(temp.temperature);
Serial.println(" degC");
Serial.println("");
delay(500);
}

怎么看串口输出
上传成功之后打开串口监视器,波特率设115200,应该能看到类似上图的输出:每500ms打一行,分别是X/Y/Z三个方向的加速度(单位m/s²)、三个轴的角速度(单位rad/s)、芯片温度。平放静止的时候,Z轴加速度应该在9.8左右(一个重力加速度),X和Y在0附近;把板子翻过来Z会变成-9.8左右,倾斜的时候重力会分到X和Y上。
量程设置解释一下。代码里加速度计量程设成±8G,陀螺仪±500°/s,数字滤波21Hz。机器人姿态控制这个档位比较常用:自平衡小车一般加速度动态范围不会超过8G,500°/s的陀螺量程日常转弯够用,21Hz滤波能滤掉电机震动的高频噪声。做四轴飞控可以把加速度量程开大到±16G,做慢速机械臂可以压到±2G提高分辨率,直接改setAccelerometerRange和setGyroRange的参数就行。
读完之后下一步做什么
读到原始数据只是第一步。做自平衡机器人你至少还要做两件事:一是陀螺仪零偏校准,上电静止的时候采几百个样本平均一下,把零偏减掉,不然角度积分会一直漂;二是加速度和陀螺做互补滤波或者Madgwick/Mahony滤波融合,得到稳定的Pitch/Roll角。Adafruit有SensorLab陀螺仪校准的指南,有兴趣可以顺着看下去,把角度融合那一步接上,接个舵机或者电机就能做平衡控制了。
这一篇把MPU6050在Arduino上跑通,下一篇会接一个舵机做个简单的云台稳定演示,把姿态角真正用起来。











测试评论,MPU6050教程讲得清楚。
我之前接MPU6050一直用错量程,做自平衡小车一直抖,这篇给的±8G/500deg/s参数直接抄了,今晚回去试一下。
求下一篇融合滤波的,原始数据读到之后到底怎么出稳定角度一直没搞明白,互补滤波和Mahony到底选哪个好?
AD0脚接高电平变0x69这个细节救大命,我板子上挂了两个MPU6050一直互相干扰,以为是硬件坏了。
Arduino官方库的example就是靠谱,比网上那些野路子代码稳多了,之前抄的某论坛代码动不动就卡死。