MPU6050是一款运动和姿态传感器芯片,可以获取物体当前的三个加速度分量和三个旋转角速度。由于其体积小巧,功能强大,并且价格低,在平衡车和航模制作中应用广泛。
基于Python的数据获取和互补滤波
MPU6050数据获取
MPU6050使用i2c通讯,其数据获取已有大佬使用Python完成,见[Github mpu6050],我们需要使用的是这里的mpu6050.py文件。
MPU6050数据互补滤波
通过MPU6050得到姿态角有两个途径:
- 通过加速度计可以得到加速度方向,进而求解Pitch(俯仰)和Roll(滚转)角度
- 通过陀螺仪得到角速度,角速度对时间的积分得到姿态角
但这两种方式如果单独使用效果并不好,直接从加速度计得到的角度值包含大量噪声,抖动明显;直接由角速度积分得到的角度值虽然平滑,但陀螺仪的偏差会导致积分误差不断增大。通过将加速度计和陀螺仪分别得到的角度进行融合,可以得到质量较好的角度数据。常用的融合方式有卡尔曼滤波、互补滤波等,卡尔曼滤波高深难懂,互补滤波更容易理解,且效果也不差。
互补滤波代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43import math
class Complimentary_Filter:
def __init__(self, order1_ratio=0.75, order2_ratio=0.2):
self.order1_ratio = order1_ratio
self.order2_ratio = order2_ratio
self.order1_pitch = 0.0 # angle around X axis
self.order1_roll = 0.0 # angle around Y axis
self.order2_pitch = 0.0 # angle around X axis
self.order2_roll = 0.0 # angle around Y axis
self.y_pitch=0.0
self.y_roll=0.0
return
def combine_order1(self, dt, accel_data, gyro_data):
# Turning around the X axis results in a vector on the Y-axis
pitch_accel = math.atan2(accel_data[1], accel_data[2]) * 180 / math.pi
# Turning around the Y axis results in a vector on the X-axis
roll_accel = math.atan2(accel_data[0], accel_data[2]) * 180 / math.pi
self.order1_pitch = (self.order1_pitch- gyro_data[2] * dt) * self.order1_ratio + pitch_accel * (1.0 - self.order1_ratio)
self.order1_roll = (self.order1_roll- gyro_data[1] * dt)* self.order1_ratio + roll_accel * (1.0 - self.order1_ratio)
return [pitch_accel, roll_accel, self.order1_pitch, self.order1_roll]
def combine_order2(self, dt, accel_data, gyro_data):
# Turning around the X axis results in a vector on the Y-axis
pitch_accel = math.atan2(accel_data[1], accel_data[2]) * 180 / math.pi
# Turning around the Y axis results in a vector on the X-axis
roll_accel = math.atan2(accel_data[0], accel_data[2]) * 180 / math.pi
x1=(pitch_accel-self.order2_pitch)*(1.0-self.order2_ratio)*(1.0-self.order2_ratio)
self.y_pitch = self.y_pitch + x1*dt
x2 = self.y_pitch + 2 * (1.0-self.order2_ratio) * (pitch_accel - self.order2_pitch) + gyro_data[2]
self.order2_pitch = self.order2_pitch + x2*dt
x1=(roll_accel-self.order2_roll)*(1.0-self.order2_ratio)*(1.0-self.order2_ratio)
self.y_roll = self.y_roll + x1*dt
x2 = self.y_roll + 2 * (1.0-self.order2_ratio) * (roll_accel - self.order2_roll) + gyro_data[1]
self.order2_roll = self.order2_roll + x2*dt
return [pitch_accel, roll_accel, self.order2_pitch, self.order2_roll]
树莓派获取MPU6050数据,融合滤波后绘图显示
采用树莓派3 B+,与MPU6050 I2C接口连接
代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102from pyqtgraph.Qt import QtGui, QtCore
from collections import deque
from filter import Complimentary_Filter as Filter
import pyqtgraph as pg
import math
import datetime
from mpu6050 import mpu6050
filter = Filter()
delta_T = 50
pen_width = 2
rad2deg = 180.0/math.pi
framenum = 200
x_label = range(0,framenum)
for i in range(framenum):
x_label[i] *= delta_T
acce_pitch_deque = deque(maxlen=framenum)
acce_roll_deque = deque(maxlen=framenum)
order1_filter_pitch_deque = deque(maxlen=framenum)
order1_filter_roll_deque = deque(maxlen=framenum)
order2_filter_pitch_deque = deque(maxlen=framenum)
order2_filter_roll_deque = deque(maxlen=framenum)
sensor = mpu6050(0x68)
for i in xrange(framenum):
acce_pitch_deque.append(0.0)
acce_roll_deque.append(0.0)
order1_filter_pitch_deque.append(0.0)
order1_filter_roll_deque.append(0.0)
order2_filter_pitch_deque.append(0.0)
order2_filter_roll_deque.append(0.0)
win = pg.GraphicsWindow(title = "MPU6050 Plotter")
win.resize(1200,600)
win.setWindowTitle('MPU6050 Pitch and Roll Plotter')
pg.setConfigOptions(antialias = True)
def addplot(title_name,left_name,unit_name,bottom_name,Y_range_min,Y_range_max):
subplot= win.addPlot(title = title_name)
subplot.showGrid(x = True,y = True)
subplot.setLabel('left', left_name, units = unit_name)
subplot.setLabel('bottom', bottom_name)
subplot.setYRange(Y_range_min,Y_range_max)
return subplot
acce_pitch_plotter = addplot('Acce_Pitch_Plotter','Pitch','deg','time/ms',-180,180)
curve_acce_pitch = acce_pitch_plotter.plot(pen = pg.mkPen(color = (255,0,255),width = pen_width))
acce_roll_plotter = addplot('Acce_Roll_Plotter','Roll','deg','time/ms',-180,180)
curve_acce_roll = acce_roll_plotter.plot(pen = pg.mkPen(color = (0, 255, 127),width = pen_width))
win.nextRow()
order1_filter_pitch_plotter = addplot('1st-order-filter_Pitch_Plotter','Pitch','deg','time/ms',-180,180)
curve_order1_filter_pitch = order1_filter_pitch_plotter.plot(pen = pg.mkPen(color = (255,0,255),width = pen_width))
order1_filter_roll_plotter = addplot('1st-order-filter_Roll_Plotter','Roll','deg','time/ms',-180,180)
curve_order1_filter_roll = order1_filter_roll_plotter.plot(pen = pg.mkPen(color = (0, 255, 127),width = pen_width))
win.nextRow()
order2_filter_pitch_plotter = addplot('2nd-order-filter_Pitch_Plotter','Pitch','deg','time/ms',-180,180)
curve_order2_filter_pitch = order2_filter_pitch_plotter.plot(pen = pg.mkPen(color = (255,0,255),width = pen_width))
order2_filter_roll_plotter = addplot('2nd-order-filter_Roll_Plotter','Roll','deg','time/ms',-180,180)
curve_order2_filter_roll = order2_filter_roll_plotter.plot(pen = pg.mkPen(color = (0, 255, 127),width = pen_width))
def update():
time1 = datetime.datetime.now()
acce_data = [sensor.get_accel_data().get('x'),sensor.get_accel_data().get('y'),sensor.get_accel_data().get('z')]
gyro_data = [sensor.get_gyro_data().get('x'),sensor.get_gyro_data().get('y'),sensor.get_gyro_data().get('z')]
order1_filter_pitch_roll_data = filter.combine_order1(delta_T/1000.0, acce_data, gyro_data)
order2_filter_pitch_roll_data = filter.combine_order2(delta_T/1000.0, acce_data, gyro_data)
acce_pitch_deque.append(order1_filter_pitch_roll_data[0])
acce_roll_deque.append(order1_filter_pitch_roll_data[1])
order1_filter_pitch_deque.append(order1_filter_pitch_roll_data[2])
order1_filter_roll_deque.append(order1_filter_pitch_roll_data[3])
order2_filter_pitch_deque.append(order2_filter_pitch_roll_data[2])
order2_filter_roll_deque.append(order2_filter_pitch_roll_data[3])
curve_acce_pitch.setData(x_label, list(acce_pitch_deque))
curve_acce_roll.setData(x_label, list(acce_roll_deque))
curve_order1_filter_pitch.setData(x_label, list(order1_filter_pitch_deque))
curve_order1_filter_roll.setData(x_label, list(order1_filter_roll_deque))
curve_order2_filter_pitch.setData(x_label, list(order2_filter_pitch_deque))
curve_order2_filter_roll.setData(x_label, list(order2_filter_roll_deque))
delta_time=datetime.datetime.now()-time1
#print delta_time.microseconds/1000.0
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(delta_T) #take a sample every * ms
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
绘图结果
第一、二、三行分别表示加速度计数据直接求解得到的Pitch、Yaw角度,一阶互补滤波的角度,二阶互补滤波的角度。