视频在这里:
第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;}
- 这是通过按位与后赋值 &= 和 按位或后赋值 |=
- 设置端口配置高寄存器指定位。
先看一个例子
更改设置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:%.2frn",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:%.2frn",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转向程序写完了,下面开始 把上面代码如何结合一下,然后讲解如何增加视觉功能。
联系:Q,1930299709