ethercat_test 是一个基于 IgH EtherCAT Master(EtherLab) 的实时周期通信测试程序,用于验证 Linux/RT Linux 环境下 EtherCAT 周期任务的实时性和稳定性。
程序主要完成:
- EtherCAT Master 初始化
- EtherCAT Slave 配置
- PDO 映射
- 周期性 PDO 数据收发
- CPU 亲和性绑定
SCHED_FIFO实时调度mlockall()锁定进程内存- 周期唤醒延迟统计
- 周期抖动(Jitter)统计
- 周期执行时间统计
- 周期 Overrun 统计
- EtherCAT Master/Slave 状态检查
程序适合用于评估 AGX Orin、工业 PC、RT Linux 等平台运行 EtherCAT 实时任务时的周期性能。
程序采用绝对时间周期调度:
┌──────────────────────┐
│ CLOCK_MONOTONIC │
└──────────┬───────────┘
│
▼
等待下一个绝对时间点
│
▼
┌─────────────────┐
│ 周期任务唤醒 │
└────────┬────────┘
│
▼
ecrt_master_receive()
│
▼
ecrt_domain_process()
│
▼
读取 PDO
│
▼
写入 PDO
│
▼
ecrt_domain_queue()
│
▼
ecrt_master_send()
│
▼
周期任务结束
│
└──────► 下一周期
程序通过 clock_nanosleep(..., TIMER_ABSTIME, ...) 按绝对时间点进行周期调度,而不是简单使用相对 usleep()。
这种方式可以避免周期任务执行时间产生的累积漂移。
当前程序默认配置:
| 参数 | 值 |
|---|---|
| Master | 0 |
| Slave Alias | 13330 |
| Slave Position | 0 |
| Vendor ID | 0x000013fe |
| Product Code | 0x00000051 |
| 默认周期 | 500 us |
| 默认 CPU | CPU 3 |
| 默认优先级 | 80 |
| 默认运行时间 | 10 s |
对应:
#define MASTER_INDEX 0
#define SLAVE_ALIAS 13330
#define SLAVE_POSITION 0
#define VENDOR_ID 0x000013fe
#define PRODUCT_CODE 0x00000051如果实际 EtherCAT 从站的 Alias、Position、Vendor ID 或 Product Code 不同,需要修改上述配置。
程序当前配置以下 PDO:
| PDO | 功能 |
|---|---|
0x1603 |
Pulse Counter |
0x1604 |
Digital Output |
0x1605 |
Analog Output |
| PDO | 功能 |
|---|---|
0x1A00 |
Digital Input |
0x1A01 |
Analog Input |
0x1A02 |
Temperature |
0x1A03 |
Pulse Counter |
程序实际注册并读取:
AO0
AI0
TEMP0
COUNTER0
其中:
AO0 -> 0x7050:01
AI0 -> 0x6010:01
TEMP0 -> 0x6020:01
COUNTER0 -> 0x6030:01
确保系统已经安装 EtherLab/IgH EtherCAT Master 开发环境。
典型情况下需要:
gcc ethercat_test.c -o ethercat_test \
$(pkg-config --cflags --libs ethercat) \
-pthread如果系统没有提供 pkg-config 配置,也可以根据实际安装路径手动指定:
gcc ethercat_test.c -o ethercat_test \
-I/usr/local/include \
-L/usr/local/lib \
-lethercat \
-pthread检查:
ldd ./ethercat_test确认能够找到 EtherCAT Master 库。
./ethercat_test -h命令参数:
-c <us> EtherCAT cycle period
-C <cpu> CPU affinity
-p <prio> SCHED_FIFO priority
-t <sec> Test duration
例如:
./ethercat_test -c 1000 -C 7 -p 90 -t 100表示:
周期:1000 us
频率:1000 Hz
CPU:7
SCHED_FIFO:90
测试时间:100 秒
建议按照以下周期逐级测试:
./ethercat_test -c 2000 -C 7 -p 90 -t 100
./ethercat_test -c 1000 -C 7 -p 90 -t 100
./ethercat_test -c 500 -C 7 -p 90 -t 100
./ethercat_test -c 250 -C 7 -p 90 -t 100
./ethercat_test -c 200 -C 7 -p 90 -t 100
./ethercat_test -c 125 -C 7 -p 90 -t 100
./ethercat_test -c 100 -C 7 -p 90 -t 100
./ethercat_test -c 50 -C 7 -p 90 -t 100对于机器人、运动控制等应用,建议重点关注:
1000 us 1 kHz
500 us 2 kHz
250 us 4 kHz
125 us 8 kHz
其中 500 us 和 1 ms 是比较有代表性的工业实时控制测试周期。
程序使用:
mlockall(MCL_CURRENT | MCL_FUTURE);以及:
sched_setscheduler(0, SCHED_FIFO, ¶m);因此普通用户可能没有足够权限。
建议使用:
sudo ./ethercat_test -c 500 -C 7 -p 90 -t 100如果希望不使用 sudo,需要配置相应的实时权限,例如 RLIMIT_RTPRIO、RLIMIT_MEMLOCK 等。
程序支持:
-C <cpu>例如:
./ethercat_test -c 500 -C 7 -p 90 -t 100表示 EtherCAT 实时线程固定运行在 CPU 7。
查看 CPU:
nproc或者:
lscpu查看当前进程:
taskset -cp <PID>建议实时测试时使用一个相对独立的 CPU,并尽量避免该 CPU 上存在大量普通任务。
对于 AGX Orin,可以分别测试不同 CPU:
./ethercat_test -c 500 -C 3 -p 90 -t 100
./ethercat_test -c 500 -C 7 -p 90 -t 100比较不同 CPU 的最大唤醒延迟和最大 Jitter。
程序使用:
SCHED_FIFO
优先级通过:
-p <priority>设置。
例如:
-p 90表示:
SCHED_FIFO priority = 90
Linux SCHED_FIFO 优先级范围:
1 ~ 99
实时任务一般可以使用:
80 ~ 95
但需要注意,不建议盲目设置为 99。
如果系统中存在更高优先级的实时任务,也可能影响 EtherCAT 周期任务。
例如:
-t 100表示运行:
100 秒
对于 500 us:
2000 Hz × 100 s = 200000 cycles
对于 1 ms:
1000 Hz × 100 s = 100000 cycles
如果:
-t 0程序会持续运行,直到:
Ctrl+C
停止。
测试结束后会输出:
========================================
EtherCAT Realtime Statistics
========================================
Target cycle = 500 us
Target frequency = 2000.00 Hz
Total cycles = 200000
Jitter events = 199999
Average period = 500.000 us
Min period = 493.873 us
Max period = 509.041 us
Min jitter = -6.127 us
Max jitter = 9.041 us
Avg wake-up latency = 2.651 us
Max wake-up latency = 13.686 us
Avg execution time = 10.562 us
Max execution time = 27.297 us
Cycle overruns = 0
========================================
目标周期。
例如:
Target cycle = 500 us
表示每 500 us 执行一次 EtherCAT 周期任务。
对应:
2000 Hz
实际周期的平均值:
Average period = 500.000 us
理想情况下应该非常接近目标周期。
例如:
Target = 500 us
Average = 500.000 us
说明长期平均周期非常准确。
实际测量到的最小和最大周期。
例如:
Min period = 493.873 us
Max period = 509.041 us
表示:
最短周期比目标少 6.127 us
最长周期比目标多 9.041 us
程序定义:
jitter = actual_period - target_period
因此:
Min jitter = Min period - Target period
Max jitter = Max period - Target period
例如:
Target = 500 us
Min jitter = -6.127 us
Max jitter = +9.041 us
意味着:
最早:提前 6.127 us
最晚:延迟 9.041 us
这里的 Jitter 是周期抖动。
程序还统计:
actual wakeup time - expected wakeup time
例如:
Avg wake-up latency = 2.651 us
Max wake-up latency = 13.686 us
含义是:
内核计划任务应该在某个绝对时间点唤醒
│
▼
Expected ────●────────────
│
│ + 13.686 us
▼
Actual ────●────────────
因此:
Max wake-up latency 是分析 Linux 调度实时性的非常重要的指标。
它主要反映:
- 调度延迟
- IRQ 干扰
- CPU 上其他任务
- 内核抢占
- CPU 电源管理
- 中断处理
- 内核线程
- 系统负载
等因素。
程序统计:
ecrt_master_receive()
↓
ecrt_domain_process()
↓
PDO Read
↓
PDO Write
↓
ecrt_domain_queue()
↓
ecrt_master_send()
这一段代码的执行时间。
例如:
Avg execution time = 10.562 us
Max execution time = 27.297 us
表示:
平均执行耗时 ≈ 10.6 us
最大执行耗时 ≈ 27.3 us
对于:
500 us cycle
27.3 us 只占:
约 5.5%
因此仍然有比较大的时间余量。
程序当前判断:
int64_t next_deadline_ns =
expected_wakeup_ns + target_period_ns;
if (cycle_end_ns > next_deadline_ns)
stats.overrun_events++;含义是:
当前周期的 EtherCAT 处理任务执行完成时间已经超过下一周期的计划唤醒时间。
例如:
周期 = 500 us
当前周期:
│<──────────── 500 us ────────────>│
Start Deadline
│
▼
如果 EtherCAT 任务执行到这里:
│
▼
End
则认为发生:
Cycle Overrun
这比单纯判断执行时间是否超过周期更有意义,因为周期任务的实时性最终关注的是下一周期 deadline 是否被错过。
程序目前:
if (jitter_ns != 0)
stats.jitter_events++;因此只要实际周期与目标周期存在任何纳秒级差异,就会被统计为 Jitter Event。
所以:
Target = 500 us
Jitter events = 199999
Total cycles = 200000
并不表示发生了 199999 次严重抖动。
它只表示:
几乎所有周期都不是精确的 500000 ns。
这是正常现象。
因此评估实时性时,不要主要看 Jitter Events 数量,而应该重点关注:
Min jitter
Max jitter
Max wake-up latency
Max execution time
Cycle overruns
建议按照以下优先级分析:
| 优先级 | 指标 | 关注意义 |
|---|---|---|
| ★★★★★ | Cycle overruns | 是否错过实时 deadline |
| ★★★★★ | Max wake-up latency | Linux 调度最坏延迟 |
| ★★★★★ | Max jitter | 周期稳定性 |
| ★★★★☆ | Min jitter | 周期提前程度 |
| ★★★★☆ | Max execution time | EtherCAT 任务最坏执行时间 |
| ★★★☆☆ | Average period | 长期周期准确性 |
| ★★☆☆☆ | Jitter events | 参考意义有限 |
建议固定测试条件:
CPU:
固定一个 CPU
Scheduling:
SCHED_FIFO
Priority:
90
Memory:
mlockall()
Runtime:
100 s 或更长
例如:
sudo ./ethercat_test -c 2000 -C 7 -p 90 -t 100
sudo ./ethercat_test -c 1000 -C 7 -p 90 -t 100
sudo ./ethercat_test -c 500 -C 7 -p 90 -t 100
sudo ./ethercat_test -c 250 -C 7 -p 90 -t 100
sudo ./ethercat_test -c 200 -C 7 -p 90 -t 100建议每个周期至少测试:
100 s
如果用于产品级实时性验证,可以进一步增加到:
10 min
30 min
1 h
甚至进行长时间压力测试。
为了测试最坏实时性,不建议只测试完全空闲的系统。
可以分别测试:
CPU Idle
Memory Idle
Network Idle
用于得到平台基础实时性能。
CPU stress
用于观察 CPU 竞争对实时任务的影响。
Memory stress
观察内存压力、内核回收等对实时性的影响。
由于 EtherCAT 本身依赖网络接口,建议额外测试:
EtherCAT + 普通网络流量
观察网卡 IRQ、网络协议栈等因素的影响。
最终可以测试:
CPU Stress
+
Memory Stress
+
EtherCAT
+
普通网络
+
磁盘 IO
这种测试更接近实际设备运行环境。
程序每 1000 个周期检查一次:
Master: slaves=1 link=1 state=0x08
Slave: online=1 operational=1 state=0x08
正常情况下:
Master:
slaves=1
link=1
state=0x08
Slave:
online=1
operational=1
state=0x08
其中:
0x08 = OPERATIONAL
如果测试过程中出现:
Slave operational=0
或者:
link=0
则说明 EtherCAT 通信本身存在异常。
实时性测试不能只关注 CPU Jitter,还需要确认 EtherCAT 链路一直处于正常状态。
建议按照下面的格式记录:
| Cycle | Frequency | Min Jitter | Max Jitter | Max Wake-up | Max Execution | Overrun |
|---|---|---|---|---|---|---|
| 2000 us | 500 Hz | - | - | - | - | 0 |
| 1000 us | 1 kHz | - | - | - | - | 0 |
| 500 us | 2 kHz | - | - | - | - | 0 |
| 250 us | 4 kHz | - | - | - | - | 0 |
| 200 us | 5 kHz | - | - | - | - | 0 |
建议最终重点回答三个问题:
1. 最大唤醒延迟是多少?
2. 最大周期 Jitter 是多少?
3. 有没有 Cycle Overrun?
其中第三项尤其重要。
当前实现中:
if (jitter_ns != 0)
stats.jitter_events++;几乎每个周期都会存在几个纳秒甚至微秒的偏差,因此该数值通常接近总周期数。
真正应该关注的是最大/最小 Jitter。
例如:
Average period = 500.000 us
并不能证明实时性很好。
因为可能存在:
大多数周期:500 us
少数周期:550 us
平均值仍然可能非常接近 500 us。
因此实时系统必须重点关注:
Worst Case
而不是只看平均值。
程序目前每 1000 个周期输出一次状态。
如果测试周期非常短,例如:
50 us
1000 周期只有:
50 ms
因此输出频率会比较高。
对于极低周期测试,建议减少输出频率,否则终端 I/O 本身可能影响测试结果。
对于 EtherCAT 实时性测试,不建议简单定义:
Jitter < X us = PASS
因为具体允许值取决于:
- EtherCAT 主站实现
- 从站设备
- 控制周期
- DC 配置
- 应用控制算法
- 伺服驱动器要求
- RT Linux 配置
- CPU 平台
- 系统负载
更合理的判定方式是:
周期稳定
+
最大唤醒延迟可接受
+
最大 Jitter 可接受
+
最大执行时间明显小于周期
+
Cycle Overrun = 0
+
EtherCAT Master/Slave 始终 OP
对于机器人控制场景,还需要结合实际伺服驱动器要求确定最终指标。
ethercat_test 主要用于回答:
当前 Linux/RT Linux + AGX Orin 平台,能否稳定地以指定周期执行 EtherCAT PDO 通信?
最核心的测试指标为:
Target cycle
↓
Max wake-up latency
↓
Max jitter
↓
Max execution time
↓
Cycle overruns
↓
EtherCAT OPERATIONAL 状态
其中:
Max wake-up latency
主要反映 Linux 实时调度能力;
Max execution time
主要反映 EtherCAT 周期任务本身的处理开销;
Max jitter
反映 最终周期稳定性;
Cycle overruns
用于判断 实时 deadline 是否真正被错过。
对于 AGX Orin 这类平台,建议优先使用:
sudo ./ethercat_test -c 1000 -C 7 -p 90 -t 100
sudo ./ethercat_test -c 500 -C 7 -p 90 -t 100
sudo ./ethercat_test -c 250 -C 7 -p 90 -t 100
sudo ./ethercat_test -c 200 -C 7 -p 90 -t 100逐步降低周期,观察系统在更高 EtherCAT 控制频率下的最坏实时性能。