大家好,我是張巧龍,今天給大家?guī)硪粋€平衡自行車,我實(shí)驗(yàn)室一個19級的本科生做的,他21年也獲得了全國電賽二等獎(F題)的成績。
人嘛,非常帥的一個小伙子。B站ID:_旺仔小菠蘿,歡迎大家圍觀!
好了,廢話不多說,直接開整!先看展示視頻,相關(guān)方案在后文。
文末開源所有文件(已經(jīng)獲得本人授權(quán)),程序、電路、3D打印文件。
01 硬件篇
1.1 STM32F103C8T6最小系統(tǒng)(小藍(lán)板)
1.2 MPU6050姿態(tài)傳感器(3.3V供電)
1.3 0.96寸OLED顯示屏(四針、IIC通信、3.3V供電)
1.4 HC-05藍(lán)牙模塊(串口通信、用于接收小車運(yùn)動指令)
使用教程鏈接:https://blog.csdn.net/weixin_44325419/article/details/110727911
1.5 超聲波測距模塊
1.6 N20電機(jī)及驅(qū)動(電機(jī)選型:DC 12V A12型)
1.7 無刷電機(jī)動量輪模組
該自平衡自行車中我們使用萬寶至無刷伺服電機(jī),內(nèi)置驅(qū)動,支持正反轉(zhuǎn),PWM調(diào)速,并且?guī)в?00線編碼器AB相雙通道信號輸出。
該電機(jī)接線圖如上圖所示,實(shí)際小車中的線的顏色可能與上圖有所不符,大家要按照位置來判斷而不是線的顏色。
1.信號A相和信號B相為編碼器脈沖輸出端;
2.正反轉(zhuǎn)切換的線我們直接用單片機(jī)的引腳3.3V電平控制,是完全沒有問題的;
3.編碼器供電接3.3V;
4.PWM接單片機(jī)的PWM輸出,啟動運(yùn)行我們接單片機(jī)IO口,在電機(jī)初始化時置為高電平;
5.電源負(fù)極接GND,電源正極接12V。
1.8 舵機(jī)
項(xiàng)目中所使用,有點(diǎn)小貴,可以買便宜的。
1.9 3S航模電池(注意電池尺寸)
1.10 穩(wěn)壓模塊及開關(guān)
將航模電池電壓降至5V給單片機(jī)、舵機(jī)、藍(lán)牙、超聲波、電機(jī)編碼器供電。
1.11 輪子及軸承
由于小車后輪是通過皮帶傳動,為減小摩擦,使后輪轉(zhuǎn)動更加順滑,需在后輪安裝微型軸承。(軸承根據(jù)車軸尺寸購買)
1.12 車架及轉(zhuǎn)向結(jié)構(gòu)(3D打?。?/h3>
13. 電路PCB
將上述功能模塊集成在一塊PCB電路板上(6.5x7.8cm),為方便焊接,電容電阻及三極管均為直插式元件。
02 軟件篇
2.1 main.c
#include "sys.h"
float AdcValue; //電池電壓數(shù)字量
float Pitch,Roll,Yaw; //角度
short aacx,aacy,aacz; //加速度傳感器原始數(shù)據(jù)
short gyrox,gyroy,gyroz; //陀螺儀原始數(shù)據(jù)
int PWM1;
int PWM_MAX=6500,PWM_MIN=-6500; //PWM限幅變量
int Encoder_Motor; //編碼器數(shù)據(jù)(速度)
int main(void)
{
NVIC_Config();
delay_init();
Led_Init();
Beep_Init();
Wave_SRD_Init();
uart3_init(9600);
OLED_Init(); //初始化OLED
OLED_Clear();
adc_Init();
MOTOR_1_Init();
MOTOR_2_Init();
PWM_Init_TIM3(7199,0);//定時器3初始化PWM 10KHZ,用于驅(qū)動動量輪電機(jī)
PWM_Init_TIM2(9999, 143);//定時器2初始化PWM 50HZ,用于驅(qū)動舵機(jī)
TIM_SetCompare1(TIM2, 790);//舵機(jī)復(fù)位
Init_TIM1(9998,7199);
Encoder_Init_TIM4(65535,0);
OLED_ShowString(25,4,"MPU6050...",16);
MPU_Init(); //MPU6050初始化
while(mpu_dmp_init())
{
OLED_ShowString(25,4,"MPU6050 Error",16);
}
OLED_ShowString(25,4,"MPU6050 OK!",16);
Beep=1;
delay_ms(400);
Beep=0;
MPU6050_EXTI_Init();
OLED_Clear();
OLED_ShowString(0,0,"Roll : C",16);
OLED_ShowString(0,3,"Speed: R ",16);
OLED_ShowString(0,6,"Power: V ",16);
while(1)
{
Wave_SRD_Strat();
AdcValue=11.09*(3.3*Get_adc_Average(ADC_Channel_4,10)/0x0fff); //ADC值范圍為從0-2^12=4095(111111111111)一般情況下對應(yīng)電壓為0-3.3V
OLED_Showdecimal(55,0,Roll,9,16);
OLED_Showdecimal(55,3,Encoder_Motor*0.25,9,16);
OLED_Showdecimal(50,6,AdcValue,9,16);
}
}
2.2 PID控制算法
學(xué)習(xí)視頻:
該小車實(shí)現(xiàn)直立平衡需要用到兩個閉環(huán)控制,即直立環(huán)(PD控制、負(fù)反饋),速度環(huán)(PI控制、正反饋),代碼原理及調(diào)試過程與兩輪平衡小車調(diào)試過程基本一致。
關(guān)于PID控制算法的學(xué)習(xí),內(nèi)容較多,不好詳細(xì)展開,網(wǎng)上資源豐富,大家可自行學(xué)習(xí)。
這里推薦一篇知乎文章:https://zhuanlan.zhihu.com/p/39573490
2.3 代碼閱讀注意點(diǎn)
所有頭文件都包含在sys.h中,每個.h文件都包含sys.h,方便函數(shù)調(diào)用。
#ifndef __SYS_H
#define __SYS_H
#include "stm32f10x.h"
#include "adc.h"
#include "oled.h"
#include "led.h"
#include "beep.h"
#include "wave.h"
#include "control.h"
#include "exti.h"
#include "mpu6050.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
#include "motor.h"
#include "pwm.h"
#include "encoder.h"
#include "usart.h"
#include "delay.h"
#include <math.h>
#include <stdlib.h>
STM32F10x系列的MCU復(fù)位后,PA13/14/15 & PB3/4默認(rèn)配置為JTAG功能。有時我們?yōu)榱顺浞掷肕CU I/O口的資源,會把這些端口設(shè)置為普通I/O口。
使用JLINK向STM32燒錄程序時,需要使用6個芯片的引腳(以STM32F103C8T6為例),分別是PB4 / JNTRST,PB3 / JTDO,PA13 / JTMS,PA14 / JTCK,PA15 / JTDI,NRST。
當(dāng)芯片IO口資源比較緊張時,可選擇SW模式燒錄程序。
SWD只需用到PA13 / JTMS,PA14 / JTCK兩根線,NREST可以接可不接,剩下的PB4 / JNTRST,PB3 / JTDO和PA15 / JTDI就可以當(dāng)然普通IO使用,但是這三個口當(dāng)然普通IO使用時需要先進(jìn)行如下配置。(這里MPU6050模塊用到PB3和PB4引腳)
03 最后
3.1 作品照片