插补:机头走斜线或弧线时,需要 XY 同时到达某个点,就得需要 X 走一点 Y 走一点,这个算法过程就是 插补

所有插补算法推演只在第一象限,软件点数据密化放大数据后,会与直线/圆弧重合

1、逐步对比法直线插补

前置知识:

1
2
3
F>=0  F=F-|Y|
F<0 F=F+|X|

image-20250320141048996.png

$$
A(0,0) \ \ \ \ \ B(6,4)
$$

  • 一开始要求得终点步骤,根据X与Y值,可以看出最多需要移动6+4次到达终点,所以终点判断为10
  • 偏差判别是当前位置处于大于等于0的区域还是小于等于0的区域,如果是处于大于等于0的区域,可以看出来,此时需要X增加一步,才能趋于终点,如果当前位置处于小于0的区域,此时需要Y增加一步,那么映射到现实中,就是机器XY轴各向前动了一个脉冲,最终不断的交替运动到达终点
  • 坐标给进就是偏差判别后的进步标志位,决定当前步骤X或Y哪一个前进
  • 偏差计算就是根据上面的公式,以及当前坐标所在位置,计算出下一步的XY坐标给进
  • 首先当前坐标肯定位于起点A(0,0),根据偏差判别,此时需要X进一步,则坐标给进+X,此时F>=0,偏差计算代入F>=0 F=F-|Y|,F减去终点坐标Y值,得到下一次的偏差,此时完成一步,终点判断减去1。下一次再根据偏差判别进行 坐标给进与偏差计算,往复循环,直到终点判断为0,偏差计算的步数也来到了B(6,4)
  • 根据坐标给进,依次按一格坐标移动XY,即可得到插补路径
  • 如果坐标不在0点?在其他象限?把起点作为0点映射计算,然后再转换回去就行
步数 偏差判别 坐标给进 偏差计算 终点判断
0 F(0,0) = 0 E=6+4 =10
1 F(0,0)>=0 +X F(1,0)= 0-4 = -4 E=9
2 F(1,0)<0 +Y F(1,1)= -4+6 = 2 E=8
3 F(1,1)>=0 +X F(2,1)= 2-4 = -2 E=7
4 F(2,1)<0 +Y F(2,2)= -2+6 = 4 E=6
5 F(2,2)>=0 +X F(3,2)= 4-4 = 0 E=5
6 F(3,2)>=0 +X F(4,2)= 0-4 = -4 E=4
7 F(4,2)<0 +Y F(4,3)= -4+6 = 2 E=3
8 F(4,3)>=0 +X F(5,3)= 2-4 = -2 E=2
9 F(5,3)<0 +Y F(5,4)= -2+6 = 4 E=1
10 F(5,4)>=0 +X F(6,4)= 4-4 = 0 E=0

根据计算过程可以整理参考简单伪代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
comparedLine()
{
int x,y,dx,dy,e,f;
x = start.x();//起点坐标
y = start.y();
dx = abs(end.x() - start.x());//终点坐标减去起点坐标
dy = abs(end.y() - start.y());
e = dx + dy;//终点判断步数计算
f = 0;

draw(x, y);
for(int i = 0; i < e; ++i) {
if (f >= 0) {
x++;
f -= dy;
} else {
y++;
f += dx;
}
draw(x, y);
}
}

2、逐步对比法圆弧插补

前置知识:
$$
F>=0 \ \ \ \ \ \ F=F-2|Y|+1
\F<0 \ \ \ \ \ \ F=F+2|X|+1
\ 一象限顺时针,二象限逆,三象限顺,四象限逆
\
\F>=0 \ \ \ \ \ \ F=F-2|X|+1
\F<0 \ \ \ \ \ \ F=F+2|Y|+1
\一象限逆时针,二象限顺,三象限逆,四象限顺
\公式中的XY为终点坐标XY
$$

image-20250320150132460.png

$$
A(0,5) \ \ \ \ \ B(5,0)
$$

  • 一开始要求得终点步骤,根据X与Y值,可以看出最多需要移动5+5次到达终点,所以终点判断为10
  • 偏差判别是当前位置处于大于等于0的区域还是小于等于0的区域,如果是处于大于等于0的区域,可以看出来,此时需要Y减少一步,才能趋于终点,如果当前位置处于小于0的区域,此时需要X增加一步,那么映射到现实中,就是机器XY轴各向前动了一个脉冲,最终不断的交替运动到达终点
  • 坐标给进就是偏差判别后的进步标志位,决定当前步骤X或Y哪一个前进
  • 偏差计算就是根据上面的公式,以及当前坐标所在位置,计算出下一步的XY坐标给进
  • 首先当前坐标肯定位于起点A(0,5),根据偏差判别,此时需要Y退后一步,则坐标给进-Y,此时F>=0,显然这是个顺时针,偏差计算代入F>=0 F=F-2|Y|+1,得到下一次的偏差,此时完成一步,终点判断减去1。下一次再根据偏差判别进行 坐标给进与偏差计算,往复循环,直到终点判断为0,偏差计算的步数也来到了B(5,0)
  • 根据坐标给进,依次按一格坐标移动XY,即可得到插补路径
步数 偏差判别 坐标给进 偏差计算 坐标计算 终点判断
0 F(0,0) = 0 x=0,y=5 E=5+5 =10
1 F(0,0)>=0 -Y F(1,0)= 0-2*5+1 = -9 x=0,y=4 E=9
2 F(1,0)<0 +X F(1,1)= -9+2*0+1 = -8 x=1,y=4 E=8
3 F(1,1)<0 +X F(2,1)= -8+2*1+1 = -5 x=2,y=4 E=7
4 F(2,1)<0 +X F(2,2)= -5+2*2+1 = 0 x=3,y=4 E=6
5 F(2,2)>=0 -Y F(3,2)= 0-2*4+1 = -7 x=3,y=3 E=5
6 F(3,2)<0 +X F(4,2)= -7+6+1 = 0 x=4,y=3 E=4
7 F(4,2)>=0 -Y F(4,3)= 0-6+1 = -5 x=4,y=2 E=3
8 F(4,3)<0 +X F(5,3)= -5+8+1 = 4 x=5,y=2 E=2
9 F(5,3)>=0 -Y F(5,4)= 4-4+1 = 1 x=5,y=1 E=1
10 F(5,4)>=0 -Y F(6,4)= 1-2*1+1 = 0 x=5,y=0 E=0

根据计算过程可以整理参考简单伪代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
comparedLine()

int e=0,f=0,x=0,y=0;

e = max(abs(end.x()), abs(end.y())) + max(abs(start.x()), abs(start.y()));
x = abs(start.x());
y = abs(start.y());

draw(x, y);
for(int i =0; i<e ; i++){
if(f>=0){
f = f-2*y+1;
y--;
} else {
f = f+2*x+1;
x++;
}
draw(x, y);
}
}

3、数字积分法直线插补

前置知识:

  • 累加寄存器:数字积分法的操作就是将路程分割n份,每 周期 累加一份,如果 溢出 就进给。一般溢出值就是单位1
  • 因为实际运用问题,机器在存储数据时是采用二进制的形式。为了节省空间和加快运算,Max是多少,就采用多少位的 累加器 运算。也就是2^n-1,能放得下即可。比如终点E(7,5),Max为7,采用三位(最大可存8)累加器计算。所以分割份数m总是2的次方,而且列表时也不写十进制,而是写二进制。

image-20250320153420746.png

$$
A(0,0) \ \ \ \ \ B(7,5)
$$

  • ```c
    • 此计算分为X积分器,Y积分器
    • X积分器包括√vX、√rX、ΔX
    • X积分器包括√vY、√rY、ΔY
    • √vX保存终点的X坐标,√vY保存终点的Y坐标
    • √rX为 √rX=√vX+√rX ,当√rX运算累计值大于累加器值,视为溢出,使用累加器值减去√rX再赋值给√rX,同时ΔX因为累加器溢出+1
    • √rY为 √rY=√vY+√rY ,当√rY运算累计值大于累加器值,视为溢出,使用累加器值减去√rY再赋值给√rY,同时ΔY因为累加器溢出+1
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72



      - 一开始确定累加器,Max是多少,就采用多少位的 累加器 运算,比如终点B(7,5),Max为7,采用三位(最大可存8)累加器计算,即2^3=8

      - 在√vX保存终点的X坐标111(7),√vY保存终点的Y坐标101(5),其余都为0

      - 然后开始计算,√rX与√rY固定不变,√rX=√vX+√rX,√rY=√vY+√rY,√rX或√rY如果任一超过累加器,视为溢出,使用累加器值减去√rX、√rY再赋值给√rX、√rY,同时ΔX、ΔY因为累加器溢出+1

      [^如 ]: 111+111 > 2^3 -> 7+7-8 = 6 =110

      - 往复循环,直到√rX与√rY都加上111减去累加器为0,当前位置也来到了B(7,5)

      - 根据ΔX、ΔY的值变化,依次按一格坐标移动XY,即可得到插补路径

      | 步数 | √vX | √rX | ΔX | √vY | √rY | ΔY |
      | ---- | :--: | :------------: | :--: | :--: | :--: | :--: |
      | 0 | 111 | 0 | 0 | 101 | 0 | 0 |
      | 1 | 111 | 111(111+0) | 0 | 101 | 101 | 0 |
      | 2 | 111 | 110(111+111) | 1 | 101 | 010 | 1 |
      | 3 | 111 | 101(111+110) | 1 | 101 | 111 | 0 |
      | 4 | 111 | 100(111+101) | 1 | 101 | 100 | 1 |
      | 5 | 111 | 011(111+100) | 1 | 101 | 001 | 1 |
      | 6 | 111 | 010(111+011) | 1 | 101 | 110 | 0 |
      | 7 | 111 | 001(111+010) | 1 | 101 | 011 | 1 |
      | 8 | 111 | 000(111+001) | 1 | 101 | 000 | 1 |

      根据计算过程可以整理参考简单伪代码如下

      ```c
      ddaLine()
      {
      int vx, vy, rx=0, ry = 0;
      int dx=0, dy=0;
      float x, y = 0.0;

      x += start.x();
      y += start.y();

      dx = end.x() - start.x();
      dy = end.y() - start.y();

      vx = abs(end.x() - start.x());
      vy = abs(end.y() - start.y());
      rx += vx;
      ry += vy;

      int max_val = max(abs(vx), abs(vy));
      // 数控技术中,对于分割数m牵扯到 寄存器 的概念。
      // 也就是2^n-1,能放得下即可 比如终点(7,5),max为7,采用三位8累加器计算。
      int acc = 1;
      while (acc < max_val) {
      acc <<= 1; // 左移一位,相当于乘以2
      }

      draw(x, y);

      for (int i = 0; i < acc; i++) {
      rx += vx;
      ry += vy;

      if (rx >= acc) {
      x++;
      rx -= acc;
      }
      if (ry >= acc) {
      y--;
      ry -= acc;
      }
      draw(x, y);
      }
      }

4、数字积分法圆弧插补

前置知识:

  • 累加寄存器:数字积分法的操作就是将路程分割n份,每 周期 累加一份,如果 溢出 就进给。一般溢出值就是单位1

  • 因为实际运用问题,机器在存储数据时是采用二进制的形式。为了节省空间和加快运算,Max是多少,就采用多少位的 累加器 运算。也就是2^n-1,能放得下即可。比如终点E(7,5),Max为7,采用三位(最大可存8)累加器计算。所以分割份数m总是2的次方,而且列表时也不写十进制,而是写二进制。

image-20250320164428897.png

1
2
3
$$
A(5,0) \ \ \ \ \ B(0,5)
$$
1
2
3
4
5
6
7
8
9
此计算分为X积分器,Y积分器
X积分器包括√vX、√rX、ΔX
X积分器包括√vY、√rY、ΔY
√vX保存起点的Y坐标,√vY保存起点的X坐标,注意这里与直线插补是反的
√rX为 √rX=√vX+√rX ,当√rX运算累计值大于累加器值,视为溢出,使用累加器值减去√rX再赋值给√rX,
同时ΔX因为累加器溢出+1,此时另外一边的√vY+1
√rY为 √rY=√vY+√rY ,当√rY运算累计值大于累加器值,视为溢出,使用累加器值减去√rY再赋值给√rY,
同时ΔY因为累加器溢出+1,此时另外一边的√vX+1
Ex与Ey为步数
  • 一开始确定累加器,Max是多少,就采用多少位的 累加器 运算,比如终点B(0,5),Max为5,采用三位(最大可存8)累加器计算,即2^3=8

  • 在√vX保存起点的Y坐标0,√vY保存起点的X坐标101(5),Ex与Ey为步数5

  • 然后开始计算,√rX=√vX+√rX,√rY=√vY+√rY,√rX或√rY如果任一超过累加器,视为溢出,使用累加器值减去√rX、√rY再赋值给√rX、√rY,同时ΔX因溢出-1时√vY-1,ΔY因溢出+1时√vX+1

  • 往复循环,直到Ex与Ey都为0,当前位置也来到了B(0,5)

  • 根据√rX、√rY的值变化,依次按一格坐标移动XY,即可得到插补路径

步数 √vX √rX ΔX Ex √vY √rY ΔY Ey
0 000 000 0 101 101 0 0 101
1 000 000 0 101 101 101 0 101
2 000 000 0 101 101 010 1 100
001(Ey)
3 001 001 0 101 101 111 0 100
4 001 010 0 101 101 100 1 011
010(Ey)
5 010 100 0 101 101 001 1 010
011(Ey)
6 011 111 0 101 101 110 0 010
7 011 010 -1 100 101 011 1 001
100(Ey) 100(Ex)
8 100 110 0 100 100 111 0 001
9 100 010 -1 100 100 011 1 000
101(Ey) 011(Ex)
10 101 111 0 011 011
11 101 100 -1 010 011
010(Ex)
12 101 001 -1 001 010
13 101 110 0 001 001
14 101 011 -1 000 000

根据计算过程可以整理参考简单伪代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
ddaCircle()
{
int vx=0, vy=0, rx=0, ry=0, ex=0, ey = 0;

vx = std::abs(end.x() - start.x());
vy = std::abs(end.y() - start.y());

int max_val = max(abs(vx), abs(vy));
int acc = 1;
while (acc < max_val) {
acc <<= 1;
}

vx = start.y();
vy = start.x();

ex = std::abs(end.x()-start.x());
ey = std::abs(end.y()-start.y());

draw(x, y);
for (int i =0; i<acc ; i++ ) {
if(ex){
rx += vx;
}
if(ey){
ry += vy;
}

if(rx>acc){
ex--;
rx -= acc;
vy--;
}
if(ry>acc){
ey--;
ry -= acc;
vx++;
}
if(vy < start.y()){
continue;
}
draw(x, y);
}
}