Skip to content

10.2 工业物联网数据采集:Modbus与OPC UA

10.2.1 工业数据采集:Modbus协议与驱动配置

工厂里最让人头疼的事之一,就是设备“不说话”。西门子的 PLC 用 S7 协议,罗克韦尔的用 CIP,三菱的用 CC-Link,还有一些老旧的仪表只认 RS-485 串口上的几个字节。想把这些数据统一收上来,首先得解决协议互认的问题。

Modbus 是解决这个问题的老兵。它由 Modicon 公司在 1979 年提出,后来交给 Modbus 组织维护,规范当前的稳定版本是 v1.1b3。近半个世纪过去,新装的设备仍在用 Modbus,原因很简单:可靠。一个请求帧通常不超过几十个字节,主站发起,从站应答,没有协商、没有会话管理,任何单片机都能实现。很多工程师把 Modbus 叫作“工业界的 ASCII 码”——性能不是最优,但谁都认。

Modbus 寄存器模型:四种数据对象

Modbus 协议定义了一套寄存器地址空间。无论物理上是 PLC 的存储区还是传感器的内存,逻辑上被抽象为四类数据对象(见表10-3)。理解这一模型是驱动配置的基础。

表10-3:常见 Modbus 功能码说明

数据对象类型位宽访问类型对应功能码 (读取 / 写入)典型用途
线圈1 bit读写01 (读线圈) / 05 (写单线圈) / 15 (写多线圈)继电器状态、开关量输出
离散输入1 bit只读02 (读离散输入)按钮信号、限位开关
输入寄存器16 bit只读04 (读输入寄存器)模拟量输入:温度、压力、液位
保持寄存器16 bit读写03 (读保持寄存器) / 06 (写单寄存器) / 16 (写多寄存器)设备参数、PID 设定值、累计值

每一种数据对象通过“功能码”来区分操作意图。主站发送功能码 + 起始地址 + 数量,从站返回对应数据或写入确认。帧结构极其简单,以 Modbus RTU 为例:

  • 请求帧[从站地址] [功能码] [起始地址高] [起始地址低] [数量高] [数量低] [CRC低] [CRC高]
  • 响应帧[从站地址] [功能码] [字节数] [数据1]... [数据N] [CRC低] [CRC高]

CRC 校验采用 CRC-16/MODBUS(生成多项式 0x8005,实现中常用其位反转形式 0xA001),保障了串行链路的数据完整性。Modbus TCP 则去掉 CRC,帧中增加事务标识符,协议本身的数据结构不变,TCP 模式走 502 端口。

工程上有一个关键认知:Modbus 没有订阅/上报模式。主站必须周期性轮询每个从站的每个寄存器。这意味着采集周期、从站数量、每次读取字节数三者之间需要做权衡。一个 RS-485 网络挂载多个从站时,轮询一遍的总时间取决于帧传输时间、从站响应时间和帧间距。吞吐量随从站数量增加线性下降,在高速现场总线场景下这是一个硬约束——如果要求所有点百毫秒级更新一次,Modbus RTU 就不现实了,得考虑 Profinet 或 EtherCAT。

为什么需要“写”能力

Modbus 不仅是读数据,还需要写命令。IoT DC3 平台的闭环依赖这个能力:当 AI 分析发现某台泵的电流已经偏离正常窗口,系统可以下发一条写保持寄存器的指令,把泵的转速降下来,而不是只发一条告警等人工操作。写功能的支持程度,在驱动选择时就需要确认。从 IoT DC3 的驱动矩阵来看,ModbusTcpDriverModbusRtuDriver 同时支持读写,这一点在后续“命令平面”与“AI 闭环”相关章节中有进一步展开。

IoT DC3 驱动配置实例:Modbus TCP 驱动

在 IoT DC3 中,驱动接入设备遵循统一的流程:驱动注册 → 设备注册 → 位号配置 → 启动采集。下面是一个 Modbus TCP 驱动的 JSON 配置片段,用于接入一台支持 Modbus TCP 的温控仪。

json
{
  "driver": {
    "code": "ModbusTcpDriver",
    "name": "Modbus TCP驱动"
  },
  "device": {
    "name": "温控仪-01",
    "deviceCode": "TEMP_CTRL_001",
    "driverCode": "ModbusTcpDriver",
    "ip": "<device-ip>",
    "port": 502,
    "timeout": 3000,
    "retryCount": 3,
    "interval": "PT5S"
  },
  "points": [
    {
      "pointCode": "PV_TEMP",
      "name": "过程温度",
      "registerType": "HOLDING_REGISTER",
      "functionCode": 3,
      "address": 0,
      "dataType": "FLOAT32",
      "slaveId": 1,
      "unit": "℃"
    },
    {
      "pointCode": "SV_TEMP",
      "name": "设定温度",
      "registerType": "HOLDING_REGISTER",
      "functionCode": 3,
      "address": 2,
      "dataType": "FLOAT32",
      "slaveId": 1,
      "unit": "℃"
    },
    {
      "pointCode": "ALARM_STATUS",
      "name": "报警状态",
      "registerType": "DISCRETE_INPUT",
      "functionCode": 2,
      "address": 0,
      "dataType": "BOOLEAN",
      "slaveId": 1
    }
  ]
}

关键参数说明:

  • 在本配置示例中,interval: "PT5S"表示驱动每 5 秒向该设备发起一次轮询采集;实际周期应依据设备响应时间和现场总线负载校准。
  • registerTypefunctionCode 成对出现:选对了寄存器类型,功能码自动确定;但部分特殊场景可手动指定。
  • dataType: "FLOAT32":Modbus 寄存器原值仅 16 位整数,但工程上常用两个连续寄存器拼成一个 32 位浮点数。IoT DC3 驱动内部实现了字节序和数据类型转换。
  • slaveId:Modbus RTU 模式下是从站站点地址;TCP 模式下通常设为 1 或 255(因为 TCP 本身已标识设备),但部分网关或 PLC 要求必须填写。

该配置写入 IoT DC3 Manager 中心后,温控仪的温度值以结构化的 PointValue 格式(含租户、时间戳、单位)进入Data 中心,上层规则引擎和 AI 模型可以直接消费。这一步至关重要——它把“协议收敛”从抽象概念变为可运行的规则。关于 PointValue 的结构和如何从裸数据转化为带语义的位号值,可参考第 3 章 3.7 节(物模型)与第 4 章 4.3 节(设备抽象与数据模型标准化)。

工程调试要点

部署 Modbus 驱动时最容易踩的几个坑:

  1. 地址偏移。Modbus 协议地址从 0 开始,但部分设备的人机界面从 1 开始显示。配置时务必对照设备手册确认“0x0000 对应设备上的哪个寄存器”,否则会读到错误值。

  2. 字节序。同为 32 位浮点数,不同厂家可能采用不同字节序(Big Endian 或者 Little Endian)。IoT DC3 的驱动配置中,如果数据类型设为 FLOAT32 但读出来是乱数,需要检查驱动是否支持字节序参数配置。ModbusTcpDriver 默认支持通过 byteOrder 参数切换。

  3. 响应超时。串口链路上的多从站系统,若某个从站掉线,可能导致整个轮询周期变长。配置 timeoutretryCount 要留足余量,同时为每个从站设置独立的采集间隔,避免一个慢从站拖慢整条总线。

  4. 写操作的确认机制。写功能码 06 或 16 的请求,正常的从站会原样返回请求帧作为确认。如果返回的是异常响应码(功能码高位为 1,如 0x83),表明写入失败。驱动日志中应捕获这个异常并重试或上报。

这些细节决定了工业数据采集的可靠性。一个驱动是不是“好用”,往往不取决于协议支持的广度,而是这些边界条件的处理深度。IoT DC3 在这方面的工程实践,将在 OPC UA 的对比中进一步体现。

10.2.2 OPC UA协议及与Modbus的异同

Modbus用寄存器地址直接锁死数据位置,快、稳、简单,但有个要命的缺陷:它不告诉你这个寄存器里装的是什么——是电流、是温度,还是状态位?不同厂商的设备即使使用相同的Modbus功能码,寄存器地址的定义也各自为政,集成人员必须死磕设备手册,逐位确认映射表。

OPC UA(OPC Unified Architecture,统一架构)解决的就是这个问题。它的设计目标不是替代Modbus,而是在Modbus只传“裸数据”的地方补上“语义”和“安全”两层。PLC、SCADA(监控与数据采集系统)和边缘网关内置OPC UA服务端的做法已经相当普遍,现场数据以节点树的形式对外暴露。

核心差异:寄存器寻址 vs. 对象模型寻址

从寻址方式入手,两者的本质差异就清楚了。Modbus的通信单元是寄存器地址——一个16位整数(如40001),表示保持寄存器的起始偏移。你告诉对方“读40001-40010”,对方返回10个16位值,但值的含义由双方事先约定,协议本身不做约束。

OPC UA则把每个数据点建模为一个节点(Node),由NodeId唯一标识。NodeId包含两部分:命名空间索引(namespace index)和一个标识符(可以是整数、字符串等)。命名空间把不同来源的标识符隔开——两个厂商可能在各自的命名空间下定义相同数值的标识符,但不会冲突。这才是OPC UA跨界互操作的基础:你不必要求所有设备采用同一个地址映射表,而是通过命名空间和节点树来解耦。

在物联网四层架构里,OPC UA是运行于TCP/IP之上的应用层协议,向下对接PLC/控制器,向上把数据递给数据平台。与Modbus TCP固定使用502端口(Modbus RTU则运行在RS-485等串行链路上,并无端口概念)不同,OPC UA使用opc.tcp://协议(默认为4840端口),并内置了会话管理、安全通道和数据加密。

安全机制

Modbus在安全方面的短板是行业共识。最初的Modbus TCP没有认证、没有加密,连最简单的用户名密码都没有。后续从业者通过各种方式打补丁:限制IP访问、部署VPN、在网关上做协议转换。但协议层面,Modbus的安全依然是“事后补充”。

OPC UA把安全作为规范的一部分从第一天就内建了进去。每个OPC UA连接都需要经过一个完整的握手过程:客户端与服务端建立安全通道,协商安全策略(如Basic256Sha256),交换证书,通过签名和加密保证消息的完整性和机密性。管理员的日常工作之一是处理证书的信任链——服务端证书、客户端证书、CA(证书颁发机构)证书,缺一不可。这在产线调试阶段经常给集成人员带来额外的工作量,但产线一旦运行,安全收益是实打实的。

信息模型与地址空间

OPC UA的核心创新在于信息模型。它不只是传一个值,而是把值与它的类型、单位、描述、元数据一起包装好,暴露给上层。这意味着,一个OPC UA客户端(比如IoT DC3的OPC UA驱动)连上服务端后,不是通过查手册确定地址,而是直接遍历节点树,读取每个节点的元数据,自动发现设备的数据结构。

OPC UA地址空间是一个对象模型的树形结构,根节点是Objects,下挂具体设备对象,每个对象包含变量节点(VariableNode)、方法节点(MethodNode)和引用关系。

图 10-5 OPC UA地址空间树状结构OPC UA以Organizes组织设备、以HasComponent包含变量和方法;NodeId、DataType、Description属于变量节点属性,仅EngineeringUnits等附加属性通过HasProperty引用。图 10-5 OPC UA地址空间树状结构NodeId、DataType、Description 是 Variable Attributes;仅 EngineeringUnits 等附加属性使用 HasPropertyObjects所有对象的容器Organizes 组织主链路电机1设备对象温度 · 转速 · 状态设备2设备对象流量 · 压力HasComponent 包含温度变量节点 · Float转速变量节点 · Int状态变量节点 · Bool流量变量节点 · Float复位方法节点 · 可远程调用Variable AttributesNodeId: ns=2;i=1234 · DataType: DoubleDescription: 温度测量值Property NodeEngineeringUnits: °CHasProperty 引用附加属性蓝色框=对象节点绿色框=变量节点橙色框=方法节点实线=HasComponent虚线=HasProperty蓝色实线=Organizes图 10-5 OPC UA地址空间以引用组织节点;变量自身属性与通过 HasProperty 关联的附加属性必须区分。
图 10-5 OPC UA地址空间树状结构

这种自描述能力在Modbus上是做不到的。Modbus客户端必须知道要读哪个寄存器地址,以及读回来的值是什么含义——这些信息不在协议内传输,而在手册和配置文件里。OPC UA把这些元数据放到协议的地址空间中,客户端程序连入后自动发现,减少了大量人工配置。

信息模型的图景也没有停在“节点树”上。面向控制器与控制器之间的现场级通信,OPC基金会推出了OPC UA FX(Field eXchange)伴生规范,把OPC UA从“控制器对上层系统”扩展为“控制器对控制器(C2C)”;配合TSN(时间敏感网络)与单对以太网,OPC UA正在从信息层下沉到确定性实时控制域。在语义互操作这一侧,资产管理壳(Asset Administration Shell,AAS,IEC 63278)把设备资产全生命周期的描述标准化,与OPC UA信息模型互为表里。截至本书写作时(2026年),“OPC UA传数据、AAS管语义”已成为工业语义互操作的主流图景,选型时应把驱动对FX与AAS相关规范的跟进程度纳入评估。

IoT DC3 OPC UA驱动配置

IoT DC3的OPC UA驱动(dc3-driver-opc-ua)已经在官方文档中标记为完整实现,支持读写两种操作。在配置层面,它需要提供端点的URL、安全策略,以及要订阅的节点列表。一个典型的JSON配置如下(非真实项目配置,仅供理解结构):

json
{
  "driver": "opc-ua",
  "endpoint": "opc.tcp://<plc-ip>:4840",
  "security": {
    "mode": "SignAndEncrypt",
    "policy": "Basic256Sha256",
    "clientCert": "cert/iot-dc3-client.der",
    "clientKey": "cert/iot-dc3-client.pem"
  },
  "namespaceIndex": 2,
  "points": [
    {
      "name": "motor-1-temperature",
      "nodeId": "ns=2;i=1001",
      "dataType": "float",
      "unit": "°C",
      "pollInterval": 1000
    },
    {
      "name": "motor-1-speed",
      "nodeId": "ns=2;i=1002",
      "dataType": "int16",
      "unit": "rpm",
      "pollInterval": 500
    }
  ]
}

配置中的nodeId可以是数字标识符(ns=2;i=1001),也可以是字符串标识符(ns=2;s="Temperature"),取决于服务端地址空间的定义。安全策略的选择是这部分配置的难点:产线调试阶段可以先降级为NoneSign模式,待证书互信关系建立后再切换到SignAndEncrypt

选型判断

Modbus和OPC UA不是谁取代谁的关系。一个成熟的工业物联网系统通常两者共存:

  • Modbus用于简单传感器、老旧仪表和成本敏感的从站设备。寄存器地址固定、协议栈轻量,一个RS-485总线可以挂载几十个Modbus RTU从站。
  • OPC UA用于需要语义互操作的复杂设备、系统级集成和跨厂商交互。如果设备本身支持OPC UA(很多西门子、罗克韦尔的控制器从固件层面就内建了),直接使用OPC UA驱动可以省去大量的地址映射表维护工作。

工业现场很多网关产品同时支持Modbus和OPC UA,在Modbus设备和OPC UA服务端之间做协议转换。一个3层网络的模式很常见:Modbus总线上挂传感器和仪表,PLC作为集中器向上层暴露OPC UA服务端,IoT DC3通过OPC UA驱动接入PLC。这样既兼容了底层的简单设备,又在上层获得了语义集成和安全管控的能力。

10.2.3 边缘网关与数据预处理

从 Modbus 的 RS-485 串口到 OPC UA 的以太网,再到大量老旧设备仍在使用的 4-20mA 模拟量接口,工业现场的通信协议、电气接口、波特率和字节序参差不齐。如果每条链路都选择透传——让设备直接与云平台建立长连接——面临的不仅是网络带宽的峰值压力,还有现场控制周期被轮询延迟打乱的风险。这就是为什么生产线和云平台之间必须存在一层边缘网关。它不是简单的中继,而是“端-边-云”三层架构中承担协议转换数据预处理本地缓存的核心节点。这三个职责决定了采集链路的质量和鲁棒性,是从“能连上”到“连得好”的工程分界线。

协议转换:把碎片归一化

最直观的需求是把异构协议归一到平台层可理解的统一数据模型。一台工业边缘网关通常内置数十种设备驱动,能够同时挂载 RS-485 总线上不同地址的 Modbus RTU 从站、以太网上的 OPC UA 服务器,甚至私有 TCP 协议的设备。转换不是简单的字节搬运:Modbus 的寄存器地址 40001 映射到 OPC UA 的哪个 NodeId?一个 4-20mA 模拟量通道按什么缩放系数转换为工程值(例如 4mA 对应 0 °C、20mA 对应 150 °C)?这些映射关系需要在网关配置工具中预先定义,形成一份可版本管理的“位号映射表”。

协议转换的工程难点不在“能转”,而在“可配置、可追溯”。一个设计良好的网关允许运维人员在不重启设备的情况下动态更新映射,并把每一次转换的原始值与结果值写入日志。这并非简单的冗余日志——它是数字孪生所需数据血缘的起点。当产线上出现异常温度时,工程师应当能追溯回“这个 135 °C 最初对应的是 Modbus 保持寄存器 40100 的第 3-4 字节”。没有这个能力,排查故障时只能全链路重头对一遍,效率极低。

数据预处理:减量不减质

云平台不需要每一个毫秒级的原始波形,它关心的是趋势和事件。边缘网关可以在本地完成三道工序:滤波去除传感器毛刺和电源噪声;降采样把 1 kHz 的振动数据压缩到 1 Hz 的均值或极值;阈值判断形成事件型上报——例如“温度超过 85 °C 持续 10 秒”才触发一次上发,而非每个采集周期都推送原始超限状态。

这些预处理步骤的价值不是算力上的“省”,而是语义上的“浓缩”。网关可以在采集点打上标签——设备编号、工位、测量量程、单位——这样数据到达平台时已经是带上下文的 PointValue(值 + 语义 + 时间戳 + 租户),而不是没有含义的裸字节。IoT DC3 的驱动层与Data 中心之间的归一化管道,正是通过这样的预处理来实现的。预处理的结果决定了后续规则引擎能触发什么逻辑、AI 模型能“看懂”什么——这是一个工程判断。

离线缓存与断点续传

工业现场的网络可靠性远低于办公网络。光纤被叉车撞断、交换机不定期重启、Wi-Fi 信号被金属货架遮挡——断连是常态,不是异常。边缘网关必须在网络中断时持续采集,暂存到本地闪存或 SD 卡;网络恢复后按时间戳窗口回传缺失数据,同时不覆盖新采集值。断点续传的核心是有序时间戳队列:每条数据记录携带全局递增的时间戳,平台端根据戳判断是否有区间缺失,缺什么就向网关发起补传请求。

缓存容量需要工程判断。一个例子:车间 200 个采集点,每秒一条快照,一天约 1700 万条记录。现场网关通常配置数十至上百 GB 的闪存,并支持循环覆盖策略——保留最近 N 天数据,更早的数据可以丢弃或按周归档。这个策略的关键权衡是:历史保留越长,断点续传的完整性越大但本地存储压力越大;工程上一般以“一次长周末加一个工作日”为基线,覆盖约 72-120 小时的窗口。如果要保留更长时间供本地离线分析,通常选择分类存储——元数据保留在闪存,原始波形定向转存至外部存储节点。

部署:电子组装产线

例子:某电子组装产线部署了 4 台回流焊炉、6 台贴片机和 2 台 AOI 光学检测仪。回流焊炉通过 Modbus RTU 输出炉温曲线(6 个测温点);贴片机用 OPC UA 暴露吸嘴压力和转速;AOI 通过私有 TCP 协议输出缺陷坐标。一台边缘网关安装在产线旁的 IP54 机柜内,同时连接这三类设备。网关内部运行三套驱动:Modbus RTU 主站轮询 4 台炉子、OPC UA 客户端订阅 6 台贴片机、TCP Socket 解析器接收 AOI 数据流。它每 1 秒轮询一次各位号,炉温按最大-最小-平均降采样后以 MQTT 上报;AOI 缺陷只上报检出事件(原始坐标保留在本地)。网关配置约 64 GB 存储,保留 72 小时历史数据,断网时正常采集,网络恢复后自动补传未确认的时间区间。

这套配置下,云平台收到的不是每秒 200 条原始值,而是经过聚合的事件型数据——流量显著降低,而产线异常诊断所需的炉温极值信息并未丢失。边缘网关在这里成了数据质量的第一把关人。

边缘网关不是附属品,它是工业物联网在“最后一公里”的工程支撑。协议转换解决可连接问题,数据预处理解决可消费问题,离线缓存解决可生存问题——这三条缺一条,采集链路都不可靠。而 IoT DC3 驱动架构提供的核心价值之一,就是把这些职责从业务代码中剥离出来,交付给专门的驱动模块,让开发者可以专注于更高层的业务逻辑。下面讨论数据到达平台后的时序存储与规则引擎设计,而边缘网关交付的干净、带语义的数据正是所有上层智能的基石。

从工业软件到 AI 智能体 · 构建面向智能体演进的多协议、云原生、开源工业物联网平台