Hololens2无法连接OPC.UA服务器问题求助
HoloLens2上Unity OPC UA客户端连接失败问题排查
我正在进行一项大学Unity项目,需开发Hololens2应用以展示通过OPC.UA服务器从3D打印机采集的CO2数据。我使用Opc.Ua库用C#编写了OPC客户端,代码在Unity播放器中运行完全正常,但在Hololens2上运行时遇到以下错误:
Session not connected! UnityEngine.DebugLogHandler:Internal_Log_Injected(LogType, LogOption, String, IntPtr) UnityEngine.DebugLogHandler:Internal_Log(LogType, LogOption, String, Object) UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[]) UnityEngine.Logger:Log(LogType, Object) UnityEngine.Debug:LogError(Object) OpcClient:read() Ausnahme ausgelöst bei 0x00007FF8DF6B5E5C in Test project.exe: Microsoft C++-Ausnahme: Il2CppExceptionWrapper bei Speicherort 0x0000002B47DFCF40. Connection failed: The type initializer for 'Opc.Ua.ServiceMessageContext' threw an exception. UnityEngine.DebugLogHandler:Internal_Log_Injected(LogType, LogOption, String, IntPtr) UnityEngine.DebugLogHandler:Internal_Log(LogType, LogOption, String, Object) UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[]) UnityEngine.Logger:Log(LogType, Object) UnityEngine.Debug:LogError(Object) OpcClient:connect() OpcClient:read()
相关代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using Opc.Ua.Client; using Opc.Ua.Configuration; using Opc.Ua; public class OpcClient : MonoBehaviour { string url = @"opc.tcp://192.168.0.172:4840"; private Session session; private ApplicationConfiguration app_configuration = new ApplicationConfiguration(); public Dictionary<string, string> values = new Dictionary<string, string>(); private void connect() { try { app_configuration = new ApplicationConfiguration() { ApplicationName = "Unity OPC UA Client", ApplicationUri = url, ApplicationType = ApplicationType.Client, TransportConfigurations = new TransportConfigurationCollection(), TransportQuotas = new TransportQuotas { OperationTimeout = 10000 }, ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 50000 }, TraceConfiguration = new TraceConfiguration() }; EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(url, false); session = Session.Create(app_configuration, new ConfiguredEndpoint(null, endpointDescription, EndpointConfiguration.Create(app_configuration)), false, "", 10000, null, null).GetAwaiter().GetResult(); } catch (System.Exception e) { Debug.LogError("Connection failed: " + e.Message); } } void read() { if (session == null || !session.Connected) { Debug.LogError("Session not connected!"); connect(); return; } try { DataValue turn = session.ReadValue(NodeId.Parse("ns=2;i=2")); addValue("turn", turn.Value.ToString()); Debug.Log("TURN: " + turn.ToString()); DataValue timestamp = session.ReadValue(NodeId.Parse("ns=2;i=3")); addValue("timestamp", timestamp.Value.ToString()); Debug.Log("TIMESTAMP: " + timestamp.ToString()); DataValue totalInputWH = session.ReadValue(NodeId.Parse("ns=2;i=4")); addValue("totalInputWH", totalInputWH.Value.ToString()); Debug.Log("TOTALINPUT in WH: " + totalInputWH.ToString()); DataValue totalPowerW = session.ReadValue(NodeId.Parse("ns=2;i=5")); addValue("totalPowerW", totalPowerW.Value.ToString()); Debug.Log("TOTALPOWER in W: " + totalPowerW.ToString()); DataValue powerHeatbedW = session.ReadValue(NodeId.Parse("ns=2;i=6")); addValue("powerHeatbedW", powerHeatbedW.Value.ToString()); Debug.Log("POWERHEATBED in W: " + powerHeatbedW.ToString()); DataValue powerHotendW = session.ReadValue(NodeId.Parse("ns=2;i=7")); addValue("powerHotendW", powerHotendW.Value.ToString()); Debug.Log("POWERHOTEND in W: " + powerHotendW.ToString()); DataValue currentWork = session.ReadValue(NodeId.Parse("ns=2;i=10")); addValue("currentWork", currentWork.Value.ToString()); Debug.Log("CURRENTWORK in W: " + currentWork.ToString()); DataValue currentTurn = session.ReadValue(NodeId.Parse("ns=2;i=11")); addValue("currentTurn", currentWork.Value.ToString()); Debug.Log("CURRENTURN: " + currentWork.ToString()); DataValue currentCo2 = session.ReadValue(NodeId.Parse("ns=2;i=12")); addValue("currentCo2", currentCo2.Value.ToString()); Debug.Log("CURRENCO2: " + currentCo2.ToString()); } catch (System.Exception e) { Debug.Log("Read failed: " + e.Message); session.Close(); } } private void addValue(string key, string value) { if (values.ContainsKey(key)) { values[key] = value; } else { values.Add(key, value); } } // Start is called before the first frame update public string getValue(string key) { if (values.ContainsKey(key)) { return values[key]; } else { return "Key not found!"; } } void Start() { connect(); //call read every 1 seconds InvokeRepeating("read", 2.0f, 1.0f); } }
已配置的权限
<Capabilities> <Capability Name="internetClient" /> <Capability Name="internetClientServer" /> <Capability Name="privateNetworkClientServer" /> <DeviceCapability Name="webcam" /> <DeviceCapability Name="microphone" /> </Capabilities>
额外信息
- Unity版本:2023.1.20f
- OPC.UA库版本:1.5.373.121
解决方案
1. 修复ServiceMessageContext类型初始化异常
这个异常核心原因是IL2CPP编译时裁剪了OPC UA库依赖的反射序列化类型。在Unity项目Assets目录下创建link.xml文件,强制保留OPC UA相关库的所有代码:
<linker> <assembly fullname="Opc.Ua" preserve="all" /> <assembly fullname="Opc.Ua.Client" preserve="all" /> <assembly fullname="Opc.Ua.Configuration" preserve="all" /> </linker>
2. 修正ApplicationUri配置错误
代码中把客户端ApplicationUri设为服务器URL是错误的,需改为客户端自身的唯一标识:
app_configuration = new ApplicationConfiguration() { ApplicationName = "Unity OPC UA Client", ApplicationUri = "urn:unity-opc-client", // 替换为客户端专属URI ApplicationType = ApplicationType.Client, // 其他配置保持不变 };
3. 正确处理异步操作
同步阻塞调用异步方法可能导致HoloLens2线程死锁,改用协程处理:
private IEnumerator connectCoroutine() { try { app_configuration = new ApplicationConfiguration() { ApplicationName = "Unity OPC UA Client", ApplicationUri = "urn:unity-opc-client", ApplicationType = ApplicationType.Client, TransportConfigurations = new TransportConfigurationCollection(), TransportQuotas = new TransportQuotas { OperationTimeout = 10000 }, ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 50000 }, TraceConfiguration = new TraceConfiguration() }; // 先验证配置合法性 yield return app_configuration.Validate(ApplicationType.Client).AsCoroutine(); EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(url, false); var sessionTask = Session.Create(app_configuration, new ConfiguredEndpoint(null, endpointDescription, EndpointConfiguration.Create(app_configuration)), false, "", 10000, null, null); yield return sessionTask.AsCoroutine(); session = sessionTask.Result; } catch (System.Exception e) { Debug.LogError("Connection failed: " + e.Message); Debug.LogError(e.StackTrace); // 打印完整堆栈追踪深层问题 } } // 修改Start方法 void Start() { StartCoroutine(connectCoroutine()); InvokeRepeating("read", 2.0f, 1.0f); }
需添加using UnityEngine.Networking;以使用AsCoroutine()扩展方法。
4. 验证HoloLens2网络权限
确保HoloLens2与OPC服务器在同一局域网,且Wi-Fi连接设置为私有网络(否则privateNetworkClientServer权限不生效),手动ping服务器地址确认连通性。
5. 升级OPC UA库版本
当前使用的1.5.373.121版本存在IL2CPP兼容性问题,建议升级到最新稳定版(如1.5.412.x),新版本会修复更多平台适配问题。
内容的提问来源于stack exchange,提问作者Martin Mali
相关产品推荐
相关产品推荐

