第四章:数据采集协议与接入
各位工程师朋友,今天我们来聊聊数据采集协议。说实话,这是整个AALC系统最底层的功夫。协议选不对,后面全是白搭。我见过太多项目,硬件装好了,软件写完了,结果数据上不来——问题就出在协议理解不透彻。
这一章,我会把Modbus RTU/TCP、OPC UA、MQTT这三个主流协议掰开揉碎了讲。还会聊聊数据解析和格式统一的问题。嗯,都是实战中踩过的坑,希望能帮你少走弯路。
核心观点:没有最好的协议,只有最合适的协议。选型要看场景、看设备、看网络环境。
4.1 Modbus RTU/TCP:工业现场的老黄牛
Modbus,1979年诞生的协议。你想想看,比我都大。但它至今还在大量使用,为什么?简单、可靠、成本低。我在一个老旧的水泥厂改造项目中,现场全是Modbus RTU设备,RS485总线拉了上千米,照样跑得稳稳的。
4.1.1 Modbus RTU(串行通信)
RTU模式走的是RS232或RS485物理层。我个人习惯用RS485,抗干扰能力强,传输距离远。波特率一般设9600或19200,别贪快,稳定第一。
数据帧结构是这样的:
地址码(1字节) + 功能码(1字节) + 数据区(N字节) + CRC校验(2字节)
举个例子,读取保持寄存器的指令:
发送:01 03 00 00 00 02 C4 0B
解释:地址01,功能码03(读保持寄存器),起始地址0000,读取2个寄存器,CRC校验C40B
我的经验:CRC校验一定要做对。我曾经因为CRC计算错误,排查了整整两天。后来发现是高低字节顺序搞反了。Modbus RTU的CRC是低字节在前,高字节在后,别记错了。
4.1.2 Modbus TCP(以太网通信)
Modbus TCP就是把RTU的报文封装在TCP/IP包里。去掉了CRC校验(TCP本身有校验),加了个MBAP头(7字节)。
结构对比:
| 协议 | 物理层 | 最大节点数 | 传输距离 | 典型场景 |
|---|---|---|---|---|
| Modbus RTU | RS485/RS232 | 32(无中继) | 1200米 | 传感器、PLC、仪表 |
| Modbus TCP | 以太网 | 无限制 | 100米(交换机级联可扩展) | 上位机与PLC通信 |
避坑指南:我曾经在一个项目中,RTU和TCP混用,结果地址映射搞乱了。建议:同一系统尽量统一协议。如果必须混用,一定要做好地址映射表,文档写清楚。
4.2 OPC UA:跨平台的工业通信标准
OPC UA,说白了就是工业界的"通用翻译器"。不同厂商的设备,语言不通怎么办?OPC UA来当中间人。我参与过一个汽车焊装线项目,西门子PLC、罗克韦尔变频器、库卡机器人,全靠OPC UA统一接入。
OPC UA的核心优势:
- 平台无关:Windows、Linux、嵌入式都能跑
- 安全机制:支持加密、签名、认证
- 信息模型:不只是传数据,还能传数据结构
- 历史数据:内置历史数据访问功能
连接示例(Python + opcua库):
from opcua import Client
client = Client("opc.tcp://192.168.1.100:4840")
client.connect()
# 读取变量
temp = client.get_node("ns=2;i=1001")
value = temp.get_value()
print(f"当前温度:{value}°C")
client.disconnect()
我的建议:OPC UA的节点ID(NodeId)一定要提前规划好。我见过一个项目,节点ID乱得像蜘蛛网,后期维护简直是噩梦。建议用命名空间+数字ID的方式,清晰明了。
4.3 MQTT:物联网时代的轻量级协议
MQTT,发布/订阅模式。你想想看,就像微信群聊——有人发消息(发布者),有人收消息(订阅者),中间有个服务器(Broker)转发。非常适合设备多、网络不稳定的场景。
为什么选MQTT?
- 轻量级:最小报文只有2字节
- QoS机制:三种服务质量等级,按需选择
- 遗嘱消息:设备掉线自动通知
- 保留消息:新设备上线就能拿到最新数据
QoS等级对比:
| QoS等级 | 含义 | 可靠性 | 适用场景 |
|---|---|---|---|
| 0 | 最多发一次 | 低 | 传感器数据(可丢失) |
| 1 | 至少发一次 | 中 | 状态上报(可重复) |
| 2 | 恰好发一次 | 高 | 控制指令(不能丢不能重) |
发布示例(Python + paho-mqtt):
import paho.mqtt.client as mqtt
client = mqtt.Client()
client.connect("broker.emqx.io", 1883, 60)
# 发布温度数据,QoS=1
client.publish("factory/temperature", "25.6", qos=1)
# 订阅所有传感器数据
def on_message(client, userdata, msg):
print(f"主题:{msg.topic},数据:{msg.payload}")
client.on_message = on_message
client.subscribe("factory/#")
client.loop_forever()
避坑指南:我曾经在生产环境中用过QoS 2,结果Broker负载飙升,消息堆积严重。后来发现,大部分场景QoS 1就够了。QoS 2只在控制指令等关键场景使用。别滥用。
4.4 数据解析与格式统一
协议搞定了,数据上来了,但格式五花八门怎么办?有的设备发JSON,有的发二进制,有的发自定义格式。这时候就需要做数据解析和格式统一。
4.4.1 JSON格式
JSON,人类可读,调试方便。我建议在边缘网关层统一转成JSON,方便上层应用处理。
标准格式示例:
{
"device_id": "sensor_001",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"temperature": 25.6,
"humidity": 68.2,
"pressure": 1013.25
},
"quality": "good"
}
4.4.2 Protobuf格式
Protobuf,二进制格式,体积小、解析快。适合带宽有限或数据量大的场景。我在一个风电项目中,上千个传感器数据,用JSON传带宽不够,换成Protobuf后,数据量减少了70%。
定义文件示例:
syntax = "proto3";
message SensorData {
string device_id = 1;
int64 timestamp = 2;
float temperature = 3;
float humidity = 4;
float pressure = 5;
string quality = 6;
}
4.4.3 格式统一策略
我个人习惯的做法:
- 边缘层统一:在网关或边缘设备上,把各种协议数据转成统一格式
- JSON用于调试:开发阶段用JSON,方便查看
- Protobuf用于生产:正式部署用Protobuf,节省带宽
- 时间戳标准化:统一用Unix时间戳或ISO 8601格式
- 质量标签:每个数据点加quality字段,标记数据可信度
我的经验:格式统一这件事,越早做越好。我见过一个项目,数据格式混乱,后期写了几百行转换代码,还经常出bug。一开始就定好规范,能省很多事。
4.5 本章知识体系
下面这张图,是我梳理的本章知识结构。你可以看到,从底层协议到上层数据格式,是一条完整的数据链路。
这张图展示了从物理层到数据格式的完整链路。你想想看,每个环节都环环相扣。物理层选错了,协议层再牛也白搭。协议层选对了,数据解析才能顺畅。
好了,这一章的内容就到这里。协议选型、数据解析、格式统一,这三件事做好了,你的AALC系统就成功了一半。剩下的,就是把这些知识用到实际项目中去。