如何通过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接口的内存结构,但这种方法对版本依赖高、文档少,不推荐生产环境使用:
- 接口内存结构:
ITcVnDisplayableImage是COM兼容接口,远程指针指向的对象第一个8字节是虚函数表(vtable)地址,vtable中存储了接口方法的入口地址。 - 定位GetJpeg方法:
GetJpeg是父接口ITcVnImage的方法,在vtable中的偏移量通常为0x28(不同TwinCAT版本可能变化),你需要通过TcAdsClient.ReadMemory读取vtable中的方法地址。 - 远程调用:利用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
相关产品推荐
相关产品推荐

