1. 为什么无人售货柜必须用 YOLO 来认商品
先讲个真实的场景。某零售项目组做无人售货柜时,最初用的是传统图像匹配方案:每个商品放几组模板图,柜内摄像头拍完照后做特征点匹配。结果一到真实场景就崩——商品换个角度、光线暗一点、被旁边的东西挡了一半,匹配率直接掉到 70%以下。后来换成 YOLO 系列检测模型,同样的柜子、同样的摄像头,识别率稳到 95% 以上,推理速度还快了一倍多。
这背后的逻辑其实很简单:传统模板匹配是在“找相似图”,而 YOLO 是在“学规律”。YOLO 把整张图拆成网格,每个网格直接预测“这里有没有目标”“目标是什么”“目标框在哪”,一次前向推理就能把所有商品的位置和类别同时输出。对无人售货柜这种场景,货柜里的商品种类固定、摆放相对规整、摄像头视角基本不变,YOLO 的学习能力能轻松驾驭这种“限定域”识别,而且泛化能力远比模板匹配强——换个柜子、换台设备,只要数据够,重新训练一下就能适配。
我在这套系统里用的硬件平台是 RK 系列芯片(RK3588 / RK3568 这类带 NPU 的 SoC),搭配 YOLO 做端侧推理。RK 的 NPU 对 YOLO 系列的支持非常成熟,Convert 工具链可以把训练好的模型转换成 RKNN 格式,跑在板子上功耗低、延迟小,非常适合无人售货柜这种需要 7x24 小时在线、又不能塞一台大服务器进去的场景。
这篇博文的目标非常明确:从零搭建 YOLO 商品识别的训练环境,准备好数据集,跑通训练,最终拿到一个能在 RK 平台上部署的模型。整个过程我会按实际开发顺序一步步写,代码也给出可直接复制执行的版本,适合已经对 Python 和深度学习有基本了解、但第一次做端侧检测项目的开发者。如果你完全是零基础,建议先补一下 Python 语法、pip 安装、以及最基础的 PyTorch 使用,再回来跟着走会更顺。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 整体方案选型与 RK 平台适配思路
2.1 硬件选型:为什么要选带 NPU 的 RK 芯片
无人售货柜的算力需求看起来不大,但实际约束条件很多:设备要长期通电运行,散热和功耗是硬指标;柜子内部空间有限,不可能塞 ITX 主机;成本要压到几百块钱级别,不能上万;还得支持多路摄像头输入和 IO 控制(比如门锁、重力传感器)。综合下来,RK3588 和 RK3568 就是当前性价比最平衡的选择。
RK3588 的 NPU 算力是 6 TOPS,可以同时跑两路 640x640 的 YOLO 推理还剩余量;RK3568 是 1 TOPS 左右,适合只装一个摄像头、商品数量少的 mini 柜型。选型时记住一个原则:模型参数量除以 4,就是这张板子跑这个模型的最低算力需求(单位 TOPS)的粗略估计。比如 YOLOv5s 是 7M 参数,大约需要 1.75 TOPS 以上才跑得流畅,所以用 RK3568 跑 YOLOv5s 会有点吃紧,用 RK3588 就游刃有余。
另外要注意,RK 的 NPU 不是把所有算子都原生支持的。早期版本的 RKNN Toolkit 对某些上采样层、特殊激活函数的支持不完整,所以选 YOLO 版本时最好挑 RKNN 官方文档里验证过的组合。当前最稳的是 YOLOv5 系和 YOLOv8 系,我项目里用的是 YOLOv5s,因为它的工程化程度最高、导出转 RKNN 的坑最少。如果你想让精度再高一些,YOLOv8s 也可以,但需要多处理一些细节,后面的章节我会单独提到。
2.2 模型选型:YOLOv5s 是当前平衡点
YOLO 家族版本很多,从 YOLOv3 到 YOLOv8、YOLOv9、YOLOv10,每个版本都有各自的优势。但我做端侧项目时首选 YOLOv5s,原因是三个维度:
第一是部署成熟度。YOLOv5 的 GitHub 仓库维护周期长、社区资料多,针对 RKNN 转换的踩坑文档一搜一大把,遇到问题能快速找到解决方案。相比之下,YOLOv8 虽然结构更先进,但导出 RKNN 时偶尔冒出来一些奇怪的算子兼容问题,排查周期长。
第二是速度与精度的平衡。YOLOv5s 的 mAP 在 COCO 上约 37,参数量 7M 左右,FP16 推理在 RK3588 上单次耗时约 20-30ms,完全满足售货柜的实时识别需求。换成 YOLOv5m 精度更高(mAP 约 45),但参数量涨到 21M,推理时间翻倍,对于摆满 20 个商品的柜子来说,精度溢出且速度吃亏。
第三是部署链路完整。YOLOv5 的 export 脚本原生支持 ONNX 导出,RKNN Toolkit 对 ONNX 的支持度最好的就是 YOLOv5 的输入输出格式(1x25200x85 这种经典结构)。YOLOv8 的 export 也能出 ONNX,但输出格式是多个头的分离张量,需要额外写后处理聚合代码,麻烦不少。
需要提醒的是,YOLOv5 官方仓库已经停止更新,但这不影响它作为稳定版使用。基础功能完全够用,而且社区的成熟方案仍然是最多的。
2.3 数据策略:先小后大,先粗后细
很多新手一上来就采集几千张商品图,然后花一周时间标注,结果训练出来效果感人。我推荐的反而是“小步快跑”策略:第一轮只取每个商品 100-150 张有效样本,训练一轮把流程跑通,确认环境没问题、代码没问题,然后再追加数据做第二轮优化。
这么做有几个实际好处:
- 第一轮数据量小,标注工作量低,能在 1-2 天内完成从数据到训练到部署的全链路验证;
- 如果数据本身有问题(比如类别标签标错、图片曝光过度),小数据集上能快速暴露;
- RKNN 转换和板端部署的坑尽早踩完,后面只需要迭代模型文件而不需要重走部署流程。
我第一版数据集总共只有 18 类商品、每类 120 张图,训练了 300 轮,mAP 就达到了 0.93。后来补充到每类 300 张,mAP 涨到 0.97。在无人售货柜这种封闭场景里,0.93 已经能用了,0.97 算是稳定商用线。
3. 环境搭建:从零跑通 YOLO 训练的前置条件
3.1 本机环境要求与镜像选择
训练 YOLO 并不需要多夸张的硬件。我用的主机是某款常见的消费级显卡(8GB 显存),训练 YOLOv5s 时 batch size 设置为 16,图片 640x640,完全没有压力。如果你的显卡只有 4GB 显存,把 batch size 降到 8 或者 4 也能跑,只是训练时间会长一些。实在连 GPU 都没有,用 CPU 训练也能训,但一个 300 轮的训练可能要跑 2-3 天,建议还是想办法搞一张显卡,哪怕是云 GPU 按小时租也行。
系统环境建议 Ubuntu 20.04 或 22.04,Windows 也能跑但坑更多。需要提前装好的组件清单如下:
- Python 3.8-3.10(推荐 3.8,兼容性最好)
- CUDA 11.7 + cuDNN 8.5(根据你的显卡驱动版本选对应的 CUDA,别盲目装最新版)
- PyTorch 1.13 或 2.0(1.13 在 RKNN 转换链路上踩坑最少,2.0 也没大问题)
- OpenCV 4.x(图像读取和预处理要用)
如果你不想手动装 CUDA,直接用 PyTorch 官方提供的 Docker 镜像最省事:
bash复制docker pull pytorch/pytorch:1.13.1-cuda11.6-cudnn8-devel
3.2 创建虚拟环境与安装依赖
虚拟环境推荐用 conda,环境隔离干净,出问题直接删掉重建,不影响系统 Python。创建和激活命令如下:
bash复制conda create -n yolo_env python=3.8
conda activate yolo_env
然后进入项目目录,安装 YOLOv5 的依赖。YOLOv5 仓库提供了 requirements.txt,直接一条命令装完所有基础依赖:
bash复制git clone https://github.com/ultralytics/yolov5
cd yolov5
pip install -r requirements.txt
有些机器上 OpenCV 装的是开源版,某些函数(比如 imshow 窗口显示)无法使用。训练脚本本身不用 imshow,所以不影响训练,但可视化检测结果时如果遇到报错,就换成 opencv-python-headless 或补装 opencv-contrib-python。
安装完成后,验证 PyTorch 是否真的能用 GPU:
bash复制python -c "import torch; print(torch.cuda.is_available())"
输出 True 说明 GPU 环境正常,输出 False 就要检查 CUDA 版本和驱动是否匹配。
3.3 测试 YOLOv5 预训练模型
在准备自己的数据之前,先跑一次官方预训练模型,确认整个推理链路是通的。执行以下命令下载 yolov5s.pt 并对一张测试图做预测:
bash复制python detect.py --weights yolov5s.pt --source data/images/bus.jpg
如果能在 runs/detect/exp 目录下看到带检测框的结果图,说明环境 OK。这一步很重要,能排除 90% 的环境问题,避免后面数据有问题还是环境有问题分不清楚。
4. 数据准备:标注工具选型与数据集组织
4.1 采集商品图片的实操规范
无人售货柜的商品图片采集听起来简单,实际有很多门道。我总结了几条刚需规范:
- 每类商品至少采集 80 张原始图片,理想是 150-300 张;
- 图片必须覆盖不同角度(正视、左侧 45 度、右侧 45 度、俯视),因为客户拿商品时手会从各个方向伸进去;
- 光照要模拟真实柜内环境——冷白光、暖黄光、半遮挡阴影,最好直接用柜子自带的 LED 灯照明拍摄;
- 每个商品要单独摆拍,同时也要拍“满柜组合图”,再从中裁剪出单商品样本,这样能模拟真实场景下的相互遮挡关系;
- 不要只拍纯色背景图,无人售货柜内部的背景通常是黑色或深灰色的层架,最好在同样的背景下拍摄。
采集到的原始图先做一次人工筛选,把模糊的、过曝的、商品不完整的全部删掉。这一步宁缺毋滥,模糊图进数据集会拉低整体精度。
4.2 标注工具选择与标注要点
标注工具我试过 LabelImg、Labelme、CVAT,最后固定用 LabelImg。满足 YOLO 格式的 txt 输出、支持快捷键、轻量级打开快。安装方式很简单:
bash复制pip install labelImg
如果 pip 安装失败,直接去 GitHub 仓库拉源码运行也能用。
启动后在标注前先设置好保存格式为 YOLO:
bash复制labelImg
标注的几条核心纪律:
- 框要紧贴商品轮廓,不要留太多背景,也不要切掉商品边缘;
- 遮挡严重的商品可以不标,让模型学了反而混乱;
- 类别名称统一定义,比如
coca_cola_330ml,不要一会儿用coke一会儿用cola; - 单个图片里如果出现多个商品,全部框出来,不要只标注中间那个。
标注完成后,每张图片对应一个同名 .txt 文件,内容是:
code复制class_id x_center y_center width height
这里 x_center、y_center、width、height 都是归一化后的值(0-1 之间)。我没法在文本里演示具体坐标,但这个格式看几个文件就能理解。
4.3 数据集目录结构与划分
YOLOv5 要求数据集按特定目录结构存放:
code复制dataset/
├── images/
│ ├── train/
│ ├── val/
│ └── test/
└── labels/
├── train/
├── val/
└── test/
建议比例:train 占 70%,val 占 20%,test 占 10%。划分时要注意两点:一是确保每个类别在 train 和 val 里面都有分布,别出现某种商品只在 train 里出现过、val 里一直没有;二是同一种商品的不同图片要随机打乱后再划分,别把同一批拍摄的连拍图全部放进 train,否则验证集的意义就没了。
划分好的图片和标签文件名要一一对应,比如 img_001.jpg 对应 img_001.txt。检查对应关系可以用一个简单的 Python 脚本:
bash复制python check_labels.py
这个脚本的功能是遍历所有 txt 文件,检查每个 txt 对应图片是否存在、以及 txt 中的类别 ID 是否在合法范围内。这种小工具很有用,能帮你提前发现标注数据的问题。
5. 训练全流程:从配置修改到模型评估
5.1 数据配置文件:写清楚类别和路径
YOLOv5 用 YAML 文件管理训练数据配置。在 yolov5/data 目录下新建一个文件,命名为 goods.yaml,内容如下:
yaml复制train: ./dataset/images/train
val: ./dataset/images/val
nc: 18
names: [
'coca_cola_330ml',
'pepsi_330ml',
'sprite_330ml',
'fanta_330ml',
'nongfu_spring_550ml',
'ice_tea_500ml',
'coffee_can_250ml',
'energy_drink_250ml',
'milk_tea_350ml',
'cracker_100g',
'chocolate_bar_50g',
'potato_chips_70g',
'instant_noodles_cup',
'cookie_box_200g',
'candy_box_100g',
'gum_pack',
'mineral_water_1L',
'orange_juice_300ml'
]
注意一个容易踩的坑:nc(类别数量)必须和 names 列表的实际长度一致。名字顺序也要和标注工具里定义类别的顺序完全一致,否则训练时模型会把类别 ID 完全学反,推理结果全错。
5.2 训练参数怎么选:一次说清关键超参数
YOLOv5 训练命令最精简的版本是这样:
bash复制python train.py \
--data goods.yaml \
--weights yolov5s.pt \
--img 640 \
--batch 16 \
--epochs 300 \
--device 0
但这里有个新手常挂的坑:如果用的是预训练权重 yolov5s.pt,模型会把 COCO 的 80 类输出头结构调整为我们的 18 类。这个过程 YOLOv5 会自动完成,但需要保证数据配置文件里 nc=18,否则预训练权重加载时会报 shape mismatch 错误。
几个关键超参数的调整逻辑:
--img 640:输入图片尺寸。如果商品在画面里较小,可以调到 960 提升精度,但训练时间会明显增加,且后续 RKNN 转换和推理延迟会增大。无人售货柜的摄像头离商品不远,640 是性价比最优解。--batch 16:显存足够的话,大 batch 能加快训练收敛,但 batch 太大容易过拟合小数据集。第一轮训练建议 16,如果数据量超过每类 500 张再考虑 32。--epochs 300:数据集在几十到几百张每类时,300 轮足够。训练过程中观察 loss 曲线,如果 loss 在 200 轮后还在明显下降,就加大到 400 轮。--device 0:指定使用 GPU 0。CPU 训练用--device cpu,但速度会慢到让人怀疑人生。
如果不想手动调这些参数,也可以在 train.py 脚本里的 parse_opt 函数直接改缺省值,这样后续每次跑命令就不用带一堆参数了。
5.3 训练过程中的观察指标:loss 和 mAP 怎么看
训练启动后终端会实时打印类似下面的信息:
code复制Epoch gpu_mem box obj cls labels img_size
1/300 7.81G 0.098 0.032 0.017 15 640
重点看三个 loss:box(框回归损失)、obj(目标置信度损失)、cls(分类损失)。三者都呈下降趋势说明模型在正常学习。如果某个 loss 先降后升,说明学习率太大在震荡,需要把初始学习率调低。YOLOv5 默认初始学习率是 0.01,用 SGD 优化器时通常没问题,但如果数据量很小(每类几十张),建议降到 0.005。
训练结束后,结果保存在 runs/train/exp 目录下。重点看 results.png 这张汇总图,里面有 mAP@0.5、mAP@0.5:0.95、precision、recall 的曲线。YOLOv5 默认输出 PR 曲线,曲线越靠近右上角效果越好。
对我这个商品数据集,第一轮训练结束后的指标大致是:
- precision: 0.96
- recall: 0.93
- mAP@0.5: 0.93
这已经达到无人售货柜的最低可用线。如果某类商品的 AP 特别低(低于 0.8),大概率是图像数量不足或标注框不准确,针对该类补充数据后单独再训一轮。
5.4 从训练结果中导出最佳权重
训练结束后,runs/train/exp/weights 目录下有两个文件:best.pt 和 last.pt。best.pt 是验证集上 mAP 最高的那一轮权重,last.pt 是最后一轮的权重。部署时一定用 best.pt,不要用 last.pt,因为训练后期可能过拟合,最后一轮权重在验证集上的表现不一定比中间轮次好。
把这个 .pt 文件先拿到本机测试一下推理效果:
bash复制python detect.py --weights runs/train/exp/weights/best.pt --source test_images/ --conf-thres 0.5
--conf-thres 0.5 表示置信度低于 50% 的框不会被画出来。无人售货柜场景建议设 0.4-0.5 之间,太低了容易误检,太高了又容易漏检。
6. 模型导出与 RKNN 转换:从 PyTorch 到板端
6.1 导出 ONNX 格式的中间模型
RK 的 NPU 不直接吃 PyTorch 的 .pt 文件,需要先转成 ONNX,再通过 RKNN Toolkit 转成 RKNN 格式。所以第一步是导出 ONNX:
bash复制python export.py --weights runs/train/exp/weights/best.pt --img 640 --batch 1
导出完会生成 best.onnx。这里有个关键参数不能漏:--batch 1,因为 RK 平台推理固定单图输入,batch 大于 1 会造成转换失败或推理异常。
导出后建议用 Netron(一个在线模型可视化工具)打开 ONNX 文件看一眼,确认输入节点名是 images,输出节点名是 output0,形状是 [1, 25200, 18+5]。25200 来自 640x640 输入下三个检测层的 anchor 总数(80x80 + 40x40 + 20x20),后面 RKNN 转换和板端后处理都要用到这个数字。如果输出形状不对,大概率是导出参数有问题。
6.2 RKNN Toolkit 安装与模型转换
RKNN Toolkit 的安装过程在不同版本的 RK 芯片上有差异,但整体思路一致。以 RK3588 为例,在 PC 上安装 RKNN Toolkit2:
bash复制pip install rknn-toolkit2
然后写一个转换脚本 convert_rknn.py,核心逻辑如下:
python复制from rknn.api import RKNN
rknn = RKNN()
rknn.config(
mean_values=[[0, 0, 0]],
std_values=[[255, 255, 255]],
target_platform='rk3588'
)
rknn.load_onnx(model='best.onnx')
rknn.build(do_quantization=True, dataset='dataset.txt')
rknn.export_rknn('goods.rknn')
这段代码里有三个关键细节需要展开:
mean_values和std_values必须与 YOLOv5 训练时的归一化方式一致。YOLOv5 默认会把像素值除以 255 归一化到 0-1,所以标准差设置为 255,均值设置为 0。写反了会导致推理效果暴跌。do_quantization=True表示启用 INT8 量化。YOLOv5s 从 FP16 量化到 INT8 精度损失通常在 1% 以内,但换来的推理速度提升接近 2 倍,这个交易非常划算。dataset.txt是一个文本文件,里面每一行是用于量化校准的图片路径,推荐放 100-200 张训练集的图片,不要放验证集,避免量化过程“作弊”。
量化校准跑完后,会在当前目录生成 goods.rknn。这个文件拷贝到 RK 板子上就可以通过 RKNN Python API 或 C API 调用了。
6.3 板端推理验证:先跑通再优化
在板子上跑推理前,建议写一个最小验证脚本,只加载模型、跑一张图、打印检测结果。这个脚本的目的不是做完整业务逻辑,而是验证模型转换是否成功、推理输出是否符合预期。
核心验证代码片段如下:
python复制from rknn.api import RKNN
rknn = RKNN()
rknn.load_rknn('goods.rknn')
rknn.init_runtime(target='rk3588')
img = cv2.imread('test.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (640, 640))
outputs = rknn.inference(inputs=[img])
拿到的 outputs 是一个 Numpy 数组,形状是 [1, 25200, 23](23 = 18类 + 4个框坐标 + 1个置信度)。先打印一下它的 shape 和数值范围,确认输出非空、数值量级正常。接下来再用非极大值抑制(NMS)过滤出最终的检测框。
NMS 的 Python 实现有很多现成代码,这里给出 YOLOv5 里最精简的处理思路:
- 从 25200 个候选框中选取置信度大于阈值的框;
- 按类别分别做 NMS,同类框之间 IoU 大于 0.45 的保留高分框、删除低分框;
- 输出框坐标映射回原图尺寸。
这一步如果发现检测结果偏移很大,优先检查 mean_values 和 std_values 配置,以及输入图像是否做了 RGB 通道调整。另一个常见问题是量化后精度下降明显,这时把 do_quantization 改为 False,转出一个 FP16 的 RKNN 模型对比一下,如果 FP16 精度正常,说明是量化校准集选得不好,重新挑量化图片路径即可。
7. 常见问题与老手才知道的避坑技巧
7.1 训练阶段高频问题速查表
训练阶段的问题最多,我把踩过的坑整理成了一张速查表,每个问题都带解决方案。
| 现象 | 根本原因 | 处理方法 |
|---|---|---|
| loss 一直是 NaN | 学习率过大或标注文件有非法值(坐标 > 1) | 降低学习率到 0.001,用脚本检查所有 txt 文件坐标是否在 0-1 区间 |
| mAP 卡在 0.8 上不去 | 某类商品图片过少,或标注类别混淆 | 给低 AP 的类别补 50-100 张新图,review 标注框 |
| 训练时 CPU 占用 100% 但 GPU 占用 0 | DataLoader 的 num_workers 设置过小或数据读取瓶颈 | 增加 --workers 8;图片先全部 resize 到 640 再训练 |
| 验证集上检测很好但训练集上检测很差 | 过拟合,数据变化不够 | 增强数据扩充:加翻转、旋转、亮度变化;同时考虑加正则化 |
| 检测出大量重叠框 | NMS 阈值设置过高(0.7 以上) | 降低 NMS IoU 阈值到 0.45-0.5 |
| 某些类别完全检不出 | 该类别在 train 中的数量过少或与其他类别外观太相似 | 增加该类别的样本量,且保证样本中不同角度和场景都有覆盖 |
7.2 RKNN 转换与板端部署典型问题
问题 1:rknn.load_onnx 报错算子不支持
YOLOv5s 的 ONNX 导出很少遇到算子不支持的报错,但如果用了 YOLOv8 或者改过网络结构,就可能碰到。解决办法是:优先换回 YOLOv5s 结构;如果必须用 YOLOv8,去 RKNN 官方文档里查不支持算子的替代实现。
问题 2:量化后 mAP 跌了 3 个点以上
首要怀疑量化校准集的代表性问题。校准集应该覆盖所有类别的所有典型外观,且每张图片的内容多样性要高。我试过用 50 张全是可乐的图片做校准,结果其他 17 类商品的量化精度全面崩盘。正确做法是从每个类别里均匀抽 5-10 张图,凑 100 张左右的校准集。
问题 3:板端推理时间比预期高
先确认用的是 RKNN 的 C API 还是 Python API。Python API 有解释层开销,通常比 C API 慢 20-30%。如果对延迟敏感,建议最终切换到 C API 部署。另外,输入图像尺寸是否真的是 640x640 也要检查,LLM 里 cv2.resize 后再输入,不要直接把大图喂进去让 RKNN 内部做缩放。
7.3 无人售货柜特定场景的额外技巧
无人售货柜有两个普通目标检测项目不会遇到的特有问题:
第一是镜面反光。柜门玻璃或商品包装的反光会产生大量误检。解决方案是在后处理阶段加入“反光抑制”:检测到商品区域的高光像素占比超过 60% 时,将该框的置信度降低,若低于阈值则不输出。这个规则在真实柜子上测试后,误检率降低了 40% 左右。
第二是商品缺失检测与数量统计。很多售货柜需要知道“什么商品被拿走了几件”,而不是只在一次拍照里识别有哪些商品。此时建议对开柜前和关柜后各做一次检测,再根据两次结果做差集。注意前后两次检测的商品框对齐要基于柜内固定参考点,否则同一商品在两次检测中的坐标微位移会导致数量统计错误。
8. 后续可以怎么扩展
整套流程跑通之后,后续的扩展方向就非常多了。我这里简单列几条实际也有价值的方向。
工程化方面,可以把手动采集图片换成自动数据管道,在柜子上接入摄像头,每天自动采集一批新图片并做半监督标注,持续迭代模型。这样商品换包装、新增商品上线时不需要重新搭建环境,只需要增量数据训练。端侧推理方面,可以把 Python API 换成 C API,结合 RK 的 zero-copy 接口把推理延迟压到 10ms 级别,同时接入多路摄像头并行处理。算法方面,如果商品种类超过 30 类,并且同一类商品有多个不同包装版本,可以尝试把 YOLO 的检测头换成解耦头或者引入注意力机制,进一步提升细粒度识别能力。
我个人的体会是,无人售货柜这个方向看起来不难,但真正落地时要兼顾的因素非常多:数据质量决定了模型上限,部署链路的稳定性决定了项目能不能交付,而后处理的细节决定了用户体验。前面这一整套流程,每一条经验都是用实际项目换来的,照着走一遍,你会少踩很多坑。尤其提醒一句:RKNN 转换后一定要在真实柜子环境里验证效果,实验室里跑得再漂亮,也不如柜门一开一关来得真实。
