EtherCAT 基础编程指南 (IgH Master)
基于 Linux IgH EtherCAT Master 协议栈,面向初学者与现场调试人员,兼顾“教学 + 查阅”双需求。阅读顺序建议:先跑通第 0 章自检,再按需跳转到各功能章节。
快速导航
- 0. 环境准备与验证
- 1. 核心概念速览
- 2. 程序整体架构
- 3. 常用 API 速查表
- 4. 初始化流程详解
- 5. 规范化初始化封装
- 6. 周期任务与实时线程
- 7. CiA-402 状态机速览
- 8. 多从站与 PDO 组织建议
- 9. 常见问题排查
0. 环境准备与验证
0.1 前置条件清单
- 内核/补丁:优先使用 PREEMPT_RT 内核或 IgH 官方实时补丁;
uname -a确认版本。 - IgH Master:与驱动对应版本(示例使用 1.6.x);确认已安装
ethercat工具链。 - 权限配置:
groupadd ethercat并将用户加入;/dev/EtherCAT0 需0660权限。 - 网卡:独立物理口,关闭 NetworkManager,锁定全双工 100Mbps。
- 设备:准备好 ESI XML 文件并确认 Vendor ID / Product Code。
0.2 最小自检步骤
| 目标 | 命令 | 预期输出 | 失败排查 |
|---|---|---|---|
| 驱动加载 | sudo /etc/init.d/ethercat start |
Starting EtherCAT master 1.6... done |
查看 `dmesg |
| 主站状态 | ethercat master |
Master0 State: OP |
若为 INIT 检查网卡绑定 |
| 从站可见性 | ethercat slaves |
列出所有设备及 ID | 若为空,检查布线/拓扑 |
| PDO 结构 | ethercat pdos 或 ethercat cstruct |
对应条目及位宽 | 若报错,核对 XML 与固件 |
| SDO 通信 | ethercat upload --type uint16 0 0x1000 0x00 |
返回 Vendor ID | 若超时,确认从站上电 |
提示:运行示例程序前,确保上述命令在 root 或加入 ethercat 组的用户下都可执行;否则会在
ecrt_request_master处失败。
1. 核心概念速览
| 术语 | 全称 | 解释 | 类比 |
|---|---|---|---|
| Master | EtherCAT Master | 运行在 PC 上的主站程序,负责管理总线。 | 乐队指挥 |
| Slave | EtherCAT Slave | 连接在网线上的设备(驱动器、IO 模块)。 | 乐手 |
| Domain | Process Data Domain | 主站管理的共享内存,用于存放所有从站的实时数据 (PDO)。 | 乐谱架 |
| PDO | Process Data Object | 周期性实时数据,如位置、速度。快但不重传。 | 演奏中的音符 |
| SDO | Service Data Object | 非周期配置数据,如参数、报警。慢但可靠。 | 演出前调音 |
| DC | Distributed Clocks | 纳秒级同步机制,确保多从站同拍执行。 | 节拍器 |
2. 程序整体架构
1 | 项目 |
一个标准的 EtherCAT 控制程序由 初始化阶段 和 实时周期循环 两部分组成。
1 | graph TD |
3. 常用 API 速查表
| 函数 | 用途 | 关键参数 | 常见失误 |
|---|---|---|---|
ecrt_request_master |
获取主站实例 | master_index 对应 /dev/EtherCATX |
无权限、服务未启动 |
ecrt_master_create_domain |
创建 PDO Domain | master |
多域场景未区分输入输出 |
ecrt_master_slave_config |
绑定从站配置 | alias, position, vendor_id, product_code |
ID 与现场不符,导致 PREOP 卡死 |
ecrt_slave_config_pdos |
设置 PDO 映射 | n_syncs, syncs |
位宽求和错误、漏写 EC_END |
ecrt_domain_reg_pdo_entry_list |
将 PDO 条目映射到域内存 | domain, reg_list |
忘记以 {} 结尾、offset 指针指向局部变量 |
ecrt_slave_config_dc |
配置分布时钟 | assign_activate, cycle_time |
从站不支持 DC 却强行配置 |
ecrt_master_activate |
应用配置 | master |
激活后仍调用 _config 接口 |
ecrt_domain_data |
获取域内存入口 | domain |
忘记检查返回值导致段错误 |
ecrt_master_receive/send |
硬件收发帧 | master |
调用顺序错误,引入一拍延迟 |
ecrt_domain_process/queue |
解析/排队域数据 | domain |
未调用 process 就取数,读取到旧帧 |
4. 初始化流程详解 (API 深度解析)
初始化的目标是回答三件事:谁在线?交换什么数据?如何同步? 以下步骤沿用 IgH 官方推荐顺序。
4.1 请求主站与创建域
核心函数 1.1:ecrt_request_master
- 功能:请求 EtherCAT 主站实例的控制权。
- 原型:
ec_master_t *ecrt_request_master(unsigned int master_index); - 参数:
master_index: 主站索引,通常为0(对应/dev/EtherCAT0)。
- 返回值:成功返回主站指针,失败返回
NULL。 - 说明:这是程序的入口,必须首先调用。
核心函数 1.2:ecrt_master_create_domain
- 功能:在主站中创建一个新的过程数据域 (Domain)。
- 原型:
ec_domain_t *ecrt_master_create_domain(ec_master_t *master); - 参数:
master: 步骤 1.1 获取的主站指针。
- 返回值:成功返回域指针,失败返回
NULL。 - 说明:Domain 就像一个“购物车”,你需要把所有从站的 PDO 数据(商品)都注册到这个域里,最后一次性结账(交换数据)。
ecrt_request_master:申请/dev/EtherCAT0控制权。确保以 root/实时用户运行。ecrt_master_create_domain:创建一个 Domain。一个 Domain 等价于一块共享内存,可承载多个从站 PDO。
1 | ec_master_t *master = ecrt_request_master(0); |
4.2 获取从站配置 (Slave Config)
核心函数:ecrt_master_slave_config
- 功能:获取或创建指定从站的配置对象。
- 原型:
1
2
3
4
5
6
7ec_slave_config_t *ecrt_master_slave_config(
ec_master_t *master,
uint16_t alias,
uint16_t position,
uint32_t vendor_id,
uint32_t product_code
); - 参数:
alias: 从站别名。如果未设置别名,填0。position: 拓扑位置。总线上第 1 个设备为0,第 2 个为1,依此类推。vendor_id: 厂商 ID (如汇川、松下、倍福的唯一 ID)。product_code: 产品编号。
- 返回值:成功返回配置对象指针,失败返回
NULL。 - 说明:此函数不仅是获取句柄,更是一个“断言”。如果总线上实际设备的厂商/产品码与此处不符,主站会报错并拒绝工作。
使用 ecrt_master_slave_config 为每个拓扑位置断言正确的 Vendor/Product。若别名未设置,可取 0,仅依赖位置。
1 |
|
4.3 配置 PDO 映射
核心函数:ecrt_slave_config_pdos
- 功能:为从站指定完整的 PDO 映射关系(Sync Manager -> PDO -> Entries)。
- 原型:
1
2
3
4
5int ecrt_slave_config_pdos(
ec_slave_config_t *sc,
unsigned int n_syncs,
const ec_sync_info_t *syncs
); - 参数:
sc: 步骤 2 获取的从站配置指针。n_syncs: 同步管理器数量,通常使用宏EC_END让函数自动计算。syncs: 指向ec_sync_info_t数组的指针,描述了所有的 SM 和 PDO 结构。
- 返回值:
0表示成功,非0表示失败。 - 说明:这是最繁琐的一步。你需要查阅驱动器手册,构建
ec_pdo_entry_info_t->ec_pdo_info_t->ec_sync_info_t的嵌套结构体。
ecrt_slave_config_pdos 需要按照 Entry -> PDO -> SyncManager 的嵌套结构依次声明。位宽必须与手册一致,位宽求和需满足 8*n。
1 | static ec_pdo_entry_info_t axis0_pdo_entries[] = { |
4.4 注册 PDO 条目
核心函数:ecrt_domain_reg_pdo_entry_list
- 功能:批量注册 PDO 条目,获取其在共享内存中的偏移量。
- 原型:
1
2
3
4int ecrt_domain_reg_pdo_entry_list(
ec_domain_t *domain,
const ec_pdo_entry_reg_t *pdo_entry_regs
); - 参数:
domain: 步骤 1.2 创建的域指针。pdo_entry_regs: 一个以空结构体{}结尾的数组,包含所有要读写的变量信息。
- 返回值:
0表示成功,非0表示失败。 - 说明:
- 这是将“逻辑变量”映射到“物理内存”的关键步骤。
- 数组中的
offset字段是一个指针,函数执行后,会将计算出的偏移量填入该指针指向的变量中。
ecrt_domain_reg_pdo_entry_list 将逻辑变量与域内存偏移绑定。offset 指针需为全局/静态变量,否则函数结束就失效。
1 | static unsigned int off_ctrl_word; |
4.5 配置分布时钟 (DC,同步场景)
核心函数:ecrt_slave_config_dc
- 功能:配置从站的分布时钟参数。
- 原型:
1
2
3
4
5
6
7
8void ecrt_slave_config_dc(
ec_slave_config_t *sc,
uint16_t assign_activate,
uint32_t sync0_cycle_time,
int32_t sync0_shift_time,
uint32_t sync1_cycle_time,
int32_t sync1_shift_time
); - 参数:
assign_activate: 激活字。通常0x0300(激活 Sync0) 或0x0700(激活 Sync0 & Sync1)。需查阅从站手册 (ESI XML)。sync0_cycle_time: Sync0 信号周期(纳秒)。通常等于主站通信周期。sync0_shift_time: Sync0 偏移量。用于微调触发时间,避免与数据传输冲突。
- 说明:只有需要高精度同步(如多轴插补)时才需要此步骤。
ecrt_slave_config_dc(sc, 0x0300, cycle_ns, shift, 0, 0);
- 确认从站
AssignActivate支持 Sync0,否则关闭 DC。 cycle_ns建议等于周期任务周期;shift用于避开帧发送窗口。
4.6 激活主站并获取域内存
核心函数 6.1:ecrt_master_activate
- 功能:结束配置阶段,应用所有设置,启动总线通信。
- 原型:
int ecrt_master_activate(ec_master_t *master); - 返回值:
0表示成功,非0表示失败。 - 说明:一旦激活,就不能再调用
_config类的函数。此时主站会开始在后台发送数据帧。
核心函数 6.2:ecrt_domain_data
- 功能:获取过程数据域的共享内存首地址。
- 原型:
uint8_t *ecrt_domain_data(ec_domain_t *domain); - 返回值:指向共享内存的指针。
- 说明:
- 拿到这个指针后,结合步骤 4 获取的
offset,就可以读写数据了。 - 例如:
target_pos = domain_pd + offset_target_pos;
- 拿到这个指针后,结合步骤 4 获取的
1 | if (ecrt_master_activate(master)) { |
4.7 多从站提示
- 多驱动共享一个 Domain:为每个从站生成独立的 offset 变量,建议使用结构体封装(见第 8 章)。
- 多 Domain:若需要将高速输出与慢速输入隔离,可创建多个 Domain 分别绑定不同任务线程。
- 检查命令:
ethercat pdos -p <pos>验证映射是否与代码一致;ethercat diag可查看 SM 状态。
5. 规范化初始化函数封装
下面示例展示一个可复用的 init_ethercat,包含日志输出,方便在嵌入式系统上排查问题。
1 |
|
6. 周期任务与实时线程
6.1 实时线程骨架
1 |
|
要点:
mlockall避免缺页造成长抖动。- 使用
SCHED_FIFO+ 绑核,配合 PREEMPT_RT 内核。- 记录
clock_gettime结果,结合TIMESPEC2NS宏传给ecrt_master_application_time。
6.2 周期循环示例
大致顺序
- Wait: 等待周期时间到。
- App Time: 告知主站当前时间 (DC同步关键)。
- Receive: 接收数据。
- Process: 处理数据域。
- Logic: 读取输入 -> 运行算法 -> 写入输出。
- Sync: 计算并补偿时钟漂移。
- Queue & Send: 加入队列并发送。
1 |
|
7. CiA-402 状态机速览
| 状态 | StatusWord 条件 |
下一步控制字 | 备注 |
|---|---|---|---|
| Switch On Disabled | status & 0x004F == 0x0040 |
0x0006 (Shutdown) |
上电初始态 |
| Ready to Switch On | status & 0x006F == 0x0021 |
0x0007 (Switch On) |
需满足伺服上电条件 |
| Switched On | status & 0x006F == 0x0023 |
0x000F (Enable Op) |
可进使能 |
| Operation Enabled | status & 0x006F == 0x0027 |
0x000F |
可发送运动目标 |
| Fault | status & 0x0008 |
0x0080 (Fault Reset) |
需先复位再重走流程 |
最小状态机实现示例
1 | static uint16_t cia402_control_word(uint16_t status) |
在周期任务中可将上述函数与状态字结合,确保任何异常都能自动复位并重走 CiA-402 流程。
8. 多从站与 PDO 组织建议
结构体封装 offsets:
1
2
3
4
5
6
7typedef struct {
unsigned int ctrl;
unsigned int tgt;
unsigned int status;
unsigned int act;
} axis_offsets_t;
static axis_offsets_t axis[2];结合
ec_pdo_entry_reg_t的user1字段或手动拆分,避免 offset 命名失控。模板化 PDO 表:对相同型号驱动,可将
ec_pdo_entry_info_t、ec_pdo_info_t定义在单独.c文件,供多实例复用。不同厂商混合:每类从站单独一组
regs[],注册到同一 Domain。通过alias/position区分,可读性更佳。位宽校验脚本:用 Python 读取 ESI XML,计算每个 PDO 位宽总和,与代码常量比对,避免现场才发现长度不符。
命名建议:
off_<slave>_<signal>,配合注释标注单位与类型,方便交叉检查。
9. 常见问题排查 (Troubleshooting)
| 症状 | 可能原因 | 诊断命令 | 处理建议 |
|---|---|---|---|
Failed to request master |
未加入 ethercat 组或服务未启动 | ethercat master |
sudo /etc/init.d/ethercat restart,检查权限 |
PDO registration failed |
Vendor/Product 不符或 regs[] 未以 {} 结尾 |
ethercat slaves |
更新宏常量;确认 regs 终止项 |
| 从站卡在 PREOP/SAFEOP | PDO 映射和 XML 不一致 | ethercat pdos -p N |
根据 ESI 重新生成 syncs,或临时禁用自定义映射 |
| 进入 OP 但数据全 0 | 忘记 ecrt_domain_process 或 offset 无效 |
ethercat diag -p N |
检查调用顺序;确保 offset 变量为静态 |
DC 同步失败、报 clock error |
从站不支持 DC 或周期时间不匹配 | ethercat diag --dc |
关闭 DC (assign_activate=0x0000) 或校准 cycle_ns |
| 电机抖动/漂移 | 周期抖动大、线程被抢占 | cyclictest, htop |
使用 PREEMPT_RT、绑核、提高优先级、减少 printf |
Reg request busy/SDO 超时 |
在周期线程中过度发 SDO | ethercat sdos |
将 SDO 操作放在初始化线程或降低频率 |
| 多从站偶发掉线 | 布线/电源或环网拓扑问题 | ethercat crc, ethercat slaves -v |
更换网线、缩短总线、为伺服单独供电 |
排查顺序建议:物理层 → 主站日志 (
dmesg) →ethercat命令 → 应用日志 → 抓包 (Wireshark ECAT 插件)。
通过上述结构,初学者可以先做环境自检,再按章节查找 API/示例;现场调试时亦可直接定位常见故障与状态机处理逻辑。如需扩展特定驱动或实时算法,可在对应章节追加项目实践笔记。