文章目錄
- 題目任務
- 前言(閑話)
- 一、團隊分工介紹
- 二、題目分析、破題
- 1.要點分析
- 2.系統方案
- 三、電控部分
- 1、主控拓展電路
- 2、步進電機驅動信號整合板
- PCB設計分析
- 四、視覺部分
- 神經網路的訓練:
- 運行代碼:
- 五、機械部分
- 總結
- 附件
題目任務
設計并制作智能送藥小車,模擬完成在醫院藥房與病房間藥品的送取作業, 院區結構示意如圖1所示,院區走廊兩側的墻體由黑實線表示,走廊地面上畫有 居中的紅實線,并放置標識病房號的黑色數字可移動紙張,藥房和近端病房號(1、2 號)如圖1所示位置固定不變,中部病房和遠端病房號(3-8號)測驗時隨機設定,
作業程序:參賽者手動將小車擺放在藥房處(車頭投影在門口區域內,面向 病房),手持數字標號紙張由小車識別病房號,將約 200g 藥品一次性裝載到送藥小車上;小車檢測到藥品裝載完成后自動開始運送;小車根據走廊上的標識信 息自動識別、尋徑將藥品送到指定病房(車頭投影在門口區域內),點亮紅色指示燈,等待卸載藥品;病房處人工卸載藥品后,小車自動熄滅紅色指示燈,開始回傳;小車自動回傳到藥房(車頭投影在門口區域內,面向藥房)后,點亮綠色指示燈,

前言(閑話)
這次比賽因為疫情延期了,給了我們更多的準備(摸魚)時間,比賽四天三夜,占用了有課的周五(剛好碰上了實習,打鐵賊累 還得熬夜,,,)
因為太過摸魚本以為能那個省三就不錯了,沒想到沖了個國二,圓夢電賽了,打破了學校十年的記錄,所以說競賽這方面還得堅持,萬一破紀錄了呢,
我本人是負責視覺方面的,將詳細寫實作方法,保姆級教程,包括神經網路訓練,
一、團隊分工介紹
由隊長趙嘉輝(電控編程)、隊員陳為騫(視覺識別)和吳金穎(機械設計)組成,其中兩個大四,一個大三,
//兩位光電專業、一位機械的hhh
二、題目分析、破題
1.要點分析
任務可簡單分為3個:
(1)巡線移動,完成最基礎的移動功能,是所有功能的基礎,本作品采用灰度傳感器循跡和步進電機的巡線移動方案,
(2)識別病房號數字,可采用openmv、k210、樹莓派等視覺單片機識別,由于沒有提前準備k210,且樹莓派大小、功耗較大,因此采用最常見的openmv,為保證性能足夠,采用openmv4plus,
(3)雙機通信,本作品采用藍牙雙機通信,實作資料共享,
完成以上3個任務后,就是對小車代碼邏輯的構思和想法,后面的就是多除錯代碼,修bug即可,
2.系統方案
-
1、單片機選擇
采用ArduinoMEGA2560單片機作主控,由于其代碼開源性,代碼簡易,適合新手使用,強大的庫函式能極大減少開發時間,且對于該題目,運算速度足夠,因此采用,
-
2、運動系統
采用42步進電機,該款電機轉動精確度高,扭力大,額定電流2A以下,且控制簡單,不會因為不同驅動的電壓而導致轉動步數的偏差,無需使用倍訓控制即能走出非常好的直線,不易走歪,短距離內可精準控制運動位移,驅動采用TB6600 H橋雙極恒相流驅動,驅動及電機采用淘寶成品套件,設定驅動細分數為800,由于驅動體積較大,且42步進電機運行時電流較小,因此可以拆除該驅動模塊的金屬外殼(散熱器),從而達到極大縮小體積和重量,

前輪采用牛眼輪進行支撐,牛眼輪的選擇最好選摩擦力小的,本作品用的牛眼輪摩擦力較大,使得電機的速度不能提得太高,否則摩擦力會將車的運動姿態擾亂,走起來一抖一抖的,
-
3、循跡系統
采用八路灰度傳感器(實際只用了4路),調節好閾值,能精準分辨紅白色,推薦使用下圖的灰度傳感器,用非常簡單的數字邏輯檢測循跡代碼即能完成循跡功能,

-
4、視覺系統
手持病房號采用模板匹配識別,原因是手持病房號可動態調整遠近、角度,模板匹配也能很快識別成功,
地面上的病房號數字采用OpenMV4 H7 Plus神經網路方法識別,對比模板匹配,識別成功率極高,高達90%以上,由于性能受限,運行時影像僅有2~3幀,需要在病房號前停下零點幾秒讓其影像穩定下來識別數字,
-
5、通信系統
采用HM-10藍牙模塊進行雙機通信,主藍牙僅能接收從藍牙的資訊,不能傳資訊給從藍牙,因此從藍牙接1號車,主藍牙接2號車,2號車只需要接收1號車指令即可完成所有任務,注意:需提前AT指令設定主從模式和自動連接藍牙的操作,
-
6、其他
采用了oled螢屏顯示本次讀取病房號是否成功,及實時顯示一些小車運行狀態,方便除錯,設定紅綠黃指示燈、蜂鳴器提示等功能,
采用雙邊自復位按鈕作復位鍵,由于主控單片機和OpenMV作業電平不一致,復位引腳不能接入同一按鍵上,因此使用此按鍵可一鍵復位兩個單片機,
藥物檢測采用簡單的紅外避障模塊檢測高低電平即可,
三、電控部分
電控部分已在立創開源平臺發布!比賽準備的全部工程都有!點這里!!
也可以訪問:https://oshwhub.com/AngleLeon/gong-ke-sai-xin-hao-zheng-ge-ban_copy
電控代碼也在里面,
1、主控拓展電路

-
(1)單片機及其引腳外接
其中arduino的D2-D5作為IO口接入電機驅動模塊,驅動兩個步進電機(每個步進電機由DIR和PUL控制),D23-D37的其中一些引腳接灰度傳感器的8個數字信號口,
-
(2)電源輸入、輸出
12V從圓孔DC5.5系列介面輸入,一路直出給步進電機驅動和步進電機供電,領一路經過5V穩壓模塊給單片機等其他模塊供電,引出8組5V電源介面,方便擴展,
-
(3)其他
其他多余的介面沒有特別定義,只是單純引出,備用,
2、步進電機驅動信號整合板
兩個步進電機需要兩個驅動板,需要較多信號線和電源線,會導致接線較亂、易松,為了穩定性更好,制作了這塊信號整合板,并使用了XH2.54紅白排插線,連接不易松,且易拔插,
-
(1)原理圖
分為12V電源輸入輸出,布線配合單片機擴展板的IO分布,

-
(2)PCB及仿真圖
印絲層加入了對應的IO口數字號,標注了步進電機驅動細分數對應的撥碼器狀態,且該pcb孔位、大小完全適配拆了散熱外殼后的步進電機驅動模塊,能直接安裝在驅動上,省空間,

PCB設計分析
由于主要難度在電控編程上,因此對于PCB的布線難度較小,有一定基礎即可,沒有需要特別注意的地方,
四、視覺部分
很多人覺得視覺難,是因為沒辦法搭建深度學習的訓練環境,巧合的是,本人主持的大創專案正好的關于視覺神經網路的,對于懂的人識別數字十分簡單,但是要在嵌入式上載入模型,對于小白來說還是有難度的,我這里只介紹一種極簡方法,不需要懂神經網路內涵,手把手小白入門教學,
本人比賽使用的是OpenMv4 Plus,這是支持神經網路最低配的一款,當然K210、樹莓派等都可以吊打Openmv,但是由于比賽沒有準備其他兩款,只能選擇普普通通的Openmv了,
先上結果:


神經網路的訓練:
//大神請忽略此部分~~~
在線端訓練網站:[https://studio.edgeimpulse.com](https://studio.edgeimpulse.com/
創建相應數字的檔案夾

通過helloworld.py例程來采集影像,需要把畫質改為QQVGA
多加sensor.set_windowing(20,76,40,40) #框選位置,左右都需要
import sensor, image, time
sensor.reset() # Reset and initialize the sensor.
sensor.set_pixformat(sensor.GRAYSCALE) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QQVGA) # Set frame size to QVGA (320x240)
sensor.set_windowing(20,76,40,40) #框選位置自己修改成合適的
sensor.skip_frames(time = 2000) # Wait for settings take effect.
clock = time.clock() # Create a clock object to track the FPS.
while(True):
clock.tick() # Update the FPS clock.
img = sensor.snapshot() # Take a picture and return the image.
print(clock.fps()) # Note: OpenMV Cam runs about half as fast when connected
# to the IDE. The FPS should increase once disconnected.
然后開始采集,將數字放在左右兩邊,兩邊都要采集大概幾十到一百張,
-
2、在網站匯入影像(Create impulse)
從openmv IDE通過API密匙上傳采集到的資料集,
-
3、調整影像(Image)
按默認設定就好了,
-
4、遷移學習(Transfer learning)
引數也是按默認就行,

-
5、保存模型(Versioning)
及時做好備份,這是云端的,防止多次采集訓練后效果還沒以前某一次好,
-
6、匯出模型
下載神經網路后解壓匯入Openmv,完成,
運行代碼:
下面是Openmv端運行代碼,代碼含模板匹配,移步星瞳官網檔案,寫得比我好,
Openmv端程式框圖:

主程式:
import time, sensor, image,os,tf
from image import SEARCH_EX, SEARCH_DS
from pyb import UART
#從imgae模塊引入SEARCH_EX和SEARCH_DS,使用from import僅僅引入SEARCH_EX,
#SEARCH_DS兩個需要的部分,而不把image模塊全部引入,
uart = UART(3, 9600)
# Reset sensor
sensor.reset()
# Set sensor settings
# Max resolution for template matching with SEARCH_EX is QQVGA
sensor.set_framesize(sensor.QQVGA) #推薦QQVGA,能提高識別速度
# You can set windowing to reduce the search image.
#sensor.set_windowing(((640-80)//2, (480-60)//2, 80, 60))
sensor.set_pixformat(sensor.GRAYSCALE)
net = "trained.tflite" #匯入神經網路
labels = [line.rstrip('\n') for line in open("labels.txt")] #匯入模板
# Load template.
# Template should be a small (eg. 32x32 pixels) grayscale image.
template1 = ["/1.pgm"]
template2 = ["/2.pgm"]
template3 = ["/3.pgm","/3a.pgm","/3b.pgm"]
template4 = ["/4.pgm","/4a.pgm","/4b.pgm"]
template5 = ["/5.pgm","/5a.pgm","/5b.pgm"]
template6 = ["/6.pgm","/6a.pgm","/6b.pgm"]
template7 = ["/7.pgm","/7a.pgm","/7b.pgm"]
template8 = ["/8.pgm","/8a.pgm","/8b.pgm"]
A0=1
A9=1
B0=1
A1=0
A2=0
A3=0
A4=0
A5=0
A6=0
A7=0
A8=0
B0=1
C0=1
C1=0
C2=1
D0=1
D1=1
#加載模板圖片
clock = time.clock()
# Run template matching
while (True):
clock.tick()
img = sensor.snapshot()
while(A0): #開始模板匹配識別手持數字
clock.tick()
img = sensor.snapshot()
t1 = image.Image(template1[0])
r1 = img.find_template(t1, 0.80, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if r1:
img.draw_rectangle(r1)
A1=1
A0=0
t2 = image.Image(template2[0])
r2 = img.find_template(t2, 0.80, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if r2:
img.draw_rectangle(r2)
A2=1
A0=0
t3 = image.Image(template3[0])
r3 = img.find_template(t3, 0.85, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if r3:
img.draw_rectangle(r3)
print('3') #列印模板名字
A3=1
A0=0
t4 = image.Image(template4[0])
r4 = img.find_template(t4, 0.80, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if r4:
img.draw_rectangle(r4)
print('4') #列印模板名字
A4=1
A0=0
t5 = image.Image(template5[0])
r5 = img.find_template(t5, 0.80, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if r5:
img.draw_rectangle(r5)
print('5') #列印模板名字
A5=1
A0=0
t6 = image.Image(template6[0])
r6 = img.find_template(t6, 0.80, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if r6:
img.draw_rectangle(r6)
print('6') #列印模板名字
A6=1
A0=0
t7 = image.Image(template7[0])
r7 = img.find_template(t7, 0.80, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if r7:
img.draw_rectangle(r7)
print('7') #列印模板名字
A7=1
A0=0
t8 = image.Image(template8[0])
r8 = img.find_template(t8, 0.85, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if r8:
img.draw_rectangle(r8)
print('8') #列印模板名字
A8=1
A0=0
while(A9): #識別到數字,發送指令給主控
if A1==1:
uart.write('1')
print('1') #列印模板名字
num=1
A9=0
if A2==1:
uart.write('2')
print('2') #列印模板名字
num=2
A9=0
if A3==1:
uart.write('3')
print('3')
num=3
A9=0
if A4==1:
uart.write('4')
print('4')
num=4
A9=0
if A5==1:
uart.write('5')
print('5')
num=5
A9=0
if A6==1:
uart.write('6')
print('6')
num=6
A9=0
if A7==1:
uart.write('7')
print('7')
num=7
A9=0
if A8==1:
uart.write('8')
print('8')
num=8
A9=0
while(True): #接受到主控指令,可以進行識別數字
while(B0):
if (uart.any()):
B = uart.read()
print(B)
if B==b'1':
print("1")
B0=0
C0=1
while(C0):
img = sensor.snapshot() #神經網路識別右邊數字
roiL=(20,76,40,40)
for obj in tf.classify(net, img, roiL,min_scale=1, scale_mul=0.8, x_overlap=0.5, y_overlap=0.5):
print("**********\nPredictions at [x=%d,y=%d,w=%d,h=%d]" % obj.rect())
img.draw_rectangle(obj.rect())
predictions_list = list(zip(labels, obj.output()))
for i in range(len(predictions_list)):
print("%s = %f" % (predictions_list[i][0], predictions_list[i][1]))
num1=ord(predictions_list[i][0])-48
if predictions_list[i][1]>0.7 and num1==num:
uart.write('1')
print('11')
C1=1
C0=0
roiR=(89,77,40,40) #神經網路識別左邊數字
for obj in tf.classify(net, img, roiR,min_scale=1, scale_mul=0.8, x_overlap=0.5, y_overlap=0.5):
print("**********\nPredictions2 at [x=%d,y=%d,w=%d,h=%d]" % obj.rect())
img.draw_rectangle(obj.rect())
predictions_list2 = list(zip(labels, obj.output()))
for p in range(len(predictions_list2)):
print("%s = %f" % (predictions_list2[p][0], predictions_list2[p][1]))
num2=ord(predictions_list2[p][0])-48
if predictions_list2[p][1]>0.7 and num2 == num:
uart.write('2')
print("22")
C1=1
C0=0
if C1==0:
uart.write('0')
print("00")
print(clock.fps(), "fps")
五、機械部分
-
1、整車模型
如圖為小車機械結構3D圖,前輪采用兩個牛眼輪進行輔助支撐,后輪為步進電機驅動的動力輪,長21cm、寬19.5cm、高24.5cm,

圖中1為牛眼輪,2為八路灰度傳感器模塊,3為小車底板,4為六角銅柱,5為單片機和PCB擴展板,6為攝像頭支架固定底座,7為OpenMV攝像頭,8為藥品,9為藥倉,10為紅外對射模塊,11為步進電機驅動板,12為普通輪子,13為步進電機,14為12V鋰電池,15為支撐座, -
2、車底盤圖

如圖為車底盤CAD圖,使用激光切割亞克力制成,厚度4mm左右,
最終成品圖:

總結
1.選擇自己最擅長的方案,不要去嘗試其他不熟悉的方案,因為4天3頁時間真的很緊急,打算做控制類一定要把通用代碼準備好,如PID,視覺雙機通信等,
2.作為隊長要根據每個隊員的優勢長處設定任務,隊長要擔任起進度規劃的重任,經常是“單核多執行緒”作業,每個隊員都要有強烈的責任感,在選隊員上是關鍵,例如我們隊伍有一個機械,負責車組裝和3d建模列印等操作,效率極高,半天時間就設計完,一天不到就組裝出第一臺車,為我們隊伍節省了非常多寶貴的除錯時間,
3.運氣也是實力的一部分,本次比賽的題目非常符合我們隊伍陣容,車控電控、神經網路、機械,完美適配我們三人的優勢,也許這些都是命中注定,
4.頒獎典禮時聽王越院士說到:建議電賽以后的題目越來越多的人工智能,現在機器學習、深度學習實在太火了,掌握深度學習這項技能十分重要,如果不懂視覺,這次的電賽可能就沒辦法打了,
附件
B站演示視頻:https://www.bilibili.com/video/BV1Qb4y1i7Sn/
主控電路工程:https://oshwhub.com/AngleLeon/gong-ke-sai-xin-hao-zheng-ge-ban_copy#P5
主控代碼:https://download.csdn.net/download/weixin_45902201/76727241
Openmv端代碼:https://download.csdn.net/download/weixin_45902201/76727631
想白嫖代碼請訪問立創開源平臺,不想麻煩可以直接下載
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/416170.html
標籤:AI
