YOLOv5+ROS部署实战:行人红绿灯检测全流程解析
2026/9/24 21:20:00 网站建设 项目流程

简介:基于YOLOv5 ROS部署版实现行人和红绿灯识别的源码工程,包含训练好的权重与说明文档,主要面向计算机、电子信息工程、数学等专业的大学生,用于课程设计、期末大作业或毕业设计中的目标检测与ROS应用场景,帮助读者快速搭建交通参与者识别实验环境。压缩包共123个文件,大小约83.87MB,文件类型涵盖Python脚本、YAML配置、模型权重(.pt/.pth)、Shell脚本、Dockerfile、Markdown说明、Jupyter Notebook等,其中py/yaml支撑推理与参数配置,pt/pth提供预训练模型,md/ipynb用于原理讲解与快速上手。目前已有1933人学习下载,对于需要参考完整项目做二次开发的同学具有一定热度。内容还包括YOLOv5网络结构说明、注意力机制报告、示例图片及测试脚本,并针对ROS部署做了适配,流程相对完整;读者可在现有代码基础上自行修改功能、调参或扩展数据集,作为毕业设计或竞赛项目的参考资料较为合适。

1. 基于YOLOv5的ROS部署版:行人和红绿灯识别从模型到节点的一次性打通

很多做机器人课题的同学,卡住的往往不是模型训练,而是怎么把检测结果灌进ROS这个“黑匣子”里。这份基于YOLOv5的ROS部署版资源,就是把这条链路整体打包好的例子:用现成的YOLOv5权重对行人、红绿灯做检测,省去自己写一堆图像桥接代码的功夫。资源里带了源码、权重和说明文档,还配有Dockerfile和tutorial.ipynb,适合课程设计、期末大作业,或者刚接触ROS+检测的工程师当作参考资料来用。它解决的问题很具体:让YOLOv5从“吃一张JPG的Python脚本”变成“订阅一个图像话题就能持续出框的ROS节点”。如果你手里有现成摄像头或者UVc相机,顺着这份资源的思路,能很快跑出一套本地部署的识别链路。

2. 部署前先看懂耦合关系:YOLOv5推理和ROS消息循环怎么衔接

2.1 为什么标准YOLOv5不能直接进ROS

原版YOLOv5的detect.py接收命令行里的source参数,可以是图片、视频、摄像头。它的工作方式是单次调用:读文件、跑网络、保存结果。这里面没有“持续循环”和“消息订阅”的概念。

ROS节点的运行模式是event-driven的。节点要先初始化,订阅某个话题,之后每一帧图像到达时,回调函数被触发,在回调里做推理,再把结果发布出去。这个流程里没有命令行参数控制的source位置,图像输入变成sensor_msgs/Image消息,输出要么是另一个图像话题,要么是检测结果的消息数组。

所以部署版要做的第一件事,就是把YOLOv5包装成“节点”,而不是“脚本”。在这份资源里你会看到类似yolo_detect_node.py这样的节点文件,它做的事情就是典型的四步:初始化节点、订阅图像话题、调用YOLOv5推理、发布结果话题。理解这个关系,后面调试的时候就不会一头扎进模型代码里,而是先看话题传输对不对。

2.2 为什么选YOLOv5加ROS这套组合

YOLOv5不是最新的算法,但它在业内留存了大量工程化资源,部署路径非常成熟。训练好的权重可以直接加载,也可以用torch.hub方式调用,导出ONNX、TensorRT也比较方便。对于课程设计和工程demo来说,YOLOv5的精度、速度和代码可读性比较均衡。

选择ROS做载体,是因为机器人系统里所有传感器数据都以话题形式流动。摄像头在驱动节点里发布图像话题,其他模块订阅这个话题,互相解耦。YOLOv5节点只负责“看”,后续的决策、导航、报警模块可以再订阅检测结果,各自独立运行。

这套组合真正的价值在于:你只需要关心检测节点内部怎么调参,外部接口用ROS标准消息就能对接。比如行人的检测结果可以接一个跟踪节点,红绿灯的检测结果可以接一个位置估算节点,互不干扰。

2.3 资源包结构里藏着的部署思路

解压这个RAR包后,文件清单并不复杂,每个文件都有明确用途。

文件在部署中承担的角色
Dockerfile把ROS、PyTorch、YOLOv5依赖打成一个镜像,解决环境不一致问题
setup.cfgPython包安装配置,配合pip install -e .使用,让项目能作为包导入
tutorial.ipynb按单元格执行的教程,适合先在Jupyter里把单张图片的检测跑通
bus.jpg / zidane.jpg测试图片,YOLOv5仓库自带的样例图,用于快速回归验证
README.md项目导读,包含权重路径、启动方式等说明
yolov5_network.mdYOLOv5网络结构解析,适合想理解Backbone、Neck、Head的读者
注意力机制报告.md注意力机制扩展思路,对红绿灯这种小目标检测有直接帮助

我拿到这类资源,一般先看README,再打开tutorial.ipynb,最后才碰launch文件和节点代码。这样的顺序能最快的知道模型到底能不能跑,再去解决话题层面的问题。

另外,COCO预训练的YOLOv5模型本身就能检测person和traffic light这两个类别。也就是说,即使你没有自训练的数据集,直接用预训练权重也能完成基本需求。这对课程设计非常友好,算是“开箱即用”的兜底方案。

3. 把部署版跑通:环境、镜像和第一个检测节点

3.1 环境准备:Ubuntu版本、ROS版本和依赖选择

这类的资源基本都依赖ROS1,因为launch文件和rospy都是ROS1的东西。常见搭配是Ubuntu 20.04加ROS Noetic,对应Python 3.8,PyTorch生态兼容性也比较好。

ROS安装建议直接使用小鱼一键安装脚本的大名,至少可以少走很多弯路。命令行安装方式社区里已经很成熟,这里不再重复。装完之后记得验证一下ROS环境变量,用echo $ROS_DISTRO确认当前环境确实指向Noetic,而不是后面又source了别的ROS2。

深度学习依赖方面,YOLOv5需要PyTorch、torchvision、opencv-python、numpy等。如果不想让ROS环境被pip依赖搞乱,优先使用资源里的Dockerfile构建镜像。Docker的好处是可以隐藏掉宿主机Python版本差异,缺点是挂载摄像头和GPU时要多配置几步。

如果选择本地conda环境,我在实际项目中更习惯的做法是:

# 先创建独立环境,避免和ROS自带的Python打架 conda create -n yolov5_ros python=3.8 -y conda activate yolov5_ros # 在项目根目录下执行,读取setup.cfg完成包安装 pip install -e . # 额外安装YOLOv5缺失的依赖 pip install torch torchvision opencv-python numpy pandas matplotlib

这里的pip install -e .会读取setup.cfg中的package配置,把项目注册成一个可导入的Python包。否则直接在节点脚本里写import yolo_module会找不到模块。建议先跑这一步再启动ROS节点。

3.2 用Dockerfile构建镜像并启动容器

如果主机上已经有NVIDIA显卡,可以优先考虑Docker方案。以下命令需要在RAR包解压后的根目录执行。

# 构建镜像,镜像名建议带版本号,避免以后改Dockerfile后分不清 docker build -t yolov5_ros:v1 . # 启动交互式容器,使用宿主机网络,并把摄像头设备挂载进去 docker run -it --network host --gpus all \ -v /dev/video0:/dev/video0 \ yolov5_ros:v1 /bin/bash

这段命令里最关键的是--network host。ROS节点之间的通信依赖ROS_MASTER_URI,如果容器默认使用bridge网络,容器内的IP是172.17.0.x这种,和宿主机、其他机器的话题通信很容易失败。使用宿主机网络后,容器里的节点就相当于跑在宿主机上,ROS的Topic通信从根源上省掉了网络层的问题。

--gpus all只有在搭配nvidia-container-toolkit时才有效。如果报错,参考后面避坑章节的解决办法。/dev/video0是USB摄像头的设备文件,容器里默认看不到宿主机设备,必须手动挂载。

3.3 编写launch文件启动检测节点

launch文件的作用是把节点参数固化下来,以后每次启动不用记一堆命令行参数。这里给出一个常见的launch写法。

<launch> <node name="yolo_detect_node" pkg="yolov5_ros" type="yolo_detect_node.py" output="screen"> <param name="image_topic" value="/camera/rgb/image_raw"/> <param name="weights_path" value="$(find yolov5_ros)/weights/best.pt"/> <param name="conf_thres" value="0.5"/> <param name="iou_thres" value="0.45"/> <param name="img_size" value="640"/> </node> </launch>

参数image_topic指定图像输入话题,这个值必须和相机驱动节点发布的话题一致。weights_path$(find yolov5_ros)定位包路径,比自己写绝对路径可靠得多。conf_thres是置信度阈值,数值越低,框出越多,但误检也会变多;iou_thres是NMS的IOU阈值,控制重叠框去重力度;img_size是推理输入尺寸,640是速度和精度的平衡点。

这里给一个提醒:很多新手拿到包后,路径里的包名不一定叫yolov5_ros,有时叫yolov5_detectvision_yolo。launch里的pkgtype要改成实际包名,否则roslaunch会报找不到package。以README为准。

3.4 节点核心逻辑:图像桥接、推理、发布结果

下面这段代码是一个典型的YOLOv5 ROS节点核心框架,可以直接对照工程源码看。

#!/usr/bin/env python3 import rospy import cv2 import torch from sensor_msgs.msg import Image from cv_bridge import CvBridge from std_msgs.msg import Header class YoloNode: def __init__(self): rospy.init_node('yolo_detect_node', anonymous=True) self.bridge = CvBridge() self.image_sub = rospy.Subscriber( rospy.get_param('~image_topic', '/camera/rgb/image_raw'), Image, self.callback ) self.pub = rospy.Publisher('/yolo_detection/image', Image, queue_size=1) weights = rospy.get_param('~weights_path', 'weights/best.pt') self.model = torch.hub.load('ultralytics/yolov5', 'custom', path=weights, force_reload=False) self.model.conf = rospy.get_param('~conf_thres', 0.5) self.model.iou = rospy.get_param('~iou_thres', 0.45) rospy.loginfo('YOLOv5 node started with weights: %s', weights) def callback(self, msg): # 1. ROS图像转OpenCV BGR图像 frame = self.bridge.imgmsg_to_cv2(msg, desired_encoding='bgr8') # 2. 转成RGB送入模型,YOLOv5模型是在RGB图像上训练的 rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results = self.model(rgb, size=640) # 3. 渲染检测框后转回ROS图像消息 rendered = results.render()[0] pub_msg = self.bridge.cv2_to_imgmsg(rendered, encoding='rgb8') pub_msg.header = msg.header self.pub.publish(pub_msg) if __name__ == '__main__': try: node = YoloNode() rospy.spin() except rospy.ROSInterruptException: pass

这份代码的注释已经覆盖了三个关键转折点:cv_bridge转换、RGB通道顺序、ROS消息发布。特别要注意通道顺序。OpenCV默认读入的是BGR,而PyTorch模型输入通常是RGB,不做转换的话颜色语义就乱了,行人还能识别,但红绿灯这种依赖颜色特征的目标会明显变差。

results.render()[0]返回的是画好框的numpy数组,直接转成Image消息发布。如果后续要做跟踪或者决策,更专业的做法是解析results.xyxy[0],提取边界框坐标和类别,发布成vision_msgs/Detection2DArray,不过图像话题足够满足可视化验证需求了。

3.5 正式连接相机前,先用资源里的测试图做静态回归

在把USB摄像头对准真实道路前,先用Zidane或Bus图验证权重是否正常。这是成本最低的验证手段。

# 在YOLOv5项目目录下执行,placeholder替换为实际权重路径 python detect.py --weights weights/best.pt --source zidane.jpg --conf 0.5

如果检测结果里至少能看到person,说明权重本身没有问题。接着再用tutorial.ipynb里的单元格跑一遍,对比输出框的坐标和置信度。这个步骤能排除掉一大半“模型压根没加载成功”的坑,让后续ROS联调更可控。

4. 避坑:行人和红绿灯识别在ROS部署里最容易翻车的六个点

4.1 三个环境类翻车点:话题接不上、Docker GPU没启用、摄像头映射丢失

现象一:节点启动后没有任何报错,但rqt_image_view里看不到检测结果,rostopic list里也没有期待的话题输出。

原因:订阅的图像话题和相机驱动节点发布的话题不一致。真实相机常是/camera/color/image_raw,而资源里默认写成/camera/rgb/image_raw,名字差一个单词,话题就完全接不上。

解决:先执行rostopic list | grep image查看实际话题名,再用rostopic hz /实际话题名确认帧率。确认无误后修改launch文件里的image_topic参数。我自己的习惯是每次启动前都强制扫一遍话题名,绝不凭记忆写。

现象二:容器里执行nvidia-smi失败,PyTorch检测到CUDA但推理时崩溃或回退到CPU。

原因:Docker容器缺少GPU运行时支持,或者宿主机没有安装nvidia-container-toolkit。

解决:宿主机先执行sudo apt install nvidia-container-toolkit,重启Docker,运行容器时追加--gpus all参数。如果还是没有GPU可用,就老老实实改代码用CPU推理,并把img_size降到480或320,至少让CPU跑得动。

现象三:加载usb_cam或运行摄像头节点时提示Failed to open /dev/video0或权限错误。

原因:容器没映射摄像头设备,或者当前用户不在video组里。

解决:先用ls /dev/video*确认设备是否存在。容器启动时加--device=/dev/video0,必要的时候把video0和video1成对映射。本地环境则执行sudo usermod -aG video $USER,重新登录后生效。这个坑在课程设计演示前出现概率极高,建议提前一天验证摄像头通路。

4.2 三个模型类翻车点:权重与类别错位、小目标漏检、ROS版本混用

现象四:节点能跑,但检测结果里完全找不到traffic light,或者类别ID全部混乱。

原因:自训练权重文件里包含的类别列表是被“烤”进权重的,如果权重只有两个类person和traffic_light,而代码还在读COCO的80类names,就会出现标签错位。

解决:在Python里加载权重后直接打印model.names,这个属性返回的是权重自带的类别列表。如果是自训练权重,确认你的类别索引顺序和训练数据一致。如果是预训练COCO权重,person的ID是0,traffic light的ID是9。这个基础信息能避免后面所有后处理逻辑跑偏。

现象五:行人检测基本没问题,但红绿灯漏检严重,尤其小尺寸红绿灯几乎每帧都丢。

原因:默认输入尺寸640对红绿灯这种十几像素的小目标不太友好。原图分辨率本身低,下采样后特征图上的有效信息只剩几个像素点。

解决:优先把img_size调高到1280,效果立竿见影,代价是推理帧率降到原来的三分之一。如果对帧率有要求,就先对图像上方区域做ROI裁切,只让模型检测车头前方的固定区域。资源里的注意力机制报告.md讨论的SE和CBAM注意力模块,就是针对这种小目标的改进方向,可以作为后续自训练的参考。

现象六:按照教程安装完ROS,用roslaunch启动时提示找不到rospy,或者launch文件解析报错。

原因:安装了ROS2环境,没有安装ROS1。ROS2用rclpy,launch格式也从XML变成了Python,两者完全不兼容。

解决:确认系统环境变量echo $ROS_DISTRO。如果输出的是humble或foxy,说明当前是ROS2。建议直接用Ubuntu 20.04的Docker镜像跑ROS1 Noetic,或者重装ROS1。很多这类资源长期没有升级ROS2版本,硬迁移成本不低,不如在ROS1环境里先把功能验证完。

5. 验证与进阶:从固定图回归到频率可控的端到端测试

5.1 用固定图片回归,给每次修改留后悔药

每次修改节点参数或者更换权重,都先跑一张资源里自带的测试图,记录下检测框的数量、类别和置信度。这个做法的价值在于:模型出了问题,你能第一时间判断是权重的问题,还是ROS链路的问题。两个通道分开排查,效率要高得多。

具体操作很简单,打开tutorial.ipynb,按单元格执行,把输出结果里的坐标和置信度记下来。以后谁改了代码、换了权重,跑完同一张图对一下数值,不对就是被改坏了。这在团队项目里尤其重要。

5.2 没有摄像头就先用模拟图像源,把话题链路跑通

很多课程设计里,硬件设备是答辩前才借到的。为了不把所有测试压在最后几天,可以写一个简单节点,循环发布固定图片。

#!/usr/bin/env python3 import rospy import cv2 from sensor_msgs.msg import Image from cv_bridge import CvBridge rospy.init_node('image_publisher') pub = rospy.Publisher('/camera/rgb/image_raw', Image, queue_size=10) bridge = CvBridge() img = cv2.imread('zidane.jpg') rate = rospy.Rate(10) while not rospy.is_shutdown(): msg = bridge.cv2_to_imgmsg(img, encoding='bgr8') msg.header.stamp = rospy.Time.now() pub.publish(msg) rate.sleep()

这是我在移植节点时惯用的方法。它能保证输入话题以固定10Hz发布,不受摄像头帧率波动影响,便于测量检测节点本身的吞吐能力。先用这种模拟源把整个链路跑通,再换真实摄像头,出问题时就能明确责任在节点还是硬件。

5.3 用话题频率衡量部署质量,别只看可视化效果

节点跑起来后,执行rostopic hz /yolo_detection/image,观察输出频率。输入10Hz,输出稳定在10Hz,说明节点性能合格。如果输出只有2Hz,说明推理耗时太长,图像积压严重。此时优先降低img_sizeiou_thres,其次检查模型是否误用了FP32而没有开启FP16。

我用这个套路调过一个项目,当时为了压低误检率,把置信度阈值降到0.2,结果红绿灯框全乱了,几乎每个路灯都在跳框。后来加了两个约束:检测框中心位置变化必须连续,且置信度低于阈值时直接丢弃。从那以后,我每次接到新的YOLOv5 ROS部署包,都会强制先走一遍“固定图回归、模拟源链路、话题频率测量”这三个动作,养成习惯后很少再被部署问题卡住。希望这套流程对你也有用。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询