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同学的帮助。

有问题欢迎留言~

猜你喜欢

转载自blog.csdn.net/VCA821/article/details/84134780