ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TwinCAT 3 实操:第三方伺服驱动器 CoE 参数读写全攻略

TwinCAT 3 实操:第三方伺服驱动器 CoE 参数读写全攻略 刚接触 TwinCAT 3 的时候很多人第一反应是“这玩意是给 Beckhoff 自家硬件用的”等真正把一台第三方伺服驱动器挂上 EtherCAT 总线才发现事情没那么简单。扫描从站、加载 XML、分配站地址、看状态机一路折腾过去最终真正要面对的问题只剩一个怎么把一个 CoE 参数读出来再把它写进去。CoE全称 CANopen over EtherCAT简单理解就是利用了 EtherCAT 的物理链路来跑 CANopen 的应用层协议。伺服驱动器内部的地址、速度、电流、增益全部按照对象字典的形式组织所有第三方驱动器参数操作最终都会落到 CoE 上。我接下来说的这套方法既适用于 TwinCAT 3 里的 PLC 梯形图、结构化文本也适用于上位机用 C 通过 ADS 来访问。文章会围绕一个真实场景展开把一台第三方 EtherCAT 伺服驱动器接入 TwinCAT 3 工程从扫描设备开始到用系统管理器手工读写到 PLC 运行中通过 SDO 读写最后到 C 程序在上位机访问参数。全程都会标注我实际踩过的坑和验证过的处理方式建议第一次搞这块的工程师直接照着做。1. CoE 协议到底是什么为什么绕不开它1.1 从 EtherCAT 到 CoE 的协议栈关系EtherCAT 本身只解决“数据怎么在总线上高速传输”的问题它不关心传的数据代表什么意思。伺服驱动器也好IO 模块也好挂在总线上之后大家要靠应用层协议来统一交流方式。CoE 就是在 EtherCAT 上跑 CANopen 协议的一种规范方式核心是对象字典驱动器的每一个参数都对应一个 16 位主索引加 8 位子索引。对象字典按照功能分成几个区域。0x1000 到 0x1FFF 是通信对象和 CiA 402 标准对象区比如控制字 0x6040、状态字 0x6041、模式 0x6060、目标位置 0x607A 等等。0x2000 以后一般是厂家自定义区像速度环增益、位置环增益、惯量比、电流限制这类参数各家驱动器各不相同位置和数据类型都得对着厂家手册查。很多现场工程师第一次用 TwinCAT 打开系统管理器看到 CoE 选项卡里面几百个对象第一反应是头晕。其实不需要全懂抓住“标准对象做运动控制厂家对象做内部调试”这条主线绝大多数场景都能应付。1.2 SDO 与 PDO 两条通道别搞混CoE 里有两种数据访问方式SDO 和 PDO。SDO 是邮箱式通信客户端发起请求服务器返回应答适合一次读写一个参数。它的特点是可靠、明确缺点是效率低不可能靠它持续不停地发送位置指令。你打开系统管理器在线视图手动改一个增益值走的就是 SDO。PDO 则是过程数据对象按照配置好的映射关系在实时周期里固定地刷一批数据。比如每 500 微秒把一个伺服的状态字、位置实际值、速度实际值打包发给主站再接收主站发来的控制字、目标位置。运动控制里真正的高频实时数据走的是 PDO不是 SDO。这个区别如果分不清后面会出很多问题。比如你改了 PDO 映射但实际的控制程序还是按旧映射绑定变量结果就是轴使能不了又比如你用 SDO 去刷高频的速度指令刷新率根本跟不上运动就会一顿一顿。1.3 伺服驱动器里最常用的 CoE 对象我把实际项目里几乎必用的对象列出来方便对号入座对象名称典型用途0x6040控制字使能、停机、急停等状态机动作0x6041状态字读取驱动器当前状态0x6060操作模式位置/速度/转矩模式切换0x6061当前模式读回实际运行模式0x607A目标位置位置模式下写入目标0x60FF目标速度速度模式下写入目标0x6064位置实际值读取编码器反馈位置0x6081电机每转进给量电子齿轮比计算0x6091齿轮比电机轴与负载轴转速比0x2000 起厂家参数增益、惯量比、滤波时间常数等举个例子某台驱动器的速度环增益在 0x2001子索引 0数据类型是 32 位浮点数如果你不看手册很容易把它当成整数来读写结果数据完全不正常。所以每次拿到一台新驱动器我都会先打开对象字典把关键参数的数据类型、取值范围、最小值最大值都记一遍再动手写程序。2. 环境准备把第三方伺服驱动器拉进 TwinCAT 工程2.1 网卡与 TwinCAT 实时环境配置EtherCAT 主站对网卡要求比较严优先用板载 Intel 千兆网卡或者 Beckhoff 官方支持的网卡芯片USB 转网卡基本不用考虑。安装 TwinCAT 3 之后要先把实时网卡驱动激活打开 TwinCAT 的系统托盘图标选择 Real-Time Ethernet 设置把目标网卡切换到 TwinCAT RT-Ethernet 模式。如果这一步没做对扫描设备的时候要么找不到从站要么扫出来的设备上报一堆丢帧错误。激活驱动后新建一个项目建议直接创建 TwinCAT XAE 工程。第一次跑的时候系统会提示是否需要激活本地许可证进入试用模式即可大部分功能不受限制只对运行时间有要求调试足够用。2.2 扫描从站并加载 XML 描述文件把伺服驱动器的 EtherCAT IN 口和主站网卡连好给驱动器上电双击工程里的 Devices右键选择 Scan系统会扫描总线上的设备。第三方驱动器第一次扫描时经常会出现两种情况第一种设备能被识别成一个 EtherCAT 从站但是设备名是奇怪的字符串或者只有一串编号。这种一般是厂家信息没有正确写入驱动器的 EEPROM 固件里不影响基本通信但会影响你对照参数。第二种扫描直接报错提示未知设备这几乎都是因为缺少 XML 设备描述文件也就是常说的 ESI 文件。每家伺服驱动厂商都会提供配套的 ESI XML 文件里面包含从站识别号、PDO 映射定义、CoE 对象信息、厂商参数说明。TwinCAT 3 里可以通过 TwinCAT - EtherCAT Devices - Import XML 把文件加载进去加载后重新扫描设备名会变成厂家标准名称PDO 映射也会正确识别。这里要特别说一句即使不加载 XML 也能访问 CoE 参数因为 CoE 对象是驱动器本身支持的跟主站端的描述文件关系不大。但加载 XML 能让你在系统管理器里直接看到对象名称、数据类型、PDO 默认映射调试效率高很多。我遇到过一次设备扫描正常但 PLC 代码就是读不到参数的问题最后发现是 XML 版本和固件版本不匹配导致系统识别成了另一个型号换回对应固件版本的 XML 后立刻恢复正常。2.3 分配从站地址与状态机确认扫描完成后每个从站在 EtherCAT 主站里会有一个“站地址”。TwinCAT 里的从站地址和伺服面板上拨码设置的节点号不是一回事。主站会按拓扑顺序给从站分配地址通常是 1001、1002 这样排下去。后面无论是 PLC 访问还是 C 访问 CoE都需要用到这个主站分配的地址别搞混。EtherCAT 初始化有一套状态机流程INIT - PRE-OP - SAFE-OP - OP。只有在 OP 状态下PDO 周期通信才真正跑起来轴才能运动。而 CoE 的 SDO 参数访问在 PRE-OP 阶段就可以进行因为邮箱通道已经建立。调试时我习惯先把从站状态切到 OP确认绿色状态图标正常再做参数读写这样可以排除状态机没就绪的干扰。3. 在系统管理器里徒手改 CoE 参数也是最直观的验证方法3.1 用在线视图读写对象字典在解决方案资源管理器里展开 EtherCAT 设备找到对应的伺服从站双击打开设置页切换到 CoE 在线Online选项卡。这里面是对象字典的完整列表展开树形结构点击任意对象右侧会显示当前值、数据类型和单位。这一步很有用尤其是第一次接触一台不熟悉的驱动器。可以通过在线视图快速确认对象是否存在、数据类型是否正确、当前值是否合理。比如我要确认 0x6060 当前模式是什么点开对象看值是不是 0x01位置模式再改成 0x03速度模式点击写入驱动器立即生效。在线视图读写的是 SDO一次访问一个对象所以在界面上操作感觉很慢但这是最稳妥的验证方式。如果在线视图都读不到参数那排查顺序就应该是网卡驱动是否正常、从站状态是否就绪、从站地址有没有选对。3.2 离线配置实现启动自动写入CoE 在线选项卡旁边通常还有一个离线配置视图。这个视图不是摆设它里面的条目会在系统激活后由主站自动下发到从站。这个功能很适合固定产线要求每次上电后伺服驱动器必须处于某个固定模式增益参数必须是一组固定的调试值那就在离线配置里把这些对象和值填好激活工程后主站自动写入不需要人工干预。我自己常用它来做“工厂模式”初始化一台新驱动器换上后不需要手动逐个改参数只要工程重新激活所有关键参数自动灌入出错的概率大大降低。3.3 参数断电保存的正确姿势CoE 在线写入改变的大部分参数默认只存在 RAM 里。断电重启后驱动器恢复成默认值这也是“写入了不生效”的最常见原因之一。要让参数长期保存需要调用驱动器的“保存参数”功能很多协议栈在对象 0x1010 里定义了保存命令比如往 0x1010:01 写入特定值驱动器才会把参数固化到 EEPROM。不同厂家的实现方式有差异有的驱动器提供“保存所有参数”对象有的分“保存用户参数”和“保存厂家参数”一定要对着用户手册找对应对象。调试阶段我反而不建议频繁保存到 EEPROM万一参数改乱了想恢复出厂会多折腾一步。4. 用 PLC 在运行中读写 CoE 参数4.1 为什么运行时不采用在线视图现场设备不可能一直开着系统管理器改参数。最常见的情况是上位机触摸屏需要显示当前电机温度操作员要实时切换速度模式产线要在不同产品间切换增益组这些都得靠 PLC 程序在运行中去读写 CoE 参数。PLC 侧访问 CoE 的标准做法是使用 TwinCAT 提供的功能块核心思路是封装 SDO 请求在 PLC 任务里异步执行。4.2 用 FB_CoESdoRead / FB_CoESdoWrite 实现读写TwinCAT 3 里面负责 CoE 访问的库是 Tc3_CoE有些老版本会以 Tc2_EtherCAT 的形式存在。两个常用功能块是 FB_CoESdoRead 和 FB_CoESdoWrite。我以读取伺服当前模式为例写一段结构化文本FUNCTION_BLOCK FB_ReadCoeParam VAR_INPUT bExecute : BOOL; sNetId : STRING; nSlaveAddr : WORD; nIndex : WORD; nSubIndex : BYTE; nDataLen : UDINT; END_VAR VAR_OUTPUT bDone : BOOL; bError : BOOL; nErrId : UDINT; byBuffer : ARRAY[0..7] OF BYTE; END_VAR VAR fbCoeRead : FB_CoESdoRead; END_VAR每次循环调用fbCoeRead( sNetId : sNetId, nSlaveAddr : nSlaveAddr, nIndex : nIndex, nSubIndex : nSubIndex, bExecute : bExecute, cbLen : nDataLen, pDstBuf : ADR(byBuffer) ); bDone : fbCoeRead.bDone; bError : fbCoeRead.bError; nErrId : fbCoeRead.nErrId;需要注意几个输入参数的含义。sNetId 是主站的 AMS 地址通常可以从路由表里查到nSlaveAddr 是 TwinCAT 给从站分配的主站地址不是驱动器面板上的拨码地址nIndex 和 nSubIndex 就是要访问的对象pDstBuf 是存储读取结果的缓冲区缓冲区大小要预留给足比如读一个 32 位变量至少给 4 个字节。写入就反过来用 FB_CoESdoWrite把数据缓冲区指针传给 pSrcBuf。写入完成后同样要检查 bDone 和 bError不要假设一次调用就成功。4.3 触发方式与多轴通信冲突SDO 是邮箱通信同一个从站在同一时刻并发多个 SDO 请求很容易出现总线冲突或超时错误。多轴系统里如果每个轴都各自调用自己的操作界面去读参数这种冲突更明显。我习惯用一把“信号锁”统一管理全局变量声明一个 g_bSdoBusy任何功能块要执行 SDO 操作前先检查这个变量空闲才能置位然后执行操作完成或超时后立刻清除。这样虽然有点土但在四轴、八轴的场合非常管用基本不会出现莫名其妙的 0x9811 超时。另一个做法是用 TwinCAT 的邮箱请求队列把请求排成队逐个发送PLC 代码量会大一些但适用于请求特别频繁的场景。4.4 把读写封装成“上位机可调用”的接口实际项目里我不满足于只在 PLC 里读写。上位机界面要能读取驱动器温度、切换参数组那就需要把 CoE 读写封装成一个统一的接口块输入是“对象索引、子索引、读写方向、数据指针”输出是“完成标志、错误码、数据缓冲区”。C 上位机通过 ADS 调用这个接口就相当于把 CoE 的整个能力都暴露给了上位机。这样的好处是后期换驱动器品牌时只需要在 PLC 功能块里改对象映射和数据类型上位机代码一行都不用动。5. 用 C 读 CoE 参数ADS 是通往实时世界的桥5.1 ADS 协议与 TwinCAT 的通信模型TwinCAT 3 对外暴露的统一通信协议叫 ADSAutomation Device Specification。PLC 运行时、NC 轴、EtherCAT 从站在 ADS 的世界里都对应一个 AMS 地址包含 6 字节 NetId 和 2 字节 Port。C 上位机通过 TcAdsDll 连接这个地址就能读写 PLC 变量、调用 TwinCAT 系统功能。如果想直接通过 ADS 读第三方伺服驱动器的 CoE 对象一种常见思路是把 CoE 对象映射成一个 PLC 全局变量然后在 C 侧读取这个变量。以读取 PLC 全局变量 GVL_ActualVelocity 为例最小可用的 C 代码是这样的#include iostream #include cstring #include windows.h #include TcAdsDef.h #include TcAdsAPI.h int main() { long nErr, nPort; AmsAddr amsAddr; nPort AdsPortOpen(); nErr AdsGetLocalAddress(amsAddr); // 实际以系统管理器路由里的 AMS NetId 为准 amsAddr.netId[0] 192; amsAddr.netId[1] 168; amsAddr.netId[2] 0; amsAddr.netId[3] 10; amsAddr.netId[4] 1; amsAddr.netId[5] 1; amsAddr.port 851; // TwinCAT 3 PLC 运行时端口 // 获取符号句柄 char szVarName[] GVL_ActualVelocity; uint32_t hVar 0; nErr AdsSyncReadWriteReq(nPort, amsAddr, ADSIGRP_SYM_HNDBYNAME, 0, sizeof(hVar), hVar, (uint32_t)strlen(szVarName), szVarName); if (nErr) { std::cerr 获取句柄失败错误码: 0x std::hex nErr std::endl; AdsPortClose(); return -1; } double value 0.0; nErr AdsSyncReadReq(nPort, amsAddr, ADSIGRP_SYM_VALBYHND, hVar, sizeof(value), value); if (nErr) { std::cerr 读取失败错误码: 0x std::hex nErr std::endl; } else { std::cout ActualVelocity value std::endl; } AdsSyncWriteReq(nPort, amsAddr, ADSIGRP_SYM_RELEASEHND, hVar, sizeof(hVar), hVar); AdsPortClose(); return 0; }这段代码的流程是打开 ADS 端口获取本地 AMS 地址设置 PLC 运行时的 NetId 和端口通过符号名获取变量句柄再用句柄读取变量值最后释放句柄并关闭端口。TcAdsDll 里的头文件和库文件在 TwinCAT 3 安装目录下都有VS 项目里把包含目录和库目录配好即可。写符号变量时把 ADSIGRP_SYM_VALBYHND 换成写请求nErr AdsSyncWriteReq(nPort, amsAddr, ADSIGRP_SYM_VALBYHND, hVar, sizeof(value), value);有一点必须提醒ADS 端口 851 对应的是 TwinCAT 3 的 PLC 运行时如果你的工程里有多个 PLC 任务端口可能不同要以系统管理器里 PLC 实例的 AMS Port 为准。NetId 也不要写死在代码里建议从 TwinCAT 路由表读取或者做成配置文件否则换电脑后必出问题。5.2 C 直接访问 CoE 对象的进阶方案如果非得在 C 里动态访问任意 CoE 对象比如读取 0x200B 的驱动器温度并不建议直接去拼 EtherCAT 寄存器命令那样太底层还容易受驱动版本影响。我这里推荐两个可靠路径。第一种通过 PLC 功能块中转。在 PLC 里做一个通用请求块输入对象索引、子索引、方向和数据缓冲区C 通过 ADS 符号方式写输入结构体再读输出结构体。这种方案把复杂的 CoE 协议细节全部隔离在 PLC 层C 只需要和结构体打交道稳定性极高。前面说的 FB_ReadCoeParam 封装好了以后完全可以在这里复用。第二种直接在 TwinCAT 3 的 C 实时模块TcCOM里使用 TwinCAT 提供的 CoE 接口。这种方式把 SDO 请求放在实时上下文里执行性能最好但要写 .tcs 接口文件、处理代码生成和运行时注册开发成本高不少。我个人的项目经验是除非对实时性和耦合度有极高要求否则没必要用这个方案。对于大多数上位机 伺服驱动器的场景我强烈推荐“C - ADS - PLC 接口块 - FB_CoESdoRead/Write - 伺服驱动器”这条链路。它把 Tris 和协议细节都隔离开后期换品牌、改参数列表都很方便。5.3 数据类型的坑字节序、符号位和小数点位C 和 PLC 打交道时最常出问题的不是通信而是数据类型。CoE 协议在 EtherCAT 总线上默认是小端字节序所以你在 C 里用 uint16_t、int32_t 这类标准类型读写一般是没问题的编译器在 x86 平台上就是小端。可如果你把一个整数拆成字节数组手动拼接就要小心顺序容易把 0x03 拼成 0x0300。更麻烦的是驱动器参数里的浮点数。多数厂家在 CoE 里用 32 位浮点数表示但也有一些老型号用的是“带小数位的整数”比如实际值是 12.34传输时是 1234小数点在文档里单独说明。我遇到过一次把 0x6081 电机每转进给量按浮点数读结果读出来是个天文数字后来查手册才发现它是 32 位整数单位是脉冲数。所以拿到一台新驱动器第一步一定是确认数据类型和单位而不是先写代码。6. 常见问题与排查技巧实录6.1 读到的数据全是 0xFF 或者返回错误码从站刚上电就去读 CoE很容易读到一堆 0xFF因为邮箱通信还没建立。另一个常见原因是站地址选错SDO 请求发给了一个不存在的地址。处理方式很简单先把从站状态切到 OP等系统管理器里的状态图标变绿再发起 SDO 请求确认 nSlaveAddr 使用的是主站分配后的地址。如果返回 0x9811 或 0x9817这是典型的 ADS 超时错误通常是请求到了从站但从站没有及时响应。可以试试加大 ADS 超时时间或者增加重试机制。6.2 写入不生效一断电就丢最大概率是写入只在 RAM 里生效没有保存到 EEPROM。解决办法是找到厂家定义的保存对象常见的是 0x1010 系列。写入参数后延迟几十毫秒再向 0x1010 对应子索引写入触发值驱动器才真正固化。另外要检查参数是否只读。有些对象本身就是只读状态值比如 0x6041 状态字、0x6064 位置实际值写它们自然没有效果。面向对象列表凡是标注为 RO 的跳过。6.3 字节序和数据类型对不上写入一个本来是浮点的对象结果按整数写进去了或者写入一个 16 位参数时高八位和低八位颠倒了这都是新手常见问题。排查思路就一句话对着用户手册里的对象列表确认数据类型再对照 C 或 PLC 的变量定义。遇到读出来数值特别离谱第一个怀疑的就是字节序和数据类型而不是总线问题。6.4 伺服一使能就断通信不稳定如果 CoE 参数读写正常但伺服一使能就掉线问题往往不在参数本身而在 PDO 周期和物理链路。EtherCAT 周期设置得太短第三方伺服的处理能力跟不上就会出现周期性丢帧。先把周期调到 1 毫秒试试如果稳定再逐步缩短到 500 微秒、250 微秒找到这台驱动器能接受的极限。接线方面EtherCAT 线缆尽可能短电柜里变频器和伺服驱动器的动力线不要和 EtherCAT 网线捆在一起接地要规范。很多“偶发掉线”问题用示波器看干扰一抓一个准。6.5 排查速查表现象可能原因处理建议扫描不到从站网卡驱动没有切换为 TwinCAT RT-Ethernet安装驱动并激活实时模式设备名一团乱码XML 描述文件缺失或版本不符加载对应固件版本的 ESI XMLPLC 读 SDO 超时从站地址错误或邮箱未就绪确认从站地址等待 OP 状态写入后断电丢失参数只写入 RAM使用 0x1010 等保存对象固化读出的数据离谱字节序错误或数据类型不对核对对象表的数据类型和单位使能后掉线周期过短或接线干扰放宽周期优化接地与线缆6.6 用抓包工具辅助定位TwinCAT 自带的 EtherCAT 诊断功能可以抓取总线上的帧分析 CoE 邮箱数据时特别有用。你能在抓到的帧里看到主站发出的 SDO 请求目标索引、子索引以及从站返回的 Abort 码。Abort 码本身就是驱动器回给主站的错误信息通过它能直接区分是对象不存在、访问权限不对还是数据类型冲突。我第一次排查一台韩系伺服的掉线问题时就是靠抓包里频繁出现的丢帧记录定位到是 PDO 映射里一个无效对象引起的删掉之后问题解决。所以到现场调试TwinCAT 自带的抓包工具最好学会用比瞎猜效率高得多。最后再分享一个个人体会。我做第三方伺服接入时从来不会一上来就写 C 代码。先用系统管理器的在线视图手动读写一遍目标对象确认通信、数据类型、单位都对然后在 PLC 里封装好 SDO 读写功能块跑通一次完整流程最后才让 C 通过 ADS 去调。这个顺序看着麻烦但每一步的排查范围很小真出问题时很容易定位。反过来如果一上来就写 C通信不通、参数不对、类型错误全搅在一起现场会非常被动。这套顺序我建议你也照着来一遍。
返回列表