2021-09-17 11:57:48 索煒達(dá)電子 1040
項(xiàng)目編號(hào):E1221
文件大?。?M
源碼說明:帶中文注釋
開發(fā)環(huán)境:C編譯器
簡(jiǎn)要概述:
一、選材
1、主控。經(jīng)過本人血淚實(shí)踐,證明戰(zhàn)艦加7670做圖像處理還是很吃力,這次畢設(shè)直接買了阿波羅,主頻216M,性能杠杠滴。用了的人都說好。如果改其他攝像頭戰(zhàn)艦也是完全可以勝任的,攝像頭見下面!
2、攝像頭。采用7670,讀取圖像費(fèi)時(shí),處理也頭疼。比賽要求不準(zhǔn)使用學(xué)習(xí)板(畢設(shè)的話沒那么嚴(yán)格就用了阿波羅學(xué)習(xí)板)。另外攝像頭用杜邦線引出來通信極其容易異常,就算采用了原子哥的攝像頭延長(zhǎng)線干擾也是十分嚴(yán)重。綜合來看原子的攝像頭不太適合做板球(個(gè)人意見,如果不恰當(dāng)還請(qǐng)大佬指點(diǎn))。直到比賽最后一天,我同學(xué)發(fā)現(xiàn)了一款攝像頭openmv,據(jù)某寶賣家所說2017電賽專用,輸出幀率每秒可以達(dá)到85幀。本人頓時(shí)兩眼放光,但是又到了最后一天了,那種心情就像你看著希望在你面前哼著小曲慢慢悠悠的走了,你抓都抓不到~
言歸正傳,opemmv3采用STM32F7作為處理核心,時(shí)鐘頻率可以達(dá)到216M。搭載7725,輸出幀率可以高達(dá)85幀。此外外部提供python接口,只要幾行代碼即可完成一個(gè)項(xiàng)目,最后提供多種例程,如找小球,找色塊,循跡,光流等等都不在話下。這次畢設(shè)也是直接花四百多大洋入手一款,確實(shí)非常好用,具體鏈接各位某寶搜索啦!如果各位想用電阻屏檢測(cè)小球位置倒也是可以的,題目要求檢測(cè)小球運(yùn)動(dòng)方式不限,不過那樣感覺就不是正宗的板球了。
3、電機(jī)。在比賽之前網(wǎng)上廣為流傳的一個(gè)預(yù)測(cè)帖子說今年很有可能出板球控制系統(tǒng),這點(diǎn)倒是預(yù)測(cè)的很準(zhǔn),但是,帖子推薦了一款電機(jī)-直流推桿電機(jī)-確是坑了一大批人,單價(jià)貴不說還沒有反饋。PS:我也是被坑的一位(關(guān)鍵是組委會(huì)推薦元器件清單也是直線電機(jī),欲哭無淚?。。?。賽前買的老板賣斷貨,下了的單都能接到老板打電話過來道歉說沒貨了,請(qǐng)退掉訂單……在嘗試之后,最終決定采用舵機(jī),舵機(jī)一個(gè)周期為20ms,控制簡(jiǎn)單,響應(yīng)快。這次畢設(shè)我采用的是MG946R金屬齒輪舵機(jī),不要用塑料的,金屬的扭力大,穩(wěn)定。
4、球,球是很關(guān)鍵的一個(gè),乒乓球太輕而且重心不在球心。比賽的時(shí)候找不到合適的球只能采用類似樟腦丸的一種用來驅(qū)蟲的一種木球(對(duì),沒錯(cuò)就是這么心塞,還是管我們班女生要的……?,F(xiàn)在畢設(shè)易老師買了鋼球,相比之下鋼球確實(shí)是最合適的選擇,幾乎不受風(fēng)的影響。但是鋼球難以上色,采用攝像頭的色塊捕捉就不行了,只能采用灰度捕捉。灰度捕捉這樣發(fā)揮部分第四問就不知道怎么發(fā)揮了,假如采用色塊捕捉的話,發(fā)揮部分第四問可以采用激光引導(dǎo),指哪去哪。我采用普通鋼珠,發(fā)揮部分想讓它畫個(gè)圓,但是效果很差,所以就沒做。某寶上只有一個(gè)賣彩色的鋼球的,但是不零售,那我只能呵呵了。
5、平板,建議大家采用亞克力板,輕薄平整,玻璃的話太厚。亞克力板有無色跟白色可選,看個(gè)人喜好了,我是拿透明的亞克力板,一面撕去紙,一面將紙張用墨水染黑,這樣調(diào)整一下灰度的閾值就能追蹤小球了。
二、機(jī)械結(jié)構(gòu)
機(jī)械機(jī)構(gòu)很重要!機(jī)械結(jié)構(gòu)很重要!機(jī)械結(jié)構(gòu)很重要!多少隊(duì)伍都是在機(jī)械結(jié)構(gòu)上止步國獎(jiǎng)。首先機(jī)械結(jié)構(gòu)一定要穩(wěn),其次也要靈活。下面附上一張我們當(dāng)時(shí)采用的機(jī)械機(jī)構(gòu)。注意下面的結(jié)構(gòu)是錯(cuò)誤的?。▓D片來自網(wǎng)絡(luò))
這種結(jié)構(gòu)中間采用萬向節(jié)是正確的,比賽的時(shí)候我是這樣用,畢設(shè)現(xiàn)在也是這樣用。我要強(qiáng)調(diào)的是兩邊舵機(jī)上面跟板連接的結(jié)構(gòu),這樣連接板在這個(gè)方向上只能有一個(gè)活動(dòng)方向,兩個(gè)舵機(jī)只要運(yùn)動(dòng)板一定變形。如果換成三個(gè)萬向節(jié)鏈接三個(gè)就沒問題了。但是萬向節(jié)跟亞克力之間不好連接,在易老師的指點(diǎn)幫助下,兩邊我采用了下面圖的連接。
活動(dòng)部分鉆一個(gè)空插上鐵絲或者加一個(gè)螺絲就行,固定部分切割亞克力板用亞克力膠水粘就行,亞克力膠水的粘度是可以的,很給力。這樣板在上下運(yùn)動(dòng)的時(shí)候板子就不回變形了。我的板子面積是不符合題目要求的,表面也沒有按照題目要求畫圓圈,這點(diǎn)主要是考慮到體積小容易挪動(dòng),大板沒什么意思的,除了占地方!
三、軟件部分
軟件部分就是兩個(gè)PID參數(shù)校正,這里是隨動(dòng)系統(tǒng),基本上用不到微分量。PD也是非常容易找??峙逻@是這幾年電賽最簡(jiǎn)單的控制題了吧。只要大家能把球定在中間,基礎(chǔ)部分全部可以完成,只要改一下設(shè)定位置就行,發(fā)揮部分1、3也是沒什么問題。就發(fā)揮部分第二問有點(diǎn)意思,下面詳細(xì)說一下發(fā)揮部分第二問。第二問就是一個(gè)自動(dòng)選路算法。我的思路是在題目要求的九個(gè)區(qū)域之外再加上四個(gè)緩沖區(qū)域就可以完成任務(wù)。
如上圖,四個(gè)緩沖區(qū)域如上圖B1、B2、B3、B4,當(dāng)進(jìn)入到這個(gè)區(qū)域的時(shí)候,主函數(shù)掃描紅外信號(hào),收到數(shù)字幾就將區(qū)域幾設(shè)置為最終區(qū)域。然后中斷里面判斷球是不是到了設(shè)定區(qū)域周圍10個(gè)像素范圍內(nèi),如果是將計(jì)次加一,否則i清零。這樣我們?cè)谥骱瘮?shù)中可以不斷查詢這個(gè)全局變量,我們?cè)O(shè)定當(dāng)累積次數(shù)達(dá)到50次后認(rèn)為球已經(jīng)到達(dá)了目標(biāo)區(qū)域。
下面是判斷是否到達(dá)設(shè)定位置部分代碼
[mw_shl_code=c,true] //以下語句用來統(tǒng)計(jì)當(dāng)前球的位置是不是連續(xù)都在目標(biāo)區(qū)域內(nèi)部,如果有一次不進(jìn)入
//那么計(jì)次清零,當(dāng)球在目標(biāo)區(qū)域正負(fù)5個(gè)像素點(diǎn)的時(shí)候,全局變量計(jì)次增加。外部程序可以
//通過讀取這個(gè)全局變量判斷是不是達(dá)到一定值來判斷是不是進(jìn)入到了目標(biāo)區(qū)域。
if((abs(rol_curpos - rol_setpos) <= 10)&&(abs(pit_curpos - pit_setpos) <= 10))
{
PASSBY_TIME++;
}
else
{
PASSBY_TIME = 0;
}
[/mw_shl_code]
接下來判斷最終位置跟目前所處的位置是不是在一定像素點(diǎn)以內(nèi),如果是那就直接滾過去,不會(huì)跑到其他區(qū)域內(nèi)部(這里是像素單位,圖示見上面坐標(biāo)點(diǎn)。大家可以根據(jù)自己實(shí)際情況自己決定)。如果不是的話,判斷當(dāng)前是不是處在緩沖區(qū)域,如果是,進(jìn)入下一個(gè)緩沖區(qū)域再去判斷最終位置與當(dāng)前位置的位置范圍。如果不是,那么遍歷所有緩沖區(qū)域,進(jìn)入最近的哪一個(gè)。視頻中我也是只是演示了一下基礎(chǔ)部分1、2,然后就是發(fā)揮部分2了。我的算法對(duì)當(dāng)前處在所有區(qū)域都是通用的,就算從最遠(yuǎn)區(qū)域,比如說區(qū)域1到區(qū)域9也不會(huì)超過10秒;題目要求40秒內(nèi)由A到D,也就是選三次路,單次選路不超過10秒,三次絕對(duì)不會(huì)超過四十秒??梢哉f是完全可以滿足要求,詳細(xì)見下面流程圖。最后備注一點(diǎn),判斷當(dāng)前區(qū)域判斷的是設(shè)定區(qū)域跟目標(biāo)區(qū)域的差值,不建議用當(dāng)前位置跟目標(biāo)位置比較,因?yàn)樵跍y(cè)試的時(shí)候,我用當(dāng)前位置去比較,得到效果很差,經(jīng)??ㄔ诰彌_區(qū)域出不來。(算法見下面模式六代碼,流程圖如下)
下面是模式六的代碼
[mw_shl_code=c,true]//模式六
void mode_6(void)
{
u8 i;
u8 rol_set_pos_temp = 0,pit_set_pos_temp = 0; //存放最近的緩沖區(qū)域的坐標(biāo)。
int distance,min_distance = 120;
if(PASSBY_TIME >= 50) //穩(wěn)定到了一個(gè)新位置
{
if((abs(rol_setpos - FINAL_ROL_POS)<=30)&&(abs(pit_setpos - FINAL_PIT_POS)<=30))
{
//最終位置與當(dāng)前位置之間R與P方向上像素差值都小于30個(gè)像素值,那么球可以直接滾動(dòng)過去。
rol_setpos = FINAL_ROL_POS;
pit_setpos = FINAL_PIT_POS;
PASSBY_TIME = 0; //更新目標(biāo)位置,清零經(jīng)過次數(shù)
return; //距離目標(biāo)位置近,可以直接滾過去,返回。
}
else if((rol_setpos == 40)&&(pit_setpos == 40))//當(dāng)前小球處在一號(hào)緩沖區(qū)域里
{
rol_setpos = ROL_BUFF[1];
pit_setpos = PIT_BUFF[1];
PASSBY_TIME = 0; //控制小球進(jìn)入2號(hào)緩沖區(qū)域
}
else if((rol_setpos == 70)&&(pit_setpos == 40))
{
rol_setpos = ROL_BUFF[2];
pit_setpos = PIT_BUFF[2];
PASSBY_TIME = 0; //控制小球進(jìn)入3號(hào)緩沖區(qū)域
}
else if((rol_setpos == 70)&&(pit_setpos == 70))
{
rol_setpos = ROL_BUFF[3];
pit_setpos = PIT_BUFF[3];
PASSBY_TIME = 0; //控制小球進(jìn)入4號(hào)緩沖區(qū)域
}
else if((rol_setpos == 40)&&(pit_setpos == 70))
{
rol_setpos = ROL_BUFF[0];
pit_setpos = PIT_BUFF[0];
PASSBY_TIME = 0; //控制小球進(jìn)入1號(hào)緩沖區(qū)域
}
else //小球不在任何緩沖區(qū)域
{
for(i = 0;i <= 3;i++) //遍歷所有的緩沖區(qū)域,尋找到最近的緩沖區(qū)域。
{
distance = abs((int)(rol_setpos - ROL_BUFF))
+ abs((int)(pit_setpos - PIT_BUFF));
if(distance < min_distance)
{
min_distance = distance;
rol_set_pos_temp = ROL_BUFF;
pit_set_pos_temp = PIT_BUFF;
k = i;
}
}
rol_setpos = rol_set_pos_temp;
pit_setpos = pit_set_pos_temp;
PASSBY_TIME = 0;
}
} }
[/mw_shl_code]
至于發(fā)揮部分第四問,我才用的是灰度范圍追蹤,這樣激光引導(dǎo)就沒法做了。能做的也就是球畫圓圈了,這點(diǎn)倒和風(fēng)力擺有點(diǎn)像。我想讓球畫圓,但是機(jī)械結(jié)構(gòu)還是粗糙了點(diǎn),基本上畫不了所以就沒再繼續(xù)改進(jìn)了,大家參考我的風(fēng)力擺帖子吧!
四、其他
其他一些就是jasson方面的了,在串口讀取攝像頭輸出的時(shí)候,用串口助手觀察收到的數(shù)據(jù),如果攝像頭找到了多個(gè)目標(biāo)那么這些坐標(biāo)的位置都會(huì)傳輸過去,外部用大括號(hào)與小括號(hào)。每幀數(shù)據(jù)長(zhǎng)度不一致,所以我在原代碼的基礎(chǔ)上比較了一下找到的灰度塊,只發(fā)送面積最大的一個(gè)。此外jasson數(shù)據(jù)串如果找打的色塊中心坐標(biāo)是一位數(shù)或者三位數(shù)的話,那只會(huì)發(fā)一個(gè)字節(jié)的數(shù)字,這樣串口看到收到數(shù)據(jù)長(zhǎng)度就變了。jasson 解碼我沒搞懂怎么用,只是把它的keil編解碼庫下載了過來,具體在附件里。變通一下我設(shè)置了感興趣區(qū)域就是10-99,這樣保證輸出的數(shù)據(jù)長(zhǎng)度都是一致的。各位大佬懂得jasson編解碼怎么用還希望分享一下經(jīng)驗(yàn)哈!
結(jié)語
經(jīng)過小編上面的分析想必這道題對(duì)大家已經(jīng)沒有難度了吧?希望準(zhǔn)備電賽的小伙伴都能取得理想的成績(jī)。如果有小伙伴想拿這道題練習(xí)整定PID參數(shù),個(gè)人不建議這樣做。這個(gè)題目的PID參數(shù)非常容易整定,各位只要稍微懂的各個(gè)參數(shù)的含義就能整定出來。想要磨練自己整定PID參數(shù)的能力建議做一下風(fēng)力擺(15年國賽題)、倒立擺(13年國賽題)、平板擺(11年國賽題)。這幾個(gè)題目都出的很不錯(cuò)!17年題目要求板子的面積對(duì)于板球系統(tǒng)來說還是太大了,哪有這么大的板球系統(tǒng),一般30×30就差不多了,這么大的板子攝像頭也要架的老高老高了。但是出題者為了降低難度故意要求的,畢竟海闊任魚躍,天高任鳥飛!
最后衷心感謝易家傅老師這么長(zhǎng)時(shí)間以來對(duì)我的指點(diǎn)與幫助,感謝原子哥開發(fā)的學(xué)習(xí)平臺(tái)及詳細(xì)的例程代碼,同時(shí)也感謝在這么長(zhǎng)時(shí)間來給予我?guī)椭睦蠋?、同學(xué)們,謝謝你們這么久以來的幫助跟支持。
本人水平有限,如有錯(cuò)誤還歡迎各位路過的大佬指正!
目錄│文件列表:
└ 板球(滾球)控制系統(tǒng)源代碼
│ Keil.Jansson.1.0.0.pack
│ main.py
│ 板球系統(tǒng)圖示.jpg
└ 畢設(shè)板球控制系統(tǒng)
│ keilkill.bat
│ readme.txt
├ HARDWARE
│ ├ 24CXX
│ │ │ 24cxx.c
│ │ │ 24cxx.h
│ │ │ myiic.c
│ │ └ myiic.h
│ ├ ADC
│ │ │ adc.c
│ │ └ adc.h
│ ├ AP3216C
│ │ │ ap3216c.c
│ │ └ ap3216c.h
│ ├ CAN
│ │ │ can.c
│ │ └ can.h
│ ├ DAC
│ │ │ dac.c
│ │ └ dac.h
│ ├ DMA
│ │ │ dma.c
│ │ └ dma.h
│ ├ EXTI
│ │ │ exti.c
│ │ └ exti.h
│ ├ KEY
│ │ │ key.c
│ │ └ key.h
│ ├ LCD
│ │ │ font.h
│ │ │ lcd.c
│ │ │ lcd.h
│ │ │ ltdc.c
│ │ └ ltdc.h
│ ├ LED
│ │ │ led.c
│ │ └ led.h
│ ├ MOTOR
│ │ │ motor.c
│ │ └ motor.h
│ ├ MPU
│ │ │ mpu.c
│ │ └ mpu.h
│ ├ OLED
│ │ │ oled.c
│ │ │ oled.h
│ │ └ oledfont.h
│ ├ PCF8574
│ │ │ pcf8574.c
│ │ └ pcf8574.h
│ ├ PID
│ │ │ pid.c
│ │ └ pid.h
│ ├ QSPI
│ │ │ qspi.c
│ │ └ qspi.h
│ ├ REMOTE