使用Python和struct合并两个OPC UA节点值遇异常求助
问题排查与修正方案
1. 致命错误:两个节点ID完全重复
你的代码里node_id_1和node_id_2是完全相同的:
node_id_1 = "ns=2;s=well_OPC_path. 32669" node_id_2 = "ns=2;s= well_OPC_path. 32669"
这意味着你两次读取的是同一个节点的值,合并后的浮点数自然不可能正确。你需要从文档中确认对应载荷/位置的两个分节点ID(比如一个是低16位寄存器,一个是高16位寄存器,节点ID应该是连续或有区分的编号)。
另外注意节点ID里的空格:well_OPC_path. 32669中点后面的空格大概率是输入错误,实际OPC UA节点路径一般不会包含无意义空格,建议修正为well_OPC_path.32669。
2. 对"Card Plot"数据结构的误解
你提到期望得到约200组载荷与位置的数值对,说明这不是单个浮点数的合并,而是一组数组数据:
- 每组数据包含一个载荷值(由两个16位节点组成)和一个位置值(由另外两个16位节点组成)
- 总共存在200组这样的节点对(即400个寄存器节点)
你需要先从文档中确认:
- 载荷数据的起始寄存器编号、连续数量(比如载荷低字节从32669开始,共200个;高字节从32869开始,共200个)
- 位置数据的起始寄存器编号、连续数量(同理)
3. struct字节序不匹配问题
设备寄存器的字节序(大端/小端)通常和主机字节序不同,默认struct.pack('HH', ...)使用主机字节序,可能和设备的存储顺序不符。你需要根据文档指定正确的字节序:
- 小端模式:使用
<HH(比如x86架构设备) - 大端模式:使用
>HH(比如多数工业设备)
比如如果设备是大端存储,合并代码应该改成:
combined_value = struct.pack('>HH', value_high, value_low) float_value = struct.unpack('>f', combined_value)[0]
注意:要确认哪个节点是高字节、哪个是低字节,顺序搞反的话数值会完全错误。
修正后的示例代码(针对单组载荷+位置)
假设载荷的高字节节点是ns=2;s=well_OPC_path.32669,低字节是ns=2;s=well_OPC_path.32670;位置的高字节是ns=2;s=well_OPC_path.32671,低字节是ns=2;s=well_OPC_path.32672,且设备是大端字节序:
from opcua import Client import struct import time url = "opc.tcp://OPC_SERVER:PORT" client = Client(url) try: client.connect() print("Client connected to:", url) # 载荷的两个节点(高字节、低字节) load_high_node = client.get_node("ns=2;s=well_OPC_path.32669") load_low_node = client.get_node("ns=2;s=well_OPC_path.32670") # 位置的两个节点(高字节、低字节) pos_high_node = client.get_node("ns=2;s=well_OPC_path.32671") pos_low_node = client.get_node("ns=2;s=well_OPC_path.32672") for _ in range(50): # 读取载荷的两个部分并合并 load_h = load_high_node.get_value() load_l = load_low_node.get_value() load_bytes = struct.pack('>HH', load_h, load_l) load_float = struct.unpack('>f', load_bytes)[0] # 读取位置的两个部分并合并 pos_h = pos_high_node.get_value() pos_l = pos_low_node.get_value() pos_bytes = struct.pack('>HH', pos_h, pos_l) pos_float = struct.unpack('>f', pos_bytes)[0] print(f"载荷: {load_float}, 位置: {pos_float}") time.sleep(1) except Exception as e: print(f"错误: {str(e)}") finally: client.disconnect() print("Client disconnected")
如果要读取200组数据,你需要循环遍历对应的节点ID,比如:
# 假设载荷高字节从32669开始,共200个;低字节从32669+200=32869开始 load_high_start = 32669 load_low_start = 32669 + 200 pos_high_start = 32869 + 200 pos_low_start = pos_high_start + 200 # 预加载所有节点 load_high_nodes = [client.get_node(f"ns=2;s=well_OPC_path.{load_high_start + i}") for i in range(200)] load_low_nodes = [client.get_node(f"ns=2;s=well_OPC_path.{load_low_start + i}") for i in range(200)] pos_high_nodes = [client.get_node(f"ns=2;s=well_OPC_path.{pos_high_start + i}") for i in range(200)] pos_low_nodes = [client.get_node(f"ns=2;s=well_OPC_path.{pos_low_start + i}") for i in range(200)] # 读取所有200组数据 card_plot_data = [] for h1, l1, h2, l2 in zip(load_high_nodes, load_low_nodes, pos_high_nodes, pos_low_nodes): load_h = h1.get_value() load_l = l1.get_value() load_float = struct.unpack('>f', struct.pack('>HH', load_h, load_l))[0] pos_h = h2.get_value() pos_l = l2.get_value() pos_float = struct.unpack('>f', struct.pack('>HH', pos_h, pos_l))[0] card_plot_data.append( (load_float, pos_float) ) print("200组载荷-位置数据:", card_plot_data)
额外建议
- 用OPC UA客户端工具(比如UA Expert)先手动查看节点值,确认节点ID是否正确,以及每个节点的实际数值是什么,再验证合并逻辑。
- 检查文档中寄存器的数据类型:确认是无符号16位整数(对应
struct的H)还是有符号16位整数(对应h),类型错误也会导致数值异常。
内容的提问来源于stack exchange,提问作者Mohammed Alaamri
相关产品推荐
相关产品推荐

