第十六屆全國(guó)大學(xué)生智能汽車(chē)比賽是我大學(xué)參加的第一個(gè)有意義的比賽,讓我在學(xué)校實(shí)驗(yàn)室SCA打開(kāi)了進(jìn)入大學(xué)的大門(mén),無(wú)數(shù)次的包夜和學(xué)習(xí)讓我靜下了心,很榮幸參加過(guò)這樣一次的競(jìng)賽,收獲頗豐。簡(jiǎn)單的做一個(gè)總結(jié),算是畫(huà)上大二一學(xué)年的句號(hào),希望對(duì)你們有幫助。
本文僅自己看法,并不是權(quán)威結(jié)論。若有錯(cuò)誤或不足之處,還請(qǐng)多多包涵。
攝像頭算法控制我分為二類(lèi):圖像處理和車(chē)體控制
第一類(lèi):圖像處理
1.1 攝像頭如何使用(小白篇)?
我比賽用的總鉆風(fēng)130°攝像頭,拿到攝像頭后,使用例程可以在IPS屏幕上看到一個(gè)灰度圖像(原始圖像)。這個(gè)原始圖像我們一般都要進(jìn)行處理,也可以不處理。我來(lái)介紹一下常用的三種處理方法.(1)圖像二值化。(2)圖像灰度。(3)邊緣檢測(cè)算法。
我用的是簡(jiǎn)單好用的圖像二值化,所以我拿二值化進(jìn)行講解。我先簡(jiǎn)單介紹一下二值化圖像,在原始圖像的基礎(chǔ)上,把他分為黑和白(即賽道是白,其它是黑)。
灰度圖像有256個(gè)像素點(diǎn) 即0-255。0-255是什么意思,個(gè)人理解即顏色的深淺。0是黑,255是白。0-255是介于黑至白之間。對(duì)于一個(gè)灰度圖像中,圖像中每一個(gè)點(diǎn)都是在0-255之間,每一個(gè)點(diǎn)都有一個(gè)值.受光照影響,不同位置,不同時(shí)間,不同關(guān)照,每一個(gè)點(diǎn)的值都會(huì)不同。
所以我們要對(duì)這個(gè)值進(jìn)行區(qū)分黑白,要進(jìn)行處理。處理的方法就是:大津法(還有其他方法不唯一,大津法用的人比較多)
大津法就是對(duì)你的灰度圖像進(jìn)行處理后得到一個(gè)閾值。輸入進(jìn)去一個(gè)二位數(shù)組圖像,然后會(huì)返回給你一個(gè)閾值,然后你就用這個(gè)閾值進(jìn)行二值化(即大于閾值為白(黑),小于閾值為黑(白)。即你就可以得到一個(gè)二值化圖像。
1.2 掃線
關(guān)于攝像頭循跡,一般都是按照獲取賽道中線,根據(jù)賽道中線來(lái)進(jìn)行循跡的。如何獲得賽道中線,我來(lái)簡(jiǎn)單介紹一下。在2.1中我們知道中線是按照左右邊線獲得的,而左右邊線我們則需要在圖像中進(jìn)行處理獲得,這個(gè)過(guò)程就是掃線。
在二值化圖像的基礎(chǔ)上進(jìn)行掃線處理,以圖像60行120列為例,從上到下為0-60行,我們?nèi)〉?0行中點(diǎn)(圖像下面相比上面較穩(wěn)定,所以我們從下面開(kāi)始),也就第60行第60列為起始點(diǎn)往兩邊進(jìn)行掃線。
一般來(lái)說(shuō),我們的車(chē)是放在賽道中間,即起始點(diǎn)為白點(diǎn),然后我們往兩邊判斷一直到黑點(diǎn),我們記錄下黑點(diǎn)坐標(biāo)放進(jìn)左右邊線的數(shù)組里,若沒(méi)有掃到黑點(diǎn)則記錄圖像數(shù)組邊界值放進(jìn)左右邊線數(shù)組里。
這樣每一行都這樣重復(fù)就可以獲取左右邊線數(shù)組。簡(jiǎn)單的掃線就這么結(jié)束了。(后面還會(huì)補(bǔ)充掃線進(jìn)階篇,你也可以根據(jù)簡(jiǎn)單的掃線,自己想一想代碼如何升級(jí))
1.3 中線
我們是根據(jù)賽道中線進(jìn)行循跡,所以中線的處理也非常重要。
中線 = (左邊線+右邊線)/2?
中線 = 左邊線+X
中線 = 右邊線-X
X的值,根據(jù)實(shí)際情況來(lái)定。
1.4?圖像的直道和彎道
所有元素處理過(guò)后都是直道和彎道,這部分的處理也決定了你車(chē)體速度的上限。不僅是你PID的調(diào)參還有你圖像的處理。
先說(shuō)簡(jiǎn)單的,根據(jù)中線的值來(lái)確定直道和彎道,在不同情況下,調(diào)用不同的PID參數(shù)。(等元素處理都寫(xiě)完,回來(lái)在寫(xiě)這個(gè)進(jìn)階篇)
1.5?元素處理
1.5.1 十字、環(huán)島、三岔路口
這三個(gè)元素我是同一個(gè)處理方法。三個(gè)問(wèn)題:
(1)拐點(diǎn)問(wèn)題(左右看看,上下看看)
所有拐點(diǎn)我都分為下拐點(diǎn)和上拐點(diǎn)。
下拐點(diǎn):十字下面兩個(gè)拐點(diǎn),環(huán)島入環(huán)和出環(huán)拐點(diǎn),三叉下面兩個(gè)拐點(diǎn)
下拐點(diǎn)都是在邊線上,在一定范圍內(nèi)遍歷數(shù)組尋找最大值或最小值。
上拐點(diǎn):十字上面兩個(gè)拐點(diǎn),三叉路口上拐點(diǎn)。
上拐點(diǎn)(抽象講解)圖像數(shù)組 范圍內(nèi) 從左到右,從下往上掃點(diǎn)(白變黑的跳變點(diǎn)),掃到把行坐標(biāo)放入一維數(shù)組內(nèi),然后范圍內(nèi)搜索較大(小)值(一次就好)。
(2)補(bǔ)線問(wèn)題
兩點(diǎn)確定一條直線,確定斜率,就確定兩點(diǎn)中的每一個(gè)點(diǎn),然后讓這條直線上所有白點(diǎn)變成黑點(diǎn),在重新掃線,就可以了。(說(shuō)著其實(shí)都很簡(jiǎn)單,其實(shí)也不難,自己多動(dòng)動(dòng)手0.0)
(3)狀態(tài)問(wèn)題
1)十字
這是即將進(jìn)入十字的布線狀態(tài),在看到兩邊丟線且中間大量空白時(shí),進(jìn)入十字狀態(tài),然后開(kāi)始算出上下四個(gè)拐點(diǎn),上拐點(diǎn)連接下拐點(diǎn)就可以如圖所示了。
不管你是即將進(jìn)入十字還是十字中,還是即將出十字,都需要這么一個(gè)補(bǔ)線狀態(tài),所以,我們用簡(jiǎn)單的if來(lái)控制十字狀態(tài)。
當(dāng)下拐點(diǎn)消失時(shí),我們固定下拐點(diǎn)值,直接連接上拐點(diǎn)。我簡(jiǎn)單來(lái)說(shuō)一下我的代碼怎么寫(xiě)的。
if( 左邊線丟線&右邊線丟線) ? (條件判斷的有點(diǎn)粗糙,后面詳細(xì)說(shuō)一下) ? ? { ? ? if(中間大量白點(diǎn)) ? ? ?{ ? ? ? 進(jìn)入十字標(biāo)志 ? ?} ? ? ? } if( 進(jìn)入十字標(biāo)志) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? 搜索左上拐點(diǎn)(沒(méi)搜到給定值) ? ? ? 搜索左下拐點(diǎn) ?(沒(méi)搜到給定值) ? 連接左上和左下兩拐點(diǎn) ? ? ? 搜索右上拐點(diǎn)(沒(méi)搜到給定值) ? ? ? 搜索右下拐點(diǎn) ?(沒(méi)搜到給定值) ? 連接右上和右下兩拐點(diǎn) ? ? ? if(兩邊不丟線,結(jié)束十字標(biāo)志) ? { ? ? } ? ? ? ? } ? ? ?
2)環(huán)島?
?
?
環(huán)島的補(bǔ)線差不多就4個(gè)狀態(tài)(還有一個(gè)出環(huán)切內(nèi)的補(bǔ)線)但是我分為7個(gè)狀態(tài)。用的switch語(yǔ)句來(lái)控制個(gè)個(gè)狀態(tài),一但進(jìn)入環(huán)島第一個(gè)狀態(tài)后面,在環(huán)島結(jié)束前都不會(huì)誤判,非常好用。
if(左邊丟線 || 右邊丟線) ?// ?進(jìn)入元素識(shí)別狀態(tài) { ?左環(huán)島判斷 ?if(左邊丟線||右邊不丟線) ?// 可能是環(huán)島或者彎道或者車(chē)庫(kù) ?{ ? ?if(右邊邊線是條直線) ?// 排除彎道 ? ?{ ? ? ?給予左環(huán)島標(biāo)志; ? ? ?進(jìn)入左環(huán)島狀態(tài)1; ? ?} ?} roadabout_dispose(); ?//環(huán)島處理函數(shù) } roadabout_dispose() { if(左環(huán)島標(biāo)志位) { ?switch(左環(huán)島狀態(tài)) ? { ? ? case 1: ? ? ? ?if(左邊即將不丟線) ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? 進(jìn)入左環(huán)島狀態(tài)2; ? ? ? ? } ? ? break; ? ? case 2: ? ? ? ?if(左下邊為圓環(huán)) ? ? ? ? { ? ? ? ? ? 進(jìn)入左環(huán)島狀態(tài)3; ? ? ? ? } ? ? break; ? ? case 3: ? ? ? ?if(左邊第二次丟線,找拐點(diǎn)補(bǔ)線進(jìn)入環(huán)島) ? ? ? ? { ? ? ? ? ? 進(jìn)入左環(huán)島狀態(tài)4; ? ? ? ? } ? ? break; ? ? case 4: ? ? ? ?if(進(jìn)入環(huán)島,環(huán)島內(nèi)) ? ? ? ? { ? ? ? ? ? 進(jìn)入左環(huán)島狀態(tài)5; ? ? ? ? } ? ? break; ? ? case 5: ? ? ? ?if(即將出環(huán)島,找拐點(diǎn)補(bǔ)線出環(huán)島) ? ? ? ? { ? ? ? ? ? 進(jìn)入左環(huán)島狀態(tài)6; ? ? ? ? } ? ? break; ? ? case 6: ? ? ? ?if(右邊即將不丟線,車(chē)身擺正) ? ? ? ? { ? ? ? ? ? 進(jìn)入左環(huán)島狀態(tài)7; ? ? ? ? } ? ? break; ? ? case 7: ? ? ? ?if(左邊即將不丟線) ? ? ? ? { ? ? ? ? ? 進(jìn)入左環(huán)島狀態(tài)8; ? ? ? ? } ? ? break; ? ? case 8: ? ? ? ?if(完全出環(huán)島) ? ? ? ? { ? ? ? ? ? 清除左環(huán)島狀態(tài); ? ? ? ? ? 清除左環(huán)島標(biāo)志位; ? ? ? ? } ? ? break; ? } ? ? ?if(左環(huán)島狀態(tài)1||左環(huán)島狀態(tài)2) ?{ ? 找到左下拐點(diǎn); ? 找到左上拐點(diǎn); ? 補(bǔ)線; ?} ?if(左環(huán)島狀態(tài)4) ?{ ? 找到左上拐點(diǎn); ? 定點(diǎn)補(bǔ)線; ?} ?if(左環(huán)島狀態(tài)6) ?{ ? 找到右下拐點(diǎn); ? 定點(diǎn)補(bǔ)線; ?} ?if(左環(huán)島狀態(tài)7) ?{ ? 定點(diǎn)補(bǔ)線切內(nèi)環(huán); ?} ?if(左環(huán)島狀態(tài)8) ?{ ? 左邊定點(diǎn)補(bǔ)線,防抖; ?} } }
3)三岔路口
作為十六屆的新元素,起初覺(jué)得很簡(jiǎn)單,拉一條線就能過(guò),后來(lái)錯(cuò)了,其實(shí)很有講究和難度,并未有想象出來(lái)那么簡(jiǎn)單,衍生出來(lái)很多難搞的問(wèn)題,要仔細(xì)對(duì)待。三岔路口最好的特征點(diǎn),就是兩個(gè)Y拐點(diǎn)和一個(gè)V拐點(diǎn)。
在你看到三岔路口時(shí),并沒(méi)有丟線狀態(tài),所以你在直道上就要判斷Y拐點(diǎn)是否存在。有時(shí)三岔接彎道時(shí),車(chē)體無(wú)法“完全”正 ,肉眼可能覺(jué)得車(chē)體正的(但是我們稱這種為斜入)只能看到一個(gè)Y拐點(diǎn)。
所以三岔路口要分為正入,左斜,右斜,三種判斷。簡(jiǎn)單說(shuō)一下怎么寫(xiě)的三岔,因?yàn)槿砺房谖覍?xiě)的不是很好,2.8以上會(huì)誤判不是很好。
if(中間上面出現(xiàn)黑點(diǎn)) { 判斷Y拐點(diǎn)是否存在; 2個(gè)Y拐點(diǎn)為正入; 左邊存在為左斜; 右邊存在為右斜; 判斷V拐點(diǎn)是否存在; V拐點(diǎn)存在或Y拐點(diǎn)存在進(jìn)入三岔路口標(biāo)志位1; 進(jìn)入三岔路口狀態(tài)1; } 然后根據(jù)3種情況和狀態(tài) 進(jìn)入下一階段和拐點(diǎn)補(bǔ)線操作。 可以模仿環(huán)島偽代碼來(lái)寫(xiě)。 僅供參考。
借鑒一下思路即可。
1.5.2 坡道
坡道個(gè)人建議用紅外測(cè)距,還是比較準(zhǔn)的。即簡(jiǎn)單也準(zhǔn)確。
1.5.3 車(chē)庫(kù)
https://blog.csdn.net/qq_51679917/article/details/121874542
第二類(lèi):車(chē)體控制
車(chē)體控制主要是舵機(jī)和電機(jī)以及配合圖像處理進(jìn)行循跡。俗話說(shuō)的好:圖像處理的好,開(kāi)環(huán)也能跑。說(shuō)到控制那不得不說(shuō)幾個(gè)環(huán)的事,簡(jiǎn)單說(shuō)一下最基本的兩個(gè)環(huán)(1)轉(zhuǎn)向環(huán) (2)速度環(huán)
2.1 轉(zhuǎn)向環(huán)
我用的是C車(chē)模,S3010舵機(jī)。轉(zhuǎn)向要能進(jìn)行左轉(zhuǎn)和右轉(zhuǎn),所以我們要在圖像上區(qū)分左和右。
例如:我的圖像是 60×120( 60行,120列)我利用(左邊線+右邊線)/2=中線 這時(shí)候你就取一行或多行 賽道中線-圖像中線=error。得到error來(lái)區(qū)分左右,正常來(lái)說(shuō)你把車(chē)體放在賽道中間,error會(huì)是0。
車(chē)體往左邊偏為正,車(chē)體往右邊偏為負(fù)。(反之也可以)這樣我們就區(qū)分了左和右,車(chē)體就可以進(jìn)行轉(zhuǎn)彎了。
但我們發(fā)現(xiàn)轉(zhuǎn)彎可能過(guò)大或者過(guò)小,沒(méi)法理想的轉(zhuǎn)彎,這時(shí)候我們要用PID算法進(jìn)行調(diào)節(jié),新手建議位置式PID(非常夠用)。
個(gè)人建議起步用位置式PID中的純P調(diào)節(jié)。調(diào)到2米時(shí)用PD調(diào)節(jié),跳到2米8時(shí)換模糊PID。
這時(shí)候你把error放入位置式PID中,Ki和Kd給0,調(diào)節(jié)Kp,輸出Steer。然后用舵機(jī)中值加減Steer得到的控制值來(lái)控制舵機(jī)靈敏的轉(zhuǎn)向。
這樣舵機(jī)就可以根據(jù)在賽道的不同位置來(lái)進(jìn)行靈活的轉(zhuǎn)向了,這就是一個(gè)簡(jiǎn)單的轉(zhuǎn)向環(huán)。
編輯:黃飛
?
評(píng)論
查看更多