Ameba Arduino: [RTL8195] [RTL8710] MPU6050 – 使用 MPU6050 六轴惯性感测元件

材料准备

  • Ameba x 1
  • MPU6050 x 1

范例说明

MPU6050是款常见的6轴惯性感测元件,它包括了三轴加速度计及三轴陀螺仪。使用与读取资料的介面为I2C,可以控制的 细节相当多,我们可以找不少开源的library可供使用。
I2CDev是其中知名的library,你可以找到原始的source code

Ameba使用MPU6050需要2个library,I2CDev与MPU6050, 请到底下的位址下载:

  • I2CDev
    Ameba没有修改I2CDev里面的程式码,只是打包好让使用者下载
  • MPU6050
    Ameba没有修改API的内容,只有根据实际使用状况修改example。

安装library的方式请参考Arduino官方网站的教学文章将zip档的library加入Ameba:
https://www.arduino.cc/en/Guide/Libraries#toc4

接着打开范例 “Files” -> “Example” -> “AmebaMPU6050” -> “MPU6050_raw”。(这个范例与I2CDev官方网站的一样)

这个范例里展示读取三轴加速度计及三轴陀螺仪的值,我们先接线如下:
1

RTL8710接线图如下:
1

编译并上传程式码,按下Reset之后可以在Serial Monitor看到一直印讯息:
2

这六个值分别是:
1. x轴的加速度
2. y轴的加速度
3. z轴的加速度
4. x轴的角速度
5. y轴的角速度
6. z轴的角速度

值的范围是 -16383 ~ 16384,其中可以看到z轴因为重力加速度的关系,值会接近16384
这些值会因为干扰而一直变动,可以转动一下MPU6050观察一下值的变化。

 

程式码说明


虽然程式码很长,但重要的只有几个。第一个是初始化: initialize()
初始化完就可以取值了: getMotion6(int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz)

 

使用Digital Motion Processor


MPU6050搭载了一颗DMP(Digital Motion Processor),可以负责一些运动处理演算法,像是转换成飞机三轴yaw/pitch/roll,转换四元数(Quaternion),或是转换成尤拉角(Euler angle)。
DMP会以高速计算,完成后发出GPIO Interrupt讯号在INT这根Pin上。计算结果会存在FIFO里,Ameba如果一直都没将结果取出,会造成FIFO overflow,并且下一次读出的结果不正确。这种情况将FIFO reset即可。
另一个状况要注意的是,当MPU6050发出GPIO Interrupt的时候,如果正好在处理I2C资料的送收,那么MPU6050会停住,并且再也不会有任何动作。 MPU6050没有Reset或Enable Pin,这种情况下只能将MPU6050断电再插电。因此写程式的时候要注意,如果要处理要花时间的运算,最好等到下一次GPIO Interrupt发生再对MPU6050送收I2C资料。
我们打​​开范例 “File” -> “Examples” -> “AmebaMPU6050” -> “MPU6050_DMP6”。(与I2CDev官方网站的范例有些设定上的差异。)
因为打开DMP关系,在接线上需要多接一根线:
3
编译并上传至Ameba之后,按下Reset键。打开Serial Monitor,会提示键入字元之后启动DMP
4

键入字元之后,会出现ypr的值
5

ypr即Yaw/Pitch/Roll,是飞机飞行常用的表示法
6

范例里还有一些其他的输出方式可以参考。

程式码说明


除了MPU6050的Initialize()之外, DMP也需要初始化 mpu.dmpInitialize()
可以用底下这些API对初始值做校正:
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788);
启动DMP: mpu.setDMPEnabled(true);
设定Ameba在要哪根GPIO倾听Interrupt,我们设定为D3。当interrupt发生的时候,呼叫function dmpDataReady()
attachInterrupt(3, dmpDataReady, RISING);
取得DMP每次计算结果的封包大小
packetSize = mpu.dmpGetFIFOPacketSize();
设定DMP的运算速度,这个值预设值是4,也就是1k/(1+4) = 200Hz,但是会因为印Log很花时间的关系,造成Ameba来不及在下一次Interrupt发生的时候印完log,造成有机会在I2C送收的时候发生Interrupt,随即MPU6050就停住不动了。所以需要适当选择rate,如果rate的值太高(s​​ample rate太低),会让DMP的反应速度没那么快。
mpu.setRate(5); // 1khz / (1 + 5) = 166 Hz
接着在loop()里面检查是否有interrupt发生,如果有就将结果取出
fifoCount = mpu.getFIFOCount();
mpu.getFIFOBytes(fifoBuffer, packetSize);
范例里预设使用OUTPUT_READABLE_YAWPITCHROLL,并各种转换
mpu.dmpGetQuaternion(&q, fifoBuffer); // 四元数
mpu.dmpGetGravity(&gravity, &q); // 取得重力的值
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); // 转换成yaw/pitch/roll