插补:机头走斜线或弧线时,需要 XY 同时到达某个点,就得需要 X 走一点 Y 走一点,这个算法过程就是 插补
所有插补算法推演只在第一象限,软件点数据密化放大数据后,会与直线/圆弧重合
1、逐步对比法直线插补
前置知识:
F>=0 F=F-|Y|
F<0 F=F+|X|

$$ 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 |
根据计算过程可以整理参考简单伪代码如下
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 $$

$$ 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 |
根据计算过程可以整理参考简单伪代码如下
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的次方,而且列表时也不写十进制,而是写二进制。

$$ A(0,0) \ \ \ \ \ B(7,5) $$
- 此计算分为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- 一开始确定累加器,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
- 往复循环,直到√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 根据计算过程可以整理参考简单伪代码如下
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的次方,而且列表时也不写十进制,而是写二进制。

$$ A(5,0) \ \ \ \ \ B(0,5) $$此计算分为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 根据计算过程可以整理参考简单伪代码如下
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); } }
评论