
工业现场的数据采集与上云这几年从可选项变成了标配题。但真正落地过几个项目的人都知道这件事的难点从来不是能不能连上而是连上之后数据能不能用、稳不稳、扛不扛得住现场的各种意外。我前后做过七八个不同规模的PLC上云项目从单台西门子S7-1200的小产线到几十台三菱、汇川、ABB变频器混跑的车间踩过的坑比写过的代码还多。这篇就把整套架构从边缘侧到云端拆开讲清楚包括协议选型、边缘网关设计、数据模型、云端接入和现场排错尽量把那些文档里不会写的经验都倒出来。1. 先想清楚PLC数据上云到底要解决什么问题很多人一上来就问用什么网关上哪个云平台这其实是把顺序搞反了。PLC上云的本质是把工业现场封闭在控制器里的过程数据变成可以被远程系统消费的结构化信息。这个消费决定了后面所有的技术选型。1.1 三类典型需求对应三套不同的架构我把见过的需求归成三类你可以对号入座。第一类是监控展示型。老板想在手机上看产线产量、设备运行状态、报警信息。这类需求对实时性要求不高秒级甚至分钟级刷新都能接受数据量小重点是稳定和便宜。架构上边缘网关做协议转换后直接推MQTT到云平台云端存时序库加个看板就够了。第二类是数据分析型。要算OEE、做设备预测性维护、分析能耗。这类需求对数据完整性要求极高不能丢点而且需要历史数据回溯。架构上要考虑边缘侧本地缓存、断点续传云端要有完整的数据清洗和存储链路。第三类是远程控制型。不只是读还要写比如远程下发配方、远程启停。这类需求最敏感安全要求最高必须考虑指令确认、超时回滚、权限分级边缘侧要有独立的控制通道和本地兜底逻辑。提示绝大多数项目其实是第一类和第二类的混合。真正涉及远程写操作的一定要单独评估安全方案不要和只读采集混在一套逻辑里。1.2 为什么直接让PLC连云是个坏主意新手最容易犯的错是想着让PLC自己通过以太网口直接连云端。理论上某些高端PLC确实支持MQTT但实际项目里我强烈不建议这么做原因有三个。一是安全边界问题。PLC一旦直接暴露在公网链路上等于把控制层暴露了。工业现场的网络隔离是有道理的边缘网关在这里扮演的就是隔离墙的角色。二是协议适配问题。现场设备五花八门西门子走S7协议三菱走MC协议汇川走Modbus TCP或CODESYS的OPC UA还有一堆老设备只有串口Modbus RTU。指望PLC自己搞定这些异构协议不现实边缘网关才是干这个的。三是业务逻辑问题。数据采集往往需要做预处理——滤波、单位换算、状态映射、报警判断。这些逻辑放在边缘侧做既减轻云端压力又能在断网时保持本地判断能力。PLC的算力和编程方式不适合干这个。1.3 边缘计算在这里到底承担什么角色热词里边缘计算出现频率很高但很多人对它的理解停留在在本地跑个程序。我的理解是边缘计算在PLC上云场景里承担四件事协议转换、数据预处理、本地缓存、断网自治。协议转换是把S7、MC、Modbus、OPC UA这些异构协议统一成一种上行协议通常是MQTT或HTTP。数据预处理包括量纲转换、死区过滤、变化上报。本地缓存解决网络抖动时的数据不丢。断网自治则是当云端不可达时边缘侧仍能维持本地逻辑运行网络恢复后自动补传。这四件事里本地缓存和断点续传是最容易被低估的。我见过太多项目演示时一切正常一到现场网络波动就丢数据最后被客户追着问为什么昨天的产量对不上。2. 协议选型Modbus、OPC UA、S7到底怎么选协议这块是绕不开的选错了后面全是返工。我把现场最常见的几种协议按适用场景理一遍。2.1 现场层协议的真实分布根据我做过的项目统计现场设备协议分布大致是这样的协议典型设备占比感受特点Modbus RTU/TCP仪表、变频器、老PLC最高简单、通用、无类型信息西门子S7S7-200/1200/1500很高需专用库地址寻址三菱MCFX/Q/L系列较高需专用库位软元件复杂OPC UA新设备、数控机床上升中自带语义、安全强厂商私有部分CNC、机器人中等需厂商SDKModbus之所以占比最高是因为它足够简单几乎所有仪表和变频器都支持。但它的坑也最多——没有数据类型概念你读上来的是寄存器原始值得自己知道哪个寄存器是float、哪个是int、字节序是大端还是小端。2.2 Modbus采集最容易踩的三个坑第一个坑是字节序。Modbus寄存器是16位的一个32位float要占两个寄存器。但这两个寄存器谁在前谁在后以及每个寄存器内部高低字节怎么排不同厂商实现不一样。我遇到过同一批变频器ABB和汇川的float字节序就是反的。解决办法是采集配置里必须支持字节序和字序两个独立选项现场调试时用已知值反推。第二个坑是寄存器地址偏移。Modbus协议文档里地址从1开始但很多库从0开始寻址。你按文档写40001代码里可能要写0。这个偏移量每个库不一样调试时先用一个已知寄存器验证。第三个坑是批量读取的连续性。Modbus一次读多个寄存器要求地址连续但现场需要的点往往分散在不同区域。如果每个点单独读一次效率极低。正确做法是把地址相近的点合并成块读块与块之间留出合理间隔。# Modbus批量读取的合并逻辑示意 # 把需要采集的点按地址排序合并连续或间隔小于阈值的点 def merge_read_blocks(points, max_gap8, max_block120): points sorted(points, keylambda p: p[addr]) blocks [] cur [points[0]] for p in points[1:]: if p[addr] - (cur[-1][addr] cur[-1][len]) max_gap \ and (p[addr] p[len] - cur[0][addr]) max_block: cur.append(p) else: blocks.append(cur) cur [p] blocks.append(cur) return blocks这个合并逻辑看着简单但实测能把采集周期从几百毫秒压到几十毫秒尤其是点数多的时候。2.3 OPC UA值不值得上OPC UA这两年在新建产线和数控机床上越来越常见热词里通过OPC UA与西门子PLC通讯也是高频搜索。它的优势很明显自带数据类型和语义、支持订阅模式、有完整的安全模型。但它的代价是复杂。证书管理、端点配置、会话保持每一项都能让新手卡半天。我的建议是如果是新建项目、设备原生支持OPC UA、且团队有一定IT基础优先用OPC UA如果是改造老项目、设备只有Modbus或S7别为了用OPC UA而加一层转换得不偿失。订阅模式是OPC UA的一大亮点。传统轮询是我每隔一秒问一次订阅是数据变了你告诉我。对于变化不频繁的点订阅能大幅降低通信负载。但要注意订阅的发布间隔Publishing Interval和采样间隔Sampling Interval是两个概念配不好会出现数据看起来延迟很大的错觉。2.4 S7协议采集的地址映射西门子S7协议采集核心是理解它的地址格式。比如DB1.DBD0表示数据块1里从字节0开始的32位双字M10.0表示位存储区第10字节的第0位I0.0是输入区。用开源库比如python-snap7采集时要注意几个点DB块必须关闭优化访问否则地址不固定采集前要确认PLC允许PUT/GET通信连接数有限制别开太多并发。注意S7-1200/1500默认可能禁止PUT/GET需要在硬件配置里勾选允许来自远程对象的PUT/GET通信访问。这个选项不勾库连上去也读不到数据而且报错信息往往很含糊。3. 边缘网关硬件选型与软件架构边缘网关是整个方案的心脏。选型和架构设计直接决定了项目的稳定性和后期维护成本。3.1 硬件选型的几个硬指标市面上边缘网关从几百块的工控板到上万的品牌网关都有。我选型时看这几个指标串口数量。现场老设备多的话至少2路RS485最好4路。RS485总线一条能挂几十个从站但实际建议不超过20个太多会拖慢轮询。网口数量。至少2个一个接现场设备网段一个接上行网络。物理隔离比VLAN隔离更可靠。工作温度。工业现场夏天机柜内温度能到50度以上商业级芯片扛不住。选宽温-20到70度的。存储。本地缓存需要空间至少8G eMMC最好支持TF卡扩展。断网几天的话数据量不小。看门狗。必须有硬件看门狗软件跑飞了能自动重启。这个在现场太重要了。热词里stm32物联网网关freertos stm32物联网网关出现很多说明不少人在用STM32做网关。我的看法是STM32适合做协议转换的轻量网关跑FreeRTOS处理Modbus RTU转MQTT这类任务没问题。但如果要跑OPC UA、要做复杂的数据预处理和本地数据库STM32的资源和生态就吃力了建议上Linux方案比如ARM Cortex-A系列。3.2 软件架构的分层设计我在Linux网关上通常这么分层采集层负责和各协议打交道每个协议一个采集任务独立线程或进程。采集层只负责把原始数据拿到不做任何业务判断。处理层负责数据清洗、量纲转换、死区过滤、报警判断。这一层是业务逻辑的核心也是最需要可配置的地方。缓存层负责本地存储。我一般用SQLite或轻量时序库断网时数据先落本地网络恢复后按时间顺序补传。上行层负责和云端通信通常是MQTT客户端。要处理连接管理、QoS、重连、补传。管理层负责配置下发、远程升级、日志上报、健康监控。这个分层的好处是每层职责清晰出问题好定位。比如数据不对先看采集层原始值对不对再看处理层转换逻辑一层层排查。3.3 采集任务的调度策略采集调度看着简单其实很有讲究。我的经验是分组调度把采集周期相同的点分到一组每组一个独立任务按固定周期执行。为什么要分组因为不同点的实时性要求不一样。设备运行状态可能要100ms级但能耗统计1分钟一次就够了。如果全用一个周期要么高频点拖累整体要么低频点浪费资源。分组之后还要注意任务错峰。如果所有采集任务都在同一时刻触发会造成瞬时CPU和网络压力。我一般给每组加一个小的随机偏移把负载摊开。# 采集任务分组与错峰示意 import threading, time, random def start_poll_group(name, points, interval_ms, offset_ms): def loop(): time.sleep(offset_ms / 1000.0) # 错峰偏移 while running: t0 time.time() poll_once(points) elapsed (time.time() - t0) * 1000 sleep_ms max(0, interval_ms - elapsed) time.sleep(sleep_ms / 1000.0) threading.Thread(targetloop, namename, daemonTrue).start()这段代码里有个细节sleep_ms是用目标周期减去实际执行耗时算出来的这样能保证长期平均周期稳定不会因为单次执行慢而累积漂移。3.4 断网缓存与断点续传的实现这是边缘网关最核心的能力之一也是最容易做砸的地方。我的做法是上行层每次发送数据前先写入本地缓存表带一个已发送标记收到云端确认后再更新标记。断网时数据持续写入标记保持未发送。网络恢复后后台任务扫描未发送记录按时间顺序补传。这里有几个坑缓存表会无限增长。必须设置保留策略比如最多保留7天或最多100万条超了删最老的。否则磁盘满了整个网关就挂了。补传速度要限流。网络刚恢复时如果一股脑全推上去可能把网络打满反而影响实时数据。我一般限制补传速率比如每秒最多100条。时间戳要用采集时刻不是发送时刻。否则补传上去的数据时间全乱了云端分析就废了。提示本地缓存的时间戳建议用UTC避免时区和夏令时问题。云端展示时再转本地时间。4. 数据模型从原始寄存器到可用信息数据采集上来只是第一步怎么组织这些数据决定了云端能用它做什么。4.1 点位建模的四个层次我习惯把点位建模分成四层设备-测点-属性-语义。设备层是物理设备比如1号注塑机。测点层是设备上的一个采集点比如料筒温度。属性层是测点的具体字段比如当前值单位量程。语义层是这个点的业务含义比如属于温度类、参与能耗计算、报警阈值上限280度。很多项目只做到测点层导致云端拿到一堆DB1.DBD0235.6这样的数据完全不知道是什么。加上语义层之后云端才能做真正的分析。4.2 量纲转换和死区过滤量纲转换是必须的。PLC里存的往往是原始值比如温度存的是2356表示235.6度需要除以10。压力可能是4-20mA对应的0-1000需要线性映射。死区过滤是省流量的关键。如果温度一直在235.5到235.7之间波动没必要每次都上报。设置一个死区比如0.5度只有变化超过死区才上报。但要注意死区过滤后云端看到的是变化点做趋势分析时要理解这一点。# 死区过滤 变化上报 class DeadbandFilter: def __init__(self, deadband): self.deadband deadband self.last None def check(self, value): if self.last is None or abs(value - self.last) self.deadband: self.last value return True return False4.3 设备状态机的建模设备运行状态不能简单用一个布尔值表示。实际设备有运行、待机、报警、停机、维护等多种状态而且状态之间有转换逻辑。我的做法是在边缘侧维护一个状态机根据多个采集点综合判断当前状态。比如运行的判断可能是主电机电流大于阈值 且 无报警 且 门锁闭合。这个逻辑放在边缘侧云端只接收状态结果既减轻云端负担又保证断网时状态判断不中断。状态变化时上报一条事件而不是持续上报状态值。这样云端的事件流很清晰也省流量。4.4 报警的本地判断与上报报警判断一定要放在边缘侧。原因很简单报警是时效性要求最高的等数据传到云端再判断延迟可能好几秒而且断网就完全失效了。边缘侧报警逻辑要处理几个问题抖动抑制值在阈值附近波动时不要反复报警、报警分级提示、警告、严重、确认机制报警产生后需要确认未确认的持续提醒。报警上报用独立通道优先级高于普通数据。MQTT里可以用不同的Topic云端订阅时给报警Topic更高的处理优先级。5. 云端接入MQTT、时序库与平台选择数据到了云端怎么存、怎么用是另一半工程。5.1 MQTT的Topic设计MQTT是工业上云最常用的上行协议轻量、支持QoS、有断线重连。但Topic设计不好后期会很痛苦。我的Topic命名规范是{企业}/{工厂}/{产线}/{设备类型}/{设备ID}/{数据类型}。比如acme/shanghai/line1/injection/machine01/telemetry。这样设计的好处是可以用通配符订阅。云端要订阅所有注塑机的遥测数据订阅acme/shanghai/line1/injection//telemetry就行。数据类型我一般分三种telemetry周期遥测、event事件如状态变化、alarm报警。分开的好处是可以用不同的QoS和处理策略。QoS选择上遥测数据用QoS 1至少一次报警用QoS 1或2事件用QoS 1。QoS 0虽然快但会丢工业场景基本不用。5.2 时序数据库的选型云端存储遥测数据时序数据库是标配。主流选择有InfluxDB、TDengine、TimescaleDB。数据库优势适用场景InfluxDB生态成熟、查询语言友好中小规模、快速上手TDengine国产、压缩率高、写入快大规模、成本敏感TimescaleDB基于PostgreSQL、SQL兼容需要复杂关联查询我个人的经验是如果团队熟悉SQLTimescaleDB上手最快如果追求写入性能和存储成本TDengine很能打如果要用现成的可视化生态InfluxDB配套最全。选型时还要考虑数据保留策略。原始数据一般保留3-6个月聚合数据小时级、天级保留几年。这个策略要在建库时就设计好后期改很麻烦。5.3 开源物联网平台的取舍热词里物联网平台开发thinglinks这类开源平台出现不少。开源平台的好处是功能全、开箱即用坏处是定制成本高、出问题排查难。我的建议是如果项目周期紧、需求标准用开源平台快速搭起来没问题。但如果需求有特殊性、或者后期要深度定制不如自己用MQTT Broker加时序库加应用层搭一套可控性更强。用开源平台时要注意数据主权问题。数据存在平台自己的表结构里想导出或迁移可能很麻烦。接入前一定要确认数据能不能方便地导出。5.4 云端数据清洗与补全边缘侧虽然做了预处理云端还是要做一层清洗。主要处理重复数据QoS 1可能重复投递、乱序数据补传的数据时间戳可能早于实时数据、缺失数据网络问题导致的空洞。乱序处理是重点。云端收到数据后不能直接按到达顺序存要按时间戳排序。对于补传的历史数据要能正确插入到历史区间。缺失数据的补全策略要看业务。对于监控展示可以用前值填充对于能耗统计缺失时段要标记出来不能简单填充否则统计结果不准。6. 现场排错那些文档里不会写的问题这部分是我最想分享的因为现场问题往往最耗时间而文档里基本不会提。6.1 采集不稳定时好时坏这是最常见的现象。可能的原因按概率排序网络干扰、从站响应慢、轮询太密、地址冲突。排查思路先用抓包工具看通信层。如果请求发出去了但从站不响应是设备侧问题如果响应了但数据不对是地址或解析问题如果请求都发不出去是网关侧问题。RS485总线上如果多个从站一个从站故障可能拖垮整条总线。排查时可以逐个断开从站看通信是否恢复。6.2 数据对不上云端和现场不一致这种问题最让人头疼因为涉及链路长。我的排查顺序是现场仪表显示值 → PLC内部值 → 网关采集值 → 云端存储值逐段对比。大部分情况问题出在量纲转换。比如现场显示235.6度PLC里是2356网关采集到2356但没做转换云端就显示2356。或者字节序搞反了2356变成60211这种离谱值。还有一种情况是采集了错误的寄存器。Modbus地址偏移搞错读到了相邻的寄存器。这种要靠对照设备手册逐个核对。6.3 断网恢复后数据重复或丢失这是缓存和补传逻辑的问题。重复通常是QoS 1的固有特性加上补传没做去重。丢失通常是缓存写入和发送的顺序问题——如果先发送后缓存发送成功但缓存失败就会丢如果先缓存后发送发送成功但标记更新失败就会重。正确做法是先缓存标记未发送→ 发送 → 收到确认后更新标记。这个顺序保证了至少一次投递配合云端去重实现精确一次。6.4 网关运行几天后变慢或死机长时间运行出问题通常是内存泄漏、缓存表膨胀、连接未释放。内存泄漏要靠代码审查和长时间压测发现。缓存表膨胀要靠保留策略控制。连接未释放常见于异常处理不完善——连接失败后没关闭旧连接就重连导致句柄耗尽。我的经验是给网关加定期自检和重启机制。比如每天凌晨低峰期重启一次采集进程能规避很多累积性问题。这不是优雅的方案但在现场很实用。6.5 时间不同步导致的数据错乱边缘网关和云端时间不一致会导致数据时间戳错乱。网关要配置NTP同步且要有多个NTP源做冗余。如果现场网络不能访问外网NTP要在本地部署NTP服务器。时间同步出问题时补传的数据时间戳可能比实时数据还新云端排序就乱了。所以网关启动时要先确认时间同步成功再开始采集。7. 一套可复用的最小可行架构讲了这么多最后给一套我自己常用的最小可行架构适合中小规模项目快速落地。边缘侧一台Linux边缘网关ARM Cortex-A2路RS4852路网口跑采集程序。采集层用python-snap7、pymodbus、opcua这几个库覆盖主流协议。处理层做量纲转换和死区过滤。缓存用SQLite。上行用paho-mqtt。传输层MQTT over TLSQoS 1Topic按前面说的规范设计。云端EMQX或Mosquitto做BrokerTDengine或TimescaleDB存时序数据Grafana做可视化再写一个应用服务处理报警和事件。这套架构我跑过好几个项目稳定性和成本都控制得不错。规模再大就考虑加消息队列Kafka做缓冲加规则引擎做流处理。提示最小架构不代表可以省掉安全。TLS、认证、权限控制一个都不能少尤其是涉及远程写操作的场景。这套东西说起来是一篇文章做起来是几个月的调试。现场永远比实验室复杂多留调试接口、多做日志、多考虑异常情况比追求架构优雅重要得多。我现在的习惯是任何采集程序上线前先在实验室模拟断网、模拟设备掉线、模拟数据异常把异常路径都跑一遍现场才能少熬夜。