调用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
相关产品推荐
相关产品推荐

