简介:这套资源基于IgH EtherCAT Master 1.5.2,面向需要学习EtherCAT主站开发、特别是伺服电机力矩控制与PDO/SDO对象字典操作的工业自动化工程师。作者用其驱动过三洋与泰科伺服电机,并适配ET1100 IO板,代码涵盖电机使能/失能、运行模式切换、力矩命令下发、反馈读取,以及IO控制和温湿度读取等实用功能。压缩包共113个文件,以C语言头文件(37个)、源文件(27个)和Makefile(8个)为主,另有配置文件、生成从站信息的脚本、调试记录等,总大小1.25MB,目录组织清晰。已有1091人学习下载。资源中scripts可自动生成从站PDO/SDO配置,ec_common二次封装库大幅简化调用,同时保留ioctl和libethercat两套原生接口示例,便于对照理解。对想做EtherCAT主站开发或迁移现有方案的工程师来说,是一份可直接参考甚至复用的开源模板。
1. 一次现场调试让我确信:EtherCAT 主站不是装上就能跑
那天在车间调一台六轴设备,EtherCAT 总线像抽风一样,伺服电机均匀抖动,偶发“六号轴掉线”。查了网线、换了从站、调了驱动增益,该翻的车都翻了,最后发现是主站周期和从站同步周期差了半拍。后来把主站换成 IgH EtherCAT master 源码包自己编译,问题才算收敛。这个包(往往就是一个 ethercatpack.7z)不是拿来就能用的现成工具,而是一整套 Linux 实时网卡驱动、主站内核模块和用户态调试工具的集合。适合做运控、上位机,或者想摆脱专用控制器、在通用 PC 上自己搭 EtherCAT 方案的工程师。能省掉不少二次开发,但前提是你得懂得怎么把它“编译”成自己设备的样子。
2. 解开 ethercatpack.7z 之前,先搞清楚这个包里装的是哪几层东西
2.1 解压之后你会看到 master、tool、script 三个层次
拿到一个名为 ethercatpack.7z 的文件,第一件事不是急着解压,而是确认解压工具。常见发行版可能没有 p7zip,需要先装上,再解压到自己习惯的目录。命令里的输出路径最好不要带空格,否则后续路径操作会让你在脚本里绕来绕去。
sudo apt-get install p7zip-full # Debian/Ubuntu 系 7z x ethercatpack.7z -o$HOME/ecat cd $HOME/ecat ls -l第一行安装 7z 命令,如果系统里已经有 p7zip,可以跳过。第二行的-o$HOME/ecat指定把解压内容放到~/ecat,注意-o后面没有空格,这是 7z 的固定写法。第三行进入目录,第四行查看目录下的内容。通常你会看到master、tool和几个说明文件,有些包还会带script或doc。master目录下是内核模块的源码,包含核心的 EtherCAT 主站逻辑、时钟同步、帧调度,以及若干网卡驱动的“马甲”模块。tool目录则是一个叫ethercat的命令行工具,编译安装后它会去访问主站,用来扫描从站、查看状态、读写对象字典。script目录一般放一些初始化脚本示例,比如怎么在系统启动时绑定网卡、加载模块。
如果你解压时报错“Cannot open file as archive”,先查这个 7z 文件是否有完整权限,或者是不是在 Windows 下压缩时带了特殊文件名。用7z t测试包完整性,比硬着头皮解压更能快速定位问题。
2.2 主站为什么是内核模块而不是普通应用:实时性和中断占用的取舍
我见过不止一个工程师问:EtherCAT 主站不就是一个数据包收发器吗,为什么非要在内核态运行?答案就在周期严格性上。EtherCAT 从站依靠主站发送的帧来同步自己的本地时钟,如果主站收发帧的延迟忽大忽小,从站的 DC 同步就会漂移,表现为电机电流环抖动、噪声变大,严重时直接报同步错误。用户态程序虽然可以通过mmap和ioctl访问网卡,但每一次收发都要经过 Linux 网络协议栈、套接字缓冲区、调度器上下文切换,这个不确定开销在微秒级实时场景里是致命的。
所以 IgH 主站把帧收发放在一个内核模块里,直接注册到网卡设备的中断处理路径上。收到中断后立刻处理接收帧,再在周期任务里发送下一帧。用户态只通过字符设备接口做配置和监控,不影响实时路径。这种设计还带来一个实际操作上的约束:主站模块和网卡驱动必须严格匹配。包里的master目录会带着几个网卡驱动模块,比如常见的ec_e1000e、ec_8139too,它们在编译时会针对内核版本生成。如果你加载了ec_master却没有加载对应的网卡模块,主站就找不到物理设备。这一步是新手最容易忽略的,也最容易被想当然糊弄过去。
2.3 先确认你的网卡是不是“被支持的那几种”
在编译主站之前,先用lspci看一下自己板子上的网卡芯片。EtherCAT 主站对网卡实时性要求高,并不是随便一块 USB 网卡都能干。常见做法是找板载 PCIe 千兆网卡,控制芯片为常见的 Intel 系列或 Realtek 8139 等百兆/千兆芯片。先记下网卡对应的驱动名,这直接决定后面 configure 时开哪个模块。
lspci -nnk | grep -i ethernet -A 2这条命令列出 PCI 设备中的以太网控制器,并显示当前内核使用的驱动模块名。假如输出显示Kernel driver in use: e1000e,那么你要在编译主站时开启e1000e支持;如果显示8139too,就开8139too。别只看网卡速率,很多千兆网卡在支持列表之外,强行加载主站驱动只会得到空设备。特别提醒:如果你的工控机只有一个网卡,并且还指望它同时给上位机提供 SSH 和文件共享,那最好再加一块独立网卡,把 EtherCAT 专用网卡和日常管理网卡分开。专用网卡在主站运行后就不再是普通 TCP/IP 网卡,你无法再通过它 SSH,否则会干扰实时收发。
3. 把主站跑起来:从打内核补丁到装好 ethercat 命令
3.1 准备内核:RT 补丁优先,否则周期跑不满
IgH EtherCAT master 对内核实时性有要求。虽然理论上可以在普通内核里运行,但如果你要做的是伺服控制,周期抖动会让你调驱动调到怀疑人生。我一般会在编译主站前先给内核打上实时补丁,也就是常见的 PREEMPT_RT 补丁。具体版本搭配上,每个内核版本都有一个对应的 RT 补丁,下载时注意要和内核源码版本完全一致,差一个 patch 级别都可能编不过。
进入内核源码目录后,先用默认配置生成基础配置文件,再打开菜单配置界面。
cd /usr/src/linux make menuconfig在make menuconfig界面里,进入General Setup > Preemption Model,选择Fully Preemptible (Real-Time)。这里选完只是把调度模型改了,还要留意 Timer 相关的选项,老版本内核里还需要打开High Resolution Timer Support。配置保存后,开始编译内核:
make -j$(nproc) bzImage modules sudo make modules_install sudo make install-j$(nproc)用所有内核并行编译,能快很多;modules_install把编译出的模块放到/lib/modules/$(uname -r),make install安装内核镜像并更新引导。重启后确认uname -r是否指向新内核。如果使用 GRUB 引导,有时新内核不会自动成为默认项,需要手动调整 GRUB 的启动优先级。编译到中途报错,最常见的是内核源码和 RT 补丁版本不匹配,只能换源重来,没有后悔药。
如果你用的是某个发行版自带的实时内核,也可以跳过自编译,直接装发行版的实时内核包。省了编译时间,但代价是主站模块要按这个内核的 headers 编译,环境对不上更容易翻车。公司里如果多个设备,最好统一内核版本,否则同一份 ethercatpack.7z 在每个设备上都要重新编译一遍。
3.2 编译主站:configure 参数决定了你能吃到多少功能
进入master目录后,先用./configure --help看一眼可选项,别依赖记忆。不同版本的包支持的特性不一样,有的默认开 RTDM,有的默认关。常见配置是关闭 RTDM、开启对应网卡驱动:
cd $HOME/ecat/master ./configure --prefix=/usr/local --disable-rtdm --enable-e1000e make sudo make install sudo depmod第一行进入源码目录。第二行配置主站,--prefix=/usr/local表示安装到/usr/local,这样ethercat命令会在/usr/local/sbin/下;--disable-rtdm是因为较新内核里已经移除了老的实时设备驱动框架,如果你的源码包基于较新的内核,必须禁用;--enable-e1000e告诉主站编译自带的ec_e1000e网卡驱动模块。如果你的网卡是其他型号,把参数换成对应的。在 configure 之前最好先执行sudo apt-get install autoconf libtool linux-headers-$(uname -r),因为缺少这些会导致“configure: error: no acceptable C compiler found”或找不到内核头文件。
make和make install负责编译和安装,depmod更新模块依赖。这一步最常见的失败是 configure 提示找不到内核源码。原因通常是你没有安装与当前内核匹配的linux-headers包,或者/usr/src/linux没有正确指到当前内核。安装对应 headers 后,在master目录下重新跑 configure 即可,不需要重编内核,这算是个后悔药。
编译完成后,加载模块的顺序也有讲究。先卸载掉系统原来的网卡驱动,再加载主站自带的网卡驱动,最后加载ec_master:
sudo rmmod e1000e sudo modprobe ec_e1000e sudo modprobe ec_master看明白了吗?先拆座钟再上发条。rmmod e1000e把原来的普通网卡驱动摘掉,因为ec_e1000e和它抢同一个 PCI 设备,如果原驱动还在,ec_e1000e就绑定不到设备上。然后modprobe ec_e1000e让主站接管网卡,最后modprobe ec_master加载主站本体。顺序反了,你会看到Device not found一类的报错,原因就在这。
3.3 扫描总线:确认主站和从站已经在握手
安装完后,用ethercat工具验证总线是否通:
sudo /usr/local/sbin/ethercat scan如果能看到一串从站编号和名称,说明链路没问题。如果输出为空或者报错,先跑sudo /usr/local/sbin/ethercat master看主站状态。常见情况是主站没有进入OP或PREOP状态,需要先用sudo /usr/local/sbin/ethercat states -s PREOP切到预运行态,再重复扫描。区分“物理链路通了”和“主站协议栈处于可用状态”这两件事,排查时别混在一起。
还可以用sudo /usr/local/sbin/ethercat version确认工具和主站是否来自同一版本,如果版本对不上,后续读到的状态可能是错的。反正第一步已经能把八成环境问题暴露出来了,剩下八成才值得深入。
4. 配置主站匹配伺服:周期、Pdo 映射与 DC 同步
4.1 周期参数不是拍脑袋设的:主站周期与 DC 同步的关系
电机驱动器内部的电流环周期通常固定,比如 1 kHz 或 4 kHz。主站发送 EtherCAT 帧的周期决定所有从站的同步基准。如果你主站周期设成 2 ms,驱动器电流环周期 1 ms,两者不在一个节拍上,运行中就会出现周期性误差。IgH 主站允许在应用代码里设置周期,常见做法是直接在实时任务里调用:
#include <ecrt.h> #define TIMER_INTERVAL_NS 1000000 /* 1ms */ ecrt_master_set_periodic_master(master, TIMER_INTERVAL_NS);代码里的1000000是 1 ms 的纳秒数。这个函数告诉主站,你将在主循环里按这个周期调用发送和接收。注意“告知”不等于“锁定”,实际周期由你的主循环心跳决定。如果主循环因为调度延迟跑偏,主站帧速率也会跟着偏。所以常见做法是在 RT 任务里把该线程绑定到独立 CPU 核,并使用SCHED_FIFO优先级。
下面这个表格是常见的周期与帧率对应关系,方便你在看ethercat master输出时快速比对:
| 周期 (ms) | 对应帧率 (Hz) | 典型应用场景 |
|---|---|---|
| 0.25 | 4000 | 高频电流环,高端伺服 |
| 0.5 | 2000 | 大多数伺服默认支持 |
| 1.0 | 1000 | 通用运动控制,兼容性最好 |
| 2.0 | 500 | IO 采集,非高动态场景 |
DC(Distributed Clock)是 EtherCAT 的时基同步机制。主站会周期性地发送ARMW写命令,把所有从站的本地时钟对齐到参考时钟。如果从站之间 DC 漂移过大,多半是主站周期不稳定,而不是从站坏了。调周期参数时,优先确认网卡中断没有被其他驱动抢走,再用工具观察主站帧速率波动。
4.2 看从站 Pdo 映射:用命令确认要不要重新映射
Pdo 映射决定每一个 EtherCAT 周期里主站和从站交换哪些对象。比如伺服驱动器通常要映射控制字 0x6040、状态字 0x6041、目标速度 0x6042、实际速度 0x6044 等。不同驱动器出厂默认映射可能跟你上位机程序预期的不一致,这就需要用到ethercat pdo查看当前配置。
sudo ethercat pdo -m 0这条命令把主站 0 下所有从站的 Pdo 映射一行行列出来,包括每个 Pdo 的索引、子索引进出方向。如果发现某个从站缺了关键对象,可以通过ethercat upload、ethercat download在 PREOP 状态下修改映射表。但有个原则:修改 Pdo 映射必须在进入 OP 状态前完成,也就是从站处于 PREOP 或更早的状态,否则从站认为配置锁定,写入会静默失败。
修改映射对象的一个常见场景是给第三方驱动器增加一组 0x60xx 对象。先用ethercat upload读取当前映射子索引个数:
sudo ethercat upload -t uint8 0 0x1600 0x00这里-t uint8表示按单字节读,0是从站地址,0x1600是 Pdo 的索引,0x00是子索引。返回的数字能告诉你当前这个 Pdo 已经映射了几个对象,后面再决定怎么往下加。参数不要搞混,0x1600是输入还是输出映射,需要看从站的对象字典,不是光靠地址猜。很多驱动器把输出 Pdo 放在 0x1600,输入 Pdo 放在 0x1A00,但不同厂家有自己的习惯,用ethercat pdo多确认一次总没错。
4.3 从站状态机:PREOP、SAFEOP、OP 的切换踩点
EtherCAT 从站状态机四个状态:INIT、PREOP、SAFEOP、OP。主站从 INIT 逐级往 OP 推,每推一级都要做对应配置。比如 PREOP 下可以读对象字典,SAFEOP 下开始周期输入,OP 下才能输出。切换状态的命令是:
sudo ethercat states -m 0 -s OP-m 0指定主站 0,-s OP表示目标状态。执行后再用sudo ethercat states检查全部从站状态,如果某些从站卡在 SAFEOP,说明主站给它的输出配置没有通过检查。这时优先查看主站日志,常用的排查入口是内核日志:
dmesg | tail -50日志里会出现类似“PDO mapping mismatch”或者“watchdog timeout”的线索。状态切换是逐级进行的,遇到问题先用sudo ethercat states -s SAFEOP退一步看,别直接尝试再推 OP。退到 SAFEOP 后再跑一次ethercat pdo,对比映射和实际对象字典,通常 5 分钟内就能定位。
5. 主站起不来的 5 个典型翻车现场:避坑与排查
5.1 现象:加载模块报错 “Unknown symbol” 或 “Device not found”
原因在于内核版本与主站模块版本不一致,或者网卡驱动绑定顺序错误。尤其是你把一个别人打包好的 ethercatpack.7z 里的 .ko 文件拿到自己内核下面用,没重新编译,几乎百分之百会遇到符号表缺失。因为内核模块对导出的符号有严格依赖,包作者编译时用的内核和你当前的内核可能差了好几个 patch。
解决:回到第 3.2 节重新编译主站,确保./configure是在当前内核源码树下跑的;加载顺序必须是先网卡驱动后ec_master,顺序反了也会报找不到设备。用modinfo ec_e1000e看一下模块参数,确认它确实识别到网卡的 PCI ID。如果modinfo显示 unknown 符号,说明模块和内核头文件不匹配,只能重编。
5.2 现象:扫描只能看到从站 0,后面的从站全部无法识别
原因有两个方向。一是 EtherCAT 从站默认地址是 0,如果多个从站都没有配置别名,扫描器会把第一个设备的地址当作 0,但后面的设备无法通过地址区分,总线会显示混乱,甚至只认出一个设备。二是相邻从站之间网线没有按照菊花链顺序接,信号断在中间。
解决:先检查中间网线,用万用表确认从站供电正常,然后给每个从站通过 EEPROM 工具写入不同的别名地址,再重新扫描。注意写别名时从站必须在 INIT 或 PREOP 状态,不要在运行中写。有些现场还会遇到从站本身没上电,导致它“不存在”,表现也是后面的设备失踪,先排除供电再谈地址。
5.3 现象:主站周期抖动大,电机电流环噪声明显
原因通常不是 EtherCAT 协议问题,而是内核没有实时补丁,或者主站中断没有绑到独立 CPU 上。普通内核下,网卡中断可能被其他进程抢占,导致帧发送间隔不稳定。强实时场景用 PREEMPT_RT 内核后仍然抖动大,就要考虑核隔离和频率锁定。
解决:把主站的实时任务绑定到一个专用 CPU 核心,并把该核从普通调度器中隔离出来。使用taskset -c 3运行主站应用,同时检查 BIOS 是否开启了 C 状态节能和 CPU 频率动态调整,这两者会让 CPU 频率飘移,间接影响中断响应。还可以把实时线程的优先级用chrt -f 80提到最高,确保它优先于普通进程。
5.4 现象:断电重启后主站配置全部丢失
原因很直白:许多人调试时是手动跑命令完成配置的,一旦重启,网卡回到系统默认驱动,主站模块没有加载,前面手动写的配置自然没了。这个坑最隐蔽,因为断电前一切正常,断电后从站链路还通,但上位机就是连不上,你会以为是硬件坏了。
解决:把绑定网卡、加载模块、切换到 OP 状态写成启动脚本,放进 systemd 服务。注意服务启动顺序要在网卡就绪之后,并且在从站上电完成后再拉起主站。可以在脚本里加sleep 1等待网络设备真正出现,避免开机时序问题。脚本里尽量用绝对路径,避免 PATH 环境不同导致找不到命令。
5.5 现象:从站切到 OP 后立刻回到 SAFEOP,状态字报 watchdog 超时
原因常常是主站和从站的周期配置不匹配,或者从站没有在超时周期内收到新的有效帧。这又多半是 Pdo 映射不完整,导致从站输出数据校验失败,看门狗立刻跳闸。还有种情况是从站要求的周期能力只支持 500us,你硬设成 250us,它直接拒绝同步。
解决:用ethercat pdo查一下每个从站的映射列表是否包含了状态字和控制字。如果少了,在 PREOP 下重新配置映射。然后在主站代码里检查帧发送返回值,确认每个周期都成功交换了数据。别忽略应用层处理超时,实时任务里一旦有系统调用堵塞,看门狗也会误判。
6. 用一个真实周期日志脚本判断主站有没有被“喂饱”
这个技巧很适合在现场快速判断主站实时性是否达到预期,不需要额外装复杂工具。原理很简单:用高精度时钟记录相邻两个周期之间的时间差,如果某个周期超过设定值的 1.5 倍,说明有调度噪声。
/* gcc -o rt_record rt_record.c -lpthread */ #include <stdio.h> #include <time.h> #define EXPECTED_NS 1000000LL /* 1ms */ int main(void) { struct timespec now, prev; clock_gettime(CLOCK_MONOTONIC, &prev); while (1) { clock_gettime(CLOCK_MONOTONIC, &now); long long diff = (now.tv_sec - prev.tv_sec) * 1000000000LL + (now.tv_nsec - prev.tv_nsec); if (diff > EXPECTED_NS * 3 / 2) printf("overrun: %lld ns\n", diff); prev = now; } return 0; }这个程序本身不跑 EtherCAT 主循环,只作为系统调度质量的探针。如果你的实时线程能够稳定在 1 ms 附近,说明系统的中断响应没有明显黑洞。实际操作时,我会先用chrt -f 80 ./rt_record启动它,然后连续跑几分钟,观察 overrun 出现的频率。超过两三次,说明 CPU 核分配有问题,或者主站线程被其他任务挤掉。
配合ethercat master输出一起看更直观:
watch -n 0.5 "sudo ethercat master"注意看Frame rate和Error counters。如果帧速率稳定在 1000 Hz 附近,Error counters 不增长,说明主站周期没有丢帧;一旦 error 持续增加,多半是网卡中断被其他负载干扰。调优时先关闭无关服务,再用taskset固定主站线程的 CPU,最后再把实时线程优先级提到最高。记住一点:先让系统有时间,再谈 EtherCAT。
这个脚本的价值不在于记录数据,而在于让你在调增益之前就判断出主站是否处于健康状态。我最早调试第一套主站时,忘了绑定网卡,原驱动还在抢中断,周期 overrun 刷屏,折腾了一个通宵,最后才发现是顺序问题。后来养成了习惯,每次编译完先看lspci -k确认驱动归属,再决定加载哪个ec_xxx。希望这些记录能帮你少占几个凌晨的工位。希望帮到你。
本文还有配套的精品资源,点击获取