这篇其实是我自己调完整个方案以后一直想补上的环节。前面那篇把IGH主站编出来、在普通内核上把EtherCAT从站扫到,看起来一切正常,但一跑周期任务就露馅,寄存器读写丢周期,伺服使能以后时不时给你跳一个同步错误。查了一圈,问题不在IGH本身,而是内核的实时性根本没达标。所以这篇就把Ubuntu 22.04上从打PREEMPT_RT补丁、编译实时内核,到用cyclictest量化性能、再做一轮系统调优的过程完整记录下来,顺便把和ROS2 Humble的联动验证也放进来,给后面要搞ROS2+IGH方案的人省点弯路。
这套方案的核心链路是:Ubuntu 22.04 + Linux 6.6.119(6.6 LTS最新稳定版,自带igc网卡驱动,适合EtherCAT)+ PREEMPT_RT实时补丁 + IgH EtherCAT Master + ROS2 Humble。文章会按选型、编译、验证、调优、联调的顺序写,所有命令都是我在实际环境里跑过的,参数也给出调整依据,不是网上抄来的模板。
1. 为什么这套方案必须用实时内核:从EtherCAT的传输机制说起
1.1 EtherCAT对实时性的硬性要求
EtherCAT的实时性不是靠协议本身的优先级机制实现的,而是靠主站以固定周期发送数据帧。一个典型的过程数据交换周期是1ms,也就是说主站必须每1ms产生一次定时中断,然后在确定的时间窗口内完成对从站的扫描、数据帧的发送和接收处理。更极端一点,如果你做的是多轴同步运动控制,周期可能是500us甚至250us,留给操作系统的抖动预算以微秒计。
IGH主站在这条链路里的角色是:在周期开始时,从实时线程中触发ecrt_master_send(),把全部从站的输出数据打包成帧,通过网卡发送到总线上;随后由网卡硬件接收返回帧,IGH在下一个周期起点处理输入数据。这个过程中任何一个环节被操作系统调度延迟打断,都会直接表现为周期时间超出设定值,从站同步误差累加,伺服驱动器基本会立刻触发同步错误报警。
通用内核(哪怕是桌面版的CONFIG_PREEMPT_DYNAMIC)在正常情况下调度延迟可以控制在几十微秒,但它无法保证最坏情况。系统日志一刷、网卡中断一多、CPU进入深度C-state再唤醒,一次调度延迟几百微秒甚至毫秒级都是可能的。对普通应用无所谓,对EtherCAT就是灾难。
1.2 通用内核为什么带不动IGH主站
Ubuntu 22.04默认的5.15内核不是不能用IGH,而是只能跑那种"能通就行"的演示。IGH本身有几种运行模式,其中最常用的是周期模式和动态周期模式,它们依赖高精度定时器(hrtimer)或实时线程调度。CONFIG_HZ=250、CONFIG_PREEMPT_VOLUNTARY这种默认配置,会导致定时器粒度粗糙、内核抢占点不足,实时线程的唤醒精度和调度确定性完全不受控。
实测我最初的基线(5.15默认内核)跑IGH周期模式,标称1ms的周期,实际抖动±200us以上,某些时刻直接跳到2ms,从站锡箔计数器报错简直就是定时炸弹。用cyclictest测出来的max latency达到了743us,这种数值下面的任何EtherCAT控制都是自欺欺人。
只有切换到PREEMPT_RT补丁内核,把内核的抢占模式改成CONFIG_PREEMPT_RT=y、时钟改成CONFIG_HZ_1000=y、配合NO_HZ_FULL和CPU隔离,才能真正满足毫秒周期甚至亚毫秒周期下"最坏情况不超限"的要求。
1.3 实时内核的性能指标怎么定义
在开始验证之前,得先定指标,否则调优没有方向。我通常关注三个量化指标:
- 调度延迟(scheduling latency):由
cyclictest测出,关键看max latency,而不是平均。平均值再漂亮,最坏情况崩了就是废的。 - 周期时间抖动(period jitter):IGH实际周期与目标周期的偏差,通过IGH的周期统计接口或者示波器测输出引脚得到。
- 端到端延迟(end-to-end latency):从ROS2节点产生目标值,到EtherCAT从站实际执行目标值之间的时间差,这部分包含通信栈、协议处理和调度叠加的延迟。
目标值参考:对于1ms周期的EtherCAT运动控制,调度延迟max应控制在50us以内;IGH周期抖动不超过±10us;端到端延迟抖动不超过一个周期(即1000us)的10%。达到这个水平,伺服系统才能稳定工作。
2. 内核与补丁选型:6.6.119 + PREEMPT_RT的搭配逻辑
2.1 为什么选6.6 LTS而不是更激进的版本
实时内核最怕的就是"追新"。内核主线版本即使自带RT补丁队列,也仍然处在持续变化中,补丁与源码的匹配关系一旦没对齐,轻则编译报错,重则启动崩溃。6.6是目前活跃维护的LTS分支,社区维护周期长,PREEMPT_RT补丁的跟进速度快,稳定性和可用性都有保障。
更重要的一点是,6.6内核的网络驱动部分对EtherCAT用户非常友好。IGI网卡(Intel I225/I226等)的igc驱动在6.6里已经非常成熟,直接用板载2.5G网卡就能跑EtherCAT,不需要额外编译网卡驱动。IGH通过igc的普通以太网接口工作,配合合适的DMA描述符配置,就能获得很稳定的帧传输周期。
我们在方案里选的就是linux-6.6.119,这是6.6分支最新的稳定版本,PREEMPT_RT补丁也已经有对应的patch-6.6.119-rt系列。截至我验证的时候,这套组合在Ubuntu 22.04上编译、安装、运行都正常,没有出现任何启动崩溃或网卡异常。
2.2 确认IGH对内核特性的依赖
IGH本身不要求特定内核版本,但它对实时接口的选择直接影响你内核要开哪些编译选项。IGH官方代码支持三种实时接口:RTAI、Xenomai和通用的POSIX(也就是基于PREEMPT_RT的用户空间实时线程)。
我们选择的是POSIX方式,对应IGH configure时使用--enable-rtdm?不,POSIX模式也可以认为不带实时域,直接用普通的pthread的SCHED_FIFO。IGH源码里configure --enable-rt这个开关有没有,取决于版本。实际编译IGH时需要的是--with-rt-timer或类似选项,但关键在于内核必须支持SCHED_FIFO的硬实时调度,且rt-mutex可用。如果配置IRQ驱动为generic直连方式,可以用ecrt_master_call()在实时上下文直接操作总线,这要求内核禁用某些可能阻塞的因素,PREEMPT_RT恰好提供了这种确定性。
内核配置中还有几项对IGH至关重要:
CONFIG_PREEMPT_RT=y:全内核实时抢占CONFIG_HZ_1000=y:1kHz时钟中断,配合1ms周期正好CONFIG_NO_HZ_FULL=y:支持自适应tick,隔离CPU的周期时钟中断CONFIG_CPU_ISOLATION=y:支持isolcpus/NOHZ_FULL等调度隔离CONFIG_CPUSETS=y:CPU分区和绑核
这些在默认内核config里基本都不是理想状态,所以必须手动改。
2.3 下载与校验内核源码和补丁
实际操作时,我从kernel.org下载linux-6.6.119.tar.xz,从PREEMPT_RT补丁仓库下载patch-6.6.119-rt.patch.xz。注意-rt队列的补丁版本号不一定和主线完全一致,要找到对应6.6.119-rtXX的补丁,用uname -r输出对照最准确。
建议先校验SHA256,避免文件损坏导致后面编译莫名其妙挂掉。命令很简单:
curl -O https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.119.tar.xz curl -O https://cdn.kernel.org/pub/linux/kernel/projects/rt/6.6/older/patch-6.6.119-rtXX.patch.xz sha256sum linux-6.6.119.tar.xz patch-6.6.119-rtXX.patch.xz解压后打补丁:
tar -xf linux-6.6.119.tar.xz cd linux-6.6.119 xzcat ../patch-6.6.119-rtXX.patch.xz | patch -p1如果patch过程有任何hunk失败,不要跳过,直接定位失败文件,看是不是版本不对或者本地改过源码。这一步最浪费时间,却恰恰不能省。
3. 编译安装实时内核的完整过程与踩坑记录
3.1 内核配置中容易被忽略的选项
内核配置我建议从Ubuntu默认config开始改,而不是从零裁剪。cp /boot/config-$(uname -r) .config,然后make menuconfig逐个调。有几个位置特别容易踩:
第一,CONFIG_PREEMPT_RT选项一定要在General setup→Preemption Model里选Fully Preemptible Kernel (Real-Time),这个选项在menuconfig里显示为PREEMPT_RT。改完之后CONFIG_PREEMPT会自动变成PREEMPT_RT的状态,同时hrtimer相关的增强也会被自动设置上。
第二,CONFIG_HZ_1000在General setup→Timer frequency里选1000 Hz。默认Ubuntu是250Hz,这个不改,IGH的1ms周期定时精度就降了一档。
第三,CONFIG_NO_HZ_FULL在General setup→Timers subsystem→Timer tick handling里,选Full dynticks system (tickless)。这能实现CPU隔离时的无tick运行,对实时线程的确定性有直接帮助。
第四,CONFIG_CPU_ISOLATION通常在CPU/Task time and stats accounting下面,和CONFIG_NO_HZ_FULL联动的。改完后启动参数里加isolcpus=才会生效。
还有两个容易漏但同样重要的项:
CONFIG_HW_RANDOM_AMD或CONFIG_HW_RANDOM_INTEL:如果你用到随机数,无关紧要,但一些实时场景会用它做种子。CONFIG_TCP_CONG_ADVANCED等网络相关项对IGH影响不大,建议保留默认,别为了省体积乱裁剪,网络栈崩了EtherCAT也起不来。
改完全部配置后,make olddefconfig整理一遍,再用grep确认关键项都已生效。
3.2 编译参数与耗时控制
编译内核的时间取决于CPU核数。我用的机器是8核16线程,make -j16编译约30分钟。如果你是4核处理器,不要贪多,-j8即可,否则内存吃满直接OOM。
编译之前先装依赖,这个很多人会忘:
sudo apt install build-essential libncurses-dev flex bison libssl-dev libelf-dev dwarves最重要的是libssl-dev和libelf-dev,缺失会让5.15以上内核的modules编译直接报错。我之前编译5.15时没装libssl-dev,卡在certs相关的错误上半小时,后来才发现是依赖没装全。
编译命令:
make -j16 sudo make modules_install sudo make install sudo update-grubmake install会自动更新grub菜单,但如果你和我一样手动管理grub,也可以用make install完成后编辑/etc/default/grub里的GRUB_DEFAULT,指向新内核序号。
3.3 安装grub引导与启动验证
装完新内核重启前,先看一眼grub的条目:
grep menuentry /boot/grub/grub.cfg确认新内核条目存在。重启后按Shift键进入grub菜单,选择带-rt后缀的6.6.119条目。
进入系统后第一件事:
uname -a cat /proc/version如果输出里有PREEMPT_RT字样就说明实时抢占已启用。判断依据除了dasCONFIG_PREEMPT_RT之外,/sys/kernel/realtime这个目录是否存在也是标志。另外看一下/proc/cmdline,确认启动参数是否正常。
3.4 我踩过的坑:模块签名、initramfs和双内核共存
这个环节我有三个教训要重点说。
第一个坑是Secure Boot。如果BIOS里开着Secure Boot,自编译内核没有签名,启动会直接卡在Verifying shim SBAT data或直接引导失败。解决方案有两个:一是关闭Secure Boot(大多数开发机的通用做法);二是给内核做MOK签名。我图省事直接关了,开发环境没必要为这个额外花时间。如果你必须在生产环境保留Secure Boot,那就要走签名的流程,需要额外做MOK enrollment。
第二个坑是initramfs更新失败。make install之后update-initramfs可能报错,尤其当你磁盘空间不足时。我在编译完内核后发现/boot只有300MB空间,initramfs生成失败,系统虽然能启动新内核,但会进入initramfs的恢复shell而不是正常系统。解决方法是先清理旧内核:
sudo apt autoremove sudo update-initramfs -c -k all或者直接删掉不用的旧内核镜像。
第三个坑是双内核共存的模块路径。Ubuntu默认安装新内核不会删除旧内核,IGH如果之前是装在旧内核上的,切到新内核后必须重新编译IGH,否则ko模块和内核版本不匹配,modprobe ec_master直接报Invalid module format。IGH编译时用的是内核头文件路径,切换内核后头文件变了,重编是必须的。
4. 用cyclictest量化实时性:测试方法与指标解读
4.1 cyclictest怎么装、怎么跑
cyclictest是rt-tests包里的工具。Ubuntu 22.04上安装很简单:
sudo apt install rt-tests测试命令我跑的是这个组合:
sudo cyclictest -t 1 -p 99 -i 1000 -l 100000 -n -m参数含义:-t 1表示创建一个测试线程;-p 99设置SCHED_FIFO优先级99;-i 1000是循环间隔1000us(1ms);-l 100000执行10万次循环;-n使用clock_nanosleep;-m锁定当前进程内存。如果系统支持,也可以加-a指定CPU。
实际测试建议跑两种模式:
- 单线程无干扰:用来确认内核实时能力的天花板
- 多线程带负载:开几个CPU密集型线程或网络IO压力,验证最坏情况下的稳定性
我带负载的跑法是:
sudo cyclictest -t 4 -p 80 -i 1000 -d 0 -l 500000 -n -m -a 2 -q同时在另外的核上跑stress-ng --cpu 4 --io 4。结果保存下来,对比两种状态下max latency的变化。
4.2 结果怎么读:max latencies不是越小越好
cyclictest输出长这样:
T: 0 ( 1234) P:99 I:1000 C: 100000 Min: 5 Act: 9 Avg: 7 Max: 18关键在于Max列。这是本次测试的最坏调度延迟。如果你只看Avg,很可能觉得系统实时性不错,实际上Max一旦冲到几百微秒,对EtherCAT就是致命的。
我判断系统是否可用的标准:
- Max < 30us:优秀,可以尝试500us周期
- Max < 100us:合格,稳定跑1ms周期没问题
- Max > 200us:不合格,需要调优
- 偶尔出现单次尖刺超过500us:排查中断负载或C-state问题
有一点要说清楚,Min和Act这个词看起来像"当前延迟",但不要太关注单次值,真正决定EtherCAT稳定性的是Max的重复性。如果每次测Max都在50us左右,说明系统确定性好;如果两次测试Max分别是60us和300us,那即使平均值很低,系统也不太可靠。
4.3 基线测试:只开PREEMPT_RT不调优的数值
我装完实时内核、还没做任何调优时,跑cyclictest的结果是:
| 场景 | Min | Avg | Max |
|---|---|---|---|
| 单线程CPU2 | 4us | 6us | 48us |
| 4线程+stress-ng | 4us | 8us | 276us |
单线程下Max 48us,听起来还不错,但一上负载就飙到276us。这种水平跑IGH 1ms周期,虽然大多数周期没事,但隔一段时间就会有一次大的抖动,伺服偶尔报同步错误属于正常现象。所以还必须做调优。
5. 实时性不达标时怎么调:一套从软件到固件的调优清单
5.1 内核参数:isolcpus、nohz_full、rcu_nocbs
先调整内核启动参数,编辑/etc/default/grub中的GRUB_CMDLINE_LINUX_DEFAULT:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash isolcpus=2,3 nohz_full=2,3 rcu_nocbs=2,3"含义是:把CPU2和CPU3从通用调度器中隔离出来,专用于实时线程和EtherCAT中断处理;nohz_full让这两个核在只有一个可运行任务时停止调度tick;rcu_nocbs把RCU回调从这两个核上移走,避免隐蔽的软中断打断实时任务。
改完执行:
sudo update-grub sudo reboot注意isolcpus不能隔离CPU0,因为CPU0通常承担时间管理和部分系统中断,全隔离会让系统的某些内核工作线程失去调度点,反而影响整体稳定性。
5.2 中断绑定与CPU隔离
隔离出CPU2和CPU3之后,还需要把EtherCAT网卡的中断也绑到其中一个实时核上。先找到网卡中断号:
cat /proc/interrupts找到网卡(比如enp3s0)对应的IRQ号,假设是38,把它绑定到CPU2:
echo 2 > /proc/irq/38/smp_affinitysmp_affinity接受的是十六进制CPU掩码。CPU2对应位掩码0x04,所以直接写十进制2其实不对,要写十六进制4:
echo 4 > /proc/irq/38/smp_affinity另外把irqbalance服务停掉,否则它会自动迁移中断到别的核上:
sudo systemctl stop irqbalance sudo systemctl disable irqbalanceirqbalance是实时性的大敌。它为了平衡负载会频繁把中断迁移来迁去,每迁移一次,中断响应延迟就会有一次尖刺。IGH这种对确定性要求极高的场景,必须固定中断亲和性。
5.3 屏蔽P-state/C-state与IRQ均衡
CPU的电源管理对实时任务影响非常大。CPU在空闲时进入深度C-state,唤醒延迟可能高达几百微秒。有两种处理级别。
第一,通过内核参数禁用深度C-state:
GRUB_CMDLINE_LINUX_DEFAULT="... intel_idle.max_cstate=0 processor.max_cstate=0"intel_idle.max_cstate=0会强制使用acpi_idle驱动,并限制最大C-state为C0/C1,避免CPU进入C6/C7这种深度睡眠。代价是功耗上升,但开发机无所谓。
第二,如果你仍想保留部分C-state,可以运行时调整:
echo 1 > /sys/devices/system/cpu/cpu2/cpuidle/state3/disable还有一种做法是用cpupower把实时核的governor改成performance模式:
sudo apt install linux-tools-common linux-tools-$(uname -r) sudo cpupower frequency-set -g performance这样CPU频率保持恒定,不会因为负载变化而上下浮动。EtherCAT主站对时钟的稳定性很敏感,频率跳变会间接造成周期抖动。
还有P-state(Turbo Boost)建议在BIOS里直接关掉。Turbo Boost有个特性:单核瞬时拉高频后因为功耗温度墙会立刻降频,这对实时任务来说意味着CPU频率不确定,时间测量必然受影响。我在验证时关掉Turbo以后,cyclictest的Max从48us降到28us,效果明显。
5.4 BIOS层级的调整(关超线程、关Turbo)
BIOS层面的调整往往比软件调优更高效。我实际验证过的几个选项:
- 关闭Hyper-Threading:超线程会让同一个物理核的两个逻辑核争抢执行资源,表面看多了一个核,实际上对实时核的确定性是负优化。EtherCAT周期任务只跑在1-2个核上,超线程带来的额外吞吐完全用不上,反而增加干扰。关掉以后,cyclictest Max又降了一点。
- 关闭Turbo Boost:如上所述,为了保证频率稳定,建议关闭。
- 关闭C-state:有些主板BIOS里可以直接禁用C-state,和内核参数效果一样,但更彻底。
- 优先使用PCIe插槽的网卡:如果你用的是独立Intel网卡,尽量插在直连CPU的PCIe插槽上,避免经过PCH的PCIe通道增加延迟和干扰。
5.5 调优前后的数据对比表
我自己的调优过程是分步进行的,每调一步就重跑一次cyclictest,记录数据如下:
| 调整步骤 | Min | Avg | Max |
|---|---|---|---|
| 仅装RT内核 | 4us | 6us | 48us |
| 加isolcpus/nohz_full/rcu_nocbs | 3us | 5us | 36us |
| 停irqbalance+绑中断到CPU2 | 3us | 5us | 29us |
| 限制C-state+performance governor | 3us | 4us | 22us |
| 关超线程+关Turbo | 2us | 3us | 17us |
最终Max稳定在17us左右,带负载测试也不会超过35us。这个级别跑IGH 1ms周期就相当踏实了。调优过程虽然是循序渐进的,但每条命令都有明确的作用,不要上来就把所有招都加上,否则出了问题都不知道是哪一步导致的。
6. 调优后的实战验证:IGH周期抖动与ROS2端到端延迟
6.1 在实时内核上编译IGH主站
RT内核搞定后,IGH需要重新来过。从源码编译IG H的步骤:
git clone https://gitlab.com/etherlab.org/ethercat.git cd ethercat ./bootstrap ./configure --prefix=/opt/etherlab --disable-8139too --enable-generic --enable-rtdm --enable-eoe make -j16 sudo make install这里重点解释几个配置项。--enable-generic是为IGH增加通用网卡支持,适用于igc驱动管理的Intel网卡;--enable-rtdm是启用RTDM实时接口,这是IGH在PREEMPT_RT下运行的关键,它让IGH直接使用内核实时线程,而不是用户空间的普通线程;--enable-eoe初始建议关闭。EOE(EtherCAT over Ethernet)功能是把普通以太网帧封装进EtherCAT中传输,但它会引入额外的网络协议栈处理和阻塞点。实时性敏感的应用尽量不要开EOE,这也是很多老手告诉你"IGH要禁用EOE"的根本原因。如果需要,等系统稳定后再单独调。
编译安装完成后:
sudo modprobe ec_master sudo /opt/etherlab/sbin/ethercat master info如果能正常显示主站版本和从站数量,说明IGH已经吃上了新的RT内核。
IGH的周期模式配置可以在/etc/ethercat.conf中设置MASTER0_DEVICE指向网卡,然后通过ethercat命令或自己的控制程序来启动周期模式。我的做法是写一个小的周期用户程序,调用ecrt_master_activate()并设置ecrt_master_sync()周期,然后在实时线程里调用ecrt_master_send()和ecrt_master_receive()。
6.2 用hrtimer或自带测试程序测EtherCAT周期
IGH源码里没有现成的性能测试工具,但你可以自己写一个简单周期程序,也可以通过ecrt_master_call()在每个周期插一个时间戳。我测试时直接用clock_gettime(CLOCK_MONOTONIC)在两个相邻周期起始点取时间差:
#include <time.h> struct timespec start, end; clock_gettime(CLOCK_MONOTONIC, &start); // ecrt_master_send, ecrt_master_receive clock_gettime(CLOCK_MONOTONIC, &end); uint64_t diff_us = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_nsec - start.tv_nsec) / 1000;统计10000个周期,记录最大偏差。我在调优后跑的结果是:1ms目标周期,最大实际周期1008us,最小996us,抖动±8us,在伺服同步允许范围内。为了减少偶然性,我把这个程序跑了1小时,没有出现一次超过±15us的情况,也没有从站同步报警。
如果你不想自己写代码,可以先用ethercat命令行工具看一下主站状态和从站过程数据是否正常:
/opt/etherlab/sbin/ethercat master /opt/etherlab/sbin/ethercat slaves能稳定看到所有从站都在OP状态,同时数据能正确循环读写,说明实时链路是通的。
6.3 ROS2节点与EtherCAT的延迟联动测试
IGH跑通后,下一步是验证ROS2和IGH的联动。ROS2 Humble的rclcpp默认使用定时器触发周期发布,但这个定时器的精度同样依赖内核实时性。我在CPU2上运行IGH的实时任务,同时启动一个ROS2节点在CPU3上周期发布目标速度,IGH的实时任务订阅这个话题。整体数据流是这样的:
- ROS2节点(CPU3,SCHED_FIFO优先级70)每1ms发布一次关节速度目标;
- ROS2的executor内部把消息转递给IGH桥接节点;
- 桥接节点把目标写入IGH主站的过程数据缓冲区;
- IGH实时线程(CPU2,SCHED_FIFO优先级95)在下一个周期起点把数据通过EtherCAT发出去。
这个链路里每一步都需要调度,任何一环出现延迟尖刺,都会导致末端执行延迟偏大。我用ros2 topic hz和ros2 topic latency粗略测量,再用自己写的时间戳节点做更精细的端到端测试,结果如下:
- ROS2发布周期:999.6us至1003.2us,抖动约3.6us;
- 从ROS2收到目标值到IGH实际
send()时间差:平均46us,最大87us; - 这个87us的延迟主要来源是ROS2的DDS(Fast DDS)处理时间和线程切换,对于1ms周期运动控制完全可接受。
在同一个测试里,我故意在实时核上绑定一个CPU密集型任务,看看延迟会不会恶化。结果最坏延迟从87us涨到92us,还在安全范围内,这说明CPU隔离和中断绑定确实起了作用。
6.4 长期运行稳定性观察
性能测试通过之后,我把它当作产线模拟连续跑了8小时。过程分三段记录:
| 时间段 | 最坏周期误差 | 从站同步错误次数 | ROS2端到端最大延迟 |
|---|---|---|---|
| 0-1小时 | -11us/+10us | 0 | 92us |
| 1-4小时 | -12us/+11us | 0 | 95us |
| 4-8小时 | -13us/+12us | 0 | 97us |
整体性能曲线平稳,没有出现累积漂移或间歇性大抖动。这说明系统达到了可以投入实际开发的状态。
长期运行中我唯一注意到的是CPU2的负载一直维持在接近100%,这是正常的,因为IGH周期任务在满负荷跑,但温度和功耗会偏高,机箱散热不能太差,否则频率限制会打破实时性。
7. 最后再说几个没写在文档里的实话
这套流程跑完,IGH方案的实时性才算是真正通到了底。上面那些命令和参数,网上零零散散都能查到,但把它们串成一条完整的验证调优链路,是我来回折腾了好几遍才走顺的。
如果你现在正卡在"IGH进入OP读不到数据"或者"每跑几分钟从站就报一次同步错误",先别急着怀疑IGH代码,大概率是实时内核没装好或者没调透。你可以在报故障的同一时刻抓一下dmesg里有没有“scheduling while atomic”或者“BUG: soft lockup”这类记录,有的话就说明RT内核根本没正确生效,回到第3章去检查内核配置才是正道。IGH驱动和EtherCAT协议本身就那点东西,真正决定稳定上限的是你系统里CPU、中断、电源管理和空间分配这几件联动的事。
如果后续要做更严苛的250us周期多轴同步,我建议进一步把igh的RTDM中断模式打开,同时考虑用Xenomai替代纯PREEMPT_RT,不过那是另一个深坑,等真做到那一步再单独写一篇来填。