公司动态
realvirtual+TwinCAT虚拟调试:PLC驱动虚拟产线的完整实践
一条产线从设计到量产最贵的时间花在哪里很多自动化团队的答案不是机械加工也不是电气装配而是“现场联调”。PLC 程序写好后必须等机械、电气、气路全部就位才能在现场看到设备真正动起来。这个阶段一旦暴露程序逻辑问题哪怕只是气缸顺序差一步也要协调机械、电气、调试三方重新排期时间成本和资源成本都非常高。虚拟调试Virtual Commissioning要解决的正是这个问题在设备还没有制造出来之前就让真实的 PLC 程序去驱动一个虚拟产线。这样程序逻辑可以在设计阶段被反复验证现场调试只需要处理物理层面的参数和安装差异而不是在最贵的时间里改逻辑。本期是 realvirtual 视频系列教程的图文版第 11 期以倍福 TwinCAT 为例把“realvirtual TwinCAT”这条虚拟调试链路完整讲一遍。读完你会理解它到底解决什么问题、环境怎么搭、PLC 和 Unity 怎么通信、最小示例怎么跑通、最常见的坑在哪里。先说一个判断虚拟调试真正难的不是把 3D 场景做得多逼真而是把通信链路和信号映射做规范。3D 逼真只能提升演示效果决定虚拟调试能否落地的是“PLC 变量 ↔ 虚拟对象”这条双向通道。现实中做砸的虚拟调试项目大多数不是画面太丑而是信号乱、地址错、循环慢、映射表靠口头交接。1. 虚拟调试到底解决了什么问题传统自动化项目的调试链路是机械设计 → 电气装配 → PLC 编程 → 现场联调。PLC 工程师通常在设备已经在车间组装时才看到硬件程序里关于“设备会不会干涉”“传感器信号到底什么时候来”的假设只有在现场才能验证。虚拟调试把“PLC 程序验证”这个环节从物理世界搬到了数字世界。它有几个非常直接的好处。第一逻辑验证提前。设备还没有加工PLC 程序已经可以在三维场景里跑起来气缸顺序、传送带启停、机器人信号交互都能被检查。第二迭代成本降低。改一个 PLC 程序里的时序问题在虚拟调试里只需要重新激活一个配置、点一下 Play几分钟完成在现场却意味着停机、协调、复查。第三培训与验收前置。虚拟调试场景稍加包装就能作为操作员培训环境也能作为甲乙双方阶段性验收的可视化依据。但要强调虚拟调试不是替代现场调试而是把问题分层。它擅长发现逻辑类、时序类、干涉类问题不擅长发现线缆松动、传感器安装偏移、机械间隙这类物理问题。因此虚拟调试的目标是“在虚拟阶段把逻辑问题清零让现场只面对物理问题”。在 realvirtual 与 TwinCAT 的组合中realvirtual 承担虚拟产线和对象交互TwinCAT 承担真实 PLC 程序执行。两者通过通信协议连接后PLC 程序在 TwinCAT 中运行控制的是 realvirtual 里的三维物体而不是真实电机。2. 核心概念与原理realvirtual、TwinCAT 与 ADS在动手之前需要把三个核心术语讲清楚。很多人第一次接触虚拟调试容易把 realvirtual、TwinCAT、ADS 混在一起。realvirtual 是一个基于 Unity 的虚拟调试与数字孪生工具包。它提供了一系列工业对象组件比如驱动器、传感器、传送带、机器人模型以及一套 IO 通信机制。它负责的是“物理表现层”让三维模型能够按照 PLC 的逻辑运动同时把虚拟传感器状态反馈给 PLC。TwinCAT 是倍福Beckhoff的自动化软件平台。它把 PLC、运动控制、HMI、工业通信都集成在 Windows 环境中可以在普通 PC 上作为软件 PLC 运行不一定要专用硬件。TwinCAT 3 中XAE 是工程开发环境XAR 是运行时内核。对虚拟调试来说这台“软件 PLC”就是被测试对象。ADS 是 Automation Device Specification 的缩写是 TwinCAT 系统的设备间通信协议。它定义了如何通过 AmsNetId 和 AMS Port 来定位一个设备上的某个服务然后进行变量、状态和数据的读写。这三者的关系可以用一个类比理解TwinCAT 是大脑realvirtual 是三维身体ADS 是连接大脑和身体的神经。大脑发出“电机启动”的指令神经把指令送到三维身体身体执行运动同时传感器信号通过神经返回大脑形成闭环。下表列出三者在虚拟调试中的角色概念作用在虚拟调试中的角色realvirtualUnity 虚拟调试与数字孪生框架三维场景、物理仿真、对象逻辑、IO 驱动TwinCAT倍福自动化软件平台软 PLC运行真实 PLC 程序作为被验证的控制逻辑ADSTwinCAT 系统通信协议连接 Unity 与 TwinCAT实现双向变量读写3. 为什么要用 TwinCAT realvirtual 做虚拟调试市面上可以做虚拟调试的组合很多realvirtual 也支持 TCP/IP、Modbus、EtherNet/IP 等多种 PLC 协议。那为什么教程要以 TwinCAT 为例这不是因为 realvirtual 只能搭配 TwinCAT而是因为 TwinCAT 在虚拟调试场景中有几个工程上的优势。第一个优势是“软 PLC”特性。TwinCAT 不需要专用的 PLC 硬件直接安装在 Windows PC 上就能作为 PLC 运行。这让虚拟调试的开发环境变得非常轻量一台开发笔记本就能同时跑 Unity、TwinCAT XAE、realvirtual不需要额外买倍福控制器。第二个优势是 ADS 协议的开放性和易用性。外部程序可以通过 ADS 直接读写 TwinCAT PLC 变量过程非常直观。只要知道变量的符号路径比如MAIN.xMotorRun就能读取或写入。相比之下很多传统 PLC 品牌的对外通信要配置复杂的地址映射、数据块、通信驱动链路长一倍不止。第三个优势是 TwinCAT 3 的纯软件扩展。从 TwinCAT 3 开始相关生态提供了 EtherCAT Simulation可以在没有真实 EtherCAT 从站的情况下仿真从站设备也提供了 User Mode Runtime 这一类授权让 TwinCAT 运行时可以脱离实时内核在用户态运行。这两个能力正好和虚拟调试“不需要物理硬件”的目标一致。当然这不代表所有项目都应该用 TwinCAT。如果你的客户指定使用另一个品牌的 PLCrealvirtual 也具备对应的通信驱动只是配置和调试方式不同。在入门学习阶段用 TwinCAT 能把虚拟调试的核心链路以最低成本跑通等技术经验成熟后再切换到目标品牌是效率最高的路径。4. 环境准备与前置条件搭建一套“realvirtual TwinCAT”的虚拟调试环境不需要昂贵的硬件但软件准备要仔细。我把环境清单和安装注意事项拆开说明。建议软件清单Windows 10 或 Windows 11 64 位操作系统推荐使用管理员权限账号Unity 编辑器建议使用 LTS 版本具体以你安装的 realvirtual 版本兼容性为准TwinCAT 3 XAE 工程环境安装时选择包含 PLC、System Manager、IO 的典型组件realvirtual 工具包导入到 Unity 工程中TwinCAT ADS 开发库安装 TwinCAT XAE 后一般会自带到安装目录可选软件TwinCAT 3 EtherCAT Simulation在没有真实 EtherCAT 从站时仿真从站设备适合验证 EtherCAT 通信逻辑TwinCAT User Mode Runtime相关授权代码常以 TC1702 形式出现允许运行时以用户态方式运行不依赖实时内核适合只有普通 PC 的开发验证场景安装顺序安装顺序建议是先 TwinCAT 后 Unity。TwinCAT 安装完成后系统会要求重启重启后再安装 Unity 并导入 realvirtual。TwinCAT 的 ADS 库在安装 XAE 时已经带上了Unity 工程里可以直接引用也可以从安装目录复制到 Assets 下的 Plugins 文件夹。关于授权TwinCAT 提供试用授权试用期内功能完整但需要在 TwinCAT 系统中激活。激活过程会弹出授权管理器选择试用即可。User Mode Runtime 这类运行方式通常需要单独授权具体授权方式和试用申请以倍福官网当前信息为准不同版本之间的差异较大教程中不固定写死版本号。卸载与重装提示TwinCAT 是带有实时驱动的软件卸载干净与否直接影响重装体验。卸载前先停止所有 TwinCAT 服务关闭 Visual Studio、Unity 等占用相关 DLL 的进程再从控制面板或官方卸载工具卸载。如果卸载不干净会出现驱动残留、路由服务无法启动、重装失败等问题。5. 从通信链路到最小示例TwinCAT 与 Unity 的 ADS 握手环境搭好后第一个关键技术点就是让 Unity 和 TwinCAT 建立 ADS 通信。这一步是整个虚拟调试的地基通信不通后面的一切都是空谈。5.1 ADS 通信的关键参数ADS 通信需要三个关键信息AmsNetId标识一台设备的地址格式类似192.168.0.1.1.1AMS Port标识设备上的某个服务TwinCAT 3 PLC 运行时的默认端口是 851变量符号路径标识 PLC 程序里的具体变量例如MAIN.xMotorRun在 TwinCAT 系统托盘中右键可以进入路由设置查看或修改本机的 AmsNetId。开发初期如果 Unity 和 TwinCAT 运行在同一台电脑上使用本机 AmsNetId 和端口 851 即可。如果是跨机器联调还需要在 TwinCAT 路由中把开发机的 IP 和 AmsNetId 添加为静态路由这一步很多新手会漏掉导致 Unity 端一直提示连接超时。5.2 TwinCAT 侧最小 PLC 程序我们先用一个最简单的启保停逻辑作为被验证对象。在 TwinCAT 的 PLC 工程中新建一个程序 MAIN写入以下代码PROGRAM MAIN VAR bPowerOn : BOOL; bStart : BOOL; bStop : BOOL; xMotorRun : BOOL; END_VAR xMotorRun : (xMotorRun OR bStart) AND NOT bStop AND bPowerOn;这段程序表达的是当上电且启动信号置位时电机运行如果停止信号置位或断电则电机停止。xMotorRun是运行状态输出。注意一点在纯虚拟调试阶段这台 PLC 程序里可以不映射任何真实 EtherCAT IO。启动、停止、运行状态都是普通 PLC 变量由 ADS 从外部写入或读取。这个设计非常适合虚拟调试PLC 程序不需要关心“信号来自真实按钮还是来自 Unity”它只看到变量变化。5.3 Unity 侧的 ADS 连接脚本Unity 端需要引用 ADS 库。比较常见的做法是从 TwinCAT 安装目录中找到 ADS 相关 DLL比如TwinCAT.Ads.dll连同同目录下的配套 DLL 一起复制到 Unity 工程的Assets/Plugins文件夹。不同 TwinCAT 版本的库路径有差异请以实际安装目录为准。下面是一个最小可用的 C# 脚本负责连接 TwinCAT、读取布尔变量、写入布尔变量。// 文件路径Assets/Scripts/TwinCATAdsService.cs using System; using Beckhoff.TwinCAT.Ads; using UnityEngine; public class TwinCATAdsService : MonoBehaviour { public string amsNetId 127.0.0.1.1.1; public int amsPort 851; private TcAdsClient _client; void Start() { TryConnect(); } private void TryConnect() { try { _client new TcAdsClient(); _client.Connect(amsNetId, amsPort); Debug.Log($[TwinCAT ADS] 连接成功 {amsNetId}:{amsPort}); } catch (Exception ex) { Debug.LogError($[TwinCAT ADS] 连接失败请检查 TwinCAT 路由和端口。{ex.Message}); } } public bool ReadBool(string symbolPath) { int handle 0; try { handle _client.CreateVariableHandle(symbolPath); return (bool)_client.ReadValue(typeof(bool), handle); } catch { return false; } finally { if (handle ! 0) _client.DeleteVariableHandle(handle); } } public void WriteBool(string symbolPath, bool value) { int handle 0; try { handle _client.CreateVariableHandle(symbolPath); _client.WriteValue(handle, value); Debug.Log($[TwinCAT ADS] 写入 {symbolPath} {value}); } catch (Exception ex) { Debug.LogError($[TwinCAT ADS] 写入 {symbolPath} 失败: {ex.Message}); } finally { if (handle ! 0) _client.DeleteVariableHandle(handle); } } void OnDestroy() { if (_client ! null) { _client.Dispose(); } } }这段脚本做了三件事Start 时建立 ADS 连接ReadBool 按变量路径读取布尔值WriteBool 按变量路径写入布尔值。每次读写都用 CreateVariableHandle 创建句柄结束后释放避免重复访问符号表带来的性能问题。5.4 使用脚本驱动一个最简单的虚拟对象有了通信服务下一步是让场景里的物体随着 PLC 变量运动。写一个简单的设备控制脚本挂在 Unity 场景中的任意 Cube 上// 文件路径Assets/Scripts/VirtualMotor.cs using UnityEngine; public class VirtualMotor : MonoBehaviour { public TwinCATAdsService adsService; public float speed 1.0f; void Update() { bool motorRunning adsService.ReadBool(MAIN.xMotorRun); if (motorRunning) { transform.Translate(Vector3.forward * speed * Time.deltaTime); } if (Input.GetKeyDown(KeyCode.S)) { adsService.WriteBool(MAIN.bStart, true); } if (Input.GetKeyDown(KeyCode.T)) { adsService.WriteBool(MAIN.bStop, true); } } }在 Unity 中把TwinCATAdsService和VirtualMotor挂到同一个对象上将 adsService 字段拖拽赋值。运行时按 S 键写入启动信号按 T 键写入停止信号Cube 就会根据 PLC 程序中的xMotorRun状态决定是否移动。这个最小示例虽然简单但已经跑通了完整闭环Unity 写入 PLC 变量 → PLC 程序计算 → PLC 输出变量被 Unity 读取 → Unity 对象运动。真实世界里的虚拟调试无非是把“Cube”换成传送带、机械手把“按键输入”换成 realvirtual 的信号组件核心链路不变。6. realvirtual 场景里的信号映射让虚拟设备动起来的关键最小示例跑通后你已经有能力验证 Unity 和 TwinCAT 的通信链路。接下来要进入 realvirtual 的真正用法把工业场景里的设备组件与 PLC 变量做信号映射。很多初学者看到 realvirtual 的庞大组件库第一反应是“先把整个产线模型都摆进 Unity”。这个思路容易把自己拖入建模和渲染的深坑。更稳妥的做法是先用一个最小场景验证通信和信号映射方法再逐步扩展设备数量。在 realvirtual 中搭建虚拟调试场景一般遵循这样的流程导入或创建三维模型。可以从 CAD 软件导出 FBX 格式也可以先用 Unity 内置几何体搭一个简化模型给模型添加 realvirtual 的设备组件。例如需要旋转的电机就添加驱动器类组件需要检测对象的传感器就添加传感器类组件在 realvirtual 的 IO 配置中新增通信驱动协议选择 TwinCAT/ADS 相关的驱动在信号映射表中把 PLC 变量如MAIN.xMotorRun与 realvirtual 组件的输入输出信号绑定运行 TwinCAT 激活配置再运行 Unity观察信号是否双向流动这里最关键的步骤是“信号映射表”。信号映射表相当于虚拟调试项目的接线图。PLC 端的变量名、数据类型、读/写方向realvirtual 端的组件信号、设备动作都要在这张表里一一对应。它决定了“PLC 输出MAIN.xMotorRun后到底控制的是 3D 场景里的哪台电机”。在实际项目中如果 PLC 变量命名规整比如所有电机控制信号都以xMotor_开头所有传感器信号都以bSensor_开头那么映射表的建立、审查、维护都会轻松很多。反之如果变量名随意信号映射表就会变成一份没人敢动的“天书”这也是很多虚拟调试项目后期失控的根源。如果你的技术路线不想依赖 realvirtual 内置的 ADS Provider也可以沿用上一节的思路先用TwinCATAdsService脚本读取变量再手动把值传给 realvirtual 组件的公开属性。这种方式代码更透明适合学习阶段理解信号流当项目规模变大后再切换到 realvirtual 的 IO 配置体系会更符合工程化要求。7. 运行验证与效果判断跑通一个虚拟调试链路判断成功不能只看“画面动没动”要看信号闭环是否完整。我建议从三个层面验证。第一层ADS 连接是否建立。运行 Unity观察 Console 窗口。如果输出[TwinCAT ADS] 连接成功 127.0.0.1.1.1:851说明 ADS 链路已经打通。如果输出连接失败优先检查 TwinCAT 是否已经激活配置、端口是否确实是 851、AmsNetId 是否填写正确。第二层Unity 到 PLC 的写入方向。按 S 键在 TwinCAT 的 Online 监视窗口中观察MAIN.bStart是否变为 TRUE。如果变量没有变化说明 Unity 的 WriteValue 没有真正写入 PLC需要检查符号路径大小写、变量是否被 TwinCAT 运行时访问权限限制。第三层PLC 到 Unity 的读取方向。在 TwinCAT 中手动把MAIN.bStart置为 TRUE再观察MAIN.xMotorRun是否按 PLC 逻辑变为 TRUE。如果 PLC 程序正确Unity 场景里的 Cube 应该开始移动同时 Console 窗口会打印读取并驱动的日志。这三个层面全部通过才说明“PLC 变量 ↔ 虚拟对象”的双向通道是健康的。后续扩展真实设备、增加 IO 数量时这套验证方法不需要改变只是把信号数量放大而已。在实际项目中这个最小验证环境建议保留下来作为以后排查问题的基准环境。任何一个新的 realvirtual 组件接不进来都先回到最小示例里验证通信避免把“信号映射配置”“3D 模型问题”“PLC 程序问题”三个层面的错误混在一起。8. 常见问题与排查思路问题现象可能原因排查方式解决方案ADS 连接失败AmsNetId 填写错误、路由未配置、TwinCAT 未激活在 TwinCAT 系统托盘中查看实际 AmsNetId检查路由列表填写正确 AmsNetId跨机器时添加静态路由先激活 TwinCAT 配置Unity 脚本找不到 ADS 命名空间TwinCAT.Ads.dll 未放入 Plugins 或版本不匹配查看 Unity Console 编译错误从 TwinCAT 安装目录复制 DLL 及相关配套文件到 Assets/Plugins写入 PLC 变量不生效符号路径拼写错误、变量未在运行的任务中声明在 TwinCAT 在线监视中查看变量路径确认变量完整路径为MAIN.变量名注意大小写读取 PLC 变量一直为 falseADS 端口不对、变量类型不匹配检查端口和变量类型使用 851 端口确认ReadValue的类型参数与 PLC 变量一致TwinCAT 卸载失败服务未停止