简介:这份资源面向工业自动化领域的组态开发与现场调试人员,聚焦MCGS组态软件与OPC工业通信标准的对接实践,帮助读者理解跨厂商设备数据交换的实现思路。包内共15个文件,约1.15MB,涵盖mcg组态工程、mdb数据库、doc说明文档、tpy与pro工程配置、sym符号表、xml及sym_xml描述文件、dfr、ci、sdb、toc、asd、bak等工程与备份文件,基本覆盖MCGS工程运行所需的各类配置与数据文件。资源围绕MCGS作为OPC客户端连接OPC服务器的核心流程展开,涉及服务器添加与参数配置、OPC项与变量映射、实时数据读写、双向通讯、断线缓存与故障处理,以及OPC UA在身份验证、授权和加密方面的安全机制,并延伸至生产线监控、能源管理、环境监测等应用场景。目前已有346人学习下载,适合希望掌握组态软件与OPC通讯集成、提升自动化系统互操作能力的开发者参考。
1. 工控现场的数据孤岛:MCGS与OPC通讯到底在解决什么问题
车间里一台老设备跑着 MCGS 嵌入版触摸屏,旁边新上的 MES 系统要采数据,中间隔着一条看不见的墙——触摸屏里的实时曲线、配方参数、报警记录,MES 那边一个都拿不到。现场工程师最常见的做法是加一块通讯模块、改 PLC 程序、再写一套上位机转发,折腾两三天还不一定稳。而 MCGS 与 OPC 通讯这个方向,本质上是把 MCGS 当成一个 OPC 数据源或者 OPC 客户端,让触摸屏里已经采到的变量直接暴露给上位系统,省掉中间那层转发。
这份资源包适合三类人:一是手上有一堆 MCGS 老项目、被要求接入 MES 或 SCADA 的现场工程师;二是做数据采集平台、需要对接国产组态软件的数据中台开发;三是刚接触工控通讯、想搞明白 OPC 到底怎么在组态软件里落地的新手。它不解决 PLC 底层协议问题,解决的是组态层到上层系统之间的数据通道问题。
2. MCGS 侧配置:把内部变量变成 OPC 可读的标签
2.1 先搞清楚 MCGS 的版本和 OPC 支持边界
MCGS 分嵌入版、通用版、网络版,不同版本对 OPC 的支持差异很大。嵌入版 7.7 是现场最常见的版本,它本身不直接提供 OPC Server,但可以通过 MCGS 物联助手或者第三方 OPC Server 做桥接。通用版和网络版在安装时如果勾选了 OPC 组件,会在系统里注册一个 MCGS OPC Server,这个 Server 能把 MCGS 实时数据库里的变量以 OPC DA 标签的形式暴露出来。
判断手头 MCGS 能不能直接走 OPC,看两个地方:一是安装目录下有没有OPCServer文件夹,二是 Windows 服务列表里有没有MCGS OPC Server这个服务。两个都有,说明可以直接用;只有一个或者都没有,就得走物联助手或者第三方桥接方案。
提示:嵌入版运行在 WinCE 或 Linux 屏上时,OPC Server 通常跑不起来,因为 OPC DA 依赖 Windows COM/DCOM。这种情况下要么换通用版做数据中转,要么用物联助手把数据推到支持 OPC UA 的平台。
2.2 在 MCGS 里建实时数据库并绑定设备变量
OPC 能读到的变量,前提是它在 MCGS 实时数据库里存在并且已经跟设备通道绑定。很多人卡在这一步:OPC 客户端连上了,但标签列表是空的,就是因为实时数据库里没建对应变量,或者建了但没跟 PLC 通道关联。
操作路径是:打开 MCGS 组态环境 → 工作台 → 实时数据库 → 新增对象。变量名建议用英文加下划线,比如Tank_Level、Motor_Speed,不要用中文,OPC 标签对中文支持不稳定。变量类型根据实际数据选,模拟量用浮点,开关量用开关型。
建完变量后,进设备窗口,把变量跟 PLC 通道的寄存器地址绑上。这一步跟平时做触摸屏画面是一样的,不绑的话变量值永远是 0,OPC 读过去也是 0。
# 检查 MCGS OPC Server 是否注册成功(Windows 命令行) reg query "HKLM\SOFTWARE\Classes\OPC.Server.MCGS" /s # 如果返回一堆注册表项,说明 OPC Server 已注册 # 如果提示找不到,需要重新运行 MCGS 安装目录下的 OPC 注册脚本这段命令用来确认 OPC Server 的 COM 注册信息是否存在。HKLM\SOFTWARE\Classes下面存的是 COM 组件的 CLSID 和 ProgID 映射,OPC 客户端就是靠这个找到 Server 的。返回结果里重点看ProgID是不是OPC.Server.MCGS,以及CLSID对应的LocalServer32路径指向的 exe 文件是否存在。
2.3 用 OPC 客户端工具验证标签能不能读
MCGS 侧配好后,别急着写代码,先用现成的 OPC 客户端工具连一下。常见的做法是用 KEPServer 自带的 OPC Quick Client,或者用 Matrikon OPC Explorer。打开工具,新建一个 OPC DA 连接,ProgID 填OPC.Server.MCGS,然后浏览标签空间。
如果能看到之前建的Tank_Level这些变量,并且值在刷新,说明 MCGS 侧没问题。如果连不上,报0x80070005拒绝访问,那是 DCOM 权限问题,不是 MCGS 的问题。DCOM 配置在dcomcnfg里,找到 MCGS OPC Server,把身份验证级别改成“无”,启动和访问权限里加上Everyone或者当前用户。
# 用 Python 的 OpenOPC 库快速测试 MCGS OPC 连接 import OpenOPC opc = OpenOPC.client() # 列出本机所有 OPC DA Server servers = opc.servers() print("可用 OPC Server:", servers) # 连接 MCGS OPC Server opc.connect('OPC.Server.MCGS') # 读取单个标签 value = opc.read('Tank_Level') print("Tank_Level 当前值:", value) # 批量读取多个标签 tags = ['Tank_Level', 'Motor_Speed', 'Alarm_Status'] values = opc.read(tags) for tag, val in zip(tags, values): print(f"{tag} = {val}") opc.close()这段代码用 OpenOPC 这个库做快速验证。opc.servers()列出本机注册的所有 OPC DA Server,确认 MCGS 在列表里。opc.connect()的参数就是前面注册表里查到的 ProgID。opc.read()支持单个标签和列表两种传参方式,批量读的时候返回的是一个列表,顺序跟传入的标签顺序一致。如果读出来是None或者报错,先检查标签名拼写,再检查 MCGS 实时数据库里变量是否已经跟设备绑定。
3. 上位机侧对接:C# 和 Python 怎么稳定拿到 MCGS 数据
3.1 C# 走 OPC DA 的典型写法与坑
C# 对接 OPC DA 一般用OpcNetApi或者OpcRcw.Da这套 COM 包装。OpcNetApi是开源封装,用起来比直接调 COM 舒服,但底层还是走 DCOM。新建一个控制台项目,NuGet 装OpcNetApi和OpcNetApi.Com,然后按下面的结构写。
using Opc.Da; using System; class Program { static void Main() { // 创建 OPC Server 对象,ProgID 跟注册表里一致 Opc.Da.Server server = new Opc.Da.Server( new OpcCom.Factory(), new Opc.URL("opcda://localhost/OPC.Server.MCGS") ); try { server.Connect(); // 构建要读取的 Item 列表 Item[] items = new Item[] { new Item(new ItemIdentifier("Tank_Level")), new Item(new ItemIdentifier("Motor_Speed")) }; // 同步读取 ItemValueResult[] results = server.Read(items); foreach (var r in results) { Console.WriteLine($"{r.ItemName}: {r.Value} 质量: {r.Quality}"); } server.Disconnect(); } catch (Exception ex) { Console.WriteLine("连接失败: " + ex.Message); } } }Opc.URL里的localhost换成目标机器的 IP 就是远程连接。server.Connect()这一步最容易翻车,报HRESULT: 0x80070005就是 DCOM 权限没配好,报0x800706BA是 RPC 服务没开。server.Read()是同步读,现场如果标签多、刷新快,建议用订阅模式,server.CreateSubscription()然后AddItems(),数据变化时走回调,比轮询省资源。
注意:C# 项目编译平台要跟 OPC Server 的位数一致。MCGS OPC Server 如果是 32 位的,C# 项目也得编译成 x86,否则连不上,报“没有注册类”。
3.2 Python 侧用 OpenOPC 做数据采集的完整流程
Python 做数据采集脚本,OpenOPC 是最省事的方案,但它依赖 PyWin32,而且只支持 Windows。安装就是pip install OpenOPC-Python3x,注意包名跟 Python2 时代不一样。
import OpenOPC import time import csv from datetime import datetime # 连接配置 OPC_SERVER = 'OPC.Server.MCGS' TAGS = ['Tank_Level', 'Motor_Speed', 'Alarm_Status'] INTERVAL = 1.0 # 采集间隔,秒 opc = OpenOPC.client() opc.connect(OPC_SERVER) # 打开 CSV 文件准备写入 with open('mcgs_data.csv', 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerow(['timestamp'] + TAGS) try: while True: values = opc.read(TAGS) row = [datetime.now().strftime('%Y-%m-%d %H:%M:%S')] for tag, (val, quality, ts) in zip(TAGS, values): # quality 是 OPC 质量码,'Good' 表示数据有效 row.append(val if quality == 'Good' else '') writer.writerow(row) f.flush() # 实时刷盘,防止断电丢数据 time.sleep(INTERVAL) except KeyboardInterrupt: print("采集停止") finally: opc.close()opc.read()返回的每个元素是(值, 质量码, 时间戳)三元组。质量码是 OPC 规范里定义的,Good表示正常,Bad表示通讯断了或者变量没绑好,Uncertain表示值可能不新鲜。采集脚本里一定要判断质量码,不然会把 0 或者旧值当成真实数据写进数据库。f.flush()是血泪经验,不刷盘的话程序崩了缓冲区里的数据全丢。
3.3 远程连接时的 DCOM 配置清单
本机连本机基本不用配 DCOM,但上位机跟 MCGS 不在同一台机器上时,DCOM 就是最大的黑匣子。配置分两步:MCGS 所在机器上开权限,上位机所在机器上改默认身份。
在 MCGS 机器上运行dcomcnfg,展开“组件服务 → 计算机 → 我的电脑 → DCOM 配置”,找到MCGS OPC Server,右键属性。常规选项卡里身份验证级别选“无”,位置选项卡勾选“在数据所在计算机上运行”,安全选项卡里启动权限和访问权限都加上ANONYMOUS LOGON和Everyone。
上位机这边同样跑dcomcnfg,在“我的电脑”属性里,默认属性选项卡把“在此计算机上启用分布式 COM”勾上,默认身份验证级别选“无”。默认协议里确保面向连接的 TCP/IP在列表里。
# 在 MCGS 机器上开放 OPC 相关端口(防火墙) netsh advfirewall firewall add rule name="OPC DA" dir=in action=allow protocol=TCP localport=135 # OPC DA 动态端口范围,通常需要开放 1024-65535 netsh advfirewall firewall add rule name="OPC DA Dynamic" dir=in action=allow protocol=TCP localport=1024-65535OPC DA 走的是 DCOM,底层依赖 RPC,RPC 用 135 端口做端点映射,实际数据传输走动态端口。现场如果防火墙管得严,要么按上面命令开放端口范围,要么把 OPC 相关程序加进白名单。动态端口范围开太大有安全顾虑的话,可以在注册表里把 RPC 动态端口范围收窄,但那是另一个话题了。
4. 避坑与排查:MCGS OPC 通讯里最常见的五个翻车点
4.1 连上了但标签列表为空
现象是 OPC 客户端能连上 Server,浏览标签空间时一个变量都看不到。原因通常是 MCGS 实时数据库里没建变量,或者建了变量但没跟设备通道绑定。OPC Server 暴露的是实时数据库里的“对象”,不是设备窗口里的通道。解决方法是回到 MCGS 组态环境,确认实时数据库里有变量,并且这些变量在设备窗口里已经跟 PLC 寄存器做了连接。只建变量不绑通道,OPC 能读到标签名,但值永远是 0。
4.2 读出来的值一直是 0 或者不刷新
现象是标签能读到,但值不动。原因有三个可能:一是变量没绑通道,上面说过了;二是 MCGS 运行环境没启动,组态环境里变量是不刷新的,必须让 MCGS 进入运行状态;三是 OPC 客户端读的是缓存值,而 Server 没往缓存里更新。解决方法是先确认 MCGS 运行环境在跑,然后在 OPC 客户端里把读取方式从“缓存”改成“设备”,强制走设备读取。如果设备读取正常、缓存读取是 0,那就是 Server 的缓存更新周期设得太长,在 MCGS OPC Server 配置里把更新周期改短。
4.3 远程连接报 0x80070005 拒绝访问
这是 DCOM 权限问题,不是 MCGS 的问题。现象是本机测试正常,换一台机器就连不上,报“拒绝访问”或者“没有注册类”。原因是 DCOM 默认不允许匿名访问,而 OPC 客户端很多时候是以匿名身份去连的。解决方法是按 3.3 节的清单配 DCOM 权限,重点是把ANONYMOUS LOGON加进启动和访问权限里。配完记得重启 OPC Server 服务和客户端程序,DCOM 配置不会热生效。
4.4 批量读取时部分标签报 Bad
现象是单个读都正常,批量读的时候有几个标签质量码是Bad。原因是 OPC 规范里批量读有数量限制,一次读太多标签,Server 处理不过来会返回部分失败。解决方法是分批读,每批控制在 50 到 100 个标签以内。另外检查报 Bad 的标签是不是在 MCGS 里被删了或者改名了,OPC 客户端缓存了旧的标签句柄,Server 那边找不到对应变量就会返回 Bad。
4.5 长时间运行后连接断开
现象是采集脚本跑几个小时或者几天后,OPC 连接突然断了,报0x800706BARPC 服务器不可用。原因是 DCOM 连接有超时机制,长时间没有数据交互会被回收。解决方法是在采集脚本里加心跳,定期读一个固定标签,保持连接活跃。另外在 OPC 客户端里设置自动重连,OpenOPC 的opc.connect()失败后可以捕获异常然后重新连。更稳的做法是用订阅模式代替轮询,订阅模式下 Server 会主动推数据,连接不容易被回收。
5. 进阶技巧:用 OPC UA 做 MCGS 数据的二次转发
OPC DA 依赖 DCOM,跨网段、跨平台都很麻烦,现在新项目更推荐走 OPC UA。MCGS 本身不直接支持 OPC UA Server,但可以用一个中间层把 DA 转成 UA。常见做法是跑一个开源的 OPC UA 网关,比如open62541或者UA-.NETStandard的示例 Server,让它作为 OPC DA 客户端去读 MCGS,然后以 OPC UA Server 的身份对外暴露。
# 用 asyncua 库建一个简单的 OPC UA Server,把 MCGS 数据转发出去 import asyncio from asyncua import Server, ua import OpenOPC async def main(): # 启动 OPC UA Server server = Server() await server.init() server.set_endpoint("opc.tcp://0.0.0.0:4840/mcgs_gateway/") server.set_server_name("MCGS Gateway") # 建一个对象节点放 MCGS 变量 idx = await server.register_namespace("mcgs") objects = server.nodes.objects mcgs_node = await objects.add_object(idx, "MCGS_Data") # 建变量节点 tank_level = await mcgs_node.add_variable(idx, "Tank_Level", 0.0) motor_speed = await mcgs_node.add_variable(idx, "Motor_Speed", 0.0) await tank_level.set_writable() await motor_speed.set_writable() # 连接 MCGS OPC DA opc = OpenOPC.client() opc.connect('OPC.Server.MCGS') async with server: while True: # 从 MCGS 读数据 values = opc.read(['Tank_Level', 'Motor_Speed']) # 写入 OPC UA 节点 await tank_level.write_value(values[0][0]) await motor_speed.write_value(values[1][0]) await asyncio.sleep(1) asyncio.run(main())这个网关脚本同时跑 OPC UA Server 和 OPC DA Client,asyncua负责 UA 侧,OpenOPC负责 DA 侧。server.set_endpoint()里的0.0.0.0表示监听所有网卡,端口 4840 是 OPC UA 默认端口。add_variable()建出来的节点,UA 客户端可以直接浏览和订阅。set_writable()让节点可写,如果只做采集可以去掉。循环里每秒从 MCGS 读一次,然后写进 UA 节点,UA 客户端那边看到的就是实时值。
验证方法是拿一个 OPC UA 客户端工具,比如 UaExpert,连opc.tcp://<网关IP>:4840/mcgs_gateway/,在地址空间里找到MCGS_Data节点,看下面的变量值是不是在刷新。如果 UaExpert 能读到值,说明网关通了,后面接 MES 或者数据中台就简单了,因为 OPC UA 跨平台、跨网段都比 DA 省心。
从那以后我每次做 MCGS 数据对接,都强制先在本机用 OPC 客户端工具验证一遍标签,确认 DA 侧没问题了再写代码,不然代码里报的错全是 DCOM 的锅,查半天查不到 MCGS 头上。希望帮到你。
本文还有配套的精品资源,点击获取