4. 逐点比较法实现:偏差计算、进给方向判定、终点判别

逐点比较法,说白了就是让刀具一步一步“摸着石头过河”。

每走一步,都算算当前位置跟理想圆弧差了多少。然后决定下一步往哪走。就这么简单。

我刚开始做数控系统那会儿,觉得这方法太笨了。后来才发现,它稳定、可靠,特别适合硬件资源有限的嵌入式系统。你想想看,没有浮点运算器,没有三角函数库,照样能走出漂亮的圆弧。

4.1 核心思想:步步为营

逐点比较法的核心逻辑就三个步骤:

  1. 偏差计算:算一下当前点离圆弧有多远
  2. 进给方向判定:根据偏差值,决定下一步往X还是Y方向走
  3. 终点判别:看看走完了没有

这三个步骤循环执行,直到终点。嗯,就这么简单粗暴。

关键理解:逐点比较法不是一次算出整条轨迹,而是每走一步算一次。这种“边走边算”的方式,天然适合实时控制。

4.2 偏差计算:怎么判断偏了?

假设我们要加工第一象限的逆圆弧。圆心在原点,半径为R。当前刀具在点P(x, y)。

偏差值F的定义很简单:

F = x² + y² - R²

为什么这么定义?

  • 如果F = 0,说明点P正好在圆弧上
  • 如果F > 0,说明点P在圆弧外侧(离圆心远了)
  • 如果F < 0,说明点P在圆弧内侧(离圆心近了)

我记得第一次在示波器上看这个偏差值的变化,特别有意思。它就像个“指南针”,告诉你该往哪个方向修正。

我的经验:实际项目中,偏差值F可能很大。我习惯用递推公式来算,避免每次都做平方运算。后面会讲到。

4.3 进给方向判定:往哪走?

判定规则其实很直观:

  • 如果F ≥ 0(在圆弧上或外侧),下一步向-X方向走一步
  • 如果F < 0(在圆弧内侧),下一步向+Y方向走一步

为什么会这样?你想想看:

当F ≥ 0时,刀具偏外了。我们需要让它往圆心方向走,也就是X负方向。当F < 0时,刀具偏内了,需要让它远离圆心,也就是Y正方向。

这个逻辑,说白了就是“哪边偏了就往反方向修”。

注意:不同象限、顺圆逆圆的进给方向都不一样。我曾经在项目里搞混过顺圆和逆圆的判定规则,结果走出来的圆弧反了。后来我画了个象限图贴在工位上,再也没错过。

4.4 终点判别:怎么知道走完了?

终点判别有三种常用方法:

方法 原理 优缺点
总步数法 预先计算X和Y方向的总步数,每走一步减1 简单可靠,我最常用
坐标比较法 实时比较当前坐标与终点坐标 需要做减法,但更直观
偏差值法 当偏差值连续变化到某个阈值时停止 精度可控,但实现复杂

我个人习惯用总步数法。为什么?因为它不依赖坐标值,不会因为坐标累加误差导致终点判不准。

4.5 递推公式:别每次都算平方

如果每次都用F = x² + y² - R²,计算量太大了。尤其是早期数控系统,CPU性能有限。

所以,我们用递推公式。假设当前点偏差为F,走一步之后的新偏差F'可以这样算:

向-X方向走一步(x' = x - 1):

F' = (x-1)² + y² - R²
   = x² - 2x + 1 + y² - R²
   = F - 2x + 1

向+Y方向走一步(y' = y + 1):

F' = x² + (y+1)² - R²
   = x² + y² + 2y + 1 - R²
   = F + 2y + 1

你看,只需要做加法和移位操作,连乘法都省了。这就是逐点比较法能在8位单片机上跑起来的原因。

核心公式

  • 向-X走:F' = F - 2x + 1
  • 向+Y走:F' = F + 2y + 1

记住这两个公式,整个逐点比较法就掌握了一半。

4.6 完整流程:一个例子走一遍

假设我们要从点A(4, 0)到点B(0, 4),走第一象限逆圆弧。半径R=4。

总步数 = |4-0| + |0-4| = 8步。

初始偏差F₀ = 4² + 0² - 4² = 0。

走几步看看:

步数 当前点 偏差F 判定 进给方向 新偏差F'
0 (4, 0) 0 F ≥ 0 -X 0 - 2×4 + 1 = -7
1 (3, 0) -7 F < 0 +Y -7 + 2×0 + 1 = -6
2 (3, 1) -6 F < 0 +Y -6 + 2×1 + 1 = -3
3 (3, 2) -3 F < 0 +Y -3 + 2×2 + 1 = 2
4 (3, 3) 2 F ≥ 0 -X 2 - 2×3 + 1 = -3
5 (2, 3) -3 F < 0 +Y -3 + 2×3 + 1 = 4
6 (2, 4) 4 F ≥ 0 -X 4 - 2×2 + 1 = 1
7 (1, 4) 1 F ≥ 0 -X 1 - 2×1 + 1 = 0
8 (0, 4) 0 终点 - -

走完8步,正好到终点。完美。

避坑指南:我曾经在调试时发现,终点处偏差不为0。后来查了半天,发现是步长设置问题。逐点比较法默认步长为1,如果你用细分步长(比如0.1mm),记得调整递推公式里的系数。

4.7 代码实现:C语言版

下面是一个完整的逐点比较法圆弧插补函数。我尽量写得简洁,方便你移植到自己的项目里。

// 第一象限逆圆弧逐点比较法插补
// start_x, start_y: 起点坐标
// end_x, end_y: 终点坐标
// radius: 圆弧半径
void arc_interpolate(int start_x, int start_y, int end_x, int end_y, int radius) {
    int x = start_x;
    int y = start_y;
    int F = x*x + y*y - radius*radius;  // 初始偏差
    int steps = abs(end_x - start_x) + abs(end_y - start_y);  // 总步数
    
    while (steps > 0) {
        // 偏差判定和进给
        if (F >= 0) {
            // 向-X方向走一步
            x--;
            F = F - 2*x - 1;  // 注意:这里x已经减1了,所以公式变成F - 2x - 1
        } else {
            // 向+Y方向走一步
            y++;
            F = F + 2*y - 1;  // 同理,y已经加1了
        }
        
        steps--;
        
        // 这里可以输出当前坐标,或者驱动电机
        // printf("Step %d: (%d, %d), F=%d\n", steps, x, y, F);
    }
}

注意:代码里的递推公式跟前面推导的略有不同,因为x和y的值在计算前已经更新了。写代码时一定要搞清楚“先更新坐标还是先算偏差”,顺序错了结果全乱套。

4.8 知识体系总览

下面这张图,把逐点比较法的核心逻辑串起来了。我建议你把它存下来,调试的时候对照着看。

逐点比较法圆弧插补核心逻辑 开始插补 偏差计算 F = x²+y²-R² F ≥ 0 ? 向 -X 方向走一步 F' = F - 2x + 1 向 +Y 方向走一步 F' = F + 2y + 1 到达终点? 插补结束 图例 开始/结束 计算/动作 判断

这张图把整个流程串起来了。你顺着箭头走一遍,就是一次完整的插补过程。

4.9 我的几点体会

  • 别小看逐点比较法:虽然它看起来简单,但在很多工业场景下,它比复杂的插补算法更可靠。我见过一些高端数控系统,在低速高精度加工时,反而会切回逐点比较法。
  • 注意象限切换:不同象限的进给方向不同。我习惯在代码里用查表法,把8种情况(4个象限 × 顺圆/逆圆)的进给方向提前算好,运行时直接查表,又快又不容易出错。
  • 速度控制:逐点比较法天然是匀速的——每走一步时间固定。但如果你需要变速,可以在进给方向判定后,插入一个延时函数。延时长短决定进给速度。

最后说一句:逐点比较法就像学骑自行车——刚开始觉得别扭,掌握了之后发现它特别自然。多写几遍代码,多跑几个例子,你就能找到感觉。


公众号:蓝海资料掘金营,微信deep3321