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

调用Milo OPC UA Multiply方法遇Bad_UnexpectedError错误求助

问题:调用OPC UA Multiply方法时触发UaSerializationException错误

尝试调用包含Multiply方法的FolderType节点计算2*5,执行程序时抛出以下错误:

UaException: status=Bad_UnexpectedError, message=java.util.concurrent.ExecutionException: org.eclipse.milo.opcua.stack.core.UaSerializationException: unknown builtin type: -1

使用Milo OPC UA 0.6.8版本,已确认OPC地址和节点均正确,相关代码如下:

val loadedConfig   : Config        = ConfigFactory.parseFile ( new File ( path ) )
val namespaceIndex : Int           = loadedConfig.getInt ( "namespaceIndex" )
val nodeID         : String        = loadedConfig.getString ( "nodeId" )
val readMethodId   : QualifiedName = new QualifiedName ( QualifiedNameIndex, Read )
val Read           : String        = loadedConfig.getString ( "readMethodId" )

val client : Option [ OpcUaClient ] = new OpcConnector ( config = loadedConfig ).createOpcClients ( )

read ( nodeId = nodeId,
       readMethodId = readMethodId,
       multiply = 5 )

private def read ( nodeId : NodeId, readMethodId : QualifiedName, multiply : Int ) : Unit = {
  val method : UaMethod = client
    .get
    .getAddressSpace.getObjectNode ( nodeId )
    .getMethod ( readMethodId )

  val inputs : Array [ Variant ] = Array ( new Variant ( multiply , 2 ) )

  val outputs : AnyRef = method.call ( inputs ) 

  println ( "result: " + outputs )
}

错误原因及修复方案

1. Variant构造方法误用

你创建Variant时使用的new Variant(multiply, 2)是错误的:这个构造方法的第二个参数是编码ID(encodingId),而非运算参数。这里的2被错误解析为无效的编码ID,导致序列化时抛出unknown builtin type: -1异常。

OPC UA方法的每个输入参数需要单独封装为一个Variant对象,而非将多个参数塞进同一个Variant。

2. 变量定义顺序错误

原代码中readMethodId的定义在Read变量之前,这会导致编译错误(Read未定义时就被引用),需要调整变量定义顺序。

修复后的代码

val loadedConfig   : Config        = ConfigFactory.parseFile ( new File ( path ) )
val namespaceIndex : Int           = loadedConfig.getInt ( "namespaceIndex" )
val nodeID         : String        = loadedConfig.getString ( "nodeId" )
val Read           : String        = loadedConfig.getString ( "readMethodId" )
// 先定义Read变量,再引用它创建QualifiedName
val readMethodId   : QualifiedName = new QualifiedName ( QualifiedNameIndex, Read )

val client : Option [ OpcUaClient ] = new OpcConnector ( config = loadedConfig ).createOpcClients ( )

// 注意:nodeId参数需要是NodeId类型,原代码中nodeID是String,需要转换
read ( nodeId = NodeId.parse(nodeID),
       readMethodId = readMethodId,
       num1 = 2, num2 = 5 )

private def read ( nodeId : NodeId, readMethodId : QualifiedName, num1: Int, num2: Int ) : Unit = {
  val method : UaMethod = client
    .get
    .getAddressSpace.getObjectNode ( nodeId )
    .getMethod ( readMethodId )

  // 每个运算数单独封装为Variant,按方法定义的参数顺序排列
  val inputs : Array [ Variant ] = Array ( new Variant(num1), new Variant(num2) )

  // 调用方法并获取输出结果
  val outputs: Array[Variant] = method.call(inputs).getOutputs

  println ( "result: " + outputs(0).getValue )
}

额外注意点

  • 确保Multiply方法的输入参数顺序与你传入的num1、num2一致;
  • 原代码中nodeID是String类型,需要转换为NodeId对象才能传入getObjectNode;
  • method.call返回的是MethodCallResult,通过getOutputs可获取封装了结果的Variant数组,取第一个元素即可得到乘法结果。

内容的提问来源于stack exchange,提问作者FlyingStone

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 11:13:20