ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

树莓派上编译IgH EtherCAT主站:4.x内核下的完整踩坑记录

树莓派上编译IgH EtherCAT主站:4.x内核下的完整踩坑记录

如果你手头有一块树莓派,又恰好想玩EtherCAT总线,那这套组合里最绕不开的就是IgH EtherCAT master主站。我在做一个运动控制原型验证时,需要在没有工业PC的情况下快速搭出一个EtherCAT主站,树莓派加一块网卡是最省钱的路子,但真正折腾下来才发现:装主站本身不难,难的是让它在4.x内核下顺利编译、加载、跑起来,而且每一步的报错还都不是同一个原因。

这篇文章不是抄文档式的教程,是我自己在树莓派上把IgH EtherCAT master从源码编译到实际驱动从站设备的完整记录。适合谁看?手头只有树莓派、想验证EtherCAT从站设备的工程师,或者想给小型机器人控制器做原型demo的爱好者。我会按环境准备、编译安装、验证方法、常见坑的顺序走一遍,尽量把那些让人卡一晚上也不一定想明白的细节讲透。

1. 为什么要碰这套组合:树莓派与EtherCAT主站的适配逻辑

1.1 树莓派在工业控制原型里的真实定位

很多人一听树莓派跑EtherCAT主站就觉得不靠谱,其实这是对协议栈的误解。EtherCAT主站不需要专用的从站芯片,它本质上是通过标准以太网硬件发送实时以太网帧,主站侧跑的是一套软件协议栈,从站侧才需要专用ESC芯片来处理数据。所以树莓派板载的百兆网口、外扩的USB网卡,甚至4B上的千兆口,从硬件能力上说都不存在"不能用"的问题。

但定位要摆正。正式产线上一般用带实时扩展的工业电脑加上专用网卡驱动,追求的是微秒甚至亚微秒的抖动控制。树莓派这套组合更适合做三件事:一是从站设备的离线读写测试,比如在没有现场PLC环境时先验证通信逻辑;二是小型机器人控制器的原型预研,先把运动控制算法跑通再说硬实时;三是给学生或者刚入行的工程师熟悉EtherCAT协议本身。把预期设对,后面就不会被性能问题劝退。

1.2 IgH主站与4.x内核之间到底存在什么问题

IgH EtherCAT master是开源社区里使用最广的EtherCAT主站协议栈实现,分内核模块和用户空间工具两部分。它的编译方式和普通应用程序完全不同:内核模块部分会直接和当前内核源码树绑定,生成专属于某个内核版本的ec_master.ko,所以运行的是什么内核,就必须用完全对应的内核源码去编主站。

4.x内核在树莓派官方支持里是个漫长的过渡期,从4.14一路维护到4.19。IgH主站本身的发展速度跟不上内核API变动的频率,所以针对4.x内核,通常需要选特定版本的IgH源码,版本选对了就是一路顺畅,选错了轻则编译报错,重则模块加载直接崩溃。这点我在后面会单独用一节讲清楚,因为这是整个安装过程中最矛盾的点:内核是树莓派官方在维护的,而IgH主站不是。

1.3 亲手跑出来的性能感受

我在树莓派上做了完整的周期测试:1ms周期是稳的,状态机切换和周期数据交换没有出现异常;试着压到500us周期,抖动明显上升,还能勉强维持;再往下就不建议了,丢帧和EtherCAT从站的看门狗超时开始出现。

原因也不复杂:板载网卡的中断处理、Linux内核本身的调度延迟、USB总线如果有别的设备抢带宽,都会直接反映在周期抖动上。如果你的目标是高精度多轴同步,那就得认真考虑独立千兆网卡加实时补丁内核的路线。但如果只是做从站读写验证和逻辑原型,这套组合完全够用。

2. 开工前的三个前置项:内核源码、网卡与依赖环境

2.1 内核源码版本必须与运行内核严格一致

这条是整个安装链路上最容易翻车、也最重要的点。IgH主站的configure脚本会读取内核源码目录里的版本信息和配置头文件,如果源码版本和uname -r显示的内核版本对不上,最终编译出来的模块在加载时会因为内核符号不一致而失败。

具体操作很直接。先看当前运行的版本:

uname -r uname -a

比如我用的官方系统镜像显示的是4.19.75-v7l+,那我就必须拿到rpi-4.19.y这个分支的内核源码。拉取树莓派官方维护的内核源码时不需要完整历史,剪个浅克隆就可以,否则源代码体积太大,在树莓派本机上拉包会等很久。

git clone --depth=1 --branch rpi-4.19.y <树莓派官方内核源码仓库地址> linux

之后进入内核源码目录,做编译前的准备工作:

cd linux make modules_prepare make scripts

这两步会生成编译外部内核模块所需的头文件和脚本工具,IgH的configure脚本要靠它们来判断内核版本和配置。如果跳过这一步,后面configure十有八九会报找不到autoconf.h或者内核版本识别失败。

2.2 网卡选型直接决定主站能不能通

IgH主站对网卡的接管有两种策略。一种是为特定芯片写的专用驱动,比如8139too、e1000e这类;另一种是通用驱动,它忽略具体芯片型号,通过内核以太网接口层直接接管你指定的网卡。

树莓派板载网卡通常是smsc95xx这类USB总线网卡,不建议再用USB去挂一块外接网卡跑EtherCAT,因为USB总线调度延迟本身就不稳定,会让本来就有限的实时性雪上加霜。实测下来,树莓派板载接口在1ms周期下表现可以接受,我的首个实验就是在板载百兆口上跑通的。

如果你对性能要求更高,可以考虑在支持PCIe的树莓派型号上外扩一张Intel I210系列千兆网卡,这种卡的专用驱动对IgH主站的兼容性比较成熟,抖动也能降一个档次。选卡思路就一句话:尽量走原生PCIe,不要叠USB。

2.3 编译依赖一次性装齐

在树莓派上编译IgH主站需要的依赖不算多,但最好在开装前一次性装齐,免得中途停下来补包:

sudo apt update sudo apt install build-essential automake autoconf libtool pkg-config

另外要确保内核头文件已经可用。如果你前面已经完成了make modules_prepare,头文件环境就是就绪的,不需要再单独安装linux-headers包,因为用发行版的headers包反而容易出现和源码树不一致的情况。

2.4 RTDM选项:不要盲目追求实时扩展

IgH主站支持两种用户空间接口:一种是原生字符设备接口,另一种是RTDM,后者需要Xenomai这类实时扩展配合,要求你在树莓派上重新编译并启动一个带实时补丁的内核。这个工程量比较大,对于原型验证阶段来说收益并不明显。

我在实验环境中并没有启用RTDM。原因很现实:跑通EtherCAT从站读写和状态机切换用普通的字符设备接口就够了,等真正需要硬实时调度的时候,再投入时间做Xenomai和独立网卡的组合也不迟。所以下面所有编译操作,我都会加上--without-rtdm这个参数。

3. 从源码到内核模块:IgH主站的编译安装全流程

3.1 获取源码与确认版本

从IgH项目的官方发布页面下载稳定版本源码包,注意选择适配范围包含4.x内核的版本。我自己用的是1.5.2这条分支,兼容性相对稳妥,社区里的资料也最多。

wget <IgH项目官方下载地址>/ethercat-1.5.2.tar.bz2 tar xjf ethercat-1.5.2.tar.bz2 cd ethercat-1.5.2

在这里多说一句,很多人会顺手在网上下一个别人编译好的成品模块,我强烈不建议。因为EtherCAT主站模块必须和你当前运行内核版本精确匹配,别人编译好的东西放到你的板子上十有八九版本魔法对不上,最后还是要走回源码编译这条路。

3.2 configure参数详解

进入源码目录后,执行:

./configure --prefix=/usr/local \ --enable-generic=yes \ --enable-8139too=no \ --without-rtdm

这几个参数不是随便填的,解释一下用意:

  • --prefix=/usr/local:指定安装路径,工具和库会放到/usr/local/sbin和/usr/local/lib下,避免和系统自带库混在一起。
  • --enable-generic=yes:启用通用网卡驱动,这是树莓派板载网卡能工作的关键选项。
  • --enable-8139too=no:树莓派板子上没有8139芯片,关掉这个驱动可以少编译一堆代码,也能规避一些编译器的告警被当作错误的场景。
  • --without-rtdm:明确不依赖Xenomai实时扩展,使用普通字符设备接口。

configure输出末尾会打印出它识别到的内核版本、启用的网卡驱动列表、是否启用RTDM。看到识别出的版本是4.19.x并且没有RTDM字样时,说明它认到我们准备的内核源码树了,可以继续往下走。

3.3 编译安装与模块部署

接下来就是常规的两步:

make -j4 sudo make install

make install会做三件事:把ethercat命令行工具下载到/usr/local/sbin;把用户空间接口库放到/usr/local/lib;把编译出来的ec_master.ko等内核模块复制到/lib/modules/$(uname -r)/kernel/drivers/ethercat/。

复制完模块之后,需要更新内核模块依赖信息:

sudo depmod -a

这一步经常被忽略,如果跳过,后面modprobe ec_master就会提示找不到模块。注意depmod -a一定要在当前运行的uname -r对应的模块目录下执行,确认无问题后再做下一步。

3.4 加载主站并确认内核态状态

第一次加载就指定主站要接管的网卡:

sudo modprobe ec_master main_devices=eth0

如果modprobe失败,可以用insmod直接指定ko文件路径:

sudo insmod /usr/local/modules/ec_master.ko main_devices=eth0

加载完立刻看内核日志:

dmesg | tail -20

正常情况下会看到主站注册成功,提示类似EtherCAT master 0 registered的信息。到这一步,内核态的主站就算跑起来了,接下来才是真正的验证环节。

这里顺便说一下为什么我没有用交叉编译:在树莓派本机上编译虽然慢一点,但能最大程度避免内核配置和头文件不一致的问题。交叉编译还必须先把树莓派的内核配置完整复制下来,再配置工具链,步骤更多,一旦配置漂移,错误非常难排查。在原型验证阶段,本机编译是性价比最高的方案。

4. 验证链路:从内核节点到ethercat命令

4.1 确认设备节点和访问权限

主站加载成功后,系统会自动生成字符设备节点/dev/EtherCAT0:

ls -l /dev/EtherCAT0

如果节点没有自动出现,可以手动创建:

sudo mknod --mode=666 /dev/EtherCAT0 c 254 0

这里的254是主设备号,IgH主站默认就是这个值。权限要特别注意,很多用户第一次跑ethercat命令时就卡在Permission denied,其实只是权限没放好。可以把当前用户加入dialout组,也可以直接临时用sudo跑命令,原型验证阶段我都是直接sudo,节省时间。

4.2 主站与从站信息的读取

IgH主站提供了几个高频命令,安装完成后就能直接使用:

sudo ethercat master sudo ethercat slaves sudo ethercat states

ethercat master会显示主版本、运行周期、总线上实际连接的从站数量;ethercat slaves列出每个从站的厂商ID、产品码、站地址和状态;ethercat states输出从站的状态机,这在调试过程中非常关键。

有一个小细节:如果提示找不到ethercat命令,说明/usr/local/sbin没有加进PATH。执行export PATH=$PATH:/usr/local/sbin或者直接调用绝对路径就行。

4.3 一个真实的从站状态切换实验

我把一个模拟EtherCAT从站设备接入总线之后,先扫描了从站信息,确认站地址和产品码都能正确读到,再执行状态切换:

sudo ethercat states -s OP

这条命令会把所有已配置的从站切换到OP状态。正常情况下,从站进入OP后,状态机会按主站的周期同步运行。如果从站没有进入OP,最直接的排查方式是看dmesg输出,通常会提示某个从站请求的状态转换失败。

我在这个环节里遇到过一次卡在PREOP切不进OP的情况,最后定位是分布式时钟没有配置到位。把主站周期参数和从站的DC配置对齐之后,状态切换就正常了。

4.4 常见报错速查表

症状可能原因处理思路
insmod加载模块时version magic报错内核源码版本与运行内核不一致重新拉对应分支内核源码并编译模块
modprobe提示找不到模块depmod未更新或模块目录不对确认模块在正确版本目录后执行depmod -a
主站注册成功但网卡错误main_devices参数指定错误检查ip a里的实际网卡名
从站扫描不到设备网线或从站电源问题先确认从站是否上电,再接网线
从站切不到OP状态DC配置或周期配置不匹配查看dmesg中的EtherCAT相关报错

5. 4.x内核下的高频坑:在不换系统的情况下怎么绕

5.1 版本魔法错误的真相与解决

这类错误应该是4.x内核下遇到最多的一个问题。加载ec_master.ko时,内核会检查模块的vermagic信息,例如:

version magic '4.19.75-v7l+' should be '4.19.75-v7'

说明模块是用v7配置编译的,但运行内核是v7l配置。这两种配置对同一份源码来说会生成不同的vermagic,导致模块拒绝加载。

解决思路有两个方向。一是确认你拉取的内核分支和你实际运行的镜像架构一致,树莓派官方镜像的v7和v7l区别在于是否启用LPAE,镜像版本对应好之后再重新编译模块。二是如果实在懒得重新拉源码,可以修改内核源码中的modpost配置关掉严格校验,但这一步有风险,不推荐在正式项目里用。

5.2 模块目录和depmod的连带问题

还有一次我卡在modprobe ec_master找不到模块上,反复检查源码也没有问题,最后发现make install把ko文件复制到了一个和uname -r不完全一致的目录下。

这种问题藏在细节里:树莓派官方内核在升级之后,/lib/modules下可能残留多个版本目录。你编译模块对应的是4.19.75,但系统里可能还有4.19.66的旧目录。查找方式很简单:

ls /lib/modules/ find /lib/modules/$(uname -r) -name "ec_master.ko"

确认文件在正确版本目录后,再执行一次sudo depmod -a,问题基本就解决了。

5.3 configure阶段提示找不到内核源码

有几次configure在检测内核头文件时直接报错,报错信息指向缺少generated/autoconf.h。这个文件必须由make modules_prepare生成,如果直接拿一份干净的内核源码树给IgH用,十有八九会触发这个错误。

这时候不要急着改configure脚本,回到内核源码目录重新执行:

make modules_prepare make scripts

如果还是不行,就先执行一次make defconfig生成基础配置,再重复上面的命令。

5.4 板载网卡被主站接管后的网络冲突

这是一个非常容易被误解成主站故障的现象。EtherCAT主站加载时会把指定的网卡从普通网络协议栈里摘出来,切换成主站专用模式。如果树莓派原本就是靠eth0上网的,插上网线的一瞬间SSH断开,很多人第一反应是"主站把系统搞挂了",但其实这恰恰说明主站正常接管了网卡。

我踩过这个坑之后养成了一个习惯:在任何EtherCAT实验开始前,先断开eth0的DHCP服务或者干脆不依赖有线网络上网。需要远程操作时,用树莓派的Wi-Fi连接外部网络,把eth0纯粹留给EtherCAT总线,既保证通信稳定,也避免SSH中途断开带来的恐慌。

5.5 周期参数设置的隐性门槛

在上电验证完状态机之后,还有一个坑容易在4.x内核下出现:主站默认周期可能和从站期望周期不一致,导致从站虽然进入了OP,但实际运行一段时间后触发看门狗超时,总线自动回到SAFEOP。

排查这类问题要看dmesg有没有Watchdog相关日志,如果有,就去设置主站运行周期:

sudo ethercat master -t 1000000

这里的单位是纳秒,1000000就是1ms。设置完之后重新切换到OP状态,只要周期和从站配置匹配,系统就能稳定运行。

我在实际项目中的体会是,树莓派上的IgH主站安装本质上是一条主线加三条支线:主线是"内核源码必须匹配",支线是"网卡别乱选"、"依赖别漏装"、"状态机切换时看日志"。只要把这四条理顺,整个安装过程就是水到渠成的事,并不会比在一台x86工控机上安装复杂太多。最后再分享一个小技巧,源码编译完成后,最好把configure时识别到的内核版本信息记到笔记里,下次升级内核后照着对比,能省去一大半的排查时间。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进