這段時(shí)間要用超聲波做一個(gè)演示實(shí)驗(yàn),就是使用超聲波和舵機(jī)結(jié)合,做一個(gè)自動(dòng)壁障演示實(shí)驗(yàn)。
就是將超聲波接到舵機(jī)上,通過轉(zhuǎn)動(dòng)舵機(jī)來獲取各個(gè)方向到小車的距離,從而控制小車運(yùn)動(dòng),避開障礙物,并尋找最佳路徑。整個(gè)小車基于航太電子提供的51智能小車,如下圖:
車前面的超聲波模塊就是固定在下面的舵機(jī)上面的,實(shí)際實(shí)驗(yàn)時(shí)需要將顯示屏取下,否則會(huì)檔到舵機(jī)。
下面簡單說下超聲波模塊:
HC-SR04超聲波測距模塊可提供2cm-400cm的非接觸式距離感測功能,測距精度可達(dá)3mm;模塊包括超聲波發(fā)射器、接收器與控制電路,檢測角度為30°。
另外還有超聲波的控制方式:
(1)采用IO口TRIG觸發(fā)測距,給最少10us的高電平信號(hào)。
(2)模塊自動(dòng)發(fā)送8個(gè)40khz的方波,自動(dòng)檢測是否有信號(hào)返回;
(3)有信號(hào)返回,通過IO口ECHO輸出一個(gè)高電平,高電平持續(xù)的時(shí)間就是超聲波從發(fā)射到返回的時(shí)間。測試距離=(高電平時(shí)間*聲速(340M/S))/2
下面說說這個(gè)超聲波的缺陷了,由于該超聲波測距本身的缺陷以及該模塊也是市面上比較便宜的模塊,在實(shí)際運(yùn)行時(shí)往往達(dá)不到要求,特別是小車在運(yùn)行時(shí)整個(gè)車子是在震動(dòng)的,對(duì)距離測試十分不利。
當(dāng)車子在跑動(dòng)時(shí)測出來的距離變動(dòng)幅度會(huì)較大,如果加上舵機(jī)的轉(zhuǎn)動(dòng),想實(shí)時(shí)測到距離是更不可能的了。目前超聲波測量周期建議是100ms,在100ms的時(shí)間里,超聲波在車上的變動(dòng)還是比較大的,所以在測量距離的時(shí)候,盡量讓車子停下來,而且舵機(jī)停止轉(zhuǎn)動(dòng)。
另外還有一個(gè)大問題,就是前面的障礙物與超聲波不是正對(duì)著,而是呈一個(gè)較大的角度時(shí),測出來的距離也是不準(zhǔn)的。這種現(xiàn)象體現(xiàn)在當(dāng)小車與墻斜著跑過去時(shí)會(huì)直接撞上去,顯然是完全沒檢測到墻面。根據(jù)示波器查看結(jié)果,當(dāng)相對(duì)正對(duì)超聲波傾斜角度小于約30°時(shí),還是可以測出來的,當(dāng)變得更大時(shí),就會(huì)出現(xiàn)回響電平突然變得很長的情況,這種時(shí)候也會(huì)有測量比較接近實(shí)際的時(shí)候,所以在這里需要做濾波處理?;仨懶盘?hào)要么是接近實(shí)際,要么是很長,這樣的情況是很好判斷的。
下面是我基于51單片機(jī)平臺(tái)做的超聲波讀取的方法,暫沒考慮單片機(jī)性能浪費(fèi)的問題,用到了while等待。觸發(fā)信號(hào)輸出以及回響信號(hào)計(jì)數(shù)采用了定時(shí)器T2
如下:
初始化函數(shù),對(duì)T2 初始化
void UltraSoundInit()
{
Trig = 0;
TH2 = RCAP2H = 0;
TL2 = RCAP2L = 0;
TR2 = 0;//關(guān)閉定時(shí)器
ET2=1; //允許T2中斷
}
然后就是T2的中斷函數(shù),當(dāng)定時(shí)器溢出時(shí)進(jìn)入,可以用來判斷輸出的回響信號(hào)是否過長,當(dāng)超聲波模塊異常時(shí)也可用來跳出while死循環(huán)
/*******************************************************************************
* 函 數(shù) 名 :Timer0Int
* 函數(shù)功能 :定時(shí)器0中斷服務(wù)函數(shù)
* 輸 入 :無
* 輸 出 :無
*******************************************************************************/
void Timer2Int() interrupt 5 // 定時(shí)器2中斷是5號(hào),當(dāng)定時(shí)器2發(fā)生溢出時(shí)說明量測的距離過遠(yuǎn)或超聲波本次測量異常
{
TF2 = 0;
overflow_count++;
TH2 = 0;
TL2 = 0;
if(overflow_count == 2)
{
status = 5;//超時(shí)
}
}
下面就是測量的方法,比較簡單,當(dāng)測量失敗就讓那個(gè)全局變量為0,注意:超聲波是有最小測量距離的,一般障礙物理超聲波2cm以內(nèi)時(shí),測得距離就不準(zhǔn)了,所以測量距離不可能為0
void GetDistance()
{
//發(fā)送觸發(fā)信號(hào)
Trig = 1;
status = 1;
TH2 = 0;
TL2 = 0;
TR2 = 1;//打開定時(shí)器
while(TL2 < 42);//延時(shí)超過10us
status = 2;
Trig = 0;
TR2 = 0;
TH2 = 0;
TL2 = 0;
overflow_count = 0;
TR2 = 1;
while(Echo == 0)//等待回向信號(hào)起始位置
{
if(status == 5)
{
status = 0;
distance_cm = 0;
return;//本次失敗
}
}
TR2 = 0;//清空計(jì)數(shù)
TH2 = 0;
TL2 = 0;
overflow_count = 0;
TR2 = 1;
while(Echo == 1)//開始計(jì)算長度
{
if(status == 5)
{
status = 0;
distance_cm = 0;
TR2 = 0;
return;//本次失敗
}
}
dis_count =overflow_count*65536 + TH2*256 + TL2;
TR2 = 0;
distance_cm = (unsigned int)(((long)(dis_count) * 34)/8000);//聲速 dis_count*(1/(FOSC/12))*Vsound*100/2
status = 0;//準(zhǔn)備下次發(fā)送
}
下面就是要調(diào)用上面函數(shù)的方法,注意這個(gè)函數(shù)執(zhí)行間隔至少是100ms(其實(shí)75ms的時(shí)候也可以)
void GetDistanceDelay()
{
distance_cm = 0;
while(distance_cm == 0)
{
GetDistance();
if(distance_cm != 0)
{
return;
}
Delayms(100);
}
}
這樣做雖然浪費(fèi)了很多處理器性能,但比起獲得錯(cuò)誤數(shù)據(jù)還是要好些。在這個(gè)實(shí)驗(yàn)中,除了車子前行時(shí)沒100ms檢測一次距離,在其他時(shí)候都是要等車子停止時(shí)才測距的,另外使用超聲波做這個(gè)事本來就是比較勉強(qiáng)的,如果想要更好的效果,建議搭配其他傳感器如光電對(duì)管壁障模塊,用這個(gè)模塊來檢測斜邊的障礙物還是很有效的,也就是遠(yuǎn)處交給超聲波處理,近處交給壁障模塊處理。