1. 程式人生 > >飛思卡爾智慧車經驗

飛思卡爾智慧車經驗

本人蔘加了第九屆飛思卡爾智慧車比賽,光電組。現在分享下自己的心得和體會,希望能夠給後來人帶來點幫助。為什麼不在智慧車論壇發,因為那個論壇我現在不經常上了,如果有人回覆我怕不能及時回覆,下面這些內容適合新手,當然也可能有錯誤,希望根據自己的情況甄別。好了廢話不多說開始吧,分幾點來說。

1.做車心態和賽前準備

這個放在第一點是非常重要的,做車一定必須有個好心態,中間可能遇到各種各樣的問題,比如車本來好好的,突然不能跑了,或者龜速了,突然某個器件燒了,電機不轉動了,尤其是光電組和攝像頭組的對環境依賴很大,電磁組雖然訊號較穩定,但是車因為速度快,往往會撞壞採集模組,同樣很坑。不論什麼時候都要保持一個積極向上的心態,小車虐我千百遍,我待小車如初戀。不乏很多人開始做車之前士氣高昂,遇到困難也會嘗試解決,但是如果一個問題長時間不能解決,就漸漸放棄了,長時間是多次時間,也許一週,一個月都是有可能的,或者別人的車都跑的很快了,自己的車還是龜速,甚至連龜速都是不能跑,在雪上加霜的是,你還要上課,課程難,但是你上課又沒有心思聽,人在教室,心裡卻想著車,一學期快結束了,也快比賽了,大家都準備考試,你還在調車,擔心各種掛科,白天上課,晚上調車調到深夜........各種情況也要有心裡準備,這些都是極有可能經歷的,在比賽中也有不少大神的車6次機會都沒有跑下來......這些都要去思考都是很有可能的,所以我們做車心裡準備一定要做好,同時要保持一個好的心態,在自己遇到困難的時候,要時刻相信困難的解決就在下一秒,也要不斷總結,思考問題可能出現在什麼地方。另一點不得不說的就是要選擇好隊友了,一定要相互合作,隊友不一定要多麼多麼牛,但是一定要是那種樂意付出,能吃苦的人,有困難大家一起扛才可以,遇到問題可以一起商量解決才可以,希望做車時一定要嚴以律己,絕對不能坑隊友,以負責的態度去對自己的隊伍,同時為了自己不被坑,選擇自己信任的人。上面這些絕對是重要的,所以放在第一點,你可以不相信,但是別後悔。

2.車的機械結構

智慧車有個大神說的不錯:車的機械結構決定了車的最大速度,車的軟體決定了車可以達到的速度。這點我非常認可,很多參賽的都不是機械專業的,基本都是根據以往的車來確定車的機械結構,重心高低,電池位置,前輪內傾還是外傾等等。其實我感覺這些在車2m/s一下的時候都不是很關鍵的,至少說影響不是那麼明顯。說一下我當初一個愚蠢的錯誤,認為舵機的中值在pwm週期為20K的時候,1500是中值,就給舵機1500的pwm值然後把這個位置當作中間位置,放車上去了,後來很長時間發現左右轉不一樣,發現舵機1500根本不是中值。舵機的打角度範圍是0-180度,車的前輪用不了那麼多,我們只需要選擇一個範圍,在這個範圍裡面選擇一個值作為中值,給這個值的時候要保證舵機打角度可以使車的前輪左右打角度都能打到極限,最好選取90度時候作為中值。這樣是最好的,個人這樣辦的。車的機械調整也不是一成不變的,不要過於盲目的聽從別人,有些時候別人會無意誤導了你,比如第八屆飛思卡爾的B車模是倒著跑的,輪子的差速應該是緊一些效果好,第九屆變了,車正著跑,如果你還是把車的差速調到很緊,車根本不行,彎道必然出去,所以遇到問題還是多嘗試多分析好,在前期不要過於在意車的結構,除非你比較明白,假如在第九屆你按照第八屆參賽的人的意見把車差速調緊,以後也不懷疑這個問題,你的車估計永遠跑不了,但是你只要隨意點,前期車不太快的情況下還是可以跑的,以後自己調節找找規律也很好啊。

3.採用的感測器

這一點也是重要的,車的控制是根據採集來的資訊來處理的,如果採集得到的資訊本身都是錯誤的,那麼無論你的演算法有多牛,估計車也不能跑。電磁的我沒有做過,我對硬體瞭解很少,但是在設計或者製作的時候最好保證採集性要好,讓在距離一個相對較遠的範圍還是能夠採集到訊號。光電組的只有一行資料,經常會遇到丟線的問題,尤其是車入彎道後必丟內圈的線,最令人蛋疼的就是線性ccd的餘弦效應。選擇感測器的時候一定要選擇餘弦效應比較小的,視野比較大的。比如我們反覆換,最後選擇了廣角無畸變鏡頭,效果不錯,這一步也是決定車能否執行的關鍵一環。如果這一環選擇的好,程式按照最簡單的寫都可以使車執行,也許速度不盡人意,但是選擇不好,不論你程式怎麼改,引數怎麼調節,車都不能跑完全程一次。

4.硬體電路

這一點具體我不能說什麼,因為我不懂,參賽的時候發現原來一個很不起眼的問題,顯的很重要,撥碼開關,當時我們用了四個,因為自己的車起跑線檢測是利用程式檢測跳變沿的個數實現的,怕誤檢,不得已只能犧牲一個開關設定檢測與不檢測,只要有一次誤檢,我就把開關撥回來。後來聽別人說,有些賽區試車的時候燈光和比賽燈光不一樣,導致很多車沒有跑下來,又犧牲了一開關設定兩個不同的閾值,,現在就剩下兩個開關設定速度了。四個速度有點少。能夠在硬體上解決的最好在硬體上解決,比如起跑線檢測,我的很有可能出現漏檢,但是用硬體的紅外檢測就不會,比程式要好很多。而比賽的時候尤其是名次靠前些的隊伍,一秒的名次差距是很恐怖的。

5.演算法

上面完了後,就應該說是程式了,很多人把這個稱為演算法,其實我感覺這算不上演算法,頂多算策略,至少大多數人的都不能成為演算法,我的是不能的。根據採集到的資訊進行處理讓車在賽道上行駛就是一種策略,其實不必過於在策略,尤其是非要找大神的程式碼,別人一半不給,給了也不全,或者看不懂,看懂的時間估計自己思考的都差不多了。這種控制策略絕對不是一條,但是,自己要去根據賽道元素對比自己的演算法去思考,看看有沒有什麼漏洞。怎麼去修改,有沒有少考慮了什麼情況。比如,拿ccd來說,無法就是如何根據採集到的一行資料,提取中線位置,然後車根據這個位置求出誤差,然後得到舵機打的角度,丟線的時候無非就是要求在如何只有一條線的情況下,或者兩條線都丟的情況下正確的得到中線位置,保證舵機打相應的角度,確切的說打的角度在合理範圍之內。不同的思考方式會有不同的演算法,但是都是為了計算中線位置,但是,計算過程可能不一樣,比如有些人用二值化,有些人用根據左右線計算中值。下面我說一下自己對幾種方法的看法。首先你得到一個數組,裡面包含了採集到的值,你是怎麼提取,從左向右,從右向左,從中間向兩邊,不論怎麼樣,你都要避免利用賽道外的資訊,或者防止賽道外的資訊對你處理這些資料造成影響,有時候利用了也無所謂因為比賽時候賽道環境比較好,但是建議最好還是不用好。

1.二值化

這種方式有很多人用,程式碼大概如下
void binaryzation(unsigned char *pixel)
{
    int i,j;
    for(int j=0;j<128;j++)
    {
        if(chen[j]>=PixelAverageValue)//比較是否大於臨界值,黑線電平低
            chen[j]=1;
        else
            chen[j]=0;
    }
    for(int i=0;i<128;i++)//根據賽道黑白都是連續的特性進行濾波處理
    {
        if(Pixel[i]==0)
        {
            if((Pixel[i-1]==1)&&(Pixel[i+1]==1))
            {
                Pixel[i]=1;
            }
        }
        if(Pixel[i]==1)
        {
            if((Pixel[i-1]==0)&&(Pixel[i+1]==0))
            {
                Pixel[i]=0;
            } 

        }
    }

}
void calculate_line(void)//計算中線
{
    for(int i=(int)g_centre_line_new;i>=0;i--)
    {
        if(Pixel[i]==1&&Pixel[i-1]==0&&Pixel[i-2]==0&&Pixel[i-3]==0)
        {
            left=i-1;//記錄左線的座標
            break;
        }
    }
for(int j=(int)g_centre_line_new;j<=127;j++)
{
    if(Pixel[j]==1&&Pixel[j+1]==0&&Pixel[j+2]==0&&Pixel[j+3]==0)
    {
        right=j+1;//記錄右線的座標
        break;
    }   
}
old_line= new_line;
new_line=(left+right)/2;
}

這種方法我感覺不是很好,但是有些人用的非常不錯,想不到什麼好處,感覺壞處:首先這個值設定顯的非常重要,相對於下面將要提到的檢測跳變沿還重要,尤其是餘弦效應比較大,或者採集到的影象資訊不太好的時候,這一個值確定很難,如果設定成靜態,對環境依賴很強,動態根據採集到畫素點平均值在乘以係數得到,很坑爹,下面會提到調引數問題,一個值決定生死,裡面判斷有可能會出現很多點是誤判了,如果誤判的點是在接近左右線的位置,把黑線看成了白線,或者判斷的是白線其實是黑線,當然如果誤判都對稱還好說,如果不對稱的,比如單側丟線的時候呢,未丟線的黑線和白色賽道沒有什麼變化,因為丟線的位置原來是黑色電壓低,現在突然變成了白色,按照平均值來計算臨界值肯定不準確,對確定為丟失黑線的位置有干擾。而且這個要多次對陣列進行訪問,有點浪費時間。還有就是當ccd視野比較廣的時候,某些邊界點的值實際是賽道外面的,就我個人來說我的ccd資訊的陣列,座標小於40,或者大於90的點都是看的賽道外面,上面方法確定中線的時候顯然利用了這些點,是不應該的。如果ccd鏡頭視野不廣闊,又非常容易丟線,這就矛盾了。

2.檢測跳變沿:

這種方法是用的最多的,不是我瞎說,以前看過別人統計。程式碼大概如下:
void CCD_P2(unsigned char *s,int interval,int yuzhi)
{
  int i,j;
  int lines=0;
  b_left_flag=0;
  b_right_flag=0;//左右線檢測標誌位
  for(i=lines;i-interval-1>=L_B;i--)
  {
    if(s[i]-s[i-interval]>yuzhi&&s[i-1]-s[i-interval-1]>yuzhi)
    {
			b_left=i-interval;
			b_left_flag=1;
			break;
    }
  }
  for(j=lines;j+interval+1<=R_B;j++)
   {
		if(s[j]-s[j+interval]>yuzhi&&s[j+1]-s[j+interval+1]>yuzhi)
		{
			b_right=j+interval;
			b_right_flag=1;
			break;
		}
	}
 
}
雖然這種方法也用到比較,也是通過找臨界值,來確定中線位置。但是,通過隔幾個點比較這些值是否大於臨界值來確定黑線這種方法要比那個小,而且可以也比較容易修復誤差,比如我檢測到第i個點符合條件,i是不是黑線呢,我可以繼續檢測到,直道不符合條件,就可以準確的知道那個一定是黑線了,當然這只是一種思想。我用的就是這種方法。
當兩條線都檢測到就可以正常處理,所以關鍵的是如何處理丟線的情況,這種策略不是唯一的,不能說對與錯,這個同樣可以自己尋找方法,關鍵同樣是,你要自己琢磨自己這樣操作符不符合實際,比如丟了右線,你給多少,你是給右線確定的數值,如果這樣,右線給多少。還是根據自己左線的位置的座標加上一個數值直接得到中值,這個值給多少 如何確定,怎麼才算合理。我的方法是補上一次的賽道寬度的一半。程式碼後面會提供。 3.尋黑不尋白。這個方法不是我的。雖然簡單,但是人家可以用,我用不了,不知道為什麼。也許這個適合直立平衡車,程式碼大概如下:
void ccd_p(char *s)
{
    int i,line=0,count=0;
    for(i=0;i<128;i++)
    {
       if(s[i]>yuzhi)
       {
           count++;
           line+=i;
       } 
    }
    if(count!=0)
    {
        line=line/count;
    }
    else
    {
        line=64;
    }
}
這種方法,雖然也利用了賽道外資訊,但是省去了丟線的處理,因為檢測的是白色部分。臨界值的確定也要是動態的,根據自己嘗試,比如本次採集到的最大值和最小值的差之類的再乘一個係數。如果賽道背景是藍色,這種方法也許可以,但是如果是白色,或者淺色,估計有點玄乎。這種方法就不用糾結於丟線。效果如何還是自己嘗試吧。

6.引數除錯和細節

程式碼完成了就是引數的除錯了

舵機的PD調節

不知道別人是怎麼樣的,我是這樣的,首先根據舵機中值是1900,距離左右極限是600.,然後移動車體,用上位機軟體用手左右移動車在直道或者彎道上車的中線距離64的差的最大值大概是多少,比如我的在30左右,600除以30就是20多,這還不確定,但是確定的是,他是一個兩位數。先在20上下範圍調,這時候把D設定為0.然後給車一個慢速,1.5m/s左右,一直調到車可以非常穩定的適應各種賽道的時候,然後,慢慢加D,一直到車不能跑了,可以先給個大的D,往下減。然後試著提速,一直到車不能穩定跑完全程,這個時候速度,記下來,然後,稍微降速,然後降低P值,自己要慢慢調節每次降低多少合適。D值不要動。

速度PID調節

說實話,這個我不知道怎麼調節,但是調節的效果如果好的話應該是彎道減速不太明顯。幾乎全程都是一個速度,自己設定的除外。但是實際發現,比賽的時候很多隊伍設定了直道加速彎道減速,效果不好,車反應不過來。當然也有好的。我直接給電機一個pwm值發現車根據自身可以很好的適應賽道,彎道減速,直道加速。但是最好還是調節下,因為決賽的坡道,如果速度開環下坡非常不穩定,衝出去是必然。

C語言資料型別統一

程式設計的時候C語言的資料型別儘量做到統一,尤其是函式宣告的引數的資料型別和傳遞進去的資料的資料型別,不然會有很多隱患,比如,設定形參是unsigned char型別,實際傳遞的是char ,如果計算中線出現了負數,很坑。具體分析見C語言資料型別重新認識,最後結尾的例子。 最後一句感悟,智慧車最大的特點不是保證每個時刻不出現錯誤,而是每個時刻都能對前次出現的誤差進行正確的,快速的調節。希望看到這篇部落格的人做車順利,如果有人向參考最終程式碼,請前往:https://github.com/xiaobai1993/FreeScaleSmartCar下載,。雖然不做車了,但是還是願意幫一些像我一樣的小白的 比賽視訊:智慧車視訊,其他的都在我的專輯裡面