Skip to content

EtherNet/IP 驱动 ​

dc3-driver-ethernet-ip 把基于 EtherNet/IP(CIP)的罗克韦尔 Allen-Bradley PLC 接入 IoT DC3:它以标签名(Tag Name) 为目标,周期性读取 PLC 标签值,并支持向标签写值的命令。读完本页你能看懂 EtherNet/IP 的寻址方式、给设备和位号填对协议属性,并清楚这个驱动当前的实现边界。

你在这里:现场设备的"罗克韦尔 PLC"接入侧。要理解工业协议为什么各家私有、CIP 在网络层处于什么位置,先读 工业总线与协议。

协议背景 ​

EtherNet/IP(Ethernet Industrial Protocol)是一种工业以太网协议,把 CIP(Common Industrial Protocol,通用工业协议) 承载在标准 TCP/IP 之上。它由 ODVA 维护,主要用于罗克韦尔 Allen-Bradley 系列 PLC(如 ControlLogix / CompactLogix)以及兼容这套生态的伺服、变频器、I/O 模块。在工厂自动化里,它和 Siemens 的 S7、Mitsubishi 的 MELSEC、Omron 的 FINS 一样,属于"厂商主导、彼此不通"的私有协议阵营——选了哪家 PLC,往往就被绑定到哪套协议。

EtherNet/IP 与 Modbus 这类协议最大的不同在寻址模型:

  • Modbus 按寄存器地址寻址——你要知道某个量挂在第几号保持寄存器(如 40001),地址是裸数字。
  • CIP 按标签名寻址——PLC 工程里的变量有名字(如 Motor_Speed),驱动通过 CIP 的 Data Table Read/Write 服务直接按名字读写,不必关心它在控制器内存的物理地址。

这套"按名字访问"的模型让 PLC 程序改动后地址不再漂移,但也意味着标签名必须与 PLC 工程逐字一致。

在物联网四层架构里,EtherNet/IP 属于网络层的工业有线侧:它解决"现场设备如何在以太网上把一个数据点送出去" 的问题,位于感知层(传感器/变送器)之上、平台层(IoT DC3 数据汇聚)之下。下面这张图给出 CIP 按名寻址在一次采集里的位置:

主从 / 请求-响应模型 · CIP 按标签名寻址 (而非寄存器地址)平台侧 Platform · CIP 客户端设备侧 · Allen-Bradley PLC (ControlLogix / CompactLogix)Data Table Read ▶tagName=Motor_Speed◀ 单元素值小端字节 · elementCount 暂固定 1Data Table Write ▶按 tagType 编码写入dc3-driver-ethernet-ipCIP 客户端 · 手工组帧· slot 背板槽位 (校验必填)· timeout 5000ms → 套接字 SoTimeout· 读写异常 → 连接失效重连TCP 44818 · CIP 显式报文隐式 I/O (UDP 2222) 本驱动不涉及写命令 Write按 tagType 编码值 · sendCommand 模板预留未消费标签值上送位号值 PointValueControlLogix / CompactLogix CPU背板 slot 定位 CPU 模块 · ODVA CIP 生态控制器标签表 Controller Tags (按名访问)Motor_Speed · DINT4 字节整型Valve_Open · BOOL1 字节开关量Batch_Name · STRINGASCII 文本tagType 决定字节解码 (驱动不探测类型)BOOL/SINT 1B · INT 2B · DINT 4B · REAL 4B · STRING · 小端序与 Modbus 寄存器地址不同:CIP 直接按 PLC 工程变量名读写,程序改动后地址不漂移;标签名必须与工程逐字一致平台 / 驱动PLC / 设备读标签 ◀▶ 响应写标签协议 / 传输标签表

CIP 不依赖物理地址,因此位号上配的是 tagName 而非偏移量;驱动按 CIP 应答里的类型码把 PLC 返回的标签值解码成具体数值后,统一为 位号值 上送平台。

属性配置 ​

EtherNet/IP 的接入参数分两层:驱动属性(driver-attribute) 描述"连哪台 PLC、用什么端口和超时" ,填在 设备 上;位号属性(point-attribute) 描述"读哪个标签、写值按什么类型编码" ,填在每个 位号 上。可写位号再加一项命令属性(command-attribute)。这些属性的默认值都来自驱动的 application.yml,三层来历见 属性与配置。

驱动属性(设备级 driver-attribute) ​

接入一台 EtherNet/IP PLC 时,先在设备上指明它的网络位置。host / port 决定 TCP 连到哪里,slot 标识 PLC 在背板上的槽位(多模块机架需要据此定位 CPU),timeout 限制单次请求的等待时长。

属性code类型默认值说明
HosthostSTRINGlocalhostPLC 主机地址(IP 或主机名)
PortportINT44818EtherNet/IP TCP 端口(标准 44818)
SlotslotINT0PLC 背板槽位号,定位机架中的 CPU 模块
TimeouttimeoutINT5000请求超时(毫秒),设到套接字 SoTimeout

slot 会编入 CIP 连接路径

validate() 把 host / port / slot 列为必填项;组帧时 buildConnectionPath() 先写背板端口段(0x01 + slot),再写 ANSI 扩展符号段携带标签名,请求因此路由到机架中该槽位的 CPU。多槽机架请把 slot 填成控制器实际所在槽位(单 CPU、0 号槽保持默认即可)。

位号属性(point-attribute) ​

每个采集位号都要指明读哪个标签、以及写值时按什么类型编码——读方向则以 CIP 应答自带的类型码为准(见下方提示)。

属性code类型默认值说明
Tag NametagNameSTRING(空)CIP 标签名,如 Motor_Speed,必须与 PLC 工程逐字一致
Tag TypetagTypeSTRINGDINT写值编码类型:BOOL / SINT / INT / DINT / REAL(读不看此项;STRING 读可解码、写被拒)
Element CountelementCountINT1读取的元素个数(数组标签用)

读按应答类型码解码,写按 tagType 编码

读:parseTagValue() 不看配置的 tagType,而是按 Read Tag 应答里的 CIP 类型码解码(BOOL/SINT/INT/DINT/REAL 均按小端序,STRING 取 ASCII 文本),未知类型码回退为十六进制原文。写:encodeTagValue() / mapTypeCode() 按你填的 tagType 编码,支持 BOOL / SINT / INT / DINT / REAL;STRING 写不支持(需结构化类型,直接抛 ...cannot be written atomically)。写值时 tagType 必须与 PLC 里该标签的实际类型一致,否则 PLC 会误解字节;位号自身的数据类型( Point 的 pointTypeFlag)应与之对应。

elementCount 当前未被消费

read() 调 buildMrReadTagRequest() 时把元素个数硬编码传 1,配置的 elementCount 暂不生效。数组标签的整段读取需待实现补全;当前只能按单元素读取。

命令属性(command-attribute) ​

可写位号在写命令上额外配置写值模板。

属性code类型默认值说明
Send CommandsendCommandSTRING${value}写值模板,约定用命令参数渲染后按 tagType 编码

sendCommand 模板当前未被消费

write() 直接取命令传入的值并按 tagType 编码(encodeTagValue()),未经过 sendCommand 模板渲染。该属性目前是预留约定,模板替换逻辑待补全。

采集与健康 ​

  • 采集周期:application.yml 基线 read cron 0/30 * * * * ?(每 30 秒读一轮);默认激活的 dev profile 在 application-dev.yml 把 read cron 覆盖为 0/5 * * * * ?(每 5 秒),故开箱即用的实际采集间隔是 5 秒。
  • 自定义调度:schedule.custom 在 yml 中启用(cron 0/5 * * * * ?),但当前 schedule() 方法体为空,不执行任何自定义逻辑。
  • 健康/在线:设备健康检查默认 cron 0/15 * * * * ?,租约超时 45 秒 ——在线状态机制见 设备。

故障排查 ​

EtherNet/IP 接入失败大多落在"连不上"和"读到的值不对"两类。下面按由表及里的顺序排查。

端口或防火墙:44818 不通

EtherNet/IP 显式报文走 TCP 44818(隐式 I/O 另用 UDP 2222,本驱动不涉及)。先在驱动主机上确认 host:44818 可达( telnet <host> 44818 或 nc -vz <host> 44818)。常见原因:PLC 侧未启用 EtherNet/IP 服务、网段不通、防火墙拦了 44818。 getConnector() 建连失败会抛 ConnectorException,日志含 EtherNet/IP connection failed。

tagName 不存在或大小写不符

CIP 按名字寻址,tagName 必须与 PLC 程序里的变量名逐字一致且区分大小写。这点和 Modbus 的 offset 不同:Modbus 填错偏移会静默读到别的寄存器,而 CIP 标签名不存在会直接读取失败、抛 ReadPointException。排查时优先回到 PLC 工程核对标签拼写与作用域(控制器级标签 vs 程序级标签)。

写值的 tagType 与 PLC 真实类型不符,写入会错位

写方向按你填的 tagType 编码字节,不向 PLC 探测真实类型:把一个 REAL(浮点)标签配成 DINT 写入,会按 4 字节整数编码,PLC 按浮点解释就得到乱值。读方向不受影响——读按 CIP 应答自带的类型码解码。接入前在 PLC 工程里逐个确认标签的实际类型,并让位号的 pointTypeFlag 与之对应。

超时偏短导致间歇性读失败

timeout 设到套接字 SoTimeout,默认 5000 毫秒。网络抖动或 PLC 负载高时,过短的超时会让 readFully() 抛 SocketTimeoutException,进而触发 invalidateConnector() 断开重连。表现为周期性读失败、设备在线态抖动。可适当调大 timeout,并优先排查网络质量。

设备显示在线但读不到值

health() 只检查缓存的套接字是否 isConnected() && !isClosed(),不做真实协议探测。也就是说,TCP 连着但 CIP 会话未真正建立时,设备仍可能显示"在线"。判断是否真正采到数据,应以 位号值 是否更新为准,而非仅看设备在线态。

多槽机架定位不到 CPU

slot 已编入 CIP 连接路径(背板端口段 0x01 + slot),请求会路由到该槽位的 CPU。若仍定位不到,核对 slot 是否为控制器实际所在槽位、机架背板配置是否与工程一致。

在 IoT DC3 中如何落地 ​

  • dc3.driver.code:EthernetIpDriver(稳定路由标识,注册与消息路由都以它为准,不要随意改)。驱动名 EtherNet/IP Driver ,类型 DRIVER_CLIENT(驱动主动连 PLC)。
  • 读能力:✓ 已实现。read() 先 RegisterSession(封装命令 0x00F0)注册 CIP 会话,再经 sendRRData(0x005F)发 Read Tag(0x4C)非连接报文取标签值。
  • 写能力:✓ 已实现。write() 经同一非连接通道发 Write Tag(0x4D),按位号 tagType 编码值。
  • 订阅/上报:不支持。EtherNet/IP 显式报文是请求-应答模型,本驱动按采集周期主动轮询,不监听设备主动上报。

与 驱动能力矩阵 对齐:EtherNet/IP 在矩阵中标记为读 ✓ / 写 ✓ / 订阅 —,状态"可用"。

实现边界(Unconnected 报文,无连接型 I/O)

EthernetIpDriverCustomServiceImpl 的 CIP 组帧是完整实现(24 字节封装头、RegisterSession、sendRRData 非连接报文、Read Tag 0x4C / Write Tag 0x4D 均已落地),但有以下边界:

  • 只走 Unconnected 报文:ForwardOpen 连接型 I/O 明确不在本版范围(标签读写用非连接报文已覆盖);
  • STRING 标签写被拒(需结构化类型支持),STRING 读可按应答类型码解码;
  • elementCount、sendCommand 两个属性当前未被消费(见上文告警);
  • health() 仅检查套接字状态,非真实协议探测。

最终行为以 EthernetIpDriverCustomServiceImpl 的 read() / write() / initial() 源码为准。

把一台 Allen-Bradley PLC 接进来的最小路径:

  1. 选 EtherNet/IP Driver 创建 设备,driver 属性填 host=192.168.1.20、port=44818、 slot=0、timeout=5000。
  2. 给设备绑定的 模板 加一个转速 位号( pointTypeFlag=INT、READ_ONLY),point 属性填 tagName=Motor_Speed、tagType=DINT、elementCount=1。
  3. 启动驱动观察连接与采集日志,30 秒内即可在 位号值 看到采集值(默认 dev profile 实际每 5 秒一轮)。

完整的接入操作流程见 设备接入。

延伸阅读 ​

基于 AGPL-3.0 协议发布