EtherCAT 伺服接入 Klipper / Kalico
三条结论
- Klipper 主线与 Kalico 都没有原生 EtherCAT。能上机的路线只有一条:Linux 内核里跑 IgH 主站,外加一个把 Klipper
toolhead位置流翻译成 CiA402 CSP 目标位置的桥接守护进程。脉冲转换器和 LinuxCNC + lcec 混合是备选,其余路径停在实验阶段。- 纯总线机(伺服 + IO 板、没有物理 MCU 板)必须用 Linux host MCU 为
toolhead.mcu提供打印时间基准,否则[mcu]直接Unable to connect;这个 MCU 在没有/dev/gpiochip的 x86 上还要打一个 GPIO 补丁才不 segfault。- 软实时 IgH 在 1 kHz / 500 mm/s 量级是稳的(
print_stall = 0、丢帧 0.0001% 级);推到 1000 mm/s 的瓶颈是主站周期而不是加速度。到 µs 级周期、8 kHz 伺服刷新这个量级,才需要 FPGA 硬主站——而用 USB 连硬主站会把优势全部吃掉。
从站拓扑:一块 IO 板 + 四路伺服
一个可用的最小总线拓扑(四轴机,X/Y/Z + 挤出):
| slave | 设备 | 角色 | profile | 周期 |
|---|---|---|---|---|
| 1 | EaserCAT 3000 | 数字 IO 板(限位/回零/急停) | cia402_mode = -1,不下发控制字 |
1 kHz |
| 2 | L6N COE | X 轴伺服 | CSP | 1 kHz |
| 3 | L6N COE | Y 轴伺服 | CSP | 1 kHz |
| 4 | L6N COE | Z 轴伺服 | CSP | 1 kHz |
| 5 | L6N COE | E 轴(挤出)伺服 | CSP | 1 kHz |
几个值得固定下来的工程约定:
- PDO 描述统一成四段式
0x6040:0:16:0,即index:subindex:bits:offset。写配置时一眼能看出映射对不对,比纯十六进制偏移表好查。 - IO 板与伺服走同一套 profile 机制,用
cia402_mode = -1表示"这块从站不参与 CiA402 状态机",只搬 PDO、不写控制字。这样同一份代码可以同时驱动两种从站,不必为 IO 板单开分支。 - 从站序号就是轴身份。
slave_index同时出现在printer.cfg轴段和主站配置里,两边错一个数字,现象是"某个轴不动/乱动"而不是报错——排查时先核对这两处。
IO 板出厂默认已经配好了限位,用 SDO 读一遍即可确认,不必从零映射:
| 对象 | 默认值 | 含义 |
|---|---|---|
0x2400 |
1 | 正限位 POT |
0x2401 |
2 | 负限位 NOT |
0x2402 |
0x16 |
回零 HOME |
0x2403 |
— | 预留 |
对应手册的 SI 功能号:正向限位 PL = 25h、反向限位 NL = 26h、HOME = 22h。回零速度要注意 IO 板是 10 ms 轮询,高速回零的触发误差约等于 10 ms × 速度,精确定位场合不可接受,回零应交给伺服自己的 DI。
生态现实:四条路,只有一条能上机
| 方案 | 集成难度 | 实时性 | 硬件成本 | 成熟度 |
|---|---|---|---|---|
| EtherCAT → Step/Dir 脉冲转换器 | 低 | 中 | 中(每轴一个模块) | 成熟 |
| LinuxCNC + lcec 混合 | 中 | 高 | 低 | 中等 |
| IgH 主站 + 位置流桥接 | 高 | 中高 | 低 | 已在真机跑通 |
| Klipper MCU 层原生 EtherCAT(PRU/专用从站芯片) | 极高 | 极高 | 低 | 未验证 |
调研到的硬事实:
- mainline Klipper 官方不支持 EtherCAT,原生接口只有 step/dir、CAN、USB、串口,社区论坛口径是"别浪费时间"。
- Kalico(原 Danger Klipper)也没有原生 EtherCAT,仓库里只有通用
servo.py。 - GitHub 上没有成熟的 Klipper 直挂 EtherCAT 伺服公开项目。公开可见的尝试是用 Beckhoff EK1100 耦 EtherCAT 伺服搭大型机——主站装好、
ethercat slaves能看到从站,然后卡在"怎么对接 Klipper"。 - 工业 3D 打印的 EtherCAT 案例集中在建筑/大幅面(例如专利 CN109537455A),配的是 PLC 或运动控制卡,不是 Klipper。
- 唯一成熟对标是 LinuxCNC + linuxcnc-ethercat (lcec)。
所以路径选择的判据不是"哪个先进",而是"谁负责 1 kHz 的确定性":主站必须在内核态(IgH),运动规划留在用户态(Klipper 的 Python 规划器),两者之间用环形缓冲/共享内存解耦。脉冲转换器最省事,但每轴一个模块的成本加上额外一级延迟,在大幅面多轴机上不划算。
开源硬件主站板:能用,但不该用在打印机上
市面上有现成的开源 EtherCAT 主站小板可以买,接上 USB 就能扫从站。识别特征:STM32H743(Cortex-M7 @ 480 MHz、1 MB RAM、硬件以太网 MAC + RMII PHY,常见 LAN8720,CH340 做调试串口),跑开源 SOEM 库(裸机 / FreeRTOS / RT-Thread 任选)。另有 ESP32 + W5500 的变体——SPI 接网口芯片,实时性更差一档。
这类板子与上位机架构(klippy 是 Linux 进程)不兼容,三条理由:
- klippy 跑在 Linux 上,H743 是 MCU,跑不了 Klipper 的运动引擎——螺杆补偿、分段 mesh、输入整形这些全部丢失;
- 裸机 SOEM 在 1 kHz 下确定性不错(比 ESP32 强),但运动插值只能在 MCU 里做简单梯形,做不了前瞻;
- 受内存限制,从站规模只能十几个,DC 精度与 x86 上的 IgH 有实质差距。
正确用途:EtherCAT 协议学习、从站调试工具(挂总线扫伺服身份)、不需要 Klipper 的单轴嵌入式设备。
扫描从站身份的最小验证(pysoem):
import pysoem
master = pysoem.Master()
master.open('enp2s0')
if master.config_init() > 0:
for s in master.slaves:
print(s.position, s.name, hex(s.man), hex(s.id))
输出形如 1 EtherCATServo 0x100 0x100 就说明链路和从站都活着,可以接着做 SDO 身份读取和 CSP/CSV 模式控制测试。
一个容易跑偏的排查:CH340 串口枚举正常但板子无输出,先查固件是否烧录、网口 Link 灯是否亮,别去怀疑串口驱动——这类板子出厂常常是空片。
没有物理 MCU 的机器:Linux host MCU
EtherCAT 驱动不是独立运动引擎,它挂在 Klipper 的 MCU 抽象上,需要 toolhead.mcu 提供打印时间基准。纯总线机没有物理 MCU 板,[mcu] serial: /tmp/xxx 会直接报 Unable to connect。
编译 Kalico 的 Linux host MCU:
cd ~/kalico
echo "CONFIG_MACH_LINUX=y" > .config
make olddefconfig && make -j4
sudo bash scripts/flash-linux.sh # → /usr/local/bin/klipper_mcu
GPIO 补丁(没有 /dev/gpiochip 的 x86)
在没有 /dev/gpiochip 的机器(典型是 Intel 消费级平台)上,klipper_mcu 启动即 segfault。补丁改三处:
get_chip_fd()失败返回-1,不走 shutdown 流程;gpio_out_reset/gpio_out_write/gpio_in_read对无效 fd 静默 no-op;- EtherCAT 轴的
step_pin/dir_pin只是配置占位,实际运动由桥接守护进程驱动,GPIO 层不参与。
第三条是关键认识:这些 pin 是给 Klipper 的配置解析器看的,不是给硬件看的。理解这点就不会去纠结"pin 明明电平没变,轴怎么在动"。
systemd
[Service]
Type=simple
User=kalios # 普通用户,避免 socket 权限问题
ExecStart=/usr/local/bin/klipper_mcu
Restart=always
用 root 跑会带来 /tmp/klipper_host_mcu 的属主问题,klippy 以普通用户连不上。
printer.cfg
[mcu]
serial: /tmp/klipper_host_mcu
[stepper_x]
step_pin: gpio0 # 占位,无实际 GPIO
dir_pin: gpio1
enable_pin: gpio2
drive_type: eth # EtherCAT 伺服
slave_index: 2
endstop_pin: ^gpio3
drive_type: eth 把该轴从"发脉冲"切到"发目标位置";slave_index 必须与主站配置一致。
主站启动顺序
顺序错了会出现"从站看得见、轴不动",或者主站反复重载:
sudo ethercatctl stop
sudo rmmod ec_generic ec_master 2>/dev/null || true
sudo modprobe ec_master && sudo modprobe ec_generic
sudo ethercatctl start # dmesg: Accepting ... as main device
sudo systemctl start klipper-ethercatd
- systemd 服务里不要手动
modprobe ec_master,全部交给ethercatctl start——它内部带main_devices参数做卸载重载,手动加载会让主站绑错网卡。 ethercatctl start之后dmesg里必须有Accepting ... as main device。没有这行,说明网卡没绑上,后面所有调试都是白费。- 主站进程用
SCHED_FIFO优先级 80 绑隔离核,网卡 IRQ 也要绑到同一批核(irqaffinity),否则中断会跑到跑着 GUI/切片的核上。
一组可对照的参数:
| 项目 | 取值 |
|---|---|
| 内核 | 6.8 系 -realtime(PREEMPT_RT) |
| 隔离核 | isolcpus=10,11 + nohz_full + rcu_nocbs + irqaffinity |
| 网卡 | 独立 PCIe 网卡,专供 EtherCAT,不配 IP |
| 主站进程调度 | SCHED_FIFO 80,绑 CPU 10/11 |
| 网卡 IRQ | 绑 CPU 10 |
CiA402:位置/速度之外还能读什么
总线方案相对脉冲方案最大的增量不是"接线少",而是每一毫秒都能拿到伺服内部状态。
已接入读取的:
| 数据 | 对象 | 用途 |
|---|---|---|
| 位置实际值 | 0x6064 |
运动控制 |
| 速度实际值 | 0x606C |
运动控制 |
| 扭矩实际值 | 0x6077 |
堵料/碰撞检测;int16,单位 0.1% 额定扭矩,实测可读 |
同族伺服支持、但需要显式加 PDO/SDO 的:
| 数据 | 对象 | 3D 打印里的用途 |
|---|---|---|
| 位置误差 | 0x60F4 |
丢步检测:误差突增 = 丢步/撞车 |
| 目标位置 | 0x60FC |
与指令对比,判断桥接层是否跟丢 |
| 控制字/状态字 | 0x6040 / 0x6041 |
伺服健康状态、故障码入口 |
| 输入信号 | 0x60FD |
限位/回零状态 |
| 电机电流 / 母线电压 | 厂商区 0x2xxx |
功率监控 |
| 温度 | 厂商区 | 过热预警 |
| 编码器多圈位置 | 0x6063 |
断电后位置恢复 |
| 报警历史 | 0x1003 / 厂商区 |
故障诊断 |
| 滤波后实际速度 | 厂商区 | 速度环诊断 |
据此能做出八类优化,按价值排序:
- 挤出机扭矩监控 + 堵料检测(最实用):扭矩 > 阈值持续 N ms → 堵料,自动暂停;扭矩 ≈ 0 而挤出指令 > 0 → 断料/齿轮打滑。
- XY 碰撞检测:
0x60F4突增超阈值 → 立即停机,比限位开关更早、更灵敏。 - 扭矩显示界面:给现场看,是售前卖点。
- 压力提前(PA)闭环:扭矩近似正比于熔体压力 → 实时调挤出速度。大厂靠 loadcell 做这件事,总线方案直接从伺服读扭矩,不需额外传感器。
- 丢步检测与自动补偿:按层统计位置误差,累积量对应 Z 偏移。
- 机械健康诊断:扭矩波形频谱中,周期性波动指向丝杆弯曲/轴承磨损,高频振动指向皮带松动,堵转特征指向润滑不良。
- 速度环 PID 自动整定:读速度环误差自动调 Kp/Ki/Kd。
- 断电恢复:
0x6063多圈绝对值 → 恢复精确位置 → 续打。
一个反直觉但很关键的点:多数 CSP 配置只下发位置,不下发目标速度(Rx PDO 只有 0x6040/0x607A/0x60B8,没有 0x60FF)。好处是配置简单,坏处是伺服完全靠内部滤波消化位置流的不平滑——这正是下一节诊断的根因之一。
CSP 周期与线宽脉动:诊断流程
三步法
第一步,速度达成率。 对目标轴做递增速度测试并量实际速度:
SET_VELOCITY_LIMIT VELOCITY={vel}
G1 X±100 F{vel*60}
判据:中低速达成率 ≥ 90% 正常,< 80% 说明存在硬限制。一组实测:
| 目标速度 | 实际速度 | 达成率 |
|---|---|---|
| 50 mm/s | 48 mm/s | 96% |
| 100 mm/s | 91 mm/s | 92% |
| 200 mm/s | 156 mm/s | 78% |
| 400 mm/s | 256 mm/s | 64% |
巡航速度封顶约 270 mm/s(ACCEL = 3000)。这种"低速几乎不丢、越高速越掉"的形状,指向限幅/前瞻不足,而不是电机能力不足。
第二步,CSP 流送分析。 从 klippy.log 解析 STREAM 行,取 tp(目标位置)、tv(目标速度)、pa(实际位置),做相邻差分并统计:
| 指标 | 正常 | 异常 |
|---|---|---|
| 步进波动 CV | < 10% | > 30% |
| 大幅跳跃(> 3σ) | 0 | ≥ 1 |
| 跳跃间隔 | — | ≈ 50 ms → trapq 速率问题 |
| 跟随误差 | < 1 mm | > 3 mm |
实测 200 mm/s 往复:CV 正向 49.2% / 反向 38.4%,> 3σ 跳跃 31 / 30 次,跳跃间隔 ~51 ms / ~62 ms,跟随误差 3.27 mm。CV 近 50% 加 50 ms 间隔,几乎等于直接指认 trapq 失配。
第三步,根因定位。
trapq (20 Hz,50 ms 间隔)
├─ t = 0~49 ms : 目标位置不变(49 个 cycle 是同一个数)
└─ t = 50 ms : 目标位置跳一大步 → 伺服急加速追赶 → "咔咔"响
Klipper 的 trapq 按约 20 Hz 更新位置,CSP 以 1 kHz 流送。中间 49 个周期目标位置不变、第 50 个周期跳一步,伺服为跟上这个阶跃会瞬时加大加速度。这是周期/速率不匹配,不是机械故障。
参数修正
| 参数 | 默认 | 建议 | 说明 |
|---|---|---|---|
max_delta_mm |
1.0 | 0 | 关闭步进限幅,减少高频微跳 |
jump_resync_mm |
8.0 | 30.0 | 避免高速时误触发重同步 |
stream_lookahead |
0.020 s | 0.040~0.060 s | 加长前瞻,平滑轨迹 |
EC_SAFE_LIMITS VELOCITY |
30 | 500 | 解除速度锁定 |
EC_SAFE_LIMITS ACCEL |
500 | 3000 | 提高加速度上限 |
另一类根因是 position_scale 不一致:配置写 3276.8,监测 API 报 6553.6,差整两倍。表现是回零后 Klipper 认为 X = 0,监测页却显示伺服实际位置 356 mm。改这个数不会让机器动起来,但会让所有基于位置的判据全部失真——诊断前先核对它,否则后面的误差分析都是在错误尺子上量。
弧线线宽周期性脉动
更难的案例:四轴全 CSP,直线正常、弧线线宽周期性脉动,同一台机器改脉冲方式控制就正常。这类"换驱动方式就好了"的现象容易误判成 Klipper 轨迹问题,静态读代码可定位到四个叠加因素。
① DC 同步未激活(最硬)。 实际调用是:
ecrt_slave_config_dc(sl->sc, 0x0300, g_cycle_ns, 0, 0, 0);
IgH 的签名是 (sc, sync0_cycle, sync1_cycle, assign_activate, sync0_shift, sync1_shift)。这里把 768 ns 当成了 sync0 周期(应为 DP 周期 1 ms),而 assign_activate = 0 意味着 SYNC0 根本没激活。正确写法:
ecrt_slave_config_dc(sc, g_cycle_ns, g_cycle_ns, EC_DC_ACTIVATE_SYNC0, 0, 0);
DC 不激活时,各从站按自己收到帧的时刻锁存目标位置,帧到达的微小偏差直接变成位置锁存偏差。
② Rx PDO 里没有目标速度。 profile 只有 0x6040/0x607A/0x60B8,offset_target_velocity = -1,纯位置闭环。没有速度前馈,伺服只能靠内部滤波器"猜"这一毫秒该走多快,对指令平滑度和时序极度敏感。
③ 主站时间开环累加。 全局 g_seg_pt_est += cyc_s 固定加 1 ms,只有 host 时钟段到达时才用 PLL 系数 0.05 对齐。周期抖动不会被纠正,只能缓慢收敛。
④ 从站各自独立估时。 早期实现每个从站独立 pt_est,E 轴与 XY 之间存在相位差;改全局统一后有所缓解,但 ① 未改,问题仍在。
为什么直线正常、弧线暴露:直线匀速时位置随时间线性变化,采样相位差只产生恒定相位偏移,不改变速度,也不改变挤出量。弧线被离散成大量微小线段,频繁加减速和变向,从站目标位置的锁存稍不同步就转成周期性速度波动 → 挤出量与运动量失配 → 线宽脉动。线宽脉动的本质是"位置同步误差被微分成了速度误差"。
修复优先级:DC 激活 → PLL 对齐系数/批次(0.05 跟不上圆弧加减速)→ 周期与资源(1 ms 周期下用户态 RT 被切片器和浏览器抢占,系统负载 7~8 时明显;把重负载挪走,或把周期降到 500 µs)。
只读验证(不触运动):
ethercat slaves # 每个从站的 SYNC / OP 状态
ethercat master # DC 参考时钟与偏移
两类"假故障"
8612 / Er1B0 单周期 TP 跳变。 现象是"首次打印正常,二次打印必 fault",故障位置固定。根因不在速度达成率,而在状态复位不完整:打印中复位后 Klipper 重新武装 sync_count_offset 并 CLEAR,桥接层 seg_clear() 清了 have_host_tp,却没有重置 tp_last,残留 2.5 亿 counts(≈ 376 mm)。重武装时用队列头(未来时刻)的时间戳去锚定,锚定检查因 have_host_tp = false 被跳过,于是一步锚到未来位置,目标位置突变,护栏 vmax × dt × 1.2 太松没拦住,报 Er1B0 并进入 fail-closed 级联 CLEAR 三次。
日志特征很好认:pt=266.411(残留时钟)+ d=-252248297(-376 mm)+ 打印中全轴 seg_clear 连续三次。修法三条:seg_clear 时把 tp_last 重置到 PA;锚定兜底改用 seg_tp(PA);重武装改用 estimated_print_time(monotonic())。
教训值得单列:护栏基准(tp_last)与锚定检查(have_host_tp)是两个独立状态,clear 时必须一起重置,否则陈旧基准继续参与限幅,形成"看起来有护栏、实际全部放行"。
丢帧率的脏数据。 报 0.0298%(Lost 2001 / Tx 671 万)不一定是真丢帧。核实下来是统计窗口落在最脏时段:某轴 count_offset 失配导致"积分突变"日志 63034 条 / 3 分钟,journald 磁盘 IO 饱和,偶发拖垮 RT 周期。判据是规律性——每 3 秒丢一帧是周期性 IO 刷新的节奏,不是随机调度抖动;再取 60 秒双快照比对帧数零变化,说明主站已停,丢帧发生在刷屏时段而非打印时段。
结论:丢帧率必须先确认窗口干净(无日志洪水、无异常刷屏),否则 0.03% 这个量级的数字全是假象;真实值要用干净打印窗口的前后增量对比。
长期方案:把 50 ms 台阶从根上消掉
参数调优只能压平台阶,压不掉它。两条根治路线:
stepper_sync_manager:新版 Klipper 提供的高频位置内插机制,本质是把trapq的粗粒度位置在 MCU/驱动侧做原生插值,从根上消除 50 ms 跳变。先确认版本是否带这个模块:
grep -r "stepper_sync_manager" klippy/
有则升级 klipper-ethercat 组件后启用;这需要动组件版本,不能只改配置。
- CSP 层插值/平滑:无法升级时的退路——在桥接层加一阶低通,或用最近 2~3 个 trapq 采样点做线性外推,把中间的空档 cycle 填满。代价是引入一点相位滞后(半个采样周期量级),在圆弧上表现为跟随误差略增,但比"每 50 ms 一次阶跃"好得多。
判断该走哪条:如果跳跃间隔稳定在 50 ms 且 CV > 30%,走路线一;如果已经做了内插但 CV 仍在 10~20%,说明瓶颈转移到 DC/PLL,回去查第六节 ①。
能不能到 1000 mm/s
先把账算清楚。
| 项 | 当前 | 目标 | 差距 |
|---|---|---|---|
max_velocity |
500 mm/s | 1000 mm/s | ×2 |
| 主站周期 | 1000 µs (1 kHz) | 500 µs (2 kHz) 建议 | ×2 |
| 伺服刷新 | 1 kHz | 2 kHz+ | ×2 |
max_accel |
20000 | 5000 即够 | 不是瓶颈 |
关键换算:
- 位置增量:1 ms × 1000 mm/s = 每周期 1 mm。20 位编码器约 3277 counts/mm → 每周期下发 3277 counts。切到 2 kHz 后每周期 0.5 mm ≈ 1638 counts,增量减半,插值更平滑。
- 加速度:0.2 s 加到 1000 mm/s 需要 5000 mm/s²,现有
max_accel = 20000有四倍余量。 - 所以瓶颈是主站周期,不是速度值本身。1 ms 周期下每周期 1 mm 的台阶已接近伺服速度环能平稳消化的上限。
链路各段余量:
运动规划(Klipper, Python) → ecrtd(C) → IgH(内核) → 伺服
1 kHz 无压力 CPU 11% PREEMPT_RT
连续运行数天的实测指标:
| 指标 | 实测 |
|---|---|
print_stall |
0(规划端从不卡顿) |
mcu_task_stddev |
0.0001(0.1 ms 级抖动) |
| 丢帧率 | 446 / 4500 万帧 = 0.001%;另一台 58 / 5900 万 = 0.0001% |
| 主站进程占用 | 12 MB 内存 / 10.8% 单核 |
| 网络重传 | 数千帧中 9 次 |
改法:
# ethercat_bus.cfg
cycle_us = 500
# printer.cfg
max_velocity: 1000
改完重启 klipper-ethercatd。但先验证三件事:
- 伺服支持 2 kHz 周期——查手册 DC 同步范围(多数 1~4 kHz),按型号确认,不要默认。
- ecrtd 在 2 kHz 的 CPU——1 kHz 用 11%,2 kHz 约 20~25%,工控机/ARM 板都扛得住,但要给切片和 UI 留余量。
- 机械刚性——颗粒机/大流量机质量大、惯性大,1000 mm/s 可能机械先抖。空跑测试(不装料)看伺服跟不跟得上、有无同步错误;
ethercat master的帧率应从 1000/s 变成 2000/s。
软实时 vs FPGA 硬主站
| 方案 | 1 kHz 空闲抖动 | 压力下抖动 | 周期能力 |
|---|---|---|---|
| FPGA 硬主站(网口/PCIe 直连) | < 3.6 µs | 14~15 µs | µs 级 |
| IgH 软件主站 + RT 内核 | 均值 < 20 µs | ~100 µs | 1 kHz 稳定 |
短板要说清楚:
| 短板 | 受限场景 |
|---|---|
| 抖动 10~100 µs(硬主站是 ns 级) | 精密多轴插补(机床、机器人)不行 |
| 125 µs 以下周期不稳 | 8 kHz+ 伺服刷新的极端场景 |
反过来,软实时在 3D 打印赛道有硬优势:Klipper 全家桶(断电续打、调平、输入整形、Mainsail/摄像头/远程)直接可用;配置改一行重启秒级生效,而 Zynq 改一版 PL 要重新综合(小时级);SSH + 日志 + ethercat master 就能调试,不需要 JTAG 和示波器。
USB 是硬主站的天花板。 USB High-Speed 帧周期固定 125 µs,FPGA 再快,数据也要每 125 µs 过一个 USB 帧;USB 是主机轮询协议,延迟 = 帧周期 + 驱动排队 + 调度抖动,叠加后比原生 PCIe/网卡差一个数量级。USB 连接的硬主站,实时性大概率不如 IgH + RT 内核 + 直连网卡。
提升实时性的收益排序:
| 方案 | 提升 | 成本 |
|---|---|---|
| IgH + 直连网卡 + RT 内核(现状) | 基准 | 0 |
IgH + 专用网卡 + isolcpus/IRQ 绑核 |
+20~30% | 一块网卡 |
| Xenomai 双内核(IgH 原生支持) | ~2× | 0 |
| FPGA 硬主站 + PCIe 直连 | 5~10× | 数千元 |
| FPGA 硬主站 + USB | 持平或更差 | 数千元,不推荐 |
补充一条:消费级网卡(如 Intel 82574L + ec_e1000e)没有硬件时间戳,换 I210 + ec_igb 只能优化软实时,真硬实时仍要 FPGA/Zynq。
边界结论:1~4 ms 周期、1000 mm/s、颗粒/大流量打印,软实时够用且功能完整;要 µs 级周期、多轴高精插补(雕刻、机器人、机床),才上 FPGA + PCIe。
诊断判据总表
| 现象 | 首选判据 | 常见根因 |
|---|---|---|
| 轴不动、无报错 | ethercat slaves 是否进 OP;两侧 slave_index 是否一致 |
从站未进 OP / 序号写错 |
[mcu] Unable to connect |
klipper_mcu 是否在跑;socket 属主 |
未编 host MCU / 用 root 跑 |
klipper_mcu 启动即崩 |
有无 /dev/gpiochip |
缺 GPIO 补丁 |
| 主站绑错网卡 | dmesg 有无 Accepting ... as main device |
手动 modprobe 抢占 |
| 高速掉速、低速正常 | 速度达成率曲线 | 安全限幅、前瞻不足 |
| "咔咔"声 + CV > 30% + 跳跃间隔 ≈ 50 ms | STREAM 解析的跳跃间隔 | trapq 20 Hz 与 CSP 1 kHz 失配 |
| 弧线线宽周期性脉动、直线正常 | ethercat master 的 DC 状态 |
DC 未激活 / 缺 0x60FF / PLL 太慢 |
| 回零后位置凭空偏移整倍数 | position_scale 与监测 API 的 scale 对比 |
换算系数差 2× |
| 二次打印必 fault(Er1B0 / 8612) | 日志 pt= 残留 + d= 大幅负跳变 |
seg_clear 未重置 tp_last |
| 丢帧率 0.0x% | 丢帧是否规律(每 3 s 一帧)、窗口内有无日志洪水 | IO 刷屏拖垮 RT,脏数据 |
| 扭矩读数恒定或为 0 | 0x6077 是否在 Tx PDO 里 |
PDO 未映射,不是伺服坏了 |
相关阅读
- 脉冲型伺服:电子齿轮、接线与多轴 —— 电子齿轮换算、NPN/PNP、上电使能、回零坐标系、Klipper 多轴