ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

EtherCAT+ros2_control+1kHz到底怎么实现?从网卡中断到电机指令解析机器人实时控制链路

EtherCAT+ros2_control+1kHz到底怎么实现?从网卡中断到电机指令解析机器人实时控制链路 在前面的文章中我们已经连续讨论了ROS 2的Executor、实时Linux、CPU核心隔离、内存管理、零拷贝以及ros2_control也进一步分析了SCHED_FIFO、SCHED_RR和SCHED_DEADLINE在1 kHz机器人控制线程中的作用。但如果继续往下追问一个问题ros2_control中的控制指令究竟是怎么从软件一路送到机器人电机上的答案就不再只是ROS 2。真正的链路往往是ROS 2 ↓ ros2_control ↓ Controller ↓ Hardware Interface ↓ EtherCAT / CAN / PCIe ↓ Linux Driver ↓ 网卡 / 控制器 ↓ 工业总线 ↓ 伺服驱动器 ↓ 电机而当控制频率达到500 Hz、1 kHz甚至更高时真正影响实时性的也不再只是“Controller算法执行得快不快”。数据什么时候到网卡中断什么时候触发驱动什么时候处理控制线程什么时候读取到数据输出指令什么时候发送EtherCAT通信周期是否稳定这些问题都会最终汇聚到一个结果机器人这一周期的控制指令究竟能不能在规定的时间窗口内送到执行器。因此如果说前面的文章解决的是“1 kHz控制线程怎么调度”那么这一篇要进一步解决“1 kHz控制线程如何与真实硬件通信并形成一条完整、可预测的实时控制链路”一、从ros2_control到电机1 kHz机器人控制到底经历了什么先假设我们有一台机械臂。它拥有6个关节 6个伺服驱动器 EtherCAT通信 1 kHz控制周期 ROS 2软件框架 ros2_control控制框架机器人控制器每1ms执行一次读取关节状态 ↓ 计算控制量 ↓ 输出电机指令在ros2_control中可以把它抽象成┌──────────────────────┐ │ Controller │ │ 轨迹 / PID / 控制算法 │ └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ Controller Manager │ └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ Hardware Interface │ └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ EtherCAT │ └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ Servo Drive │ └──────────┬───────────┘ │ ▼ Motor而一个完整周期通常可以进一步理解为T0 │ ├── Read │ ├── Update │ ├── Write │ └── 等待下一周期 ↓ T1如果控制周期是1msT1 - T0 1ms看起来非常简单。但真正的数据流实际上是双向的。从机器人到控制器电机 ↓ 伺服驱动器 ↓ EtherCAT ↓ 网卡/控制器 ↓ 驱动 ↓ Hardware Interface ↓ ros2_control ↓ Controller这条链路负责告诉软件当前位置 当前速度 当前力矩 状态字 错误状态从控制器到机器人Controller ↓ ros2_control ↓ Hardware Interface ↓ EtherCAT ↓ 伺服驱动器 ↓ 电机这条链路负责告诉硬件目标位置 目标速度 目标力矩 控制字所以一个真正的机器人实时控制周期实际上是Read ↓ Compute ↓ Write ↓ Hardware Response ↓ Next Read这就是一个闭环。二、为什么EtherCAT会成为机器人实时控制中的关键一环如果只是普通的网络通信那么很多人会自然想到“ROS 2发消息给电机驱动器不就可以了吗”问题在于机器人控制和普通网络应用对于通信的要求并不完全一样。普通网络通信可能更关心吞吐量 连接稳定性 平均延迟 数据可靠性但机器人控制还要关注周期 同步 抖动 延迟 时间确定性例如目标 1ms发送一次控制指令理想情况0ms 1ms 2ms 3ms 4ms │-------│-------│-------│-------│ ↓ ↓ ↓ ↓ CMD CMD CMD CMD如果实际变成0ms 1.0ms 2.0ms 3.5ms 4.0ms那么平均来看可能并没有特别大的问题。但是3.5ms这一周期产生的额外延迟对于闭环控制来说可能就非常值得关注。这就是通信延迟和通信抖动。EtherCAT之所以大量出现在工业机器人、运动控制等场景中一个重要原因就是它针对工业实时通信场景进行了专门设计。可以简单理解为控制器 │ ▼ EtherCAT Master │ ▼ ┌─────────┐ │ Drive 1 │ └────┬────┘ │ ┌────▼────┐ │ Drive 2 │ └────┬────┘ │ ┌────▼────┐ │ Drive 3 │ └────┬────┘ │ ...多个伺服驱动器可以通过工业以太网形成周期性的数据交换。控制器周期性发送目标位置 目标速度 目标力矩 控制状态同时接收实际位置 实际速度 实际力矩 状态字 故障信息于是形成控制器 ↓ EtherCAT ↓ 伺服驱动器 ↓ 电机 ↓ 机械结构 ↓ 传感器 ↓ EtherCAT ↓ 控制器整个系统形成闭环。三、真正影响1 kHz实时性的不只是EtherCAT而是“中断→驱动→线程”这一整条链这里是机器人实时控制中非常容易被忽略的一层。很多开发者会认为“EtherCAT本身支持实时通信所以我的控制系统自然就是实时的。”实际上并不能这么简单理解。因为数据从硬件到用户态控制程序中间还存在大量软件层。可以把数据接收过程抽象成EtherCAT Frame ↓ 网卡 ↓ 硬件中断 ↓ IRQ ↓ 驱动程序 ↓ 内核处理 ↓ 数据准备 ↓ 控制线程 ↓ Hardware Interface ↓ Controller任何一环发生额外延迟都可能影响整个控制周期。例如EtherCAT帧已经到达 ↓ 网卡产生中断 ↓ CPU正在处理其他任务 ↓ IRQ等待 ↓ 驱动开始处理 ↓ 数据进入软件缓冲区 ↓ 控制线程获得CPU ↓ 读取数据这里至少涉及两个不同的问题问题一硬件数据什么时候到这是通信周期问题。问题二数据到了以后CPU什么时候开始处理这是操作系统调度和中断处理问题。因此工业实时通信 ≠ 操作系统天然实时。EtherCAT可以提供高效、周期性的工业通信能力但最终数据什么时候被CPU处理依然与IRQ Driver Scheduler CPU Memory Lock密切相关。这也是为什么机器人实时控制必须同时考虑通信实时性 操作系统实时性 应用实时性三者缺一不可。四、为什么IRQ Affinity对于1 kHz EtherCAT控制非常重要假设机器人控制线程绑定在CPU6同时我们希望CPU6 专门负责1kHz控制但如果EtherCAT网卡的IRQ也频繁进入CPU6CPU6 │ ├── Control Thread ├── EtherCAT IRQ ├── Network IRQ ├── USB IRQ └── Other IRQ那么所谓的“专用控制CPU”实际上并没有那么干净。因为控制线程 ↓ 正在执行 ↓ 硬件中断到来 ↓ CPU响应IRQ ↓ 控制线程被打断于是控制线程开始时间 ↓ ├── 正常情况 │ └── IRQ介入 ↓ 延迟增加这就是为什么实时系统中经常需要进一步规划IRQ Affinity。例如CPU0 CPU1 CPU2 CPU3 ──────────────────── 网络 USB 普通设备 系统任务 CPU4 CPU5 ──────────────────── 状态估计 ROS 2非实时任务 CPU6 ──────────────────── 1kHz控制线程 CPU7 ──────────────────── EtherCAT相关实时资源当然具体怎么分配需要根据硬件、驱动和系统负载进行测试而不是套用固定的CPU编号。关键思想是让关键实时任务和无关中断尽可能减少资源争用。于是形成完整的实时资源规划Thread Affinity Core Isolation IRQ Affinity Scheduler这四个东西需要放在一起看。五、为什么ros2_control的Hardware Interface也是实时系统的重要边界前面提到Controller ↓ Hardware Interface ↓ EtherCATHardware Interface实际上承担了非常关键的角色。它把机器人控制算法和具体硬件通信方式连接起来。例如Controller只需要知道joint1.position joint1.velocity joint1.effort而Hardware Interface负责知道这些数据到底来自哪个设备 通过EtherCAT还是CAN 对应哪个PDO 如何读取 如何写入 如何处理状态因此Controller更关注“我要什么控制结果”而Hardware Interface更关注“如何把控制结果真正送到硬件”这意味着Hardware Interface本身必须认真考虑实时性。例如一个糟糕的设计可能在read()里面做动态内存分配 复杂日志 文件操作 网络请求 阻塞等待 长时间锁那么即使Controller本身运行得非常稳定1kHz SCHED_FIFO CPU隔离最终仍然可能在Hardware Interface这里出现延迟。因此一个更加合理的实时控制结构应该是ROS 2 │ ▼ Controller │ ▼ ros2_control │ ┌────────┴────────┐ ▼ ▼ read() write() │ │ ▼ ▼ EtherCAT EtherCAT │ │ ▼ ▼ Motor State Motor Command而实时路径应该尽可能保持短 固定 可预测 少阻塞 少分配 少锁竞争六、1 kHz控制为什么还需要“时间同步”如果机器人只有一个电机那么问题相对简单。但假设一台机械臂有6轴或者人形机器人拥有20~40个执行关节那么一个控制周期实际上需要同时处理大量设备。例如Joint1 Joint2 Joint3 Joint4 Joint5 Joint6如果不同关节的数据时间戳存在较大差异Joint110.000ms Joint210.002ms Joint310.020ms Joint410.005ms那么控制器拿到的并不是一个严格意义上的“同一时刻机器人状态”。对于多轴运动控制来说时间同步就非常重要。因此工业实时控制除了关心通信速度还要关心时间同步这也是工业以太网在运动控制场景中需要解决的重要问题。对于机器人来说传感器状态 ↓ 统一时间基准 ↓ 控制算法 ↓ 同步输出 ↓ 多轴执行如果多个轴之间的时间关系不稳定那么即使单个轴的数据延迟都不高整体运动控制也可能受到影响。因此在分析机器人实时性时需要从延迟进一步扩展到延迟 抖动 同步七、为什么“1 kHz EtherCAT 1 kHz控制”仍然不代表系统一定实时现在假设EtherCAT周期1ms Controller周期1ms很多人可能认为1ms 1ms 完美实时其实远远不够。因为整个链路可能是EtherCAT ↓ IRQ ↓ Driver ↓ Buffer ↓ Hardware Interface ↓ Controller ↓ Control Calculation ↓ Hardware Interface ↓ Driver ↓ EtherCAT ↓ Servo如果把每一个环节都考虑进去通信延迟 IRQ延迟 调度延迟 驱动处理时间 read时间 update时间 write时间才是真正需要分析的东西。例如1ms周期 │ ├── 50μs IRQ/Driver ├── 100μs Read ├── 200μs Controller ├── 100μs Write ├── 50μs 调度及其他 └── 500μs 余量如果某一次突然发生IRQ延迟 100μs 控制算法 100μs 锁等待 150μs那么原本500μs 最坏850μs如果再叠加其他系统干扰就可能突破1ms。所以真正需要优化的是整个实时路径的Worst-Case Behavior。而不是单独优化EtherCAT或者单独优化ROS 2。八、把AI、视觉和实时控制放在一起问题会更加明显现代机器人已经不是一台只负责运动控制的机器。同一台设备可能同时运行ROS 2 ros2_control EtherCAT 视觉 3D点云 SLAM AI推理 路径规划 大模型 网络 日志 监控例如CPU0~CPU3 AI / Vision / SLAM / Planning CPU4~CPU5 ROS 2 / State Estimation CPU6 1kHz Control CPU7 实时通信 / Safety这样的资源划分本质上是在建立两个世界实时世界 ────────────── Control Servo Safety Hardware IO 非实时世界 ────────────── AI Vision Planning UI Logging Network实时世界关注什么时候必须执行 最长允许延迟多久 是否会被打断 是否存在资源竞争非实时世界更关注吞吐量 计算能力 任务完成速度两者并不是谁比谁更重要而是目标不同。例如AI推理可能希望GPU持续满载而1kHz控制线程希望CPU资源稳定 调度延迟可预测如果让两者无边界地争抢同一组CPU、内存和系统资源就容易产生不可预测的干扰。因此实时控制系统真正需要的不是“更强的CPU”而是更清晰的资源边界。九、望获rtLinux在这条实时链路中解决的是什么问题把前面的内容全部串起来ROS 2 ↓ ros2_control ↓ Controller ↓ Hardware Interface ↓ EtherCAT ↓ Driver ↓ IRQ ↓ CPU ↓ Servo ↓ Motor可以发现ROS 2解决的是机器人软件模块之间的协作。ros2_control解决的是控制器和硬件之间的标准化连接。EtherCAT解决的是工业设备之间的实时通信。而操作系统需要解决的是线程如何调度 CPU如何分配 IRQ如何处理 资源如何隔离 实时任务如何减少干扰因此操作系统实际上位于整个实时链路的底层。对于机器人、工业控制、运动控制等对实时性、确定性和资源隔离要求较高的场景望获rtLinux可以作为一种实时Linux技术环境选择从操作系统层面对实时调度、核心隔离、资源管理等能力进行支撑。但依然需要强调一个原则实时操作系统 ≠ 应用天然实时真正的实时系统应该是实时OS 实时应用设计 实时驱动 合理CPU规划 IRQ规划 内存管理 通信机制 硬件设计共同形成的。如果只替换操作系统而应用层仍然存在长时间锁 动态内存分配 不可控I/O 大量日志 CPU资源争抢 IRQ干扰 不稳定硬件通信那么实时性仍然可能受到影响。所以从工程角度来看实时系统建设更应该被理解为从应用、调度、资源、驱动到硬件的一体化设计。十、如何真正验证一条1 kHz实时控制链路最后还有一个非常关键的问题怎么证明它真的实时不能只看程序运行起来了也不能只看控制频率显示1000Hz更应该进行系统化测试。例如测试1. 控制周期目标1ms记录最小周期 平均周期 最大周期 周期标准差重点观察最大值和抖动。2. 调度延迟观察线程Ready ↓ 真正获得CPU之间的时间。3. IRQ延迟观察硬件事件 ↓ IRQ处理之间是否存在异常延迟。4. Deadline Miss例如测试周期1,000,000次 Deadline Miss 0或者出现3次 17次就需要进一步分析原因。5. 压力测试不要只测试CPU空闲而应该同时运行视觉 AI SLAM 网络 日志 EtherCAT然后观察控制周期 最大调度延迟 IRQ延迟 CPU利用率 Deadline Miss可以进一步使用Linux实时测试和追踪工具对调度、线程唤醒、IRQ等行为进行分析也可以结合ROS 2自身的trace机制观察应用层执行路径。这些工具的作用是帮助找到实时问题。而不是简单地测一次结果就证明系统一定具备实时性。实时系统验证的核心仍然是持续观察最坏情况并在不同负载和异常条件下进行压力测试。结语机器人实时控制最终是一条从“消息”到“电机”的时间链从ROS 2一路追踪到电机我们终于可以把整个机器人实时控制系统完整地串起来ROS 2 │ ▼ Executor │ ▼ ros2_control │ ▼ Controller │ ▼ Hardware Interface │ ▼ EtherCAT │ ▼ Driver / IRQ │ ▼ CPU │ ▼ Servo Drive │ ▼ Motor │ ▼ Robot Body │ └──────────┐ │ ▼ Sensor Feedback │ ▼ ROS 2这条链路中任何一个环节发生不可预测的延迟都可能最终表现为机器人控制周期抖动。因此真正的1 kHz实时控制并不是简单地ROS 2 EtherCAT 1kHz而是ROS 2 Executor 实时线程 实时调度 CPU隔离 IRQ管理 实时驱动 EtherCAT周期通信 Hardware Interface Controller 电机执行共同构成的。而这也解释了为什么机器人操作系统的“实时性”最终并不是单独某一个软件组件的属性。它是一条完整的系统工程链路。当机器人进一步进入人形机器人、工业机械臂、移动机器人等复杂场景之后还会出现一个更加现实的问题如果ROS 2同时运行控制、感知、AI和规划如何让不同实时等级的任务共享同一台机器却互不干扰这就需要从单纯的CPU隔离进一步进入实时任务隔离、控制域隔离以及多控制周期协同。下一篇可以继续沿着这条线深入《ROS 2多控制周期怎么协同1kHz关节控制、500Hz状态估计和30Hz视觉为什么不能“一锅煮”》这会进一步把前面讲过的调度、核心隔离、资源隔离和ros2_control串起来并进入更接近真实机器人系统架构的设计问题。
RELATED READING

延伸阅读

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