欢迎光临
我们一直在努力

【实时Linux工业PLC解决方案系列】第十二篇 - 实时Linux PLC EtherCAT主站实时方案

一、简介:为什么 EtherCAT 是工业实时通信的首选?

  • EtherCAT 优势:

    • 百兆以太网物理层,单帧遍历全站,理论周期 31.25 μs。

    • 分布式时钟(DC)精度 < 100 ns,多轴同步无需额外硬件。

    • 开源主站(IGH、SOEM)成熟,Linux 实时补丁(PREEMPT_RT)完善。

  • 实际痛点:

    • 标准 Linux 协议栈延迟抖动 10 ms+,无法满足 1 ms 控制周期。

    • 从站数量 > 50 时,扫描超时、数据丢包频发。

    • EoE 功能与实时数据竞争带宽,导致控制指令延迟。

  • 掌握本方案 = 让 x86/ARM 工控机变身“硬实时 PLC”,替代进口倍福、汇川方案,成本下降 60%+。


二、核心概念:6 个关键词搞懂 EtherCAT 实时化

关键词一句话本文出现场景
EtherCAT 帧结构 标准以太网帧,Type=0x88A4,Payload 含多个从站数据 抓包分析、帧组装
过程数据对象(PDO) 周期性交换的实时数据,如电机位置、扭矩 映射到 PLC 变量表
邮箱(Mailbox/SDO) 非周期参数配置,如驱动器增益调整 启动时初始化
分布式时钟(DC) 从站本地时钟与主站同步,消除传输延迟 多轴同步控制
EoE(EtherCAT over Ethernet) 在 EtherCAT 帧中隧道传输标准 TCP/IP 远程调试、摄像头
IGH / SOEM 两大开源主站栈:IGH 功能全,SOEM 轻量 本文选用 IGH

三、环境准备:15 分钟搭好 EtherCAT 实验室

3.1 硬件清单

组件型号/规格数量说明
工控机 x86_64,4 核 2.0 GHz+ 1 主站,带 Intel i210 网卡(推荐)
EtherCAT 从站 伺服驱动器(如汇川 SV660N) 2-4 验证 DC 同步
交换机 标准百兆交换机 1 拓扑扩展
网线 CAT5e 屏蔽双绞线 若干 降低 EMI

网卡选型关键:Intel i210/i211 支持 MSI-X,延迟 < 10 μs;Realtek 芯片慎用。

3.2 软件环境

组件版本安装命令
Ubuntu Server 22.04 LTS 官方镜像
PREEMPT_RT 内核 5.15.71-rt53 见下文脚本
IGH EtherCAT Master 1.5.2 源码编译
libethercat 1.5.2 IGH 依赖

3.3 一键安装实时内核 + IGH(可复制)

#!/bin/bash
# setup_ethercat.sh
set -e

# 1. 安装依赖
sudo apt update
sudo apt install -y build-essential git autoconf libtool libpopt-dev

# 2. 下载并打 PREEMPT_RT 补丁(略,同系列前文)
# 假设已重启进入 RT 内核

# 3. 下载 IGH
cd /opt
sudo git clone https://gitlab.com/etherlab.org/ethercat.git
cd ethercat
sudo git checkout stable-1.5

# 4. 配置编译
sudo ./bootstrap
sudo ./configure –prefix=/usr/local/etherlab \\
–with-linux-dir=/lib/modules/$(uname -r)/build \\
–enable-8139too=no \\
–enable-e1000e=yes \\
–enable-igb=yes
sudo make -j$(nproc)
sudo make modules
sudo make install
sudo make modules_install

# 5. 加载驱动
sudo depmod -a
sudo modprobe ec_master
sudo modprobe ec_generic # 通用网卡驱动,或指定 e1000e/igb

echo "IGH 安装完成,执行 sudo /usr/local/etherlab/bin/ethercat start 启动主站"

3.4 配置网卡与启动

# 编辑主站配置
sudo tee /usr/local/etherlab/etc/ethercat.conf <<'EOF'
MASTER0_DEVICE="00:1e:67:xx:xx:xx" # 替换为你的网卡 MAC
DEVICE_MODULES="generic"
EOF

# 启动主站
sudo /usr/local/etherlab/bin/ethercat start

# 验证状态
sudo /usr/local/etherlab/bin/ethercat master
# 输出应显示:Master0 running, 0 slaves


四、应用场景:自动化生产线的多轴同步控制

在某汽车零部件焊接产线,6 台伺服驱动器控制机械臂轨迹,要求:

  • 控制周期:1 ms(1000 Hz)

  • 同步精度:各轴位置偏差 < 1 μs(DC 同步)

  • 网络拓扑:线型 + 分支,共 8 个从站节点

  • 功能扩展:EoE 通道承载 2 台工业相机,用于焊缝质量检测

通过实时 Linux + IGH 方案,工控机作为主站,以 1 ms 周期下发目标位置,从站 DC 时钟锁定后,实际轴间同步抖动 < 50 ns;EoE 数据与控制数据分时复用,带宽利用率 40%,满足实时性与可视化双重需求。


五、实际案例与步骤:从扫描到 DC 同步

5.1 从站扫描与配置

# 扫描总线上的从站
sudo /usr/local/etherlab/bin/ethercat slaves
# 输出示例:
# 0 0:0 PREOP E 0x00000002:0x044c2c52 SV660N
# 1 0:1 PREOP E 0x00000002:0x044c2c52 SV660N

# 读取从站信息
sudo /usr/local/etherlab/bin/ethercat slave -p0 -v

5.2 实时控制程序(C 语言)

/* ec_realtime.c – 1 ms 周期 DC 同步控制 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <ecrt.h>

#define VENDOR_ID 0x00000002 /* 汇川 */
#define PRODUCT_CODE 0x044c2c52 /* SV660N */

static volatile int running = 1;
static ec_master_t *master = NULL;
static ec_domain_t *domain = NULL;
static ec_slave_config_t *sc = NULL;

/* PDO 入口偏移 */
static unsigned int off_target_pos;
static unsigned int off_actual_pos;
static unsigned int off_control_word;
static unsigned int off_status_word;

/* 周期:1 ms = 1,000,000 ns */
#define CYCLE_TIME_NS 1000000

void signal_handler(int sig) {
running = 0;
}

void cyclic_task(struct timespec *wakeup_time) {
/* 等待下一个周期 */
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, wakeup_time, NULL);

/* 接收过程数据 */
ecrt_master_receive(master);
ecrt_domain_process(domain);

/* 读取实际位置 */
int32_t actual_pos = EC_READ_S32(ecrt_domain_pdo(domain, off_actual_pos));

/* 计算目标位置(简单梯形轨迹) */
static int32_t target_pos = 0;
target_pos += 100; /* 每周期增 100 脉冲 */

/* 写入目标位置和控制字 */
EC_WRITE_S32(ecrt_domain_pdo(domain, off_target_pos), target_pos);
EC_WRITE_U16(ecrt_domain_pdo(domain, off_control_word), 0x0f);

/* 发送过程数据 */
ecrt_domain_queue(domain);
ecrt_master_send(master);

/* 更新唤醒时间 */
wakeup_time->tv_nsec += CYCLE_TIME_NS;
if (wakeup_time->tv_nsec >= 1000000000) {
wakeup_time->tv_nsec -= 1000000000;
wakeup_time->tv_sec++;
}
}

int main(int argc, char **argv) {
signal(SIGINT, signal_handler);

/* 1. 请求主站 */
master = ecrt_request_master(0);
if (!master) {
fprintf(stderr, "Failed to request master\\n");
return -1;
}

/* 2. 创建域 */
domain = ecrt_master_create_domain(master);
if (!domain) {
fprintf(stderr, "Failed to create domain\\n");
return -1;
}

/* 3. 配置从站 */
sc = ecrt_master_slave_config(master, 0, 0, VENDOR_ID, PRODUCT_CODE);
if (!sc) {
fprintf(stderr, "Failed to get slave config\\n");
return -1;
}

/* 4. 配置 PDO */
ec_pdo_entry_reg_t regs[] = {
{0, 0, VENDOR_ID, PRODUCT_CODE, 0x6040, 0x00, &off_control_word},
{0, 0, VENDOR_ID, PRODUCT_CODE, 0x607a, 0x00, &off_target_pos},
{0, 0, VENDOR_ID, PRODUCT_CODE, 0x6041, 0x00, &off_status_word},
{0, 0, VENDOR_ID, PRODUCT_CODE, 0x6064, 0x00, &off_actual_pos},
{}
};

if (ecrt_domain_reg_pdo_entry_list(domain, regs)) {
fprintf(stderr, "PDO registration failed\\n");
return -1;
}

/* 5. 激活主站,启用 DC */
ecrt_master_activate(master);

/* 6. 获取域数据指针 */
uint8_t *domain_pd = ecrt_domain_data(domain);

/* 7. 配置实时调度 */
struct sched_param param = { .sched_priority = 99 };
pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);

/* 8. 锁定内存 */
if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
perror("mlockall failed");
return -1;
}

/* 9. 启动周期任务 */
struct timespec wakeup_time;
clock_gettime(CLOCK_MONOTONIC, &wakeup_time);
wakeup_time.tv_sec += 1; /* 1 秒后开始 */

while (running) {
cyclic_task(&wakeup_time);
}

/* 清理 */
ecrt_master_deactivate(master);
ecrt_release_master(master);
munlockall();

return 0;
}

编译与运行:

gcc ec_realtime.c -o ec_realtime -I/usr/local/etherlab/include \\
-L/usr/local/etherlab/lib -lethercat -lrt -pthread
sudo ./ec_realtime

5.3 DC 分布式时钟同步

# 查看 DC 状态
sudo /usr/local/etherlab/bin/ethercat dc
# 输出应显示:DC enabled, 0 ns drift

# 在代码中启用 DC 同步(追加到配置段)
ecrt_slave_config_dc(sc, 0x0300, CYCLE_TIME_NS, 0, 0, 0);

验证精度:

# 循环读取从站时钟偏差
watch -n 0.1 'sudo /usr/local/etherlab/bin/ethercat dc -p0'
# 正常范围:±50 ns

5.4 EoE 功能启用

# 1. 加载 EoE 内核模块
sudo modprobe ec_eoe

# 2. 配置虚拟网卡
sudo ip link set eoe0s0 up
sudo ip addr add 192.168.100.1/24 dev eoe0s0

# 3. 从站侧配置(通过 SDO 或从站网页)
# IP: 192.168.100.10, 网关: 192.168.100.1

# 4. 测试连通性
ping 192.168.100.10


六、常见问题与解答(FAQ)

问题现象解决
ecrt_request_master 返回 NULL 主站未启动或网卡被占用 确认 ethercat start,关闭 NetworkManager
周期抖动 > 100 μs 非实时内核或中断未隔离 启用 PREEMPT_RT,CPU 隔离 isolcpus=2,3
DC 同步偏差 > 1 μs 网线质量差或从站晶振漂移 换屏蔽网线,启用 DC 漂移补偿算法
EoE 数据导致控制延迟 带宽竞争 限制 EoE 帧大小,或分时调度(控制周期偶数帧传 EoE)
从站偶尔掉线 总线负载过高或 EMI 降低 PDO 数据量,增加分布式时钟同步周期

七、实践建议与最佳实践

  • 网卡选型
    Intel i210/i211 为首选,避免 Realtek 和 USB 网卡。

  • CPU 隔离
    启动参数 isolcpus=2,3 nohz_full=2,3,将实时任务绑核。

  • 中断优化

    # 网卡中断绑到隔离核
    sudo sh -c 'echo 4 > /proc/irq/$(grep eth0 /proc/interrupts | head -1 | cut -d: -f1)/smp_affinity'

  • 监控与日志
    启用 IGH 的 ecrt_master_create_domain() 统计,周期打印最大/平均/最小执行时间。

  • 热插拔处理
    实现从站状态机:OP → SAFEOP → PREOP → 重新扫描 → 恢复 OP。

  • 版本锁定
    IGH、内核、驱动版本写入《BOM 清单》,升级需回归测试。


  • 八、总结:一张脑图带走全部要点

    EtherCAT 实时主站
    ├─ 硬件:i210 网卡 + 屏蔽网线 + 多核工控机
    ├─ 软件:PREEMPT_RT + IGH 1.5.2
    ├─ 配置:MAC 绑定 → 启动主站 → 扫描从站
    ├─ 开发:PDO 映射 → DC 同步 → 1 ms 周期任务
    ├─ 扩展:EoE 隧道 → 远程调试 + 视觉
    └─ 优化:CPU 隔离 + 中断绑核 + 版本锁定

    通过本文方案,x86/ARM 工控机即可替代传统专用 PLC,实现:

    • 1 ms 控制周期,抖动 < 50 μs

    • 100 ns 级多轴同步,满足精密加工

    • EoE 融合通信,简化网络架构

    将代码推送到你的 GitLab,下次产线升级,只需“改 PDO 映射表 + 重编译”,让国产实时 PLC 从“能用”走向“好用”!

    赞(0)
    未经允许不得转载:171主机测评 » 【实时Linux工业PLC解决方案系列】第十二篇 - 实时Linux PLC EtherCAT主站实时方案
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址