第17章-用6050走直线和转90度功能 平衡车入门---MPU6050陀螺仪的使用 超详细陀螺仪MPU6050模块输出姿态角(有完整版源码)

这个是全网最详细的STM32项目教学视频。
第一篇在这里:
视频在这里:

STM32智能小车V3-STM32入门教程-openmv与STM32循迹小车-stm32f103c8t6-电赛 嵌入式学习 PID控制算法 编码器电机 跟随

第17章-用6050走直线和转90度功能

17.1-6050姿态数据读取

STM32读取6050数据

先把我们的参考历程里面的6050文件复制过去
在这里插入图片描述
添加文件
在这里插入图片描述
在这里插入图片描述
然后在魔术棒添加上面两个的路径,不再截图了。
简单阅读代码,知道 我们需要设置两个引脚,这两个引脚使用模拟IIC读取6050数据
1.在mpuiic.c延时使用自己写的、引脚需要使用两个先设置推挽输出、高电平
在这里插入图片描述

void mpuiic_Delayus(uint32_t usdelay)
{
  __IO uint32_t Delay = usdelay * (SystemCoreClock /8U/1000U/1000);//SystemCoreClock:系统频率
  do
  {
    __NOP();//使用空指令延时、移植不同单片机注意__NOP(); 执行时间
  }
  while (Delay --);
}
  //MPU IIC 延时函数
void MPU_IIC_Delay(void)
{
	mpuiic_Delayus(2);
}

//初始化IIC
void MPU_IIC_Init(void)
{					     
//  GPIO_InitTypeDef  GPIO_InitStructure;
//	
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//先使能外设IO PORTB时钟 
//		
//  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;	 // 端口配置
//  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
//  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
//  GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIO 
//	
//  GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11);						 //PB10,PB11 输出高	
 
}

使用软件初始化两个引脚

6050_SDA–PB9

6050_SCL–PB8
在这里插入图片描述
PB8-输出模式-起始输出高电平
在这里插入图片描述
PB9 输出模式 起始状态高电平
在这里插入图片描述
生成代码

打开我们的代码,是通过模拟IIC 读取6050数据的,我们知道SDA是模拟IIC的数据线 所以通信过程中是再输入和输出模式中切换的,但是我们的STM32CubeMX是设置的输出,是在哪里更改的模式那?

是通过寄存器设置的,在mpuiic.h可以看到

删除掉#include “sys.h”

把这个修改了
在这里插入图片描述
2.在mpuiic.h更改相内容

改成下面这样的
在这里插入图片描述

//IO方向设置 设置SDA-PB9为输入或者输出
#define MPU_SDA_IN()  {GPIOB->CRH&=0XFFFFFF0F;GPIOB->CRH|=8<<4;}
#define MPU_SDA_OUT() {GPIOB->CRH&=0XFFFFFF0F;GPIOB->CRH|=3<<4;}
  1. 这是通过按位与后赋值 &=按位或后赋值 |=

  2. 设置端口配置高寄存器指定位。

先看一个例子
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
更改设置SDA与SCL电平的宏
在这里插入图片描述

//IO操作函数	 
#define MPU_IIC_SCL_Hige    	HAL_GPIO_WritePin(SCL_6050_GPIO_Port,SCL_6050_Pin,GPIO_PIN_SET)//设置SCL高电平
#define MPU_IIC_SCL_Low      	HAL_GPIO_WritePin(SCL_6050_GPIO_Port,SCL_6050_Pin,GPIO_PIN_RESET)//设置SCL低电平
#define MPU_IIC_SDA_Hige        HAL_GPIO_WritePin(SDA_6050_GPIO_Port,SDA_6050_Pin,GPIO_PIN_SET)   //设置SDA高电平
#define MPU_IIC_SDA_Low         HAL_GPIO_WritePin(SDA_6050_GPIO_Port,SDA_6050_Pin,GPIO_PIN_RESET) //设置SDA低电平
  	 
#define MPU_READ_SDA            HAL_GPIO_ReadPin(SDA_6050_GPIO_Port,SDA_6050_Pin)    //读SDA电平

更改一下 mupiic.c文件

//把之前的MPU_IIC_SDA=1;	 换成 MPU_IIC_SDA_Hige;
//MPU_IIC_SDA=0;	 换成 MPU_IIC_SDA_Low;
//MPU_IIC_SCL=1;  换成 MPU_IIC_SCL_Hige;
//MPU_IIC_SCL=0;  换成 MPU_IIC_SCL_Low;
//

编译一下、删掉没有用的文件

把u8 替换为uint8_t
在这里插入图片描述
t替换一下,u8 替换为uint8_t u32替换为uint32_t

可以一个文件一个文件的替换掉,如果整个工程替换其他HAL库文件内容也可能改变了
在这里插入图片描述
删除多余的库文件

注释掉
在这里插入图片描述
如果有其他的delay_ms 都替换为HAL_Delay

还有一个错误

		if((txd&0x80)>>7) MPU_IIC_SDA_Hige;
		else MPU_IIC_SDA_Low;

在这里插入图片描述
编译一下 、没有错误和警告

然后在main.c中定义变量和添加同文件

float pitch,roll,yaw; // 俯仰角 横滚角 航向角

#include "mpu6050.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h" 

在这里插入图片描述
替换inv_mpu.h的

#include "stm32f1xx_it.h"

在这里插入图片描述
初始化6050

  HAL_Delay(500);//延时0.5秒 6050上电稳定后初始化
  MPU_Init(); //初始化MPU6050
  while(MPU_Init()!=0);
  while(mpu_dmp_init()!=0);

在这里插入图片描述
我们通过下面的代码获得数据

   	sprintf((char *)Usart3String,"pitch:%.2f roll:%.2f yaw:%.2f\r\n",pitch,roll,yaw);//显示6050数据
	HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),0xFFFF);//通过串口三输出字符 strlen:计算字符串大小	
   
   //mpu_dmp_get_data(&pitch,&roll,&yaw);//返回值:0,DMP成功解出欧拉角
    while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){}  //这个可以解决经常读不出数据的问题

在这里插入图片描述
然后我看一下 这个Usart3String 现在发送的大概多大的?
在这里插入图片描述

uint8_t OledString[50];
uint8_t Usart3String[50];

编译、烧录、然后就可以连接手机蓝牙,在蓝牙软件查看数据了
在这里插入图片描述

17.2-利用6050直线和90度(有代码)

为什么小车还是不能走直线

为什么两个电机转速一样不能走非常正直线,如何控制小车转弯90度。

当然,我们可以开环控制,但是控制效果可能不好,受外界影响比较大。

如果我们使用闭环控制,就要使用一个传感器来获得现在小车角度。
在这里插入图片描述
https://www.bilibili.com/video/BV1UV4y1p7Hd/?spm_id_from=333.337.search-card.all.click

走直线(控制朝一个方向运动)

在pid.c中定义一个姿态控制使用的PID
在这里插入图片描述

tPid pidMPU6050YawMovement;  //利用6050偏航角 进行姿态控制的PID

在这里插入图片描述

	pidMPU6050YawMovement.actual_val=0.0;
	pidMPU6050YawMovement.target_val=0.00;//设定姿态目标值
	pidMPU6050YawMovement.err=0.0;
	pidMPU6050YawMovement.err_last=0.0;
	pidMPU6050YawMovement.err_sum=0.0;
	pidMPU6050YawMovement.Kp=2;//定距离跟随的Kp大小通过估算PID输入输出数据,确定大概大小,然后在调试
	pidMPU6050YawMovement.Ki=0;
	pidMPU6050YawMovement.Kd=0;

仿照之前红外循迹代码编写姿态控制函数
在这里插入图片描述

float  g_fMPU6050YawMovePidOut = 0.00f; //姿态PID运算输出
float  g_fMPU6050YawMovePidOut1 = 0.00f; //第一个电机控制输出
float  g_fMPU6050YawMovePidOut2 = 0.00f; //第一个电机控制输出

走直线程序如下(因为上电初始化时候航向角是0、而且pidMPU6050YawMovementPID结构体的目标值target_val 也是0)
在这里插入图片描述


//*************MPU6050航向角 PID转向控制*****************//

   	sprintf((char *)Usart3String,"pitch:%.2f roll:%.2f yaw:%.2f\r\n",pitch,roll,yaw);//显示6050数据 俯仰角 横滚角 航向角
	HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const  char  *)Usart3String),0xFFFF);//通过串口三输出字符 strlen:计算字符串大小	
   
   //mpu_dmp_get_data(&pitch,&roll,&yaw);//返回值:0,DMP成功解出欧拉角
    while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){}  //这个可以解决经常读不出数据的问题
	
	
	g_fMPU6050YawMovePidOut = PID_realize(&pidMPU6050YawMovement,yaw);//PID计算输出目标速度 这个速度,会和基础速度加减

	g_fMPU6050YawMovePidOut1 = 1.5 + g_fMPU6050YawMovePidOut;//基础速度加减PID输出速度
	g_fMPU6050YawMovePidOut2 = 1.5 - g_fMPU6050YawMovePidOut;
	if(g_fMPU6050YawMovePidOut1 >3.5) g_fMPU6050YawMovePidOut1 =3.5;//进行限幅
	if(g_fMPU6050YawMovePidOut1 <0) g_fMPU6050YawMovePidOut1 =0;
	if(g_fMPU6050YawMovePidOut2 >3.5) g_fMPU6050YawMovePidOut2 =3.5;
	if(g_fMPU6050YawMovePidOut2 <0) g_fMPU6050YawMovePidOut2 =0;
	motorPidSetSpeed(g_fMPU6050YawMovePidOut1,g_fMPU6050YawMovePidOut2);

然后调节PID参数

顺序 先确定P 正负 然后P大小

然后D正负 然后D大小

最后调节的参数如下
在这里插入图片描述

	pidMPU6050YawMovement.Kp=0.02;//6050航向角PID运动控制 
	pidMPU6050YawMovement.Ki=0;
	pidMPU6050YawMovement.Kd=0.1;

然后我们把小车放在地上就可以完成一直朝着初始方向前进,如果往侧面推也会马上矫正。

转弯90度功能(控制转弯角度)

然后我们增加一下,如何旋转90度程序

在串口接收回调函数表姿态PID的目标值
在这里插入图片描述

extern tPid pidMPU6050YawMovement;  //利用6050偏航角 进行姿态控制的PID

在这里插入图片描述

		if(g_ucUsart3ReceiveData == 'H')//转向90度
		{				
			if(pidMPU6050YawMovement.target_val <= 180)pidMPU6050YawMovement.target_val += 90;//目标值
		}
		if(g_ucUsart3ReceiveData == 'I')//转回90度
		{				
			if(pidMPU6050YawMovement.target_val >= -180)pidMPU6050YawMovement.target_val -= 90;//目标值
        }	

然后我们的蓝牙APP增加两个发送按钮的设置
在这里插入图片描述
现象 是上电小车向初始方向直行,如果推小车车头方向,小车能够立马矫正。

然后连接蓝牙发送转90度 小车会转90度,按下 转回90度小车回转回。

这样我们就把6050转向程序写完了,下面开始 把上面代码如何结合一下,然后讲解如何增加视觉功能。

  • 36
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 要实现MPU6050控制直线,可以按照以下步骤进行操作。 首先,需要将MPU6050传感器与小主控板进行连接。MPU6050传感器有多个引脚,例如VCC、GND、SCL、SDA等,需要根据具体的硬件情况进行正确的连接。 接下来,需要编写代码来读取MPU6050传感器的数据。可以使用适当的库函数或者驱动来实现这一步骤。通过读取传感器的数据,可以获取小的加速信息。 然后,需要对于读取到的加速数据进行处理。可以使用滤波算法,如卡尔曼滤波器来优化数据的准确性。处理后的数据可以用来控制的运动。 接下来就是控制的行进方向和速。可以根据小的设计情况,使用适当的电机控制方法来实现。例如,可以通过PWM信号控制电机的速和方向,进而控制的运动。 最后,根据读取到的传感器数据和控制方法,设计合适的算法来实现小直线。例如,可以通过控制向和加速来保持小直线上的平衡,并弥补传感器的误差。 需要注意的是,实现MPU6050控制直线是一个复杂的过程,需要对硬件和软件进行深入的理解和设计。同时,还需要根据具体的应用场景进行适当的调整和优化。因此,建议在具体操作之前,先查阅相关的资料和文档,了解相关的知识和技术。如果遇到问题,可以咨询相关的专业人士或者技术支持。 ### 回答2: 要实现MPU6050控制直线,我们需要进行以下几个步骤: 1. 硬件连接:将MPU6050传感器与控制的主控板进行正确的电路连接。通常,MPU6050有6个引脚,包括电源引脚、地引脚、SCL引脚、SDA引脚、INT引脚和AD0引脚。正确连接各引脚至主控板相应的引脚。 2. 软件编程:使用合适的编程语言(如C++或Arduino语言),编写程序以读取MPU6050传感器的数据并控制直线。首先,需要初始化MPU6050传感器,设置合适的采样率和滤波器参数。然后,通过读取MPU6050传感器的加速计和陀螺仪数据,计算小需要调整的方向和速。根据所得的数据,调整小的电机速,使其保持直线行驶。 3. 数据处理:根据MPU6050传感器读取的数据,判断小是否偏离了直线。如果检测到偏移,需要根据偏移的方向和幅来调整小的行驶方向和速。可以使用比例控制、PID控制或其他自动控制算法来实现精确的控制。 4. 实时反馈:为了实现更精确的控制,可以利用小上的其他传感器(例如编码器)来实时检测小的行驶状态,并将其反馈给MPU6050传感器的控制算法。通过实时反馈,可以更准确地调整小的行驶方向和速,从而实现更直线的行驶效果。 总之,实现MPU6050控制直线需要正确连接硬件、编写合适的软件程序,根据传感器数据进行精确的控制,并通过实时反馈来进行优化。通过这些步骤,我们可以实现小在不倾斜的情况下保持直线行驶。 ### 回答3: 实现MPU6050控制直线,需要进行以下步骤: 首先,确保MPU6050传感器与小控制器(如Arduino)正确连接。将MPU6050的SCL和SDA引脚连接到相应的Arduino引脚,并通过I2C协议进行通信。 其次,通过编程读取MPU6050传感器的原始数据。通过使用适当的库,你可以获得加速计和陀螺仪的数据。加速计可以用于检测小的倾斜,而陀螺仪可以提供小。 接下来,对读取的数据进行处理。首先,可以通过将加速计数据进行平滑处理,获得小的倾斜。其次,可以通过对陀螺仪数据进行积分,获得小变化。 然后,根据处理后的数据调整小的电机输出。根据小的倾斜变化,可以将相应的修正值应用于左右电机的输出,以使小保持在直线上。 最后,反复读取和处理数据,并持续调整电机输出,以保持小直线上平稳移动。 需要注意的是,实现MPU6050控制直线还需要考虑其他因素,例如小的重心位置、轮子的摩擦力等。因此,可能需要进行一些试验和调试,以找到最佳的控制方式。同时,根据具体的需求和条件,可以灵活调整控制算法和参数。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值