循迹模式—差速轉彎
為什麼要差速轉彎?
普通循迹模式下,小車轉彎是讓一個輪子停止,另一個輪子轉動,強行帶動停下的輪子前進,是以會造成轉彎時“一拐一拐的”,顯得不平滑;
如果使轉彎時外側輪子速度快,裡側輪子速度慢,在兩個輪子的速度差下進行轉彎,便會現得平滑很多
程式
實作差速轉彎,主要用到了左右輪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;
}
}
}