4. 逐点比较法实现:偏差计算、进给方向判定、终点判别
逐点比较法,说白了就是让刀具一步一步“摸着石头过河”。
每走一步,都算算当前位置跟理想圆弧差了多少。然后决定下一步往哪走。就这么简单。
我刚开始做数控系统那会儿,觉得这方法太笨了。后来才发现,它稳定、可靠,特别适合硬件资源有限的嵌入式系统。你想想看,没有浮点运算器,没有三角函数库,照样能走出漂亮的圆弧。
4.1 核心思想:步步为营
逐点比较法的核心逻辑就三个步骤:
- 偏差计算:算一下当前点离圆弧有多远
- 进给方向判定:根据偏差值,决定下一步往X还是Y方向走
- 终点判别:看看走完了没有
这三个步骤循环执行,直到终点。嗯,就这么简单粗暴。
关键理解:逐点比较法不是一次算出整条轨迹,而是每走一步算一次。这种“边走边算”的方式,天然适合实时控制。
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 知识体系总览
下面这张图,把逐点比较法的核心逻辑串起来了。我建议你把它存下来,调试的时候对照着看。
这张图把整个流程串起来了。你顺着箭头走一遍,就是一次完整的插补过程。
4.9 我的几点体会
- 别小看逐点比较法:虽然它看起来简单,但在很多工业场景下,它比复杂的插补算法更可靠。我见过一些高端数控系统,在低速高精度加工时,反而会切回逐点比较法。
- 注意象限切换:不同象限的进给方向不同。我习惯在代码里用查表法,把8种情况(4个象限 × 顺圆/逆圆)的进给方向提前算好,运行时直接查表,又快又不容易出错。
- 速度控制:逐点比较法天然是匀速的——每走一步时间固定。但如果你需要变速,可以在进给方向判定后,插入一个延时函数。延时长短决定进给速度。
最后说一句:逐点比较法就像学骑自行车——刚开始觉得别扭,掌握了之后发现它特别自然。多写几遍代码,多跑几个例子,你就能找到感觉。
公众号:蓝海资料掘金营,微信deep3321