Slave API
通过 master[n] 或 master.slave(n) 访问(1-based 索引)。
快速开始
索引访问
slave = master[1] # 第1个从站(1-based 索引)
slave = master.slave(1) # 等效写法
count = master.slave_count # 从站总数
组访问
servo = master.groups[0][0] # 默认组第1个从站
io = master.groups[1][2] # 组1第3个从站
group_count = len(master.groups[1]) # 组1从站数
提示
组相关属性详见 从站分组。
地址访问
# 物理配置地址(自动分配)
addr = slave.config_addr # 如 0x1001
# 别名地址(EEPROM 中配置,可选)
alias = slave.alias_address
# 按地址查找
target = next((s for s in master.slaves if s.config_addr == 0x1001), None)
标识访问
name = slave.name # 设备名称
drive_name = slave.drive_name # 驱动名称(SDO 0x1008)
vendor_id = slave.vendor_id # 厂商 ID
product_id = slave.product_id # 产品 ID
revision = slave.rev_id # 修订号
serial = slave.serial_number # 序列号
# 按名称查找
target = next((s for s in master.slaves if s.name == "EL2008"), None)
协议访问
| 协议 | 属性 | 说明 |
|---|---|---|
| PDO | slave.pdo | 过程数据对象,实时 IO 数据读写 |
| CoE | slave.coe | CANopen over EtherCAT,SDO 对象字典访问 |
| CiA 402 | slave.cia402 / CiA402Advanced | 伺服驱动器协议,状态机管理与使能控制 |
| MDP | slave.mdp | 模块化设备协议,模块检测与自动配置 |
| SoE | slave.soe | Servo over EtherCAT,伺服驱动器参数 |
| FoE | slave.foe | File over EtherCAT,文件传输 |
| EoE | slave.eoe | Ethernet over EtherCAT,以太网隧道 |
| AoE | slave.aoe | ADS over EtherCAT,Beckhoff ADS 协议 |
| VoE | slave.voe | Vendor over EtherCAT,厂商特定协议 |
| FSoE | slave.fsoe | Functional Safety over EtherCAT,功能安全协议 |
PDO 数据读写
详细的 PDO 读写方式请参见 PDO 输入输出。
推荐方式 — 结构体映射 (零拷贝):
import ctypes
class ServoInput(ctypes.Structure):
_pack_ = 1
_fields_ = [
("status_word", ctypes.c_uint16),
("actual_position", ctypes.c_int32),
("actual_velocity", ctypes.c_int32),
]
input_ref = slave.pdo.bind_pdo_struct(ServoInput, is_input=True)
if input_ref:
print(f"当前位置: {input_ref.actual_position}")
EMCY 紧急消息
EtherCAT 从站在检测到异常时会发送 EMCY (Emergency) 紧急消息。通过 slave.coe 访问, 详见 CoE — EMCY 紧急消息。
# 获取紧急消息历史
history = slave.coe.get_emergency_history()
for msg in history:
print(f"错误码: 0x{msg.error_code:04X}, 寄存器: 0x{msg.error_register:02X}")
# 清除紧急消息历史
slave.coe.clear_emergency_history()
拓扑查询
通过从站的 children 属性获取子从站列表, 实现拓扑树的遍历。
# 获取从站的子从站
children = slave.children
# 遍历拓扑树
def print_tree(s, depth):
indent = " " * depth
print(f"{indent}[{s.slave_num}] {s.name}")
for child in s.children:
print_tree(child, depth + 1)
for s in master.slaves:
if s.topology == 1 or s.parent_station == 0:
print_tree(s, 0)