視頻在這里:
第17章-用6050走直線和轉(zhuǎn)90度功能
17.1-6050姿態(tài)數(shù)據(jù)讀取
STM32讀取6050數(shù)據(jù)
先把我們的參考?xì)v程里面的6050文件復(fù)制過(guò)去
添加文件
然后在魔術(shù)棒添加上面兩個(gè)的路徑,不再截圖了。
簡(jiǎn)單閱讀代碼,知道 我們需要設(shè)置兩個(gè)引腳,這兩個(gè)引腳使用模擬IIC讀取6050數(shù)據(jù)
1.在mpuiic.c延時(shí)使用自己寫的、引腳需要使用兩個(gè)先設(shè)置推挽輸出、高電平
void mpuiic_Delayus(uint32_t usdelay)
{
__IO uint32_t Delay = usdelay * (SystemCoreClock /8U/1000U/1000);//SystemCoreClock:系統(tǒng)頻率
do
{
__NOP();//使用空指令延時(shí)、移植不同單片機(jī)注意__NOP(); 執(zhí)行時(shí)間
}
while (Delay --);
}
//MPU IIC 延時(shí)函數(shù)
void MPU_IIC_Delay(void)
{
mpuiic_Delayus(2);
}
//初始化IIC
void MPU_IIC_Init(void)
{
// GPIO_InitTypeDef GPIO_InitStructure;
//
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//先使能外設(shè)IO PORTB時(shí)鐘
//
// 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); //根據(jù)設(shè)定參數(shù)初始化GPIO
//
// GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11); //PB10,PB11 輸出高
}
使用軟件初始化兩個(gè)引腳
6050_SDA–PB9
6050_SCL–PB8
PB8-輸出模式-起始輸出高電平
PB9 輸出模式 起始狀態(tài)高電平
生成代碼
打開我們的代碼,是通過(guò)模擬IIC 讀取6050數(shù)據(jù)的,我們知道SDA是模擬IIC的數(shù)據(jù)線 所以通信過(guò)程中是再輸入和輸出模式中切換的,但是我們的STM32CubeMX是設(shè)置的輸出,是在哪里更改的模式那?
是通過(guò)寄存器設(shè)置的,在mpuiic.h可以看到
刪除掉#include “sys.h”
把這個(gè)修改了
2.在mpuiic.h更改相內(nèi)容
改成下面這樣的
//IO方向設(shè)置 設(shè)置SDA-PB9為輸入或者輸出
#define MPU_SDA_IN() {GPIOB->CRH&=0XFFFFFF0F;GPIOB->CRH|=8<<4;}
#define MPU_SDA_OUT() {GPIOB->CRH&=0XFFFFFF0F;GPIOB->CRH|=3<<4;}
- 這是通過(guò)按位與后賦值 &= 和 按位或后賦值 |=
- 設(shè)置端口配置高寄存器指定位。
先看一個(gè)例子
更改設(shè)置SDA與SCL電平的宏
//IO操作函數(shù)
#define MPU_IIC_SCL_Hige HAL_GPIO_WritePin(SCL_6050_GPIO_Port,SCL_6050_Pin,GPIO_PIN_SET)//設(shè)置SCL高電平
#define MPU_IIC_SCL_Low HAL_GPIO_WritePin(SCL_6050_GPIO_Port,SCL_6050_Pin,GPIO_PIN_RESET)//設(shè)置SCL低電平
#define MPU_IIC_SDA_Hige HAL_GPIO_WritePin(SDA_6050_GPIO_Port,SDA_6050_Pin,GPIO_PIN_SET) //設(shè)置SDA高電平
#define MPU_IIC_SDA_Low HAL_GPIO_WritePin(SDA_6050_GPIO_Port,SDA_6050_Pin,GPIO_PIN_RESET) //設(shè)置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
可以一個(gè)文件一個(gè)文件的替換掉,如果整個(gè)工程替換其他HAL庫(kù)文件內(nèi)容也可能改變了
刪除多余的庫(kù)文件
注釋掉
如果有其他的delay_ms 都替換為HAL_Delay
還有一個(gè)錯(cuò)誤
if((txd&0x80)>>7) MPU_IIC_SDA_Hige;
else MPU_IIC_SDA_Low;
編譯一下 、沒有錯(cuò)誤和警告
然后在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);//延時(shí)0.5秒 6050上電穩(wěn)定后初始化
MPU_Init(); //初始化MPU6050
while(MPU_Init()!=0);
while(mpu_dmp_init()!=0);
我們通過(guò)下面的代碼獲得數(shù)據(jù)
sprintf((char *)Usart3String,"pitch:%.2f roll:%.2f yaw:%.2frn",pitch,roll,yaw);//顯示6050數(shù)據(jù)
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),0xFFFF);//通過(guò)串口三輸出字符 strlen:計(jì)算字符串大小
//mpu_dmp_get_data(&pitch,&roll,&yaw);//返回值:0,DMP成功解出歐拉角
while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){} //這個(gè)可以解決經(jīng)常讀不出數(shù)據(jù)的問(wèn)題
然后我看一下 這個(gè)Usart3String 現(xiàn)在發(fā)送的大概多大的?
uint8_t OledString[50];
uint8_t Usart3String[50];
編譯、燒錄、然后就可以連接手機(jī)藍(lán)牙,在藍(lán)牙軟件查看數(shù)據(jù)了
17.2-利用6050直線和90度(有代碼)
為什么小車還是不能走直線
為什么兩個(gè)電機(jī)轉(zhuǎn)速一樣不能走非常正直線,如何控制小車轉(zhuǎn)彎90度。
當(dāng)然,我們可以開環(huán)控制,但是控制效果可能不好,受外界影響比較大。
如果我們使用閉環(huán)控制,就要使用一個(gè)傳感器來(lái)獲得現(xiàn)在小車角度。
https://www.bilibili.com/video/BV1UV4y1p7Hd/?spm_id_from=333.337.search-card.all.click
走直線(控制朝一個(gè)方向運(yùn)動(dòng))
在pid.c中定義一個(gè)姿態(tài)控制使用的PID
tPid pidMPU6050YawMovement; //利用6050偏航角 進(jìn)行姿態(tài)控制的PID
pidMPU6050YawMovement.actual_val=0.0;
pidMPU6050YawMovement.target_val=0.00;//設(shè)定姿態(tài)目標(biāo)值
pidMPU6050YawMovement.err=0.0;
pidMPU6050YawMovement.err_last=0.0;
pidMPU6050YawMovement.err_sum=0.0;
pidMPU6050YawMovement.Kp=2;//定距離跟隨的Kp大小通過(guò)估算PID輸入輸出數(shù)據(jù),確定大概大小,然后在調(diào)試
pidMPU6050YawMovement.Ki=0;
pidMPU6050YawMovement.Kd=0;
仿照之前紅外循跡代碼編寫姿態(tài)控制函數(shù)
float g_fMPU6050YawMovePidOut = 0.00f; //姿態(tài)PID運(yùn)算輸出
float g_fMPU6050YawMovePidOut1 = 0.00f; //第一個(gè)電機(jī)控制輸出
float g_fMPU6050YawMovePidOut2 = 0.00f; //第一個(gè)電機(jī)控制輸出
走直線程序如下(因?yàn)樯想姵跏蓟瘯r(shí)候航向角是0、而且pidMPU6050YawMovementPID結(jié)構(gòu)體的目標(biāo)值target_val 也是0)
//*************MPU6050航向角 PID轉(zhuǎn)向控制*****************//
sprintf((char *)Usart3String,"pitch:%.2f roll:%.2f yaw:%.2frn",pitch,roll,yaw);//顯示6050數(shù)據(jù) 俯仰角 橫滾角 航向角
HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),0xFFFF);//通過(guò)串口三輸出字符 strlen:計(jì)算字符串大小
//mpu_dmp_get_data(&pitch,&roll,&yaw);//返回值:0,DMP成功解出歐拉角
while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){} //這個(gè)可以解決經(jīng)常讀不出數(shù)據(jù)的問(wèn)題
g_fMPU6050YawMovePidOut = PID_realize(&pidMPU6050YawMovement,yaw);//PID計(jì)算輸出目標(biāo)速度 這個(gè)速度,會(huì)和基礎(chǔ)速度加減
g_fMPU6050YawMovePidOut1 = 1.5 + g_fMPU6050YawMovePidOut;//基礎(chǔ)速度加減PID輸出速度
g_fMPU6050YawMovePidOut2 = 1.5 - g_fMPU6050YawMovePidOut;
if(g_fMPU6050YawMovePidOut1 >3.5) g_fMPU6050YawMovePidOut1 =3.5;//進(jìn)行限幅
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);
然后調(diào)節(jié)PID參數(shù)
順序 先確定P 正負(fù) 然后P大小
然后D正負(fù) 然后D大小
最后調(diào)節(jié)的參數(shù)如下
pidMPU6050YawMovement.Kp=0.02;//6050航向角PID運(yùn)動(dòng)控制
pidMPU6050YawMovement.Ki=0;
pidMPU6050YawMovement.Kd=0.1;
然后我們把小車放在地上就可以完成一直朝著初始方向前進(jìn),如果往側(cè)面推也會(huì)馬上矯正。
轉(zhuǎn)彎90度功能(控制轉(zhuǎn)彎角度)
然后我們?cè)黾右幌?,如何旋轉(zhuǎn)90度程序
在串口接收回調(diào)函數(shù)表姿態(tài)PID的目標(biāo)值
extern tPid pidMPU6050YawMovement; //利用6050偏航角 進(jìn)行姿態(tài)控制的PID
if(g_ucUsart3ReceiveData == 'H')//轉(zhuǎn)向90度
{
if(pidMPU6050YawMovement.target_val <= 180)pidMPU6050YawMovement.target_val += 90;//目標(biāo)值
}
if(g_ucUsart3ReceiveData == 'I')//轉(zhuǎn)回90度
{
if(pidMPU6050YawMovement.target_val >= -180)pidMPU6050YawMovement.target_val -= 90;//目標(biāo)值
}
然后我們的藍(lán)牙APP增加兩個(gè)發(fā)送按鈕的設(shè)置
現(xiàn)象 是上電小車向初始方向直行,如果推小車車頭方向,小車能夠立馬矯正。
然后連接藍(lán)牙發(fā)送轉(zhuǎn)90度 小車會(huì)轉(zhuǎn)90度,按下 轉(zhuǎn)回90度小車回轉(zhuǎn)回。
這樣我們就把6050轉(zhuǎn)向程序?qū)懲炅?,下面開始 把上面代碼如何結(jié)合一下,然后講解如何增加視覺功能。
聯(lián)系:Q,1930299709