4、圆弧插补算法详解:逐点比较法、DDA、角度逼近法、时间分割法
圆弧插补,说白了就是让刀具走出一个完美的圆弧。你想想看,数控系统里只有直线和圆弧两种基本轨迹,直线好办,但圆弧就有点讲究了。我这些年调试过的设备,十有八九的加工瑕疵都出在圆弧段。今天我把四种主流算法掰开揉碎了讲,都是实战中摸爬滚打出来的经验。
4.1 逐点比较法圆弧插补
这是最经典的方法,也是我入行时第一个学会的。它的核心思想就八个字:步步逼近,偏差判别。
每次只走一步,走完就看看当前位置偏离圆弧有多远。偏内了就往外走,偏外了就往里走。就这么简单粗暴。
核心公式:
偏差判别:F = x² + y² - R²
F > 0:点在圆弧外,下一步向圆内走(-X 或 -Y)
F < 0:点在圆弧内,下一步向圆外走(+X 或 +Y)
举个例子,第一象限逆圆插补:
// 逐点比较法 - 第一象限逆圆
int x = 0, y = R;
int F = 0; // 初始偏差
while (x <= y) {
if (F >= 0) {
// 点在圆弧外或圆弧上,向圆内走
y--;
F = F - 2*y + 1;
} else {
// 点在圆弧内,向圆外走
x++;
F = F + 2*x + 1;
}
// 输出插补点 (x, y)
}
我的经验:逐点比较法最大的优点是计算量小,适合老式单片机。但缺点也明显——速度不均匀。我在做雕刻机项目时发现,它在45度方向附近会明显抖动。后来加了速度前瞻才压下去。
4.2 DDA圆弧插补
DDA(数字微分分析器)法,说白了就是用积分的思想来走圆弧。它把圆弧运动分解成X和Y两个方向的速度分量,然后对时间积分。
为什么会这样?因为圆弧的参数方程是:
x = R * cos(θ)
y = R * sin(θ)
对时间求导,速度分量就是:
dx/dt = -R * sin(θ) = -y
dy/dt = R * cos(θ) = x
你看,X方向的速度和Y坐标有关,Y方向的速度和X坐标有关。这就是DDA的精髓——交叉积分。
// DDA圆弧插补 - 第一象限逆圆
int x = R, y = 0;
int fx = 0, fy = 0; // 积分累加器
int dt = 1; // 时间步长
while (x >= 0 && y <= R) {
fx += y; // X方向积分
fy += x; // Y方向积分
if (fx >= R) {
x--;
fx -= R;
}
if (fy >= R) {
y++;
fy -= R;
}
// 输出插补点 (x, y)
}
注意:DDA法有个坑——积分累加器会溢出。我曾经在16位单片机上吃过亏,R值一大,fx和fy就爆了。后来改用32位,或者做归一化处理才解决。
DDA法的好处是速度均匀,比逐点比较法平滑得多。但精度受积分步长限制,步长越小精度越高,计算量也越大。
4.3 角度逼近法
这个方法我是在做激光切割机时接触到的。它的思路很直接——把圆弧等分成小角度,然后直接算坐标。
每次走一个固定角度Δθ,新的坐标就是:
x_new = R * cos(θ + Δθ)
y_new = R * sin(θ + Δθ)
但直接算三角函数太慢了,所以实际用的是递推公式:
x_new = x * cos(Δθ) - y * sin(Δθ)
y_new = x * sin(Δθ) + y * cos(Δθ)
你看,只要提前算好cos(Δθ)和sin(Δθ),后面全是乘加运算,快得很。
关键参数:
- Δθ 越小,精度越高,但插补点数越多
- 一般取 Δθ = 1° ~ 0.1°
- 弦高误差:e ≈ R * (1 - cos(Δθ/2))
// 角度逼近法圆弧插补
float cos_dt = cos(0.1°); // 预计算
float sin_dt = sin(0.1°);
float x = R, y = 0;
for (int i = 0; i < 900; i++) { // 90度圆弧
float x_new = x * cos_dt - y * sin_dt;
float y_new = x * sin_dt + y * cos_dt;
x = x_new;
y = y_new;
// 输出插补点 (x, y)
}
我的建议:角度逼近法最适合做高速圆弧插补。我在做PCB钻孔机时就用它,配合FPGA硬件加速,一个时钟周期就能算出一个点,速度拉满。
4.4 时间分割法
时间分割法,也叫数据采样插补。它是目前高档数控系统的主流方法。思路是:把时间切成小片,每片里走一段直线。
说白了,就是用直线段去逼近圆弧。但关键是怎么切——不是等角度切,而是等时间切。
假设插补周期为T,进给速度为F,那么每步走的弧长就是:
ΔL = F * T
对应的角度变化:
Δθ = ΔL / R
然后就和角度逼近法一样递推了。但时间分割法更灵活,可以实时调整进给速度。
// 时间分割法圆弧插补
float T = 0.001; // 插补周期 1ms
float F = 100; // 进给速度 mm/s
float R = 50; // 圆弧半径
float delta_L = F * T;
float delta_theta = delta_L / R;
float cos_dt = cos(delta_theta);
float sin_dt = sin(delta_theta);
float x = R, y = 0;
float theta = 0;
while (theta < PI/2) {
float x_new = x * cos_dt - y * sin_dt;
float y_new = x * sin_dt + y * cos_dt;
x = x_new;
y = y_new;
theta += delta_theta;
// 输出插补点 (x, y)
}
避坑指南:我曾经在时间分割法上栽过跟头——进给速度F和插补周期T不匹配,导致ΔL太大,圆弧变成了多边形。后来加了弦高误差校验,如果误差超限就自动加密插补点。
4.5 四种算法对比
| 算法 | 计算量 | 速度均匀性 | 精度 | 适用场景 |
|---|---|---|---|---|
| 逐点比较法 | 极小 | 差 | 中等 | 低端单片机、步进电机 |
| DDA法 | 小 | 好 | 中等 | 中端数控、伺服系统 |
| 角度逼近法 | 中等 | 好 | 高 | 高速加工、激光切割 |
| 时间分割法 | 大 | 最好 | 最高 | 高档数控、多轴联动 |
选哪种?我的建议是:
- 做玩具、小设备,用逐点比较法就够了
- 做雕刻机、3D打印机,DDA法性价比最高
- 做激光切割、高速铣床,上角度逼近法
- 做五轴联动、精密加工,老老实实用时间分割法
嗯,四种算法就讲到这里。每种都有它的脾气,选对了事半功倍,选错了调试到哭。我个人建议,新手先从逐点比较法入手,理解偏差判别的思想,再逐步过渡到更高级的算法。一口吃不成胖子,做运动控制更是这样。