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 实现:四步循环

逐点比较法的实现,我习惯把它拆成四个步骤,循环执行直到终点:

  1. 偏差判别:计算当前偏差F
  2. 坐标进给:根据F的正负,决定走X还是Y
  3. 偏差计算:走完一步后,更新偏差值
  4. 终点判别:检查是否到达终点

代码实现其实很简洁:

// 逐点比较法直线插补(第一象限)
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 知识体系总览

下面这张图是我画的两种算法的核心逻辑对比,帮你快速理清思路:

直线插补算法核心逻辑对比 逐点比较法 核心思想:偏差判别 → 坐标进给 偏差公式:F = xe·yi - ye·xi 特点:每步只走一个轴,阶梯轨迹 适用:低速高精度定位 数字积分法(DDA) 核心思想:速度分量 → 累加溢出 累加器:acc_x += xe, acc_y += ye 特点:可同时走两个轴,轨迹平滑 适用:中高速连续轨迹控制 vs

两种算法各有千秋,没有绝对的好坏。选哪个,取决于你的应用场景和硬件条件。我个人建议初学者先掌握逐点比较法,因为它逻辑简单,容易理解。等把逐点比较法吃透了,再学DDA,你会发现很多概念是相通的。

好了,直线插补的两种经典算法就讲到这里。记住:算法是死的,应用是活的。多动手写代码,多在实际项目中调试,才能真正理解它们的精髓。


专注资料整理