ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

Ubuntu 20.04下IgH EtherCAT主站部署实战:从网卡选型到性能调优

Ubuntu 20.04下IgH EtherCAT主站部署实战:从网卡选型到性能调优 Ubuntu 20.04下IgH EtherCAT主站部署实战工控圈混久了你会发现EtherCAT基本成了多轴运动控制和分布式IO的事实标准。而IgHEtherLab开源的EtherCAT主站则是最常见的一套开源方案。这篇文章把我最近在Ubuntu 20.04 LTS上从零部署IgH主站的完整过程、踩过的坑和调优经验写出来给正在搞这套东西的朋友一个参考。先说结论Ubuntu 20.04配合IgH 1.5.2版本只要内核选对、网卡选对、配置不偷懒跑起来之后稳定性和实时性都能达到工业现场的要求。我这次部署的目标是带6个伺服从站和1个数字量IO从站经过一周的连续运行测试总线抖动控制在微秒级完全满足项目需求。如果你正打算在X86工控机或RK3568这类ARM板卡上搭建EtherCAT主站或者手头有CODESYS方案想对比一下开源的IgH路线这篇文章都能给你省下不少折腾时间。1. 先搞清楚EtherCAT主站和IgH的定位1.1 EtherCAT协议在工业总线里的位置EtherCAT全称是Ethernet for Control Automation Technology由倍福Beckhoff在2003年推出。它的核心设计思想很聪明传统以太网帧是发一个帧到设备设备解析再回应而EtherCAT采用飞读飞写方式主站发送一个帧经过所有从站时每个从站在帧经过的瞬间读取发给自己的数据、插入自己的数据帧在最后一个从站返回主站。这样整个循环只需要一个以太网帧就能完成所有从站的数据交互效率非常高。这种列车车厢分发报纸的机制决定了EtherCAT特别适合周期短、同步要求高的场景。1000个IO点的刷新时间可以做到100微秒以内50个轴的同步抖动可以控制在1微秒内。所以它在伺服控制、机器人、锂电设备、半导体设备等领域用得非常多。IgHIngenieurgemeinschaft für Hard- und Software是德国一个开源组织EtherLab维护的EtherCAT主站实现基于LGPL协议开源。它包含内核态的主站模块ec_master和应用层的用户空间库提供了完整的EtherCAT状态机管理、PDO映射、SDO通信、DC时钟同步等功能本身不依赖特定硬件平台x86、ARM都能跑只需要一个千兆网口。1.2 为什么我选了IgH而不是SOEM很多人在选型的时候会在IgH和SOEM之间纠结我也一样。SOEMSimple Open EtherCAT Master是另一个非常流行的开源主站由RT-Labs维护代码量小、移植方便很多国产EtherCAT主站方案都是基于SOEM或者SOEM的微变种做的。但IgH相对SOEM有几个明显优势。第一是内核态实时性IgH实现了完整的内核态驱动可以直接和PREEMPT_RT实时内核配合中断延迟和调度抖动更可控而SOEM一般是用户态轮询实时性上限取决于线程调度精度。第二是协议栈完整度IgH对DC分布时钟同步、冗余链路、EoEEtherCAT over Ethernet、FoEFile over EtherCAT的支持都比较完整文档也更详细。第三是生态成熟度IgH从2007年就开始迭代在欧美的设备制造商中应用非常广你遇到的大部分问题谷歌都能搜到。当然SOEM也有它的优势比如代码简洁、虚拟从站测试方便、跨平台更容易。如果只是做个原型验证、跑个PC端演示SOEM完全够用但如果是要上设备、长时间运行、对同步要求高的场景我建议直接上IgH。2. 编译部署前先把准备工作做扎实2.1 硬件选型网卡和处理器是决定成败的两个件IgH官方支持列表里最稳妥的网卡是Intel的8254x/8257x系列比如82574L、I210、I350以及部分Realtek 8169。实际项目里我强烈建议用Intel I210或I350这几个型号在IgH驱动里是原生支持不用改驱动代码而且中断行为稳定对实时调度更友好。我踩过的最深的坑就是一开始拿板载Realtek RTL8168跑IgH。刚开始也能扫描到从站但周期一短低于1ms就开始出现丢帧、WDT超时后来排查发现是因为Realtek网卡的驱动中断处理和DMA缓冲方式在高速小包场景下表现很差而且IgH的ec_e1000e驱动和ec_r8169驱动的稳定性差距确实大。所以如果你有条件千万别用螃蟹卡跑IgH这不是玄学是Intel网卡的硬件设计对DMA缓冲、中断合并的控制更精细能适应EtherCAT这种高频率小帧的极短交互周期。处理器方面x86的工控机Intel赛扬J1900级别以上跑IgH都足够因为主站本身的计算量不大瓶颈都在网卡和内核调度上。如果要在RK3568这类ARM板卡上跑也完全可行但要注意把实时补丁内核编译对另外ARM平台的网卡驱动适配和中断延迟会比x86更敏感建议优先选择带PCIe千兆网口的板子。2.2 内核与实时性方案PREEMPT_RT还是普通内核IgH主站要求内核支持CONFIG_PREEMPT但要想达到工业控制级别的确定性建议使用PREEMPT_RT实时内核。Ubuntu 20.04自带的5.4内核默认有CONFIG_PREEMPT选项如果只是功能验证、周期要求在1ms以上普通内核也能跑起来。我的做法是直接编译一个带了RT补丁的5.4.*内核。具体步骤不展开细说关键是从kernel.org下载对应的内核源码和rt补丁保持版本一致用patch -p1 patch-xxx打补丁然后在make menuconfig里开启CONFIG_PREEMPT_RTy选Voluntary Kernel Preemption下面的Fully Preemptible KernelCONFIG_HZ_1000y内核时钟频率设1000Hz把频率相关的CPU调频设置为performance或者在内核启动参数加intel_pstatedisable注意不要图省事用Ubuntu自带的linux-image-rt我试过几次它的配置和IgH模块在某些组合下会出现奇怪的时序问题还不如自己手动编译虽然耗时但出来的内核和IgH的配合是最可靠的。编译RT内核时记得把网卡驱动编成模块不要编进内核因为IgH要接管网卡如果网卡驱动已经绑定到了网络子系统IgH加载的时候会报设备忙。这个细节很多教程没提但真影响部署成功。2.3 安装编译依赖与源码获取Ubuntu 20.04的依赖包很简单主要是编译工具链和内核头文件sudo apt update sudo apt install build-essential linux-headers-$(uname -r) autoconf automake libtool pkg-configIgH源码可以从官方仓库拿git clone https://gitlab.com/etherlab.org/ethercat.git cd ethercat git checkout stable-1.5注意要切到stable-1.5分支master分支有时候处于开发状态编译或者运行时可能存在问题。我实际用的版本是1.5.2这是目前最稳定的发布版。下载后用中有个ethercat的顶层目录执行后续的编译流程。3. IgH主站的编译、安装与网卡绑定3.1 源码编译的两种模式内核态还是用户态IgH编译有两种方式内核态模式和用户态模式RTDM/RTAI。普通X86平台我们直接用默认的内核态模式。用户态模式需要事先装好Xenomai或RTAI实时扩展通常是配合实时性要求更高的场景但调试难度大一圈。编译命令很简单./bootstrap ./configure --prefix/opt/etherlab --enable-generic --disable-eoe make sudo make install这里两个参数很关键。--enable-generic是让IgH使用generic网卡驱动这种方式可以绑定任意网卡但性能通常比不上原生驱动。实际上对于支持的Intel网卡IgH会自动检测并使用ec_e1000e、ec_igb等原生驱动不用额外配置。--disable-eoe是禁用EoE这个后面单独说明。编译完成后主站模块需要在/etc/ethercat.conf里配置网卡和设备信息MASTER0_DEVICE00:1b:21:00:xx:xx # 改成你的网卡MAC地址 MASTER0_POSITION0 # 网卡在系统中的位置配置文件里还可以设置DEVICE_EOE0来禁用EoE设置DEBUG_LEVEL控制日志级别。配置好后加载模块sudo modprobe ec_master sudo /opt/etherlab/sbin/ethercatctl start这时候用dmesg | tail可以看到主站识别到了哪几个从站用ethercat slaves可以列出从站列表。提示ethercatctl start如果报错找不到网卡99%的情况是MASTER0_DEVICE配错了MAC地址或者网卡已经被NetworkManager接管。后者可以临时用ip link set eth0 down把网卡down下来再试但更好的方案是在配置里彻底把这张网卡的NetworkManager管理关掉防止系统启动时自动把它拉起来。3.2 给网卡降温释放网络子系统对网卡的占用IgH主站加载后要独占这张网卡所以不能让Linux的网络协议栈继续管理它。否则会出现两类问题一是eth0等网卡接口自动up后IgH没法绑定二是网络协议栈的中断和IgH的实时中断互相干扰。我常用的做法是在/etc/network/interfaces里把这张网卡设置为手动manual模式auto eth0 iface eth0 inet manual如果系统用的是NetworkManager还需要sudo nmcli device set eth0 managed no然后在启动IgH之前手动确认网卡是down状态sudo ip link set eth0 down sudo /opt/etherlab/sbin/ethercatctl start这一步虽然简单但很多人忽略之后会遇到各种绑不上的问题。IgH绑定网卡后你用ip link看这张网卡是no-carrier状态这是正常的不要慌。3.3 开机自启动和权限设置生产设备肯定不能每次开机手动敲命令。Ubuntu 20.04我用systemd服务管理IgH。先创建服务文件/etc/systemd/system/ethercat.service[Unit] DescriptionEtherCAT Master Afternetwork.target [Service] Typeoneshot RemainAfterExityes ExecStart/opt/etherlab/sbin/ethercatctl start ExecStop/opt/etherlab/sbin/ethercatctl stop Userroot [Install] WantedBymulti-user.target然后启用sudo systemctl enable ethercat.service sudo systemctl start ethercat.service另外要注意ethercat命令行工具在编译安装后默认在/opt/etherlab/bin下如果不想每次都写全路径可以加一个软链或者把它加入PATH。同时给普通用户sudo权限即可不需要额外调整。4. 配置细节和关键参数EOE为什么必须禁PDO怎么映射4.1 配置文件里那些经常被忽略的参数IgH的配置文件除了网卡MAC还有几个建议重点关注。MASTER0_POSITION多个网卡时指定用哪一张一般填0。DEVICE_EOE禁用EoE的开关建议设为0。DEBUG_LEVEL调试日志级别正式运行可以设为0排查问题时设为1-4。MAX_DEVICES和MAX_SLAVES默认值够用不需要改。TIMECONV和DC相关选项如果要用分布时钟同步编译时需要启用DC支持IG配置默认是启用的。有一件事我提醒过很多新手改了配置之后要重新编译IgH吗答案是配置文件改完了ethercatctl restart即可但如果你是在./configure时通过参数调整了编译选项比如启用或禁用某个特性那必须重新执行make sudo make install。两条路径不要搞混否则改半天不生效还以为是bug。4.2 聊聊IgH为什么要禁用EoEEoEEtherCAT over EtherCAT是一个把传统的IP数据包封装在EtherCAT帧里进行传输的特性。启用EoE后你可以通过EtherCAT总线直接和设备通信比如直接ping从站设备。听起来很方便对吧但实际工程里我建议把它禁掉。原因有三个。一是实时性损耗EoE的数据包需要主站拆包重组插入EtherCAT周期帧这个过程会打乱主站严格的时间片分配对DC同步的稳定性影响很明显。IgH官方文档也明确建议在实时应用中禁用EoE。二是排查复杂度上升开了EoE一旦总线出现异常你要同时排查实时链路和IP链路问题定位难度翻倍。三是大多数项目中用不上EtherCAT从站的配置、参数读写走CoE/SoECANopen over EtherCAT / Sercos over EtherCAT指令就行了压根不需要IP层协议。所以如果只是一个纯运动控制、IO采集场景直接在编译或者配置阶段把EoE关掉。省心也稳定。4.3 PDO映射让从站数据按你需要的格式流动从站能扫描出来不代表你的应用程序能拿到数据。要让数据在你的控制程序和从站之间流动核心是配置PDOProcess Data Object映射。以常见的伺服从站为例如果你用ethercat cstruct生成从站信息结构体它会根据从站的ESI文件EtherCAT Slave Information自动生成PDO结构体定义。我在实际项目里习惯用IgH提供的ethercat命令行来进行即时映射操作比如查看某从站当前PDOethercat pdos -p 0如果默认PDO不满足需求可以先用ethercat sdo访问对象字典或者用ethercat xml生成基于从站描述文件的映射。应用层里最核心的是这个流程主站启动后各从站进入PRE_OP状态然后调用ecrt_master_activate把PDO数据准备好主站开始周期发送数据帧应用代码里拿到ecrt_slave_config_pdo_assign配置PDO分配和ecrt_slave_config_pdo_entry配置PDO条目之后每个周期调用ecrt_master_receive和ecrt_master_send完成数据收发。值得注意的是PDO映射改了之后必须重启主站并重新激活从站。而且从站数量或者类型变了PDO映射也要重新核对。我最开始干这行的时候就吃了这个亏换了从站之后没重新做映射程序跑起来从站能扫描到但应用层读出来全是0。5. 常见问题排查与避坑实录5.1 Igh进入OP后读不到数据到底怎么回事这是最常被问的问题也是热词榜上高频出现的igh进入op读不到数据。我碰到过的情况大致有这几类按排查优先级列一下第一从站没有完成状态切换。进入OP需要经过INIT - PRE_OP - SAFE_OP - OP的过程。每一步都有检查机制比如PRE_OP要求在从站能正常通信SAFE_OP要求PDO映射有效OP要求DC同步就绪。如果你的应用代码里只是调用了ecrt_master_activate但没有等待从站状态机切换完成数据帧可能还在发但从站没有进入OP应用层读到的是初始值或者零值。这种情况用ethercat slaves看看每个从站的状态再用ethercat states手动触发状态切换基本能定位。第二PDO映射和从站实际配置不匹配。比如你按默认PDO映射去读寄存器位置但实际从站被配置成了另一种PDO模式那读回来的数据位置就是错的。建议做一个自检函数把从站的PDO列表打印出来和你的结构体定义一 一比对。第三硬件层面的物理链路问题。EtherCAT对物理层的要求就是链式连接从站端口顺序接错或者线缆太长都可能导致数据帧经过某个从站时被丢弃或返回超时。检查一下从站的Link指示灯如果最后一个从站亮但中间有个灯异常就用ethercat slaves -p看看哪个编号缺失。第四网卡中断和CPU绑定问题。如果从站不多但数据还是偶尔读不到看一下CPU中断分布。IgH中断处理最好绑定到一个独立核心不要和其他密集中断混在一起。在启动参数里加irqaffinity或者用taskset绑定中断能有效减少丢帧。5.2 主站无法进入OP从站地址分配和WDT还有一种特别容易掉进去的坑主站进入了OP但某个从站报WDT看门狗超时。这是在从站正常刷新周期内没有收到新的数据帧导致的。WDT超时的常见根源是主站发送帧的周期和从站配置的看门狗时间不匹配。EtherCAT从站都有同步管理器看门狗如果你的主站周期是1ms但从站看门狗设成了0.5ms那必然超时。IgH的配置里可以通过设置从站配置参数watchdog_divider和watchdog_intervals来调整看门狗倍数但更稳妥的做法是在从站侧通过SDO把看门狗时间改到主站周期的2-3倍。此外如果从站数量多一帧里塞的数据量大到超过了一个以太网帧的最大长度1500字节也会导致帧拆分、周期变长进而触发WDT。这种时候优先考虑调整PDO映射把不必要的数据剔除而不是强行拉高看门狗时间。5.3 瑞芯微RK3568等ARM平台部署IgH需要注意什么不少硬件方案选了正点原子RK3568这类ARM核心板来跑EtherCAT主站。RK3568本身性能不错但部署IgH有下面几个点要注意网卡适配很多人直接在核心板的原生千兆网口上跑IgH。RK3568的GMAC是板载设计IgH的generic驱动能识别但性能和Intel独立PCIe网卡没法比周期建议放到1ms以上。如果要求更高建议通过PCIe扩展一张Intel I210网卡。实时补丁RK3568的官方内核不一定带PREEMPT_RT补丁需要自己从Rockchip的SDK里把内核源码拿下来打RT补丁重新编译。注意RK3568的SDK内核版本通常和kernel.org不完全同步打补丁时可能需要手动解决一些冲突。从站数量限制ARM平台的DMA缓冲、内存带宽都有限从站数量超过8个之后建议实测一下总线周期是否稳定不要按x86的标准来预估。5.4 和CODESYS、正点原子方案怎么对比很多人在选主站方案时会拿CODESYS Control RTE SL软PLC运行时来和IgH对比。CODESYS对EtherCAT主站的支持确实是开箱即用装好运行时在设备树里添加EtherCAT主站CODESYS会自动扫描从站、生成PDO映射底层不用写任何代码。这对做上位机逻辑的人来说特别省事也是CODESYS生态强大的地方。但代价是CODESYS是商业授权Runtime是把控在黑盒里的出了问题你只能等厂商支持同时它的主站周期经过了几层软件调度底层实时性不如你直接控制一个IgH主站灵活。所以我的经验是如果你做的是通用设备开发用CODESYS能快速落地但如果你做的是运动控制核心算法、要深度定制同步行为、或者要嵌入到自己的C/C框架里IgH是更可控的选择。正点原子有提供EtherCAT主站例程但一般也是基于SOEM做演示侧重教学而非工业级部署。真要跑产线建议还是走上文说的IgHRT内核这条路。6. 实操心得与性能调优6.1 CPU隔离与中断绑定把实时性榨出来我的台式工控机是四核CPU部署IgH时做了这么几步优化首先要让RT任务和网络中断固定在独立CPU核上。比如把IgH的中断绑定到CPU2应用层实时线程绑定到CPU3CPU0和CPU1留给系统调度。具体做法找到IgH网卡的中断号cat /proc/interrupts用echo 4 /proc/irq/xxx/smp_affinity二进制掩码应用线程用pthread_attr_setaffinity_np绑定CPU核心。然后要避免CPU调频造成时钟漂移。在BIOS里把CPU频率固定到最大值或者在启动参数里加intel_pstatedisable防止处理器在空闲时降频导致周期执行时间膨胀。如果你用的内核带了PREEMPT_RT补丁还有一点很关键把非实时的中断尽量和IgH中断分开。比如显卡、USB控制器的中断不要落在IgH中断所在的CPU核心上。否则一旦外设触发大量中断IgH的实时性会受影响。我实测过把IgH中断单独隔离后总线抖动从十几微秒降到2微秒以内。6.2 用ethercat命令行工具快速定位现场问题IgH自带一套ethercat命令行工具干现场调试时候特别好用建议每个字段含义都熟悉一下ethercat slaves查看所有从站显示本站地址、厂商、产品号、状态。ethercat states -p 0 -s OP强制把0号从站切换到OP状态。ethercat pdos -p 0查看0号从站当前的PDO分配。ethercat sdos -p 0列出0号从站所有SDO对象。ethercat sdo -p 0 -i 0x6060 -o 0x00读对象字典比如电机运行模式。ethercat debug -l 4开启调试日志用于查看主站内部通信过程。用得多了你会发现ethercat命令行工具本身就是排查EtherCAT问题最强大的入口。很多看不见的故障比如从站线上通讯错误率飙升、某从站周期性掉线用ethercat slave --verbose看计数器都能找到线索。6.3 稳定性和长期运行建议从实验室走向产线在实验室跑通了不代表产线能稳定运行。根据我自己的经历从能用到好用还有几个关键步骤做链路质量监控在应用层周期性读从站的错误计数器0x0400等对象连续超过阈值就报警防患于未然。配置DC同步如果从站支持分布式时钟DC务必要启用。DC能让所有从站采集命令同步执行对多轴运动控制是刚需。IgH里配置DC需要为每个从站手动设置DC激活参数建议参考IgH示例代码里的rt_servo例子这个例子写得很清楚。日志不要长期开着生产环境建议把DEBUG_LEVEL设为0dmesg级别的日志在频繁通信时会产生大量IO开销影响实时性。供电和接地要重视EtherCAT现场出问题有很大概率是地电位差、电源纹波造成的通信不稳定。排查问题时第一件事往往不是看配置而是拿示波器看PE和从站电源的噪声。这虽然是硬件话题但它比任何软件配置都更影响IgH的稳定性。6.4 其他想到的经验最后分享两个个人认为比较重要的实操经验。第一个别忽略ESI文件。IgH启动时会根据从站的ESI文件来配置从站。如果你手上拿到的是国产从站ESI文件版本很乱建议用官方从站配置工具重导一遍ESI再到IgH里跑能省很多兼容性排查时间。第二个尽量用IgH提供的接口做事不要自己直接操作内核对象。IgH的用户空间库libethercat和内核接口封装得还算清晰配合RT内核跑起来没有问题。我看到有些人为了图快直接在用户态用mmap方式操作主站内存短期能跑长期维护性极差而且一升级IgH版本就废。老老实实用官方API之后升级、排查都方便。Ubuntu 20.04下部署IgH这条链路核心就四个字配置克制。网卡选Intel内核上RTEoE关掉PDO映射理清然后让一切在确定性的调度里运行。按这个思路走下来大概率能避开我当年踩过的那些坑。
RELATED READING

延伸阅读

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