国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

STM32兩輪平衡小車原理詳解(開源)

這篇具有很好參考價值的文章主要介紹了STM32兩輪平衡小車原理詳解(開源)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、引言

關(guān)于STM32兩輪平衡車的設(shè)計,我想在讀者閱讀本文之前應(yīng)該已經(jīng)有所了解,所以本文的重點是代碼的分享和分析。至于具體的原理,我覺得讀者不必閱讀長篇大論的文章,只需按照本文分享的代碼自己親手制作一輛平衡車,其原理并不言而喻了。源完整代碼工程在文章末尾百度網(wǎng)盤鏈接,請需要的讀者自行下載即可。

另外,由于平衡車的精髓在于PID算法的運用,有需要了解PID算法的讀者可以參考以下兩篇文章:

PID算法詳解(代碼詳解篇),位置式PID、增量式PID(通用)_pid 代碼-CSDN博客

PID算法詳解(精華知識匯總)_小小_掃地僧的博客-CSDN博客

二、所需材料

1、STM32F03C8T6

STM32兩輪平衡小車原理詳解(開源),32單片機,自動控制,stm32,嵌入式硬件,單片機

2、MPU6050

STM32兩輪平衡小車原理詳解(開源),32單片機,自動控制,stm32,嵌入式硬件,單片機

3、藍牙模塊

STM32兩輪平衡小車原理詳解(開源),32單片機,自動控制,stm32,嵌入式硬件,單片機

4、編碼電機

STM32兩輪平衡小車原理詳解(開源),32單片機,自動控制,stm32,嵌入式硬件,單片機

5、TB6612

STM32兩輪平衡小車原理詳解(開源),32單片機,自動控制,stm32,嵌入式硬件,單片機

6、電源+穩(wěn)壓模塊

7、OLED顯示模塊

STM32兩輪平衡小車原理詳解(開源),32單片機,自動控制,stm32,嵌入式硬件,單片機

三、接線強調(diào)

1、TB6612接線

STM32兩輪平衡小車原理詳解(開源),32單片機,自動控制,stm32,嵌入式硬件,單片機

2、藍牙模塊與單片機之間

單片機? ? ? ? ? ? ? ??藍牙模塊

?TX? ?? ?——>? ? ?RX ?

?RX? ?? ?——>? ? ?TX ?

3、MPU6050?

使用IIC通信,所以對照代碼接SDA、SCL、GND、VCC、IN(中斷觸發(fā)線)

四、功能介紹

1、兩輪平衡直立

2、藍牙APP控制運動狀態(tài)

3、遙控手柄控制

4、超聲波避障

五、關(guān)鍵算法

PID算法對編碼電機的控制

1.位置閉環(huán)控制

????????位置閉環(huán)控制就是根據(jù)編碼器的脈沖累加測量電機的位置信息,并與目標(biāo)值進行比較,得到控制偏差,然后通過對偏差的比例、積分、微分進行控制,使偏差趨向于零的過程 位置閉環(huán)控制就是根據(jù)編碼器的脈沖累加測量電機的位置信息,并與目標(biāo)值進行比較,得到控制偏差,然后通過對偏差的比例、積分、微分進行控制,使偏差趨向于零的過程.

1.1理論分析

STM32兩輪平衡小車原理詳解(開源),32單片機,自動控制,stm32,嵌入式硬件,單片機

1.2控制原理圖?

STM32兩輪平衡小車原理詳解(開源),32單片機,自動控制,stm32,嵌入式硬件,單片機

1.3C語言實現(xiàn)?

int Position_PID (int Encoder, int Target)
{
    static float Bias, Pwm,Integral_bias,Last_Bias;
    Bias=Encoder-Target;//計算偏差
    Integral_bias+=Bias; //求出偏差的積分
    Pwm=Position_KP*Bias+Position_KI*Integral_bias+Position_KD*(Bias-Last_Bias);Last_Bias=Bias;  //保存上一次偏差
    return Pwm; //輸出
}
   

入口參數(shù)為編碼器的位置測量值和位置控制的目標(biāo)值,返回值為電機控制PWM(現(xiàn)在再看一下上面的控制原理圖是不是更加容易明白了)。
第一行是相關(guān)內(nèi)部變量的定義。
第二行是求出速度偏差,由測量值減去目標(biāo)值。第三行通過累加求出偏差的積分。
第四行使用位置式PID控制器求出電機 PWM。第五行保存上一次偏差,便于下次調(diào)用。最后一行是返回。
然后,在定時中斷服務(wù)函數(shù)里面調(diào)用該函數(shù)實現(xiàn)我們的控制目標(biāo):Moto=Position_PID(Encoder, Target_Position);
Set_Pwm(Moto) ;//===賦值給PWM寄存器

2、速度閉環(huán)控制

速度閉環(huán)控制就是根據(jù)單位時間獲取的脈沖數(shù)(這里使用了M法測速)測量電機的速度信息,并與目標(biāo)值進行比較,得到控制偏差,然后通過對偏差的比例、積分、微分進行控制,使偏差趨向于零的過程。
一些PID的要點在位置控制中已經(jīng)有講解,這里不再贅敘。
需要說明的是,這里速度控制20ms一次,一般建議10ms或者5ms,因為在這里電機是使用USB供電,速度比較慢,20ms可以延長獲取速度的單位時間,提高編碼器的采值。

?2.1理論分析

根據(jù)增量式離散PID公式 根據(jù)增量式離散PID公式
Pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]
e(k):本次偏差
e(k-1):上一次的偏差e (k-2):上上次的偏差
Pwm 代表增量輸出

在我們的速度控制閉環(huán)系統(tǒng)里面只使用PI控制,因此對PID控制器可簡化為以下公式:
Pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)

2.2 控制原理圖

STM32兩輪平衡小車原理詳解(開源),32單片機,自動控制,stm32,嵌入式硬件,單片機

2.3 C語言實現(xiàn)

增量式PI控制器具體通過C語言實現(xiàn)的代碼如下:
?

int Incremental_PI (int Encoder,int Target)
{
    static float Bias, Pwm, Last_bias;
    Bias=Encoder-Target;//計算偏差
    Pwm+=Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias;//增量式PI控制器
    Last_bias=Bias;//保存上一次偏差
    return Pwm;//增量輸出
}

入口參數(shù)為編碼器的速度測量值和速度控制的目標(biāo)值,返回值為電機控制PWM。
第一行是相關(guān)內(nèi)部變量的定義。
第二行是求出速度偏差,由測量值減去目標(biāo)值。第三行使用增量PI控制器求出電機PWM。
第四行保存上一次偏差,便于下次調(diào)用。最后一行是返回。
然后,在定時中斷服務(wù)函數(shù)里面調(diào)用該函數(shù)實現(xiàn)我們的控制目標(biāo):

Moto=Incremental_PI(Encoder, Target_Velocity);Set_Pwm(Moto);//===賦值給對應(yīng)MCU的PWM寄存器

六、關(guān)鍵代碼分析

1、編碼電機PID算法控制

#include "control.h"
#include "usart2.h"

/**************************************************************************
函數(shù)功能:所有的控制代碼都在這里面
         5ms定時中斷由MPU6050的INT引腳觸發(fā)
         嚴(yán)格保證采樣和數(shù)據(jù)處理的時間同步	
				 在MPU6050的采樣頻率設(shè)置中,設(shè)置成100HZ,即可保證6050的數(shù)據(jù)是10ms更新一次。
				 讀者可在imv_mpu.h文件第26行的宏定義進行修改(#define DEFAULT_MPU_HZ  (100))
**************************************************************************/
#define SPEED_Y 100 //俯仰(前后)最大設(shè)定速度
#define SPEED_Z 80//偏航(左右)最大設(shè)定速度 

int Balance_Pwm,Velocity_Pwm,Turn_Pwm,Turn_Kp;

float Mechanical_angle=8; 
float Target_Speed=0;	//期望速度(俯仰)。用于控制小車前進后退及其速度。
float Turn_Speed=0;		//期望速度(偏航)

//針對不同車型參數(shù),在sys.h內(nèi)設(shè)置define的電機類型
float balance_UP_KP=BLC_KP; 	 // 小車直立環(huán)PD參數(shù)
float balance_UP_KD=BLC_KD;

float velocity_KP=SPD_KP;     // 小車速度環(huán)PI參數(shù)
float velocity_KI=SPD_KI;

float Turn_Kd=TURN_KD;//轉(zhuǎn)向環(huán)KP、KD
float Turn_KP=TURN_KP;



void EXTI9_5_IRQHandler(void) 
{
	static u8 Voltage_Counter=0;
	if(PBin(5)==0)
	{
		EXTI->PR=1<<5;                                          //清除LINE5上的中斷標(biāo)志位   
		mpu_dmp_get_data(&pitch,&roll,&yaw);		            //得到歐拉角(姿態(tài)角)的數(shù)據(jù)
		MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);				//得到陀螺儀數(shù)據(jù)
		Encoder_Left=Read_Encoder(2);                           //讀取編碼器的值,保證輸出極性一致
		Encoder_Right=-Read_Encoder(3);                         //讀取編碼器的值
		Led_Flash(100);
		
		Voltage_Counter++;
		if(Voltage_Counter==20)                                 //100ms讀取一次電壓
		{
			Voltage_Counter=0;
			Voltage=Get_battery_volt();		                    //讀取電池電壓
		}
		
		if(KEY_Press(100))										//長按按鍵切換模式并觸發(fā)模式切換初始化
		{
			if(++CTRL_MODE>=101) 
				CTRL_MODE=97;
			Mode_Change=1;
		}
		
		Get_RC();
			
		Target_Speed=Target_Speed>SPEED_Y?SPEED_Y:(Target_Speed<-SPEED_Y?(-SPEED_Y):Target_Speed);//限幅
		Turn_Speed=Turn_Speed>SPEED_Z?SPEED_Z:(Turn_Speed<-SPEED_Z?(-SPEED_Z):Turn_Speed);//限幅( (20*100) * 100)
			
		Balance_Pwm =balance_UP(pitch,Mechanical_angle,gyroy);   							//===直立環(huán)PID控制	
		Velocity_Pwm=velocity(Encoder_Left,Encoder_Right,Target_Speed);       //===速度環(huán)PID控制	 
		Turn_Pwm =Turn_UP(gyroz,Turn_Speed);        						  //===轉(zhuǎn)向環(huán)PID控制
		Moto1=Balance_Pwm-Velocity_Pwm+Turn_Pwm;                              //===計算左輪電機最終PWM
		Moto2=Balance_Pwm-Velocity_Pwm-Turn_Pwm;                              //===計算右輪電機最終PWM
	    Xianfu_Pwm();  														  //===PWM限幅
		Turn_Off(pitch,12);													  //===檢查角度以及電壓是否正常
		Set_Pwm(Moto1,Moto2);                                                 //===賦值給PWM寄存器  
	}
}

/**************************************************************************
函數(shù)功能:直立PD控制
入口參數(shù):角度、機械平衡角度(機械中值)、角速度
返回  值:直立控制PWM
**************************************************************************/
int balance_UP(float Angle,float Mechanical_balance,float Gyro)
{  
   float Bias;
	 int balance;
	 Bias=Angle-Mechanical_balance;    							 //===求出平衡的角度中值和機械相關(guān)
	 balance=balance_UP_KP*Bias+balance_UP_KD*Gyro;              //===計算平衡控制的電機PWM  PD控制   kp是P系數(shù) kd是D系數(shù) 
	 return balance;
}

/**************************************************************************
函數(shù)功能:速度PI控制
入口參數(shù):電機編碼器的值
返回  值:速度控制PWM
**************************************************************************/
int velocity(int encoder_left,int encoder_right,int Target_Speed)
{  
    static float Velocity,Encoder_Least,Encoder;
	  static float Encoder_Integral;
   //=============速度PI控制器=======================//	
		Encoder_Least =(Encoder_Left+Encoder_Right);//-target;              //===獲取最新速度偏差==測量速度(左右編碼器之和)-目標(biāo)速度 
		Encoder *= 0.8;		                                                //===一階低通濾波器       
		Encoder += Encoder_Least*0.2;	                                    //===一階低通濾波器    
		Encoder_Integral +=Encoder;                                         //===積分出位移 積分時間:10ms
		Encoder_Integral=Encoder_Integral - Target_Speed;                   //===接收遙控器數(shù)據(jù),控制前進后退
		if(Encoder_Integral>10000)  	Encoder_Integral=10000;             //===積分限幅
		if(Encoder_Integral<-10000)		Encoder_Integral=-10000;            //===積分限幅	
		Velocity=Encoder*velocity_KP+Encoder_Integral*velocity_KI;          //===速度控制	
	  if(pitch<-40||pitch>40) 			Encoder_Integral=0;     			//===電機關(guān)閉后清除積分
	  return Velocity;
}
/**************************************************************************
函數(shù)功能:轉(zhuǎn)向PD控制
入口參數(shù):電機編碼器的值、Z軸角速度
返回  值:轉(zhuǎn)向控制PWM
**************************************************************************/

int Turn_UP(int gyro_Z, int RC)
{
	int PWM_out;
		/*轉(zhuǎn)向約束*/
	if(RC==0)
		Turn_Kd=TURN_KD;                                              //若無左右轉(zhuǎn)向指令,則開啟轉(zhuǎn)向約束
	else 
		Turn_Kd=0;                                                    //若左右轉(zhuǎn)向指令接收到,則去掉轉(zhuǎn)向約束
	
	PWM_out=Turn_Kd*gyro_Z + Turn_KP*RC;
	return PWM_out;
}

void Tracking()
{
	TkSensor=0;
	TkSensor+=(C1<<3);
	TkSensor+=(C2<<2);
	TkSensor+=(C3<<1);
	TkSensor+=C4;
}
void Get_RC()
{
	static u8 SR04_Counter =0;
	static float RATE_VEL = 1;
	float RATE_TURN = 1.6;
	float LY,RX;      //PS2手柄控制變量
	int Yuzhi=2;  		//PS2控制防抖閾值
	switch(CTRL_MODE)
	{
		case 97:
			SR04_Counter++;
			if(SR04_Counter>=20)									         //100ms讀取一次超聲波的數(shù)據(jù)
			{
				SR04_Counter=0;
				SR04_StartMeasure();												 //讀取超聲波的值
			}
			if(SR04_Distance<=30)				
			{
				Target_Speed=0,Turn_Speed=40;
			}
			else
			{
				Target_Speed=30,Turn_Speed=0;
			}
			break;
			
		case 98://藍牙模式
			if((Fore==0)&&(Back==0))
				Target_Speed=0;//未接受到前進后退指令-->速度清零,穩(wěn)在原地
			if(Fore==1)
				Target_Speed--;//前進1標(biāo)志位拉高-->需要前進
			if(Back==1)
				Target_Speed++;//
			/*左右*/
			if((Left==0)&&(Right==0))
				Turn_Speed=0;
			if(Left==1)
				Turn_Speed-=30;	//左轉(zhuǎn)
			if(Right==1)
				Turn_Speed+=30;	//右轉(zhuǎn)
			break;
			
		case 99://循跡模式
			Tracking();
			switch(TkSensor)
			{
				case 15:
					Target_Speed=0;
					Turn_Speed=0;
					break;
				
				case 9:
					Target_Speed--;
					Turn_Speed=0;
					break;
				
				case 2://向右轉(zhuǎn)
					Target_Speed--;
					Turn_Speed=15;
					break;
				
				case 4://向左轉(zhuǎn)
					Target_Speed--;
					Turn_Speed=-15;
					break;
				
				case 8:
					Target_Speed=-10;
					Turn_Speed=-80;
					break;
				
				case 1:
					Target_Speed=-10;
					Turn_Speed=80;
					break;
			}
			break;
			
		case 100://PS2手柄遙控
			if(PS2_Plugin)
			{
				LY=PS2_LY-128; //獲取偏差
				RX=PS2_RX-128; //獲取偏差
				if(LY>-Yuzhi&&LY<Yuzhi)
					LY=0; //設(shè)置小角度的死區(qū)
				if(RX>-Yuzhi&&RX<Yuzhi)
					RX=0; //設(shè)置小角度的死區(qū)
				if(Target_Speed>-LY/RATE_VEL) 
					Target_Speed--;
				else if(Target_Speed<-LY/RATE_VEL) 
					Target_Speed++;
				Turn_Speed=RX/RATE_TURN;
			}
			else
			{
				Target_Speed=0,Turn_Speed=0;
			}
		break;
	}
}

?2、編碼電機編碼值采集

#include "encoder.h"


/**************************************************************************
函數(shù)功能:把TIM2初始化為編碼器接口模式
入口參數(shù):無
返回  值:無
**************************************************************************/
void Encoder_Init_TIM2(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
  TIM_ICInitTypeDef TIM_ICInitStructure;  
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定時器4的時鐘
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PB端口時鐘
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;	//端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
  GPIO_Init(GPIOA, &GPIO_InitStructure);					      //根據(jù)設(shè)定參數(shù)初始化GPIOB
  
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 預(yù)分頻器 
  TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //設(shè)定計數(shù)器自動重裝值
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//選擇時鐘分頻:不分頻
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上計數(shù)  
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用編碼器模式3
  TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICFilter = 10;
  TIM_ICInit(TIM2, &TIM_ICInitStructure);
  TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新標(biāo)志位
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
  //Reset counter
  TIM_SetCounter(TIM2,0);
  TIM_Cmd(TIM2, ENABLE); 
}
/**************************************************************************
函數(shù)功能:把TIM3初始化為編碼器接口模式
入口參數(shù):無
返回  值:無
**************************************************************************/
void Encoder_Init_TIM3(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
  TIM_ICInitTypeDef TIM_ICInitStructure;  
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能定時器4的時鐘
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PB端口時鐘
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;	//端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
  GPIO_Init(GPIOA, &GPIO_InitStructure);					      //根據(jù)設(shè)定參數(shù)初始化GPIOB
  
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 預(yù)分頻器 
  TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //設(shè)定計數(shù)器自動重裝值
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//選擇時鐘分頻:不分頻
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上計數(shù)  
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 
  TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用編碼器模式3
  TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICFilter = 10;
  TIM_ICInit(TIM3, &TIM_ICInitStructure);
  TIM_ClearFlag(TIM3, TIM_FLAG_Update);//清除TIM的更新標(biāo)志位
  TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
  //Reset counter
  TIM_SetCounter(TIM3,0);
  TIM_Cmd(TIM3, ENABLE); 
}

/**************************************************************************
函數(shù)功能:單位時間讀取編碼器計數(shù)
入口參數(shù):定時器
返回  值:速度值
**************************************************************************/
int Read_Encoder(u8 TIMX)
{
    int Encoder_TIM;    
   switch(TIMX)
	 {
	   case 2:  
		 Encoder_TIM= (short)TIM2 -> CNT; 
		 TIM2 -> CNT=0;
		 break;
	   case 3:  
		 Encoder_TIM= (short)TIM3 -> CNT;  TIM3 -> CNT=0;
	     break;	
		 default: Encoder_TIM=0;
	 }
		return Encoder_TIM;
}


3、PWM配置

#include "pwm.h"



//PWM輸出初始化
//arr:自動重裝值
//psc:時鐘預(yù)分頻數(shù)
//TIM1_PWM_Init(7199,0);//PWM頻率=72000/(7199+1)=10Khz

void TIM1_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);// 
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  //使能GPIO外設(shè)時鐘使能
   //設(shè)置該引腳為復(fù)用輸出功能,輸出TIM1 CH1 CH4的PWM脈沖波形
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_11; //TIM_CH1 //TIM_CH4
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //復(fù)用推挽輸出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_TimeBaseStructure.TIM_Period = arr; //設(shè)置在下一個更新事件裝入活動的自動重裝載寄存器周期的值	 
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //設(shè)置用來作為TIMx時鐘頻率除數(shù)的預(yù)分頻值  不分頻
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置時鐘分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上計數(shù)模式
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根據(jù)TIM_TimeBaseInitStruct中指定的參數(shù)初始化TIMx的時間基數(shù)單位

 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //選擇定時器模式:TIM脈沖寬度調(diào)制模式1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
	TIM_OCInitStructure.TIM_Pulse = 0;                            //設(shè)置待裝入捕獲比較寄存器的脈沖值
	TIM_OCInitStructure.TIM_Pulse = arr >> 1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;     //輸出極性:TIM輸出比較極性高
	TIM_OC1Init(TIM1, &TIM_OCInitStructure);  //根據(jù)TIM_OCInitStruct中指定的參數(shù)初始化外設(shè)TIMx
	TIM_OC4Init(TIM1, &TIM_OCInitStructure);  //根據(jù)TIM_OCInitStruct中指定的參數(shù)初始化外設(shè)TIMx

    TIM_CtrlPWMOutputs(TIM1,ENABLE);	//MOE 主輸出使能	

	TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH1預(yù)裝載使能	 
	TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH4預(yù)裝載使能	 
	
	TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的預(yù)裝載寄存器
	
	TIM_Cmd(TIM1, ENABLE);  //使能TIM1
}

4、藍牙控制

#include "usart2.h"

/**************************************************************************
函數(shù)功能:串口2初始化
入口參數(shù): bound:波特率
返回  值:無
**************************************************************************/
void uart2_init(u32 bound)
{  	 
	  //GPIO端口設(shè)置
  GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//使能UGPIOB時鐘
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);	//使能USART2時鐘
	//USART2_TX  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA2
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//復(fù)用推挽輸出
  GPIO_Init(GPIOA, &GPIO_InitStructure);
   
  //USART2_RX	  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入
  GPIO_Init(GPIOA, &GPIO_InitStructure);

   //USART 初始化設(shè)置
	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長為8位數(shù)據(jù)格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬件數(shù)據(jù)流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收發(fā)模式
  USART_Init(USART2, &USART_InitStructure);     //初始化串口2
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//開啟串口接受中斷
  USART_Cmd(USART2, ENABLE);                    //使能串口2 
}

/**************************************************************************
函數(shù)功能:串口2接收中斷
入口參數(shù):無
返回  值:無
**************************************************************************/
u8 Fore,Back,Left,Right;
void USART2_IRQHandler(void)
{
	int Uart_Receive;
	if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)//接收中斷標(biāo)志位拉高
	{
		Uart_Receive=USART_ReceiveData(USART2);//保存接收的數(shù)據(jù)
		BluetoothCMD(Uart_Receive);								
	}
}

void BluetoothCMD(int Uart_Receive)
{
	switch(Uart_Receive)
		{
			case 90://停止
				Fore=0,Back=0,Left=0,Right=0;
				break;
			case 65://前進
				Fore=1,Back=0,Left=0,Right=0;
				break;
			case 72://左前
				Fore=1,Back=0,Left=1,Right=0;
				break;
			case 66://右前
				Fore=1,Back=0,Left=0,Right=1;
				break;
			case 71://左轉(zhuǎn)
				Fore=0,Back=0,Left=1,Right=0;
				break;
			case 67://右轉(zhuǎn)
				Fore=0,Back=0,Left=0,Right=1;
				break;
			case 69://后退
				Fore=0,Back=1,Left=0,Right=0;
				break;
			case 70://左后,向右旋
				Fore=0,Back=1,Left=0,Right=1;
				break;
			case 68://右后,向左旋
				Fore=0,Back=1,Left=1,Right=0;
				break;
			default://停止
				Fore=0,Back=0,Left=0,Right=0;
				break;
		}
}

void Uart2SendByte(char byte)   //串口發(fā)送一個字節(jié)
{
		USART_SendData(USART2, byte);        //通過庫函數(shù)  發(fā)送數(shù)據(jù)
		while( USART_GetFlagStatus(USART2,USART_FLAG_TC)!= SET);  
		//等待發(fā)送完成。   檢測 USART_FLAG_TC 是否置1;    //見庫函數(shù) P359 介紹
}

void Uart2SendBuf(char *buf, u16 len)
{
	u16 i;
	for(i=0; i<len; i++)Uart2SendByte(*buf++);
}
void Uart2SendStr(char *str)
{
	u16 i,len;
	len = strlen(str);
	for(i=0; i<len; i++)Uart2SendByte(*str++);
}

5、中斷處理函數(shù)

void EXTI9_5_IRQHandler(void) 
{
	static u8 Voltage_Counter=0;
	if(PBin(5)==0)
	{
		EXTI->PR=1<<5;                                          //清除LINE5上的中斷標(biāo)志位   
		mpu_dmp_get_data(&pitch,&roll,&yaw);		            //得到歐拉角(姿態(tài)角)的數(shù)據(jù)
		MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);				//得到陀螺儀數(shù)據(jù)
		Encoder_Left=Read_Encoder(2);                           //讀取編碼器的值,保證輸出極性一致
		Encoder_Right=-Read_Encoder(3);                         //讀取編碼器的值
		Led_Flash(100);
		
		Voltage_Counter++;
		if(Voltage_Counter==20)                                 //100ms讀取一次電壓
		{
			Voltage_Counter=0;
			Voltage=Get_battery_volt();		                    //讀取電池電壓
		}
		
		if(KEY_Press(100))										//長按按鍵切換模式并觸發(fā)模式切換初始化
		{
			if(++CTRL_MODE>=101) 
				CTRL_MODE=97;
			Mode_Change=1;
		}
		
		Get_RC();
			
		Target_Speed=Target_Speed>SPEED_Y?SPEED_Y:(Target_Speed<-SPEED_Y?(-SPEED_Y):Target_Speed);//限幅
		Turn_Speed=Turn_Speed>SPEED_Z?SPEED_Z:(Turn_Speed<-SPEED_Z?(-SPEED_Z):Turn_Speed);//限幅( (20*100) * 100)
			
		Balance_Pwm =balance_UP(pitch,Mechanical_angle,gyroy);   							//===直立環(huán)PID控制	
		Velocity_Pwm=velocity(Encoder_Left,Encoder_Right,Target_Speed);       //===速度環(huán)PID控制	 
		Turn_Pwm =Turn_UP(gyroz,Turn_Speed);        						  //===轉(zhuǎn)向環(huán)PID控制
		Moto1=Balance_Pwm-Velocity_Pwm+Turn_Pwm;                              //===計算左輪電機最終PWM
		Moto2=Balance_Pwm-Velocity_Pwm-Turn_Pwm;                              //===計算右輪電機最終PWM
	    Xianfu_Pwm();  														  //===PWM限幅
		Turn_Off(pitch,12);													  //===檢查角度以及電壓是否正常
		Set_Pwm(Moto1,Moto2);                                                 //===賦值給PWM寄存器  
	}
}

七、PCB板設(shè)計

STM32兩輪平衡小車原理詳解(開源),32單片機,自動控制,stm32,嵌入式硬件,單片機

STM32兩輪平衡小車原理詳解(開源),32單片機,自動控制,stm32,嵌入式硬件,單片機

八、代碼開源

1、寄存器版本

鏈接:https://pan.baidu.com/s/1NlMHsgMF2Cu8sz955n27Eg?pwd=zxf1?
提取碼:zxf1?
--來自百度網(wǎng)盤超級會員V2的分享

2、HAL庫版本

鏈接:https://pan.baidu.com/s/1rW5M7Dz-TK4IWJxNp57mBw?pwd=zxf1?
提取碼:zxf1?
--來自百度網(wǎng)盤超級會員V2的分享文章來源地址http://www.zghlxwxcb.cn/news/detail-754226.html

到了這里,關(guān)于STM32兩輪平衡小車原理詳解(開源)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 基于stm32的平衡小車

    基于stm32的平衡小車

    目錄 前言 一、電機驅(qū)動部分 1、TB6612FNG電機驅(qū)動模塊接線方式: 2、代碼使用定時器2的4路輸出pwm 3、gpio引腳初始化,以及前進,后退引腳設(shè)置 二、MPU6050陀螺儀部分 三、編碼器捕獲部分 四、pid部分 1、直立環(huán)KD 2、速度環(huán)KI 3、轉(zhuǎn)向環(huán)(PD) 五、藍牙通信部分 總結(jié) 經(jīng)過幾天對

    2024年02月09日
    瀏覽(22)
  • 復(fù)刻stm32平衡小車(適合入門)

    復(fù)刻stm32平衡小車(適合入門)

    目錄 前言: 1.硬件部分 1.1 STM32最小系統(tǒng) 1.2 電源 1.3 TB6612電機驅(qū)動模塊 1.4 串口通信 1.5 OLED模塊 1.6 藍牙模塊 1.7 LED燈模塊 ?1.8 MPU6050模塊?編輯 1.9 硬件焊接與調(diào)試 1.10 組裝 2.軟件部分 2.1 代碼 2.2 邏輯實現(xiàn) 2.2.1 control.c 2.2.2 usart.c 結(jié)尾 本文主要為復(fù)刻b站up主開源的平衡小車以及

    2024年02月13日
    瀏覽(21)
  • 基于STM32-F401的平衡小車

    基于STM32-F401的平衡小車

    目錄 一、控制系統(tǒng)設(shè)計 1.1機械結(jié)構(gòu)設(shè)計 1.2傳感系統(tǒng)設(shè)計 1.3執(zhí)行器設(shè)計 1.4控制算法設(shè)計 二、控制系統(tǒng)的制作與調(diào)試 2.1機械結(jié)構(gòu)的制作與調(diào)試 2.2電路系統(tǒng)的制作與調(diào)試 2.3控制程序的編寫與調(diào)試 三、控制系統(tǒng)的測試與分析 3.1測試方法 3.2測試數(shù)據(jù)與現(xiàn)象 3.3結(jié)果分析 一個系統(tǒng)

    2024年02月06日
    瀏覽(20)
  • STM32平衡小車 TB6612電機驅(qū)動學(xué)習(xí)

    STM32平衡小車 TB6612電機驅(qū)動學(xué)習(xí)

    單片機引腳的電流一般只有幾十個毫安,無法驅(qū)動電機,因此一般是通過單片機控制電機驅(qū)動芯片進而控制電機。TB6612是比較常用的電機驅(qū)動芯片之一。 ? ? ? ? TB6612FNG可以同時控制兩個電機,工作電流1.2A,最大電流3.2A。 ?VM電機電源正極,是驅(qū)動電壓輸入端(10V), VCC為邏

    2024年02月06日
    瀏覽(24)
  • 畢業(yè)分享 stm32智能平衡小車設(shè)計與實現(xiàn)

    畢業(yè)分享 stm32智能平衡小車設(shè)計與實現(xiàn)

    文章目錄 0 前言 1 項目背景 2 設(shè)計思路 3 硬件設(shè)計 4 軟件設(shè)計 4.2 直立控制程序設(shè)計 4.3 速度控制程序設(shè)計 4.4 方向控制程序設(shè)計 4.5 關(guān)鍵代碼 5 最后 ?? 這兩年開始畢業(yè)設(shè)計和畢業(yè)答辯的要求和難度不斷提升,傳統(tǒng)的畢設(shè)題目缺少創(chuàng)新和亮點,往往達不到畢業(yè)答辯的要求,這

    2024年02月02日
    瀏覽(23)
  • 基于STM32的平衡小車設(shè)計過程分享(1)

    基于STM32的平衡小車設(shè)計過程分享(1)

    一、簡介 接觸STM32開發(fā)一段時間了,想用STM32做一個有意思的項目,經(jīng)歷了無數(shù)的調(diào)參調(diào)參再調(diào)參,終于讓它站穩(wěn)了,接一下就一步步的跟大家介紹一下,項目的整體實現(xiàn)過程— 二、項目介紹 ??? STM32平衡小車是一種基于STM32芯片的智能小車,它可以通過自動控制來保持平衡

    2024年02月05日
    瀏覽(21)
  • 100、基于STM32單片機自動跟隨小車 紅外遙控控制小車避障模式 跟隨模式設(shè)計(程序+原理圖+PCB源文件+流程圖+硬件設(shè)計資料+元器件清單等)

    100、基于STM32單片機自動跟隨小車 紅外遙控控制小車避障模式 跟隨模式設(shè)計(程序+原理圖+PCB源文件+流程圖+硬件設(shè)計資料+元器件清單等)

    智能小車通過各種感應(yīng)器獲得外部環(huán)境信息和內(nèi)部運動狀態(tài),實現(xiàn)在復(fù)雜環(huán)境背景下的自主運動,從而完成具有特定功能的機器人系統(tǒng)。而隨著智能化電器時代的到來,它們在為人們提供的舒適的生活環(huán)境的同時,也提高了制造智能化電器對于人才要求的門檻。智能小車是集

    2024年02月15日
    瀏覽(116)
  • [CubeMX項目]基于STM32的平衡小車(硬件設(shè)計)

    [CubeMX項目]基于STM32的平衡小車(硬件設(shè)計)

    一直以來我都想在本科畢業(yè)前完成一個電機相關(guān)的實驗,之前看了網(wǎng)上比較火熱的自平衡萊洛三角形項目后,決心先做一個類似的小項目。因此,我通過學(xué)習(xí)大量前輩的項目案例,完成了該項目。 本項目的特點是:在需要通信的部分,全部采用STM32自帶的硬件接口,使用自己

    2024年02月03日
    瀏覽(19)
  • 從零復(fù)刻平衡小車(基于STM32F1)

    從零復(fù)刻平衡小車(基于STM32F1)

    本項目是對b站up主的開源項目進行了復(fù)刻,平衡車也特別適合作為入門單片機了解控制原理的一個小項目,這里主要記錄復(fù)刻的過程與心得。 ? ? ? ? 所需工具:焊烙鐵、熱風(fēng)槍 ? ? ? ? 首先焊單片機最小系統(tǒng),包括原理圖中的最小系統(tǒng)、電源以及串口通信部分。 ? ? ? ?

    2023年04月15日
    瀏覽(22)
  • stm32平衡小車制作遇到的問題和解決方案分享

    ????????1、電機帶負載所引起的死區(qū)補償問題 ????????2、利用MPU6050傳感器進行某一軸的角度測量問題 ????????3、stm32串口通訊得到的數(shù)據(jù)用DMA轉(zhuǎn)運問題 ????????我選用的電機為直流減速電機,型號為GA25-370,是12V的電機。 ????????電機運行分為帶負載和不

    2024年01月18日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包