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

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

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

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

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

1、 要求

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

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

二、方案論證與比教

1、小車控制單元的選擇

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

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

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

方案一:

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

方案二:

用電機(jī)的專用芯片來驅(qū)動電機(jī)。專用驅(qū)動芯片雖說價格稍微貴了一點,但是,專用芯片可同時操作多可電機(jī),且電路連接簡單,穩(wěn)定性好。是一種比較好的驅(qū)動電路。

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

3、 軌跡檢測模塊選擇:

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

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

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

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

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

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

傳感器的安裝

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

圖1紅外探頭的分布圖

4、 顯示模塊選擇

方案一:

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

方案二

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

方案三

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

方案選擇

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

三、硬件設(shè)計

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

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

圖2

2、 LCD顯示電路

圖3

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

3、 循跡模塊,如圖4

圖4

4、 避障模塊

采用超聲波模塊壁障。

四、軟件設(shè)計

軟件流程圖:

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

圖5

五、作品總結(jié)

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

六、附錄

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

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

《全國大學(xué)生電子設(shè)計競賽培訓(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ù)*/
void delay(uint z)
{
 uint x,y;
 for(x=z;x>0;x--)
  for(y=120;y>0;y--);
}

/*10us的延時函數(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;
}

/*測得運(yùn)行時間的函數(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ù)*/
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)文章