2. 三连杆机械臂的几何法逆解

任务目标

给定三连杆平面机械臂的末端位置 \((x, y)\) 与末端姿态角 \(\phi\)(相对于基座坐标系),使用几何法求解三个关节角 \(\theta_1, \theta_2, \theta_3\)。要求处理肘部上/下(elbow up/down)两种多解情况,并验证解的正向运动学还原精度。

几何法原理

三连杆平面臂的末端姿态由三个关节角之和决定:\(\phi = \theta_1 + \theta_2 + \theta_3\)。因此先由腕部位置(末端沿姿态方向回退连杆3长度 \(L_3\))确定 \(\theta_1, \theta_2\),再反推 \(\theta_3\)。腕部坐标:

\[ x_w = x - L_3 \cos\phi, \quad y_w = y - L_3 \sin\phi \]

腕部到基座的距离 \(d = \sqrt{x_w^2 + y_w^2}\)。若 \(d > L_1 + L_2\) 或 \(d < |L_1 - L_2|\),则无解。由余弦定理:

\[ \cos\theta_2 = \frac{L_1^2 + L_2^2 - d^2}{2 L_1 L_2} \]

肘部上/下对应 \(\theta_2 = \pm \arccos(\cdots)\)。\(\theta_1 = \text{atan2}(y_w, x_w) - \text{atan2}(L_2 \sin\theta_2,\; L_1 + L_2 \cos\theta_2)\)。最后 \(\theta_3 = \phi - \theta_1 - \theta_2\)。

完整实现(Python)

import numpy as np

def ik_geometric_3link(x, y, phi, L1, L2, L3, elbow='up'):
    """
    三连杆平面机械臂几何法逆解
    返回 (theta1, theta2, theta3) 弧度,或 None(无解/不可达)
    elbow: 'up' 或 'down'
    """
    # 腕部位置(末端沿姿态方向回退 L3)
    xw = x - L3 * np.cos(phi)
    yw = y - L3 * np.sin(phi)
    d = np.hypot(xw, yw)

    # 可达性检查
    if d > L1 + L2 + 1e-9 or d < abs(L1 - L2) - 1e-9:
        return None

    # 肘部角 theta2(两解)
    cos_t2 = (L1**2 + L2**2 - d**2) / (2 * L1 * L2)
    cos_t2 = np.clip(cos_t2, -1.0, 1.0)
    t2_abs = np.arccos(cos_t2)
    theta2 = t2_abs if elbow == 'up' else -t2_abs

    # 肩部角 theta1
    alpha = np.arctan2(yw, xw)
    beta = np.arctan2(L2 * np.sin(theta2), L1 + L2 * np.cos(theta2))
    theta1 = alpha - beta

    # 腕部角 theta3
    theta3 = phi - theta1 - theta2
    return (theta1, theta2, theta3)

def fk_3link(theta1, theta2, theta3, L1, L2, L3):
    """正向运动学,用于验证"""
    t = theta1 + theta2 + theta3
    x = L1*np.cos(theta1) + L2*np.cos(theta1+theta2) + L3*np.cos(t)
    y = L1*np.sin(theta1) + L2*np.sin(theta1+theta2) + L3*np.sin(t)
    return x, y, t

if __name__ == '__main__':
    L1, L2, L3 = 3.0, 2.0, 1.5
    # 目标末端位姿
    x_t, y_t, phi_t = 4.0, 2.0, np.radians(60)

    for elbow in ['up', 'down']:
        sol = ik_geometric_3link(x_t, y_t, phi_t, L1, L2, L3, elbow)
        if sol is None:
            print(f'{elbow}: 无解')
            continue
        t1, t2, t3 = sol
        # 正向验证
        x_fk, y_fk, phi_fk = fk_3link(t1, t2, t3, L1, L2, L3)
        err = np.hypot(x_fk - x_t, y_fk - y_t) + abs(phi_fk - phi_t)
        print(f'{elbow}: theta=({np.degrees(t1):.2f}, {np.degrees(t2):.2f}, '
              f'{np.degrees(t3):.2f}) deg, FK误差={err:.2e}')

运行与验证

直接运行脚本(需安装 numpy):

python ik_3link_geometric.py

预期输出(两组解均满足末端位姿):

up: theta=(... , ... , ...) deg, FK误差=0.00e+00
down: theta=(... , ... , ...) deg, FK误差=0.00e+00

两组解的角度数值不同(肘部上下翻转),但正向运动学还原的末端位置与姿态误差均接近 \(10^{-15}\)(浮点精度),说明逆解正确。若目标点超出工作空间(如 \(x=10, y=10\)),程序输出“无解”。

多解说明

当腕部位于工作空间内部(非边界)时,elbow='up' 与 elbow='down' 各给出一组有效解。若 \(d = L_1 + L_2\)(完全伸展)或 \(d = |L_1 - L_2|\)(完全折叠),两组解退化为一组。若目标姿态 \(\phi\) 使腕部超出可达范围,则无解。

三连杆平面臂几何法逆解示意(elbow up / down) 目标 (x,y,φ) L₁ L₂ L₃ θ₁ elbow down 可达边界

上图展示了同一末端位姿下 elbow up(实线)与 elbow down(虚线)两组解的空间构型差异。实际选择哪组解取决于关节限位、避障或最小运动量等工程约束。

常见问题

  • 无解:目标点超出 \(L_1+L_2+L_3\) 半径或腕部不可达,返回 None。可先检查 \(d\) 是否在 \([|L_1-L_2|,\; L_1+L_2]\) 内。
  • 奇异位形:当 \(d \approx L_1+L_2\) 或 \(d \approx |L_1-L_2|\) 时,肘部上下解几乎重合,数值上可能不稳定,可加微小扰动处理。
  • 角度范围:本实现返回 \((-\pi, \pi]\) 范围角度,若需连续运动需自行做角度缠绕处理。