一、条码靠"扫",RFID靠"喊"
在传统的仓储作业中,一托盘货到了库口,操作员需要拿着PDA,把上面的条码一个个扫一遍。如果是整托盘 50 箱货,可能需要 2 分钟。
RFID(无线射频识别)的出现改变了游戏规则。它不需要"视距"和"对准",只要标签在电磁场内,就能被读取。理论上,一托盘的货推进库口,两秒钟就能全部识别。但实际上,如果你直接把 100 个标签丢进读卡器范围,读取率可能会断崖式下跌。

为什么?因为发生了信号碰撞(Collision)。
二、时隙 ALOHA 算法:让标签排队"说话"
当读卡器发出"盘点"指令时,范围内的所有标签会同时响应。如果两个标签同时发声,信号叠加在一起,读卡器就什么也听不懂(类似于多个人同时在一个房间里大喊大叫)。
为了解决这个问题,RFID 协议(如 EPC Gen2)采用了**时隙 ALOHA(Slotted ALOHA)**算法。
它的核心逻辑是:时间分片,随机排队。
-
读卡器发出盘存指令,并广播一个参数 QQ(表示当前有多少个时间槽)。
-
标签接收后,随机在 0,2Q−10,2Q−1 中选一个数字。
-
读卡器在每个时间槽结束后,宣布"谁选了这个槽?",选了这个槽的标签就回答。
-
如果没有标签回答(空闲),或者多个标签回答(碰撞),读卡器就调整 QQ 值,继续下一轮。
这本质上是一个动态调整时间窗口大小的过程。如果 QQ 值太大,时间槽过多,效率低下;如果 QQ 值太小,碰撞频繁,识别速度慢。工程上需要根据现场环境动态调整 QQ 值。
三、动态 QQ 值调整算法实现
以下是一个简化的动态 QQ 值调整算法逻辑(基于实际观测到的碰撞率和空闲率):
java
public class QAlgorithm {
private int qValue = 4; // 初始 Q 值,窗口大小为 16
private static final double C_MIN = 0.1;
private static final double C_MAX = 0.5;
/**
* 根据上一轮的碰撞槽、空闲槽和成功槽计算新的 Q 值
*/
public int adjustQ(int emptySlots, int collisionSlots, int successSlots) {
double totalSlots = emptySlots + collisionSlots + successSlots;
if (totalSlots == 0) return qValue;
double emptyRatio = emptySlots / totalSlots;
double collisionRatio = collisionSlots / totalSlots;
// 根据 Q 算法标准(如 EPC Gen2 规范),
// 空闲过多说明窗口太大,减少 Q;碰撞过多说明窗口太小,增加 Q
if (emptyRatio > 0.5 && collisionRatio < 0.1) {
qValue = Math.max(0, qValue - 1);
} else if (collisionRatio > 0.5 && emptyRatio < 0.1) {
qValue = Math.min(15, qValue + 1);
} else if (collisionRatio > 0.1 && emptyRatio > 0.1) {
// 处于中间状态,使用微调逻辑
// 略去复杂的防抖动处理
}
return qValue;
}
}
在工程实践中,高性能的读写器固件(如 Impinj 芯片)内部已经实现了非常成熟的防碰撞算法。作为软件开发者,尽量不要自己重写底层防碰撞逻辑 ,而是通过配置(如 Session 级别、Target 模式)来优化阅读器的工作状态。
四、边缘计算:在源头过滤冗余数据
假设一托盘的 100 个标签被成功读取,读卡器可能在一分钟内连续刷新了 10 次,这就会产生 1000 条数据上报。如果每次都传给 WMS,会给后端造成巨大压力。
破局之道:边缘过滤 。
现代工业 RFID 读写器或边缘网关,应该具备本地去重和业务逻辑判断能力。
java
public class RfidEdgeProcessor {
// 维护当前托盘上正在读取的标签集合(缓存)
private Set<String> currentInventory = ConcurrentHashMap.newKeySet();
private long lastReportTime = 0;
private static final long QUIET_PERIOD_MS = 2000; // 静止期,2秒没有新标签算一轮结束
public void onTagRead(String epc) {
currentInventory.add(epc); // 去重加入本地集合
lastReportTime = System.currentTimeMillis();
}
// 后台定时任务:检查是否过了“静止期”
public void checkAndReport() {
if (!currentInventory.isEmpty() &&
System.currentTimeMillis() - lastReportTime > QUIET_PERIOD_MS) {
// 读取稳定,打包发送给 WMS
List<String> tagsToSend = new ArrayList<>(currentInventory);
sendToWms(tagsToSend);
// 清空缓存,准备迎接下一个托盘
currentInventory.clear();
}
}
}
这种**"防抖 + 批量合并"**的设计,不仅将网络通信量降低了 90%,还完美契合了仓库"一托盘一托盘操作"的物理规律。
五、硬件部署的三个"玄学"参数
-
功率与距离:读卡器的发射功率不能开到最大。如果功率太大,读到了隔壁通道的标签,就会导致"串读"(多件)。通常需要结合金属屏蔽和功率调整,把读取范围精准控制在一托盘之内。
-
标签朝向:RFID 标签有方向性。如果贴在商品底部的标签刚好在金属屏蔽层上,信号会被吸收。现场需要用特殊的抗金属标签,或者调整贴标规范。
-
抗干扰(Session 参数) :在传送带这种连续流动作业中,标签快速经过。需要将读卡器配置为
Session 1或Session 2模式,并启用Dense Reader Mode,防止多个读卡器之间互相干扰。
六、避坑指南
坑1:试图用软件去弥补硬件的安装缺陷。 如果天线角度不对,标签就是读不到。无论是防碰撞算法还是边缘计算,前提都是"信号能被天线捕捉到"。
坑2:依赖单次读取就下结论。 RFID 读取率永远达不到 100%。对于关键的高价值货物,必须配合红外传感器或视觉相机做"双保险"复核,否则极易导致漏发。
坑3:没有处理"串读"问题。 读卡器功率过大,或者金属环境产生反射,会把隔壁的货读进来。边缘网关需要结合物理位置(如通道门禁)过滤信号强度(RSSI),剔除明显来自远处的微弱信号。
七、总结
RFID 批量群读的核心挑战是"多标签碰撞"。通过时隙 ALOHA 的动态 QQ 值调整,可以实现标签排队;通过边缘计算完成标签去重和静止期合并,可以大幅降低后端压力。但硬件部署环境比软件算法更重要。只有在天线覆盖、标签朝向和功率控制都完美的前提下,RFID 才能实现真正的"秒级无感入库"。
下一篇预告:RFID 解决了入库的批量识别,但如果你的系统部署在跨国环境,API 每天被大促流量冲击,该怎么办?明天聊跨国 API 网关限流与熔断。
> 本文作者:深圳+Eyf•半字节科技▪技术产品团队
> 物流、快递、快运作业管理系统,让每一票,都清晰可控。从任务分配到签收回传,一站式管理每个作业环节。