ARTICLE DETAIL

资讯详情

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

树莓派5部署YOLOv5实战:工业车间视觉检测六大坑复盘

树莓派5部署YOLOv5实战:工业车间视觉检测六大坑复盘 树莓派 5 拿进车间做视觉检测这件事本来以为撑死两周就能上线结果前后磨了一个多月。倒不是模型训练花了多少时间而是从系统到供电、从环境到推理链路一路踩过去卡在六个大坑上出不来。这篇文章就把这六件事完整复盘一遍给想在工业现场部署树莓派 5 做 YOLOv5 推理的朋友做个参考。我这边场景是产线上的小零件计数和缺陷粗筛自己用 YOLOv5 训练了一个模型类别不多就三种缺陷想着树莓派 5 的 CPU 性能比 4 代强不少应该能扛住轻量推理。实际上树莓派 5 确实能跑但能不能稳定跑取决于你怎么处理系统、供电、散热、依赖编译、模型导出和工程化这几道关。我把这些坑拆开讲需要的可以直接抄作业。1. 系统底座Ubuntu 装不上先卡在启动盘1.1 为什么不用树莓派官方系统树莓派 5 刚拿到手时我第一反应是装 Raspberry Pi OS毕竟官方支持最全。但我的目标是部署自训练的 YOLOv5 模型训练环境一直在 Ubuntu 下模型转换、依赖库、Python 生态在 Ubuntu 上更顺。Raspberry Pi OS 基于 Debian也能跑 PyTorch但很多底层库、驱动、内核模块的兼容性我实在不想在这上面浪费时间。另一个原因是 Ubuntu 对 arm64 架构的 wheel 包支持更完整PyTorch 和 OpenCV 的预编译包能直接装不用动不动就源码编译这一点对后续部署省了太多事。1.2 烧录与启动的细节说句实话树莓派 5 的启动比 4 代娇气不少。我一开始用 Win32DiskImager 直接写 Ubuntu Server 23.10 的镜像插上电显示器黑屏网口灯不亮以为板子坏了。排查了半天才发现是镜像写入方式的问题。树莓派 5 的 boot 流程和 4 代不一样对分区表、引导文件要求更严格老老实实用 Raspberry Pi Imager 来烧录就没事别贪方便用通用写盘工具。另一个细节是树莓派 5 的 UART 调试口和 HDMI 输出对显示器的兼容性有坑。很多车间里的老旧 VGA 显示器接了转接头之后没信号这时候别急着判定系统没起来。先把网线插上看路由器后台有没有新的 DHCP 客户端或者直接扫描局域网 IPSSH 能通就说明系统活着头铁去折腾显示输出纯粹浪费时间。1.3 Ubuntu Server 还是 Desktop我直接选了 Ubuntu Server不装桌面环境。车间部署不需要图形界面多一个桌面就多一分内存和 CPU 开销。树莓派 5 哪怕是 8GB 版本在推理任务下内存也不算宽裕少跑一个桌面能省出不少资源。安装 Server 版之后连显示器都不用接烧录完镜像后在 boot 分区放一个 user-data 文件配置好 SSH 密钥和用户名通电就能远程登录。这里有个经验树莓派 5 的 Ubuntu Server 镜像默认没有开启 SSH 远程登录服务必须在 first boot 之前把 user-data 里的 ssh 配置写好否则你就要接显示器和键盘麻烦得很。系统装完之后的第一件事是把 apt 源换成国内镜像然后apt update apt dist-upgrade。树莓派 5 的固件更新频繁有些硬件 bug 靠固件修复比如 PCIe 和 USB 控制器的稳定性问题升级固件能明显改善。这一步看起来基础其实后面很多莫名其妙的问题都靠它解决。2. 供电与散热车间环境里最基础的坑2.1 电源适配器的选择与验证树莓派 5 对供电的要求相当苛刻官方推荐 5V/5A 或者 USB PD 27W 以上的电源但真正影响稳定性的是握手时序。我一开始用了一个标称 65W 的 PD 充电器想着功率绰绰有余结果开 YOLOv5 推理还不到两分钟系统就出现“Under-voltage”警告CPU 被强制降频推理速度掉到一个不可用的程度。查了一圈资料才发现问题出在 PD 协议握手时序上部分充电器在电压协商阶段会先输出 5V/3A然后才切换到更高电压档位这个切换过程中树莓派 5 如果检测到电压跌落就会进入欠压保护状态持续降频直到你重新插拔电源。这个问题的排查方法很简单在终端运行dmesg | grep -i voltage能看到欠压警告。更准确的做法是查控制寄存器cat /sys/devices/platform/soc/soc:firmware/get_throttled这个命令返回的十六进制值bit 0 代表欠压bit 1 代表降频bit 2 代表过热降频。如果长时间不稳定直接换一个专为树莓派 5 设计的电源别用通用手机充电器哪怕是 100W 的也不一定靠谱。2.2 散热方案实测对比树莓派 5 的发热量比 4 代大很多。在车间这种室温 30 度左右的环境里被动散热的铝合金外壳根本压不住满载推理的时候 CPU 温度能冲到 85 度以上然后触发降频推理性能直线下滑。我试过三种方案原装主动散热片加小风扇、铝合金被动散热壳、自己加装 5V 涡轮风扇。实测下来原装散热片加风扇这套方案在裸板状态下能把满载温度压在 60 度左右但装进防尘外壳之后效果打折。铝合金被动壳适合低负载场景跑模型推理基本没有意义。最后用的方案是主动风扇加散热片外壳侧面开孔加了一层防尘滤网温度稳定在 63 度上下。这里有个细节散热风扇的供电别直接用 GPIO 的 5V 引脚除非风扇是静音低功耗型号否则启动瞬间的电流冲击可能导致系统不稳。我用的风扇是 5V 0.2A 的直连 GPIO 没出问题但你如果用的是 5V 0.5A 以上的风扇建议加一个独立的 MOSFET 开关模块软件控制启停既省电又能延长寿命。2.3 供电和接地的坑车间环境的接地问题比想象中麻烦。电网里电动机、变频器多地线如果接得不好树莓派的 USB 摄像头或者 HDMI 接口容易受到干扰偶尔出现图像闪烁或者 USB 设备掉线的现象。我在现场排查过两次最后发现是设备外壳和电源适配器之间产生了电位差加了一个隔离变压器才解决。这个情况不常见但如果你在现场调试时遇到莫名其妙的视频流中断先想一想是不是电源地线的问题别一上来就怀疑代码。3. Python 环境与依赖编译装包装了三天3.1 Python 版本与虚拟环境Ubuntu Server 官方源里自带的 Python 版本是 3.12而我的 YOLOv5 训练环境用的是 Python 3.8 系列一开始想直接pip install -r requirements.txt结果一堆库要么没 arm64 wheel要么版本冲突。后来决定用 Python 3.11 建虚拟环境原因很现实官方 apt 源里有现成的 python3.11 包同时大多数深度学习库对 3.11 的支持已经非常成熟arm64 平台的 wheel 覆盖率也高编译的概率小得多。sudo apt install python3.11 python3.11-venv python3.11-dev python3.11 -m venv yolov5_env source yolov5_env/bin/activate这里提醒一下python3.11-dev这个包一定要装很多 pip 包在安装时会编译一些 C 扩展缺少头文件直接报错尤其是 numpy 和 PyTorch 的某些子依赖。3.2 PyTorch 安装的捷径树莓派 5 上装 PyTorch不需要源码编译这是我折腾两天之后才想明白的。早期在树莓派 4 上装 PyTorch 时经常要编译因为官方不给 armv7 的预编译包。但树莓派 5 是 arm64 架构PyTorch 官方 PyPI 里直接有 aarch64 的 wheelpip install torch torchvision就能装省掉了编译的几小时时间。唯一的坑是版本要匹配。我自己折腾过一次把 torch 和 torchvision 装成了不同小版本加载模型时爆出“torchvision 与 torch 版本不兼容”的运行时错误。直接按官方版本对应表装别偷懒。pip install torch2.2.0 torchvision0.17.03.3 OpenCV 的依赖问题YOLOv5 的推理链路里 OpenCV 跑不了。在树莓派 5 上直接pip install opencv-python能装上但import cv2的时候会报缺 libGL.so.1。原因是 OpenCV 的 Python wheel 包假设系统里有 GUI 相关的底层库而 Ubuntu Server 默认没有装。安装命令sudo apt install libgl1 libglib2.0-0 libgstreamer-plugins-base1.0-0这一行能救你的命我在这卡了整整半天一开始以为是 OpenCV 安装包损坏重装了好几次。另外一个容易忽略的是 numpy 版本。PyTorch 2.2 和 OpenCV 对 numpy 2.x 的兼容性不太好实测下来会有一些隐性的数值问题建议锁定 numpy 1.26.4pip install numpy1.26.44. 模型部署自训练 YOLOv5 上板精度与速度都要管4.1 导出 TorchScript 还是 ONNXYOLOv5 训练完之后在 PC 上导出的模型格式有两种常见选择TorchScript 和 ONNX。树莓派 5 上没有 NVIDIA GPUTensorRT 想都不要想纯 CPU 推理下TorchScript 的兼容性和部署简易度最高直接在 PyTorch 环境里加载不用额外依赖。ONNX 的优势是可以用 ONNX Runtime 做优化在某些算子上的推理速度可能比 PyTorch 的原生推理快但对树莓派这种 ARM 平台ONNX Runtime 的优化未必比 PyTorch 原生好多少。我最终的方案是导出 TorchScript理由是少一层依赖少一份出错的可能。导出命令很简单python export.py --weights best.pt --include torchscript --img-size 640这里要注意导出时的--img-size参数会影响模型的推理分辨率后面部署时输入图像的尺寸必须和这个一致否则会爆维度错误。我训练时用 640后面推理为了速度降到 416结果导出的时候没重新导代码里 resize 之后模型跑起来各种报错。4.2 推理脚本改造要点在树莓派上跑 YOLOv5不能直接套跑 PC 的detect.py资源开销太大。我自己写了一个精简版推理脚本核心就三步。先加载模型并设置推理参数import torch from models.experimental import attempt_load device torch.device(cpu) model attempt_load(best.torchscript, map_locationdevice) model.eval() # 关键优化设置线程数避免资源争抢 torch.set_num_threads(4)然后对输入图像做预处理YOLOv5 模型需要的输入是 RGB、归一化到 0-1、维度为 NCHW这一步用 OpenCV 完成。import cv2 import torch def preprocess(image): img cv2.cvtColor(image, cv2.COLOR_BGR2RGB) img cv2.resize(img, (416, 416)) img img.astype(float32) / 255.0 img img.transpose(2, 0, 1) img torch.from_numpy(img).unsqueeze(0) return img推理过程加一次 warm-up第一次推理会触发一些初始化慢得吓人但不代表真实性能跑几次之后再计时才有意义。4.3 性能实测与预期管理树莓派 5 的 CPU 性能确实比想象中好一点但远达不到 PC 级别。我的模型输入尺寸 416x416用 TorchScript 在 CPU 推理一帧大概在 250-300ms 之间大约 3-4 FPS。如果输入尺寸降到 320能跑到 150ms 左右也就是 6-7 FPS。这对产线上静态摆放的工件计数来说是够用的但如果你想跑 30 FPS 的实时视频流趁早换方案别难为树莓派。优化空间在于量化和算子融合。YOLOv5 官方提供了 int8 量化工具但树莓派 CPU 上量化模型的加速效果并不稳定我在实测中精度掉了一点速度提升不到一倍综合考虑放弃了。另外OpenCV 的 DNN 模块加载 ONNX 模型在某些层上有特殊优化但 YOLOv5 的模型结构比较新opencv-dnn 支持的算子覆盖不全效果不理想。经验是模型部署之前必须和目标用户对齐性能预期。车间主管一开始以为 AI 模型跑起来就该和手机扫码一样快看到 3 FPS 的演示视频差点让我返工。后来我把检测目标从视频流改成定时拍照检测每次拍照后 300ms 内出结果体验下来反而更稳定因为灯光明暗变化、工件搬运遮挡这些现场干扰静态抓拍比连续视频更好控制。5. 摄像头与图像同步视频流的两个坑5.1 CSI 摄像头与 libcamera树莓派 5 的 CSI 接口和 4 代不通用线序变了我最初用的是树莓派官方 CSI 摄像头结果插上去libcamera-hello能出画面但 OpenCVVideoCapture(0)打开摄像头是黑屏。原因在于树莓派 5 的摄像头驱动默认走 libcamera 框架不再直接提供 V4L2 设备节点OpenCV 拿到的设备索引不对。解决方案有两个。一个是用 libcamera 提供的 GStreamer 管道通过 OpenCV 的 CAP_GSTREAMER 后端获取视频流cap cv2.VideoCapture(libcamerasrc ! video/x-raw,width1280,height720,framerate15/1 ! videoconvert ! appsink, cv2.CAP_GSTREAMER)另一个方案是先用libcamera-vid -t 0 --width 1280 --height 720 --output -把视频流转发到标准输出然后用管道读取。但 GStreamer 方案集成度高一些我在最终方案里用的就是这种方式。5.2 USB 摄像头的带宽与供电陷阱车间现场临时换过 USB 摄像头又踩了带宽的坑。树莓派 5 的 USB 控制器带宽是共享的两个 USB3.0 摄像头同时以 1080p 30FPS 取流第二个摄像头频繁丢帧。排查发现树莓派 5 的 USB 供电不足摄像头启动瞬间电流过大导致枚举失败。解决方式是把摄像头的供电独立或者降低分辨率我用 1280x720 15FPS 之后两个摄像头稳定工作。另外USB 摄像头的 UVC 协议对 CPU 占用不高但 OpenCV 的默认读取方式是阻塞式读取慢的时候会把推理线程卡住导致检测结果延迟越来越大。处理方式是开一个独立线程专门读取视频帧存入队列推理线程从队列里取最新一帧宁可丢帧也不让队列堆积。import threading import queue frame_queue queue.Queue(maxsize2) def capture_thread(): cap cv2.VideoCapture(0) while True: ret, frame cap.read() if ret: if frame_queue.full(): frame_queue.get() frame_queue.put(frame) t threading.Thread(targetcapture_thread, daemonTrue) t.start()槽点在 maxsize2队列超过 2 帧就阻塞摄像头线程这样处理延时保持在一个较低水平避免内存无限制增长。6. 工程化落地断电重启、自启与远程维护6.1 systemd 服务与开机自启模型和脚本都跑通之后最难的是让它变成一个“现场设备”而不是一个开发板。我写了一个 systemd 服务来管理推理进程服务配置里有几个细节值得注意。一是Restartalways保证进程崩了自动拉起。二是StartLimitIntervalSec要设置合理不然频繁重启会被 systemd 熔断。三是服务启动前最好加一个延时等网络和摄像头初始化完成再跑主程序我在ExecStartPre里加了一行sleep 10避开了开机时各种设备竞争。[Unit] DescriptionYOLOv5 Detection Service Afternetwork-online.target [Service] ExecStartPre/bin/sleep 10 ExecStart/home/ubuntu/yolov5_env/bin/python /home/ubuntu/detect_server.py Restartalways RestartSec5 StartLimitIntervalSec60 StartLimitBurst3 StandardOutputappend:/var/log/yolov5.log StandardErrorappend:/var/log/yolov5.log [Install] WantedBymulti-user.target服务写好后systemctl enable yolo.service开机自启。这里还有个小细节日志直接写到 TF 卡对卡有损耗我改成了挂载到内容目录之后写内存盘减少闪存写入次数。6.2 看门狗与断电恢复车间断电是个逃不开的场景。树莓派正常关机没问题但突然断电之后如果程序写日志写一半TF 卡的文件系统容易出问题轻则丢配置重则进不了系统。我在服务里做了一层保护所有关键配置在开机时从只读分区加载运行时的中间状态只写内存盘/tmp断电重启后自动恢复到初始状态。再进一步树莓派的硬件看门狗也打开了。设备树里默认加载了bcm2835_wdt把/dev/watchdog对应的 systemd 服务启用一旦系统卡死无法喂狗硬件会自动重启突出一个省心。配置方式sudo systemctl enable watchdog sudo systemctl start watchdog如果不用 systemd 的 watchdog 服务也可以在自己的 Python 脚本里定期os.system(echo 1 /dev/watchdog)喂狗本质上是在系统卡死的时候强制重启。这个在无人值守的车间场景里非常实用。6.3 远程维护与日志排查部署在车间人不可能天天跑现场。我把 SSH 端口映射到机房跳板机平时通过跳板机连过去看日志、改代码。日志管理上建议按天轮转不要一个文件撑到底用 logrotate 或者自己的定时任务都行。我在服务脚本里用logging.handlers.TimedRotatingFileHandler每天一个日志文件保留七天不然 TF 卡的剩余空间撑不了多久。远程排查一个经典问题是内存泄漏。树莓派 5 的内存虽然不小但 detect_server 长时间运行后内存碎片会越积越多。我在服务里加了一个定期打印内存和 CPU 占用的逻辑每处理 500 帧输出一次性能统计方便对比前后几天的数据。import resource def print_stats(): mem_mb resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024 logging.info(fMemory usage: {mem_mb:.1f} MB)实测跑了两周内存占用稳定在 800MB 左右没有明显泄漏这在跑 YOLOv5 模型的情况下已经算是健康水平。6.4 数据回传与结果落库检测结果不能只存在板子上我写了一个简单的 MQTT 客户端每检测到一个缺陷就向中心服务器推送一次结果包含时间戳、缺陷类别、置信度和图片编号。图片本身有选择性地存储只在置信度超过某个阈值时才保存到本地其余正常帧直接丢弃这个策略减少了存储压力也方便后续做误报分析。MQTT 断线重连的逻辑一定要处理不然网络抖动一次服务就断送一条数据。我用的 paho-mqtt断线回调里设置 10 秒重连实测断网十分钟后恢复数据队列能自动补发没有丢记录。其实这一路踩下来我最深的体会一句话就能说明白树莓派 5 在车间里真正的问题不是算力不行而是你把一个消费级设备当成工控机来用的时候供电、散热、稳定性这些“看不见的工程”才是真正决定项目成败的关键。模型训练只要刷一遍数据就出来了但你不知道它什么时候会被一个欠压警告拖慢也不知道风扇积灰一个月后会不会自动降频。这些都要在现场一遍一遍磨才能磨出一个稳定运行的环境。最后再分享一个小技巧别急着上复杂的容器方案Docker 在树莓派 5 上资源开销不小一个 systemd 服务加一个 Python 虚拟环境反而是最轻量可靠的组合至少在我这个场景下它是真的撑住了。
返回列表