mpu6050.py

#一阶互补滤波k=0.02,ACC+-2g,Gyro+-2000°/s,初始校正6轴值需要10s,采样频率50Hz=20ms读取一次,角速度传感器带宽20Hz(约25Hz)
#-*- encoding: utf-8 -*-
import time, math

MPU6050_ADDRESS_AD0_LOW  = 0x68	 # 1.检查通讯117
MPU6050_ADDRESS_AD0_HIGH = 0x69
MPU6050_REG_POWER_MGMT_1 = 0x6B  # 2.复位+100ms,107;3.唤醒MPU6050和配置时钟源pll 107
MPU6050_REG_POWER_MGMT_2 = 0x6C  # 8.激活传感器6轴108
MPU6050_REG_INTERRUPT_EN = 0x38  # 禁用中断(自己添加未使用中断功能)	56
MPU6050_REG_READ_SENSORS = 0x3B  # 9.获取传感器数据59-72
MPU6050_REG_CONFIG       = 0x1A  # 6.配置带宽和输出频率26
MPU6050_REG_SMPRT_DIV    = 0x19  # 7.设置采样率25
MPU6050_REG_CONFIG_GYRO  = 0x1B  # 5.设置陀螺仪量程范围27
MPU6050_REG_CONFIG_ACC   = 0x1C  # 4.设置加速度计量程28

class MPU6050():

    def __init__(self, i2c):
        self.captures = bytearray(14)  # 14个字节数组
        self.AngleX = 0#Roll	角度表示方法:欧拉角、四元数、轴角(用一个向量+角度表示)
        self.AngleY = 0#Pitch
        self.AngleZ = 0#Yaw
        self.i2c = i2c
        if self.detect():
           self.reset()
           self.config()
           self.calibration()
           self.temps = time.ticks_ms()#获得ms计数值
	
    def detect(self):
        detect_mpu6050 = False
        i2c_peripheriques = self.i2c.scan()
        for i2c_peripherique in i2c_peripheriques:
            if (i2c_peripherique == MPU6050_ADDRESS_AD0_LOW):
                self.address = MPU6050_ADDRESS_AD0_LOW
                detect_mpu6050 = True
            if (i2c_peripherique == MPU6050_ADDRESS_AD0_HIGH):
                self.address = MPU6050_ADDRESS_AD0_HIGH
                detect_mpu6050 = True
        return detect_mpu6050
		
	#bit7=1复位+100ms
    def reset(self):
        self.data = bytearray(2)
        self.data[0] = MPU6050_REG_POWER_MGMT_1#0x6B
        self.data[1] = 1 << 7  # 10000000 : reset mpu6050
        self.i2c.writeto(self.address, self.data)
        time.sleep(0.100)  # 延迟100ms
	
    def config(self):
		#配置时钟源:
		#Bit6=0工作模式,非睡眠模式;bit3=0温度sensor可用;bit321时钟源,默认内部8M RC晶振,精度不高,
		#将器件配置为使用陀螺仪XYZ其中一个(或外部时钟源)作为时钟参考,以提高稳定性。
        self.data = bytearray(2)
        self.data[0] = MPU6050_REG_POWER_MGMT_1#0x6B
        self.data[1] = 1  #配置外部时钟源PLL,(PLL WITH X AXIS GYROSCOPE REFERENCE)
        self.i2c.writeto(self.address, self.data)
		
		#配置加速度计量程:bit4 bit3:0(+-2g),1(+—4g),2(+-8g),3(+-16g)
        self.data[0] = MPU6050_REG_CONFIG_ACC#0x1C
        self.data[1] = 0 #+/- 2g(65536/4=16384LSB/g) 
        self.i2c.writeto(self.address, self.data)
		
		#配置陀螺仪量程:bit4 bit3:0(+-250°/s),1(+—500°/s),2(+-1000°/s),3(+-2000°/s)
        self.data[0] = MPU6050_REG_CONFIG_GYRO#0x1B
        self.data[1] = 24  #+/- 2000deg/s(65536/4000=16.4LSB/(°/s)) 
        self.i2c.writeto(self.address, self.data)
				
		#配置数字低通滤波器DLPF[2:0]:配置陀螺仪输出频率
		'''
		DLPF_CFG[2:0] 		加速度传感器 Fs=1Khz 			角速度传感器 (陀螺仪) 
							 带宽(Hz) 	延迟(ms) 			带宽(Hz) 	延迟(ms) 	Fs(Khz) 
		000 				  260 			0 				  256 		   0.98 	  8 
		001 				  184 			2.0 			  188 	 	   1.9 	  	  1 
		010 				  94 			3.0 			  98 		   2.8 		  1 
		011 				  44 			4.9 			  42 		   4.8 		  1 
		100 				  21 			8.5 			  20 		   8.3 	      1 
		101 				  10 			13.8 			  10 		   13.4 	  1 
		110 				  5 			19.0 			  5 		   18.6 	  1 
		111 						保留 							保留 			  8 

		'''
		self.data[0] = MPU6050_REG_CONFIG#0x1A 
        self.data[1] = 100 #角速度传感器带宽20Hz,约25Hz,一般设置角速度传感器的带宽为其采样率的一半
        self.i2c.writeto(self.address, self.data)
		
		#bit7-bit0
		#配置采样频率=陀螺仪输出频率/(1+SMPLRT_DIV)=1000Hz / 20 = 50Hz , 0.02s更新一次6轴数据寄存器,主函数是20ms读取一次
        self.data[0] = MPU6050_REG_SMPRT_DIV#0x19
        self.data[1] = 19 
        self.i2c.writeto(self.address, self.data)
		
		#激活6轴为非待机模式bit5-bit0
        self.data[0] = MPU6050_REG_POWER_MGMT_2#0x6C
        self.data[1] = 0  
        self.i2c.writeto(self.address, self.data)		

    def sensor_captures(self):	
		if self.detect():
			self.i2c.readfrom_mem_into(self.address,
										MPU6050_REG_READ_SENSORS,
										self.captures)
			self.acc()
			self.temp()
			self.gyro()
			self.angle()
		else:
			print('mpu6050 communication error')
			
	#读取3轴加速度0x3B-0x40(59-64)
    def acc(self):
        self.accX_high_byte = self.captures[0]
        self.accX_low_byte = self.captures[1]
        self.accX = self.bytes_to_int(self.accX_high_byte, self.accX_low_byte)
		#初始化是第99(从0开始,相当于第100次)次-100次平均值,调用是第101次-100次平均值,才开始显示角度。
        self.accX_calibre = self.accX - self.accX_calibration

        self.accY_high_byte = self.captures[2]
        self.accY_low_byte = self.captures[3]
        self.accY = self.bytes_to_int(self.accY_high_byte, self.accY_low_byte)
        self.accY_calibre = self.accY - self.accY_calibration

        self.accZ_high_byte = self.captures[4]
        self.accZ_low_byte = self.captures[5]
        self.accZ = self.bytes_to_int(self.accZ_high_byte, self.accZ_low_byte)
        self.accZ_calibre = self.accZ - self.accZ_calibration
	
	#读取温度值0x41-0x42(65-66)
    def temp(self):
        self.temp_high_byte = self.captures[6]
        self.temp_low_byte = self.captures[7]
        self.temperature = self.bytes_to_int(self.temp_high_byte,
                                             self.temp_low_byte)
        self.temperature = self.temperature / 340.00 + 36.53#MPU6050参考公式:Temperature=regval/340+36.53
		
	#读取3轴角速度0x43-0x48(67-72)
    def gyro(self):
        self.gyroX_high_byte = self.captures[8] 
        self.gyroX_low_byte = self.captures[9] 
        self.gyroX = self.bytes_to_int(self.gyroX_high_byte, self.gyroX_low_byte)#100ms陀螺仪输出一次值
        self.gyroX_calibre = self.gyroX - self.gyroX_calibration
		
        self.gyroY_high_byte = self.captures[10] 
        self.gyroY_low_byte = self.captures[11]
        self.gyroY = self.bytes_to_int(self.gyroY_high_byte, self.gyroY_low_byte)
        self.gyroY_calibre = self.gyroY - self.gyroY_calibration

        self.gyroZ_high_byte = self.captures[12] 
        self.gyroZ_low_byte = self.captures[13] 
        self.gyroZ = self.bytes_to_int(self.gyroZ_high_byte, self.gyroZ_low_byte)
        self.gyroZ_calibre = self.gyroZ - self.gyroZ_calibration
		
	#移位合并
    def bytes_to_int(self, firstbyte, secondbyte):
		#读取值为正数时(-128~127)
        if not firstbyte & 0x80:#为0时直接合并
            return (firstbyte << 8 | secondbyte)
		#读取值为负数时,异或255,合并,再加1,变为正数,再加负号;
		return - (((firstbyte ^ 255) << 8) | (secondbyte ^ 255) + 1)  
		
	#读取100次求出平均值,第一次初始化时求出陀螺仪6轴初始值,不动的情况下,理论初始值等于0
    def calibration(self):
        i = 0
		#实例方法里的变量在实例属性里初始化,那变量的值与实例属性一样可保持;
        self.gyroX_calibration = 0
        self.gyroY_calibration = 0
        self.gyroZ_calibration = 0
        self.accX_calibration = 0
        self.accY_calibration = 0
        self.accZ_calibration = 0
        while i < 100:
			#在self.address从属设备中的MPU6050_REG_READ_SENSORS地址读取14个字节到self.captures;
            self.i2c.readfrom_mem_into(self.address, MPU6050_REG_READ_SENSORS, self.captures)
            self.acc()
            self.accX_calibration += self.accX
            self.accY_calibration += self.accY
            self.accZ_calibration += self.accZ
			self.gyro()
            self.gyroX_calibration += self.gyroX
            self.gyroY_calibration += self.gyroY
            self.gyroZ_calibration += self.gyroZ
            i += 1
            time.sleep(0.100)#每100ms读取一次值,读取100次10s求平均值,第一次初始化时求出陀螺仪6轴初始平均值
        self.accX_calibration /= 100
        self.accY_calibration /= 100
        self.accZ_calibration /= 100
        self.gyroX_calibration /= 100
        self.gyroY_calibration /= 100
        self.gyroZ_calibration /= 100
		
    def angle(self):
        self.temps_precedent = self.temps#第一次是初始化完成后开始时间,也即开始调用时间;
        self.temps = time.ticks_ms()
        self.interval = time.ticks_diff(self.temps, self.temps_precedent) / 1000#dt两次采样时间间隔,
		
		self.aX = self.accX_calibre / 16384.0  # +/-2g,32767/2=16384LSB/g
        self.aY = self.accY_calibre / 16384.0
        self.aZ = self.accZ_calibre / 16384.0	
		
		#DMP输出的姿态:Pitch(Y)范围是-90~90,Roll(X)范围-180~180,Yaw(Z)范围-180~180
		#atan(y / x):-PI/2<θ<PI/2;atan2(y, x):-PI<θ=PI (直接计算公式)
		self.accX_angle=atan2(self.aY,self.aZ)*57.3#angel_X=roll=atan2(Accel_Y,Accel_Z)*180/PI
		self.accY_angle=atan2(self.aX,self.aZ)*57.3#angel_Y=pitch=atan2(Accel_X,Accel_Z)*180/PI
		
		'''
		self.accX_angle = math.degrees (math.atan(self.aY / math.sqrt((self.aX * self.aX) + (self.aZ * self.aZ))))#accX_Roll
        self.accY_angle = math.degrees (math.atan(-1 * self.aX / math.sqrt((self.aY * self.aY) + (self.aZ * self.aZ))))#accY_Pitch	
        self.accZ_angle = math.degrees (math.atan(math.sqrt((self.aX * self.aX) + (self.aY * self.aY)) / self.aZ ))
        '''
		self.gyroX_angle = self.gyroX_calibre / 16.4  #  +/- 2000deg/s,65536/4000=16.4LSB/(°/s)
        self.gyroY_angle = self.gyroY_calibre / 16.4
        self.gyroZ_angle = self.gyroZ_calibre / 16.4
		#self.gyroX_angle=self.gyroX_angle + self.gyroX_angle * self.interval(正规积分累加值计算)
		
		#一阶互补滤波		
		self.AngleX = 0.98 * (self.AngleX + self.gyroX_angle * self.intervalle) + 0.02 * self.accX_angle#Roll
        self.AngleY = 0.98 * (self.AngleY + self.gyroY_angle * self.intervalle) + 0.02 * self.accY_angle#Pitch
        self.AngleZ = 0.98 * (self.AngleZ + self.gyroZ_angle * self.intervalle) + 0.02 * self.accZ_angle#Yaw
		'''
		不管是四元数解算还是MPU6050读出的Z轴角速度积分解算,静止不动时Yaw会很缓慢的增大,
		静止时Z轴角速度输出并不干净,不是绝对干净的0,所以在积分作用下会缓慢变化。	
        '''

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值