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

如何通过C# .NET的Beckhoff ADS库利用TwinCAT 3 Vision的ITcVnDisplayableImage接口指针获取JPEG图像

如何通过C# .NET的Beckhoff ADS库利用TwinCAT 3 Vision的ITcVnDisplayableImage接口指针获取JPEG图像

我之前处理过类似的TwinCAT Vision图像获取需求,直接通过ADS读取到的8字节接口指针本身并不能直接拿到JPEG数据——这个指针是TwinCAT COM风格接口的内存地址,你需要通过它调用ITcVnDisplayableImage接口的方法来提取图像数据。下面是两种可行的解决方案,优先推荐第一种,因为更简单可靠:

方法一:在TwinCAT PLC中封装JPEG数据(推荐)

最省心的方式是在PLC侧先把ITcVnDisplayableImage的JPEG数据导出到一个可直接通过ADS读取的PLC变量中,避免在C#里处理复杂的接口指针调用。

步骤1:在PLC中添加变量并封装接口调用

在TwinCAT 3的ST代码中,创建动态BYTE数组存储JPEG数据,再调用ITcVnDisplayableImage的GetJpeg方法把图像写入数组:

VAR_GLOBAL
    // 由Vision模块赋值的接口实例
    cameraImage : ITcVnDisplayableImage;
    // 存储JPEG数据的动态数组(自动扩容)
    CameraJpegData : ARRAY OF BYTE;
    // 记录JPEG数据的实际长度
    CameraJpegLength : UDINT;
    // 预设最大JPEG尺寸(根据你的场景调整,比如200KB)
    maxJpegSize : UDINT := 200000;
END_VAR

// 在循环OB中执行,定期更新图像数据
IF cameraImage <> 0 THEN
    // 确保缓冲区足够容纳当前图像
    IF SIZEOF(CameraJpegData) < maxJpegSize THEN
        Realloc(CameraJpegData, maxJpegSize);
    END_IF;
    // 调用接口方法提取JPEG数据
    cameraImage.GetJpeg(ADR(CameraJpegData), SIZEOF(CameraJpegData), CameraJpegLength);
END_IF;

步骤2:C#侧直接读取JPEG数组

现在你可以通过ADS直接读取PLC中的JPEG数据变量,转换为图像文件:

using TwinCAT.Ads;
using System.Drawing;
using System.IO;

class Program
{
    static void Main(string[] args)
    {
        using (var client = new TcAdsClient())
        {
            try
            {
                // 连接到TwinCAT ADS服务器
                client.Connect("10.0.0.51.1.1", 851);

                // 读取JPEG数据的实际长度
                var lengthSymbol = client.ReadSymbol("MAIN.Supervisor.CameraJpegLength");
                uint jpegLength = client.ReadValue<uint>(lengthSymbol);

                if (jpegLength == 0)
                {
                    Console.WriteLine("未获取到有效JPEG图像数据");
                    return;
                }

                // 读取JPEG字节数组
                var jpegSymbol = client.ReadSymbol("MAIN.Supervisor.CameraJpegData");
                byte[] jpegData = client.ReadValue<byte[]>(jpegSymbol, (int)jpegLength);

                // 转换为Image对象并保存
                using (var ms = new MemoryStream(jpegData))
                {
                    using (Image image = Image.FromStream(ms))
                    {
                        image.Save("camera_capture.jpg");
                        Console.WriteLine($"图像已保存到:camera_capture.jpg");
                    }
                }
            }
            catch (AdsException ex)
            {
                Console.WriteLine($"ADS操作错误:{ex.Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"其他错误:{ex.Message}");
            }
        }
    }
}

方法二:纯C#通过接口指针调用GetJpeg方法(进阶)

如果必须在C#侧直接处理接口指针,需要深入了解TwinCAT COM接口的内存结构,但这种方法对版本依赖高、文档少,不推荐生产环境使用:

  1. 接口内存结构:ITcVnDisplayableImage是COM兼容接口,远程指针指向的对象第一个8字节是虚函数表(vtable)地址,vtable中存储了接口方法的入口地址。
  2. 定位GetJpeg方法:GetJpeg是父接口ITcVnImage的方法,在vtable中的偏移量通常为0x28(不同TwinCAT版本可能变化),你需要通过TcAdsClient.ReadMemory读取vtable中的方法地址。
  3. 远程调用:利用ADS的InvokeMethod功能调用该方法,需要严格匹配GetJpeg的签名(HRESULT GetJpeg([out] BYTE* pBuffer, [in] UINT bufSize, [out] UINT* pActualSize)),过程复杂且易出错。

关键注意事项

  • 动态数组:使用TwinCAT动态BYTE数组避免固定长度不足导致的数据截断。
  • 接口校验:PLC侧必须先判断cameraImage指针非空再调用方法,避免PLC运行时错误。
  • ADS权限:确保C#程序的ADS客户端在TwinCAT中拥有足够的读写权限,若遇访问拒绝需调整TwinCAT的ADS配置。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 07:39:50