2. 圆弧插补基础实现

任务目标

实现空间圆弧插补:给定圆心坐标、圆弧半径、起始角与终止角,在圆弧所在平面内生成一系列离散路径点,供后续运动学逆解或轨迹规划使用。本案例聚焦于圆弧几何路径生成,不涉及速度规划与关节空间映射。

实现思路

圆弧位于空间任意平面时,需先建立局部坐标系:以圆心为原点,以圆弧所在平面的法向量为z轴,在平面内选取两个正交向量作为x轴与y轴。随后在局部坐标系中按角度参数化生成点,再通过旋转平移变换映射回世界坐标系。

关键完整代码

import numpy as np

def normalize(v):
    """向量归一化"""
    norm = np.linalg.norm(v)
    if norm < 1e-12:
        raise ValueError("零向量无法归一化")
    return v / norm

def build_local_frame(center, normal, ref_vector):
    """
    构建圆弧局部坐标系
    center: 圆心世界坐标 (3,)
    normal: 圆弧平面法向量 (3,)
    ref_vector: 平面内参考向量,用于确定x轴方向 (3,)
    返回: (R, center) 其中R为3x3旋转矩阵,世界坐标 = R @ 局部坐标 + center
    """
    z_axis = normalize(normal)
    # x轴取参考向量在平面内的投影方向
    x_axis = normalize(ref_vector - np.dot(ref_vector, z_axis) * z_axis)
    y_axis = np.cross(z_axis, x_axis)  # 保证右手系
    R = np.column_stack([x_axis, y_axis, z_axis])
    return R, center

def circular_interpolation(center, radius, normal, ref_vector,
                           start_angle, end_angle, num_points):
    """
    空间圆弧插补
    参数:
        center: 圆心世界坐标 (3,)
        radius: 圆弧半径
        normal: 圆弧平面法向量 (3,)
        ref_vector: 平面内参考向量,决定起始角0度的方向 (3,)
        start_angle: 起始角(弧度)
        end_angle: 终止角(弧度)
        num_points: 生成的路径点数(含端点)
    返回:
        points: 世界坐标系下的圆弧路径点,形状 (num_points, 3)
    """
    if num_points < 2:
        raise ValueError("num_points必须大于等于2")
    if radius <= 0:
        raise ValueError("半径必须为正数")

    R, center = build_local_frame(center, normal, ref_vector)

    # 在局部坐标系中生成角度序列
    angles = np.linspace(start_angle, end_angle, num_points)

    # 局部坐标: x = r*cos(theta), y = r*sin(theta), z = 0
    local_points = np.zeros((num_points, 3))
    local_points[:, 0] = radius * np.cos(angles)
    local_points[:, 1] = radius * np.sin(angles)

    # 映射回世界坐标: world = R @ local + center
    world_points = local_points @ R.T + center
    return world_points

# ===== 使用示例 =====
if __name__ == "__main__":
    # 定义空间圆弧: 圆心(0,0,0),半径5,法向量(0,0,1)即XY平面
    center = np.array([0.0, 0.0, 0.0])
    radius = 5.0
    normal = np.array([0.0, 0.0, 1.0])
    ref_vector = np.array([1.0, 0.0, 0.0])  # x轴方向

    # 从0度到90度,生成10个点
    pts = circular_interpolation(center, radius, normal, ref_vector,
                                 0.0, np.pi/2, 10)
    print("生成的点数:", pts.shape[0])
    print("首点:", pts[0])
    print("末点:", pts[-1])
    print("所有点距圆心距离(应均为5):")
    print(np.linalg.norm(pts - center, axis=1))

运行与验证

运行方式:需安装NumPy库(pip install numpy),直接执行脚本即可。

验证方法:

  • 检查输出点数量是否为num_points(示例中为10);
  • 首点坐标应为 (5, 0, 0),末点应为 (0, 5, 0)(对应90度位置);
  • 所有点到圆心的距离应严格等于半径5(浮点误差范围内),验证点确实位于球面上;
  • 所有点应满足平面方程 z = 0(因法向量为z轴),验证点位于正确平面内。

预期输出:末点坐标约为 [2.16e-16, 5.0, 0.0](浮点精度导致x分量接近0而非严格0),各点到圆心距离均为5.0。

常见问题

  • 法向量与参考向量平行:若ref_vector与normal平行,投影后x轴为零向量,代码会抛出归一化错误。应确保参考向量不平行于法向量。
  • 旋转方向:圆弧从起始角到终止角按逆时针方向(从法向量正方向观察)。若需顺时针,可交换起止角或取法向量反方向。
  • 角度单位:所有角度使用弧度制,调用时需自行转换。