尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

OPC UA通信实例:PLC与PC机数据交互的C#实现与调优

OPC UA通信实例:PLC与PC机数据交互的C#实现与调优 简介面向工业自动化中PLC与上位机之间的数据交换提供一套完整的OPC UA通信实例源码适合PLC工程师、工控软件开发人员及需要深入理解OPC UA协议栈的进阶学习者可借此快速搭建服务器与客户端的通信框架从而降低工业通信项目的开发门槛。资源共285个文件压缩包大小仅926KB源码以C语言和C程序文件为主另含Python辅助脚本、CMake构建配置、Shell部署脚本、Markdown说明文档等目录分明便于定位服务器端、客户端及安全配置模块兼顾可读性与工程实用性。已有263人学习下载代码覆盖OPC UA的核心机制包括信息模型节点组织、身份验证与加密、读写与订阅服务、二进制编码传输等并配套示例应用展示完整的交互流程帮助开发者快速理解关键实现。通过学习可理解从服务器建模、监听请求到客户端浏览读写、订阅推送的完整通信链路为实际项目集成或二次开发提供直接可用的工程参考。1. OPC UA 通信在 PLC 与 PC 机之间到底解决什么问题车间里最不缺的就是各种协议。老式 PLC 要往 PC 机传数据常见做法是组态软件做变量映射或者写底层 Socket 去解析私有协议换一台 PLC 型号解析代码就要重来一遍。OPC UA 的出现把设备与上位机之间的数据通道标准化成以太网服务PLC 侧要么内置服务器要么通过网关把地址空间暴露出来PC 机侧只用统一的 OPC UA 客户端库就能读状态、写指令、订阅变化。标题里“实例源码”多数是指 PC 机客户端这部分以及与之对应的 PLC 服务器配置。对做设备数据采集、MES 对接、上位机开发的工程师来说这个标题实际能拆成三件事连接怎么建立、节点怎么定、读写和订阅怎么落地。2. PLC 与 PC 机通信前先准备好 OPC UA 服务器端点与网络连接2.1 PLC 侧内置 OPC UA 服务器已经是最省事的接法现在的 PLC 侧支持 OPC UA 通信的路径有好几条。最省事的是使用 PLC 内置的 OPC UA 服务器比如西门子 S7-1200/1500 在博途项目中可以勾选激活 OPC UA 服务器CPU 固件本身就会监听 4840 端口三菱、汇川等品牌对 OPC UA 的支持也在逐步覆盖不支持时通常借助协议转换网关。内置服务器的好处是少一台中间硬件PLC 的 DB 块、I/Q 地址会被映射成 OPC UA 服务器地址空间中的节点PC 机客户端不需要安装 PLC 私有驱动直接走标准协议。无论内置还是网关PC 机和 PLC 之间第一步是网络层能通。PLC 一般固定占用一个工程网口IP 通常为 192.168.1.xPC 机网卡要设在同一个网段例如 PLC 为 192.168.1.10PC 机为 192.168.1.20掩码统一 255.255.255.0。如果用虚拟机跑客户端网络连接模式建议选桥接而不是 NAT桥接能让 PLC 的回包直接发到宿主机的物理网卡NAT 模式在部分工业网段里会出现 ARP 不同、PLC 端回包错路的现象。这里说的网络连接模式指 VMware 或 VirtualBox 给虚拟机网卡分配 IP 的方式桥接模式下 PC 机虚拟机可以拿到和 PLC 同一子网的 IP。2.2 OPC UA 客户端连接地址和最小连接代码PC 机侧 OPC UA 客户端以库的形式接入。C# 常见做法是拿 OPC Foundation 的 UA-.NETStandard 库C 用 open62541Python 可以用 asyncua。连接地址统一写成opc.tcp://192.168.1.10:4840这是 UA 的标准格式不需要额外指定协议厂商标识。很多 OPC UA 客户端库还会要求一个 ApplicationName服务器会拿这个名称来区分是哪台 PC 发起的连接。C# 的最小连接代码如下省掉证书细节先把会话建起来using Opc.Ua; using Opc.Ua.Client; using Opc.Ua.Configuration; var config new ApplicationConfiguration { ApplicationName PCClient, ApplicationType ApplicationType.Client, SecurityConfiguration new SecurityConfiguration { // 演示环境先自动接受不受信任的证书生产环境必须删除这一行 AutoAcceptUntrustedCertificates true, RejectSha1SignedCertificates false }, TransportQuotas new TransportQuotas { OperationTimeout 15000 } }; // useSecurityfalse 表示先用无加密策略把连接跑通 var endpoint CoreClientUtils.SelectEndpoint( config, opc.tcp://192.168.1.10:4840, useSecurity: false); using (var session Session.Create(config, endpoint, true, true, pc-session).Result) { Console.WriteLine(连接成功: session.Endpoint.EndpointUrl); }逻辑说明ApplicationConfiguration是每个 OPC UA 客户端启动前都要准备的配置文件包含应用名、证书、传输配额。CoreClientUtils.SelectEndpoint会先尝试连接服务器并读取它声明的支持的安全策略列表useSecurity: false表示选择SecurityPolicy.None这一条适合现场调试。Session.Create的参数里第三个updateBeforeConnect为 true 时会在创建会话前重新获取端点第四个checkDomain为 true 时跳过证书域名校验IP 直连 PLC 时这句很关键否则可能出现域名不匹配的异常。OperationTimeout是单个请求的等待时间PLC 侧响应慢时调到 30000 毫秒更稳妥。连接参数可以直接做成配置项建一个表格方便对接时快速核对。参数常见值说明EndpointUrlopc.tcp://192.168.1.10:4840PLC 侧 OPC UA 服务器地址内置服务器默认 4840SecurityPolicyNone / Basic256Sha256演示先用 None正式环境使用加密策略OperationTimeout15000 msPC 机客户端请求超时PLC 响应慢要调大ApplicationNamePCClient会出现在 PLC 服务器的会话列表里checkDomaintrueIP 直连时跳过证书域名校验2.3 节点地址不是猜出来的连接建立后读写的是 PLC 地址空间里的节点。节点地址由命名空间和标识符组成例如ns2;sDB1_Temp。ns2是命名空间索引 2不同 PLC 品牌把 DB 块字段放在不同的命名空间后面sDB1_Temp是字符串标识符表示 PLC 程序里的变量。节点 ID 的准确写法必须通过 OPC UA 客户端工具浏览地址空间得到常见工具是 UA Expert输入上面的连接地址连上后就能看到 PLC 暴露出来的所有 DB、I/Q 地址和它们的类型。不要凭记忆拼节点 ID尤其是西门子 DB 块在 PLC 侧还需要把对应 DB 块的“OPC UA 访问权限”打开否则节点在服务器侧不会公布。3. PC 机侧 OPC UA 实例源码读实时值、写点与订阅数据变化3.1 批量读取多个节点一次往返拿到一整组数据PC 机与 PLC 通信最常用的是读操作。逐点调用ReadValue会要求每个点做一次请求PLC 地址空间大的时候 PC 机 CPU 占用率很高。常见做法是用ReadValues把多个 NodeId 打包在一个请求里OPC UA 服务器端也会尽量顺序执行整体延迟比逐点读低不少。var nodeIds new NodeIdCollection { new NodeId(ns2;sDB1_Temp), new NodeId(ns2;sDB1_Pressure), new NodeId(ns2;sDB1_Speed) }; var readValues session.ReadValues(nodeIds, 0, TimestampsToReturn.Both); for (int i 0; i readValues.Count; i) { Console.WriteLine(${nodeIds[i]} {readValues[i].Value} | {readValues[i].StatusCode}); }逻辑说明ReadValues第一个参数是要读的节点集合第二个参数 0 表示取最近的值第三个参数TimestampsToReturn.Both表示同时返回来源时间戳和服务器时间戳方便 PC 机侧判断数据是否长时间未更新。返回列表和请求节点顺序一一对应循环时按索引取数据。StatusCode用于判断单个节点读取失败比如某个节点地址写错不会影响同批次其它节点成功返回。3.2 写操作布尔点、整数点、浮点点的类型对齐PC 机向 PLC 写入启动命令、设定值是 PLC 控制逻辑要求最严的一部分。写操作必须保证 NodeId 准确并且值类型和 PLC 侧变量类型一致常见坑是 PLC 侧是REALPC 侧写了个int服务器会直接返回BadTypeMismatch。var writeCollection new WriteValueCollection { new WriteValue { NodeId new NodeId(ns2;sDB1_StartBtn), AttributeId Attributes.Value, Value new DataValue(true) { SourceTimestamp DateTime.UtcNow, ServerTimestamp DateTime.UtcNow } }, new WriteValue { NodeId new NodeId(ns2;sDB1_SpeedSet), AttributeId Attributes.Value, Value new DataValue(30.0f) } }; session.Write(writeCollection, out var results); foreach (var r in results) { Console.WriteLine(r.Code); }逻辑说明WriteValue的AttributeId固定是Attributes.ValueDataValue里不光放值还可以带时间戳。写入布尔点时 PLC 侧一般映射为 BIT 或 BOOL用true/false浮点最好显式写成30.0f不要写成30避免 C# 编译成 double 后 OPC UA 栈把类型识别成双精度而 PLC 变量是单精度 REAL。写的结果列表和请求集合顺序一致拿到Good才算成功如果返回BadNotWritable先检查 PLC 服务器账户的写权限而不是怀疑代码。3.3 订阅数据变化按周期推送比轮询更省网络带宽OPC UA 相对传统 Socket 通信的明显优势是订阅。PC 机不需要每秒向 PLC 轮询而是告诉服务器“我关注这几个节点有变化再推给我”。订阅由Subscription和MonitoredItem组成一个订阅可以挂多个监控项服务器按发布周期批量推送。var subscription new Subscription(session.DefaultSubscription) { PublishingInterval 100, KeepAliveCount 10, LifetimeCount 100 }; session.AddSubscription(subscription); subscription.Create(); var monitoredItem new MonitoredItem { StartNodeId new NodeId(ns2;sDB1_Temp), AttributeId Attributes.Value, SamplingInterval 100, QueueSize 10, DiscardOldest true }; monitoredItem.Notification (MonitoredItem sender, MonitoredItemNotificationEventArgs e) { var dataValue sender.LastValue; Console.WriteLine($温度值: {dataValue.WrappedValue.Value}); }; subscription.AddItem(monitoredItem); subscription.ApplyChanges();逻辑说明PublishingInterval是服务器向 PC 机客户端推送数据的周期单位毫秒100 毫秒意味着最多每秒推送 10 次SamplingInterval是 PLC 侧采样节点的间隔它决定了服务器多久检查一次节点变化。两者不相等的时候数据是否真的推送还取决于节点值变化和发布周期。QueueSize10表示服务器在客户端处理不及时的时候缓存最多 10 个变化值DiscardOldesttrue表示趁旧保新适合温度、压力这种只关心当前值的过程量。Notification事件在客户端收到推送时触发事件处理器里直接从sender.LastValue取最新值不需要再主动读一次 PLC。表格总结三个操作的关键 API操作API关键参数批量读session.ReadValues(ids, 0, ts)第三个参数设置时间戳返回策略写session.Write(items, out results)Value必须和 PLC 变量类型一致订阅SubscriptionMonitoredItemPublishingInterval 与 SamplingInterval 分开设4. 实例源码连通性排查与参数调优端点、证书、采样间隔4.1 先分清网络不通还是协议不通写完了连接、读写、订阅代码剩下的工作就是排坑。最常见的第一道坑是 PC 机 ping 不通 PLC。在 PC 机上先做端口探测确认 4840 真的在监听# Windows PowerShell Test-NetConnection 192.168.1.10 -Port 4840如果显示TcpTestSucceeded: False问题在网络层检查 PLC 是否启用了 OPC UA 服务器、防火墙是否放行Windows 还得注意专用网络与公用网络的文件共享策略。如果端口能通但客户端报BadTimeout或握手错误才进入协议层排查。用 UA Expert 工具直接连同一个地址能连上就说明 PC 机代码库版本和服务器不兼容的概率很小问题出在客户端配置。排查表可以覆盖绝大多数现场情况现象原因处理办法端口测试失败PLC 侧服务器未启动 / 防火墙检查 PLC 项目是否激活 OPC UA放行 4840BadSecurityChecksFailed客户端证书不被服务器信任把客户端证书发到 PLC 服务器信任列表或临时 AutoAcceptBadNodeIdUnknown节点 ID 拼错用 UA Expert 浏览地址空间复制节点BadSessionIdInvalid会话被服务器关闭增大 KeepAliveCount或客户端做了长连接重连数据读到 null节点类型映射错误用 UA Expert 查看节点 DataType再改 C# 类型4.2 证书与安全策略的正确配置顺序OPC UA 服务器在 PLC 侧只监听一个端口但访问控制由安全策略加用户认证两层决定。PC 机客户端第一次连接时库会生成本机证书服务器默认不接受陌生证书所以会出现BadSecurityChecksFailed。测试期最省事的做法是把AutoAcceptUntrustedCertificates设为 true让它自动信任服务器端证书。这个开关只能用于内网演示一旦接入产线PLC 侧的安全审计就会把它拒掉因此生产环境要把客户端证书导出后添加到 PLC 服务器的信任列表。不同 PLC 的添加界面不一样但原理都是“服务器端信任客户端客户端信任服务器”。安全策略的选择顺序老式 PLC 或网关只支持Basic256新设备基本支持Basic256Sha256更强的是Aes128_Sha256_RsaOaep。能支持时优先用Basic256Sha256。如果客户端代码里设了useSecurity: true但服务器不支持对应策略SelectEndpoint会返回一个不支持的 endpoint 然后握手失败反过来把安全策略设成 None 就可以通。这说明不是代码逻辑错而是两端策略不匹配。4.3 采样间隔和发布间隔不是越小越好订阅参数调优是 OPC UA 通信实例源码里最容易被人忽略的部分。把PublishingInterval调到 10 毫秒PC 机端每秒要处理 100 个包PLC 侧 CPU 也承受不住。实际参数至少参考三个因素PLC 扫描周期、数据变化速度、PC 机数据显示需求。给出一个经验参考表场景SamplingIntervalPublishingIntervalQueueSize电机转速监控50 ms100 ms5模拟量温度采集500 ms1000 ms10状态机变化100 ms100 ms10打开调试日志20 ms50 ms50还有一个容易踩的坑SamplingInterval设得比 PLC 实际扫描周期还短服务器会按自己能力返回值不会报错但 PC 机端可能以为数据是每 10 毫秒刷新一次实际上 PLC 扫描一遍就要几十毫秒。调试时可以打上数据的时间戳看真实间隔。订阅对象要长期持有方法退出就被 GC 回收的话订阅会静默断开等下一次发布超时才会发现。5. 把 OPC UA 实例源码扩展成控制场景的高级用法5.1 用结构化节点一次读回整块 DB 数据PLC 侧程序里一旦有几十个温度、压力、状态信号逐个读写节点会让代码变得又长又难维护。常见做法是在 PLC 内把这些信号放进同一个 DB 块然后让 OPC UA 服务器把这个 DB 块暴露成一个结构化节点。PC 机端只需要读这一个 NodeId就能拿回一个带有多个字段的结构体网络往返次数从几十次降低到一次。var dbNode new NodeId(ns2;sDB1_DataBlock); DataValue dv session.ReadValue(dbNode); if (dv.Value is ExtensionObject ext ext.Body ! null) { Console.WriteLine(ext.Body); }说明ExtensionObject是 OPC UA 表示复杂结构体的一种数据类型具体字段顺序要在客户端侧按 PLC 定义的结构体反序列化。西门子 PLC 的 OPC UA 服务器会把整个 DB 的结构暴露出来如果发现读取结果是 null多数是因为服务器没有把这个 DB 设置为可访问。5.2 用方法调用代替裸写把互锁放到 PLC 侧面向控制场景时PC 机直接写“启动”位是不推荐的做法。更可靠的方法是 PLC 里定义好 OPC UA 方法例如StartPump、StopAlarmPC 机调用方法而不是写变量。调用时所有互锁条件在 PLC 内判断返回一个结果码PC 机再根据结果码显示成败原因。这样即使 PC 机键盘误触发PLC 扫描周期内也会首先执行安全条件。实例源码里这一块往往只体现客户端调用真正的实现细节在 PLC 侧方法块里。5.3 用 Reconnect 保证断线后自动恢复长连的 OPC UA 会话会因 PLC 重启、网线松脱而断开PC 机程序需要监听SessionReconnect事件并重新建立订阅。常见做法是维护一个已订阅节点集合断线重连成功后把这些监控项重新加回去。注意重新订阅后的第一帧数据通常需要等一个发布周期控制程序里要做超时判断不要误以为订阅已经失效。本文还有配套的精品资源点击获取
返回列表