六轴 MPU6050 模块的使用
MPU6050 模块
MPU6050 是一种非常流行的空间运动传感器芯片,可以获取器件当前的三个加速度分量和三个旋转角速度。 由于其体积小巧,功能强大,精度较高,不仅被广泛应用于工业,同时也是航模爱好者的神器,被安装在各类飞行器上驰骋蓝天。 MPU6050 芯片内自带了一个数据处理子模块 DMP,已经内置了滤波算法,在许多应用中使用 DMP 输出的数据已经能够很好的满足要求。 在使用时只需要将偏移量减去即可使用,如果对精度有更高的要求可以使用上位机或这里使用卡尔曼滤波再次对数据进行优化。
大家在购买的时候,如果只需要陀螺仪和加速度计的话,就买和上图或者下图一样的六轴的 GY-521 六轴 MPU6050 模块即可, 某宝上只需要 4 块钱左右即可买到还包邮,挺便宜的,一定不要买错型号,否则你在使用的时候一定会让你欲哭无泪。这里的库你可能不能直接用了。
硬件连接
接线和 MPU 数据的方向示意如图所示:
MPU6050 | ESP32 |
---|---|
VCC | VCC(+5) |
GND | GND |
SCL | GPIO4 |
SDL | GPIO5 |
代码
MPU6050 库文件
class Accel:
def __init__(self, i2c, addr=0x68):
self.iic = i2c
self.addr = addr
self.iic.start()
self.iic.writeto(self.addr, bytearray([107, 0]))
self.iic.stop()
def get_raw_values(self):
self.iic.start()
a = self.iic.readfrom_mem(self.addr, 0x3B, 14)
self.iic.stop()
return a
def get_ints(self):
b = self.get_raw_values()
c = []
for i in b:
c.append(i)
return c
def bytes_toint(self, firstbyte, secondbyte):
if not firstbyte & 0x80:
return firstbyte << 8 | secondbyte
return - (((firstbyte ^ 255) << 8) | (secondbyte ^ 255) + 1)
def get_values(self):
raw_ints = self.get_raw_values()
vals = {}
vals["acc_x"] = self.bytes_toint(raw_ints[0], raw_ints[1])
vals["acc_y"] = self.bytes_toint(raw_ints[2], raw_ints[3])
vals["acc_z"] = self.bytes_toint(raw_ints[4], raw_ints[5])
vals["temp"] = self.bytes_toint(raw_ints[6], raw_ints[7]) / 340.00 + 36.53
vals["gy_x"] = self.bytes_toint(raw_ints[8], raw_ints[9])
vals["gy_y"] = self.bytes_toint(raw_ints[10], raw_ints[11])
vals["gy_z"] = self.bytes_toint(raw_ints[12], raw_ints[13])
return vals # returned in range of Int16
# -32768 to 32767
def val_test(self): # ONLY FOR TESTING! Also, fast reading sometimes crashes IIC
from time import sleep
while 1:
print(self.get_values())
sleep(0.05)
import time
from mpu6050 import Accel
from machine import SoftI2C, Pin
g = 9.8
i2c = SoftI2C(scl=Pin(4), sda=Pin(5))
accel = Accel(i2c)
while 1:
accel_dict = accel.get_values()
print(accel_dict)
# 将重力加速度换算为角度
a_x = accel_dict["acc_x"] * 2 / 32768 * 180
a_y = accel_dict["acc_y"] * 2 / 32768 * 180
a_z = accel_dict["acc_z"] * 2 / 32768 * 180
print(a_x, a_y, a_z)
time.sleep(1)
参数解析
六轴 MPU6050 输出所有参数:
- 加速度计的 X 轴分量:
ACC_X
- 加速度计的 Y 轴分量:
ACC_Y
- 加速度计的 Z 轴分量:
ACC_Z
- 当前温度:
TEMP
- 绕 X 轴旋转的角速度:
GYR_X
- 绕 Y 轴旋转的角速度:
GYR_Y
- 绕 Z 轴旋转的角速度:
GYR_Z
MPU6050 芯片的座标系是这样定义的:令芯片表面朝向自己,将其表面文字转至正确角度,此时,以芯片内部中心为原点,水平向右的为 X 轴,竖直向上的为 Y 轴,指向自己的为 Z 轴。
三轴加速度计
加速度计的三轴分量 ACC_X、ACC_Y 和 ACC_Z 均为 16 位有符号整数,分别表示器件在三个轴向上的加速度,取负值时加速度沿座标轴负向,取正值时沿正向。
三个加速度分量均以重力加速度 g 的倍数为单位,能够表示的加速度范围,即倍率可以统一设定,有 4 个可选倍率:2g、4g、8g、16g。在这里不介绍如何进行倍率修改,如果想修改只需将不同倍率对应的标志位写入对应寄存器即可。倍率默认设定为 2g,以 ACC_X 为例,在倍率为 2g 的时候,ACC_X 的最小值为 -32768,最大值为 32768。当 ACC_X 为 32768 时,当前加速度为沿 X 轴正方向 2 倍的重力加速度。
加速度计算公式如图所示:
三轴陀螺仪 绕 X、Y 和 Z 三个座标轴旋转的角速度分量 GYR_X、GYR_Y 和 GYR_Z 均为 16 位有符号整数。从原点向旋转轴方向看去,取正值时为顺时针旋转,取负值时为逆时针旋转。
三个角速度分量均以“度/秒”为单位,能够表示的角速度范围,即倍率可统一设定,有 4 个可选倍率:250 度/秒、500 度/秒、1000 度/秒、2000 度/秒。以 GYR_X 为例,若倍率设定为 250 度/秒,则意味着 GYR 取正最大值 32768 时,当前角速度为顺时针 250 度/秒;若设定为 500 度/秒,取 32768 时表示当前角速度为顺时针 500 度/秒。显然,倍率越低精度越好,倍率越高表示的范围越大。倍率默认设定为 250 度/秒。具体修改方式此处不做讲解。
角速度的换算公式为:
数据处理与实现
MPU6050 芯片提供的数据夹杂有较严重的噪音,在芯片处理静止状态时数据摆动都可能超过 2%。除了噪音,各项数据还会有偏移的现象,也就是说数据并不是围绕静止工作点摆动,因此要先对数据偏移进行校准 ,再通过滤波算法消除噪音。
校准
校准是比较简单的工作,我们只需要找出摆动的数据围绕的中心点即可。我们以 GRY_X 为例,在芯片处理静止状态时,这个读数理论上讲应当为 0,但它往往会存在偏移量,比如我们以 10ms 的间隔读取了 10 个值如下:
-158.4, -172.9, -134.2, -155.1, -131.2, -146.8, -173.1, -188.6, -142.7, -179.5
取这 10 个值的均值,也就是这个读数的偏移量为 -158.25。在获取偏移量后,每次的读数都减去偏移量就可以得到校准后的读数了。当然这个偏移量只是估计值,比较准确的偏移量要对大量的数据进行统计才能获知,数据量越大越准,但统计的时间也就越慢。一般校准可以在每次启动系统时进行,那么你应当在准确度和启动时间之间做一个权衡。
三个角速度读数 GYR_X、GYR_Y 和 GYR_Z 均可通过统计求平均的方法来获得,但三个加速度分量就不能这样简单的完成了,因为芯片静止时的加速度并不为 0。
加速度值的偏移来自两个方面,一是由于芯片的测量精度,导至它测得的加速度向量并不垂直于大地;二是芯片在整个系统(如无人机)上安装的精度是有限的,系统与芯片的座标系很难达到完美重合。前者我们称为读数偏移,后者我们称为角度偏移。因为读数和角度之间是非线性关系,所以要想以高精度进行校准必须先单独校准读数偏移,再把芯片固定在系统中后校准角度偏移。然而,由于校准角度偏移需要专业设备,且对于一般应用来说,两步校准带来的精度提升并不大,因此通常只进行读数校准即可。
读数校准方法:
为了尽量避免读数偏移带来的影响,首先将 MPU6050 牢牢地固定在系统中,并使二者座标系尽可能的重合。 此时,我们认为芯片的 ACC_X 和 ACC_Y 的理论值应为 0,ACC_Z 的理论值应为 -16384(默认 2g 的倍率)。 由于 ACC_X 和 ACC_Y 的理论值应为 0,与角速度量的校准类似,这两个读数偏移量可用统计均值的方式校准。ACC_Z 则需要多一步处理,即在统计偏移量的过程中,每次读数都要加上 16384,再进行统计均值校准。 卡尔曼滤波 对于夹杂了大量噪音的数据,卡尔曼滤波器的效果无疑是最好的。如果不想考虑算法细节,可以直接使用 Arduino 的 Klaman Filter 库完成。在我们的模型中,一个卡尔曼滤波器接受一个轴上的角度值、角速度值以及时间增量,估计出一个消除噪音的角度值。跟据当前的角度值和上一轮估计的角度值,以及这两轮估计的间隔时间,我们还可以反推出消除噪音的角速度。
卡尔曼滤波建议在上位机实现,Micropython 本身对矩阵的运算并没有特别好的支持,在上位机可以借助 numpy 实现快速卡尔曼滤波运算。
编写 ESP32 MPU6050 驱动
用的是 esp32 的 I2C(0),默认 scl 接 GPIO18,sda 接 GPIO19
关键词:micropython,esp32,mpu6050
附录
https://blog.csdn.net/qq_45779334/article/details/113122089
编写 ESP32 MPU6050 驱动:https://blog.csdn.net/supermodule/article/details/137654789 (计算欧拉角)
语言识别 SD 卡语音包,语言识别的语音包。