Arduino与MPU-6050的通信
为避免纠缠于电路细节,我们直接使用集成的MPU6050模块。MPU6050的数据接口用的是I2C总线协议,因此我们需要Wire程序库的帮助来实现Arduino与MPU6050之间的通信。请先确认你的Arduino编程环境中已安装Wire库。
Wire库的官方文档(http://www.arduino.cc/en/Reference/Wire)中指出:在UNO板子上,SDA接口对应的是A4引脚,SCL对应的是A5引脚。MPU6050需要5V的电源,可由UNO板直接供电。按照下图连线。
(紫色线是中断线,这里用不到,可以不接)
MPU6050的数据写入和读出均通过其芯片内部的寄存器实现,这些寄存器的地址都是1个字节,也就是8位的寻址空间,其寄存器的详细列表说明书请点击下载:https://www.olimex.com/Products/Modules/Sensors/MOD-MPU6050/resources/RM-MPU-60xxA_rev_4.pdf
1.1 将数据写入MPU-6050
在每次向器件写入数据前要先打开Wire的传输模式,并指定器件的总线地址,MPU6050的总线地址是0x68(AD0引脚为高电平时地址为0x69)。然后写入一个字节的寄存器起始地址,再写入任意长度的数据。这些数据将被连续地写入到指定的起始地址中,超过当前寄存器长度的将写入到后面地址的寄存器中。写入完成后关闭Wire的传输模式。下面的示例代码是向MPU6050的0x6B寄存器写入一个字节0。
Wire.beginTransmission(0x68); //开启MPU6050的传输
Wire.write(0x6B); //指定寄存器地址
Wire.write(0); //写入一个字节的数据
Wire.endTransmission(true); //结束传输,true表示释放总线
1.2 从MPU-6050读出数据
读出和写入一样,要先打开Wire的传输模式,然后写一个字节的寄存器起始地址。接下来将指定地址的数据读到Wire库的缓存中,并关闭传输模式。最后从缓存中读取数据。下面的示例代码是从MPU6050的0x3B寄存器开始读取2个字节的数据:
Wire.beginTransmission(0x68); //开启MPU6050的传输
Wire.write(0x3B); //指定寄存器地址
Wire.requestFrom(0x68, 2, true); //将输据读出到缓存
Wire.endTransmission(true); //关闭传输模式
int val = Wire.read() 《《 8 | Wire.read(); //两个字节组成一个16位整数
1.3 具体实现
通常应当在setup函数中对Wire库进行初始化:
Wire.begin();
在对MPU6050进行各项操作前,必须启动该器件,向它的0x6B写入一个字节0即可启动。通常也是在setup函数完成,代码见1.1节。
MPU6050芯片提供的数据夹杂有较严重的噪音,在芯片处理静止状态时数据摆动都可能超过2%。除了噪音,各项数据还会有偏移的现象,也就是说数据并不是围绕静止工作点摆动,因此要先对数据偏移进行校准 ,再通过滤波算法消除噪音。
对于夹杂了大量噪音的数据,卡尔曼滤波器的效果无疑是最好的。如果不想考虑算法细节,可以直接使用Arduino的Klaman Filter库完成。在我们的模型中,一个卡尔曼滤波器接受一个轴上的角度值、角速度值以及时间增量,估计出一个消除噪音的角度值。跟据当前的角度值和上一轮估计的角度值,以及这两轮估计的间隔时间,我们还可以反推出消除噪音的角速度。
arduino读取MPU6050数据源代码参考:
#include “Wire.h” //包含头文件
#define SMPLRT_DIV 0x19 //陀螺仪采样率,典型值:0x07(125Hz)
#define CONFIG 0x1A //低通滤波频率,典型值:0x06(5Hz)
#define GYRO_CONFIG 0x1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define ACCEL_CONFIG 0x1C //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
#define ACCEL_XOUT_H 0x3B //定义加速度x轴的高八位[15:8]
#define ACCEL_XOUT_L 0x3C //定义加速度x轴的低八位[7:0]
#define ACCEL_YOUT_H 0x3D //定义加速度y轴的高八位[15:8]
#define ACCEL_YOUT_L 0x3E //定义加速度y轴的低八位[7:0]
#define ACCEL_ZOUT_H 0x3F //定义加速度z轴的高八位[15:8]
#define ACCEL_ZOUT_L 0x40 //定义加速度z轴的低八位[7:0]
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43 //定义加速度x轴的高八位[15:8]
#define GYRO_XOUT_L 0x44 //定义加速度x轴的低八位[7:0]
#define GYRO_YOUT_H 0x45 //定义加速度y轴的高八位[15:8]
#define GYRO_YOUT_L 0x46 //定义加速度y轴的低八位[7:0]
#define GYRO_ZOUT_H 0x47 //定义加速度z轴的高八位[15:8]
#define GYRO_ZOUT_L 0x48 //定义加速度z轴的低八位[7:0]
#define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用)
#define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68,只读)
#define SlaveAddress 0xD0 //IIC写入时的地址字节数据,+1为读取
int ax0,ax1,axout; //定义加速度传感器从寄存器地址获取的高八位低八位数据以及输出的模拟量
int ay0,ay1,ayout;
int az0,az1,azout;
int gx0,gx1,gxout; //定义陀螺仪传感器从寄存器地址获取的高八位低八位数据以及输出的模拟量
int gy0,gy1,gyout;
int gz0,gz1,gzout;
double Xa,Ya,Za;
double Xg,Yg,Zg;
//float aax,aay;
//float pi=3.1415926;
int MPU6050address = 0x68;//MPU6050的地址
void setup()
{
Wire.begin(); //设置I2通信时的本机地址
Serial.begin(9600);
Wire.beginTransmission(MPU6050address);//启动I2通信,读取MPU6050地址
// Wire.write(GYRO_CONFIG);//从传感器写入数据
// Wire.write(ACCEL_CONFIG);
Wire.write(8); //写入8位字节
Wire.endTransmission();//结束通信
}
void loop()
{
Wire.beginTransmission(MPU6050address);
Wire.write(ACCEL_XOUT_H);//写加速度计x轴数据
Wire.write(ACCEL_XOUT_L);
Wire.write(GYRO_XOUT_H);//写陀螺仪计x轴数据
Wire.write(GYRO_XOUT_L);
Wire.endTransmission();
Wire.requestFrom(MPU6050address,2);
if(Wire.available()《=2);//用于返回接受的字节数
{
ax0 = Wire.read();
ax1 = Wire.read();
ax1 = ax1《《8;
axout = ax0+ax1;
gx0 = Wire.read();
gx1 = Wire.read();
gx1 = gx1《《8;
gxout = gx0+gx1;
}
Wire.beginTransmission(MPU6050address);
Wire.write(ACCEL_YOUT_H);
Wire.write(ACCEL_YOUT_L);
Wire.write(GYRO_YOUT_
H);
Wire.write(GYRO_YOUT_L);
Wire.endTransmission();
Wire.requestFrom(MPU6050address,2);
if(Wire.available()《=2);
{
ay0 = Wire.read();
ay1 = Wire.read();
ay1 = ay1《《8;
ayout = ay0+ay1;
gy0 = Wire.read();
gy1 = Wire.read();
gy1 = gy1《《8;
gyout = gy0+gy1;
}
Wire.beginTransmission(MPU6050address);
Wire.write(ACCEL_ZOUT_H);
Wire.write(ACCEL_ZOUT_L);
Wire.write(GYRO_ZOUT_H);
Wire.write(GYRO_ZOUT_L);
Wire.endTransmission();
Wire.requestFrom(MPU6050address,2);
if(Wire.available()《=2);
{
az0 = Wire.read();
az1 = Wire.read();
az1 = ax1《《8;
azout = az0+az1;
gz0 = Wire.read();
gz1 = Wire.read();
gz1 = gz1《《8;
gzout = gz0+gz1;
}
Xa=axout/256.00; //把输出结果转换为重力加速度g,精确到小数点后2位
Ya=ayout/256.00;
Za=azout/256.00;
Xg=gxout/256.00;
Yg=gyout/256.00;
Zg=gzout/256.00;
// aax = atan(Xa/Za) * (-180) / pi; //想转化为角度的,可是感觉到有点不对,就没写进去
// aay = atan(Ya/Xa) * (-180) / pi;
Serial.println(“Xa:”);//输出6050不同轴采集到的数据
Serial.print(Xa,DEC);
Serial.println(‘\n’);
Serial.println(“Ya:”);
Serial.print(Ya,DEC);
Serial.println(‘\n’);
Serial.println(“Za:”);
Serial.print(Za,DEC);
Serial.println(‘\n’);
delay(500);
Serial.println(“Xg:”);
Serial.print(Xg,DEC);
Serial.println(‘\n’);
Serial.println(“Yg:”);
Serial.print(Yg,DEC);
Serial.println(‘\n’);
Serial.println(“Zg:”);
Serial.print(Zg,DEC);
Serial.println(‘\n’);
delay(500);
}
评论
查看更多