简介:这份PDF面向使用TwinCAT3与台达伺服ASD-A2-E的工控工程师,聚焦第三方EtherCAT驱动器在COE协议下实现伺服内部Homing模式这一实际问题。相比依赖PLC变量传递参考点、精度受扫描周期影响的Plc CAM方式,文档给出利用CANOpen预定义模式寻找零点的高精度思路,并覆盖PDO配置、Homing参数设置、模式选择与切换回同步位置模式的完整流程。资源包共1个PDF文件,约381KB,内容以图文步骤与Q&A形式组织,便于对照TwinCAT Manager界面逐步操作。文档还整理了多种Homing方式的差异、不同速度下停止位置偏移的原因,以及SDO读写、Homed标志置位等常见疑问,适合需要提升第三方伺服回零精度的中高级调试人员参考。目前已有777人学习。
1. 台大A2第三方EtherCAT驱动里的Homing模式:为什么原厂手册翻烂了也跑不通
台大A2伺服驱动器在不少运动控制项目里都能见到,但真正让人头疼的,往往不是接线和上电,而是当你想用第三方EtherCAT主站去驱动它、并且要跑通Homing回零模式的时候。原厂手册写得四平八稳,可你照着配完PDO映射、设好0x6098回零方法、下发0x6040控制字,电机要么纹丝不动,要么朝着限位一路狂奔。问题出在第三方主站和台大A2之间那层没有明说的状态机约定上——Homing模式在CiA 402协议里是标准动作,但台大A2对控制字时序、模式切换窗口、回零加速度单位的要求,和很多通用主站的默认行为并不一致。这篇笔记就是把我自己在台大A2上反复翻车后跑通Homing的路径拆开,从对象字典配置到状态字判读,再到第三方主站里那些必须手动改的PDO映射细节,让做EtherCAT配置和COE调试的同行少走几个通宵的弯路。适合已经能建立EtherCAT通信、但卡在回零这一步的从业者。
2. 台大A2的Homing模式在CiA 402里到底怎么走:状态机与对象字典
2.1 从0x6040控制字看Homing的进入条件
CiA 402把Homing定义成一种独立运行模式,模式号是6,写入对象0x6060。但台大A2不会因为你写了6就立刻切过去,它要求驱动器先处于「Operation enabled」状态,也就是状态字0x6041的bit2、bit1、bit0依次为1、1、1,并且bit3为0(无故障)。很多第三方主站的上使能流程是「Shutdown → Switch on → Enable operation」三步走,但台大A2在Switch on之后如果立刻写0x6060=6,它会把这次模式切换请求丢掉,状态字bit10(Target reached)也不会按你预期变化。
我一般会这样做:先让驱动器完整进入Operation enabled,读一次0x6041确认低四位是0x27(即0b00100111),再写0x6060=6,然后回读0x6061确认模式已经变成6。这个回读动作很关键,第三方主站如果只写不读,你根本不知道模式切换有没有生效。
import pysoem def enter_homing_mode(master, slave_pos): # 读取状态字,确认Operation enabled status_word = master.slaves[slave_pos].sdo_read(0x6041, 0x00, 2) status_val = int.from_bytes(status_word, byteorder='little') if (status_val & 0x006F) != 0x0027: raise RuntimeError(f"驱动器未就绪,状态字=0x{status_val:04X}") # 写入Homing模式 master.slaves[slave_pos].sdo_write(0x6060, 0x00, b'\x06') # 回读确认 mode_display = master.slaves[slave_pos].sdo_read(0x6061, 0x00, 1) if mode_display[0] != 6: raise RuntimeError(f"模式切换失败,当前模式={mode_display[0]}") return True这段代码里,0x6041读回来是2字节小端,掩码0x006F用来同时检查bit0到bit3和bit6(bit6是Switch on disabled的取反)。0x6060写1字节,0x6061读1字节。参数上唯一要注意的是SDO读取的字节序,台大A2默认小端,但有些第三方主站库会做转换,写之前确认一下。
2.2 0x6098回零方法与0x6099速度参数的配合
Homing的具体行为由0x6098决定,台大A2支持的方法和标准CiA 402基本一致,但有几个细节容易踩坑。方法1到14是带原点开关的,方法17到30是不带原点开关、直接找限位或Z相信号的。台大A2对方法17到30的支持比较完整,但方法33到35(找Z相)需要额外配置0x6098之外的编码器参数。
回零速度分两段:0x6099子索引1是「找开关速度」,子索引2是「找Z相速度」。台大A2的单位是「用户单位/秒」,但很多第三方主站的默认单位是「转/分」,如果你不换算,电机会以极慢的速度爬行,看起来像不动。我一般会把找开关速度设在额定转速的10%到20%,找Z相速度设在1%到5%。
| 对象 | 子索引 | 含义 | 台大A2典型值 | 单位 |
|---|---|---|---|---|
| 0x6098 | 0x00 | 回零方法 | 17(找负限位) | - |
| 0x6099 | 0x01 | 找开关速度 | 200 | 用户单位/秒 |
| 0x6099 | 0x02 | 找Z相速度 | 20 | 用户单位/秒 |
| 0x609A | 0x00 | 回零加速度 | 500 | 用户单位/秒² |
0x609A是回零加速度,台大A2对这个参数很敏感。设得太小,电机加速慢,回零过程拖长;设得太大,接近开关时容易过冲,导致状态字bit10还没置位就撞限位。我一般从500开始试,根据实际机械负载调整。
2.3 第三方主站PDO映射里必须手动改的三个地方
第三方EtherCAT主站(比如基于SOEM或IgH EtherCAT Master的)默认的PDO映射往往只包含0x6040、0x6041、0x6060、0x6061、0x607A、0x6064这几个常用对象。但Homing模式还需要0x6098、0x6099、0x609A参与,如果这些对象不在PDO里,你就得用SDO去写,而SDO写入的时机如果和状态机不同步,驱动器会返回SDO中止码0x06010000(不支持的对象访问)。
常见做法是修改从站的PDO映射,把0x6098、0x6099子1和子2、0x609A加进RxPDO。台大A2的默认RxPDO是0x1600,你可以用SDO写0x1C12和0x1C13来重新分配,但更稳妥的方式是在主站启动前用SDO配置好,再让主站进入OP状态。
# 配置台大A2的RxPDO映射,加入Homing相关对象 def setup_homing_pdo(master, slave_pos): # 先切换到PreOP,才能改PDO映射 master.state = pysoem.PREOP_STATE master.send_processdata() master.receive_processdata() # 清空0x1C12,避免冲突 master.slaves[slave_pos].sdo_write(0x1C12, 0x00, b'\x00') # 写入新的PDO映射对象0x1600 # 条目:0x6040, 0x6060, 0x607A, 0x6098, 0x6099:01, 0x6099:02, 0x609A pdo_entries = [ (0x6040, 0x00, 16), (0x6060, 0x00, 8), (0x607A, 0x00, 32), (0x6098, 0x00, 8), (0x6099, 0x01, 32), (0x6099, 0x02, 32), (0x609A, 0x00, 32), ] # 写入条目数量 master.slaves[slave_pos].sdo_write(0x1600, 0x00, bytes([len(pdo_entries)])) for idx, (index, sub, bits) in enumerate(pdo_entries, start=1): entry = (index & 0xFFFF) | ((sub & 0xFF) << 16) | ((bits & 0xFF) << 24) master.slaves[slave_pos].sdo_write(0x1600, idx, entry.to_bytes(4, 'little')) # 把0x1600分配给SyncManager 2 master.slaves[slave_pos].sdo_write(0x1C12, 0x01, (0x1600).to_bytes(2, 'little')) master.slaves[slave_pos].sdo_write(0x1C12, 0x00, b'\x01')这段代码的关键是0x1C12子0写条目数量,子1写PDO映射对象索引。台大A2要求先清空再写入,否则会报「PDO配置冲突」。0x1600的条目格式是「索引低16位 + 子索引8位 + 位长度8位」,小端写入。改完PDO后必须重新初始化主站,让新的映射生效。
3. 在第三方EtherCAT主站里跑通台大A2回零的完整步骤
3.1 从PreOP到OP:状态切换的时序要求
第三方主站启动EtherCAT网络时,状态机是「Init → PreOP → SafeOP → OP」。台大A2在PreOP阶段才能改PDO映射和SDO参数,一旦进入SafeOP,SDO写入会被限制。所以我的习惯是:在PreOP阶段把所有Homing相关的SDO参数(0x6098、0x6099、0x609A、0x607C原点偏移等)全部写完,再请求进入SafeOP,最后进OP。
这里有个坑:有些第三方主站库在send_processdata之后会自动推进状态,如果你在PreOP阶段写SDO的同时主站已经在尝试进SafeOP,SDO写入会失败。解决办法是在写SDO之前显式设置master.state = pysoem.PREOP_STATE,并且每次SDO写入后调用master.send_processdata()和master.receive_processdata()各一次,确保从站响应。
# 完整的PreOP配置流程 def configure_homing_params(master, slave_pos): master.state = pysoem.PREOP_STATE master.send_processdata() master.receive_processdata() # 设置回零方法:17 = 找负限位开关 master.slaves[slave_pos].sdo_write(0x6098, 0x00, b'\x11') # 找开关速度 200 用户单位/秒 master.slaves[slave_pos].sdo_write(0x6099, 0x01, (200).to_bytes(4, 'little')) # 找Z相速度 20 用户单位/秒 master.slaves[slave_pos].sdo_write(0x6099, 0x02, (20).to_bytes(4, 'little')) # 回零加速度 500 用户单位/秒² master.slaves[slave_pos].sdo_write(0x609A, 0x00, (500).to_bytes(4, 'little')) # 原点偏移,根据机械零点调整 master.slaves[slave_pos].sdo_write(0x607C, 0x00, (0).to_bytes(4, 'little')) print("Homing参数配置完成")0x6098写1字节,0x6099和0x609A写4字节小端。0x607C是原点偏移,如果机械零点和开关位置有偏差,在这里补偿。写完这些,再让主站进入SafeOP和OP。
3.2 用0x6040控制字触发回零:bit4和bit5的配合
进入OP状态后,Homing的启动靠0x6040控制字的bit4(新设定点)和bit5(立即生效)配合。标准流程是:先写0x6040=0x000F(使能),然后写0x6040=0x001F(bit4置1,启动Homing),驱动器开始回零。回零完成后,状态字0x6041的bit10(Target reached)会置1,bit12(Homing attained)也会置1。
但台大A2有个特殊要求:bit4必须在bit5为0的情况下置1,如果bit5同时为1,驱动器会忽略这次触发。很多第三方主站的默认控制字模板会把bit4和bit5一起置1,导致回零不启动。我一般会手动构造控制字:
def trigger_homing(master, slave_pos): # 先确保使能 master.slaves[slave_pos].outputs = (0x000F).to_bytes(2, 'little') master.send_processdata() master.receive_processdata() # 触发Homing:bit4置1,bit5保持0 master.slaves[slave_pos].outputs = (0x001F).to_bytes(2, 'little') master.send_processdata() master.receive_processdata() # 等待回零完成 import time timeout = 30.0 start = time.time() while time.time() - start < timeout: master.send_processdata() master.receive_processdata() status = int.from_bytes(master.slaves[slave_pos].inputs[0:2], 'little') if status & 0x0400: # bit10 Target reached if status & 0x1000: # bit12 Homing attained print("回零完成") return True time.sleep(0.01) raise TimeoutError("回零超时,检查限位开关和0x6099速度")outputs和inputs是过程数据映像,前2字节对应0x6040和0x6041。0x001F就是bit0到bit4全1,bit5为0。等待循环里每10毫秒发一次过程数据,同时检查状态字。如果30秒还没完成,大概率是0x6099速度设得太低,或者限位开关没接对。
3.3 回零完成后怎么验证位置:0x6064和0x607A的读数
回零完成后,0x6064(实际位置)应该稳定在0x607C(原点偏移)附近。台大A2在Homing attained之后会把0x6064清零,然后加上0x607C的偏移。你可以读0x6064确认,如果读回来是0或者等于0x607C,说明回零成功。如果读回来是一个很大的数,说明回零过程中撞了限位但没停,检查0x6099子1的速度是否过高。
def verify_homing(master, slave_pos): actual_pos = master.slaves[slave_pos].sdo_read(0x6064, 0x00, 4) pos_val = int.from_bytes(actual_pos, 'little', signed=True) offset = master.slaves[slave_pos].sdo_read(0x607C, 0x00, 4) offset_val = int.from_bytes(offset, 'little', signed=True) if abs(pos_val - offset_val) < 10: # 允许10个用户单位的误差 print(f"回零验证通过,当前位置={pos_val},原点偏移={offset_val}") return True else: print(f"位置异常:当前位置={pos_val},期望={offset_val}") return Falsesigned=True是因为位置值可能是负数。误差阈值10根据机械精度调整,一般编码器分辨率高的话可以设到1。
4. 台大A2 Homing调试避坑:5个血泪教训
4.1 现象:写0x6060=6后状态字bit10一直不置位
原因:驱动器没有完整进入Operation enabled,或者0x6060写入后没有回读确认。台大A2在Switch on状态下写模式切换请求会被静默丢弃,状态字bit10不会变化。
解决:在写0x6060之前,先读0x6041确认低字节是0x27。写完0x6060后立刻读0x6061,如果回读不是6,重新走一遍使能流程。第三方主站里如果用了自动状态机,检查它是否在Switch on之后有足够的延时再发模式切换。
4.2 现象:回零启动后电机朝一个方向慢速爬行,不停
原因:0x6099子1的速度单位搞错了。第三方主站默认按「转/分」下发,台大A2按「用户单位/秒」解释,数值差了几十倍,电机看起来像不动或者极慢。
解决:确认0x6099的单位。台大A2的「用户单位」由0x6092(进给常数)决定,如果没配过,默认是编码器脉冲。我一般会把0x6099子1设成200到500之间,子2设成20到50之间,先低速测试,确认方向对了再提速。
4.3 现象:回零过程中撞到限位开关但不停,直接冲过去
原因:0x6098的回零方法选错了。方法17是「找负限位开关」,方法18是「找正限位开关」。如果机械上负限位在左边,你选了18,电机会往右找正限位,但正限位可能没接,或者接反了。
解决:先用手动模式(0x6060=1)点动确认限位开关的方向和极性。台大A2的限位开关默认常闭,如果接成常开,驱动器认为限位一直触发,回零会直接跳过找开关阶段。检查0x60FD(数字输入)的bit0和bit1,确认限位状态。
4.4 现象:SDO写入0x6098返回中止码0x06010000
原因:驱动器不在PreOP状态,或者PDO映射里已经包含了0x6098,SDO和PDO冲突。台大A2在SafeOP和OP状态下不允许SDO写已经被映射到PDO的对象。
解决:把0x6098从PDO映射里移除,只用SDO配置。或者反过来,把0x6098加进PDO,用过程数据写。我一般选前者,因为Homing参数不需要实时刷新,SDO写一次就够了。改PDO映射前记得切到PreOP。
4.5 现象:回零完成后0x6064读数跳变,不稳定
原因:0x609A回零加速度设得太大,电机在接近开关时过冲,编码器计数抖动。或者0x607C原点偏移和实际机械零点差了半个脉冲。
解决:把0x609A降到200到300,重新回零。如果还抖,检查编码器接线屏蔽是否良好。台大A2的编码器反馈是差分信号,屏蔽层单端接地,如果两端都接地会形成地环路,导致计数跳变。
5. 用状态字bit12做回零完成中断:一个少写轮询的技巧
很多第三方主站跑Homing时用轮询状态字bit10的方式等回零完成,占CPU还容易漏判。台大A2的状态字bit12(Homing attained)在回零成功后会保持为1,直到下一次模式切换。你可以用这个位做中断触发,而不是死等bit10。
具体做法是在主站的过程数据回调里检查bit12的上升沿。以SOEM为例,receive_processdata之后读inputs,如果bit12从0变1,就触发一个事件,停止轮询。这样主循环可以去做其他事,比如监控其他从站。
class HomingMonitor: def __init__(self, master, slave_pos): self.master = master self.slave_pos = slave_pos self.last_bit12 = False self.homing_done = False def update(self): self.master.send_processdata() self.master.receive_processdata() status = int.from_bytes(self.master.slaves[self.slave_pos].inputs[0:2], 'little') bit12 = bool(status & 0x1000) if bit12 and not self.last_bit12: self.homing_done = True print("Homing attained,回零完成") self.last_bit12 = bit12 return self.homing_done这个类每次update只做一次过程数据收发和位判断,比轮询bit10轻量。注意bit12在回零完成后不会自动清零,如果你要重新回零,得先切到其他模式再切回6,或者写0x6040的bit4重新触发。
验证方法:在回零完成后读0x6064,确认位置在0x607C附近。然后手动把电机转一个角度,再读0x6064,看数值是否跟着变。如果不变,说明编码器反馈没进PDO,检查0x1C13的TxPDO映射里有没有0x6064。
我自己的习惯是每次改完PDO映射或SDO参数,先用低速空载跑一遍回零,确认状态字bit12能置位,再装负载。台大A2的Homing模式在第三方主站上跑通一次之后,后面就是复制配置的事,但第一次的时序和单位换算,值得花时间记下来。希望帮到你。
本文还有配套的精品资源,点击获取