IXNORFID Insight
← 返回洞察
工程实战2026-09-27 · 20 分钟

从零搭建 UHF RFID 产线在制品盘点系统:硬件连接 → 协议解析 → Node.js 后端 → Web 看板

本文以一个完整的产线在制品(WIP)追踪项目为例,从读写器接线、通信协议解析,到 Node.js 后端开发、Web 实时看板,手把手带你跑通一套可落地的 RFID 盘点 Demo。所有代码可直接复用到实际项目中。

本文以一个完整的产线在制品(WIP)追踪项目为例,从读写器接线、通信协议解析,到 Node.js 后端开发、Web 实时看板,手把手带你跑通一套可落地的 RFID 盘点 Demo。所有代码可直接复用到实际项目中。

一、为什么产线需要 RFID 自动盘点

制造业产线上的在制品(Work In Progress, WIP)管理长期依赖人工扫码或纸质工单流转。一个典型的痛点是:产线节拍快、工位多,人工扫码容易漏扫、错扫,导致 MES 系统中的在制品数量与实际不符。当出现质量问题需要追溯时,往往要花大量时间「找料」。

UHF RFID 在这类场景下有几个不可替代的优势:

  • 批量读取:一次盘点可读取视野内数百枚标签,不需要逐一对准;
  • 非接触识别:标签贴在产品/载具内部,无需暴露即可读取;
  • 抗污损:相比条码,RFID 标签不怕油污、灰尘覆盖;
  • 可写入:标签内可存储工位编号、工序状态等信息,随产品流转。

我们要做的这套系统,核心目标就一个:在每个关键工位部署读写器,自动识别当前工位上的所有载具/产品标签,实时上报到后端,形成在制品看板。

二、系统整体架构

先看一下整体架构,心里有个全貌。整个系统分三层:

  • 设备层:读写器通过 TCP 连接天线,对工位上的 RFID 标签进行周期性盘点;
  • 服务层:Node.js 后端负责连接读写器、解析协议、处理业务逻辑(去重、工位判定、异常告警),并将数据写入 SQLite;
  • 展示层:Web 看板通过 WebSocket 实时接收数据,展示各工位的在制品状态。

数据流路径是:读写器 → TCP → Node.js 协议解析 → 业务逻辑 → SQLite + WebSocket → Web 看板。读写器默认通过 TCP 端口 6000 通信,后端用 Node.js 的 net 模块建立长连接,实时接收盘点数据。

三、硬件连接与网络配置

3.1 读写器接线

固定式 UHF 读写器通常有以下几个物理接口:SMA 天线接口 ×4(分别连接四根圆极化天线)、RJ45 网口(TCP/IP 通信)、GPIO 接口(触发外部设备)、电源接口(DC 12V 或 PoE 供电)。

接线步骤:将四根天线通过 SMA 线缆连接到读写器的 ANT1~ANT4 接口,注意拧紧防松;用网线将读写器连接到产线交换机,确保与后端服务器在同一网段;接通电源,等待指示灯变为常亮(通常 10~15 秒初始化)。

3.2 网络配置

大多数读写器出厂默认 IP 为 192.168.1.200(具体参考说明书),需要将后端服务器的 IP 配置在同一网段。在 Linux 上用 ip addr show eth0 查看当前网络接口,如果不在同一网段则用 sudo ip addr add 192.168.1.100/24 dev eth0 配置。

验证连通性:ping 192.168.1.200 应收到回复,然后用 nc -zv 192.168.1.200 6000 测试 TCP 端口。

3.3 天线部署建议

产线工位的天线部署要注意几点:天线朝向方面,圆极化天线正对标签面,距离控制在 30~80cm;功率调节方面,相邻工位的天线功率要错开,避免交叉读取,一般从 20dBm 开始调;屏蔽措施方面,如果工位间距小于 1.5m,建议在天线之间加装金属屏蔽板,或使用窄波束天线。

四、通信协议解析

这是整个项目中最关键也最容易踩坑的部分。读写器的通信协议通常基于 TCP,采用「命令-响应」模式。

4.1 帧结构

一个典型的读写器通信帧由以下部分组成:帧头(0xBB,1 字节)、长度(2 字节,大端序)、命令(1 字节)、参数数据(N 字节)、CRC16 校验(2 字节)、帧尾(0x7E,1 字节)。长度字段是从命令到 CRC 的总字节数。

4.2 核心命令

我们主要用到以下几个命令:0x00 单次盘点(执行一次标签扫描)、0x27 循环盘点(持续盘点直到收到停止命令)、0x01 停止(停止循环盘点)、0x03 设置功率(单位 0.25dBm)、0x14 切换天线(指定使用哪些天线)。

4.3 标签数据格式

盘点响应中,每个标签的数据包含:EPC 长度(1 字节)、EPC 数据(N 字节,通常为 12 字节 96 位)、RSSI(1 字节,信号强度)、天线编号(1 字节)、时间戳(4 字节)。EPC 是标签的唯一标识,RSSI 可以用来做粗略的距离估算。

五、Node.js 后端开发

现在开始写代码。先初始化项目:mkdir rfid-wip-demo && cd rfid-wip-demo && npm init -y && npm install express ws better-sqlite3。

5.1 项目结构

项目分为四层:reader 层(protocol.js 协议解析 + connection.js TCP 连接管理)、service 层(inventory.js 盘点业务逻辑 + alert.js 异常告警)、routes 层(api.js REST 接口)、以及入口 index.js。前端放在 public/index.html。

5.2 协议解析模块

这是核心中的核心。首先定义帧头 0xBB 和帧尾 0x7E,以及各命令码常量。CRC16 采用 Modbus 变体算法,初始值 0xFFFF,多项式 0xA001,结果以大端序写入帧中。

buildFrame 函数负责组帧:将命令和参数拼接为 payload,计算 CRC16,然后按帧头 + 长度 + payload + CRC + 帧尾的顺序组装成 Buffer。

FrameParser 类处理 TCP 粘包/半包问题。它维护一个内部缓冲区,每次 feed 新数据后,循环查找帧头、检查长度、验证帧尾和 CRC,提取完整的帧。这种缓冲队列模式是处理 TCP 流的标准做法。

parseInventoryResponse 函数解析盘点响应中的标签列表:第一个字节是标签数量,然后循环读取每个标签的 EPC 长度、EPC 数据、RSSI(转为 dBm)、天线编号和时间戳。

5.3 TCP 连接管理

ReaderConnection 类继承 EventEmitter,封装了 TCP 长连接的完整生命周期。connect 方法建立连接,绑定 data 事件将收到的数据喂给 FrameParser,close 事件触发自动重连(5 秒间隔)。

send 方法将命令和参数通过 buildFrame 组帧后写入 socket。startInventory 发送循环盘点命令,stopInventory 发送停止命令。disconnect 方法先停止盘点、清除重连定时器,再销毁 socket。

5.4 盘点业务逻辑

InventoryService 是业务核心。它维护一个 currentTags Map,记录每个 EPC 标签当前所在的工位。ANTENNA_STATION_MAP 将天线编号映射到工位名称和编码(如天线 1 → 上料站 ST-A01)。

processTags 方法处理三种核心事件:ENTER(新标签首次出现)、MOVE(标签从一个工位移动到另一个工位)、以及同工位更新(只刷新 lastSeen 时间戳)。

cleanup 方法每 5 秒执行一次,清理超过 30 秒未出现的标签(TAG_TIMEOUT_MS),认为它们已流转到下一工位或离开产线。getStationSummary 方法生成各工位的当前状态快照,包含标签数量和详情。

5.5 主入口与服务集成

index.js 把所有模块串起来。Express 提供静态文件服务和 REST API(/api/stations 返回工位状态、/api/reader 返回读写器连接状态)。WebSocket 服务器负责向前端广播实时更新。

事件绑定逻辑:reader 收到帧后判断命令码,调用 parseInventoryResponse 解析标签,再交给 inventory.processTags 处理。inventory 的 inventory-update 和 tags-expired 事件触发 WebSocket 广播。reader 连接成功后自动开始循环盘点。

5.6 Web 看板页面

看板用原生 HTML + CSS + JS 实现,不需要前端框架。深色主题(#0f172a 背景),顶部显示读写器在线状态,中间 4 列网格展示各工位卡片(工位名、在制品数量、标签列表),底部是最近 50 条事件日志。

WebSocket 连接后,收到 update 消息时更新工位卡片和事件列表,收到 reader-status 消息时更新连接状态指示灯。事件类型用不同颜色标签区分:绿色「进入」、蓝色「流转」、红色「离开」。

六、运行与联调

6.1 启动服务

设置环境变量 READER_HOST=192.168.1.200,然后执行 node src/index.js。正常输出应该是:Server HTTP + WebSocket 已启动端口 3000,Reader 已连接,Reader 开始循环盘点。打开浏览器访问 http://localhost:3000 即可看到看板。

6.2 常见问题排查

  • 读写器连接失败:检查网络是否同网段,用 nc -zv 确认端口可达,部分读写器需要在配置工具中开启 TCP 服务模式;
  • 读不到标签:先确认天线 SMA 接口是否拧紧,检查标签是否在范围内,用厂家调试工具先验证硬件;
  • 交叉读取严重:降低天线功率(CMD_SET_POWER),或在天线间加装金属屏蔽板,也可用 RSSI 阈值过滤弱信号标签;
  • TCP 粘包导致解析异常:确认 FrameParser 的缓冲逻辑正确工作,可以在 feed 方法中加日志打印原始数据长度和解析帧数。

6.3 扩展方向

这套 Demo 跑通之后,可以往几个方向扩展:对接 MES 系统,将盘点事件通过 HTTP 或 MQTT 推送,实现工单自动流转;增加告警规则,比如工位停留超时或标签跳站时触发声光报警和钉钉/企微通知;多读写器组网,创建多个 ReaderConnection 实例统一管理;数据看板升级,接入 ECharts 或 Grafana 展示产线节拍和 WIP 趋势。

七、总结

本文从一个实际产线场景出发,完整走通了 UHF RFID 盘点系统的搭建过程:硬件接线和网络配置、通信协议的帧解析、Node.js 后端的连接管理和业务逻辑、Web 实时看板的开发。核心代码不到 400 行,但覆盖了 RFID 工程中最关键的几个环节。

三个实践建议:第一,先调通硬件再写代码,用厂家调试工具确认读写器、天线、标签都能正常工作后再开发软件;第二,协议解析要做好容错,TCP 是流式协议,粘包半包是常态,FrameParser 的缓冲队列模式是标准做法;第三,天线部署是系统工程,RFID 项目的成败往往不取决于代码,而取决于天线的选型、位置和功率调节,现场调试时多花时间在物理层,比在软件层打补丁高效得多。

关于本文的常见问题

问:UHF RFID 读写器的通信协议一般是什么格式?

答:大多数国产 UHF 读写器采用基于 TCP 的「命令-响应」协议,帧结构为:帧头(0xBB)+ 长度(2 字节)+ 命令码(1 字节)+ 参数数据 + CRC16 校验 + 帧尾(0x7E)。开发时最关键的是处理好 TCP 粘包/半包问题,用缓冲队列模式逐帧解析。

问:产线 RFID 盘点,天线怎么部署才能避免交叉读取?

答:三个手段配合使用:一是功率调节,从 20dBm 开始逐步增大到刚好覆盖本工位;二是物理隔离,相邻工位间距小于 1.5m 时加装金属屏蔽板;三是软件过滤,用 RSSI 阈值剔除弱信号标签。优先调物理层,比软件补偿可靠得多。

问:Node.js 适合做 RFID 读写器的后端服务吗?

答:适合。Node.js 的 net 模块天然支持 TCP 长连接,EventEmitter 模式与读写器的异步数据推送契合度很高。Express + WebSocket 可以快速搭建 REST API 和实时看板。对于中小规模产线(10 台以内读写器),Node.js 完全够用。大规模部署建议考虑 Java 或 Go。

问:RFID 标签超时判定一般设多久合适?

答:取决于产线节拍。快速产线(节拍 < 30 秒/工位)建议设为 10~15 秒;常规产线建议 30 秒;慢速产线或仓储场景可以放到 1~5 分钟。核心原则是:超时应大于「正常停留时间 + 盘点周期」,但小于「流转到下一工位的预期时间」。

问:这套系统能直接对接 MES 或 ERP 吗?

答:可以。InventoryService 的 ENTER/MOVE 事件可以直接通过 HTTP POST 或 MQTT publish 推送到 MES。建议对接时做好幂等性设计(同一事件重复推送不应导致重复操作),并在中间层做数据缓冲,避免 MES 接口抖动影响盘点服务。

问:Demo 中的代码可以直接用于生产环境吗?

答:核心架构(协议解析、连接管理、业务逻辑)可以直接复用,但生产环境还需要补充:日志系统(winston/pino)、进程管理(PM2)、数据备份、读写器断线告警、以及更完善的异常处理。建议先在测试环境跑稳再上产线。

继续阅读