專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機(jī)教程網(wǎng) >> MCU設(shè)計(jì)實(shí)例 >> 瀏覽文章

智能循跡避障小車設(shè)計(jì)

作者:佚名   來(lái)源:本站原創(chuàng)   點(diǎn)擊數(shù):  更新時(shí)間:2014年03月11日   【字體:

本文介紹了一種基于51單片機(jī)的小車尋跡系統(tǒng)。該系統(tǒng)采用四組高靈敏度的光電對(duì)管,對(duì)路面黑色軌跡進(jìn)行檢測(cè),并利用單片機(jī)產(chǎn)生PWM波,控制小車速度。測(cè)試結(jié)果表明,該系統(tǒng)能夠平穩(wěn)跟蹤給定的路徑。整個(gè)系統(tǒng)基于普通玩具小車的機(jī)械結(jié)構(gòu),并利用了小車的底盤、前后輪電機(jī)及其自動(dòng)復(fù)原裝置,能夠平穩(wěn)跟蹤路面黑色軌跡運(yùn)行。

一、設(shè)計(jì)任務(wù)

1、 要求

(1)車輛從起跑線出發(fā),開始直線行走一段時(shí)間。當(dāng)遇到黑線時(shí),小車自動(dòng)檢測(cè)黑線并沿著黑線自動(dòng)行進(jìn)。黑線走完之后,直線行走。然后遇到障礙物,通過(guò)檢測(cè)障礙物離自己的距離來(lái)判斷自己是前進(jìn)、后退還是左轉(zhuǎn)、右轉(zhuǎn),最終達(dá)到繞過(guò)障礙物的目的。

(2)小車能夠自動(dòng)記錄,自動(dòng)顯示行駛時(shí)間,從而判斷是否符合要求。(1602必須安裝在小車上)。

二、方案論證與比教

1、小車控制單元的選擇

主控部分是整個(gè)小車的大腦,是整個(gè)小車運(yùn)行的核心部件,起著控制小車所有運(yùn)行狀態(tài)的作用。通常選用單片機(jī)作為小車的核心控制單元,本文以STC公司的STC89c52單片機(jī)為例予以介紹。STC89c52是一款擁有8K RAM、32 個(gè)I/O 口的單片機(jī),它還擁有豐富的處理功能,為小車的功能擴(kuò)展提供了相當(dāng)大的空間,只要按照該單片機(jī)的要求對(duì)其編制程序就可以實(shí)現(xiàn)很多不同的功能。此外,STC是國(guó)產(chǎn)單片機(jī),價(jià)格便宜,性價(jià)比更高。             

2、小車驅(qū)動(dòng)單元的選擇

小車驅(qū)動(dòng)電機(jī)一般不使用現(xiàn)成的玩具小車上的配套直流電機(jī),而使用減速電機(jī),因?yàn)槠潋?qū)動(dòng)力更強(qiáng),優(yōu)于普通直流電機(jī)。考慮到小車必須能夠前進(jìn)、倒退、停止,并能靈活轉(zhuǎn)向,在左右兩輪各裝一個(gè)電機(jī)分別進(jìn)行驅(qū)動(dòng)。當(dāng)左輪電機(jī)轉(zhuǎn)速高于右輪電機(jī)轉(zhuǎn)速時(shí)小車向右轉(zhuǎn),反之則向左轉(zhuǎn)。為了能控制車輪的轉(zhuǎn)速,可以采取PWM調(diào)速法,即由單片機(jī)的IOB8、IOB9輸出一系列頻率固定的方波,再通過(guò)功率放大來(lái)驅(qū)動(dòng)電機(jī),在單片機(jī)中編程改變輸出方波的占空比就可以改變加到電機(jī)上的平均電壓,從而可以改變電機(jī)的轉(zhuǎn)速。左右輪兩個(gè)電機(jī)轉(zhuǎn)速的配合就可以實(shí)現(xiàn)小車的前進(jìn)、倒退、轉(zhuǎn)彎等功能。用單片機(jī)控制電機(jī)的時(shí)候,需要加驅(qū)動(dòng)電路,為電機(jī)提供足夠大的驅(qū)動(dòng)電流。使用不同的電機(jī),其驅(qū)動(dòng)電路也不同,我們應(yīng)該根據(jù)實(shí)際需求選擇合適的驅(qū)動(dòng)電路,通常有以下幾種方案:

方案一:

用三極管電流放大驅(qū)動(dòng)電路。三極管是一種常見(jiàn)的電子元器件,價(jià)格便宜,也很實(shí)用。但是,它僅能驅(qū)動(dòng)單個(gè)單片機(jī)并且要求所驅(qū)動(dòng)電流不大,而且用三極管搭建驅(qū)動(dòng)電路也很麻煩。

方案二:

用電機(jī)的專用芯片來(lái)驅(qū)動(dòng)電機(jī)。專用驅(qū)動(dòng)芯片雖說(shuō)價(jià)格稍微貴了一點(diǎn),但是,專用芯片可同時(shí)操作多可電機(jī),且電路連接簡(jiǎn)單,穩(wěn)定性好。是一種比較好的驅(qū)動(dòng)電路。

考慮到電機(jī)的穩(wěn)定性及便捷性,我們選擇了L298芯片作為驅(qū)動(dòng)電機(jī)的驅(qū)動(dòng)電路。

3、 軌跡檢測(cè)模塊選擇:

方案一、使用簡(jiǎn)易光電傳感器結(jié)合外圍電路探測(cè)。

 光電傳感器實(shí)際效果并不理想,對(duì)行駛過(guò)程中的穩(wěn)定性要求很高,且誤測(cè)幾率較大、易受光線環(huán)境和路面介質(zhì)影響。在使用過(guò)程極易出現(xiàn)問(wèn)題,而且容易因?yàn)?該部件造成整個(gè)系統(tǒng)的不穩(wěn)定。

方案二、利用兩只光電開關(guān)。

分別置于軌道的兩側(cè),根據(jù)其接受到白線的先后來(lái)控制小車轉(zhuǎn)向來(lái)調(diào)整車向,但測(cè)試表明,如果兩只光電開關(guān)之間的距離很小,則約束了速度,如果著重于小車速度的提升,則隨著車速的提升,則勢(shì)必要求兩只光電開關(guān)之間的距離加大,從而使得小車的行駛路線脫離軌道幅度較大,小車將無(wú)法快速完成準(zhǔn)確的導(dǎo)向從而有可能導(dǎo)致尋跡失敗。

方案三、用四只光電開關(guān)。

一只置于軌道中間,兩只置于軌道外側(cè),當(dāng)小車脫離軌道時(shí),即當(dāng)置于中間的一只光電開關(guān)脫離軌道時(shí),等待外面任一只檢測(cè)到黑線后,做出相應(yīng)的轉(zhuǎn)向調(diào)整,直到中間的光電開關(guān)重新檢測(cè)到黑線(即回到軌道)再恢復(fù)正向行駛�,F(xiàn)場(chǎng)實(shí)測(cè)表明,雖然小車在尋跡過(guò)程中有一定的左右搖擺(因?yàn)樗?gòu)小車的內(nèi)部結(jié)構(gòu)決定了光電開光之間的距離到達(dá)不了精確計(jì)算值1厘米),但只要控制好行駛速度就可保證車身基本上接近于沿靠軌道行駛。綜合循跡的準(zhǔn)確性和行車的速度,我們選擇了方案三。并采用了ST168光電對(duì)管。因?yàn)镾T168采用高發(fā)射功率紅外光、電二極管和高靈敏光電晶體管組成,采用非接觸式檢測(cè)方式。ST168的檢測(cè)距離很小,一般為8~15毫米,因?yàn)?毫米以下是它的檢測(cè)盲區(qū),而大于15毫米則很容易受干擾。經(jīng)過(guò)多次測(cè)試、比較,發(fā)現(xiàn)把傳感器安裝在距離檢測(cè)物表面10毫米時(shí),檢測(cè)效果最好。

傳感器的安裝

  正確選擇檢測(cè)方法和傳感器件是決定循跡效果的重要因素,而且正確的器件安裝方法也是循跡電路好壞的一個(gè)重要因素。從簡(jiǎn)單、方便、可靠等角度出發(fā),同時(shí)在底盤裝設(shè)4個(gè)紅外探測(cè)頭,進(jìn)行兩級(jí)方向糾正控制,將大大提高其循跡的可靠性,具體位置分布如圖1所示。圖中循跡傳感器全部在一條直線上。其中X1與Y1為第一級(jí)方向控制傳感器,X2與Y2為第二級(jí)方向控制傳感器,并且黑線同一邊的兩個(gè)傳感器之間的寬度不得大于黑線的寬度。小車前進(jìn)時(shí),始終保持(如圖3中所示的行走軌跡黑線)在X1和Y1這兩個(gè)第一級(jí)傳感器之間,當(dāng)小車偏離黑線時(shí),第一級(jí)傳感器就能檢測(cè)到黑線,把檢測(cè)的信號(hào)送給小車的處理、控制系統(tǒng),控制系統(tǒng)發(fā)出信號(hào)對(duì)小車軌跡予以糾正。第二級(jí)方向探測(cè)器實(shí)際是第一級(jí)的后備保護(hù),它的存在是考慮到小車由于慣性過(guò)大會(huì)依舊偏離軌道,再次對(duì)小車的運(yùn)動(dòng)進(jìn)行糾正,從而提高了小車循跡的可靠性。

圖1紅外探頭的分布圖

4、 顯示模塊選擇

方案一:

 采用LED顯示,LED常見(jiàn)且價(jià)格便宜,但是僅能顯示數(shù)字和簡(jiǎn)單的字母,且外部電路比較復(fù)雜,需要專門的驅(qū)動(dòng)電路實(shí)現(xiàn)。

方案二

     采用LCD1602顯示,1602是市面上價(jià)格適中的顯示器件,不僅僅能顯示數(shù)字還能顯示字母和特殊符號(hào),且支持背光解決了一半LCD顯示不夠清晰的問(wèn)題,且有3.3低電壓產(chǎn)品,更大的解決了功耗問(wèn)題。

方案三

采用LCD12864顯示,12864顯示效果清晰,且可以顯示更多信息,支持中文字庫(kù),有很好的人及交換功能,能顯示更多更清楚的信息。但是12864顯示器市場(chǎng)上價(jià)格比較昂貴,且功耗很大,在開背光的情況下耗電非常之大,不易于使用在移動(dòng)設(shè)備上。

方案選擇

使用LCD1602不僅價(jià)格適中,且功耗很低,用擁有較好的人機(jī)交互價(jià)值。且在此方案中僅顯示小車需要采集的數(shù)據(jù)即可,所以本系統(tǒng)采用了低功耗的1602顯示器,即方案二。

三、硬件設(shè)計(jì)

1、 最小系統(tǒng)的設(shè)計(jì),如圖2。

單片機(jī)最小系統(tǒng)能夠運(yùn)行的必要條件是:(1)電源,(2)晶振電路,(3)復(fù)位電路。

圖2

2、 LCD顯示電路

圖3

本次選用的1602液晶顯示屏最主要的是顯示小車運(yùn)行時(shí)間。我們將1602的液晶的D0~D7數(shù)據(jù)口接到單片機(jī)的P0口;然后將讀寫選擇端(R/W)直接接地;液晶顯示對(duì)比度調(diào)節(jié)端(VO)接一個(gè)10K的電位器,最后與電源正極相連;數(shù)據(jù)/命令選擇端(RS)P3^5口,是能信號(hào)(E)接P3^4口。如圖3。

3、 循跡模塊,如圖4

圖4

4、 避障模塊

采用超聲波模塊壁障。

四、軟件設(shè)計(jì)

軟件流程圖:

其程序控制框圖如圖5。小車進(jìn)入循跡模式后,即開始不停地掃描與探測(cè)器連接的單片機(jī)I/O口,一旦檢測(cè)到某個(gè)I/O口有信號(hào),即進(jìn)入判斷處理程序(switch),先確定4個(gè)探測(cè)器中的哪一個(gè)探測(cè)到了黑線,如果InfraredML(左面第一級(jí)傳感器)或者InfraredSL(左面第二級(jí)傳感器)探測(cè)到黑線,即小車左半部分壓到黑線,車身向右偏出,此時(shí)應(yīng)使小車向左轉(zhuǎn);如果是InfraredMR(右面第一級(jí)傳感 器)或InfraredSR(右面第二級(jí)傳感器)探測(cè)到了黑線,即車身右半部壓住黑線,小車向左偏出了軌跡,則應(yīng)使小車向右轉(zhuǎn)。在經(jīng)過(guò)了方向調(diào)整后,小車再繼續(xù)向前行走,并繼續(xù)探測(cè)黑線重復(fù)上述動(dòng)作。由于第二級(jí)方向控制為第一級(jí)的后備,則兩個(gè)等級(jí)間的轉(zhuǎn)向力度必須相互配合。第二級(jí)通常是在超出第一級(jí)的控制范圍的情況下發(fā)生作用,它也是最后一層保護(hù),所以它必須要保證小車回到正確軌跡上來(lái),則通常使第二級(jí)轉(zhuǎn)向力度大于第一級(jí),即level2>level1(level1、level2為小車轉(zhuǎn)向力度,其大小通過(guò)改變單片機(jī)輸出的占空比的大小來(lái)改變),具體數(shù)值在實(shí)地實(shí)驗(yàn)中得到。
   

圖5

五、作品總結(jié)

    這個(gè)避障循跡小車使我們自己設(shè)計(jì)硬件、自己編輯軟件制作的。在制作的過(guò)程中,我們遇到了許多困難,在困難中也學(xué)到了許多知識(shí),亦得到了許多樂(lè)趣。在這個(gè)過(guò)程中,我懂得了,遇到困難不要退縮,只有迎難而上,方能成就大事。同時(shí),在學(xué)習(xí)的過(guò)程中,要注意細(xì)節(jié)。所謂細(xì)節(jié)決定成敗,便是如此。就像我們編輯軟件的時(shí)候,出現(xiàn)過(guò)這樣一個(gè)問(wèn)題,在現(xiàn)實(shí)時(shí)間這個(gè)模塊中,我們用定時(shí)器來(lái)定時(shí),50ms一次中斷,同時(shí)定義一個(gè)變量count,每次中斷count都自加一次,然后用if(count==20)來(lái)判斷時(shí)間,但結(jié)果卻是幾十秒才加一次,我們花了近一天的時(shí)間沒(méi)有想出結(jié)果,最后在學(xué)長(zhǎng)的幫助下將判斷時(shí)間的語(yǔ)句改為if(count>=20),結(jié)果與自己想的一模一樣了。所以我們?cè)谝院蟮膶W(xué)習(xí)過(guò)程中一定要注重理論知識(shí),不要把事情想得太簡(jiǎn)單了,這樣才可以提高我們的能力。

六、附錄

參考文獻(xiàn):《51單片C語(yǔ)言教程》  郭天祥

              《C程序設(shè)計(jì)》  譚浩強(qiáng)

《全國(guó)大學(xué)生電子設(shè)計(jì)競(jìng)賽培訓(xùn)系列教程》  高吉

#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
#define speed  170
uchar code aa1[]="distance:";
uchar code aa2[]="t=";
uchar code aa3[]="s=";

sbit E=P3^4;
sbit RS=P3^5;
sbit echo=P2^0;
sbit trig=P2^1;
sbit bell=P1^0;
sbit dj1=P1^4;
sbit dj2=P1^5;
sbit dj3=P1^6;
sbit dj4=P1^7;
sbit A1=P2^2;
sbit B1=P2^3;
sbit C1=P2^4;
/*
sbit left_red = P3^4;
sbit mid_red1 = P3^5;
sbit mid_red2 = P3^6;
sbit right_red = P3^7;
*/

uchar m,count,miao;
uint juli;

/*void xunji();*/
void delay(uint z);
void delay50us() ;
void write_com(uchar com);
void write_data(uchar date);
void init(void);
uint getdistance(void);
void write_data2(uchar add,uchar date);
void write_data3(uchar add,uchar date);
void write_date1(unsigned long x);
void forward(void);
void back(void);
void turnleft(void);
void turnright(void);
void xianshi(void);
void bizhang(uint x);
void zhishideng(uint p);

/*延時(shí)函數(shù)*/
void delay(uint z)
{
 uint x,y;
 for(x=z;x>0;x--)
  for(y=120;y>0;y--);
}

/*10us的延時(shí)函數(shù)*/
void delay50us()  
{
    uchar i;
    for(i=50;i>0;i--);
}

/*寫指令函數(shù)*/
void write_com(uchar com)
{
 E=0;
 RS=0;
 delay(5);
 E=1;
 P0=com;
 E=0;
}

/*寫數(shù)據(jù)函數(shù)*/
void write_data(uchar date)
{
 E=0;
 RS=1;
 delay(5);
 E=1;
 P0 = date;
 E=0;
 RS=0;
}

 

/*初始化函數(shù)*/
void init()
{
/*
 left_red =  0;
 mid_red1 =  1;
 mid_red2 =  1;
 right_red = 0;
*/
 TMOD = 0x11;
 trig=0;   //超聲波模塊控制端                        
    echo=0;   //超聲波模塊接收端
    TH0=0;
    TL0=0;
    TR0=0;
 A1=1;
 B1=1;
 C1=1;
 bell = 0;
 miao = 0;
 juli = 0;
 delay(15);
 write_com(0x38);
 delay(5);
 write_com(0x38);
 delay(5);
 write_com(0x08);
 write_com(0x01);
 write_com(0x06);
 write_com(0x0c);
 write_com(0x80+0x40);
 for(m=0;m<2;m++)
 {
  write_data(aa2

­­);
  delay(5);
 }
 write_com(0x80+0x40+6);
 for(m=0;m<2;m++)
 {
  write_data(aa3 ­);
  delay(5);
 }
 TH1 = (65535-50000)/256;
 TL1 = (65535-50000)%256;
 EA = 1;
 ET1 = 1;
 TR1 = 1;
}

/*所的距離函數(shù)*/
uint getdistance()
{
 uint time;
 uint i = 65530;
 TR0 = 0;
 TH0 = 0;
 TL0 = 0;
 echo = 1;
 trig = 1;
 delay50us();
 trig = 0;
 while((echo==0)&&(i>10))
 {
  i--;
 }
 if(echo==1)TR0=1;
 else TR0=0;
 i=0;
 while((echo==1)&&(i<4672))
 {
  i++;
 }
    TR0=0;
 time=(TH0*0x0100)+TL0;
 return time;
}

/*測(cè)得運(yùn)行時(shí)間的函數(shù)*/
void write_data2(uchar add,uchar date)
{
 uchar bai,shi,ge;
 bai = date/100;
 shi = date%100/10;
 ge = date%10;
 write_com(0x80+0x40+add);
 write_data(0x30+bai);
 write_data(0x30+shi);
 write_data(0x30+ge);
}

 
/*顯示離障礙物的距離函數(shù)*/
void write_date1(unsigned long x)
{
 uchar qian,bai,shi,ge;
 qian = x/1000;
 bai = (x%1000)/100;
 shi = (x%100)/10;
 ge = x%10;
 write_com(0x80);
 for(m=0;m<9;m++)
 {
  write_data(aa1

­­­);
  delay(1);
 }
 write_com(0x80+10);
 write_data(0x30+qian);
 delay(1);
 write_data(0x30+bai);
 delay(1);
 write_data(0x30+shi);
 delay(1);
 write_data(0x30+ge);
 delay(1);
}

/*小車前進(jìn)函數(shù)*/
void forward()
{
 dj1 = 1;
 dj2 = 0;
 dj3 = 1;
 dj4 = 0;
}

/*小車后退函數(shù)*/
void back()
{
 dj1 = 0;
 dj2 = 1;
 dj3 = 0;
 dj4 = 1;
}

/*小車左轉(zhuǎn)函數(shù)*/
void turnleft()
{
 dj1 = 0;
 dj2 = 1;
 dj3 = 1;
 dj4 = 0;
}

/*小車右轉(zhuǎn)函數(shù)*/
void turnright()
{
 dj1 = 1;
 dj2 = 0;
 dj3 = 0;
 dj4 = 1;
}

/*顯示時(shí)間和路程函數(shù)*/
void  xianshi()
{
  if(count>=20)
  {
   count = 0;
   miao++;
   write_data2(2,miao);
   if(miao%3==0)
   {
    bell = 1;
    delay(20);
    bell = 0;
   }
  }
}

/*避障函數(shù)*/
void bizhang(uint x)
{
  switch(x/100)
  {
   case 0:
   case 1:
   case 2: back();break;
   case 3:
   case 4:
   case 5: forward();break;
   default: forward();break;
  }
}

/*指示燈函數(shù) */
void zhishideng(uint p)
{
 if(p>300)
 {
  C1 = 0;
  B1 = 1;
 }
 else
 {
  B1 = 0;
  C1 = 1;
  bell = 1;
 }
 
}

/*循跡函數(shù)*/
/*
void xunji()
{

 uchar flag;
 if((left_red==1)||(mid_red1==1))
  flag = 1;
 else
  if((right_red==1)||(mid_red2==1))
   flag = 2;
  else
   if((mid_red2==1)&&(mid_red1==1))
    flag = 3;
   else
    flag = 0;

 switch(flag)
 {
  case 0:forward();break;
  case 1:turn_left();break;
  case 2:turn_right();break;
  case 3:forward();break;
  default:break;
 }
}
*/

void main() 
{
    uint dis;
  init();
 while(1)
   {
    A1 = 0;
  xianshi();
  /*xunji();*/
  dis= getdistance();
  dis = (uint)(dis*0.17);
  zhishideng(dis);
     write_date1(dis);
  bizhang(dis);
 }
}

void timer0() interrupt 3
{
    TH1 = (65535-50000)/256;
 TL1 = (65535-50000)%256;
 count++;
}

關(guān)閉窗口

相關(guān)文章