简介:基于YOLOv5的ROS部署版行人与红绿灯识别完整方案,内含源码、预训练权重及说明文档,面向计算机、电子信息、数学等专业学生在课程设计、期末大作业或毕业设计中作为参考资料。压缩包共123个文件,以YAML配置、Python脚本、PT/PTH权重文件为主,其中YAML对应模型与数据集配置,Python脚本涵盖训练、推理及ROS节点封装,另含Dockerfile、Shell脚本、IPYNB交互式教程和Markdown说明文档,整体大小约83.87MB,便于快速部署与二次开发。目前已有1934人浏览学习,适合有一定代码基础、需要自行调试和扩展功能的读者参考。读者可获得完整的模型配置与权重、ROS部署示例、注意力机制相关报告及网络结构说明,能够帮助理解YOLOv5在交通场景识别中的应用流程,并在此基础上按需修改实现。压缩包目录结构清晰,便于按模块检索学习。
1. 用 YOLOv5 + ROS 部署版做行人和红绿灯识别,它到底替你省了哪些事
在无人小车、服务机器人和校园巡检项目里,“识别行人”和“识别红绿灯”是感知模块最常被要求的两件事。拿到这个“基于YOLOv5 ROS部署版实现行人和红绿灯识别(源码+权重+说明文档).rar”,你要做的不是从零写一个YOLO检测器,也不是自己去啃ROS通信和模型后处理之间的对接,而是把解压、编译、配参数、启动这几步走通,就能在ROS里以订阅图像、发布检测结果的方式拿到目标框。它适合刚入门机器人感知的开发者,也适合竞赛中需要快速迭代、不想在环境上耗时间的学生。但部署不等于万事大吉:先搞懂这个包背后的消息流和参数边界,才能真正把它跑在真车上。
2. 为什么是 YOLOv5 + ROS:感知节点的消息流与选型理由
2.1 把 YOLOv5 装进 ROS 的本质:图像话题进来,检测消息出去
如果只看“部署版”这三个字,很多人会误以为是把YOLOv5的代码塞进ROS里编译一遍就完事。实际上,ROS感知节点关心的不是模型内部有多少层,而是“图像数据从哪进来、检测结果从哪出去”。这个部署包的核心,就是解决这个输入输出闭环。
整体结构通常是一个独立节点或一组节点:订阅相机驱动发布的图像话题,通过cv_bridge把sensor_msgs/Image转成OpenCV的Mat,再送进YOLOv5的PyTorch模型做前向推理。推理得到的原始预测经过置信度过滤和NMS(非极大值抑制)处理,这一步就是常说的yolov5后处理。后处理完的目标框、类别、置信度会被封装成ROS消息发布出来,供下游的导航、避障或行为决策节点订阅。整个过程里,模型本身只是一个被调用的函数,真正的开发量在话题对接和消息转换上。
选型上,YOLOv5在ROS社区里最成熟。虽然现在YOLOv8、YOLOv9性能更好,但网上能直接编译、直接用、问题答案最多的还是v5系列。它的网络结构是CSPDarknet + PANet + Head,对新手来说,对照yolov5网络结构图能快速理解输入输出,部署版里也保留了修改网络结构的可能。换到v8当然可以做,但你在ROS里面临的Unknown module等问题会比v5多。所以如果这个包给你的是v5权重,不建议轻易换模型,先把链路跑通,再考虑升级。
另一个关键点是消息机制用的主题(/topic)。图像话题通常是/camera/image_raw,检测结果话题可以是/detected_objects或/yolov5/detections。这里容易踩坑的是话题名不一致:相机节点发布到A话题,检测节点却订阅B话题,结果就是节点看似都在运行,rostopic list一片繁荣,图像就是不出检测框。部署版的价值在于把所有话题名写死在config或launch文件里,你只需要按说明文档改相机驱动的话题名。
2.2 一个模型检测两类,还是两个模型分开跑:红绿灯识别的边界
YOLOv5用COCO预训练权重时,已经能检测person和traffic light两个类别。所以严格意义上,这个部署包如果默认加载COCO权重,你不需要重新训练就能识别行人和红绿灯。但你得区分“识别红绿灯”和“识别红灯/绿灯”。COCO的traffic light类别只告诉你“这是一个交通灯”,不告诉你灯当前亮的是什么颜色。
这就有了一条分界线:
| 需求 | COCO权重能否满足 | 建议方案 |
|---|---|---|
| 只要有行人框 + 红绿灯框 | 满足 | 直接用COCO权重,不用训练 |
| 需要区分红灯/绿灯/黄灯 | 不满足 | 在检测框内做颜色分类,或训练三/四类自己的数据集 |
| 只需要红灯停车 | 不满足 | 检测到traffic light后,用HSV提取亮灯区域颜色,判断是否为红色 |
我一般在做红绿灯状态时,不直接改YOLOv5的多类别输出,而是保持模型只检测灯的位置,在ROS节点里对检测框裁剪出来,转到HSV颜色空间做亮灯颜色判断。这样训权重时样本量小很多,也不影响行人检测精度。如果你的目标很明确就是要识别“红灯、绿灯”并把结果发给底盘,那就得按后面第4章说的去训练自己的数据集,把类别换掉。这个边界在部署版说明文档里通常会写,但很多新手没仔细看,最后拿着COCO权重说“它检测不出红灯”,其实是需求没对齐。
3. 跑通最小系统:从 ROS 环境到 YOLOv5 节点发布检测结果
3.1 装 ROS 环境:包里的说明文档默认你用的是 ROS Noetic
部署版通常默认Ubuntu 20.04 + ROS Noetic(也可用Ubuntu 22.04 + ROS Humble,但需要确认cv_bridge是否兼容)。如果你还在为ROS安装头疼,用鱼香ROS一键安装脚本是最快的方式:按脚本菜单选“ros-noetic-desktop”或“ros1-install”,它会自动配置源和依赖,不必手动折腾apt源。我在新机器上装Noetic,从执行脚本到能跑roscore,大概10分钟。
如果你不想用第三方脚本,标准做法是:
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' sudo apt install curl curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add - sudo apt update sudo apt install ros-noetic-desktop sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential sudo rosdep init rosdep update echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc source ~/.bashrc逻辑说明:这段命令先添加ROS软件源,再把ROS的OpenPGP密钥装进去,接着安装desktop版(自带相机驱动、rviz、tf等基础工具),rosdep解决后续编译时的依赖查找。注意rosdep init只需要成功率,如果网络不稳,可以加代理,但那是题外话。
参数说明:ros-noetic-desktop是常用版本,资源占用比desktop-full少;如果你要用Gazebo仿真,需要替换成ros-noetic-desktop-full。另一个易错点是编译源码包时,系统里同时存在Python2和Python3,ROS Noetic只支持Python3,所以后续编译节点必须用python3的catkin接口。
3.2 解压部署包并编译 ROS 节点:catkin 工作空间的三个步骤
拿到这个rar,第一步不是点开源码,而是先看说明文档。说明文档会写明依赖版本,比如“需要OpenCV 4.2、torch 1.8、numpy 1.19”。把这些版本装好,再解压编译。
sudo apt install unar # Ubuntu解压rar的工具 mkdir -p ~/yolo_ws/src cd ~/yolo_ws/src unar ~/下载/基于YOLOv5ROS部署版实现行人和红绿灯识别(源码+权重+说明文档).rar # 解压后通常出现一个 src 目录,把里面的功能包放到 src 下 cd ~/yolo_ws catkin_make -DPYTHON_EXECUTABLE=$(which python3)逻辑说明:catkin_make把工作空间里的ROS功能包编译成可执行文件和消息生成代码。指定PYTHON_EXECUTABLE是为了避免系统里Python路径不对导致cv_bridge链接到Python2。
参数说明:如果编译过程中报“找不到cv_bridge”,说明你没有安装ros-noetic-cv-bridge,用sudo apt install ros-noetic-cv-bridge补上再重新catkin_make。如果报“no module named torch”,需要在系统Python3里装一遍PyTorch,不要装在conda里,否则节点起来时加载不到。
3.3 打开相机并启动检测节点:你最关心的第一帧输出
环境就绪后,先单独确认相机能出图。USB摄像头最常用的是usb_cam包:
roslaunch usb_cam usb_cam-test.launch # 另开终端 rosrun rqt_image_view rqt_image_view /usb_cam/image_raw如果能看到画面,说明摄像头话题已经发布。我用roslaunch启动usb_cam时,常用/usb_cam/image_raw;如果用的是自带驱动或海康相机,话题名可能是/camera/image_raw,需要按实际情况改后续节点的话题参数。
接着启动部署包里的YOLOv5检测节点:
source ~/yolo_ws/devel/setup.bash roslaunch yolov5_ros detect.launch image_topic:=/usb_cam/image_raw conf_thres:=0.35 iou_thres:=0.45逻辑说明:image_topic告诉节点订阅哪个图像话题;conf_thres是置信度阈值,低于它的框会被丢弃;iou_thres是NMS阶段的重叠框合并阈值。这里的关键是话题名必须和相机驱动一致,启动后看终端是否打印“Subscribed: /usb_cam/image_raw”。
参数说明:在室内行人场景,conf_thres=0.35通常能兼顾误检和漏检;如果检测框抖动厉害,把conf提高到0.5;如果红绿灯较远偏小,conf低于0.3容易漏检。这些参数在launch文件里就是一行<arg name="conf_thres" default="0.35"/>,改起来很方便。
如果源码包里没给launch,只给了python脚本,核心推理回调是这样的:
#!/usr/bin/env python3 import rospy, cv2, torch from sensor_msgs.msg import Image from cv_bridge import CvBridge class YoloNode: def __init__(self): self.model = torch.hub.load('/path/to/yolov5', 'custom', path='/path/to/best.pt', source='local') self.model.conf = 0.35 # 置信度阈值,可动态调整 self.model.iou = 0.45 # NMS IoU阈值 self.bridge = CvBridge() rospy.Subscriber('/image_raw', Image, self.callback) rospy.init_node('yolov5_node') def callback(self, msg): frame = self.bridge.imgmsg_to_cv2(msg, 'bgr8') # 转OpenCV图像 result = self.model(frame) # 推理 result.render() # 把框画到图 self.publisher.publish(self.bridge.cv2_to_imgmsg(result.ims[0], 'bgr8')) if __name__ == '__main__': YoloNode() rospy.spin()逻辑说明:torch.hub.load的source='local'表示从本地加载YOLOv5源码目录,而不是从GitHub拉取,这在离线机器上是关键。模型加载后,ROS回调收到图像转成BGR,推理、画框,再把结果图发布出去。这个代码里没有定义publisher,真实部署版还会发布一帧检测结果消息,供下游读取。
参数说明:path='/path/to/best.pt'要指向部署包提供的权重文件;如果你用COCO官方权重,best.pt换成yolov5s.pt。回调里必须用bgr8,不要用rgb8,否则颜色通道反转,模型准确率会肉眼可见地下降。这也是后处理里最憋屈的坑之一。
4. 参数怎么调:让模型在真实路口和行人场景里不瞎报
4.1 推理参数:conf、iou、img_size 的取舍
部署包能跑通和能真正用起来之间,隔着3个核心参数。很多新手拿着默认的conf=0.25,结果在校园路上把树干都识别成行人,回来骂模型不行。其实是参数没量过场景。
| 参数 | 默认值 | 作用 | 实际调整建议 |
|---|---|---|---|
| conf_thres | 0.25 | 低于此置信度的所有框被丢弃 | 行人0.35~0.5,红绿灯0.2~0.3 |
| iou_thres | 0.45 | NMS时与高置信度框重叠超过此IoU的被抑制 | 密集人群0.3,稀疏场景0.5 |
| img_size | 640 | 推理分辨率,越大越能发现小目标但越慢 | 小目标灯珠640或800;只测行人640 |
为什么红绿灯的conf要放低?因为交通灯在图像里可能只有20×20像素,特征弱,模型给出0.28的置信度在城市路况里已经很可信。但低conf会带入更多误检,所以我会在检测节点里加一个“动态conf”:画面中同时出现行人框和远处的小目标时,对小目标降低conf,而不是整体降低。
img_size的影响最直接:从640提到800,小目标召回率能提高10%左右,但推理时间可能从30ms涨到50ms。如果你的底盘规划节点需要10Hz的结果,640是稳妥选择。我一般不做全局改img_size,而是在图像进模型之前,用ROI把红绿灯区域裁剪放大,这样帧率不跌太多,小目标也能认出来。
4.2 训练自己的数据集:让红绿灯状态识别成为可能
如果你确认要用这个部署包做红灯/绿灯识别,又不想依赖颜色判断,那就要train一个自己的YOLOv5模型。部署包里通常带有训练好的COCO权重,但COCO没有“red_light/green_light”类别。你需要用LabelImg或CVAT标注图像,类别设为person, red_light, green_light, yellow_light。
标好数据集后,训练最小命令:
cd /path/to/yolov5 pip install -r requirements.txt python train.py --data data/my_light.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --cache其中my_light.yaml是你自己的数据配置:
train: /path/to/train/images val: /path/to/val/images nc: 4 names: ['person', 'red_light', 'green_light', 'yellow_light']逻辑说明:train.py会按yaml里的路径读图,nc必须和names数量一致。--weights yolov5s.pt是预训练权重,能让小数据集收敛更快。--cache把图像预加载到内存,省去每次epoch读盘的时间。
参数说明:batch 16在6GB显存显卡上比较安全;显存不够就降到8,同时把--workers降到0或2,否则Dataloader容易崩。epochs我一般先跑100,如果val精度还在涨就加50。训练完后在runs/train/exp/weights/下会得到best.pt,把YOLOv5节点的权重路径指到它:
roslaunch yolov5_ros detect.launch model_path:=/path/to/best.pt conf_thres:=0.3这里的yolov5超参数,比如mosaic增强、HSV扰动,默认就行,不需要动。真正要动的是--img:如果红绿灯小目标多,建议训练时用--img 800,推理时也保持800,避免训练和推理分辨率不一致导致精度损失。
4.3 发布检测结果给下游:话题频率和坐标系才是能不能用的关键
行人和红绿灯识别最终是为了给底盘节点用。检测节点不光要发一个可视化图像,还要发结构化消息:目标框、类别、置信度、检测时间戳。如果底盘节点要控制速度,它关心的是“前方5米有没有行人”,而不是图像里一帧框在哪个像素。
常见的做法是定义自定义消息:
std_msgs/Header header string[] class_names float32[] confidences int32[] x_min int32[] y_min int32[] x_max int32[] y_max然后在launch里设置发布队列长度:
<param name="pub_queue_size" value="2"/>参数说明:pub_queue_size=2表示只保留最新两帧,避免订阅方处理太慢导致消息堆积到内存里占满CPU。如果你用rostopic echo /detected_objects能看到一个接一个的消息,但帧率波动大,说明下游处理一次的时间超过了推理周期。这时候需要做多机通信配置?不,先把车上的话题频率确认好。
用rostopic hz /ubi_ros_node/detections可以看发布频率。如果理想是10Hz,实际只有3Hz,首先排查推理回调里是否用了time.sleep或者把可视化图也发布出去了。发布可视化图非常耗带宽,我通常只在调试模式开启。
5. 避坑:YOLOv5 + ROS 部署最常见的 5 个坑
坑1:cv_bridge 编译报错,OpenCV版本冲突
现象:catkin_make时出现Could not find a package configuration file provided by "cv_bridge",或者编译完成后运行时提示libopencv_core.so.3.4: cannot open shared object file。
原因:系统里同时装有OpenCV 3.4和4.x,ROS Noetic默认用OpenCV 4,而YOLOv5依赖的torch或opencv-python可能是3.4版本,导致cv_bridge编译时链接到了错误的库。
解决:先用python3 -c "import cv2; print(cv2.__version__)"确认Python里的OpenCV版本。如果不对,统一用sudo apt install ros-noetic-cv-bridge的版本,并把无关OpenCV路径从LD_LIBRARY_PATH里删除。我一般在部署节点前,先单独编译一个最小cv_bridge示例,确认能转图像,再跑YOLO。
坑2:相机话题没数据,rostopic list 里却能看到节点
现象:roslaunch usb_cam后,rostopic hz /usb_cam/image_raw显示0,但rosnode list里有节点。
原因:usb_cam驱动没拿到摄像头权限,或摄像头被其他进程占用。权限问题最常见的是没有把用户加入video组。
解决:执行sudo usermod -aG video $USER,注销重登。如果还是没数据,用lsusb和v4l2-ctl --list-formats看设备被认成什么格式,把usb_cam的pixel_format改成yuyv或mjpeg。在虚拟机上跑,这个问题更常见,摄像头会被VMware拦截,此时用ros打开电脑自带摄像头反而容易在物理机上成功。
坑3:模型权重路径写错,节点启动就退出
现象:roslaunch后终端报FileNotFoundError: [Errno 2] No such file or directory: 'yolov5s.pt'。
原因:launch文件里的权重路径是相对路径,而launch的当前工作目录不定。ROS节点运行时不会自动定位到源码包目录。
解决:在launch里写绝对路径,或通过rospack find yolov5_ros动态拼接路径。我倾向在launch中写:
<param name="model_path" value="$(find yolov5_ros)/weights/best.pt"/>表示从功能包根目录找weights/best.pt,这样不管从哪cal启动都有效。
坑4:CPU推理一张图要1秒多,ROS控制完全跟不上
现象:在普通笔记本CPU上跑YOLOv5s,rostopic hz /detections显示0.6Hz,底盘控制节点频繁超时。
原因:没有GPU或没有用TensorRT加速。YOLOv5s在CPU上运行,640分辨率单张推理要0.5~1秒,还没算预处理和后处理。
解决:如果机器是jetson orin或树莓派5,建议用TensorRT或ONNX Runtime做推理,不要直接跑PyTorch。先导出ONNX,再用trtexec转engine,节点改为用onnxruntime调用。CPU机器上还有一个临时方案:把img_size降到416,conf调高到0.5,能到2Hz左右,但只适合功能验证,不适合真车。真正要上小车,预算允许就上jetson orin,这个部署包在orin上用TensorRT能到15~20Hz。
坑5:与底盘节点衔接时坐标错乱
现象:检测到“前方有行人”,但底盘转向时把行人当成障碍物绕开了,方向完全不对。
原因:检测框是2D图像坐标,而底盘需要的是基于深度相机或激光测距的3D位置。直接拿框中心去算角度,忽略了镜头畸变和安装位置。
解决:先用相机内参标定,再在节点里把x_mm、y_mm、depth发出去。如果只有单目,就至少用检测框底部中心点作为地面投影,并设定一个固定距离区间,而不是直接接话题。这一步虽然不是YOLOv5的问题,但往往会让整个项目翻车。我先在rviz里叠加图像和激光点云,确认检测框对应的实际物体大致在哪个方位,再交给底盘节点。
6. 从“识别出来”到“能用来导航”:先录包验证,再上真车
6.1 用 rosbag 离线回放,省下反复启动相机的时间
第一次拿到这个部署包运行时,我不建议直接对着真实路测。因为我经历过一次在室内测没问题、到室外红绿灯就检测不到的情况。正确的做法是先录一段包含行人、红绿灯的rosbag,然后离线跑检测节点:
rosbag record /camera/image_raw -O traffic_light_scene.bag # 录3分钟后 rosbag play traffic_light_scene.bag -r 1.0 roslaunch yolov5_ros detect.launch image_topic:=/camera/image_raw代码块说明:record保存原始图像话题,play按原速度回放。离线跑的意义在于你能反复调参数而不需要别人在路口配合。我还会把检测结果话题一并录进bag,用rqt或rviz对比每一帧检测框和真实场景。这样在车上实测之前,就知道conf阈值和img_size是否适合这个场景。
6.2 把检测结果接入底盘前,先检查这两个质量指标
- 检测频率:至少5Hz,稳定到8Hz以上才适合让底盘决策。低于5Hz,障碍物到了面前才更新,很容易撞上。
- 漏检率:在bag里统计“有行人的前50帧,模型检出多少帧”。漏检一帧可能意味着一次急刹车,所以宁可把conf调低一点接受少量误检,也不追求过高精度。
我见过不少人把时间花在调模型精度上,却忽略了ROS消息延迟。实际上检测节点发布消息到底盘订阅,中间可能经过了不止一个节点,一旦漂移,底盘拿到数据时物体已经移动了。所以我会在rviz里同时显示图像、检测框和机器人位置,确认这三个坐标系的时间戳是否接近。如果差了200ms以上,就得检查是否某个环节用了不同的时间源。
最后的习惯是:每次改参数都先记录,因为部署包的说明文档只写了参数名,没写适合你场景的值。红绿灯识别这个方向,关键不是让模型表现出多么惊艳的精度,而是让它在固定安装位置、固定相机的条件下,稳定输出。我自己的第一次真车测试就吃过没验证频率的亏,差点让小车轮打滑撞到路沿。后来老老实实先录bag再上真车,再没出过这种事。希望帮到你。
本文还有配套的精品资源,点击获取