MPU6050

一、运动传感器与姿态测量

1、欧拉角

欧拉角:以运动物体建立坐标系,通过绕轴旋转来表示运动物体当前的姿态

(Yaw -偏航角 Roll-翻滚角)

(Pitch -俯仰角)

2、加速度计测量姿态

加速度计,也被称为重力传感器G-Sensor,是一种测量物体加速度的传感器

加速度计通过测量物体在三个轴向上的加速度来推算物体的姿态。在静止或匀速直线运动状态下,加速度计可以准确地测量出重力加速度在三个轴向上的分量,从而推算出物体的俯仰角(Pitch)和横滚角(Roll)。然而,由于加速度计无法直接测量绕垂直轴的旋转(即偏航角Yaw),因此无法单独测量出完整的欧拉角。

优点:能直接算出欧拉角

缺点:外部震动会引入噪声

3、陀螺仪测量姿态

陀螺仪是一种测量角速度的传感器,它可以感知物体绕三个轴的旋转角速度。通过积分陀螺仪输出的角速度信号,可以得到物体的旋转角度,从而推算出欧拉角。然而,陀螺仪的积分过程会导致误差的累积,特别是在长时间运行或受到较大干扰时,误差会显著增加。

优点:准确、无干扰

缺点:误差会累积

4、传感器融合

加速度计和陀螺仪在测量欧拉角时的优缺点:

为了克服加速度计和陀螺仪各自的缺点,提高姿态测量的准确性和稳定性,通常会将两者的数据进行融合。数据融合的方法有多种,包括互补滤波、卡尔曼滤波等。这里利用的是互补滤波的方法,它利用加速度计在静止或匀速直线运动状态下测量准确的优点,以及陀螺仪在动态过程中测量角速度的优点,通过加权平均或叉乘运算将两者的数据进行融合。这种方法可以减小陀螺仪积分过程中的误差累积,同时提高加速度计在动态过程中的响应速度。

二、MPU6050介绍

说明:

DMP(Digital Motion Processor,数字运动处理器)是一种专门用于处理和分析运动数据的集成电路或处理器。DMP通常与传感器(如加速度计、陀螺仪和磁力计)结合使用,以提供精确、实时的姿态和运动信息。

工作原理:DMP通过内置的算法和滤波器对传感器数据进行处理,从而提取出有用的运动信息。这些算法可以包括姿态估计、运动分类、步态分析等。DMP能够高效地处理传感器数据,减少噪声和误差的影响,提供准确的运动参数。

三、MPU6050通信及配置

1、通信方式

IIC通信,可支持快速IIC

2、器件地址

有一个引脚可以产生逻辑电平0 1

如果地址引脚接地 七位器件地址0x68

如果地址引脚接高 七位器件地址0x69

我们板子默认 接地 七位器件地址0x68

注意,要加读写控制位

写: (0x68 << 1) //0xd0

读: (0x68 << 1) | 0x01 //0xd1

3、MUP6050通信时序

1.主控芯片发送一个字节到MPU6050

设置一个寄存器的时序

2.主控芯片发送多个字节到MPU6050

设置地址连续的多个寄存器

3.主控芯片从MPU6050中读一个字节回来

读某一个寄存器里面的值

4.主控芯片从MPU6050中连续读多个字节回来

读地址连续的多个寄存器的值,比如读xyz方向的值

四、MPU6050相关寄存器

MPU6050初始化就是把上面的寄存器配置

五、MPU6050获取陀螺仪和加速度数据

初始化后,发送数据寄存器地址,就可以读到数据寄存器的内容,将两个8位数据合成16位数据

带入到公式中就可以得到具体角度值和加速度值

说明:

数据寄存器因为地址连续,所以可以连续读出

六、MPU6050程序设计

①IIC通信相关程序

/***********************************************
*函数名    :iic_IO_init
*函数功能  :IIC所用IO口初始化配置
*函数参数  :无
*函数返回值:无
*函数描述  :SCL----PB8
            SDA----PB9
************************************************/
void iic_IO_init(void)
{
	//端口时钟使能
	RCC->AHB1ENR |= (1<<1);
	//端口模式配置
	GPIOB->MODER &= ~((3<<16)|(3<<18));
	GPIOB->MODER |= ((1<<16)|(1<<18));
	//输出类型
	GPIOB->OTYPER &= ~(1<<8);         //时钟线配置位推挽输出
	GPIOB->OTYPER |= (1<<9);          //数据线配置为开漏输出
	//输出速度
	GPIOB->OSPEEDR &= ~((3<<16)|(3<<18));
	//上下拉
	GPIOB->PUPDR &= ~((3<<16)|(3<<18));
	//输出数据寄存器让时钟线和数据线处于空闲转态
	GPIOB->ODR |= ((1<<8) | (1<<9));
}


/***********************************************
*函数名    :iic_star
*函数功能  :IIC起始信号函数
*函数参数  :无
*函数返回值:无
*函数描述  :         
************************************************/
void iic_star(void)
{
	//时钟线拉低    可以动数据线
	IIC_SCL_L;
	//数据线拉高    保证可以出现下降沿
	IIC_SDA_OUT_H;
	
	
	//时钟线拉高    起始信号的条件
	IIC_SCL_H;
	TIM11_delay_us(5);
	//数据线拉低    产生了起始信号
	IIC_SDA_OUT_L;
	TIM11_delay_us(5);
	
	IIC_SCL_L;//安全作用
}



/***********************************************
*函数名    :iic_stop
*函数功能  :IIC停止信号函数
*函数参数  :无
*函数返回值:无
*函数描述  :         
************************************************/
void iic_stop(void)
{
	IIC_SCL_L;
	IIC_SDA_OUT_L;
	
	IIC_SCL_H;
	TIM11_delay_us(5);
	IIC_SDA_OUT_H;
	TIM11_delay_us(5);
	
}




/***********************************************
*函数名    :iic_send_ack
*函数功能  :IIC发送应答/不应答信号函数
*函数参数  :u8 ack   
*函数返回值:无
*函数描述  :ack  传入 0   表示发送应答
            ack  传入 1   表示发送不应答
************************************************/
void iic_send_ack(u8 ack)
{
	IIC_SCL_L;
	TIM11_delay_us(3);
	
	if(ack == 0) IIC_SDA_OUT_L;
	else         IIC_SDA_OUT_H;  
	TIM11_delay_us(2);
	
	IIC_SCL_H;
	TIM11_delay_us(5); 
	
	IIC_SCL_L;//安全作用
}



/***********************************************
*函数名    :iic_get_ack
*函数功能  :IIC检测应答/不应答信号函数
*函数参数  :无   
*函数返回值:u8
*函数描述  :0    应答信号
            1    不应答信号
************************************************/
u8 iic_get_ack(void)
{
	u8 ack;
	
	/*将数据线切换位输入模式*/
	IIC_SCL_L;
	IIC_SDA_OUT_H;  
	
	/*检测应答*/
	IIC_SCL_L;      //主机帮助从机把时钟线拉低,从机才可以自动改变数据线
	TIM11_delay_us(5);
	IIC_SCL_H;      //主机拉高时钟线才可以读数据线
	TIM11_delay_us(5);
	if(IIC_SDA_IN)   ack = 1;    //不应答信号
	else             ack = 0;    //应答信号
	
	
	IIC_SCL_L;    //安全作用
	return ack;
}




/***********************************************
*函数名    :iic_send_byte
*函数功能  :IIC发送一个字节函数
*函数参数  :u8 data  
*函数返回值:无
*函数描述  :
************************************************/
void iic_send_byte(u8 data)
{
	u8 i;
	
	for(i=0;i<8;i++)
	{
		IIC_SCL_L;
		TIM11_delay_us(3);
		
		if(data & 0x80)
		{
			IIC_SDA_OUT_H;  
		}
		else 
		{
			IIC_SDA_OUT_L;
		}
		TIM11_delay_us(2);
		
		IIC_SCL_H;       //帮助从机拉高时钟线,从机才可以读这一位数据
		TIM11_delay_us(5);
		
		//下一位数据
		data = data << 1;
		
	}
	
	IIC_SCL_L;      //安全作用
	
}




/***********************************************
*函数名    :iic_rec_byte
*函数功能  :IIC接收一个字节函数
*函数参数  :无  
*函数返回值:u8
*函数描述  :
************************************************/
u8 iic_rec_byte(void)
{
	u8 i;
	u8 data;
	
	/*IO切换为输入模式*/
	IIC_SCL_L;
	IIC_SDA_OUT_H;  
	
	/*接收一个字节数据*/
	for(i=0;i<8;i++)
	{
		IIC_SCL_L;          //帮助从机拉低时钟线,从才会改变数据线
		TIM11_delay_us(5);
		
		IIC_SCL_H;          //主机可以读数据线
		TIM11_delay_us(5);
	
		data = data << 1;
		if(IIC_SDA_IN)
		{
			data |= 0x01;
		}
	}
	
	IIC_SCL_L;     //安全作用
	
	
	return data;
}

②MPU6050相关程序

主控芯片发送多个字节到MPU6050函数

/***********************************************
*函数名    :mpu6050_Write
*函数功能  :写多个字节数据到MPU6050
*函数参数  :u8 reg, u8 len, u8* data
*函数返回值:无
*函数描述  :
***********************************************/
void mpu6050_Write(u8 reg,u8 len,u8* data)
{
    u8 i;
    iic_star();
	
    iic_send_byte(0x68<<1);     //器件地址+写控制位
    iic_get_ack();
		
    iic_send_byte(reg);         //发送寄存器地址
    iic_get_ack();
	
		//连续发送数据
    for (i = 0; i < len; i++)
		{
        iic_send_byte(data[i]);
        iic_get_ack();
    }
    iic_stop();
    
}

主控芯片从MPU6050中连续读多个字节回来函数

/***********************************************
*函数名    :mup6050_Read
*函数功能  :从MPU6050读多个字节数据
*函数参数  :u8 reg,u8 len, u8* buf
*函数返回值:无
*函数描述  :
***********************************************/
void mup6050_Read(u8 reg,u8 len, u8* buf)
{
    iic_star();
    iic_send_byte(0x68<<1);
    iic_get_ack();
	
    iic_send_byte(reg);       //寄存器的起始地址
    iic_get_ack();
	
	
    iic_star();
    iic_send_byte(0x68<<1 | 0x01);
    iic_get_ack();
	

		while(1)                               
		{
			*buf = iic_rec_byte();   
			len--;
			buf++;	
			if(len == 0)
			{
				iic_send_ack(1);
				break;
			}
			else
			{
				iic_send_ack(0);
			}
		}
	
    iic_stop();
   
}

MPU6050初始化配置函数

/***********************************************
*函数名    :MPU6050_init
*函数功能  :MPU6050_init 初始化配置
*函数参数  :无
*函数返回值:无
*函数描述  :
***********************************************/
void MPU6050_init(void)
{
	u8 re_buff[] = {0x89,0x09,0x18,0x00,0x04,0x13};   //采样频率计算值19 十六进制0x13
	
	/*IIC初始化*/
	iic_IO_init();
	
	/*MPU6050*/
	mpu6050_Write(PWR_MGMT_1,1,&re_buff[0]);     //复位MPU6050
	tim11_delay_ms(100);                           //不放延时会出问题 
	mpu6050_Write(PWR_MGMT_1, 1,&re_buff[1]);     //解除休眠状态
	mpu6050_Write(GYRO_CONFIG, 1,&re_buff[2]);    //陀螺仪范围 2000    16.4
	mpu6050_Write(ACCEL_CONFIG, 1,&re_buff[3]);   //2g                 16384
	mpu6050_Write(CONFIG, 1,&re_buff[4]);         //20带宽  1KHZ
	mpu6050_Write(SMPLRT_DIV, 1,&re_buff[5]);     //采样频率19

}

获取XYZ方向数据函数

/***********************************************
*函数名    :DataSynthesis
*函数功能  :获取某个方向的高低8位数据并且合成16位数据
*函数参数  :寄存器地址
*函数返回值:short
*函数描述  :
***********************************************/
short DataSynthesis(u8 REG_Address)	
{
	u8  uByte[2]; 

	mup6050_Read(REG_Address,2,uByte)  ;

	return ((uByte[0] << 8) | uByte[1]);   /*返回合成数据*/
}



/***********************************************
*函数名    :ReadAcceData
*函数功能  :读加速度和陀螺仪三个方向的数据
*函数参数  :无
*函数返回值:ACCG_t
*函数描述  :
***********************************************/
ACCG_t ReadAcceData(void)
{
	  ACCG_t ag;
		//读加速度
		ag.x_Axis = DataSynthesis(ACCEL_XOUT_H) / 16384.0 ; 
		ag.y_Axis = DataSynthesis(ACCEL_YOUT_H) / 16384.0; 
		ag.z_Axis = DataSynthesis(ACCEL_ZOUT_H) / 16384.0 ; 
		//陀螺仪
		ag.x_Gxis = DataSynthesis(GYRO_XOUT_H)  / 16.4; 
		ag.y_Gxis = DataSynthesis(GYRO_YOUT_H)  / 16.4; 
		ag.z_Gxis = DataSynthesis(GYRO_ZOUT_H)  / 16.4;
	
	
		return ag;
}
相关推荐
St_Ludwig8 分钟前
蓝桥杯疑似例题解答方案(打印任意阶杨辉三角)
c语言·c++·后端·算法·职场和发展·蓝桥杯
xiaobuding_QAQ20 分钟前
基于STM32的智能鱼缸控制系统的Proteus仿真
stm32·嵌入式硬件·proteus·智能鱼缸
心.c41 分钟前
0-1背包问题
c++·算法
kitesxian1 小时前
Leetcode146. LRU 缓存(HOT100)
数据结构·算法·leetcode·缓存
BigCowPeking1 小时前
leetcode 排序算法汇总
算法·leetcode·排序算法
eternal__day1 小时前
优选算法(双指针)
算法·leetcode·推荐算法
武昌库里写JAVA1 小时前
SpringBoot+SpringCloud面试题整理附答案
java·开发语言·算法·spring·log4j
手握风云-1 小时前
数据结构(Java版)第五期:ArrayList与顺序表(下)
java·数据结构·算法
不去幼儿园1 小时前
【RL Base】多级反馈队列(MFQ)算法
人工智能·python·算法·机器学习·强化学习
是糖不是唐1 小时前
代码随想录算法训练营第五十四天|Day54 图论
c语言·数据结构·算法·图论