3. 逐点比较法(二):直线插补的终点判别方法,插补计算流程与实例

上一章我们把逐点比较法的核心——偏差判别和进给方向讲清楚了。但有个问题一直悬着:什么时候停下来?

你想想看,电机每走一步,我们就算一次偏差、判一次方向、发一次脉冲。如果不知道终点在哪,电机就会一直跑下去,要么撞限位,要么画出一条无限长的线。所以,终点判别是插补算法里不可或缺的一环。

我个人习惯把终点判别比作「导航里的目的地提醒」。没有它,你开再好的车也到不了站。

3.1 终点判别的三种常见方法

在实际的数控系统和运动控制器里,终点判别主要有三种实现方式。我挨个给你讲清楚。

方法名称 原理简述 适用场景
总步数法 预先计算 X 和 Y 方向的总步数,每走一步减 1,减到 0 即停止 最常用,适合绝大多数直线插补
坐标比较法 实时比较当前坐标与终点坐标,两者相等时停止 需要绝对位置反馈的场合
象限投影法 将终点坐标投影到各轴,分别判断各轴是否到达 多轴联动或非正交坐标系

重点提醒:绝大多数商用数控系统和运动控制卡,默认采用总步数法。原因很简单——计算量小、逻辑清晰、不容易出错。

3.2 总步数法详解

总步数法的思路非常直接:

  1. 设起点为 (0, 0),终点为 (Xe, Ye)。
  2. 总步数 N = |Xe| + |Ye|。
  3. 每走一步,N = N - 1。
  4. 当 N = 0 时,插补结束。

这里有个细节我当年踩过坑——绝对值。不管终点在哪个象限,步数永远是正的。你想想,如果终点在第二象限,Xe 是负数,直接相加会出问题。

我曾经在调试一台三轴雕刻机时,忘了对终点坐标取绝对值。结果电机在负方向一直走,走到机械限位才停下来。那次差点把丝杠顶弯。从那以后,我写终点判别代码时,第一行一定是 abs()。

3.3 插补计算完整流程

把偏差判别、进给方向和终点判别串起来,就是逐点比较法直线插补的完整流程。我习惯用下面这张图来给团队新人做培训:

逐点比较法直线插补完整流程图 开始插补 初始化:F=0, N=|Xe|+|Ye| 当前坐标 (0,0) N = 0 ? 插补结束 F ≥ 0 ? +X 方向进给 +Y 方向进给 更新偏差 F 和当前坐标 (X, Y) 总步数 N = N - 1 说明:每次进给后先更新偏差和坐标,再判断终点。循环往复,直到 N=0。 第一象限直线插补,终点 (Xe, Ye),起点 (0, 0)。

这个流程看起来有点复杂,但核心就三个动作:判方向 → 走一步 → 减步数。循环往复,直到步数为零。

3.4 完整实例:第一象限直线插补

光讲理论不够,我们跑一个完整的例子。假设终点为 (4, 3),起点为 (0, 0)。

先算总步数:N = |4| + |3| = 7。

下面是每一步的详细计算过程:

步数 当前点 偏差 F F ≥ 0 ? 进给方向 新偏差计算 新坐标 剩余步数
0 (0, 0) 0 是 +X F = 0 - 3 = -3 (1, 0) 6
1 (1, 0) -3 否 +Y F = -3 + 4 = 1 (1, 1) 5
2 (1, 1) 1 是 +X F = 1 - 3 = -2 (2, 1) 4
3 (2, 1) -2 否 +Y F = -2 + 4 = 2 (2, 2) 3
4 (2, 2) 2 是 +X F = 2 - 3 = -1 (3, 2) 2
5 (3, 2) -1 否 +Y F = -1 + 4 = 3 (3, 3) 1
6 (3, 3) 3 是 +X F = 3 - 3 = 0 (4, 3) 0

你看,走了 7 步,正好到达终点 (4, 3)。每一步的偏差计算和进给方向都符合我们上一章讲的规则。

一个小技巧:我习惯在调试时把每一步的坐标打印出来,然后用 Excel 画个散点图。一眼就能看出插补轨迹是不是对的。如果轨迹明显偏离理论直线,多半是偏差计算公式写反了。

3.5 其他象限的处理

刚才的例子只针对第一象限。其他象限怎么办?

其实原理一样,只是进给方向要跟着象限变。我直接给你一个对照表:

象限 F ≥ 0 进给方向 F < 0 进给方向
第一象限 +X +Y
第二象限 -X +Y
第三象限 -X -Y
第四象限 +X -Y

嗯,这里要注意:偏差计算公式不变,变的只是进给方向。我见过不少新手把偏差公式也改了,结果轨迹全乱套。

3.6 代码实现示例

最后,给你一段 C 风格的伪代码。这是我当年在 STM32 上跑过的版本,稍微简化了一下:

// 逐点比较法直线插补(第一象限)
void line_interpolate(int Xe, int Ye) {
    int F = 0;          // 偏差
    int N = abs(Xe) + abs(Ye);  // 总步数
    int X = 0, Y = 0;   // 当前坐标

    while (N > 0) {
        if (F >= 0) {
            // +X 方向进给
            X++;
            F = F - Ye;
        } else {
            // +Y 方向进给
            Y++;
            F = F + Xe;
        }
        N--;  // 步数减一

        // 输出脉冲或更新位置
        output_step(X, Y);
    }
}

这段代码虽然简单,但核心逻辑都在里面了。实际工程中,你还需要考虑象限判断、加减速处理、脉冲输出频率控制等。不过那是后面章节的内容了。

核心要点回顾:

  • 终点判别最常用的是总步数法,N = |Xe| + |Ye|
  • 插补流程:初始化 → 终点判别 → 偏差判别 → 进给 → 更新 → 循环
  • 不同象限只改变进给方向,不改变偏差计算公式
  • 调试时建议打印每一步坐标,用图表验证轨迹