飛思卡爾智慧車經驗
阿新 • • 發佈:2019-01-06
本人蔘加了第九屆飛思卡爾智慧車比賽,光電組。現在分享下自己的心得和體會,希望能夠給後來人帶來點幫助。為什麼不在智慧車論壇發,因為那個論壇我現在不經常上了,如果有人回覆我怕不能及時回覆,下面這些內容適合新手,當然也可能有錯誤,希望根據自己的情況甄別。好了廢話不多說開始吧,分幾點來說。
1.做車心態和賽前準備
這個放在第一點是非常重要的,做車一定必須有個好心態,中間可能遇到各種各樣的問題,比如車本來好好的,突然不能跑了,或者龜速了,突然某個器件燒了,電機不轉動了,尤其是光電組和攝像頭組的對環境依賴很大,電磁組雖然訊號較穩定,但是車因為速度快,往往會撞壞採集模組,同樣很坑。不論什麼時候都要保持一個積極向上的心態,小車虐我千百遍,我待小車如初戀。不乏很多人開始做車之前士氣高昂,遇到困難也會嘗試解決,但是如果一個問題長時間不能解決,就漸漸放棄了,長時間是多次時間,也許一週,一個月都是有可能的,或者別人的車都跑的很快了,自己的車還是龜速,甚至連龜速都是不能跑,在雪上加霜的是,你還要上課,課程難,但是你上課又沒有心思聽,人在教室,心裡卻想著車,一學期快結束了,也快比賽了,大家都準備考試,你還在調車,擔心各種掛科,白天上課,晚上調車調到深夜........各種情況也要有心裡準備,這些都是極有可能經歷的,在比賽中也有不少大神的車6次機會都沒有跑下來......這些都要去思考都是很有可能的,所以我們做車心裡準備一定要做好,同時要保持一個好的心態,在自己遇到困難的時候,要時刻相信困難的解決就在下一秒,也要不斷總結,思考問題可能出現在什麼地方。另一點不得不說的就是要選擇好隊友了,一定要相互合作,隊友不一定要多麼多麼牛,但是一定要是那種樂意付出,能吃苦的人,有困難大家一起扛才可以,遇到問題可以一起商量解決才可以,希望做車時一定要嚴以律己,絕對不能坑隊友,以負責的態度去對自己的隊伍,同時為了自己不被坑,選擇自己信任的人。上面這些絕對是重要的,所以放在第一點,你可以不相信,但是別後悔。2.車的機械結構
3.採用的感測器
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;
}
}
這種方法,雖然也利用了賽道外資訊,但是省去了丟線的處理,因為檢測的是白色部分。臨界值的確定也要是動態的,根據自己嘗試,比如本次採集到的最大值和最小值的差之類的再乘一個係數。如果賽道背景是藍色,這種方法也許可以,但是如果是白色,或者淺色,估計有點玄乎。這種方法就不用糾結於丟線。效果如何還是自己嘗試吧。