资讯动态

注塑机联网实战:协议接入、网关采集与OEE数据对账

发布时间:2026/10/27 2:11:14 来源:尧图企业网站定制
简介面向注塑机设备管理与智能制造升级的《注塑机设备工业物联网智能解决方案》文档适合注塑生产企业设备管理、自动化运维及工业物联网实施人员参考聚焦传统注塑机状态靠人工记录、协议多样难统一、缺乏远程监控与数据分析等痛点。文档围绕工业物联网网关的5G/4G/WiFi通信、注射压力与油温模温等参数采集、后台运行状态展示、产量停机故障综合分析、远程故障诊断与程序升级、历史数据查询等模块展开并说明模温机、下料机等周边设备的接入方式形成从现场采集到云端运维的完整思路。资源包共1个docx文件约169KB轻量便于查阅与内部传阅。目前已有227人学习下载可作为设备联网改造方案选型、项目汇报或实施规划的参考材料。1. 车间里那本手抄报表才是注塑机联网真正的起点我去过不少注塑车间最显眼的往往不是机械手而是挂在机台边那本卷了边的交接班记录本——模次、停机时间、报警代码全靠人抄抄完还要录入表格第二天才能汇总。问题不在于员工不认真而在于注塑机设备工业物联网这件事的起点被搞反了多数人一上来就买平台、选大屏结果数据源是错的后面全白搭。这套方案文档讲的核心其实很朴素先用一台工业物联网网关把注塑机的注射压力、油温、模具温度、注射速度、合模注射储料顶针座台等状态实时取出来统一协议、统一时间戳再做状态监控、故障诊断和 OEE 分析。它适合正在推设备联网的注塑厂设备科、做产线改造的系统集成商以及手里有大量老机、协议杂乱不知从哪下手的运维负责人。下面按我拆文档和实际落地的顺序讲怎么盘协议、怎么选网关、脚本怎么写、坑在哪。2. 协议盘点到网关选型四种接入路径怎么选才不返工2.1 先摸清控制器EUROMAP 77、EUROMAP 63、PLC 寄存器、外挂传感器方案文档里说不同注塑机企业、不同工序设备工控协议众多无法统一接入这句话是整份文档最值钱的一句也是实际项目里最容易低估工作量的地方。注塑机的数据不像 PLC 产线那么规整同样是注塑机2018 年以后出厂的机器和新世纪前后的老机器能拿到的数据差了一个数量级。我一般把接入路径分成四类先逐台打标再谈网关数量路径适用设备能拿到的数据典型实施代价EUROMAP 77OPC UA近几年的新机控制器支持 OPC UA 信息模型完整工艺曲线、模次、报警、配方名低网关作 OPC UA Client 直连 4840 端口EUROMAP 63FTP 文件中等年份设备控制器按标准在 FTP 目录写 XML 文件周期数据、模次、停机原因粒度到每个周期一条中需要轮询目录、处理半文件与重复PLC 寄存器控制器不开放但电气柜里有 PLC 参与逻辑控制运行/自动/报警状态位、模次脉冲、少量设定值中需要电气图纸点位受限于程序里有的变量外挂传感器 IO完全无通信口的老机开合模动作、电流、模温只能算开机率与产量高但能覆盖必须联网的老机判断顺序建议是先查控制器型号和固件看有没有以太网口和 OPC UA 服务没有以太网口但有串口且支持标准文件交换走第二条串口只跑私有协议、拿不到文档的退到 PLC 侧连 PLC 都没有的才考虑外挂。这里有个血泪经验不要因为一台机器采不到工艺曲线就卡住整条产线OEE 和故障统计只需要状态位和模次先把这两样拿到工艺参数后面再补。方案文档里提到网关可同时接入模温机、下料机等周边设备这一点在点表设计时就要预留。模温机的温度是判断模具是否达到工艺条件的重要依据下料机的运行状态影响待料停机归类如果后期再加点位地址和命名规范就得返工。2.2 网关硬件选型的六个硬指标文档里写了 5G、4G、WiFi 多种通信方式这是对外宣传口径。真到选型我一般盯这六项按优先级排协议栈是否包含你需要的全部协议且是否要单独授权。有些网关 OPC UA Server 免费、Client 收费EUROMAP 63 的文件客户端要另买插件报价时一定问清楚。串口数量与隔离。一台 RS485 挂多台设备时波特率和从站地址冲突是常态能一台网关带 2~4 路独立 RS485 会省很多事光电隔离能挡掉不少地电位差导致的通信中断。边缘脚本能力。支持 Python 或 Lua 二次开发的网关能把字节序换算、状态机判定放在边缘侧做云端只收结果流量和算力都省。这一条在实际项目里权重很高。断网缓存容量与续传策略。4G 信号在钢结构厂房里掉线是必然事件缓存能不能按时间戳补传、补传会不会打乱时序直接决定历史曲线好不好看。供电与防护等级。配电柜内安装 IP30 够用直接挂机台旁边就得 IP65注塑车间有油雾和水汽这一项省不得。看门狗与远程重启。设备在异地厂区跑飞一次要派人跑两百公里这个功能必须有。提示网关数量和设备数量不是一比一。串口设备通常一路 485 带 8~16 台以太网设备可以多台共用交换机按协议 物理位置分组比按机台数买划算。2.3 现场调研清单与采集点表怎么定落地时真正决定成败的是那张采集点表。我的做法是先做一轮现场调研每台设备填一行字段包括设备编号、控制器型号与固件、通信口类型与占用情况、协议、从站地址/端口、可提供的点位清单、采样周期要求、所在车间与网络条件。调研完再回办公室统一点表不要让每个实施人员自己命名否则后面inj_pressure和InjectionPressure1混在一起平台上做聚合查询会很难受。点表本身建议按下面这几列定采集脚本可以直接读这张表驱动不用一设备一脚本字段说明示例tag统一命名小写下划线inj_pressureaddrPDU 地址文档里的 40001 要减 10count占用寄存器数2dtype数据类型float32/int16/boolbyte_order32 位数据的字节序CDABscale工程值系数0.1unit单位barperiod_ms采样周期1000deadband变化上报死区0.5采样周期要分档不要一刀切。油温、模温这类热惯性大的量 5~10 秒一次足够注射压力这类瞬态量如果真要看波形需要 20~50ms 级别普通轮询做不到得靠控制器侧曲线导出或网关的高速采样通道模次计数用状态位上升沿1 秒轮询已经够用但要注意周期短于 1 秒的快机可能漏计这种设备单独把轮询降到 200ms。3. 从寄存器到云端采集脚本、工程值换算与断网续传3.1 一个能跑起来的 Modbus 采集循环方案文档强调实时采集注射压力、油温、模具温度、注射速度落到代码就是按点表轮询寄存器。下面这段是现场调试用得最多的一版结构简单改点表就能换设备from pymodbus.client import ModbusTcpClient import time, json # 点表实际项目从数据库或 YAML 读这里内联方便调试 POINTS [ {tag: inj_pressure, addr: 0, count: 2, dtype: float32, order: CDAB, scale: 1.0}, {tag: oil_temp, addr: 10, count: 1, dtype: int16, order: AB, scale: 0.1}, {tag: screw_speed, addr: 12, count: 1, dtype: uint16, order: AB, scale: 1.0}, ] client ModbusTcpClient(host192.168.1.50, port502, timeout1.5) client.connect() def poll_once(slave_id1): frames {} for p in POINTS: # 注意pymodbus 3.7 之后 slave 参数更名为 device_id rr client.read_holding_registers(p[addr], countp[count], slaveslave_id) if rr.isError(): frames[p[tag]] None # 单点失败置空不中断整轮 continue frames[p[tag]] rr.registers return frames while True: raw poll_once() # 换算与状态判定在这里做见 3.2 print(json.dumps(raw, ensure_asciiFalse)) time.sleep(1)这段代码有三个刻意保留的细节。第一单点读失败不抛异常、不中断整轮注塑机控制器在注射动作瞬间响应会变慢一个点位超时不应该导致整台设备离线。第二地址用的是 PDU 偏移量如果手头的协议文档写的是 40001 这种 Modbus 数据模型地址必须减 1这个减一坑每年都能遇见几次。第三slave参数在 pymodbus 3.7 之后改名为device_id脚本换库版本时最容易在这里报 TypeError。生产环境还要加三样东西超时重连client.connect()失败后指数退避重试、轮询间隔按点表分档而不是全局 sleep、以及每轮采集打一个单调递增的序号方便后面做丢包对账。3.2 工程值换算字节序、系数与超量程保护32 位浮点在 Modbus 里占两个寄存器但厂商实现顺序五花八门ABCD大端、CDAB字交换、BADC、DCBA 四种都见过。读出来的数如果像 1.37e-38 这种天文数字或者 0八成就是字节序错了不是通信断了。下面这个换算函数我一直在用import struct def regs_to_value(regs, dtype, orderAB, scale1.0): 寄存器 - 工程值含字节序处理与超量程保护 if dtype in (int16, uint16): v regs[0] 0xFFFF if dtype int16 and v 0x7FFF: v - 0x10000 # 补码还原负值油温偶尔会到负数 return round(v * scale, 3) b struct.pack(HH, regs[0] 0xFFFF, regs[1] 0xFFFF) # 先按 ABCD 打包 if order CDAB: b b[2:4] b[0:2] elif order BADC: b b[1::-1] b[3:1:-1] elif order DCBA: b b[::-1] v struct.unpack(f, b)[0] # 超量程保护NaN 和明显越界的值直接丢弃避免污染统计 if v ! v or abs(v) 1e6: return None return round(v * scale, 3)逻辑说明先按标准大端打包成 4 字节再按配置的字序重排最后解 float。四个分支覆盖了绝大多数国产和进口控制器的实现。参数方面scale用整数寄存器时最常见比如油温寄存器返回 452 代表 45.2℃系数就是 0.1浮点寄存器一般系数为 1.0但有些设备内部用 0.01MPa 单位也要在点表里体现。v ! v这个判断是过滤 NaNabs(v) 1e6是挡掉字节序错误导致的荒谬值。这两个检查看似多余实际能把脏数据挡在入库之前比事后在平台侧清洗省事得多。注意字节序不要靠猜。调试时用 Modbus 调试工具读同一时刻的两个寄存器拿设备面板上显示的实际值反推四组顺序试一遍能对上的那组就是答案然后写进点表不要留在代码里硬编码。3.3 MQTT 上报报文与断网缓存队列上行报文我一般按设备维度、批量上报组织主题设计成plant/{plant}/{line}/{machine}/telemetry一条消息带一组点位和时间戳比一个点位一条消息省 90% 以上的流量。以单台设备 60 个点位、1 秒采集为例逐点上报一天约 518 万条消息批量上报后压到 8.6 万条4G 流量从几个 G 降到几百兆。import sqlite3, json, time, paho.mqtt.client as mqtt conn sqlite3.connect(/data/cache.db) conn.execute(CREATE TABLE IF NOT EXISTS buf( ts INTEGER, topic TEXT, payload TEXT, PRIMARY KEY(ts, topic))) def build_payload(machine_id, values): return json.dumps({ mid: machine_id, ts: int(time.time() * 1000), # 边缘侧打时间戳不要用云端接收时间 seq: next_seq(machine_id), v: values # {inj_pressure: 82.4, ...} }, ensure_asciiFalse) def publish_or_cache(topic, payload): try: info client.publish(topic, payload, qos1) if info.rc ! mqtt.MQTT_ERR_SUCCESS: raise RuntimeError(info.rc) except Exception: # 断网落盘恢复后按 ts 顺序补传 conn.execute(INSERT OR IGNORE INTO buf VALUES(?,?,?), (int(time.time() * 1000), topic, payload)) conn.commit()三个关键点。时间戳必须在网关侧打用云端接收时间会在断网补传时全部堆在同一秒历史曲线直接失真。qos 用 1 不用 2工业遥测允许极小概率重复去重靠seq在平台侧做qos 2 的握手开销在弱网下反而拖慢整体吞吐。缓存表用INSERT OR IGNORE加主键补传重试时天然幂等不会把同一条数据写两遍。补传策略上我一般设一个上限比如缓存 72 小时或 50 万条超了丢最旧的。听起来不优雅但比把网关存储写满导致采集进程崩溃要好得多。3.4 EUROMAP 63 文件采集的幂等处理走文件交换路线的老设备坑主要在读半截文件。控制器往 FTP 目录写 XML 时网关如果同时去读会拿到一个不完整的文件解析直接失败。可靠的做法是只认最终态文件并用文件名里的序号做去重# 目录轮询只处理 .job 结尾且 30 秒内未修改的文件 find /mnt/em63/out -name *.job -mmin 0 -mmin -5 | while read f; do base$(basename $f .job) # 已处理过的序号跳过实现幂等 grep -qx $base /data/em63.done continue python3 /opt/em63/parse.py $f echo $base /data/em63.done done-mmin 0保证文件至少静置一分钟再读em63.done记录已处理的文件名序号避免重复入库。这个方案不优雅但极其稳定跑了两年没出过重复数据。文件解析出来的字段和寄存器路径最终要归一到同一套点表否则平台侧会出现两套设备模型后面做 OEE 聚合会非常痛苦。4. 平台侧落地状态机、OEE 与告警阈值怎么定才不虚高4.1 六态状态机从信号位到可统计的运行状态方案文档要求动态形式将状态、合模、注射、储料、顶针、座台等信息实时直观显示这是动作级状态给人看的。真正用于统计的是设备级状态我一般归成六类运行、待机、调机换模、故障停机、计划停机、离线。判定不能只看一个运行中信号位必须多信号融合def judge_state(tags, prev, dur_ms): 输入当前信号快照与上一状态输出设备级状态 if tags.get(comm_ok) is False: return offline if tags.get(alarm_code): return fault # 有报警号优先判故障 if not tags.get(power_on): return planned_stop # 主电源断开 if tags.get(manual_mode): return setup if dur_ms 30 * 60 * 1000 else setup_long if tags.get(auto_mode) and tags.get(cycle_running): return running # 自动模式但超过 3 个周期时间没有模次脉冲判待机 if tags.get(auto_mode) and dur_ms 3 * tags.get(cycle_time_ms, 30000): return standby return prev参数上最关键的是dur_ms即当前信号组合已持续的时长。刚切换模式的头几秒状态是不稳定的加一个 30 秒的稳定窗口再落库能滤掉大量抖动。setup_long这个细分状态是为 OEE 服务的短时间调机算换模超过半小时的往往是没有订单或者等料归到计划停机里否则时间稼动率会被拉低得莫名其妙。一个反直觉的结论状态机的准确率瓶颈不在算法在信号完整性。有些设备只给一个自动信号不给模次脉冲这种机器判运行和待机只能靠电流互感器辅助方案文档里没提这一层但现场绕不开。4.2 OEE 三率与停机原因归类的 SQL 实现OEE 时间稼动率 × 性能稼动率 × 良品率。三个率的分子分母口径必须提前跟生产部门对齐尤其是计划生产时间扣不扣午休、换模算不算计划停机这几条不一致算出来的数字谁都不认。下面是我常用的一段聚合查询WITH base AS ( SELECT machine_id, SUM(CASE WHEN state running THEN dur_s ELSE 0 END) AS run_s, SUM(CASE WHEN state fault THEN dur_s ELSE 0 END) AS fault_s, SUM(CASE WHEN state setup THEN dur_s ELSE 0 END) AS setup_s, SUM(CASE WHEN state standby THEN dur_s ELSE 0 END) AS standby_s, SUM(CASE WHEN state planned_stop THEN dur_s ELSE 0 END) AS plan_s FROM state_log WHERE ts :shift_start AND ts :shift_end GROUP BY machine_id ) SELECT b.machine_id, ROUND(b.run_s * 1.0 / NULLIF(b.run_s b.fault_s b.setup_s b.standby_s, 0), 4) AS availability, ROUND(SUM(p.good_qty p.ng_qty) * :ideal_cycle_s * 1.0 / NULLIF(b.run_s, 0), 4) AS performance, ROUND(SUM(p.good_qty) * 1.0 / NULLIF(SUM(p.good_qty p.ng_qty), 0), 4) AS quality FROM base b JOIN production p USING (machine_id) GROUP BY b.machine_id;分母里plan_s是明确排除的这正是前面强调状态细分的原因如果把计划停机混进运行时间性能稼动率会被系统性压低反过来把调机时间算进运行时间稼动率虚高两种情况都会让 OEE 失去对标意义。:ideal_cycle_s取该设备近 30 天最快 10% 周期的均值比用铭牌理论值更贴近实际也比用平均周期更不容易被慢速生产掩盖问题。停机原因归类建议用报警号 → 原因大类 → 责任班组三级映射表不要把原始报警文本直接展示给管理层几百条报警码没人看得懂。方案文档里的故障类型数据在这一点上价值最大前提是报警号采集完整。4.3 告警阈值、去抖时间与远程诊断的边界文档提到实时告警和故障诊断分析、远程故障定位和程序升级这里要泼一点冷水远程程序升级在注塑场景风险很高控制器固件升级失败可能导致整机瘫痪多数项目最后只做到参数下发和程序备份。真正落地的是阈值告警和故障码推送。告警项触发条件去抖动作油温异常油温 设定值 8℃ 持续120s推送班组不自动停机高压报警报警号命中高危码表30s立即推送设备科 班组长长时间待机standby 持续 20min0推送调度提示排产通信中断连续 3 个周期无数据30s只记录不推人模次异常单小时模次 均值 50%3600s推送工艺提示检查去抖时间比阈值本身更重要。注塑机开模瞬间油温会有波动不去抖一天能报上百次通信中断告警如果也推给班组长手机很快就没人看了。我的原则是影响质量的告警报给人影响连接的告警只进报表。4.4 时序库建模超级表、标签与降采样单台设备 60 点位、1 秒采样一天 518 万点100 台就是 5 亿点。这个量级用关系库硬扛很快就撑不住时序库是标配。建表时把设备编号、产线、车间做成标签点位做成列能大幅压缩存储-- TDengine 建模示例 CREATE STABLE IF NOT EXISTS meters ( ts TIMESTAMP, inj_pressure FLOAT, oil_temp FLOAT, screw_speed FLOAT, cycle_time INT ) TAGS (plant BINARY(16), line BINARY(16), machine BINARY(24)); -- 建子表一台设备一张子表标签自动继承 CREATE TABLE IF NOT EXISTS m_101 USING meters TAGS (p1, l2, m101);查询时按标签过滤写入按子表批量提交500 条一批能把写入吞吐拉高一个量级。历史数据保留策略我一般设三档原始数据保 30 天1 分钟降采样保 1 年班次级汇总永久保留。看趋势用汇总表追故障才查原始点这样存储成本能压到原来的十分之一。5. 避坑与排查上线后最容易翻车的五个地方5.1 采集层读错、读慢、读不到现象一压力值显示 1.37e-38 或者 0通信指示灯正常。原因基本是 32 位浮点字节序不匹配四种顺序里试错了一种。解决方式是拿设备面板实时值做基准四组顺序逐个套能对上的写进点表同时把 3.2 里的 NaN 和越界判断加上避免脏数据入库。现象二设备越多采集延迟越大云端曲线整体滞后十几秒。原因是脚本用全局time.sleep(1)加串行轮询设备数一多累计耗时超过周期。解决方式是按时效性分档状态位 500ms、工艺量 2s、温度 10s各档独立线程并且用上一轮结束时间 周期做补偿而不是从本轮开始算。现象三网关重启后部分串口设备永久离线。多数是串口句柄没释放或者从站地址冲突两台设备配了同一个地址总线上互相打架。解决方式是网关启动脚本里先做一次端口复位再逐台 ping 式探测地址冲突的在点表里标红现场改拨码。5.2 传输层时间戳乱、流量超标、断网丢数现象四断网恢复后历史曲线上出现一大段数据堆在同一秒。原因是用了云端接收时间做时间戳补传时全部落在恢复瞬间。解决办法只有一个网关侧打时间戳平台侧按报文里的ts入库接收时间只做审计字段。这条改起来简单但前期架构没设计的话存量数据没法补救。现象五4G 卡一个月跑掉几十个 G。统计下来多半是全量定时上报没做变化上报和死区。处理方式是给每个点位配deadband变化超过死区才发同时把上报周期从 1 秒放宽到 5 秒做批量流量能降一到两个数量级。附带一个容易忽略的点MQTT 的 keepalive 设太短心跳包本身在弱网下也是流量和电量的消耗。5.3 应用层状态误判、OEE 虚高、告警风暴现象六设备明明在出产品平台显示待机两小时。常见原因是只采了自动模式信号没采模次脉冲或者模次计数用了电平而不是上升沿一个周期被计了几十次或者一次没计。解决办法是把模次判定改成开模到位信号的上升沿并加一个最小间隔过滤小于 5 秒的重复脉冲丢弃。另一个隐蔽原因是模具更换后周期时间变了状态机里固定的超时阈值失效需要按设备动态取最近周期的中位数。现象七OEE 算出来 95%车间主任说绝对不可能。八成是分母少了。检查三处计划停机有没有被算成运行、调机时间有没有混进运行时间、良品数是不是直接用了总产量。这三条任意一条出问题OEE 都会虚高到不可信。我的习惯是先手工核算一个班次跟系统对上了再全厂推。现象八上线第一周班组长手机被报警刷屏第二周就没人看了。告警没有去抖、没有分级、没有收敛。处理方式是给每类告警配去抖窗口和静默期同一设备同类告警 10 分钟内只推一次并且严格区分给人和进报表两类。提示排查顺序永远是自下而上——先确认网关能读到寄存器再确认报文格式正确最后才怀疑平台。反过来查八成时间浪费在平台日志里。6. 验收前必做的一轮压测与数据对账项目交付前我一定会做两件事缺一件都不敢签字。第一件是压测用一个脚本模拟全量设备的上行速率看平台在峰值下会不会丢消息、写入延迟能不能压在 2 秒以内。import asyncio, json, time import paho.mqtt.client as mqtt async def sim_device(mid, client, n200): for i in range(n): # 每台模拟 200 条报文 payload json.dumps({mid: mid, ts: int(time.time()*1000), seq: i, v: {inj_pressure: 80 i % 5, oil_temp: 45.2}}) client.publish(fplant/p1/l1/{mid}/telemetry, payload, qos1) await asyncio.sleep(0.05) # 20 条/秒/台 async def main(): client mqtt.Client(client_idsim) client.connect(broker.local, 1883) client.loop_start() await asyncio.gather(*[sim_device(fm{i:03d}, client) for i in range(1, 51)])五十台并发、每台 20 条每秒合计 1000 条每秒跑十分钟看平台入库条数与发送条数的差值。差值超过 0.1% 就得回头查 broker 的队列上限和数据库批量写入配置。参数上qos1是为了贴近真实sleep控制单机速率实际项目里按单台设备的真实报文频率设不要拍脑袋放大。第二件是对账。挑三台设备让操作工手工记录一个班次的模次跟平台统计值比对偏差超过 0.5% 就要找原因——通常是模次脉冲漏计或者状态机把调机时间算进了运行。对账看起来土但它是唯一能证明数据可信的手段比任何大屏演示都有说服力。这套方案文档的价值不在于列了多少功能而在于它把协议杂乱的老设备怎么统一接入这条最难的路指出来了。从我踩过的坑看真正决定项目成败的是点表、时间戳和状态机这三样枯燥的东西大屏反而是最后才需要考虑的。从那以后我每次进场第一件事就是先把点表和模次对账表打出来宁可晚两周上线也不带着错数据跑。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑