You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 08:25:11