3. 直线插补算法详解:逐点比较法与数字积分法
大家好,我是老张。今天咱们来聊聊直线插补里两个最经典的算法——逐点比较法和数字积分法(DDA)。这两个算法,说白了就是让电机走出直线的两种不同思路。我在做数控系统那几年,这两种算法都亲手调过,各有各的脾气。
核心知识点速览
- 逐点比较法:每一步都判断当前位置偏离直线的方向,然后决定下一步怎么走
- 数字积分法(DDA):用积分的思想,把直线运动分解成两个轴的速度分量
- 两种算法在精度、速度、实现难度上各有优劣
3.1 逐点比较法:一步一个脚印
逐点比较法,名字已经说得很明白了——每走一步,就停下来比较一下当前位置和理想直线的偏差。我刚开始接触这个算法时,觉得它有点笨,但后来发现,这种"笨办法"反而最可靠。
3.1.1 原理:偏差决定方向
假设我们要从原点(0,0)走到终点(xe, ye),走一条直线。逐点比较法的核心就一句话:偏差大于0往一个方向走,小于0往另一个方向走。
偏差怎么算?很简单:
F = xe * yi - ye * xi
其中(xi, yi)是当前位置。如果F=0,说明点在直线上;F>0,点在直线上方;F<0,点在直线下方。
嗯,这里要注意:我们只讨论第一象限的情况。其他象限通过坐标变换处理,原理一样。
3.1.2 实现:四步循环
逐点比较法的实现,我习惯把它拆成四个步骤,循环执行直到终点:
- 偏差判别:计算当前偏差F
- 坐标进给:根据F的正负,决定走X还是Y
- 偏差计算:走完一步后,更新偏差值
- 终点判别:检查是否到达终点
代码实现其实很简洁:
// 逐点比较法直线插补(第一象限)
void point_by_point(int xe, int ye) {
int x = 0, y = 0;
int F = 0; // 初始偏差为0
int steps = xe + ye; // 总步数
while (steps > 0) {
if (F >= 0) {
// 走X正方向
x++;
F -= ye;
} else {
// 走Y正方向
y++;
F += xe;
}
steps--;
// 输出脉冲或更新位置
}
}
你看,代码就这么几行。我在一个老式的步进电机控制板上跑过这个算法,晶振才8MHz,但跑起来一点问题没有。
避坑指南:我曾经在终点判断上吃过亏。如果用总步数判断,一定要确保xe+ye不会溢出。后来我改用坐标比较法,虽然多几行代码,但更安全。
3.2 数字积分法(DDA):用积分思想走直线
数字积分法,简称DDA(Digital Differential Analyzer)。这个算法的思路和逐点比较法完全不同——它把直线运动看成是两个轴速度的合成。
3.2.1 原理:速度分量与累加
你想想看,从起点到终点走直线,X轴和Y轴的速度比例应该是固定的。DDA就是模拟这个比例关系。
具体来说:
- X轴速度分量:Vx = xe / N
- Y轴速度分量:Vy = ye / N
其中N是累加次数。每次累加,如果累加器溢出,就发一个脉冲走一步。
说白了,DDA就是用两个累加器分别模拟X轴和Y轴的速度,谁先溢出谁就先走一步。
3.2.2 实现:累加器与溢出
DDA的实现比逐点比较法稍微复杂一点,但思路很清晰:
// DDA直线插补(第一象限)
void dda_line(int xe, int ye) {
int x = 0, y = 0;
int acc_x = 0, acc_y = 0;
int N = max(xe, ye); // 累加次数
int steps = N;
while (steps > 0) {
acc_x += xe;
acc_y += ye;
if (acc_x >= N) {
x++;
acc_x -= N;
}
if (acc_y >= N) {
y++;
acc_y -= N;
}
steps--;
// 输出脉冲或更新位置
}
}
这里有个细节:累加器用N作为比较阈值,N通常取终点坐标中较大的那个。这样能保证走完N步后,两个轴都刚好到达终点。
注意:DDA的累加器位数要足够。我见过有人用8位累加器,结果坐标值一大就溢出乱跑。建议至少用16位累加器,或者用移位处理。
3.3 两种算法对比:谁更胜一筹?
两种算法我都用过,说实话没有绝对的好坏,关键看应用场景。下面这张表是我个人的经验总结:
| 对比项 | 逐点比较法 | 数字积分法(DDA) |
|---|---|---|
| 精度 | 最大偏差不超过1个脉冲当量 | 存在累积误差,最大偏差约0.5个脉冲当量 |
| 速度均匀性 | 速度波动较大,尤其在45度线附近 | 速度均匀性好,适合连续运动 |
| 实现复杂度 | 简单,只需加减法 | 稍复杂,需要乘法和比较 |
| 计算开销 | 每步只需一次加减 | 每步需要两次加法和两次比较 |
| 适用场景 | 低速、高精度定位 | 中高速、连续轨迹控制 |
我个人习惯:做雕刻机这种需要精确定位的设备,用逐点比较法;做机器人轨迹控制这种需要速度平滑的,用DDA。
3.3.1 精度对比:谁更准?
逐点比较法的最大偏差不会超过1个脉冲当量,这是它的优势。但DDA的偏差其实更小,平均偏差只有0.25个脉冲当量左右。
为什么会这样?因为逐点比较法每次只走一个轴,轨迹是阶梯状的;而DDA可以同时走两个轴,轨迹更接近直线。
3.3.2 速度对比:谁更快?
这里说的"快"不是计算速度,而是运动速度的均匀性。DDA在这方面完胜。
我记得有一次调试一个高速点胶机,用逐点比较法时,胶水在拐角处总是堆积。换成DDA后,速度均匀了,胶水也均匀了。
我的建议:
- 如果追求绝对精度,选逐点比较法
- 如果追求速度平滑,选DDA
- 如果计算资源紧张,选逐点比较法
- 如果做多轴联动,DDA更容易扩展
3.4 知识体系总览
下面这张图是我画的两种算法的核心逻辑对比,帮你快速理清思路:
两种算法各有千秋,没有绝对的好坏。选哪个,取决于你的应用场景和硬件条件。我个人建议初学者先掌握逐点比较法,因为它逻辑简单,容易理解。等把逐点比较法吃透了,再学DDA,你会发现很多概念是相通的。
好了,直线插补的两种经典算法就讲到这里。记住:算法是死的,应用是活的。多动手写代码,多在实际项目中调试,才能真正理解它们的精髓。