ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

宇树GO2 + Jetson Orin跑YOLOv5目标检测与TensorRT加速实战

宇树GO2 + Jetson Orin跑YOLOv5目标检测与TensorRT加速实战 如果你手里正好有一台宇树GO2又准备在这台机器狗上跑YOLOv5做实时目标检测那Jetson Orin几乎是最靠谱的“机载大脑”——但靠谱不代表省心。我在Jetson AGX Orin上把宇树GO2的图像接到YOLOv5、再做完TensorRT加速前后折腾了将近一周。这篇文章就是我那次部署的完整记录包括环境选型、PyTorch安装、源码依赖、ROS2图像桥接、性能调优以及我把每一步踩过的坑都修复之后沉淀下来的解决方案。适合正在搞四足机器人视觉开发、边缘AI部署或者准备把YOLOv5搬上Orin平台的朋友看完可以直接少走很多弯路。1. 部署前的整体规划与关键决策1.1 为什么在Jetson Orin上跑YOLOv5目标检测宇树GO2本身不是一个算力平台它是一台运动能力很强的四足机器人。你要是想把实时目标检测、视觉避障、目标跟随这类功能跑在GO2自带的控制系统里基本不现实所以常规玩法是外接一台Jetson设备当作机载电脑通过网口或USB与GO2通信。我选择Jetson Orin而不是Orin Nano或者树莓派原因很直接Orin系列搭载Ampere架构GPU拥有充足且带宽高的统一内存对YOLOv5这种卷积神经网络非常友好。用我的实测数据说话在AGX Orin上YOLOv5s模型全精度推理640分辨率输入大约能跑到30到40帧每秒换成TensorRT FP16引擎后可以到60到80帧每秒完全满足移动机器人实时处理需求。如果换到树莓派哪怕只是跑YOLOv5s的CPU推理帧率也就个位数根本谈不上实时。至于目标检测模型为什么选YOLOv5而不是更新的YOLOv8或者YOLOv11我的看法是YOLOv5的部署生态实在太成熟了。无论是ONNX导出、TensorRT转换、自定义数据集训练再到部署的闭环还是社区里各种边缘设备踩坑案例数量都远超其他版本。GO2和Jetson这种组合我们在意的是快速落地和稳定运行不是追模型版本号。1.2 系统版本与JetPack选型原则在刷机之前我建议你先做一个决策选JetPack 5.x还是6.x。这不是小事因为它直接决定了后面所有CUDA、cuDNN、TensorRT、PyTorch的版本匹配方式。JetPack 5.x对应L4T 35.xCUDA版本是11.4TensorRT是8.5整体技术栈比较老但好处是稳定NVIDIA官方提供的PyTorch轮子适配得很好社区里大量案例都是基于这套组合。JetPack 6.x对应L4T 36.xCUDA升级到12.xTensorRT也变成9.x甚至更高API有改动很多旧项目需要重新适配而且部分PyTorch版本对JetPack 6的支持还不够流畅。我自己选的是JetPack 5.1.2加配套的PyTorch 2.0.0这是当时最省心的一套组合。如果让我给建议除非你有明确理由必须上CUDA 12否则先选JetPack 5.1.x或者5.2.x把项目跑通再考虑升级。另外要注意不要一上来就装自己习惯的版本先搞清楚板子出厂固件对应的JetPack版本再决定是否用SDK Manager刷机。2. Jetson Orin环境搭建中容易踩的坑2.1 系统烧录与初始设置刷机建议直接用NVIDIA SDK Manager选择对应的Jetson AGX Orin设备烧录时组件勾选默认的Jetson SDK Components和Jetson Runtime就行。这一步看起来简单但有两个细节值得注意。第一个细节是烧录过程中不要断电AGX Orin的电源最好插在稳定插座上千万别用USB-C供电凑合不然可能在烧录引导加载器的时候直接变砖。第二次刷机我换了个带稳压的电源再没出过问题。第二个细节是刷完系统后别急着装环境先做三件事确认版本、开最大性能、装监控工具。版本确认用以下命令sudo apt update sudo apt install -y nvidia-jetpack dpkg -l | grep nvidia-jetpack开最大性能的命令是sudo nvpmodel -m 0 sudo jetson_clocksjtop这个工具强烈建议装它在安装和排查问题时能让你一眼看到CPU、GPU、内存、温度、功耗状态比起凭空猜问题高效太多。安装方式也很简单sudo apt install python3-pip sudo pip3 install jetson-stats sudo jtop开机后先用jtop确认CPU和GPU频率是否正常如果你发现刚开始跑YOLOv5就卡成PPT大概率就是默认低功耗模式没有切换频率被锁在很低的位置。2.2 PyTorch与torchvision的安装是最大的坑这个坑我必须单独拎出来说。Jetson设备上直接执行pip install torch十有八九会装到x86架构的通用包要么import报错要么torch.cuda.is_available()永远是False。我当时第一次就踩了白白浪费了一个晚上。正确做法是用NVIDIA官方为Jetson发布的PyTorch轮子和对应torchvision轮子。JetPack 5.1.2搭配的是PyTorch 2.0.0。安装命令通常是这样sudo apt-get install -y python3-pip libopenblas-dev libopenmpi-dev libomp-dev pip3 install --no-cache-dir torch-2.0.0nv23.05-cp38-cp38-linux_aarch64.whl pip3 install --no-cache-dir torchvision-0.15.0a0...whl这里最关键的注意事项是torch和torchvision版本必须严格对应不能用pip自动解析否则你会拿到一个不匹配的组合运行时各种报错都会冒出来。安装完一定先做最小验证python3 import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))如果cuda.is_available()返回False试试设置环境变量再重新加载export LD_LIBRARY_PATH/usr/local/cuda/lib64:$LD_LIBRARY_PATH另外我不建议在Jetson上用Anaconda管理Python环境。原因有两个一是conda的路径优先级会干扰系统Python和NVIDIA库的调用二是很多Jetson特有的wheel包在conda环境里链接起来非常麻烦。直接用系统的Python3.8配合virtualenv或者干脆裸装反而是最稳的。2.3 CUDA/cuDNN/TensorRT版本匹配问题刷完JetPackCUDA、cuDNN、TensorRT其实都已经预装好了不需要单独去官网下载安装。很多人会犯的错是手动把某个库升级了结果其他组件不兼容。拿TensorRT来说JetPack 5.1.2自带的是TensorRT 8.5.3YOLOv5的export.py在导出engine时会自动调用当前环境的trtexec和Python绑定。如果你手动升级了TensorRT到9.x再回头看YOLOv5导出脚本可能会遇到API签名变化导致的报错比如“AttributeError: _Engine object has no attribute bindings”。这种问题的修复方式通常是重新安装JetPack对应的TensorRT版本而不是改代码去适配。我建议把版本信息固定下来记在笔记里包括JetPack 5.1.2、CUDA 11.4、cuDNN 8.6、TensorRT 8.5.3、Python 3.8、PyTorch 2.0.0。后续所有安装都以这个组合为基准网上搜到的很多报错解决方案其实都是版本错位导致的版本对齐之后问题自然消失。3. YOLOv5源码部署与依赖处理3.1 源码获取与requirements核对YOLOv5官方仓库拉到板子上以后先不要急着pip install -r requirements.txt这个文件里有很多组件在Jetson上是不需要的甚至是有害的。首先是wandb和clearml这两个分别是实验记录和模型管理工具部署阶段根本用不到。如果你网络环境不理想pip安装时它们还会卡住很长时间。我建议直接注释掉。其次是pycocotools这个包用于COCO评估如果你只是推理不训练可以不装。真要装的话需要先装好编译依赖Cython否则在aarch64上编译会报错sudo apt install -y python3-cython pip3 install pycocotools最后是opencvJetson系统本身已经预装了OpenCV而且是带GStreamer支持的版本这对后面读取摄像头数据很有用。不要再用pip安装opencv-python否则可能出现两个OpenCV版本互相覆盖最终import时报错或者cv2版本完全不对。我当时的处理策略是只保留torch、torchvision、numpy、matplotlib这些必要依赖其他能省则省先把detect.py跑通再回头补缺。3.2 OpenCV、numpy、pillow的版本陷阱YOLOv5对numpy版本有下限要求较新版本要求numpy1.23但JetPack 5.1.2系统自带的OpenCV是基于numpy 1.19.5编译的。如果你直接把numpy升级到1.24OpenCV调用时很可能报“module compiled against API version a but this version of numpy is 1.x”的警告甚至直接崩溃。所以这里存在一个版本博弈要么锁住YOLOv5仓库到v6.0/v7.0这种老版本兼容低版本numpy要么升级numpy但尽量不要用系统的OpenCV而是自己编译或使用特定opencv-python wheel。我最终选择的是锁住YOLOv5版本到v7.0.0配合numpy 1.21.6OpenCV继续用系统预装版本稳定跑了一个多月没有出问题。pillow也值得留意。我在一次部署中遇到“ImportError: The _imaging C module is not installed”的报错后来发现是pip自动把pillow升级到了版本10和系统环境中某些库不兼容。解决方案是把pillow降级到9.5.0pip3 install pillow9.5.0整理成一张表包名建议版本原因numpy1.21.6兼容JetPack自带OpenCV避免API版本报错opencv-python不安装用系统自带避免双OpenCV冲突且系统版带GStreamerpillow9.5.0避免_imaging模块缺失报错torch2.0.0nv23.05NVIDIA官方Jetson专用轮子torchvision0.15.0a0对应版必须与torch匹配pycocotools可选推理不需要训练才需要3.3 第一个推理Demo先跑通官方detect.py环境配好之后先别直接上机器狗拿一张普通图片跑通官方推理流程是最稳妥的做法。把一张测试图片放到YOLOv5目录下执行python3 detect.py --weights yolov5s.pt --source test.jpg --device 0第一次运行会自动下载yolov5s.pt权重文件这一步如果在设备上下载失败可以从别处把权重文件拷贝到YOLOv5目录下再执行。另外要注意如果提示protobuf报错通常和Pillow或numpy版本无关而是缺少libprotobuf按报错提示安装缺少的系统库即可。跑通之后你会看到runs/detect/exp目录下生成了标注好的图片同时命令行会打印推理耗时。如果在这一步就报“CUDA error: no kernel image available”说明你的torch装成了x86版本或者不是为Jetson的ARM架构编译的直接重新安装适合JetPack的轮子不要试图通过修改代码绕过。我自己第一次跑detect.py时模型加载倒是正常但检测结果全在图片左上角后来发现是权重文件下载不完整删掉重新下载就好了。这种问题往往不会报错只会在检测结果上表现出异常所以遇到结果不对先怀疑文件完整性和预处理流程。4. 打通宇树GO2与YOLOv5的图像流4.1 GO2图像源接入方式GO2提供了官方的unitree_sdk2网络上也有大量开发者维护的ROS2接口包。官方推荐的方式是把Jetson Orin和GO2通过网口连接然后通过DDS协议订阅机器人状态、图像等话题。我当时的接入步骤是先在GO2上把机器人端SDK程序跑起来这时候Jetson端可以通过ros2 topic list看到一堆话题其中图像话题一般是/go2/color_camera/image_raw或者类似路径。如果你用的不是ROS2而是纯SDK也可以直接通过SDK的API拿到共享内存或网络图像数据。在编写任何代码之前先用命令行验证图像流是否通畅ros2 topic list | grep image ros2 topic hz /go2/color_camera/image_raw只有hz命令能持续输出频率才说明图像流是稳定的否则先排查网络和GO2端SDK程序不要急着写图像算法。这里我踩过最大的坑是网口IP配置Jetson的网口IP和GO2默认IP不在同一网段导致话题时断时续后来手动配置了静态IP才稳定。4.2 ROS2节点订阅与图像格式转换拿到了图像话题接下来要做的就是把sensor_msgs/Image转换成numpy数组送进YOLOv5预处理流程。一个最基本的ROS2 Python订阅节点大概是这样的import rclpy import cv2 import numpy as np from rclpy.node import Node from sensor_msgs.msg import Image from cv_bridge import CvBridge class Go2ImageNode(Node): def __init__(self): super().__init__(go2_image_node) self.bridge CvBridge() self.sub self.create_subscription( Image, /go2/color_camera/image_raw, self.image_callback, qos_profile10 ) def image_callback(self, msg): try: frame self.bridge.imgmsg_to_cv2(msg, bgr8) except Exception as e: self.get_logger().error(str(e)) return # 后续把frame交给YOLOv5处理 cv2.imshow(frame, frame) cv2.waitKey(1) def main(argsNone): rclpy.init(argsargs) node Go2ImageNode() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ __main__: main()这里容易踩的坑是颜色通道顺序。YOLOv5在训练和推理时使用的是RGB图像但OpenCV和很多ROS2桥接默认输出BGR。如果你不做转换直接推理检测结果可能会在颜色相关的类别上表现异常。我建议统一在图像回调里用cv2.cvtColor转成RGB再做后续处理。还有一个细节是图像尺寸。GO2摄像头采集的图像不一定正好是640x640而YOLOv5推理前会做letterbox缩放。如果你自己写推理循环必须把letterbox逻辑复用进去否则检测框的坐标会整体偏移。YOLOv5官方的detect.py里已经有实现可以直接调用它的预处理函数。4.3 实时检测主循环的实现思路打通图像流之后你的选择基本有两个第一是直接在ROS2回调里调用YOLOv5模型推理第二是把图像从ROS2话题里拿下来再通过文件或共享内存交给一个独立的检测进程。我当时先采用了第一种代码结构简单但是性能不太理想。原因在于rclpy的回调度默认QoS如果设置不当会把历史图像缓存起来处理不过来时图像帧堆积延迟越来越高。解决方法是将订阅QoS的history设置为KEEP_LASTdepth设为1并且回调里做完推理就返回不要做任何阻塞操作。如果是自己写推理主循环一个比较稳的伪代码结构是订阅图像话题收到一帧图像就放入一个长度为1的队列新帧直接覆盖旧帧检测主线程不停从队列取最新帧做letterbox预处理模型推理后处理得到检测框把检测框画在图像上显示或发布出去这样做的好处是图像采集和推理解耦即使某帧推理耗时较长图像源也不会被阻塞。实测下来帧表现会比直接在回调里海量丢弃要好很多。5. 性能优化从“能跑”到“跑得顺”5.1 半精度推理与输入尺寸权衡第一个不用动架构就能白拿的性能优化是半精度推理。Orin的GPU对FP16计算有专门加速单元YOLOv5里只需要在加载模型后加一行model.half()。model torch.hub.load(ultralytics/yolov5, yolov5s, pretrainedTrue) model.half()同时输入图像的尺寸也是一个重要超参数。YOLOv5默认使用640x640如果你的检测目标不大、机器人移动速度不快尝试把imgsz降到480甚至320帧率会有大幅度提升。但要注意盲目降低尺寸会牺牲小目标检测精度实际项目中要通过测试集验证效果。我当时在AGX Orin上做了一个基准对比。YOLOv5s、640输入、全精度推理大约35毫秒每帧开启半精度后降到22毫秒左右换成TensorRT FP16后推理单帧大约12到15毫秒帧率已经能稳定跑在60到80再配合图像流的采集帧率限制实际整条链路稳定在30帧左右。5.2 TensorRT导出engine并集成如果你希望把算力榨干TensorRT是绕不开的一步。YOLOv5官方已经提供了导出脚本不再需要你去手写onnx和engine的转换流程。我导出的命令是python3 export.py --weights yolov5s.pt --include engine --device 0 --half这条命令会在本地依次完成PyTorch模型转ONNX、ONNX转TensorRT engine最终生成一个yolov5s.engine文件。需要注意TensorRT engine是和硬件以及TensorRT版本绑定的在这块AGX Orin上导出的engine文件不能随便拷贝到另一台不同JetPack版本的Orin上用会报版本不匹配。集成的时候最简单的做法是把detect.py的weights参数直接指向engine文件python3 detect.py --weights yolov5s.engine --source test.jpg --device 0在自定义代码里加载engine文件并推理会更加灵活但代码量会大不少需要你自己写输入输出的bindings绑定逻辑。如果你只是为了把GO2图像接到YOLOv5上做实时检测用TORCH_HUB加载模型然后把权重替换成engine文件的方式其实就够用了。我实际测试中遇到的一个TensorRT相关坑是固定batch size。YOLOv5默认导出engine时batch为1如果你的推理循环里传入了多个batch会直接报错。如果确实需要动态batch导出时要指定python3 export.py --weights yolov5s.pt --include engine --device 0 --half --batch-size 45.3 功耗模式、频率与散热控制Jetson AGX Orin默认不会一直跑在满频它会根据负载动态调整CPU和GPU频率。这在长时间运行时是好事但在你想看真实性能上限时会得到一坨没法解释的抖动数据。建议把所有性能测试放在固定功耗模式和固定频率下进行。我自己用的是sudo nvpmodel -m 0 sudo jetson_clocksnvpmodel -m 0选择最大性能模式jetson_clocks则把CPU/GPU核心频率锁定在最高值。做完这些之后用jtop观察温度和功耗记录稳定运行半小时后的帧率这才是可复现的基准数据。另一个容易被忽略的问题是散热。当Orin被装进GO2机身或者密封结构里温度会快速上升达到85度左右就会触发降频帧率直接腰斩。我遇到过同样一段代码在桌面上跑70帧装进机身后只能跑到40帧一查温度稳定在88度。解决方案是加装主动散热风扇或者在散热条件有限的情况下把功耗模式调低一档牺牲一些性能换取稳定。机器人应用场景里稳定的30帧永远比波动的50帧更有价值。6. 常见问题与排错实录6.1 典型报错速查表现象可能原因解决方案import torch 报缺少libcudnn.so.8LD_LIBRARY_PATH或cuDNN版本不对检查/usr/local/cuda/lib64下是否存在libcudnn.so.8并export路径torch.cuda.is_available()返回False安装了x86版或非Jetson专用torch卸载后安装NVIDIA官方对应JetPack的wheeldetect.py推理时报no kernel image availabletorch编译架构与GPU不匹配重新安装适配aarch64且包含Ampere架构的torch检测图出现颜色诡异、类别不准BGR与RGB通道未转换在图像预处理前用cv2.cvtColor转RGB检测框位置整体偏移输入图像未做letterbox或letterbox参数不一致复用YOLOv5官方预处理函数TensorRT导出后推理报bindings属性错误engine版本与当前TensorRT版本不一致删除旧engine在当前环境重新导出ROS2订阅图像延迟越来越高QoS缓存堆积设置queue_size1或depth1CPU/GPU频率跑不上去、帧率波动大默认低功耗模式或散热不足nvpmodel -m 0 jetson_clocks并检查温度长时间运行后帧率逐渐下降内存或显存泄漏缓存未释放检查是否有图像队列堆积或TensorRT上下文重复创建6.2 排查思路与独门技巧部署这类项目最大的敌人不是某个具体报错而是“不稳定的环境”。所以我强烈建议按下面的顺序排查问题第一步先用最小案例确认基础环境是否正常比如import torch之后cuda可用第二步把官方YOLOv5的detect.py跑通确认模型和预处理没问题第三步接入实时图像流但不要直接做推理先用cv2显示原始视频确认采集链路没问题第四步再做YOLOv5实时推理最后才做TensorRT优化。每一步都验证通过再进下一步不要在一步都没验证完的情况下连续叠加新功能。我个人的一个习惯是给每个环节加上耗时打印图像采集、预处理、推理、后处理各打一个时间戳这样出现掉帧时能快速锁定瓶颈而不是靠感觉优化。实测中很多所谓的“推理太慢”问题最后都出在图像采集或预处理上。还有一个很实用的建议尽量把整套环境做成可复现的镜像。我在第一台Orin上配好环境后用dd和Docker容器相结合的方式做了备份之后在另一台Orin上部署只需要还原镜像省掉了大量重复安装时间。如果你手头设备多这个技巧能帮你节省一整天。最后再分享一个很多人会忽略的细节YOLOv5推理时要避免在循环里频繁创建TensorRT上下文或者重新加载模型。正确做法是把模型加载和推理初始化放在程序启动阶段运行时只做forward和postprocess。许多现场出现的“跑着跑着就卡死”其实都是循环里不断重建资源导致的显存泄漏。这次在宇树GO2上加Jetson Orin跑YOLOv5的部署我最大的体会是版本对齐比什么都重要先跑通再优化优化时盯住数据流而不是只盯模型。把基础环境做扎实GO2加Orin这个组合完全可以成为一套稳定的边缘视觉平台后续无论是做目标跟随、动态避障还是区域巡检都能在这个底子上继续扩展。
返回列表