天天看點

循迹模式-差速轉彎

循迹模式—差速轉彎

為什麼要差速轉彎?

普通循迹模式下,小車轉彎是讓一個輪子停止,另一個輪子轉動,強行帶動停下的輪子前進,是以會造成轉彎時“一拐一拐的”,顯得不平滑;

如果使轉彎時外側輪子速度快,裡側輪子速度慢,在兩個輪子的速度差下進行轉彎,便會現得平滑很多

程式

實作差速轉彎,主要用到了左右輪PWM調速的功能,把小車PWM調速-左右輪差速調速的定時器初始化和中斷處理拿過來使用

程式檔案:

1.main.c:主要是對兩個紅外循迹子產品的輸出引腳電平進行判斷,接着調用電機驅動使小車左右轉彎

2.Motor.c:小車前進、後退、左轉、右轉和停止的函數,被定時器的PWM調速中斷處理調用

3.Delay.c:延時函數

4.Timer.c:定時器0和定時器1初始化,以及中斷PWM

循迹模式-差速轉彎

Timer.c:

#include <REGX52.H>
#include "Motor.h"
#include "Delay.h"

unsigned char CountLeft;
unsigned char SpeedLeft;

unsigned char CountRight;
unsigned char SpeedRight;

/**
  * @brief 定時器0初始化函數,左輪PWM控制
  * @param 無
  * @retval 無
  */
void Timer0Init(void)		//0.5毫秒@11.0592MHz
{
	TMOD &= 0xF0;
	TMOD |= 0x01;	//設定定時器模式
	TL0 = 0x33;		//設定定時初值
	TH0 = 0xFE;		//設定定時初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定時器0開始計時
	EA = 1;			//開啟總中斷
	ET0 = 1;		//開啟定時器0中斷
}

//Timer0中斷處理函數,每隔0.5毫秒進入一次中斷
void Timer0_Rountine() interrupt 1
{
	CountLeft++;
	TL0 = 0x33;
	TH0 = 0xFE;
	if(CountLeft < SpeedLeft)
	{
		//左輪前進
		GoForwardLeft();
	}
	else
	{
		//左輪停止
		StopLeft();
	}
	if(CountLeft == 40)	//周期長一點,小車調速會更順滑點
	{
		CountLeft = 0;
	}
}

/**
  * @brief 定時器1初始化,右輪PWM調速
  * @param 無
  * @retval無
  */
void Timer1Init(void)		//0.5毫秒@11.0592MHz
{
	TMOD &= 0x0F;
	TMOD |= 0x10;	//設定定時器模式
	TL1 = 0x33;		//設定定時初值
	TH1 = 0xFE;		//設定定時初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定時器1開始計時
	EA = 1;			//開啟總中斷
	ET1 = 1;		//開啟定時器1中斷
}


//Timer1中斷處理函數,每隔0.5毫秒進入一次中斷
void Timer1_Rountine() interrupt 3
{
	CountRight++;
	TL1 = 0x33;
	TH1 = 0xFE;
	if(CountRight < SpeedRight)
	{
		//右輪前進
		GoForwardRight();
	}
	else
	{
		//右輪停止
		StopRight();
	}
	if(CountRight == 40)	//20ms
	{
		CountRight = 0;
	}
}
           

main.c

如果測試過程中發現小車走直線會偏移,說明左右輪的速度不一樣,可以用PWM稍微調整下

需要注意的是在兩個傳感器都不反射的情況下,也就是啟動的過程中把小車從地面拿起來了,紅外沒反射回來,如果使用之前的Stop函數,則會出現電流聲,這樣是個bug,要改為将比較值置0才解決這個問題

#include <REGX52.H>
#include "Motor.h"
#include "Delay.h"
#include "Timer.h"

/*
循迹功能-差速
在簡單的循迹功能基礎上,為了讓轉彎平滑,左右輪可用PWM差速轉彎
1.增加Timer.c,初始化定時器0和定時器1,中斷函數中分别對左右輪作PWM調速
*/

//左右紅外傳感器的信号引腳
sbit LeftSersor = P2^7;
sbit RightSersor = P2^6;

extern unsigned char SpeedLeft;
extern unsigned char SpeedRight;

void main()
{
	Timer0Init(); 
	Timer1Init();
	while(1)
	{
		//兩個都反射,都亮燈
		if(LeftSersor == 0 && RightSersor == 0)
		{
			SpeedLeft = 40;
			SpeedRight = 37;	//前進時右輪會快一點,導緻不能走直線,PWM調速調低點
		}
		//左邊反射,右邊沒反射,左亮
		if(LeftSersor == 0 && RightSersor == 1)
		{
			SpeedLeft = 35;		//轉彎時如果兩個輪的差速不夠大,那小車會跑出跑道
			SpeedRight = 10;
		}
		//右邊反射,左邊沒反射,右亮
		if(LeftSersor == 1 && RightSersor == 0)
		{
			SpeedLeft = 10;
			SpeedRight = 35;
		}
		//兩個都不反射,都滅燈
		if(LeftSersor == 1 && RightSersor == 1)
		{
			/*如果停止寫Stop函數的話,運作會異常,因為都不反射的時候停止,
			但此時定時器是在工作的,當中斷處理函數那邊執行時,左右輪想轉動,
			但main函數又讓其停止,小車就會有滋滋的電流響聲,改用比較值
			SpeeLeft、SpeedRight置0操作則消除這個現象*/
			
			SpeedLeft = 0;
			SpeedRight = 0;
		}
	}
}
           

繼續閱讀