为ArduRover装上“眼睛”:基于计算机视觉的自主漫游车实战

B站影视 港台电影 2025-10-30 13:18 1

摘要:如果你曾经尝试构建搭载计算机视觉的自主系统,你就会知道入门有多么困难。当平台是空中平台时,例如FPV无人机或飞机,难度会更大——飞行过程中的任何失误都可能导致坠机和严重损坏。相比之下,使用像Rover这样的地面机器人平台就可以消除这些风险。由于它始终停留在地面

译者 | 朱先忠

审校 | 重楼

LOONARR-1搭载ArduRover

如果你曾经尝试构建搭载计算机视觉的自主系统,你就会知道入门有多么困难。当平台是空中平台时,例如FPV无人机或飞机,难度会更大——飞行过程中的任何失误都可能导致坠机和严重损坏。相比之下,使用像Rover这样的地面机器人平台就可以消除这些风险。由于它始终停留在地面上,因此你可以安全地调试和开发自动驾驶仪或其他功能,风险要低得多。

在本文中,我将提供一份全面的搭建试验指南,教你如何从零开始构建一台漫游车,并将自动驾驶仪与计算机视觉集成,用于地面目标跟踪。在本试验中,我们将使用ArduRover固件、MAVLink协议、配套计算机(Raspberry Pi 5)以及OpenCV和YOLO进行物体检测(识别)。

一般设计方案

漫游车运行ArduRover固件,并使用树莓派(RaspberryPi)作为配套计算机。连接到树莓派的摄像头可捕捉图像,用于基于人工智能的自主导航。在跟随模式下,漫游车的自动驾驶仪采用YOLO计算机视觉模型进行目标检测(识别),计算目标在NED坐标系中的位置,然后跟随目标。一旦漫游车足够接近目标,它就会停止,关闭电机,完成任务。

因此,我们的示例重点关注基于AI的自主导航,使用在GNSS环境(GPS+指南针)中运行的地面机器人平台,并使用YOLO计算机视觉模型作为目标检测器。

作为开发的基础,我们使用4WD底盘机器人框架和Dake FPV F405飞行控制器作为我们原理图的核心。

系统架构

与任何电子设备一样,Rover也有一个电路图,用于显示其组件的连接方式。虽然Rover的电路可能并不简单;但是,我还是为你绘制了一个示意图。在开始组装和焊接组件之前,请花点时间查看一下。

我们的试验目标漫游车的电路图设计

从上图可以看出,有许多组件必须相互连接。

接线组织如下:

电池组(6S2P)通过正面的8线JST接口连接到飞控(FC)。接线方式:BAT→+,GND→−。电源输入端必须安装1000µF电容以稳定电压。

XL4015DC-DC转换器配置为输出6.5V/3A,为TT黄色电机提供足够的电流给电机驱动器。

两个BTS7960驱动器上的B+/B−连接到XL4015转换器的VOUT/GND。

TT电机(左侧)通过M+和M-。焊盘与左侧BTS7960驱动器并联。

TT电机(右侧)通过M+和M-。焊盘并联连接到右侧BTS7960驱动器。

第一级(XL4015、驱动器和电机)

BTS7960(左驱动器)通过前面的8线JST插孔连接到FC:
S1→R_PWM、S2→L_PWM、5V→VCC、GND→GND、
R_EN/L_EN必须连接到VCC才能保持驱动器启用。

BTS7960(右驱动器)通过前面的8线JST插孔连接到FC:
S3→R_PWM、S4→L_PWM、5V→VCC、GND→GND
R_EN/L_EN必须连接到VCC才能保持驱动器启用。

第二层(FC、GPS、指南针、ELRS、3DR、RPi、蜂鸣器)

ELRS接收器通过正面的4线JST插孔将SpeedyBee ELRS Nano接收器2.4GHz连接到Dake FPV F405 FC,或通过直接接线:T2→RX、R2→TX、GD→GND、5V→VCC。

GPS模块(BN-220)连接4根线:5V→VCC、GND→GND、T1→RX、R1→TX。

指南针(QMC5883L)连接4根线:SDA→SDA、SCL→SCL、5V→VCC、GND→GND。

蜂鸣器

连接到FC:BZ+→VCC,BZ−→GND。

3DR遥测模块连接4根线:T4→RX,R4→TX,GND→GND,5V→VCC。

第三层(电池、RPi的DC-DC转换器)

Raspberry Pi 5通过底部的6线JST插孔连接到FC:
T5→UART0_RXD、R5→UART0_TXD、GND→GND
Raspberry Pi由专用5V/5ADC-DC转换器供电,该转换器通过XT60连接器连接到电池组。
由于系统复杂(三个层级),上面的示意图并非完整的电路原理图。部分元件(例如Raspberry Pi的专用DC-DC转换器或XL4015输出端的肖特基二极管)未显示,但最终设备必须包含这些元件。
我相信每次搭建都是一次新的实验,学习过程的一部分就是逐步完成布线。这种方法能帮助你更深入地理解设计,甚至基于这些知识创建自己的原理图。

软件配置

正确焊接所有组件并在Dake FPV F405飞行控制器上安装ArduRover固件后,下一步是使用Mission Planner软件配置你的模型。

你必须相应地配置以下参数:

FRAME_CLASS=1—流动站

FRAME_TYPE=0—未定义

MOT_PWM_TYPE=4—BrushedBiPolar流动站,可通过4WD电机实现前进和后退运动

SERVO1_FUNCTION=73—油门左

SERVO2_FUNCTION=73(已检查反向)—ThrottleLeft(反向)

SERVO3_FUNCTION=74—油门右

SERVO4_FUNCTION=74(已选中反向)—ThrottleRight(反向)

RC5_OPTION=153—布防/撤防控制

ARMING_CHECK=0—临时(禁用安全检查)

RC7_OPTION=55—切换至引导模式

GPS1_TYPE=2—UBlox(如果使用BN-220)

SERIAL1_BAUD=38–38400GPS波特率

EK3_GPS_CHECK=0—临时(禁用GPS检查)

SERIAL4_BAUD=57–遥测模块的波特率为57600

SERIAL4_PROTOCOL=42—MAVLink2(通过Mission Planner的无线电链路实现流动站控制)

WP_SPEED=0.5—GUIDED模式下的最大速度设置为0.5m/s(50cm/s)正确的配置是ArduRover固件和自动驾驶仪可靠运行的基础。此外,你需要通过基本设置将Radio Master Pocket 2.4 GHz发射器与Rover绑定,并确保模型至少可以在手动模式下运行,然后再继续操作。

自动驾驶仪

在配套计算机(Raspberry Pi)上运行并通过MAVLink与飞行控制器通信以实现自主操作的特殊软件称为自动驾驶仪。

该自动驾驶仪的完整源代码可以在下面的链接处下载:

ArduRover的目标跟踪自动驾驶仪(开发版)

我之前发布的原始实现的通用版本见下面的链接:

用于FPV战斗无人机的带目标跟踪的自动驾驶仪(模拟器版本)

如果需要,这两个版本都可以轻松适应你的特定FPV无人机、飞机或探测车模型,并且可以自由使用,无需任何担保。

软件架构

我们的自动驾驶仪LOONARR采用多线程设计,围绕中央命令队列和命令路由器构建。路由器线程处理排队的命令,而遥测线程和跟随线程则简单地将新命令附加到队列中。

ArduRover自动驾驶仪开发的软件架构

每个模块的详细描述,包括其配置参数和工作流程,都可以在我上面提到的源代码仓库中的README_DEV.md文件中找到。恕我不会在这里详细介绍。

计算机视觉

CV模块是目标跟踪过程的基石,也是我们解决方案的关键组件。它就像系统的“眼睛”,能够检测和跟踪(跟随)目标。因此,我将在本节中对它作简要介绍。

该自动驾驶仪使用YOLOv8模型进行物体检测,具体来说是yolov8n.pt模型,使用Person类(class0)。为了处理视频帧、与Raspberry Pi摄像头连接以及管理不同的分辨率,自动驾驶仪依赖于OpenCV和Picamera2。

物体检测和目标跟踪在工作过程中涉及几个复杂的任务,包括:

将目标位置从图像帧转换为笛卡尔坐标(NED—北,东,下)

根据需要调整探测车的位置和速度

考虑比例和转换因素

所有这些功能都是在位于vision.py文件中的计算机视觉模块中实现的。

import cv2

import definitions as vars

from datetime import datetime

from picamera2 import Picamera2

from ultralytics import YOLO

model = YOLO(vars.vision_model)

image_width = vars.camera_width

image_height = vars.camera_height

yaw_conversion_factor = 0.002

threshold_percentage=0.40

approach_factor = 0.8

pi_camera_index = 255

def configure_camera:

camera = {}

if vars.video_source == pi_camera_index:

camera = Picamera2

config = camera.create_preview_configuration(

main={"size": (vars.camera_width, vars.camera_height),

"format": "RGB888"})

camera.configure(config)

camera.start

else:

camera = cv2.VideoCapture(vars.video_source)

if not camera.isOpened:

print('VISION: Camera is not ready!')

return camera

cam = configure_camera

def get_camera_image:

result = {}

png_file_name = \

f'{vars.logger_directory}/img_{datetime.now.strftime("%Y-%m-%d_%H-%M-%S")}.png'

frame = cam.capture_array

result = get_anotated_frame(frame,

png_file_name)

else:

success, frame = cam.read

if success:

png_file_name)

cv2.destroyAllWindows

return result

def get_anotated_frame(frame, png_file_name):

results = model(frame, classes=vars.vision_classes,

imgsz=vars.camera_width, verbose=False)

anotated_frame = results[0].plot

cv2.imwrite(png_file_name, anotated_frame)

result = results[0]

return result

def get_ned_coordinates(x1, y1, x2, y2, altitude):

target_x = (x1 + x2) / 2

target_y = (y1 + y2) / 2

relative_x = (2 * target_x / image_width) - 1

relative_y = (2 * target_y / image_height) - 1

N_coord = relative_y * altitude

D_coord = 0

return N_coord, E_coord, D_coord

def get_yaw_angle(x1, y1, x2, y2):

target_x = (x1 + x2) / 2

yaw_angle = (target_x - image_width / 2) * yaw_conversion_factor

return yaw_angle

def get_target_threshold_area(x1, y1, x2, y2):

target_area = (x2 - x1) * (y2 - y1)

threshold_area = \

image_width * image_height * threshold_percentage

return target_area, threshold_area

def is_target_close_enough(x1, y1, x2, y2):

target_area, threshold_area = \

get_target_threshold_area(x1, y1, x2, y2)

return target_area > threshold_area

def get_ned_target(x1, y1, x2, y2, altitude):

N_coord, E_coord, D_coord = get_ned_coordinates(

x1, y1, x2, y2, altitude)

yaw_angle = get_yaw_angle(x1, y1, x2, y2)

target_area, threshold_area = \

get_target_threshold_area(x1, y1, x2, y2)

long_factor = threshold_area / target_area

return round(N_coord * long_factor * approach_factor, 4), \

round(E_coord, 4), round(D_coord, 4), round(yaw_angle, 4)

如上代码所示,该系统使用由YOLOv8驱动的目标跟踪模块。其中,OpenCV从USB摄像头或RPI摄像头(基于配置)捕获实时视频,YOLO检测人员自定义函数,将这些检测转换为导航命令(NED坐标和偏航),以便探测车跟踪目标。

NED坐标计算

如上图所示,上坡的人被YOLO模型检测为目标。代码计算边界框(红色)的中心,并在NED(北、东、下)坐标系中相应地调整Rover的移动,如图所示。

例如,NED(4.21,-1.83,-2.29)表示探测车应从当前位置向北移动4.21米,向西移动1.83米(由于值为负,因此与向东方向相反),向上移动2.29米(与向下方向相反),以跟随斜坡上的目标。

在RPi上安装

如前面的架构部分所述,Raspberry Pi(RPi)在此设置中充当配套计算机,通过MAVLink与飞行控制器上的ArduRover固件进行通信。

按照以下步骤在RPi上安装自动驾驶仪代码:

1.下载并将存储库解压到目录:/home/pi/Apps/loonarr

2.将服务和脚本文件复制config/run_autopilot.service到config/run_autopilot.sh:/etc/systemd/system

3.设置必要的权限

sudo chmod +x /etc/systemd/system/run_autopilot.sh

4.启动时启用Autopilot服务

sudo systemctl enable run_autopilot.service

sudo reboot

5.验证日志:

树莓派重启后,前往logs文件夹检查是否有新文件生成。

如果没有,请检查definitions.py并根据需要调整设置。

此时,你的Rover、自动驾驶仪以及所有相关组件应该已准备好进行首次启动和测试。请按照下一节中的说明进行操作。

用法

现在,你已经完成了所有艰苦的工作,是时候测试你的作品了,看看它在实际应用中的表现如何。前往一片空旷的地方,带上你的Rover(搭载了树莓派)、RadioMaster Tx以及你的笔记本电脑(笔记本电脑的USB端口已插入3DR遥测模块)。然后按照图片下方的说明测试你的最终组装。

GPS:3D定位(准备执行任务)

检查设备功能的步骤是:

打开你的RadioMaster TX(或另一个ELRS发射器)。

将电池组连接到Rover的XT60输入。

验证流动站响应:切换模式、布防/撤防,并在手动模式下驾驶。

使用计算机上的3DR Telemetry检查GPS信号。

将RC7(chan7_raw)切换到GUIDED模式。

武装好Rover并站在摄像机前。

等待约2秒—探测车就会朝你驶来。

完成:一旦探测车到达你身边,它将自动解除武装并且蜂鸣器会响起。

如果你做的一切都正确,那么探测车就会像本文开头的第一张插图中所示那样跟随你。

飞行记录

出于安全原因和飞行后分析,自动驾驶仪在运行期间会生成日志文件,并将导航中使用的带有边界框的所有图像保存到日志文件夹中。

目标跟踪帧

这些飞行记录在必要时可作为正确操作的宝贵证据,也可用于调查飞行过程中的碰撞或不当行为(这对Rover来说很重要)。

日志文件中的飞行记录

如图所示,自动驾驶仪几次失去目标,然后重新获得目标并继续跟踪,直到距离足够近,可以成功完成任务。

与往常一样,我建议将记录器设置为“调试”模式,以便最大限度地利用这些飞行记录。这将帮助你在每次飞行中改进自动驾驶系统。

一些注意事项

如果上述所有操作均已完成并正常运行,那么许多新的可能性就会随之而来。从这一点开始,利用你从本文中获得的方法和知识,你可以构建其他地面机器人平台,包括但不限于:

疏散流动车

医疗用品流浪者队

有效载荷运载工具

侦察平台

等等。

无论你是出于兴趣爱好还是实际使用而创建设备,都可以考虑提供经过测试的第一视角(FPV)无人机、侦察固定翼飞机,甚至大型探测车(如果你决定建造的话),以用于民用、国防保护等领域应用。

你可以在Twitter上提问:https://twitter.com/dmytro_sazonov

译者介绍

朱先忠,51CTO社区编辑,51CTO专家博客、讲师,潍坊一所高校计算机教师,自由编程界老兵一枚。

来源:汽车驾驶员

相关推荐