无网工控机离线部署实战PyQt OpenVINO 工业相机 SDK 打进一个 tar 包场景产线工控机Intel N3350 双核小主机——没网、不能装编译器、系统不能乱动。我们要把一套 PyQt5 OpenVINO FLIR Spinnaker 相机 SDK 的检测软件部署上去。方案在联网的开发机上把整个可运行环境打成一个 tar 包目标机只做两件事——解压、跑 install.sh。工控机部署的三大约束完全离线pip install、apt install全部不可用任何到目标机上再装的思路都行不通CPU 弱且指令集受限N3350 只有 SSE4.2、没有 AVX2——这直接决定了 OpenVINO 能跑但跑不快我们实测推理 300~500ms 的元凶就是它选型时必须先知先觉系统是生产环境不能为了装你的软件把系统搞坏安装过程必须只增不删、可回退。第三条最重要也最容易被忽视——后面安装脚本的设计全是围绕它。总体思路把环境当货物打包离线部署的本质把联网机器上能跑的状态原样搬运。我们的 tar 包内容offline_package/ ├── *.py, config.json, models/, fonts/ # 代码、模型、字体 ├── venv/ # 预装好的 Python 虚拟环境含全部 pip 依赖 ├── spinnaker_debs/ # 相机 SDK 官方 deb 包首选安装方式 ├── spinnaker_sdk/ # SDK 目录 udev 规则 环境变量fallback ├── system_packages/ # 全部系统依赖 .deb递归收集 ├── install.sh # 一键安装 └── autostart.sh # 开机自启打包脚本的四个关键动作1. 预建虚拟环境--copies是重点python3-mvenv--copies$OUTPUT_DIR/venv$OUTPUT_DIR/venv/bin/pipinstall-rrequirements.txt在打包机上建好 venv 并装完所有 pip 依赖目标机零安装。--copies用实体文件代替符号链接——默认 venv 的 python 二进制是指向系统解释的链接拷到目标机路径一变就失效。2. PySpin 手动拷进 site-packagesFLIR 的 Python 绑定不在 PyPI 上只能从官方安装器装到系统 Python。所以手动把三个文件拷进 venvcp$PYSPIN_SRC/PySpin.py$VENV_SITE_PKG/cp$PYSPIN_SRC/_PySpin.cpython-310-x86_64-linux-gnu.so$VENV_SITE_PKG/注意.so文件名带 Python 版本和架构cpython-310-x86_64——打包机和目标机的 Python 版本、系统架构必须一致这是整套方案成立的前提。3. 系统依赖递归收集肉眼列依赖清单一定漏用 apt 自己算# 把 Spinnaker SDK 和 FFmpeg 的所有递归依赖展开成清单mapfile-tDEPS(apt-cachedepends--recurse--no-recommends\libspinnaker libspinnaker-c spinnaker libgentl libavcodec58...\|grep^[^ ]|sort-u)forpkgin${DEPS[]};doaptdownload$pkg# 只下载不安装doneapt download在联网机器上把几十个 .deb 全拉下来目标机完全不需要网络。4. 相机 SDK 双保险优先拷官方 deb 包目标机dpkg -i正规安装依赖关系自动处理同时把/opt/spinnaker目录、udev 规则40-flir-spinnaker.rules、/etc/ld.so.conf.d/的库路径配置一并打包作为 fallback。udev 规则千万别漏——没有它USB 相机权限不对普通用户根本打不开设备。安装脚本只增不删装缺不装全install.sh的核心纪律install_system_deps(){localmissing()fordebinsystem_packages/*.deb;dopkg$(dpkg-deb-f$debPackage)# 只收集系统里没装的包dpkg-s$pkg/dev/null21||missing($deb)done[${#missing[]}-eq0]{echo系统依赖已满足跳过;return0;}sudodpkg-i${missing[]}}三条原则只安装缺失的包已存在的一个不碰绝不卸载任何东西——离线环境没有 apt 帮你兜依赖地狱dpkg -i失败就报错让人工处理不要自作聪明加--force目标已有/opt/spinnaker时先备份成.bak再装可回退。最后顺手完成udev 规则 reload、把用户加入flirimaging组相机权限、ldconfig刷新库缓存。部署后自检一份 check_env.sh 挡掉 80% 的扯皮装完先跑自检脚本再启动软件把环境问题暴露在交付现场之前echo CPU 指令集 grep-o-Esse4_2|avx|avx2/proc/cpuinfo|sort-u# 没有 sse4_2 → OpenVINO 直接跑不了没有 avx2 → 能跑但慢N3350 就是这种情况echo 内存 free-h# 3.5G 建议加 swap推理峰值会顶满echo 相机设备 ls-l/dev/video*echo 网卡 ipaddr# GigE 相机网口是否配了同网段 IP这份脚本还有一个隐藏用途远程排障。现场工人不懂 Linux让他跑一下脚本把输出发给你比电话里问你电脑什么配置高效十倍。开机自启工控机的软件必须断电重启后自己起来。autostart.sh里做三件事等桌面环境就绪 → 激活 venv → 启动 main.py。用 systemd service 或桌面自启条目均可注意 DISPLAY 环境变量要等 X 起来才有。效果离线包解压后约 865MB、压缩成 tar 约 101MB预装 venv 模型 SDK 系统 debU 盘拷过去解压 install.sh 自检即完成部署全程不碰网络交付多台同型号工控机环境零差异——因为环境根本不是在目标机上装出来的是搬过去的。小结离线部署的核心思路环境不在目标机上安装而是在联网机器上整体搬运venv --copies、递归apt download、SDK deb 目录双保险三个动作解决 90% 的离线依赖问题安装脚本只增不删、装缺不装全——生产环境的系统不是你的试验田自检脚本把环境对不对变成一份可发送的报告部署和售后都靠它。系列文章《PyQt 工业检测软件多线程实战触发、取帧、推理、UI 四条线怎么不打架》《Python 对接 PLC 实现拍照触发与结果回传——Modbus-TCP 一问一答协议实战》《YOLOv8 部署到无 GPU 工控机实战ONNX 导出 OpenVINO 推理 手写后处理》