ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

YOLOv5 ROS部署实战:实现行人与红绿灯实时识别

2026/9/28 16:10:58 拓冰建站 浏览量
YOLOv5 ROS部署实战:实现行人与红绿灯实时识别 简介基于YOLOv5 ROS部署版实现行人和红绿灯识别的完整资料包面向计算机、电子信息工程、数学等专业学生可作为课程设计、期末大作业或毕业设计的技术参考。资源包总大小约83.87MB共123个文件除核心的38个Python源码脚本外还有48个YAML配置文件用于参数与环境设置并提供pt、pth预训练权重以及shell启动脚本、Dockerfile部署文件、Markdown说明文档、Jupyter notebook教程等覆盖从模型加载、推理部署到结果解读的主要环节。借助源码、权重和说明文档可在ROS环境下快速搭建行人检测与红绿灯识别测试原型理解目标检测模型的实际部署流程说明文档中的目录与模块划分有助于按需查阅和二次扩展。目前已有1933人学习下载。适合具备一定编程和ROS基础、需要自行调试和修改功能的开发者作为毕业设计或课程项目的可靠参考资料。1. 拿到YOLOv5 ROS部署版别急着解压先搞清楚这套东西到底解决什么问题做过机器人或自动驾驶感知的朋友应该都有这种经历模型在PC上跑得飞快一搬进ROS就各种别扭——话题对不上、图像格式不对、推理延迟高、节点一启动就崩。这个「基于YOLOv5 ROS部署版实现行人和红绿灯识别」的包本质就是把YOLOv5的推理能力封装成ROS节点订阅相机图像话题实时输出行人和红绿灯的检测框与坐标供导航、避障或控制模块使用。它解决的不是“怎么训练模型”而是“训练好的权重如何稳妥地跑进ROS生态”。适合正在做ROS小车、巡检机器人、或者刚入门视觉感知部署的工程师。这里必须提醒一句拿到包先看两个地方——权重文件对应几个类别、推理节点订阅什么话题。不看这两点就盲目跑大概率会翻车。2. 部署前的三板斧权重选型、环境配置与工作空间搭建2.1 权重文件先分清一个权重对应一类检测任务网上下载的部署包里weights目录下通常会混着几种pt文件命名也五花八门yolov5s.pt、best.pt、last.pt、yolov5s_custom.pt。它们的含义完全不同用错就是灾难。yolov5s.pt、yolov5m.pt这类是官方在COCO 80类上预训练出来的通用权重。用它们直接跑行人检测还行COCO里有person类但红绿灯traffic light虽然也在COCO里却经常被漏检。原因后面避坑章节细说。如果你手上的包是用这种预训练权重做推理那说明作者没做迁移训练识别效果会打折扣。best.pt和last.pt是训练过程产生的两类产物best是验证集上效果最好的一版last是训练最后一步的存档。部署时优先选best.pt它对应的精度最高。但要注意best.pt的类别数由训练时的data yaml决定——如果是“行人红绿灯”两类的自定义数据集模型输出维度就是nc2加载到默认的YOLOv5源码里会直接报错或者输出80类垃圾结果。我个人习惯拿到包先跑一条命令确认权重类别数python -c import torch ckpt torch.load(weights/best.pt, map_locationcpu) model ckpt[model].float() print(类别数 nc , model.model[-1].nc) print(类别名 , model.names) 这条命令输出权重文件里实际的类别数量和类别名。注意看两个点一是nc是否为2二是names是否从你预想的顺序排列比如{0: person, 1: traffic_light}。如果权重是COCO预训练版本names会是80类长列表那就别指望它能把红绿灯当回事。确认完类别再进下一步能省后面一小时的排查时间。2.2 用conda把Python环境和ROS系统环境隔离开ROS Noetic用的是Python 3.8Ubuntu 20.04系统自带Python 3.8看起来兼容但YOLOv5对PyTorch版本有要求而系统Python环境里往往已经装了一堆ROS依赖包pip install很容易把系统环境搞乱。最常见的翻车现场是装完torch后ROS的rospy突然导入失败因为site-packages里的依赖被pip覆盖了。我推荐用conda单独建一个推理环境ROS只作为消息通信层依赖模型推理跑在独立Python环境里两者通过ROS话题解耦。环境创建命令大致如下conda create -n yolov5_ros python3.8 conda activate yolov5_ros pip install torch1.9.0cu111 torchvision0.10.0cu111 -f https://download.pytorch.org/whl/torch_stable.html pip install -r requirements.txt # YOLOv5源码里的依赖 pip install rospkg这里有个坑conda环境里直接用pip install rospkg只是装了Python API的包管理器但真正的rospy还需要ROS系统环境变量支持。所以每次运行前要source ROS的setup.bash。我一般把环境激活和ROS环境引入写成一个脚本避免每次手敲#!/bin/bash source /opt/ros/noetic/setup.bash conda activate yolov5_ros roslaunch yolov5_ros_detect detect.launch如果不想用conda也可以用python3 -m venv但要注意虚拟环境的Python解释器版本必须和编译ROS消息时的版本一致否则自定义消息导入会报“No module named xxx.msg”。conda在这块兼容性好一点因为很多ROS的Python包依赖libpythonconda环境管理动态库更干净。环境配好后用python -c import rospy; import torch同时验证两个关键库能否共存。ROS环境变量污染是另一个常见问题。conda环境的PYTHONPATH如果指向了ROS的dist-packages会导致import到旧版的cv_bridge或sensor_msgs。建议在启动脚本里显式清掉或覆盖PYTHONPATHexport PYTHONPATH/opt/ros/noetic/lib/python3/dist-packages:$PYTHONPATH顺序很重要ros的路径必须在最前面不然YOLOv5源码里依赖的某些包会撞车。2.3 ROS工作空间怎么建、包怎么放拿到源码包时常见做法是里面直接给了catkin工作空间也就是src/目录下放着功能包比如yolov5_ros_detect。如果包没有这个结构需要自己重建。一个标准的ROS Noetic工作空间结构是这样的catkin_ws/ ├── src/ │ ├── yolov5_ros_detect/ │ │ ├── CMakeLists.txt │ │ ├── package.xml │ │ ├── launch/ │ │ │ └── detect.launch │ │ ├── scripts/ │ │ │ └── detect_node.py │ │ ├── weights/ │ │ │ └── best.pt │ │ └── config/ │ │ └── params.yaml │ └── usb_cam/ # 或者别的相机驱动包 ├── devel/ └── build/工作空间初始化命令mkdir -p catkin_ws/src cd catkin_ws catkin_make source devel/setup.bash如果你用的是Python写的ROS节点不需要编译只要把scripts目录下的脚本加上可执行权限然后在CMakeLists.txt里加上catkin_install_python就够。这里有个新手容易踩的坑catkin_make后忘记source devel/setup.bash直接roslaunch会提示找不到包。更麻烦的是开多个终端时每个终端都要重新source我一般会在~/.bashrc里加一行省得反复折腾。catkin_make和catkin buildcatkin_tools的区别一句话说前者简单直接够用后者支持并行编译和隔离环境。对这个部署项目catkin_make完全够不要为了花哨换构建工具尤其是在Ubuntu 20.04上rosdep install的依赖解析并不会因为你换工具就变顺。最后的检查项是rosdep。新拉下来的工作空间缺少依赖时常见的报错是rospkg.common.ResourceNotFound: usb_cam。执行cd catkin_ws rosdep install --from-paths src --ignore-src -r -y这条命令会读取各包的package.xml把缺失的系统依赖装齐。网络抽风时它可能装一半卡住重跑一次通常能续上。装完之后用rospack find yolov5_ros_detect确认包被正确索引到——输出包路径而不报错说明工作空间这块已经就绪了。3. 把模型接进ROS节点设计、话题与消息类型3.1 单节点还是双节点推理速度与耦合度怎么权衡YOLOv5推理接入ROS有两种经典方案。方案A是写一个独立推理节点订阅上游相机话题比如/usb_cam/image_raw识别后发布检测结果话题。方案B是把相机驱动、推理、结果显示全部塞进一个节点启动一个launch全部搞定。方案B的好处是部署简单、调试方便——你不用先启动相机再启动识别一个launch全自动。坏处是耦合太紧相机节点崩了推理也没了而且后续想把识别节点单独换掉就要动整个包。方案A更符合ROS的哲学节点间通过话题解耦相机可以是usb_cam、可以是rosbag回放、也可以是仿真器输出推理节点完全可以无感知地切换数据源。一旦遇到实际部署环境你会发现方案A省心得多。我推荐的做法是相机走独立节点YOLOv5推理单独一个节点可视化或控制模块再挂一个接收端。在包结构里体现为三个launch文件camera.launch、detect.launch、view.launch运行时分三个终端分别启动排查问题的时候逐个定位不用整个链路推倒重来。3.2 sensor_msgs::Image和CompressedImage的选择ROS图像消息最常用的是sensor_msgs/Image它是一帧未压缩的原始图像数据包含高度、宽度、编码方式如rgb8或bgr8和数据数组。usb_cam默认发布这种类型。它的优点是无需解码直接可用缺点是数据量大——1080p的BGR图像一帧约6MB如果话题带宽受限或传输延迟大就得上CompressedImage。CompressedImage是JPEG压缩后的消息数据量小一个数量级但接收端需要cv2.imdecode解码解码耗时约5到10毫秒对检测整体延迟影响可接受。问题是很多玩ROS的新手习惯直接订阅Image话题一换CompressedImage就发现拿到的数据格式不对需要判断format字段再做解码。我的建议是本机运行且USB相机直连用Image省解码时间。跨机器传输、使用无线或网络摄像头用CompressedImage。跑rosbag离线数据按bag里记录的话题类型选择不要改代码硬适配写一个参数image_topic和image_compressed控制订阅既灵活又不用改两套代码。3.3 检测结果用自定义消息还是直接画框这是另一个容易被低估的设计点。很多示例代码把识别框直接画在图像上发布DetectionImage话题人眼看着效果很直观——框是画出来了控制节点却拿不到框的坐标信息。如果你只想做可视化验证画框发布就够了。但如果后续要做避障、导航、红绿灯状态判断就必须把每个目标的位置、类别、置信度结构化地发出去。我一般同时做两件事一是发布画框后的图像话题用于可视化二是发布一个自定义消息用于控制逻辑。自定义消息定义在包的msg目录下比如# BoundingBox.msg string class_name float32 confidence int32 xmin int32 ymin int32 xmax int32 ymax再用一个数组消息把它们聚合起来# DetectionResult.msg std_msgs/Header header BoundingBox[] boxes定义消息文件后需要在CMakeLists.txt里加add_message_files和generate_messages配置然后catkin_make编译生成Python消息类。编译完就可以在节点里通过from yolov5_ros_detect.msg import DetectionResult引用。这个设计比直接画框发布多十分钟工作量但换来的是下游节点可以同时订阅图像话题和控制信号互不干扰。如果包本身没带自定义消息我自己补上也会顺手把话题名统一写在params.yaml里不写死在代码中。4. 在ROS中跑通YOLOv5推理从加载权重到输出检测框4.1 一个最小推理节点代码下面这段代码是推理节点的核心骨架。它订阅ROS图像话题把图像转成OpenCV格式送入YOLOv5模型推理然后把检测结果画框并发布画框图像话题同时发布自定义消息。代码可直接保存到scripts/detect_node.py#!/usr/bin/env python3 import cv2 import torch import rospy import numpy as np from sensor_msgs.msg import Image from cv_bridge import CvBridge from std_msgs.msg import Header from yolov5_ros_detect.msg import BoundingBox, DetectionResult class YoloDetector: def __init__(self): rospy.init_node(yolov5_detect_node, anonymousTrue) self.device rospy.get_param(~device, cuda) self.conf_thres rospy.get_param(~conf_thres, 0.45) self.iou_thres rospy.get_param(~iou_thres, 0.45) self.img_size rospy.get_param(~img_size, 640) # 加载权重模型从weights目录读取 weights_path rospy.get_param(~weights_path, weights/best.pt) self.model torch.hub.load(ultralytics/yolov5, custom, pathweights_path, force_reloadFalse) self.model.to(self.device).eval() self.bridge CvBridge() self.image_sub rospy.Subscriber(/usb_cam/image_raw, Image, self.image_callback, queue_size1) self.result_pub rospy.Publisher(/detection/result, DetectionResult, queue_size10) self.vis_pub rospy.Publisher(/detection/image, Image, queue_size10) def image_callback(self, msg): try: frame self.bridge.imgmsg_to_cv2(msg, desired_encodingbgr8) except Exception as e: rospy.logerr(图像转换失败: %s, e) return # 推理 results self.model(frame, sizeself.img_size) dets results.xyxy[0].cpu().numpy() # 发布画框图 annotated results.render()[0] vis_msg self.bridge.cv2_to_imgmsg(annotated, encodingbgr8) self.vis_pub.publish(vis_msg) # 组装结构化结果 result_msg DetectionResult() result_msg.header Header(stamprospy.Time.now(), frame_idmsg.header.frame_id) for det in dets: x1, y1, x2, y2, conf, cls det box BoundingBox() box.class_name self.model.names[int(cls)] box.confidence float(conf) box.xmin int(x1); box.ymin int(y1) box.xmax int(x2); box.ymax int(y2) result_msg.boxes.append(box) self.result_pub.publish(result_msg) if __name__ __main__: detector YoloDetector() rospy.spin()代码逻辑不复杂四个关键点要说明。图片从ROS消息转到cv2格式这一步用cv_bridge不能直接用msg.data拼接因为ROS的Image消息数据排列方式和OpenCV的ndarray不完全一致尤其是存在行对齐字节时。推理用torch.hub加载YOLOv5这个方式会把YOLOv5源码从GitHub拉到~/.cache里第一次运行时如果网络不稳定会失败。更稳妥的替代方案是从包内直接import YOLOv5源码的models模块路径写死到包的scripts目录下一层。conf_thres和iou_thres是YOLOv5超参数里最该动手调的两个值。conf_thres过滤低置信度框行人场景建议0.35到0.45之间设低了会出现大量误检框设高了小目标和远处目标会被滤掉。iou_thres控制重叠框合并行人密集场景建议0.45红绿灯这种小目标可降到0.35避免同一目标拆成两框。这些参数在launch文件里通过rosparam传入不用改代码是后期调参最省力的出口。queue_size1这个细节常被忽略。订阅图像话题时queue_size设得过大比如10如果相机帧率高于推理速度ROS会开始堆积旧图像节点拿到的永远是几秒前的图像延迟越积越高。设成1表示只保留最新一帧推理速度跟不上时直接丢掉旧帧保证实时性。这个取舍对导航避障类应用至关重要。4.2 launch文件怎么组织参数launch文件的作用是把上一节的节点和参数包起来一行命令启动。下面给出完整可用的launch配置launch arg namedevice defaultcuda/ arg nameweights_path default$(find yolov5_ros_detect)/weights/best.pt/ arg nameimage_topic default/usb_cam/image_raw/ arg nameconf_thres default0.45/ arg nameiou_thres default0.45/ node nameyolov5_detect_node pkgyolov5_ros_detect typedetect_node.py outputscreen param namedevice value$(arg device)/ param nameweights_path value$(arg weights_path)/ param nameconf_thres value$(arg conf_thres)/ param nameiou_thres value$(arg iou_thres)/ param nameimg_size value640/ remap from/usb_cam/image_raw to$(arg image_topic)/ /node /launchlaunch里的remap字段很关键。它的作用是把代码里写死的订阅话题名/usb_cam/image_raw重映射到实际图像来源。如果你用的是usb_cam、ROS仿真或别人的相机驱动话题名可能不同直接在命令行传参即可不用改代码。这种设计在一线部署时特别管用——今天在测试机上跑usb_cam明天搬到实车上换工业相机改一个launch参数就完事。权重路径也不要写相对路径。因为ROS节点的当前工作目录通常是~相对路径weights/best.pt会找不到文件。用$(find yolov5_ros_detect)/weights/best.pt能定位到包的真实目录这是ROS的标准做法既移植性好又避免“明明文件在却加载不过”的尴尬。如果你拿到手的包是不同构建方式比如没有catkin包结构也可以直接用rosrun python脚本的方式启动但launch的方式更标准化也更方便一次调整多个参数。run之后rosparam list能查看所有已设参数rosparam get /yolov5_detect_node/conf_thres能确认实际值排查问题时这是第一道检查。4.3 可视化验证用rqt_image_view确认检测效果节点启动后光看终端日志不足以判断检测效果。ROS自带的可视化工具rqt_image_view能直接订阅图像话题显示实时画面rqt_image_view /detection/image打开以后你应该能看到视频流框和标签叠在目标上。如果画面卡顿或者没有图像先确认相机的原始话题有没有输出rostopic hz /usb_cam/image_rawrostopic hz输出的是话题发布频率。usb_cam默认30fps左右如果频率为0说明相机驱动没起来或权限不对。挂在虚拟机USB口上时常见的报错是libusb: device not found需要把用户加进video组命令是sudo usermod -a -G video $USER然后注销重登。可视化正常了再验证结构化消息。用一个命令行工具快速查看rostopic echo /detection/result能看到每帧的boxes数组里面有class_name、confidence、坐标。这一步确认的是发布端和接收端协议对齐是后续接控制逻辑前的必要检查。rostopic echo的输出量比较大CtrlC后可以改用rostopic echo --noarr /detection/result只显示header避免刷屏。如果可视化界面什么都显示不出来检查话题名是否一致——这是最简单但也是最高频的翻车原因节点发布的是a话题可视化订阅的是b话题各跑各的谁也看不见谁。5. 部署避坑清单行人与红绿灯场景下的常见问题排查5.1 现象模型检测行人很稳但红绿灯频繁漏检这是这个项目里最让人头疼的问题。现象是行人的框又准又稳红绿灯时有时无尤其远处的小灯几乎全漏。原因在于红绿灯目标在图像中占比非常小而YOLOv5默认的输入尺寸是640x640小目标经过多次下采样后特征图上的像素可能只剩几个点特征信息丢失严重。加上训练数据里红绿灯样本如果不足模型对该类别的特征表达天然偏弱。解决思路有三个层次。最直接的是把推理输入尺寸从640提到960或1280img_size调大后小目标在特征图上的尺寸也线性放大漏检率明显下降代价是推理耗时增加。第二个是单独训练一个红绿灯专用模型输入尺寸1280专门负责红绿灯检测两个模型并联运行再融合结果。第三个是检查训练数据本身红绿灯样本量如果少于行人样本的十分之一先做数据增强——对红绿灯区域随机裁剪放大、亮度扰动、翻转凑够样本量再重新训练。实际部署时我倾向于先调img_size和conf_thres成本最低收益最明显还是漏就上双模型。5.2 现象ROS节点启动后图像话题反复中断现象是rqt_image_view画面每隔十几秒卡住一次终端输出Transport endpoint has already been connected或订阅回调停止触发。原因通常是订阅者处理速度跟不上发布者ROS的TCP通信缓冲区溢出连接被重置。另外usb_cam驱动在某些USB控制下有丢帧问题也会让话题出现间隙性中断。解决从两端下手。先提高节点处理速度把queue_size调小、减少画框以外的多余拷贝。再把相机驱动端的像素格式设为YUYV而不是MJPG有些USB摄像头MJPG格式需硬件解码在树莓派或工控机上CPU解不过来。如果换设备更麻烦还有一个兜底手段写一个python脚本把原始图像话题重新发布成降采样后的版本分辨率减半但帧率稳定。降采样损失一点检测精度总比话题断开强。排查次序建议先看rostopic hz确认话题源头是否稳定再检查推理节点的CPU占用最后考虑网络传输。5.3 现象GPU显存充足但推理速度只有个位数帧率现象是nvidia-smi显示显存占用正常但YOLOv5推理fps只有3到5低于预期的25到30。这个问题在不少人自己配环境时常遇到。原因基本是这几类模型参数加载到了GPU但推理时没有放在torch.no_grad()上下文里导致梯度计算白白浪费显存和算力或者代码里每次推理都重新执行torch.hub.load加载权重模型重复载入也可能是输入图像resize操作在CPU上执行成了性能瓶颈。解决方法是推理前显式包装with torch.no_grad(): results self.model(frame, sizeself.img_size)再检查模型确实在CUDA上self.model.device输出应为cuda。然后图像resize用GPU张量操作或预先分配固定尺寸。还有一个容易被忽视的点YOLOv5默认做letterbox填充时是同步的CPU操作改成在GPU上一次性生成预处理张量能省3到5毫秒。如果设备支持TensorRT直接把模型转成engine格式跑帧率翻倍甚至更多是正常的。排查顺序先看fps和CPU占用如果CPU单核跑满说明预处理在CPU上再用nvidia-smi看GPU利用率利用率低就查数据管道。5.4 现象自定义训练权重加载到部署包时报形状不匹配现象是节点一启动就报Error(s) in loading state_dict for Detect: size mismatch for m.0.weight或者跑起来全输出一类目标、类别名乱跳。原因在权重文件和模型结构的类别数不一致常见于拿自定义两类权重加载到默认80类模型结构里或反过来。YOLOv5代码加载权重时会按模型文件里的权重结构反推ch和nc但如果加载时显式指定了nc80的模型定义就会冲突。解决方法是打开YOLOv5源码的models/yolov5s.yaml或对应配置文件把nc改成你训练时的类别数这里是2确保模型结构与权重完全对齐。还有个更隐蔽的坑权重文件名和实际类别顺序不一致。比如训练时类别顺序是[traffic_light, person]部署时代码里写死names为{0: person, 1: traffic_light}那框都对不上。准确做法是从权重本身读取names而不是在配置文件里写死。用第2章的torch.load检查一次确认names输出与你预期一致再继续。5.5 现象发布检测结果延迟越来越大最终画面整体滞后数秒现象是启动几分钟后画面显示的结果比实际场景慢好几秒越跑越滞后。原因是图像消息订阅端处理不过来ROS的回调队列开始堆积。虽然queue_size1能缓解但如果上游相机是30fps推理只能跑10fps中间没有丢帧策略旧数据还是会积压。解决思路是给推理节点加一个简单的丢帧逻辑回调函数里判断上一帧是否还在处理在则直接return丢弃当前帧。这种“最新帧优先”的策略对实时检测最友好。另一种可行方案是降低相机帧率比如从30fps降到15fps前提是应用场景的运动速度不高。行人识别场景15fps完全够用红绿灯识别甚至10fps都行。还有一个细节发布可视化图像时如果rqt_image_view没有开启话题的Publisher会阻塞吗不会但TCP传输缓存会不断占内存长时间运行后内存涨上去。建议在launch里把Visualization话题设置latchFalse同时定期清理无订阅者的Publisher连接。这条排查链条要同时检查发布端和接收端不能只看单侧。6. 性能验证与进阶优化从“跑通”到“能用”6.1 用rosbag回放做离线验证真车调试不方便rosbag是最值得养成的验证工具。先录一段包含原始图像话题的bagrosbag record -O test_scene.bag /usb_cam/image_raw之后每次改代码或调参数不用重新跑实车直接用bag回放替代相机话题rosbag play test_scene.bag --loop检测节点照常订阅图像话题像面对真实相机一样处理。对比同一条bag在不同参数下的检测结果能客观判断改进效果。我习惯把bag切成按场景分布——直道、夜晚、雨天、人流密集等各录一段。用bag回放验证时rostopic hz检查回放频率如果bag播放速度不是1.0帧率对不上检测节点的表现和真实场景会有出入。回放时有几个坑需要留意bag里如果有/diagnostics这类高频话题播放时CPU占用会额外加大--loop循环播放时话题时间戳会回到起点如果下游节点做了时间戳滤波检测结果可能被丢弃。有这种需求的话控制节点的stamp容差要放宽。6.2 把权重转成TensorRT做推理加速如果CPU和GPU资源都紧张TensorRT是目前性价比最高的加速手段。YOLOv5官方提供了转换脚本export.py一行命令把pt权重转engine格式python export.py --weights weights/best.pt --include engine --device 0 --img-size 640 --batch-size 1转换完得到best.engine加载方式和pt不同需要改用TensorRT的Python API或trt_utils。最常见的报错是TensorRT版本和CUDA版本不匹配。务必先确认nvidia-smi的CUDA版本和pip list | grep tensorrt的版本对应。Rust或ROS节点调用engine时通常要额外传optimization profile不然动态shape输入会报Network requires 2 optimization profiles。这个错误不常见但出现了就调profile维度对上输入尺寸。TensorRT部署后原本25fps的模型能到50fps以上但代价是模型灵活性降低——conf_thres和iou_thres只能在转换时预设运行时不能任意改。所以参数调优阶段先用pt跑调定了再转engine上线一步到位会把自己坑回去。这也是我反复强调“先pt后trt”的原因相当于给自己留了后悔药。最后一件事部署包里模型输出的names顺序一定要固定下来无论后续怎么reload、如何转engine不要随意更改类别顺序。否则训练时的{0: person, 1: traffic_light}和部署时不一致所有坐标全错位。我见过不止一次因为改动names字段把整个检测结果搞成黑匣子的翻车现场。把names固定写进说明文档里比任何Debug日志都管用。这套从环境到launch再到TensorRT的链路走完你的YOLOv5 ROS部署就不会只停留在跑demo层面而是真正能在行人和红绿灯场景里稳定运转。希望帮到你。本文还有配套的精品资源点击获取