资讯详情

资讯详情

基于C#和OPC UA的注塑机数据采集软件设计与实现

简介面向注塑机数据采集与系统集成场景这套基于C#开发的恩格尔注塑机采集程序支持CC100-CC300、E63及Eurp77等不同接口类型覆盖欧规63采集器应用可稳定采集开模数、节拍、生产状态等设备运行数据并能借助KepServer将采集结果写入MS SQL数据库满足车间级数据汇总与追溯需求。压缩包体积约625KB共含106个文件以C#源码工程为主体核心包括17个cs源文件、4个exe可执行程序、3个dll动态链接库同时搭配config配置文件、resources资源文件、sample示例文件等便于查看程序结构、运行配置及二次开发参考。目前该资源已有1017人学习/下载适合工业自动化、注塑车间数字化及MES系统对接开发人员深入参考。从源码中可以学习恩格尔各控制器型号的通信协议对接方式掌握设备数据采集、节拍统计、状态解析以及数据库落地的完整实现思路附带的可执行程序与配置示例也能帮助读者更快地在实际项目中部署验证整体可操作性强。1. 注塑机采集软件把车间的数据黑匣子接到你的数据库里车间里几十台注塑机每台控制器都有实时工艺数据但MES要产量、品质部要曲线、工艺员要参数全得靠人去操作屏前抄录这几乎是每个注塑车间的常态。这套基于C#开发的注塑机采集软件要解决的就是这个抄数问题——通过注塑机自带的OPC UA数据接口把设备当数据源直接接入系统一台机器就是一个可编程的数据采集点。它不需要拆机、不需要装传感器适合想打通设备层到MES层数据链路、又不愿被厂商封闭协议绑死的注塑车间和装备集成商。2. 技术选型与整体架构为什么是C#、走哪个协议、数据怎么流转2.1 协议选型Euromap 63/67是主轴Modbus TCP兜底注塑机品牌五花八门但欧洲系设备基本都会支持Euromap 63标准接口协议E牌注塑机在控制器上会开放一个以太网口作为标准数据接口。Euromap 63定义的是OPC DA方式而新一代的Euromap 67则走OPC UA把节点结构和地址空间都规范好了。你不需要理解注塑机内部的复杂逻辑只需要知道节点ID对应哪个工艺参数这张映射表。选型时的实际取舍是这样E牌新机型上Euromap 67是标配OPC UA直接可用老机型或低配机型只开了Modbus TCP或者连Euromap 63也只有一个OPC DA网关。我在项目里做了两层采集方案——优先走OPC UA读取失败自动降级到Modbus TCP地址轮询。这样同一套采集服务能覆盖不同年份、不同配置的设备不用每接一台新机器就改一套代码。2.2 整体架构采集服务、协议适配、数据持久化三层整个系统分三层我在代码里把目录也按这三层组织后续加设备、加协议都很顺手层次职责技术选型接入层与注塑机控制器通信维护连接生命周期OPC UA客户端、Modbus TCP业务层数据点映射、单位换算、缓存与报警判断C# 自定义服务存储层持久化采集数据供MES/报表调用SQL Server可选InfluxDB接入层最重要的是连接管理因为工厂环境里设备网络不稳定是常态连接要能自动恢复。业务层管的是注塑机吐出来的原始值到业务含义明确的数据之间的翻译——比如控制器返回的料筒温度可能是以0.1℃为单位的整数直接存数据库会把语义埋掉。存储层我用SQL Server做主库因为车间MES基本都用它这样采集软件的数据表能直接被MES存储过程调用。这套分层设计看起来简单但我吃过亏的地方是最早把业务逻辑全写在采集回调里一个回调里做转换、报警、写库后来想加一个温度超限才报警的需求硬是把回调函数拆成了三个类。从那以后我坚持分层宁可多写几个接口也不在回调里堆逻辑。2.3 项目目录从解决方案入手看结构采集服务的解决方案按功能拆分项目核心目录结构如下MachineCollector.sln |-- MachineCollector.Service // 后台采集服务Windows服务宿主 | |-- Connectors // 协议适配器OpcUaConnector.cs、ModbusConnector.cs | |-- Mapping // 数据点映射表MachinePoint.cs、PointMapper.cs | |-- Storage // 持久化DbWriter.cs、CacheBuffer.cs | |-- Diagnostics // 日志与运行监控DeviceHealthChecker.cs |-- MachineCollector.ConfigTool // 配置工具WinForm编辑设备清单与数据点 |-- MachineCollector.Api // 可选REST API供看板或MES拉取实时数据 |-- tests // 单元测试Mapping、Reconnect逻辑配置文件我习惯用独立的设备配置表而不是JSON硬编码——接一台新设备时在现场最怕的就是改完JSON还要重启服务做成数据库表配置工具后新增一台车间的设备十分钟搞定服务不重启也能热加载。3. 核心模块拆解从注塑机控制器到数据库的完整链路3.1 设备连接管理连接不是一次建立而是持续维护的状态机采集服务启动后要管理几十台设备的长连接每台设备都是一个独立的连接状态机。状态迁移路径是未连接 → 连接中 → 已连接 → 采集正常 → 断开 → 指数退避重连。每台设备在配置文件里有一个Device条目关键字段如下IpAddress注塑机控制器的IP地址PortOPC UA默认4840Modbus TCP默认502ProtocolOpcUa / ModbusTcp 两选一PollIntervalMs常规工艺参数的采集周期常见设置为1000ms即每秒采一轮ConnectionTimeoutMs连接超时默认3000ms设备连接这块的经验是不要全局共享一个OpcUaClient实例给所有设备每台设备独立维护自己的会话。原因很现实一台设备网络抖动会导致整个会话中断全局共享时其余设备会一起掉线独立会话最多影响一台隔离效果好。连接代码里我比较看重超时控制工厂网络环境比办公室复杂交换机老化、网线松动都很常见一个同步连接卡住两三秒是常事。所有连接操作都包了超时取消宁可返回失败走重连也不能让采集线程被一个坏连接拖死。3.2 数据点映射注塑机吐的是地址业务认的是字段名这是整个采集软件最繁琐、也最容易被低估的模块。E牌注塑机OPC UA服务器的地址空间中每个参数都有固定的节点ID比如料筒第1区温度是某个ID、注射压力是另一个ID。这些ID要用一张映射表翻译成业务字段名。数据点映射表的结构如下字段说明示例DeviceId设备编号E-001PointName业务字段名BarrelTempZone1NodeIdOPC UA节点ID / Modbus寄存器地址ns2;sTempZone1DataType原始值类型Int16 / UInt16 / FloatScale缩放到工程值的系数0.1Offset零点偏移0.0IsAlarm是否参与报警判断1单位换算是这层最容易被忽略的细节。好多注塑机返回的温度原始值要乘以0.1才是摄氏度压力可能要先除以10再转成MPa。这块我在项目里吃了大亏——早期想当然按1:1存库结果看板上的温度整体偏高十来度后来逐台核对传感器的量程系数才纠正过来。从那以后每接一台新机型第一件事就是掐着万用表和手持测温枪做一次标定对比绝对不轻信说明书上的默认系数。映射表我放在数据库里不写在代码里。理由很简单现场改映射需求频繁如果每次都要改代码重新编译会被车间催死放数据库后配置工具直接改一行记录就能热更新还能用SQL直接比对两台设备的映射差异。3.3 数据持久化与断线缓存别让数据库成为采集链路的瓶颈采集服务每秒钟会从几十台设备积累上千条数据如果每条都实时插入SQL Server数据库的压力很大而且网络抖动时写库失败会造成数据丢失。我采用的方案是内存队列 批量写入 断线缓存文件。具体流程是采集回调把一条数据丢入ConcurrentQueue后台一个独立线程每2秒批量取出拼接成一条批量INSERT语句写库。这样数据库的压力从吞吐量峰值模式变成了平稳批次模式机器配置不高也能抗住几十台设备的采集量。缓存文件是给极端场景兜底的。当写库连续失败超过5次数据先落本地SQLite或JSON文件等数据库恢复后再补写。这个设计在车间遇到过真实需求——有一次机房交换机故障数据库和采集服务失联了40多分钟如果没有本地缓存那段时间的工艺数据就全部丢了对品质追溯来说会变成一段空白。补传逻辑在后面第4章会具体讲。4. 关键代码解读一个采集周期的完整实现4.1 OPC UA客户端初始化与连接连接E牌注塑机的OPC UA服务器使用的是官方基金会标准库。初始化连接的关键是证书处理和会话建立// OpcUaConnector.cs 核心连接片段 public async Taskbool ConnectAsync(CancellationToken ct) { var config new ApplicationConfiguration { ApplicationName MachineCollector, ApplicationUri $urn:localhost:MachineCollector:{Guid.NewGuid()}, ApplicationType ApplicationType.Client, SecurityConfiguration new SecurityConfiguration { // 注塑机端一般要求客户端证书 // 首次握手时需手动信任服务器证书 ApplicationCertificate new CertificateIdentifier { StoreType CertificateStoreType.X509Store, StorePath CurrentUser\\My, SubjectName CNMachineCollector, OPlant }, TrustedPeerCertificates new CertificateTrustList { StoreType CertificateStoreType.Directory, StorePath CertificateStore/Trusted } }, TransportConfigurations new TransportConfiguration(), TransportQuotas new TransportQuotas { MaxMessageSize 65536 } }; await config.Validate(ApplicationType.Client).ConfigureAwait(false); var endpoint new EndpointDescription { EndpointUrl $opc.tcp://{_device.IpAddress}:{_device.Port}, SecurityPolicyUri SecurityPolicies.Basic256Sha256, SecurityMode MessageSecurityMode.SignAndEncrypt }; var endpointConfig EndpointConfiguration.Create(config); var endpointSelect new ConfiguredEndpoint(null, endpoint, endpointConfig); _session await Session.Create( config, endpointSelect, false, false, config.ApplicationName, 60000, // session超时60秒 new UserIdentity(new AnonymousIdentity()), null, ct).ConfigureAwait(false); _session.KeepAlive Session_KeepAlive; // 心跳检测 return _session ! null _session.Endpoint ! null; }连接代码里有两个细节值得说。一是证书问题OPC UA首次握手时客户端和注塑机的服务器端都需要信任对方的证书现场调试时最常见的报错就是CertificateUntrusted需要在设备侧操作屏上确认信任弹窗或者通过配置工具把设备证书导入客户端的信任目录。二是KeepAlive事件OPC UA会话空闲超过一定时间会被服务端关闭挂上KeepAlive事件后一旦检测到心跳失败就触发重连逻辑这个事件是断线自愈的关键入口。Session.Create里的60秒session超时是权衡结果——太短会导致采集数据还没处理完服务端就断开太长又会让故障发现变得迟钝。车间场景60秒合适配合KeepAlive每10秒一次的心跳能保证网络故障在1分钟内被感知。4.2 数据点订阅与批量读取数据读取有两种策略订阅Subscription和轮询Polling。对每秒采一轮的工艺参数用订阅更准确对偶尔读一次的报警状态用轮询更简单。// 订阅采集的核心实现 public void CreateSubscription() { var subscription new Subscription(_session.DefaultSubscription) { PublishingInterval _device.PollIntervalMs, // 订阅周期1000ms KeepAliveCount 5 }; // 把映射表里的全部数据点添加到订阅 foreach (var point in _mapper.GetPointsByDevice(_device.DeviceId)) { var monItem new MonitoredItem(subscription.DefaultItem) { StartNodeId new NodeId(point.NodeId, _session.NamespaceUris), SamplingInterval _device.PollIntervalMs, QueueSize 2, // 队列深度2防止瞬时积压 AttributeId Attributes.Value }; monItem.Notification (s, e) { // 回调中只做入队不做业务处理 var value e.NotificationValue.Value as ExtensionObject; if (value ! null) { _cacheBuffer.Enqueue(new DataSample { DeviceId _device.DeviceId, PointName point.PointName, RawValue value.ToString(), Timestamp DateTime.Now }); } }; subscription.AddItem(monItem); } _session.AddSubscription(subscription); subscription.Create(); }订阅关键点在Notification回调里只入队不做业务处理。很多第一次做采集的同学容易在这个回调里直接写库、转单位、判报警一旦设备出数据风暴线程会被拖死。我把所有后续处理都交给消费线程统一调度回调里只做一件事——把原始数据丢进队列。这样做虽然多了一个队列中转但换来了消费节奏的完全可控批量写库、补传、报警判断都能在同一个消费线程里有序执行。QueueSize 2是刻意设置的OPC UA服务端每个订阅项有队列缓存如果客户端处理慢了新数据会覆盖旧数据设为2能确保客户端短暂卡顿时数据勉强保留一份又不会积压太多导致延迟数据吃掉内存。4.3 断线重连与数据补传断线处理是采集软件稳定性的分水岭这里展示重连与补传的核心逻辑// 重连服务核心实现 private async Task ReconnectLoopAsync(CancellationToken ct) { int retryDelayMs 1000; const int maxDelayMs 60000; while (!ct.IsCancellationRequested) { try { if (_session ! null _session.KeepAlive CurrentState.Good) { retryDelayMs 1000; // 连接正常时重置退避间隔 _pendingReconnect false; await Task.Delay(2000, ct).ConfigureAwait(false); continue; } _pendingReconnect true; Logger.Warn($设备 {_device.IpAddress} 断线尝试重连...); await DisposeSessionSafeAsync().ConfigureAwait(false); var ok await ConnectAsync(ct).ConfigureAwait(false); if (ok) { // 重连成功后立即补传断线期间的缓存数据 await _cacheBuffer.FlushPendingAsync(_device.DeviceId).ConfigureAwait(false); Logger.Info($设备重连成功已补传 {_cacheBuffer.PendingCount} 条缓存数据); retryDelayMs 1000; } else { // 连接失败指数退避 retryDelayMs Math.Min(retryDelayMs * 2, maxDelayMs); Logger.Error($设备重连失败{retryDelayMs / 1000}秒后重试); } } catch (Exception ex) { Logger.Error(ex, 重连循环异常); retryDelayMs Math.Min(retryDelayMs * 2, maxDelayMs); } if (_pendingReconnect) await Task.Delay(retryDelayMs, ct).ConfigureAwait(false); } }指数退避重连是解决雪崩重连的关键。如果车间里40台设备同时断线、同时启动重连每台都在固定的10秒后去撞连接网络会出现二次拥塞。退避策略让不同设备的重连节奏错开重试间隔在第1秒、第2秒、第4秒……逐步拉长直到上限60秒避免给设备控制器造成连接风暴。补传逻辑在重连成功后第一时间触发把断线期间写入缓存文件的数据批量刷入主库保证品质追溯数据的完整性。// 缓存补传实现 public async Task FlushPendingAsync(string deviceId) { if (_pendingFile.Count 0) return; var pendingRows _pendingFile.DequeueAll(deviceId); int batchSize 500; for (int i 0; i pendingRows.Count; i batchSize) { var batch pendingRows.GetRange(i, Math.Min(batchSize, pendingRows.Count - i)); bool success await _dbWriter.BulkInsertAsync(batch).ConfigureAwait(false); if (!success) { // 写库失败则重新放回缓存队列保持数据不丢 _pendingFile.EnqueueRange(batch); Logger.Error($补传批次写库失败{batch.Count} 条数据已重新入队); break; } } }这段代码的亮点是批量补传和失败回垒500条一批是为了兼容SQL Server参数上限避免一次性传几千条导致命令超时。补传失败的数据回到缓存队列等待下一轮连接成功后再试从这个设计你可以看出来整个系统的数据保证策略是能传的实时传传不了先落地恢复后补传最终保证一条数据都不丢。5. 避坑指南现场调试注塑机采集最常见的六个坑5.1 现象OPC UA死活连不上报证书不受信任错误现场第一次接E牌注塑机时连接一直报CertificateUntrusted。原因是在安全模式下客户端发送的证书没有完成双向信任握手。解决步骤先看注塑机操作屏上有没有弹出信任请求有的话确认它没有的话检查客户端证书是否已导入到设备信任列表。我从那以后在配置工具里加了一个证书预配向导一键生成证书并自动导入省掉了现场手工操作的环节。5.2 现象采集数据显示温度整体偏高十几度设备刚接入时看板上温度比实际料温高一截。原因是注塑机控制器返回的是内部整数单位是0.1℃我忘了把Scale配置成0.1直接按1存了。解决方式在映射表里给每个温度点把Scale设为0.1并让配置工具支持批量应用系数到同类型数据点避免一台台机器手工改。这块的经历让我养成了一个习惯——接任何新机型时第一轮采集的数据比对万用表读数确认换算系数无误后再批量部署。5.3 现象设备重启后IP变了采集服务连不上车间里有台设备的IP地址是由路由器DHCP分配的设备重启后IP漂移采集服务找不到设备。排查后把设备的MAC地址绑定在交换机上做了固定IP并在采集服务的Device表里增加了一个AutoDiscover开关启用后服务启动时会通过UDP广播扫描设备在线列表发现映射表中匹配的MAC就自动更新IP。这个功能对临时加线的场景也很管用。5.4 现象采集服务内存持续上涨跑两天后占用超过2GB线上服务跑了两天内存曲线笔直向上。分析后发现是订阅回调里把每次的Notification都存进了List消费线程的吞吐跟不上队列无限积压。解决措施给队列加上上限默认1万条超出上限时丢弃最旧数据并记录日志同时把回调里的一次性分配改成复用结构体降低GC压力。内存上涨问题解决后服务连续运行两周稳定在300MB以内。5.5 现象采集速度慢了注塑机操作屏都有卡顿感增加采集频率到200ms后注塑机控制器屏幕出现操作延迟。原因是OPC UA服务器的响应能力有限客户端读得越频繁控制器负载越大。解决方式把200ms的采集需求改为1000ms的常规轮询加曲线触发采集——只在注射动作开始时启动高速采集结束时自动停止。这个按需采集的思路后面会细说。5.6 现象一条报警数据被重复写了三次断线重连后的补传逻辑和实时采集逻辑同时写同一条数据数据库里出现重复。原因是补传先执行实时采集紧跟其后两个线程并发入库没有做唯一键约束。解决方式在数据库表上加了(DeviceId, PointName, Timestamp)唯一索引并让补传和实时写库走同一条去重通道。从那以后我写任何采集系统入库表第一件事就是加唯一键不等出问题了再补。6. 二次开发思路这套采集软件怎么变成你车间的那套6.1 给采集服务扩展一种新注塑机品牌新增品牌的核心是写一个新的协议适配器实现现有的三个接口方法public interface IMachineConnector { Taskbool ConnectAsync(CancellationToken ct); TaskListDataSample ReadCurrentValuesAsync(IEnumerableMachinePoint points); Taskbool TestConnectionAsync(); }接某国产注塑机时如果协议是私有TCP格式你只需要在ConnectAsync里实现TCP连接和登录握手在ReadCurrentValuesAsync里按厂商报文格式解析数据业务层的数据映射、缓存、补传逻辑完全复用。这也是我坚持把协议接入单独做一层的意义——协议差异被隔离在接口后面不会污染上层的业务逻辑。6.2 把采集数据推给MES或看板采集数据要从SQL Server到MES系统常见做法有三种MES直接读库最方便但耦合度高走REST API更灵活适合跨系统集成推MQTT适合实时看板和移动端推送。我在采集服务里加了可选的MachineCollector.Api项目暴露几个轻量接口GET /api/devices/{deviceId}/realtime // 返回设备当前实时数据 GET /api/devices/{deviceId}/history?start...end... // 返回历史数据 POST /api/devices/{deviceId}/alarms // 订阅报警推送MES系统只需要定时拉实时接口或注册报警回调看板就能显示实时产量和温度曲线。接口返回JSON格式前端Web组态可以直接对接。6.3 按需采集控制高速采集的频率开销如果要做注塑压力曲线分析就需要注射阶段的毫秒级数据采集。我在二次开发中常用的方案是:平时采集周期保持1000msMES下发开始注射分析指令时采集服务动态把注射压力、螺杆位置、注射速度这几个点的采集间隔切到20ms持续20秒后自动恢复。这样既拿到高频曲线数据又不会给注塑机控制器带来长期负载。项目上线后的第三个星期车间反馈说夜班有一台设备温度曲线异常却没有报警记录我查了日志发现是那台设备的控制器时钟和采集服务器差了4分钟导致报警前后采样的时间戳乱套。从那以后我接每一套采集系统时都要做一遍对钟检查并且在采集服务启动时强制校时本地时间源连续三次对不上的设备直接在健康检查里标红。从这个项目里我最大的体会是采集软件的技术难点从来不在读数据这一个动作上而是在连接的稳定性、数据的准确性和断网后的自愈上。每一次现场踩坑最后都变成配置项和自检逻辑补进了系统。如果你的车间也有类似的需求这套基于C#的采集架构可以直接作为起点把协议适配层替换成你的设备型号剩下的链路基本可以原样复用。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →