逐点比较法圆弧插补:从原理到代码
逐点比较法做圆弧插补,说白了就是让刀具沿着圆弧走,每一步都问自己三个问题:我现在在圆弧的哪一侧?下一步该往哪个方向走?走到头了没有?
我刚开始做数控系统时,觉得直线插补好理解,圆弧插补绕来绕去的。后来亲手推导了一遍偏差公式,才发现其实逻辑非常清晰。今天我们就拿第一象限逆圆来开刀。
基本原理:走一步,看一步
逐点比较法的核心思想就八个字:逐点比较,步步逼近。每走一步,计算当前点与理想圆弧的偏差,根据偏差决定下一步的方向。
你想想看,这就像蒙着眼睛走圆弧——每走一步摸一下,偏里了往外拐,偏外了往里收。虽然每一步都是直线,但整体轨迹逼近圆弧。
核心流程:
- 偏差判别:当前点在圆内、圆上还是圆外?
- 坐标进给:根据偏差决定向X或Y方向走一步
- 偏差计算:计算新位置的偏差值
- 终点判别:是否到达终点?没到就继续
偏差计算公式推导(第一象限逆圆)
设圆弧起点为 (X₀, Y₀),终点为 (Xₑ, Yₑ),圆心在原点。圆弧半径为 R。
对于圆弧上任意一点 (Xᵢ, Yᵢ),理想情况下满足:
Xᵢ² + Yᵢ² = R²
我们定义偏差函数 Fᵢ:
Fᵢ = Xᵢ² + Yᵢ² - R²
这个公式很直观:
- Fᵢ = 0:点在圆弧上
- Fᵢ > 0:点在圆弧外侧(离圆心远)
- Fᵢ < 0:点在圆弧内侧(离圆心近)
我的小经验:刚开始学的时候,我老把正负搞反。后来记住一句话——"大外小内":偏差大于0在圆外,小于0在圆内。这个口诀帮我省了不少调试时间。
进给方向判定
第一象限逆圆的进给规则是这样的:
| 偏差状态 | 当前位置 | 进给方向 | 说明 |
|---|---|---|---|
| Fᵢ ≥ 0 | 圆上或圆外 | -X 方向 | 向圆内逼近 |
| Fᵢ < 0 | 圆内 | +Y 方向 | 向圆外逼近 |
为什么会这样?你想想看,第一象限逆圆是从右上往左上走。如果当前点在圆外,说明X方向走过头了,需要往-X方向回调。如果点在圆内,说明Y方向还没走够,需要往+Y方向补一步。
递推偏差计算
每次计算 X² + Y² - R² 太慢了。实际工程中我们用递推公式,只做加减法。
情况1:Fᵢ ≥ 0,向 -X 方向走一步
Xᵢ₊₁ = Xᵢ - 1
Yᵢ₊₁ = Yᵢ
Fᵢ₊₁ = (Xᵢ - 1)² + Yᵢ² - R²
= Xᵢ² - 2Xᵢ + 1 + Yᵢ² - R²
= Fᵢ - 2Xᵢ + 1
情况2:Fᵢ < 0,向 +Y 方向走一步
Xᵢ₊₁ = Xᵢ
Yᵢ₊₁ = Yᵢ + 1
Fᵢ₊₁ = Xᵢ² + (Yᵢ + 1)² - R²
= Xᵢ² + Yᵢ² + 2Yᵢ + 1 - R²
= Fᵢ + 2Yᵢ + 1
关键结论:
- F ≥ 0 时:F ← F - 2X + 1,X ← X - 1
- F < 0 时:F ← F + 2Y + 1,Y ← Y + 1
全程只用加减法,没有乘法,没有开方。这就是逐点比较法能在老式步进电机系统上跑得飞快的原因。
终点判别方法
终点判别我见过三种做法:
| 方法 | 原理 | 优缺点 |
|---|---|---|
| 总步数法 | n = |Xₑ - X₀| + |Yₑ - Y₀| | 简单可靠,我最常用 |
| 坐标比较法 | 当前坐标与终点坐标逐项比较 | 容易受累积误差影响 |
| 偏差归零法 | 回到圆弧上且到达终点附近 | 逻辑复杂,不推荐 |
我个人习惯用总步数法。先算出总共要走多少步,每走一步计数器减1,减到0就停。简单、稳定、不出错。
我曾经踩过的坑:用坐标比较法时,由于累积误差,刀具走到终点附近但坐标不完全相等,导致永远停不下来。后来全部改用总步数法,再也没出过问题。
Python 代码实现与仿真
下面是我写的一个完整实现。代码不长,但包含了所有核心逻辑。
import matplotlib.pyplot as plt
import numpy as np
def arc_interpolation_ccw(x0, y0, xe, ye):
"""
第一象限逆圆逐点比较法插补
:param x0, y0: 起点坐标
:param xe, ye: 终点坐标
:return: 插补路径点列表
"""
R2 = x0**2 + y0**2 # 半径平方
x, y = x0, y0
F = 0 # 初始偏差,起点在圆弧上
# 总步数
n = abs(xe - x0) + abs(ye - y0)
path = [(x, y)]
step = 0
while step < n:
if F >= 0:
# 向 -X 方向进给
F = F - 2*x + 1
x = x - 1
else:
# 向 +Y 方向进给
F = F + 2*y + 1
y = y + 1
path.append((x, y))
step += 1
return path
# 示例:从 (5,0) 到 (0,5) 的逆圆
path = arc_interpolation_ccw(5, 0, 0, 5)
# 可视化
xs, ys = zip(*path)
plt.figure(figsize=(8, 8))
plt.plot(xs, ys, 'b-o', markersize=4, label='插补路径')
# 绘制理想圆弧
theta = np.linspace(0, np.pi/2, 100)
plt.plot(5*np.cos(theta), 5*np.sin(theta), 'r--', label='理想圆弧')
plt.grid(True, alpha=0.3)
plt.axis('equal')
plt.xlim(-1, 6)
plt.ylim(-1, 6)
plt.xlabel('X')
plt.ylabel('Y')
plt.title('逐点比较法圆弧插补(第一象限逆圆)')
plt.legend()
plt.show()
运行建议:把这段代码复制到 Jupyter Notebook 里跑一下。你会看到蓝色折线紧密贴合红色虚线,每一步都走得很规矩。这就是逐点比较法的魅力——用最简单的加减法,走出漂亮的圆弧。
仿真结果分析
从 (5,0) 到 (0,5) 走一个90度逆圆弧,总共需要走10步。我截取中间几步的数据:
| 步数 | 当前坐标 | 偏差 F | 进给方向 |
|---|---|---|---|
| 0 | (5, 0) | 0 | -X |
| 1 | (4, 0) | -9 | +Y |
| 2 | (4, 1) | -6 | +Y |
| 3 | (4, 2) | -1 | +Y |
| 4 | (4, 3) | 6 | -X |
| 5 | (3, 3) | -2 | +Y |
| ... | ... | ... | ... |
| 10 | (0, 5) | 0 | 终点 |
你看,偏差 F 在正负之间来回摆动,刀具就在圆弧内外交替逼近。虽然每一步都有误差,但整体轨迹始终贴着圆弧走。这就是逐点比较法的精髓——用有误差的每一步,走出无误差的整体。
本章核心要点:
- 偏差公式 F = X² + Y² - R²,大外小内
- 第一象限逆圆:F≥0走-X,F<0走+Y
- 递推计算只用加减法,效率极高
- 终点判别推荐总步数法,简单可靠