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;
}
相关推荐
Coovally AI模型快速验证34 分钟前
MMYOLO:打破单一模式限制,多模态目标检测的革命性突破!
人工智能·算法·yolo·目标检测·机器学习·计算机视觉·目标跟踪
雯宝1 小时前
STM32 GPIO工作模式
stm32·单片机·嵌入式硬件
可为测控1 小时前
图像处理基础(4):高斯滤波器详解
人工智能·算法·计算机视觉
Milk夜雨2 小时前
头歌实训作业 算法设计与分析-贪心算法(第3关:活动安排问题)
算法·贪心算法
BoBoo文睡不醒2 小时前
动态规划(DP)(细致讲解+例题分析)
算法·动态规划
辰哥单片机设计2 小时前
STM32项目分享:智能厨房安全检测系统
stm32·单片机·嵌入式硬件
apz_end2 小时前
埃氏算法C++实现: 快速输出质数( 素数 )
开发语言·c++·算法·埃氏算法
仟濹3 小时前
【贪心算法】洛谷P1106 - 删数问题
c语言·c++·算法·贪心算法
CM莫问4 小时前
python实战(十五)——中文手写体数字图像CNN分类
人工智能·python·深度学习·算法·cnn·图像分类·手写体识别
sz66cm4 小时前
LeetCode刷题 -- 45.跳跃游戏 II
算法·leetcode