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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 02:29:55