1. 程式人生 > >STM32循跡避障小車製作程式碼詳解(簡單實現版)

STM32循跡避障小車製作程式碼詳解(簡單實現版)

寫在最前:最近由於需要製作了一個循跡避障小車,製作比較簡單但是還是出現了很多bug,因此在部落格中記錄一下,希望對後期需要製作的能有所幫助,小車由PWM訊號+L293D驅動。(二輪驅動,第三輪為自由輪)

要求:小車要求循跡避障,有兩種避障策略,在循跡黑線上遇到障礙物停車,循跡黑線外遇到障礙物要避障(左轉,右轉,後退均可),循跡過程中要求不能出黑線之外。

循跡原理:(紅外探頭+訊號處理板)

紅外探頭板
訊號處理板

       我們在車頭前加有3個紅外探頭板,分別在左中右三個位置,循跡原理很簡單程式碼也十分容易理解好寫,紅外探頭在光滑地板上會收到發射出去後反射的紅外訊號,如果探頭在黑線上,則無法收到(黑線吸收紅外光),當探頭收到時,對應的訊號調整板對應位置的led會亮,同時TTL輸出端會給一個低電平,相反當某個探頭在黑線上,對應位置led會滅,TTL輸出端會給一個高電平,因此通過這種方式我們就知道任意一個探頭是否在線上。

       因此我們舉個例子,兩邊燈亮,中間燈滅,說明小車前端中間探頭在線上,這時候是正向,因此我們在程式碼中要求小車直行,若左燈滅,中間燈和右燈都亮,說明左探頭在線上,小車現在是斜向右方,因此我們需要小車左轉來實現方向回正,下面配個圖來說明例子(途中只有左右兩個探頭,但不影響理解)

  若僅僅實現循跡,程式碼要求就十分簡單了(這裡我們不再說小車前進等程式碼,只說明策略)

 當左燈滅,TTL給1,車身右斜,迴圈左轉至中間燈滅兩邊燈亮(即正向)後直行,否則就一直襬正,右向同樣如此。

/***LED_1,LED_2,LED_3分別對應左中右三個紅外探頭***/

 
if(LED_1==1&&LED_3==0)   //左方黑線亮,左轉直到正向 
{
   while(1)
   {				
     CarLeft();
     if(LED_1==0&&LED_3==0&&LED_2==1)
     break;
   }
}


else if(LED_1==0&&LED_3==1)   ////右方黑線亮,右轉直到正向
{
   while(1)
   {
     CarRight();
     if(LED_1==0&&LED_3==0&&LED_2==1)
     break;
   }
}

else	CarGo();	

避障原理:(超聲波探頭)

驅動程式碼是我直接從網上覆制,借鑑的程式碼,在此附上鍊接,講解非常詳細,感謝作者。

探頭驅動:基於stm32和HC-SR04超聲波測距驅動

但是筆者在使用驅動中也遇到了只收到一個非常小的數,即使已經按照上面連結中的要求更正,但還是收到一個非常小的數字,對此筆者對其測距程式碼進行了小小改動,對定時器測距進行小延時,去除小值資料,請對比上述連結中程式碼~在中間加了一個Delay_Us(10);問題解決。其實筆者試過,Delay_Us(1);同樣可以解決問題。

float Hcsr04GetLength(void )

{

		u32 t = 0;

		int i = 0;

		float lengthTemp = 0;

		float sum = 0;

		while(i!=5)

	{

		//TRIG_Send = 1;      //傳送口高電平輸出
		GPIO_SetBits(GPIOA, GPIO_Pin_5);	// Alias

		Delay_Us(15);

		//TRIG_Send = 0;
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);	// Alias

		//while(ECHO_Reci == 0);      //等待接收口高電平輸出
		while(0 == GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6))
			OpenTimerForHc();        //開啟定時器

			i = i + 1;

			//while(ECHO_Reci == 1);
			while(1 == GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6))
			


                        Delay_Us(10);    //延時,去除小數值
		
			


                        CloseTimerForHc();        //關閉定時器

			t = GetEchoTimer();        //獲取時間,解析度為1US

			lengthTemp = ((float)t/58.0);//cm

			sum = lengthTemp + sum ;

		

	}

         	lengthTemp = sum/5.0;

		return lengthTemp;

}

在測距驅動和循跡策略都有的情況下,筆者將程式碼合二為一,實現要求功能(以下為while函式中程式碼)

 if(LED_1==0&&LED_3==0&&LED_2==0)
	{
	length = Hcsr04GetLength();
		if(length<=20.00)
		{
			while(1)
			{
				
				for(cnt1=0;cnt1 <= 60;cnt1++)
				for(cnt=0;cnt <= 8000;cnt++)
				CarBack();
			
				for(cnt1=0;cnt1 <= 60;cnt1++)
				for(cnt=0;cnt <= 8000;cnt++)
		  	CarRight();
			
				length = Hcsr04GetLength();
				if(length>=40.00)
				break;
			}
		}
		else CarGo();
	}
	else
	{
		length = Hcsr04GetLength();
		if(length<=20.00)
			CarStop();
		else
		{                              
		
		/***********路徑判斷***********/

			 if(LED_1==1&&LED_3==0)   //左方黑線亮,左轉直到正向
	   {
			 while(1)
			 {
				 length = Hcsr04GetLength();//這個判斷很重要,否則轉彎過程中
		                 if(length<=20.00)          //會被判斷為線外,會後退右轉
			         CarStop();
				 else CarLeft();
				 if(LED_1==0&&LED_3==0&&LED_2==1)
				break;
			 }
		 }
			else if(LED_1==0&&LED_3==1)   ////右方黑線亮,右轉直到正向
			{
				while(1)
			 {
				 length = Hcsr04GetLength();
	    	                 if(length<=20.00)
		  	         CarStop();
				 else CarRight();
				 if(LED_1==0&&LED_3==0&&LED_2==1)
				break;
			 }
		 }
			else	CarGo();	//其實這裡並不嚴謹,筆者後期有改動。
		
	 }
  }
}

以上程式碼和驅動沒有問題,但是有個很嚴重的問題就是

車子不能走太快,若直行左右轉過程中遇到障礙物,有可能會出現線外避障,後期作者程式碼有改動。

原因是該程式碼中測距是由定時器計數,在此cpu參與計數,微控制器是單核執行,因此大概一半以上時間都帶等資料返回,如果速度太快小車在循跡中燈閃時卻在等待資料,則直接衝出線外,解決方案(定時器捕獲測距),CPU不參與計數,大大提高了檢測速率。

此程式碼為簡單版,並不嚴謹,但完全可以完成任務,筆者後期已經更新一次程式碼,這次小車速度很快而且程式碼比較嚴謹,感謝過程中hjl同學的幫助。

有問題歡迎留言~