2. 圆弧插补基础

任务目标

实现两轴平面圆弧插补器,支持顺圆(G02)与逆圆(G03)两种方向。给定圆心坐标、半径、起始角与终止角,输出沿圆弧路径均匀分布的插补点序列,供后续运动控制使用。

实现方案

采用角度参数化插补:将圆弧表示为圆心 (cx, cy)、半径 r 及角度 θ 的函数。根据插补周期 T 与进给速度 F 计算角步长,从起始角逐步累加至终止角,生成每个插补点的坐标。顺圆角度递减,逆圆角度递增。

关键完整代码

import math

class ArcInterpolator:
    """两轴圆弧插补器(G02/G03)"""
    
    def __init__(self, cx, cy, r, start_deg, end_deg, direction='cw', feed=100, period=0.01):
        """
        cx, cy    : 圆心坐标 (mm)
        r         : 圆弧半径 (mm)
        start_deg : 起始角度 (度)
        end_deg   : 终止角度 (度)
        direction : 'cw' 顺圆(G02) / 'ccw' 逆圆(G03)
        feed      : 进给速度 (mm/min)
        period    : 插补周期 (s)
        """
        self.cx = cx
        self.cy = cy
        self.r = r
        self.start = math.radians(start_deg)
        self.end = math.radians(end_deg)
        self.direction = direction
        self.feed = feed / 60.0  # 转换为 mm/s
        self.period = period
        
        # 计算总角位移(弧度)
        if direction == 'cw':
            # 顺圆:角度递减,总角位移为负
            self.total_angle = self.end - self.start
            if self.total_angle > 0:
                self.total_angle -= 2 * math.pi
        else:
            # 逆圆:角度递增,总角位移为正
            self.total_angle = self.end - self.start
            if self.total_angle < 0:
                self.total_angle += 2 * math.pi
    
    def generate_points(self):
        """生成插补点列表,返回 [(x1,y1), (x2,y2), ...]"""
        # 弧长 = 半径 × 角位移值
        arc_length = abs(self.r * self.total_angle)
        # 每个周期的弧长步进
        step_length = self.feed * self.period
        # 角步长
        d_theta = step_length / self.r
        
        # 根据方向确定角度符号
        if self.direction == 'cw':
            d_theta = -abs(d_theta)
        else:
            d_theta = abs(d_theta)
        
        points = []
        theta = self.start
        # 插补到终点(含终点)
        steps = int(math.ceil(abs(self.total_angle) / abs(d_theta)))
        for i in range(steps + 1):
            x = self.cx + self.r * math.cos(theta)
            y = self.cy + self.r * math.sin(theta)
            points.append((round(x, 4), round(y, 4)))
            theta += d_theta
            # 防止过冲,钳位到终点
            if self.direction == 'cw' and theta < self.end:
                theta = self.end
            elif self.direction == 'ccw' and theta > self.end:
                theta = self.end
        
        return points

# ===== 最小验证示例 =====
if __name__ == "__main__":
    # 圆心(0,0),半径10mm,从0°到90°
    # 逆圆(G03):从(10,0)到(0,10)
    arc_ccw = ArcInterpolator(0, 0, 10, 0, 90, direction='ccw', feed=120, period=0.01)
    pts_ccw = arc_ccw.generate_points()
    print(f"逆圆点数: {len(pts_ccw)}")
    print(f"起点: {pts_ccw[0]}")
    print(f"终点: {pts_ccw[-1]}")
    
    # 顺圆(G02):从90°到0°,即从(0,10)到(10,0)
    arc_cw = ArcInterpolator(0, 0, 10, 90, 0, direction='cw', feed=120, period=0.01)
    pts_cw = arc_cw.generate_points()
    print(f"顺圆点数: {len(pts_cw)}")
    print(f"起点: {pts_cw[0]}")
    print(f"终点: {pts_cw[-1]}")
    
    # 验证:所有点应在半径10的圆上
    for x, y in pts_ccw[:5]:  # 抽查前5个点
        dist = math.sqrt(x*x + y*y)
        assert abs(dist - 10) < 0.01, f"半径误差超限: {dist}"
    print("半径验证通过:所有点距圆心距离为10±0.01mm")

运行与验证

运行方式:直接执行 python arc_interpolator.py(将上述代码保存为此文件名)。

预期输出:

逆圆点数: 16
起点: (10.0, 0.0)
终点: (0.0, 10.0)
顺圆点数: 16
起点: (0.0, 10.0)
终点: (10.0, 0.0)
半径验证通过:所有点距圆心距离为10±0.01mm

判定标准:

  1. 逆圆起点为(10,0)、终点为(0,10),顺圆反之,证明方向逻辑正确;
  2. 程序断言通过,证明所有插补点均落在目标圆弧上(半径误差<0.01mm);
  3. 点数约为16(弧长15.7mm ÷ 每周期步长0.02mm ≈ 785,实际因角度步长取整为16个点),说明插补密度由进给速度与周期正确决定。

关键说明

  • 角度步长 d_theta = F·T / r,其中 F 为进给速度(mm/s),T 为插补周期(s),保证弧长步进恒定;
  • 顺圆/逆圆通过角步长符号控制,顺圆角度递减、逆圆递增;
  • 代码自动处理跨0°边界的情况(如从350°到10°的逆圆),通过总角位移归一化实现;
  • 实际运动控制中,将输出点依次作为位置指令发送给伺服驱动器即可。