1. 运动控制器系统架构与实时执行引擎概览
运动控制器并不是一块“会发脉冲的板卡”,而是一套从上层指令到电机电流的完整数据通路。理解这条通路,是后续学习插补算法、轨迹队列调度和实时执行引擎的前提。本章先建立整体架构视图:一条运动指令从下发到电机转动,中间经过了哪些环节,每个环节负责什么,边界在哪里,以及它们如何协作。
一、从指令到电机:完整数据流
以典型的“直线插补到目标点”为例,一条运动指令的完整生命周期大致如下:
- 指令下发层:上位机(PC、HMI 或 PLC)通过 EtherCAT、Modbus TCP、串口或厂商私有协议,把“以 200 mm/s 走到 (100, 50) mm”这样的目标指令发给控制器。这一层只关心“做什么”,不关心“怎么走”。
- 指令解析与规划层:控制器把目标指令翻译成内部运动描述,包括起点、终点、速度、加速度、加减速方式(梯形或 S 曲线)、插补类型(直线/圆弧/螺旋)。这一层输出的是“几何路径 + 速度规划参数”。
- 插补器:把连续路径离散成一个个插补周期(例如 1 ms)内的位置增量。直线插补按比例分配各轴增量,圆弧插补按圆心和半径逐周期计算角度增量。插补器输出的是“每个周期各轴应到达的位置”。
- 轨迹队列:插补器产生的点不会立刻全部送给执行引擎,而是先进入轨迹队列缓冲。队列的作用是解耦“规划速度”和“执行速度”,让规划可以提前算、执行可以稳定取,避免因计算抖动导致电机顿挫。
- 实时执行引擎:以固定周期(如 1 ms)从队列取点,做位置闭环或前馈控制,输出速度/转矩指令给伺服驱动器。
- 伺服驱动与电机:驱动器完成电流环、速度环,驱动电机转动,编码器反馈位置回到执行引擎,形成闭环。
这条链路中,插补器决定“路径形状”,轨迹队列决定“节奏与缓冲”,实时执行引擎决定“每个周期的实际输出”。三者职责不同,但必须协同工作。
二、插补器、轨迹队列与执行引擎的职责边界
很多初学者会把这三者混为一谈,导致调试时定位错误。下面用一张职责对照表说明它们的边界。
| 模块 | 核心职责 | 输入 | 输出 | 不负责的事 |
|---|---|---|---|---|
| 插补器 | 把连续路径离散成周期位置点 | 几何路径、速度规划参数 | 各轴每周期位置增量 | 不关心队列是否满、电机是否响应 |
| 轨迹队列 | 缓冲插补点,解耦规划与执行 | 插补器输出的点 | 按周期供执行引擎取点 | 不修改路径几何、不做闭环修正 |
| 实时执行引擎 | 按固定周期输出控制量并闭环 | 队列取出的目标位置、编码器反馈 | 速度/转矩指令 | 不重新规划路径、不改变插补类型 |
举例说明边界的重要性:如果电机在圆弧段出现轻微抖动,问题可能出在执行引擎的闭环增益,也可能出在轨迹队列取点节奏不稳,还可能是插补器输出的圆弧点本身不均匀。只有明确三者边界,才能逐层排查。
三、实时执行引擎的关键约束
实时执行引擎的核心约束是周期确定性。以 1 ms 周期为例,每个周期必须完成:从队列取点、读取编码器、计算控制量、输出指令。如果某个周期因为计算量过大或中断延迟导致超时,电机就会感受到一次“顿挫”。
因此,实时执行引擎通常运行在 RTOS 或带实时补丁的 Linux 上,采用高优先级任务 + 硬件定时器触发。插补和规划可以放在非实时任务中提前计算,但执行引擎的取点和输出必须严格按时发生。
四、协作关系:谁先谁后,谁等谁
三者的协作可以概括为“规划提前跑,队列做缓冲,执行按节拍取”。规划层和插补器可以比执行引擎快很多,它们把未来若干个周期的点提前算好放进队列;执行引擎每个周期只做“取一个点、算一次控制、发一次指令”的固定动作。这样,即使规划偶尔卡顿,只要队列里还有点,电机就不会停。
反过来,如果队列满了,插补器就必须等待,不能继续往里塞点。这个“等待”信号会反向传递给规划层,形成背压。背压机制保证了内存不会无限增长,也保证了规划速度不会脱离执行能力。
五、一个具体的数值示例
假设控制器插补周期为 1 ms,执行引擎周期也是 1 ms,轨迹队列深度为 50。当前执行一条直线运动:起点 (0, 0),终点 (100 mm, 50 mm),合成速度 200 mm/s。
- 路径长度 = √(100² + 50²) ≈ 111.8 mm
- 总运动时间 ≈ 111.8 / 200 ≈ 0.559 s = 559 ms
- 需要插补点数 ≈ 559 个(每毫秒一个点)
- X 轴每周期增量 = 100 / 559 ≈ 0.179 mm
- Y 轴每周期增量 = 50 / 559 ≈ 0.089 mm
插补器按上述增量逐周期生成点,放入队列。执行引擎每 1 ms 从队列取一个点,作为位置目标送给伺服。如果队列深度为 50,则规划层最多可以提前 50 ms 计算,超过后必须等待执行引擎消费。这个例子中,559 个点会在约 559 ms 内被消费完,队列始终处于“有缓冲但不溢出”的状态。