年初我在某中转仓做库存巡查方案时,发现最耗人手的不是装卸,而是盘库和外观巡检。仓库主管跟我说:地面货摆得又多又密,让两个人拿着扫码枪一排一排扫,扫完数据还经常对不上账。我当时就提了一个想法:与其让人绕着货架转,不如做一台能沿着货道自己跑的货物巡检智能小车,同时带上 RFID 和视觉两套感知,把“这个托盘上是哪些货”和“这批货外观是否完好”一次问清楚。这个项目的核心就是把这两套传感器装到一辆能自主跑动的小车上,做成一套可以实际用来替代人工巡检的原型系统。下面这篇东西,不是产品说明书,是我从选型、搭硬件、写逻辑到上线路测一路走下来的复盘,适合正在做仓库巡检、AGV 底盘集成、或者想用 RFID 加视觉做识别校验的朋友参考。
1. 为什么巡检车最后拆成了 RFID 和视觉两条腿
做方案之前我先算了一下人工巡检的时间账。一个六百平米左右的库区,货位加上走道,人工拿着手持终端扫一遍,正常节奏是两个人轮流,全程大概一个半小时。这还只是盘点数量,如果要同时检查每一托货物的包装有没有破损、有没有歪斜、封箱带有没有翘起,时间会再翻一倍。
人工巡检还有两个更麻烦的问题:一个是数据不及时,扫完回去录入系统,发现某货位少了一件,实际是什么时候少的基本不知道;另一个是外观检查靠人眼,光线不好的角落、堆叠高的顶层,很容易漏看。
所以这个项目从一开始就不是单纯做个“会跑的扫码枪”,而是要把两个互补的信息维度结合起来。RFID 擅长的是远距离批量识别,只要小车从货道经过,读写器扫过托盘区,几秒内就能把这一片区域的标签 ID 批量读出来,用来核对“这个库位应该有哪些货、数量对不对”。但它有一个致命短板——它只知道标签在不在,不知道箱子长什么样、有没有破。视觉恰好补上这一块,摄像头可以看到箱体表面有没有凹陷、侧面有没有被叉车蹭破、货物有没有超出托盘边界。反过来,视觉也有短板,它在光线差、遮挡多的时候容易漏识别,这时候 RFID 又可以先锁定目标区域和货物编号。
我把需求拆成了三个能被算法直接回答的问题:
- 当前库位实际读到了哪些 RFID 标签?和系统台账记录的是否一致?
- 这些标签对应的货物,是否都能在视觉画面中找到对应物?
- 找到对应物之后,包装外观是否有可见异常?
第一个问题交给 RFID,第二、第三个问题交给视觉,两者通过时间戳和库位编号做关联。小车只需要按固定路线行驶,在每一个预设停靠点完成一组“RFID 盘点 + 视觉检查”的动作,数据统一打上库位标记,再汇总到后台。整个系统的复杂度其实不高,难点全在工程细节上。
2. 硬件选型里最花时间的不是底盘,而是天线和镜头的位置
2.1 底盘与驱动方案
底盘我用了最常见的四轮差速设计,前两轮是万向轮或从动轮,后两轮由直流减速电机驱动。选这个结构不为什么高大上的理由,就是因为仓库过道窄、需要频繁启停,差速底盘转弯半径小,控制逻辑也简单。
电机选了带光电编码器的 12V 直流减速电机,编码器用来测轮速和里程,这是后面做路径规划和到位判断的基础。驱动部分用双 H 桥驱动板,主控选的是 Cortex-M 系列 32 位 MCU,负责电机 PWM 控制、编码器采集、避障传感器输入和最基本的运动指令解析。
这里有个很容易踩的坑:不要把电机控制和视觉处理放在同一块开发板上。电机控制需要实时响应,PWM 周期必须稳定,一旦被图像解码这种耗时操作打断,转速就会上下抖。我最后分成两套硬件——下位 MCU 专门管电机和底盘,上位用一块 Linux 单板主机跑视觉算法和任务调度,两者用串口通信。这样不管视觉算多久,轮子都能保持稳定运行。
2.2 RFID 与摄像头选型
RFID 部分,我选的是超高频 (UHF) 读写模块。这个判断基于一个简单逻辑:仓库里的货物标签基本都用超高频,工作面在 840MHz 到 960MHz,读取距离能达到 1 到 3 米,批量盘点时性能远好于高频方案。天线选了平板天线,方向性强,能聚焦到小车一侧的货架上,而不是四周乱读。
这里有一个选型表可以参考:
| 模块 | 关键参数 | 我在这套系统里的用法 |
|---|---|---|
| 下位主控 | Cortex-M 系列 32 位 MCU | 电机控制、编码器计数、串口协议转发 |
| 上位主机 | Linux 单板机,带 USB 接口 | 跑视觉处理、任务状态机、数据库交互 |
| 电机组 | 12V 直流减速电机 x2,带编码器 | 后轮差速驱动,编码器用于里程计 |
| 驱动板 | 双 H 桥驱动模块 | 输出 PWM 控制电机,带电流限制 |
| UHF 读写器 | 840~960MHz 频段,USB/串口输出 | 读取货物标签,输出 EPC 和 RSSI |
| 平板天线 | 8dBi 左右增益,定向 | 固定在车体一侧,朝向货架 |
| 摄像头模组 | 1080P,手动对焦,广角 | 安装在车头,向下约 20 度俯角 |
| 避障模块 | 超声波或激光测距 | 低速前进时的紧急刹车保护 |
摄像头我选了 1080P 定焦广角模组。这里的考虑是:巡检车在货道内运动速度不会超过每秒 0.3 米,1080P 分辨率足够看清包装箱上的条形码和明显破损痕迹。广角镜头能覆盖一个完整货位的宽度,手动对焦比自动对焦更可靠,因为自动对焦在光线变化时容易来回拉风箱,导致图像忽糊忽清晰。
2.3 天线与摄像头的位置布局
这一节我单独拎出来说,因为很多人的失败都栽在安装布局上。RFID 天线不是随便贴在车侧面就行的。平板天线有波束角,货架上的标签一般在 0.5 米到 1.8 米高度范围,如果天线装得太低,波束只能打到货架底层,中高层标签大片漏读。
我最后把天线安装在离地约 40 厘米的位置,并让天线平面向货架方向倾斜约 30 度,这样波束中心正好覆盖货架中部到顶部。摄像头装得比天线高一些,离地约 60 厘米,向下倾斜 20 度,画面里面能同时看到托盘底部和堆垛中上部的箱体。安装完成后,我用一个贴着标签的纸箱从不同高度扫过一遍,观察读写器读到 RSSI 的连续性,来确定天线倾斜角是否合适。这个步骤务必在贴车之前做,否则焊死了再改会非常痛苦。
3. 控制逻辑与数据流:小车是怎么把一次巡检跑明白的
3.1 上下位机的串口协议设计
上下位机之间我用串口通信,波特率 115200,协议是自己定的一帧十六字节定长帧。结构很简单:帧头、数据长度、命令字、若干数据字节、CRC 校验。命令字大概分成几类:下发任务、上报位置、上报避障状态、请求停车、恢复行驶。
这套协议不需要复杂,但有一点必须注意:所有运动状态变化都要带一个递增的帧序号。否则上位机发了一个“前进”,下位机还没执行完又收到一个“前进”,执行结果无法追踪,调试时根本不知道是哪一帧出了问题。
3.2 任务状态机
巡检过程被我拆成一个典型状态机:
- 空闲:等待定时任务触发,或等待后台指令。
- 行驶:沿着预设路径前进,保持目标速度。
- 停靠:到达目标货位点,刹车,进入识别流程。
- 识别:同时执行 RFID 盘点和视觉拍照,期间小车静止。
- 判定:比对识别结果,生成正常或异常记录。
- 继续/返回:完成全部巡检点后回到起点。
3.3 数据流和异常关联
小车在每一个停靠点做两件事:RFID 读卡器连续盘点约三秒,得到该位置附近所有标签 ID 列表;摄像头同时抓取当前货位的两张照片。两张照片的拍摄时间分别对应 RFID 盘点前和盘点后,这样即使有移动中的叉车干扰,也能有一个对比。
后台做一个简单的关联逻辑:把 RFID 列表和台账里预先录入的“该库位应存放货物表”做差集。多出的标签是高危信号,说明这位置多了不该有的货;缺失的标签说明可能被挪走或漏检。然后在视觉检测结果里找对应箱子,如果箱子轮廓异常,就在异常记录里附上照片编号。
这套流程本身不复杂,但工程量在于处理各种边界情况。举个例子:一个标签在盘点窗口的后半段才进入读写器范围,第一次盘点没读到,第二次读到了,这时候不能直接判定为“缺货”,而应该标记为“待复核”。我们后来把所有 RFID 盘点结果都带了 RSSI 和时间序列,后台可以判断标签是持续存在还是偶发出现,大幅度降低了误报。
4. RFID 调优:好用的识别效果是从天线角度和功率里磨出来的
4.1 读写器参数设置
如果你以前只拿手持机扫过单标签,可能觉得 RFID 就是“靠近就读取”。到了批量盘点场景,事情就没那么美好了。读写器发射功率、天线增益、标签摆放方向、货架金属结构,每一样都能让结果天差地别。
我用的读写模块支持调节发射功率,范围大概在 17dBm 到 30dBm。理论上是功率越大读得越远,实际测试中在金属货架密集区域,功率开大了反而会引发严重多径反射,结果就是读到一堆本不该在这个位置出现的标签,或者同标签在几个货位之间反复横跳。
我的调试方法是:先设定一个中等功率(约 23dBm),把小车停在某个货位正前方,记录该货位所有应读标签的 RSSI 分布。然后逐渐降低功率,直到出现在保留区的标签数刚好只剩两台最边缘货位。再用这个值作为默认巡检功率。遇到特别偏远的货架,再局部把功率调高。总之功率不是越大越好,能让“该读的都读到,不该读的读不到”就是合适的。
4.2 漏读与误读的典型场景
漏读最常见的场景是标签贴在纸箱侧面,纸箱靠在一起时标签被夹在缝隙里,天线波束打不进去。这种状态下只能调整标签贴合策略,让库房在入库时尽量做到标签面向过道。这是业务层面和硬件层面配合的事。
误读则更多来自金属货架的反射。UHF 信号打到金属表面会反射,如果货架立柱正好形成了一种反射腔体,某些离得远的标签也会被“搬”到当前货位来。一个有效对策是启用读写器的 RSSI 阈值过滤,只保留信号强度高于某个水平的盘点结果。这是我在集成测试中摸索出来的确定有效的一招。
4.3 让“连续两次读到”成为默认规则
在自动巡检场景下,运动中的小车天线覆盖角度一直在变,单次盘点结果天然不稳定。我有两个减少误判的小技巧:
第一,在每个停靠点把盘点窗口拉长到 3~5 秒,读写器连续发起多轮盘点,后台只保留至少被读到两次的标签作为“确认存在”。
第二,启动防碰撞算法里的多标签轮询参数,把每次轮询的最大标签数调大到 32。标签不多时可以保持较低的轮询策略,但遇到整托几十个标签同时进场,轮询数太小会导致大量标签“超时未响应”。
还有一个很多人忽略的细节:盘点窗口结束前一秒,小车必须保持完全静止。哪怕只是轮子轻轻挪动几厘米,天线的相位中心位置变了,就可能让盘点到一半的标签掉线。我把“稳定停车”写进了状态机的停靠时序里,先刹车,等待 500ms,再开始盘点。
5. 视觉算法:把“包装有没有破”变成可判定的规则
5.1 视觉模块的三项任务
我把视觉任务明确成三件事:读码、测轮廓、评纹理。读码是为了和 RFID 交叉验证,防止标签被误读或货车错位;测轮廓是为了判断货物有没有超出托盘边界、堆垛有没有明显歪斜;评纹理则是检测箱体表面的破损凹陷。
读码这块,我用的是开源视觉算法库里的条形码解码功能。实际运行中最大的问题是距离和角度。直接对着箱体正面拍,条码在画面里占比小,识别率不高。我把识别程序做成连续帧处理,当小车缓慢驶过货位时,会抓取 5 到 10 帧画面各自尝试解码,只要能从中解出同一个条码,就认为识别成功。这样比单帧识别成功率高出不少。
5.2 破损检测的规则法实现
破损检测我没有一上来就上深度网络,原因很实际:一是没有足够的破损样本;二是仓库现场树影、反光、胶带阴影都会造成误报;三是在 Linux 单板上跑大模型推理,发热和功耗都麻烦。
我用的是一套“规则为主、统计辅助”的方案:将拍摄到的整箱画面分割成网格区域,对每个区域计算边缘密度和灰度梯度异常值。正常瓦楞纸箱表面纹理均匀、边缘线平直;破损区域通常表现为边缘密度突然增大、局部灰度变化剧烈,或者出现不连续的长直线。用一个很简单的阈值判定,就能把明显凹陷、撕裂、压痕这类问题筛出来。
举一个具体的判断逻辑:对图像边缘检测后,提取图像中的长直线段,正常情况下箱子边缘都是横平竖直的。如果检测到大量非水平非垂直的短线簇,就说明表面可能有皱褶或破损。这个方法对“箱子被压出一个凹坑”特别敏感,因为凹坑边缘会产生一圈放射状短线。它也有误报,比如封箱胶带起皱就可能触发,但这属于可以接受的复核范围。
5.3 光照是视觉最大的敌人
仓库里的光照是轮流折磨人的东西。靠窗区域白天强光,夜里只有冷白灯管,而且荧光灯频闪会让摄像头画面出现明暗条纹。我解决这个问题的方式是:禁用摄像头的自动曝光和自动白平衡,把曝光固定在一个略暗的基准值上,再用一个补光灯珠板补光。
补光灯的选择也有讲究,我试过红外补光和普通白光。红外光对颜色还原有影响,后来还是选了色温中性的白光。灯光装在摄像头两侧,形成与前向物体约 45 度夹角的照明,这样纸箱表面的凹陷会形成明显阴影,更利于规则检测。这项操作让视觉检测在白天和夜间的识别效果基本拉平。
6. 轮子控制与到站精度:让巡检车少跑偏的若干办法
6.1 路径引导方案
巡检车在仓库里的路径引导有很多方案,我最初考虑过给小车加激光雷达做同步定位,但成本高、调参周期也长。自己做一个固定巡检小车,最终选的是“磁条 + 编码器”的组合方案。
在地面上贴一条 3 厘米宽的磁条作为主路径,小车底部装有一组磁传感器阵列,可以判断车体相对磁条的横向偏移。正常行驶时,磁传感器给出横向偏差,底层 PID 控制器实时纠正转向;在直线段和弯道入口,再根据编码器里程数据判断当前距离前方目标库位还有多远,从而提前减速。
6.2 速度规划与 PID 调试
底盘控制的核心是速度平滑。如果小车从全速突然急停,惯性会让货物产生移动,同时也会让摄像头画面剧烈抖动,直接影响视觉识别。我为每一段路径增加了梯形加减速规划,让加速度限制在一个较小数值。这个过程直接把电机 PWM 给到固定值再停下来要复杂得多,但效果立竿见影。
PID 参数我采用了一套很直观的调法:先只调比例项,增益从小到大,观察小车在直线上有没有左右摆振。如果出现高频摆振就把比例增益减小,如果直线偏移一直收敛不掉,再逐步加入积分项。微分项我调得最小,因为在磁传感器信号里有轻微噪声,微分增益过大反而会把噪声放大成抖动。
6.3 到位停止的“软刹车”
到货位前约 30 厘米时,我让小车进入低速蠕动模式,速度降到每秒 0.05 米,一个编码器计数的变化对应不到几毫米的位移,然后根据前置测距传感器的测距值触发最终刹车。刹车不是直接抱死,而是让电机先反接制动一小段时间,等车完全停下后,再释放轮子锁止。这样停车位置误差能控制在 2 厘米以内。
这个精度对 RFIFD 识别和视觉拍照都是很必要的。我实测过如果停车偏差超过 5 厘米,天线中心位置就开始偏离货架中心,边缘标签的 RSSI 会明显下降,拍照画面也会偏出目标货位。后来干脆在控制逻辑里加了“到位后偏差超过阈值则重试一次”的机制,宁可多花五秒重新找位置,也不要带着歪视角做识别。
7. 上线测试阶段踩过的坑(电源、串扰、反光、打滑)
7.1 电源纹波让 RFID 模块反复掉线
第一版系统联调时遇到一个奇怪现象:小车一启动电机,上位机的 USB 口就报设备断开。排查了很久才发现是电源分配问题。电机启动瞬间电流很大,造成整个 12V 母线电压瞬间跌落,上位机主板的 DC 输入也跟着掉压,USB 口的供电不够稳定,读写器就直接掉线了。
解决办法是把动力电源和传感电源完全分开:12V 电池直接给电机驱动板和电机供电;另一路通过独立的 DC-DC 电源模块稳压后给上位机和读写器供电。在 DC-DC 输入端并联一个大容量的电解电容,缓冲电机启动时的瞬时压降,之后再也没出现过掉线。
7.2 RFID 金属反射造成的串位误读
整个库区是重型货架,金属立柱非常多。第一次夜间无人试跑,后台导出的数据里出现了大量“不存在”的标签——一读到了一个应该在十几米外货架上的标签。就是金属反射导致信号顺着货架结构传导过来的。
我采用的对策是三管齐下:下调发射功率、开启 RSSI 阈值、增加“临近连续两轮读到”规则。调完后误读标签数量从每轮十几个降到了接近零,偶尔还会出现一两个 RSSI 特别强的漏网之鱼,但已经不影响最终判定。
7.3 摄像机反光和频闪
有一次白天试运行,识别程序突然大量误报“破损”,把一箱外观看上去没问题的货连续判成了异常。查看原图才发现,是一个不锈钢货架立柱的反光在箱子表面形成了一条超亮的光带,边缘检测把它当成了一条异常轮廓。
方案是调整摄像头安装位置,让它在正常行驶路线上避开直射反光角度,同时固定曝光值并适当降低画面饱和度。再加上补光灯,让箱体表面的主光源变成可控的漫射光,反光问题基本被压住了。
| 现象 | 根因 | 处理方式 |
|---|---|---|
| 上位机 USB 掉线 | 电机启动导致电源跌落 | 独立 DC-DC 供电,加滤波电容 |
| 读取到远处标签 | 金属货架反射 | 降功率,开 RSSI 过滤,双轮确认 |
| 视觉误报破损 | 不锈钢反光带 | 调整镜头角度,固定曝光,补光 |
| 停车位置偏差大 | 地面打滑、加减速过猛 | 速度规划限幅,低速蠕动到位 |
| 整排货位漏读 | 天线高度和角度不合理 | 重新做天线覆盖测试,前后倾斜角 |
7.4 地面打滑带来的里程漂移
仓库地面有的区域有灰尘,有的刚拖过,摩擦力不一致。编码器的里程数据在光滑地面出现打滑后会逐渐失真,表现就是小车明明还没到货位,程序已经认为到了,直接停住。
我加了一个校准机制:在磁条路径每隔几个库位埋一个独立的标记。小车经过标记时,程序把编码器里程强制重置为已知值,抵消之前积累的漂移。这个办法简单但可靠。巡检路径越长,标记点带来的纠偏收益越明显,关键转弯前也必须强制校准一次,否则过弯位置会跑偏。
8. 这辆车还能怎么演进:我接下来的三个计划
第一版原型能稳定跑完一整条巡检路线后,我开始考虑后续的演进方向。第一个计划是把自动充电功能加上。现在小车跑完一圈还是需要人搬回起点换电池,这削弱了“无人值守”的意义。加一个充电桩对接机构,并在导航逻辑里加入低电量回充动作,就能实现真正意义上的定时自发巡检。
第二个计划是在视觉部分引入故障样本学习。现在规则法能识别明显凹陷和撕裂,但对轻微褶皱、烟盒大小的渗漏等复杂异常识别能力有限。如果能收集两三个月运行中积累的异常照片,微调一个小型分类模型,就能把识别精度再往上推。
第三个计划是把巡检数据直接对接仓储管理系统的库存台账,形成每天自动更新的库位健康报告。现在我们的数据还是独立存储,靠人工导出,打通之后才能发挥出连续巡检的长期价值。
最后一点个人经验:做这种多功能巡检车,真正的成本大头从来不是传感器本身,而是反复调参和排除干扰的时间。RFID、视觉、运动控制,每一项单拎出来都不算新鲜,但组合在一起时,所有“边缘因素”——电源、振动、反光、金属环境——都会放大成主问题。如果你也在做类似的系统,我的建议是把底层稳定性打磨好之后再加算法炫技,基础越扎实,后面的路越省心。