如何为树莓派 FPV 战斗无人机构建自动驾驶仪的“眼睛”!

描述

学习如何为FPV战斗无人机构建一个视频模块,该模块能够从模拟FPV摄像机捕获视频流,利用这些视频流执行计算机视觉任务,并将图像传输到飞行控制器进行进一步处理(OSD)以及通过VTX进行视频传输。

 

本文是我一年多来一直在进行的研发工作的自然延续,该研发工作专注于为FPV战斗无人机构建自动驾驶仪。

当我开始探索如何向FPV操作员通知自动驾驶仪的当前状态和飞行参数时,我意识到在基于Betaflight固件的飞行控制器中没有可用的软件解决方案。这促使我考虑一个软硬件结合的解决方案。
 

在评估不同选项时,有两个关键因素脱颖而出:首先,保持与Betaflight固件和流行的FPV无人机配置的兼容性,而不改变它们,这一点很重要。其次,解决方案需要具备修改FPV视频源和OSD(屏幕显示)的能力,以显示计算机视觉模型识别的目标,以及其他自动驾驶仪状态和飞行参数。

在本文中,我将分享我在这一过程中发现的内容。

架构

最初的想法是在FPV摄像机和飞行控制器(FC)之间创建一个“中间人”,以便在FPV屏幕上叠加额外的控制和消息,同时处理图像以执行人工智能驱动的计算机视觉任务。对于这个角色,我选择了一台树莓派以及两个加密狗:一个AV2USB加密狗(用于从FPV摄像机获取数字MJPEG图像)和一个HDMI2AV加密狗(用于以PAL/NTSC模拟格式将修改后的图像传输到FC)。

自动驾驶

视频模块接线图

为了在FPV摄像机和飞行控制器之间实现“中间人”功能,我决定支持常用的接口,特别是JST 3针电缆。在此设置中,一条JST电缆将AV2USB加密狗连接到FPV摄像机,而另一条JST电缆则将飞行控制器连接到HDMI2AV加密狗。两个加密狗都连接到伴侣计算机(在我们的例子中是树莓派3),使其能够获取/传输带有特定于计算机视觉任务的视频叠加的FPV摄像机图像。

自动驾驶

AV2USB加密狗的焊接点

如上图所示,我将USB电缆的红色(5V)线焊接到加密狗上的5V焊盘上,同时还将JST电缆的红色线也焊接上去。这种设置允许USB电缆同时为加密狗和FPV摄像机供电。

JST电缆的接地线(黑色)和视频信号线(黄色)焊接到加密狗上的AV和G焊盘上。此外,USB电缆的接地线(灰色)也连接到加密狗上的G焊盘上。USB的蓝色线焊接到DP(数据+)焊盘上,而USB的白色线则焊接到DM(数据-)焊盘上。

适当的焊接确保了电路板的可靠运行。

自动驾驶

4极3.5毫米AV2PAL电缆,CVBS信号线焊接至3针JST连接器

为了将HDMI2AV加密狗连接到FC,我使用了CVBS线(PAL输出中的黄色线),并将其连接到一条JST电缆上,该电缆通过用于FPV摄像机连接的相同3针JST线直接连接到FC板上。有关详细信息,请参考上面的接线图。

CVBS电缆中只有两条线连接到3针JST连接器上。黄色线是信号线(CAM),连接到另一侧的黄色线上。黑色线是接地线(GND),连接到另一侧对应的接地线上。红色线(5V)保持未连接状态,因为它通常用于为FPV摄像机供电。然而,在我们的设置中,我们以不同的方式为FPV摄像机供电。

让我们继续探讨软件部分。

导入

为了实现视频叠加功能,我们需要导入整个项目中将使用的两个包:cv2(用于计算机视觉任务,如从FPV摄像机捕获帧)和numpy(用于执行数组操作和数据操作)。

  •  
  •  

import cv2import numpy as np

如果你还没有安装它们,现在是时候安装了。

定义和状态

本节内容来源于Autopilot “BEE” 仓库中的适当文件,包括definitions.py和autopilot.py,该仓库针对FPV战斗无人机(模拟器版本)的跟踪目标功能。本节提供了应在FPV屏幕上显示的自动驾驶仪设置及当前状态这部分内容源自仓库中Autopilot "BEE" with target following for FPV Combat Drone(模拟器版本)的definitions.py和autopilot.py文件,提供了应在FPV屏幕上显示的自动驾驶仪的设置和当前状态。

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}

定义——视频叠加模块的设置:

video_source = 0,指的是通过树莓派上的USB端口连接的摄像机,由于默认情况下没有安装摄像机,因此这是索引为0的第一个摄像机。

video_full = 1,表示视频叠加将以全屏模式显示。设为0用于调试。

video_message_limit = 60,限制在FPV屏幕上显示video_msg的帧数为60帧。

camera_width和camera_height,将分辨率设置为720x480像素。

camera_fps = 1,使用OpenCV(cv2)每秒捕获1帧。

自动驾驶仪的状态(当前状态):

rssi_msg,可以设置为“Strong signal”(强信号)或“No signal”(无信号)。根据此消息,RC标签和圆形符号将以红色或绿色显示在FPV屏幕上,指示信号强度。

video_msg,可以包含要在FPV屏幕上显示的任何消息,直到达到有限的帧数(在video_msg_countdown中计数)。

frame,保存当前帧,该帧可以由计算机视觉模型处理,以实现FPV无人机的自主操作。

当前状态和所有字段状态在自动驾驶仪运行期间由应用程序的其他组件更新。

视频叠加

该子系统的核心是视频叠加功能,这些功能会添加关于自动驾驶仪状态的额外组件和消息,例如RC信号强度、自定义消息、缩放后的目标以及用于瞄准的中心十字线,所有这些都显示在FPV屏幕上(FPV护目镜或FPV显示器)。

查看代码及其在列表下方的描述。

  •  

# Autopilot's overlaydef draw_rc_auto_status(frame):    color_green = (0, 255, 0)    color_red = (0, 0, 255)    color = color_green if state['rssi_msg'] == 'Strong signal' else color_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)    if state['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))    for i 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)    if state['video_msg'] != '':        cv2.putText(frame, state['video_msg'], (43, 80), font, 0.5, color_white, 1)        countdown = int(state['video_msg_countdown'])        if countdown < video_message_limit:            state['video_msg_countdown'] = countdown + 1        else:            state['video_msg'] = ''            state['video_msg_countdown'] = 0

draw_rc_auto_status(frame)函数在视频叠加层上显示RC信号强度和自动驾驶仪模式。它使用绿色或红色圆圈来指示信号是强还是弱。如果自动驾驶仪关闭,它还会以红色显示“MANUAL”飞行模式;如果自动驾驶仪激活,则以绿色显示“AUTO”。

draw_dotted_line(frame, start, end, color, thickness, gap)函数在帧上的两点之间绘制一条虚线。它根据指定的间隔和厚度计算线段,绘制小线段以创建虚线效果。

另一个函数draw_cross_target(frame)在视频帧的中心绘制一个十字线。它使用draw_dotted_line创建一对水平和垂直的虚线,在中心相交。这个视觉辅助工具有助于在FPV无人机操作期间跟踪FPV屏幕的中心点(目标方向)。

draw_scaled_target(frame)函数提取并放大FPV视频源的中心区域,将其作为插图显示在右上角。它捕获一个方形区域,对其进行缩放,然后将其叠加到帧上。这提供了目标的更详细视图。

draw_video_message(frame)函数负责在视频叠加层上显示文本消息。如果在系统状态的video_msg字段中存在消息,则将其显示在RC信号强度下方。这包括一个倒计时计时器以控制消息的持续时间,并在计时器超过预设限制(默认:60)时清除它。此消息可以显示由FPV护目镜屏幕的视频叠加功能检索到的任何自定义文本。它对于显示自动驾驶仪操作的各个阶段非常有用。

运行点

main()函数实现了视频叠加功能所需的所有操作,处理其他函数的初始化和执行,以便在FPV屏幕上绘制额外的控制和消息。

  •  
  •  
  •  

# Main functiondef main():    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()函数使用OpenCV初始化视频捕获设备(例如,我们之前连接的FPV摄像机),配置其分辨率和帧率。如果启用了video_full(设为1),则可选地将显示窗口设置为全屏模式。该函数进入一个循环以连续读取视频帧,为计算机视觉任务更新共享状态字典中的当前帧。

它随后应用几个视频叠加函数(draw_rc_auto_status、draw_scaled_target、draw_cross_target、draw_video_message)以在FPV屏幕上显示控制和消息。

如上所述实现的main()函数仅适用于实验目的。若要集成到自动驾驶仪中,此代码将被移动到单独的线程中,并由自动驾驶仪主进程管理。然而,那是另一个话题了。

启动和使用

完成所有接线和焊接后,我启动了FPV无人机以及安装在其上的伴侣计算机。然后,我运行了一个Python脚本以验证视频模块是否正常工作,成功地将FPV视频源从FPV摄像机传输到飞行控制器,并随后通过VTX传输到FPV护目镜。

自动驾驶

带有视频叠加和OSD屏幕的FPV显示器

如上图所示,包括OSD、视频源和视频叠加在内的所有内容都正确地显示在FPV屏幕上。默认的PAL分辨率720x480像素导致图像质量不太理想。然而,对于搭载模拟FPV摄像机的FPV无人机来说,这种分辨率水平是相当常见的。

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分