一、直线插补原理:逐点比较法与数字积分法(DDA)

大家好,我是老张。今天咱们聊聊直线插补。

插补这东西,说白了就是让机床走出我们想要的轨迹。你给个起点终点,插补算法负责算出中间那些点。我刚开始做运动控制时,总觉得这玩意儿很简单——不就是两点一线吗?后来踩了不少坑才明白,插补的精度和效率,直接决定了加工质量。

这一章,我重点讲两种最经典的直线插补方法:逐点比较法数字积分法(DDA)。这两种方法,一个偏逻辑判断,一个偏数值累加,思路完全不同,但都能实现直线插补。

核心要点:

  • 逐点比较法:每一步都判断当前位置与理想直线的偏差,决定下一步走向
  • 数字积分法:用累加运算模拟积分过程,生成脉冲序列
  • 两者都能实现直线插补,但适用场景不同
直线插补原理知识体系 直线插补 逐点比较法 偏差判别 坐标进给 偏差计算 数字积分法(DDA) 累加运算 溢出脉冲 终点判断 两者本质:用离散脉冲逼近连续直线

3.1 逐点比较法——一步一个脚印

逐点比较法,名字就说明了它的思路:每走一步,都拿当前位置跟理想直线比一比,看看偏了没有,然后决定下一步往哪走。

我记得刚入行时,带我的老师傅说:「插补就像走路,走歪了赶紧纠正,别等偏到沟里再回头。」这话糙理不糙,逐点比较法就是这个道理。

3.1.1 基本原理

假设我们要从原点(0,0)走到终点(Xe,Ye)。理想直线就是连接这两点的线段。每一步,我们计算一个偏差值F:

F = Xe * Yi - Ye * Xi

其中(Xi,Yi)是当前位置。你想想看:

  • 如果F=0,说明正好在直线上
  • 如果F>0,说明在直线上方
  • 如果F<0,说明在直线下方

然后根据偏差决定进给方向:

  • F≥0时,向+X方向走一步
  • F<0时,向+Y方向走一步

我的经验:实际项目中,偏差计算可以用递推公式来优化,避免每次都做乘法。比如F≥0走+X后,新偏差F' = F - Ye;F<0走+Y后,新偏差F' = F + Xe。这样只用加减法,速度快很多。

3.1.2 实现步骤

逐点比较法的流程,说白了就是四步循环:

  1. 偏差判别:计算当前偏差F
  2. 坐标进给:根据F的正负决定走X还是Y
  3. 偏差计算:用递推公式更新F
  4. 终点判断:检查是否到达终点

代码实现也很直接:

// 逐点比较法直线插补
void line_interpolation_pc(int Xe, int Ye) {
    int X = 0, Y = 0;
    int F = 0;
    int steps = Xe + Ye;  // 总步数
    
    while (steps > 0) {
        if (F >= 0) {
            X++;           // 向+X走一步
            F -= Ye;       // 更新偏差
        } else {
            Y++;           // 向+Y走一步
            F += Xe;       // 更新偏差
        }
        steps--;
        // 输出脉冲到电机
        output_pulse(X, Y);
    }
}

注意:这段代码只处理了第一象限的情况。实际项目中要处理8个象限和坐标轴方向,需要根据终点坐标的符号做分支判断。我曾经在一个项目中忘了处理负坐标,结果机床直接往反方向跑...嗯,从那以后我写插补代码第一件事就是做象限判断。

3.2 数字积分法(DDA)——用累加逼近直线

数字积分法,英文叫Digital Differential Analyzer,简称DDA。这名字听着高大上,其实原理很简单——用累加器模拟积分过程。

为什么会想到用积分?你想想看,直线运动可以分解成X和Y两个方向的速度分量。如果速度是恒定的,那位移就是速度对时间的积分。DDA就是把这个积分过程用数字累加来实现。

3.2.1 基本原理

假设我们要从(0,0)走到(Xe,Ye),总步数为N。那么:

  • X方向每步的增量:ΔX = Xe / N
  • Y方向每步的增量:ΔY = Ye / N

但ΔX和ΔY通常不是整数,没法直接输出脉冲。DDA的做法是:用两个累加器,每次累加ΔX和ΔY,当累加值超过1时,就输出一个脉冲。

说白了,就是用累加器的溢出脉冲来模拟连续运动。

3.2.2 实现步骤

DDA的实现比逐点比较法更规整:

// DDA直线插补
void line_interpolation_dda(int Xe, int Ye, int N) {
    int X_acc = 0, Y_acc = 0;
    int i;
    
    for (i = 0; i < N; i++) {
        X_acc += Xe;
        Y_acc += Ye;
        
        if (X_acc >= N) {
            X_acc -= N;
            // X方向输出一个脉冲
            pulse_x();
        }
        
        if (Y_acc >= N) {
            Y_acc -= N;
            // Y方向输出一个脉冲
            pulse_y();
        }
    }
}

关键点:N的取值决定了插补精度。N越大,步长越小,轨迹越平滑。但N太大也会导致计算量增加。我一般取N为2的幂次,比如256或1024,这样可以用移位代替除法,效率高很多。

3.3 两种方法的对比

两种方法我都用过,各有千秋。这里做个对比:

对比项 逐点比较法 数字积分法(DDA)
核心思想 偏差判别,逐步逼近 累加积分,溢出脉冲
运算复杂度 加减法,简单 加法+比较,稍复杂
插补精度 最大偏差不超过1个脉冲当量 与累加器位数有关,一般也控制在1个脉冲当量内
速度均匀性 较好,每步都有进给 可能存在脉冲不均匀的情况
多轴扩展 较复杂,需要重新设计偏差函数 容易,增加累加器即可
适用场景 两轴联动,精度要求高的场合 多轴联动,需要平滑运动的场合

我的建议:如果你做的是两轴雕刻机,对轨迹精度要求高,逐点比较法更合适。如果是多轴机器人或者需要平滑加减速的场合,DDA更好扩展。我个人习惯是:简单场景用逐点比较法,复杂场景用DDA。

3.4 实际项目中的避坑指南

做插补这么多年,我踩过的坑不少。分享几个常见的:

  • 终点判断要谨慎:逐点比较法用总步数判断终点,DDA用累加次数判断。但实际中电机可能有丢步,单纯靠步数判断会出问题。我一般会加一个位置反馈做双重校验。
  • 象限切换要平滑:跨象限时,进给方向会变,处理不好会有冲击。建议在象限边界做速度平滑过渡。
  • 累加器溢出要正确处理:DDA的累加器溢出后要减去N,而不是清零。否则会丢失累加信息,导致轨迹偏移。

曾经踩过的坑:有一次我用DDA做四轴联动,发现轨迹总是有微小抖动。查了两天才发现,是累加器位数不够,导致溢出频率不稳定。后来把累加器从16位换成32位,问题就解决了。所以,累加器位数一定要留够余量。

3.5 小结

逐点比较法和数字积分法,是直线插补的两种经典方法。一个靠偏差判断,一个靠累加积分,思路不同但殊途同归。

理解这两种方法,是掌握插补技术的基础。后面的章节我们会讲圆弧插补、速度规划、平滑处理,这些都是在今天的基础上展开的。

嗯,今天就到这里。如果你在实际调试中遇到问题,欢迎交流。


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