<acronym id="xonnx"></acronym>
      <td id="xonnx"></td>
    1. <pre id="xonnx"></pre>

      1. 專注電子技術學習與研究
        當前位置:單片機教程網 >> MCU設計實例 >> 瀏覽文章

        智能循跡避障小車設計

        作者:佚名   來源:本站原創   點擊數:  更新時間:2014年03月11日   【字體:

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

        一、設計任務

        1、 要求

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

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

        二、方案論證與比教

        1、小車控制單元的選擇

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

        2、小車驅動單元的選擇

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

        方案一:

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

        方案二:

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

        考慮到電機的穩定性及便捷性,我們選擇了L298芯片作為驅動電機的驅動電路。

        3、 軌跡檢測模塊選擇:

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

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

        方案二、利用兩只光電開關。

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

        方案三、用四只光電開關。

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

        傳感器的安裝

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

        圖1紅外探頭的分布圖

        4、 顯示模塊選擇

        方案一:

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

        方案二

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

        方案三

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

        方案選擇

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

        三、硬件設計

        1、 最小系統的設計,如圖2。

        單片機最小系統能夠運行的必要條件是:(1)電源,(2)晶振電路,(3)復位電路。

        圖2

        2、 LCD顯示電路

        圖3

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

        3、 循跡模塊,如圖4

        圖4

        4、 避障模塊

        采用超聲波模塊壁障。

        四、軟件設計

        軟件流程圖:

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

        圖5

        五、作品總結

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

        六、附錄

        參考文獻:《51單片C語言教程》  郭天祥

                      《C程序設計》  譚浩強

        《全國大學生電子設計競賽培訓系列教程》  高吉

        #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);

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

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

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

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

         

        /*初始化函數*/
        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;
        }

        /*所的距離函數*/
        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;
        }

        /*測得運行時間的函數*/
        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);
        }

         
        /*顯示離障礙物的距離函數*/
        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);
        }

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

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

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

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

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

        /*避障函數*/
        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;
          }
        }

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

        /*循跡函數*/
        /*
        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++;
        }

        關閉窗口

        相關文章

        欧美性色欧美精品视频,99热这里只有精品mp4,日韩高清亚洲日韩精品一区二区,2020国自产拍精品高潮