學(xué)習(xí)如何為FPV戰(zhàn)斗無(wú)人機(jī)構(gòu)建一個(gè)視頻模塊,該模塊能夠從模擬FPV攝像機(jī)捕獲視頻流,利用這些視頻流執(zhí)行計(jì)算機(jī)視覺(jué)任務(wù),并將圖像傳輸?shù)斤w行控制器進(jìn)行進(jìn)一步處理(OSD)以及通過(guò)VTX進(jìn)行視頻傳輸。
本文是我一年多來(lái)一直在進(jìn)行的研發(fā)工作的自然延續(xù),該研發(fā)工作專注于為FPV戰(zhàn)斗無(wú)人機(jī)構(gòu)建自動(dòng)駕駛儀。
當(dāng)我開(kāi)始探索如何向FPV操作員通知自動(dòng)駕駛儀的當(dāng)前狀態(tài)和飛行參數(shù)時(shí),我意識(shí)到在基于Betaflight固件的飛行控制器中沒(méi)有可用的軟件解決方案。這促使我考慮一個(gè)軟硬件結(jié)合的解決方案。
在評(píng)估不同選項(xiàng)時(shí),有兩個(gè)關(guān)鍵因素脫穎而出:首先,保持與Betaflight固件和流行的FPV無(wú)人機(jī)配置的兼容性,而不改變它們,這一點(diǎn)很重要。其次,解決方案需要具備修改FPV視頻源和OSD(屏幕顯示)的能力,以顯示計(jì)算機(jī)視覺(jué)模型識(shí)別的目標(biāo),以及其他自動(dòng)駕駛儀狀態(tài)和飛行參數(shù)。
在本文中,我將分享我在這一過(guò)程中發(fā)現(xiàn)的內(nèi)容。
架構(gòu)
最初的想法是在FPV攝像機(jī)和飛行控制器(FC)之間創(chuàng)建一個(gè)“中間人”,以便在FPV屏幕上疊加額外的控制和消息,同時(shí)處理圖像以執(zhí)行人工智能驅(qū)動(dòng)的計(jì)算機(jī)視覺(jué)任務(wù)。對(duì)于這個(gè)角色,我選擇了一臺(tái)樹(shù)莓派以及兩個(gè)加密狗:一個(gè)AV2USB加密狗(用于從FPV攝像機(jī)獲取數(shù)字MJPEG圖像)和一個(gè)HDMI2AV加密狗(用于以PAL/NTSC模擬格式將修改后的圖像傳輸?shù)紽C)。

視頻模塊接線圖
為了在FPV攝像機(jī)和飛行控制器之間實(shí)現(xiàn)“中間人”功能,我決定支持常用的接口,特別是JST 3針電纜。在此設(shè)置中,一條JST電纜將AV2USB加密狗連接到FPV攝像機(jī),而另一條JST電纜則將飛行控制器連接到HDMI2AV加密狗。兩個(gè)加密狗都連接到伴侶計(jì)算機(jī)(在我們的例子中是樹(shù)莓派3),使其能夠獲取/傳輸帶有特定于計(jì)算機(jī)視覺(jué)任務(wù)的視頻疊加的FPV攝像機(jī)圖像。

AV2USB加密狗的焊接點(diǎn)
如上圖所示,我將USB電纜的紅色(5V)線焊接到加密狗上的5V焊盤(pán)上,同時(shí)還將JST電纜的紅色線也焊接上去。這種設(shè)置允許USB電纜同時(shí)為加密狗和FPV攝像機(jī)供電。
JST電纜的接地線(黑色)和視頻信號(hào)線(黃色)焊接到加密狗上的AV和G焊盤(pán)上。此外,USB電纜的接地線(灰色)也連接到加密狗上的G焊盤(pán)上。USB的藍(lán)色線焊接到DP(數(shù)據(jù)+)焊盤(pán)上,而USB的白色線則焊接到DM(數(shù)據(jù)-)焊盤(pán)上。
適當(dāng)?shù)暮附哟_保了電路板的可靠運(yùn)行。
4極3.5毫米AV2PAL電纜,CVBS信號(hào)線焊接至3針JST連接器
為了將HDMI2AV加密狗連接到FC,我使用了CVBS線(PAL輸出中的黃色線),并將其連接到一條JST電纜上,該電纜通過(guò)用于FPV攝像機(jī)連接的相同3針JST線直接連接到FC板上。有關(guān)詳細(xì)信息,請(qǐng)參考上面的接線圖。
CVBS電纜中只有兩條線連接到3針JST連接器上。黃色線是信號(hào)線(CAM),連接到另一側(cè)的黃色線上。黑色線是接地線(GND),連接到另一側(cè)對(duì)應(yīng)的接地線上。紅色線(5V)保持未連接狀態(tài),因?yàn)樗ǔS糜跒镕PV攝像機(jī)供電。然而,在我們的設(shè)置中,我們以不同的方式為FPV攝像機(jī)供電。
讓我們繼續(xù)探討軟件部分。
導(dǎo)入
為了實(shí)現(xiàn)視頻疊加功能,我們需要導(dǎo)入整個(gè)項(xiàng)目中將使用的兩個(gè)包:cv2(用于計(jì)算機(jī)視覺(jué)任務(wù),如從FPV攝像機(jī)捕獲幀)和numpy(用于執(zhí)行數(shù)組操作和數(shù)據(jù)操作)。
importcv2importnumpyasnp
如果你還沒(méi)有安裝它們,現(xiàn)在是時(shí)候安裝了。
定義和狀態(tài)
本節(jié)內(nèi)容來(lái)源于Autopilot “BEE” 倉(cāng)庫(kù)中的適當(dāng)文件,包括definitions.py和autopilot.py,該倉(cāng)庫(kù)針對(duì)FPV戰(zhàn)斗無(wú)人機(jī)(模擬器版本)的跟蹤目標(biāo)功能。本節(jié)提供了應(yīng)在FPV屏幕上顯示的自動(dòng)駕駛儀設(shè)置及當(dāng)前狀態(tài)這部分內(nèi)容源自倉(cāng)庫(kù)中Autopilot "BEE" with target following for FPV Combat Drone(模擬器版本)的definitions.py和autopilot.py文件,提供了應(yīng)在FPV屏幕上顯示的自動(dòng)駕駛儀的設(shè)置和當(dāng)前狀態(tài)。
https://github.com/under0tech/autopilot_bee_sim
# definitionsvideo_source =0video_full =1video_message_limit =60camera_width =720camera_height =480camera_fps =1# statestate= { 'bee_state':'OFF',# OFF, READY, ... 'rssi':0, 'rssi_msg':'Strong signal', 'frame': {}, 'video_msg':'[Manual control is ON]', 'video_msg_countdown':0}
定義——視頻疊加模塊的設(shè)置:
video_source = 0,指的是通過(guò)樹(shù)莓派上的USB端口連接的攝像機(jī),由于默認(rèn)情況下沒(méi)有安裝攝像機(jī),因此這是索引為0的第一個(gè)攝像機(jī)。
video_full = 1,表示視頻疊加將以全屏模式顯示。設(shè)為0用于調(diào)試。
video_message_limit = 60,限制在FPV屏幕上顯示video_msg的幀數(shù)為60幀。
camera_width和camera_height,將分辨率設(shè)置為720x480像素。
camera_fps = 1,使用OpenCV(cv2)每秒捕獲1幀。
自動(dòng)駕駛儀的狀態(tài)(當(dāng)前狀態(tài)):
rssi_msg,可以設(shè)置為“Strong signal”(強(qiáng)信號(hào))或“No signal”(無(wú)信號(hào))。根據(jù)此消息,RC標(biāo)簽和圓形符號(hào)將以紅色或綠色顯示在FPV屏幕上,指示信號(hào)強(qiáng)度。
video_msg,可以包含要在FPV屏幕上顯示的任何消息,直到達(dá)到有限的幀數(shù)(在video_msg_countdown中計(jì)數(shù))。
frame,保存當(dāng)前幀,該幀可以由計(jì)算機(jī)視覺(jué)模型處理,以實(shí)現(xiàn)FPV無(wú)人機(jī)的自主操作。
當(dāng)前狀態(tài)和所有字段狀態(tài)在自動(dòng)駕駛儀運(yùn)行期間由應(yīng)用程序的其他組件更新。
視頻疊加
該子系統(tǒng)的核心是視頻疊加功能,這些功能會(huì)添加關(guān)于自動(dòng)駕駛儀狀態(tài)的額外組件和消息,例如RC信號(hào)強(qiáng)度、自定義消息、縮放后的目標(biāo)以及用于瞄準(zhǔn)的中心十字線,所有這些都顯示在FPV屏幕上(FPV護(hù)目鏡或FPV顯示器)。
查看代碼及其在列表下方的描述。
# Autopilot's overlaydef draw_rc_auto_status(frame): color_green = (0,255,0) color_red = (0,0,255) color = color_greenifstate['rssi_msg'] =='Strong signal'elsecolor_red cv2.circle(frame, (50,50),7, color, -1) font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(frame,"RC", (65,55), font,0.5, color,2) ifstate['bee_state'] =='OFF': cv2.putText(frame,'MANUAL', (110,55), font,0.5, color_red,1) else: cv2.putText(frame,'AUTO', (110,55), font,0.5, color_green,2)def draw_dotted_line(frame, start, end, color, thickness, gap): x1, y1 = start x2, y2 = end length=int(np.sqrt((x2 - x1) **2+ (y2 - y1) **2)) fori in range(0,length, gap *2): start_x =int(x1 + (x2 - x1) * i /length) start_y =int(y1 + (y2 - y1) * i /length) end_x =int(x1 + (x2 - x1) * (i + gap) /length) end_y =int(y1 + (y2 - y1) * (i + gap) /length) cv2.line(frame, (start_x, start_y), (end_x, end_y), color, thickness)def draw_cross_target(frame): color_white = (255,255,255) height, width,_= frame.shape center_x, center_y = width //2, height //2 draw_dotted_line(frame, (center_x -50, center_y), (center_x +50, center_y), color_white,2,5) draw_dotted_line(frame, (center_x, center_y -50), (center_x, center_y +50), color_white,2,5)def draw_scaled_target(frame): color_white = (255,255,255) rect_size =50 height, width,_= frame.shape center_x, center_y = width //2, height //2 top_left_x = center_x - rect_size //2 top_left_y = center_y - rect_size //2 center_region = frame[top_left_y:top_left_y + rect_size, top_left_x:top_left_x + rect_size] scaled_region = cv2.resize(center_region, (rect_size *2, rect_size *2), interpolation=cv2.INTER_LINEAR) overlay_x_start = width - rect_size *2-20 overlay_y_start =20 frame[overlay_y_start:overlay_y_start + rect_size *2, overlay_x_start:overlay_x_start + rect_size *2] = scaled_region cv2.rectangle(frame, (overlay_x_start, overlay_y_start), (overlay_x_start + rect_size *2, overlay_y_start + rect_size *2), color_white,1)def draw_video_message(frame): font = cv2.FONT_HERSHEY_SIMPLEX color_white = (256,256,256) ifstate['video_msg'] !='': cv2.putText(frame,state['video_msg'], (43,80), font,0.5, color_white,1) countdown =int(state['video_msg_countdown']) ifcountdown < video_message_limit:? ? ? ? ? ? state['video_msg_countdown'] = countdown +?1? ? ? ? else:? ? ? ? ? ? state['video_msg'] =?''? ? ? ? ? ? state['video_msg_countdown'] =?0
draw_rc_auto_status(frame)函數(shù)在視頻疊加層上顯示RC信號(hào)強(qiáng)度和自動(dòng)駕駛儀模式。它使用綠色或紅色圓圈來(lái)指示信號(hào)是強(qiáng)還是弱。如果自動(dòng)駕駛儀關(guān)閉,它還會(huì)以紅色顯示“MANUAL”飛行模式;如果自動(dòng)駕駛儀激活,則以綠色顯示“AUTO”。
draw_dotted_line(frame, start, end, color, thickness, gap)函數(shù)在幀上的兩點(diǎn)之間繪制一條虛線。它根據(jù)指定的間隔和厚度計(jì)算線段,繪制小線段以創(chuàng)建虛線效果。
另一個(gè)函數(shù)draw_cross_target(frame)在視頻幀的中心繪制一個(gè)十字線。它使用draw_dotted_line創(chuàng)建一對(duì)水平和垂直的虛線,在中心相交。這個(gè)視覺(jué)輔助工具有助于在FPV無(wú)人機(jī)操作期間跟蹤FPV屏幕的中心點(diǎn)(目標(biāo)方向)。
draw_scaled_target(frame)函數(shù)提取并放大FPV視頻源的中心區(qū)域,將其作為插圖顯示在右上角。它捕獲一個(gè)方形區(qū)域,對(duì)其進(jìn)行縮放,然后將其疊加到幀上。這提供了目標(biāo)的更詳細(xì)視圖。
draw_video_message(frame)函數(shù)負(fù)責(zé)在視頻疊加層上顯示文本消息。如果在系統(tǒng)狀態(tài)的video_msg字段中存在消息,則將其顯示在RC信號(hào)強(qiáng)度下方。這包括一個(gè)倒計(jì)時(shí)計(jì)時(shí)器以控制消息的持續(xù)時(shí)間,并在計(jì)時(shí)器超過(guò)預(yù)設(shè)限制(默認(rèn):60)時(shí)清除它。此消息可以顯示由FPV護(hù)目鏡屏幕的視頻疊加功能檢索到的任何自定義文本。它對(duì)于顯示自動(dòng)駕駛儀操作的各個(gè)階段非常有用。
運(yùn)行點(diǎn)
main()函數(shù)實(shí)現(xiàn)了視頻疊加功能所需的所有操作,處理其他函數(shù)的初始化和執(zhí)行,以便在FPV屏幕上繪制額外的控制和消息。
#Mainfunctiondefmain(): cap = cv2.VideoCapture(video_source) if not cap.isOpened(): print("Error: Could not access the camera.") exit() cap.set(cv2.CAP_PROP_FRAME_WIDTH, camera_width) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, camera_height) cap.set(cv2.CAP_PROP_FPS, camera_fps) if video_full: cv2.namedWindow("BEE", cv2.WND_PROP_FULLSCREEN) cv2.setWindowProperty("BEE", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) print("Press 'q' to exit.") while True: ret, frame = cap.read() if not ret: print("Error: Could not read frame.") break # Save current frame to state for # Computer Vision tasks state['frame'] = frame draw_rc_auto_status(frame) draw_scaled_target(frame) draw_cross_target(frame) draw_video_message(frame) cv2.imshow('BEE', frame) if cv2.waitKey(1) &0xFF ==ord('q'): break cap.release() cv2.destroyAllWindows()
main()函數(shù)使用OpenCV初始化視頻捕獲設(shè)備(例如,我們之前連接的FPV攝像機(jī)),配置其分辨率和幀率。如果啟用了video_full(設(shè)為1),則可選地將顯示窗口設(shè)置為全屏模式。該函數(shù)進(jìn)入一個(gè)循環(huán)以連續(xù)讀取視頻幀,為計(jì)算機(jī)視覺(jué)任務(wù)更新共享狀態(tài)字典中的當(dāng)前幀。
它隨后應(yīng)用幾個(gè)視頻疊加函數(shù)(draw_rc_auto_status、draw_scaled_target、draw_cross_target、draw_video_message)以在FPV屏幕上顯示控制和消息。
如上所述實(shí)現(xiàn)的main()函數(shù)僅適用于實(shí)驗(yàn)?zāi)康摹H粢傻阶詣?dòng)駕駛儀中,此代碼將被移動(dòng)到單獨(dú)的線程中,并由自動(dòng)駕駛儀主進(jìn)程管理。然而,那是另一個(gè)話題了。
啟動(dòng)和使用
完成所有接線和焊接后,我啟動(dòng)了FPV無(wú)人機(jī)以及安裝在其上的伴侶計(jì)算機(jī)。然后,我運(yùn)行了一個(gè)Python腳本以驗(yàn)證視頻模塊是否正常工作,成功地將FPV視頻源從FPV攝像機(jī)傳輸?shù)斤w行控制器,并隨后通過(guò)VTX傳輸?shù)紽PV護(hù)目鏡。
帶有視頻疊加和OSD屏幕的FPV顯示器
如上圖所示,包括OSD、視頻源和視頻疊加在內(nèi)的所有內(nèi)容都正確地顯示在FPV屏幕上。默認(rèn)的PAL分辨率720x480像素導(dǎo)致圖像質(zhì)量不太理想。然而,對(duì)于搭載模擬FPV攝像機(jī)的FPV無(wú)人機(jī)來(lái)說(shuō),這種分辨率水平是相當(dāng)常見(jiàn)的。
-
無(wú)人機(jī)
+關(guān)注
關(guān)注
230文章
10774瀏覽量
185920 -
自動(dòng)駕駛
+關(guān)注
關(guān)注
788文章
14246瀏覽量
169955 -
樹(shù)莓派
+關(guān)注
關(guān)注
121文章
1966瀏覽量
107117
發(fā)布評(píng)論請(qǐng)先 登錄
有朋友用PIC開(kāi)發(fā)自動(dòng)駕駛儀的嗎
The Drone Pi :用樹(shù)莓派做無(wú)人機(jī)(一)——材料準(zhǔn)備
用樹(shù)莓派做無(wú)人機(jī)(三)——推進(jìn)和飛行控制
用樹(shù)莓派做無(wú)人機(jī)(完)——樹(shù)莓派部分
自動(dòng)駕駛汽車+無(wú)人機(jī) 的車企新套路
請(qǐng)問(wèn)樹(shù)莓派如何利用Tensorflow實(shí)現(xiàn)小車的自動(dòng)駕駛 ?
基于ld303+樹(shù)莓派的自動(dòng)駕駛
怎樣去設(shè)計(jì)一個(gè)基于樹(shù)莓派和Python的無(wú)人機(jī)視覺(jué)跟蹤系統(tǒng)呢
使用樹(shù)莓派Pico做了一個(gè)自動(dòng)駕駛小車
基于ARM處理器的小型無(wú)人機(jī)自動(dòng)駕駛儀的設(shè)計(jì)
TU Delft已研發(fā)出世界上最小的微型自動(dòng)駕駛儀
自動(dòng)駕駛儀開(kāi)源分享

帆船自動(dòng)駕駛儀(自動(dòng)轉(zhuǎn)向系統(tǒng))開(kāi)源分享

基于Arduino的無(wú)人機(jī)構(gòu)建

使用 Betaflight 和樹(shù)莓派實(shí)現(xiàn) FPV 無(wú)人機(jī)自主飛行!

評(píng)論