逐点比较法(一):直线插补原理、偏差计算公式推导、进给方向判定规则
各位同学,欢迎来到《多轴联动插补算法深度解析》的第一章。
今天咱们聊一个非常经典、也非常基础的东西——逐点比较法。说实话,这方法听起来有点土,对吧?但你别小看它。我当年刚入行做数控系统时,第一块调通的插补代码就是逐点比较法。那时候没有现成的库,全靠自己一行行写。嗯,现在回想起来,那段经历让我对插补的本质理解得特别透彻。
逐点比较法,说白了就是「走一步,看一步」。每走一步,都算一下当前位置跟理想轨迹的偏差,然后决定下一步往哪走。你想想看,这不就是咱们平时走路找方向的感觉吗?
一、直线插补的基本思想
先说说直线插补。我们要让刀具从起点A走到终点B,走一条直线。但问题是,数控系统的进给轴只能走正交的步进——要么走X方向,要么走Y方向,不能同时走斜线。
那怎么办?
逐点比较法的思路是:用折线逼近直线。每一步都判断当前位置是在直线的哪一侧,然后朝着靠近直线的方向走一步。
我举个例子。假设起点是(0,0),终点是(4,3)。理想轨迹是一条斜线。实际走出来的路径,是一系列台阶状的折线。只要步长足够小,这条折线跟直线的误差就在允许范围内。
这里有个关键点:每一步只走一个脉冲当量。要么X走一步,要么Y走一步。这就是「逐点比较」这个名字的由来——每走一个点,都要比较一下。
核心思想总结:逐点比较法是一种基于偏差判别和误差补偿的插补方法。它不依赖复杂的三角函数计算,而是通过简单的加减法和符号判断来实现轨迹逼近。
二、偏差计算公式推导
好,接下来咱们推导偏差公式。这部分是重点,也是很多同学觉得头疼的地方。别急,我带你一步步来。
假设我们要插补的直线起点为原点O(0,0),终点为E(Xe, Ye)。当前刀具位置为P(Xi, Yi)。
怎么判断P点在直线的哪一侧?
用矢量叉积。直线OE的矢量是(Xe, Ye),当前点P的矢量是(Xi, Yi)。这两个矢量的叉积,就是判断P点相对于直线OE的位置。
叉积公式:
F = Xe × Yi - Xi × Ye
这个F就是我们的偏差值。
为什么是这个公式?我简单解释一下。叉积的几何意义是平行四边形面积。如果F > 0,说明P点在直线的上方(或左侧,取决于坐标系定义);如果F < 0,说明P点在直线的下方(或右侧);如果F = 0,说明P点正好在直线上。
嗯,这里要注意:F的正负决定了进给方向。
那问题来了:每次都要重新算这个乘法,计算量是不是太大了?
别担心,我们有递推公式。这才是逐点比较法的精髓。
三、递推公式的推导
假设当前点P(Xi, Yi)的偏差为Fi = Xe×Yi - Xi×Ye。
情况一:Fi ≥ 0
说明P点在直线上方或线上。这时候我们走一步+X方向。新位置为(Xi+1, Yi)。
新偏差:
Fi+1 = Xe × Yi - (Xi+1) × Ye
= Xe × Yi - Xi × Ye - Ye
= Fi - Ye
情况二:Fi < 0
说明P点在直线下方。这时候我们走一步+Y方向。新位置为(Xi, Yi+1)。
新偏差:
Fi+1 = Xe × (Yi+1) - Xi × Ye
= Xe × Yi + Xe - Xi × Ye
= Fi + Xe
你看,递推公式只需要做加减法,没有乘法!这在早期的数控系统里,可是大大的优势。我记得当年用8位单片机做插补,乘法指令要几十个时钟周期,而加减法只要几个周期。这个优化,直接决定了系统能不能跑实时。
个人经验:我在做一款经济型数控系统时,CPU主频只有16MHz。如果用直接公式做插补,每步要算乘法,根本跑不到目标进给速度。改成递推公式后,插补周期从200μs降到了30μs。这个优化,让系统从「勉强能用」变成了「流畅运行」。
四、进给方向判定规则
有了偏差公式,进给方向的判定就很简单了。我整理成一张表,方便你查阅。
| 偏差符号 | 进给方向 | 偏差递推公式 |
|---|---|---|
| Fi ≥ 0 | +X方向 | Fi+1 = Fi - Ye |
| Fi < 0 | +Y方向 | Fi+1 = Fi + Xe |
这个规则适用于第一象限的直线插补。其他象限的规则类似,只是符号需要调整。后面章节我会详细讲。
这里有个容易踩的坑:终点判断。你不能一直走,得知道什么时候停下来。
终点判断的方法很简单:
- 方法一:累计步数。总步数 = Xe + Ye(以脉冲当量计)。每走一步,计数器减1。减到0就停。
- 方法二:坐标比较。当X坐标达到Xe且Y坐标达到Ye时,停止。
我个人习惯用方法一,因为实现简单,而且不容易出错。
避坑指南:我曾经在一个项目中,用坐标比较法做终点判断。结果因为累加误差,X坐标永远达不到Xe的精确值,导致插补停不下来。后来改成步数计数法,问题就解决了。所以,能用计数法就别用比较法,这是血的教训。
五、完整插补流程
把上面的内容串起来,逐点比较法直线插补的完整流程如下:
- 初始化:设置起点(0,0),终点(Xe,Ye),总步数N = Xe + Ye,偏差F = 0。
- 偏差判别:判断F的符号。
- 进给:根据F符号,决定走+X还是+Y。
- 偏差计算:用递推公式更新F值。
- 终点判断:步数计数器减1。如果为0,停止;否则回到步骤2。
你看,就这么简单。没有复杂的数学,没有高深的算法。但就是这套方法,支撑了早期数控系统的半壁江山。
六、代码示例
最后,我给出一个C语言的实现片段。你可以在自己的平台上跑一跑,感受一下。
// 逐点比较法直线插补(第一象限)
void line_interpolate(int Xe, int Ye) {
int F = 0; // 偏差
int step = Xe + Ye; // 总步数
int x = 0, y = 0; // 当前位置
while (step > 0) {
if (F >= 0) {
// +X方向进给
x++;
F -= Ye;
} else {
// +Y方向进给
y++;
F += Xe;
}
step--;
// 输出当前点坐标(实际应用中发送脉冲)
printf("(%d, %d)\n", x, y);
}
}
这段代码虽然简单,但包含了逐点比较法的全部核心逻辑。你可以在自己的开发板上试试,看看走出来的轨迹是不是一条直线。
七、小结
这一章我们讲了逐点比较法的基本原理、偏差公式的推导、递推公式的优化,以及进给方向的判定规则。
说白了,逐点比较法就是「走一步看一步」的智慧。它不需要高深的数学,不需要昂贵的硬件,靠的是巧妙的递推思想和简单的加减法运算。
下一章,我会讲逐点比较法在其他象限的推广,以及如何处理圆弧插补。到时候你会发现,核心思想是一样的,只是偏差公式的形式变了。
好,今天就到这里。如果你在实现中遇到问题,欢迎交流。记住,动手写代码才是最好的学习方式。