逆运动学:从球腕解耦到数值解的吸引盆
完整推导 6R 球腕机械臂八组解析逆解的每一步代数,剖析数值解的收敛条件、阻尼的作用与吸引盆结构,并用一套可复现的实现给出解析法与数值法的实测对比。
运动学那篇只给结论:Pieper 条件、8 组解、阻尼最小二乘。这篇把逆运动学摊开,每一步代数都走完——8 组解到底怎么来的、数值法为什么会收敛到一个用不了的构型、阻尼系数该怎么选。
正解 是把关节角代进去连乘矩阵,没有任何选择余地。逆解 是解一个非线性方程组,它和正解有三处本质不对称:
- 解可能不存在:目标在工作空间外,或者姿态可达但位置不可达;
- 解通常不唯一:6 轴臂一般位形下最多 16 组解,球腕构型 8 组,7 轴冗余臂无穷多组;
- 解不连续依赖于目标:目标位姿连续变化时,某一支解可能突然消失或跳变。
这三条决定了逆解的工程形态:它不是一个函数,而是一次带选择的搜索。
本文所有数据来自一套可复现的 6R 球腕臂实现(标准 DH:、、、、、,含肩部偏置)。
6 个未知数、6 个方程,直接硬解是一个 6 元非线性方程组,一般情况下没有闭式解。Pieper 条件给出了有闭式解的充分条件:相邻三个关节轴交于一点,或三轴平行。工业臂几乎清一色采用前者——最后三个轴交于一点,构成球腕。
球腕为什么能救命?因为它让位置和姿态解耦。设末端位姿为 ,腕心(三轴交点)位置为
其中 是末端 z 轴, 是腕心到法兰的距离。这个式子的关键性质是: 只由目标位姿决定,与关节角无关;同时,关节 4、5、6 的转动不改变腕心位置(它们都绕过腕心的轴转动)。
于是 6 元方程组裂成两个 3 元问题:
先由腕心解出前三个关节,再把前三关节造成的姿态“除掉”,剩下的姿态全部交给腕部三轴。下面逐个击破。
如果机器人没有肩部偏置, 就完了。但真实工业臂几乎都有偏置 (本文模型取 0.15 m),它让手臂平面偏离基座回转轴, 的求解也随之复杂一档。
先看几何。关节 1 转动后, 轴的方向是水平的、垂直于手臂平面的径向:
腕心的位置可以分解成“沿径向走 ,再沿 偏移 ,加上竖直分量”:
两式平方相加,交叉项消掉,得到一个只含 的关系:
正负号就是“左手/右手”(lefty/righty)两个肩部分支。再把上面两式看成一个旋转关系—— 是 绕原点转过 的结果,所以辐角相减:
顺带得到两个重要推论:根号内为负()时无解——腕心落进了半径为 的“死区圆柱”里;根号为零时两支合并,这就是肩部奇异。
选定 和 的符号后,问题降维到手臂平面内的一个 2R 问题。平面内的坐标是
两段“连杆”分别是大臂 和折线前臂——注意前臂由 和 两段垂直的偏置组成,等效长度和固有偏角为
对这个 2R 用余弦定理。设肘部夹角为 (大臂与等效前臂的夹角),腕心到肩部的距离平方为 :
说明腕心超出可达范围(太远或太近),该分支无解。否则
这个正负号就是“肘上/肘下”两个分支。有了 ,肩部角由两部分组成——目标方向的仰角 ,减去大臂相对目标连线的夹角 :
的形式来自把等效前臂投影到“垂直/平行于大臂”两个方向。最后按本文 DH 的正方向约定( 使得关节 2 的正转方向与平面内的仰角反号):
里的 是把“等效前臂方向”换算回“关节 3 的零位定义”的常数修正——它只依赖 DH 参数,与目标无关。
到这里位置子问题结束,共 组 。
前三关节确定后, 是已知的,于是
现在要把这个已知旋转矩阵分解成三次关节转动。对本文的 DH():
中间那段是一个共轭: 表示“把绕 的转动搬到绕 的转动”,即 。所以
这是一个标准 ZYZ 欧拉分解,中间角为 。展开 ZYZ 的矩阵元(记 的元素为 , 从 0 计):
由第三列的前两个元素得 的模长 ,取符号 :
的两个取值就是“腕翻转”两个分支: 与 给出同一个姿态。
当 时是腕部奇异: 和 绕同一根轴转,只有和 是确定的,单独取值不定。此时必须走单独的分支(通常固定 为当前值以保证连续性,再由 解出 ),否则 atan2(0, 0) 会产生跳变。
三处符号选择相乘,得到球腕 6R 臂的全部 8 组解:
把上面的推导实现出来,在 300 个随机可达位姿上做往返测试(随机 逆解),结果是 300/300 恢复出原构型,且每次恰好返回 8 组解——与理论完全一致。
八组解对应八个物理上不同的手臂姿态。注意红点(腕心)在八张图里位置完全相同——这正是球腕解耦的几何含义:腕心只由目标位姿决定,前三关节负责把腕心放到那儿,后三关节负责调姿态
顺带一个容易忽略的细节:如果没有肩部偏置(),“肩左/肩右”两支在物理上是同一个姿态,只是用 与 两套参数表示,此时 8 组解只对应 4 个不同的机械构型。偏置的存在才让八支真正分开。
不满足 Pieper 条件的构型(很多协作臂有链偏置)、或 7 轴冗余臂,只能用数值法。
定义 6 维位姿误差。位置部分直接相减,姿态部分必须用对数映射而不是欧拉角之差:
对数映射给出的是“从当前姿态转到目标姿态”的轴角向量,它在 上是良定义的、没有万向锁、且模长就是转角。用欧拉角差会在接近 时给出错误的方向。
一阶展开 ,令其为零得牛顿步 。但 在奇异附近病态,实用格式一律是阻尼最小二乘:
阻尼的作用在 SVD 下看得最清楚:每个奇异方向的增益从 变成 。好处是 时增益不再爆炸,坏处也在同一个式子里—— 小时增益也趋于零,那个方向的误差几乎不再下降。
这不是理论顾虑。我用固定 在一个偏近奇异的目标上迭代,残差降到 附近就彻底停滞,加到 400 次迭代也过不了 的判据。
修正办法是 Levenberg–Marquardt 式的自适应阻尼:步子有效就减小阻尼(趋近纯牛顿,恢复二次收敛),步子无效就加大阻尼(趋近梯度下降,保证稳健)。
def ik_numeric(T_des, q0, lam=1e-2, max_iter=200, tol=1e-8, step_cap=0.4): q = np.array(q0, dtype=float) err = np.linalg.norm(pose_error(fk(q), T_des)) for k in range(max_iter): if err < tol: return q, True, k e = pose_error(fk(q), T_des) J = jacobian(q) dq = J.T @ np.linalg.solve(J @ J.T + lam ** 2 * np.eye(6), e) n = np.linalg.norm(dq) if n > step_cap: # 限步:一阶展开只在小步长内可信 dq *= step_cap / n q_new = q + dq err_new = np.linalg.norm(pose_error(fk(q_new), T_des)) if err_new < err: # 成功:减阻尼,加速收敛 q, err = q_new, err_new lam = max(lam * 0.7, 1e-7) else: # 失败:加阻尼,缩步长 lam = min(lam * 2.5, 1e2) return q, err < tol, max_iter除了自适应阻尼,step_cap 也是必需的:牛顿步基于一阶展开,步长过大时展开失效,迭代会在远处乱跳。限步把它变成一个信赖域方法。
数值法只会返回一个解,返回哪一个完全由初值决定。把初值 在 上扫描(其余关节初值固定为零),记录每个初值收敛到八支中的哪一支:
(a) 每种颜色是一个解的吸引域。边界高度不规则、伴随细碎的交错结构,这是非线性方程组牛顿法的典型特征——初值差之毫厘,落到的分支谬以千里;灰色是 200 次迭代内未收敛的 3.3%。(b) 越靠近腕部奇异(),伪逆所需的关节速度线性发散,阻尼最小二乘则在 处封顶
这张图是“数值 IK 不可预测”这句话的精确形态。四个可以直接用的结论:
- 吸引域面积极不均匀:本例中最大的一支占 39%,最小的只占 0.9%。某些解你几乎永远随机不到;
- 边界是分形式的:靠近边界处,初值的微小扰动会改变收敛结果。这意味着“上一拍的解当这一拍的初值”在目标跨越某些区域时会突然跳支;
- 有不收敛区:3.3% 的初值在 200 次迭代内没收敛。生产代码必须有迭代上限和失败处理;
- 连续性靠初值维持:笛卡尔伺服里用上一拍关节角作初值,本质就是强迫解停留在同一个吸引域内——这是最便宜也最有效的分支连续性保证。
在 400 个随机可达位姿上对比两种方法(解析法枚举全部八支,数值法从单个随机初值出发):
(a) 解析法 400/400 找到解且总有至少一支落在关节限位内;数值法 382/400 收敛,但其中只有 154 次(40%)的解满足关节限位——它根本不知道限位存在。(b) 八支解里平均只有 4.89 支在限位内,接近一半不可用
这组数字里最值得记住的是 40%。数值 IK 收敛了不等于成功:它对关节限位、自碰撞、构型偏好一无所知,收敛到哪一支纯看初值。工程上处理这件事只有两条路:要么用解析解枚举全部分支再按准则挑,要么给数值法做多初值重启并逐个校验(TRAC-IK 就是同时跑一个 KDL 式的牛顿求解器和一个带限位的非线性优化求解器,谁先返回可行解用谁)。
耗时方面,这套纯 Python/NumPy 实现里解析法 0.46 ms(一次返回全部八支)、数值法 8.4 ms(中位 22 次迭代)。绝对值没有意义——C++ 实现(IKFast 生成的解析解通常在微秒量级)会快两三个数量级——但十几倍的比值是结构性的:解析法是有限次三角函数运算,数值法是几十次“正解 + 雅可比 + 求解”。
所以选择准则很清楚:
| 情形 | 推荐做法 |
|---|---|
| 满足 Pieper 条件(球腕) | 解析解(手写或 IKFast 生成),枚举八支后按准则选 |
| 一般 6R(无球腕) | 一般最多 16 解,可用 Raghavan–Roth 消元求全解;工程上多用 IKFast |
| 7 轴冗余臂 | 固定臂角参数后退化为 6 轴解析解,或直接数值法 + 零空间优化 |
| 在线笛卡尔伺服 | 数值法,以上一拍关节角为初值(天然保证连续性) |
| 规划器内部大量调用 | 解析解,否则 IK 会成为规划的瓶颈 |
拿到 8 组解之后选哪一个,这才是实际系统里最花心思的部分。常见准则按优先级排:
- 硬性可行:关节限位、自碰撞、与环境碰撞——先过滤,本文实测平均会滤掉 3 支;
- 连续性:与当前构型的关节空间距离最小,(加权范数,大关节权重更大,因为它们动起来慢且惯量大);
- 远离奇异:可操作度 大者优先,给下游的笛卡尔伺服留余量;
- 远离限位:各关节到限位的余量最小值最大者优先。
有一个陷阱值得单独说:逐点贪心地选“离当前最近的解”,在整条轨迹上不一定最优。轨迹中段可能出现某一支解消失(越限或碰撞)的情况,贪心走到那里就被迫翻腕——而翻腕意味着腕关节要转 ,在轨迹中途做这件事既慢又危险。
正确做法是对整条路径做全局分支选择:把每个路点的可行解看成图的节点,相邻路点的解之间连边(边权为关节空间距离,不可行的转移不连边),然后跑一次最短路。这样能提前发现“这条路径无论如何都要翻腕”,从而在规划阶段就换一条路径或换一个分支起点。
- 逆解与正解的三处不对称——可能无解、通常多解、不连续依赖目标——决定了它是“一次带选择的搜索”而不是一个函数。
- 球腕(Pieper 条件)的价值是把 6 元方程组解耦成“腕心定前三轴、剩余姿态定后三轴”两个 3 元问题;关键恒等式 只依赖目标位姿。
- 八组解来自三处符号选择:(肩)、(肘)、(腕翻)。没有肩部偏置时肩的两支物理上重合。
- 腕部分解的本质是 的 ZYZ 欧拉提取; 是腕部奇异,必须单独处理。
- 数值法的两个必需品:自适应阻尼(固定 会在 停滞)和限步(把牛顿法变成信赖域法)。
- 吸引盆结构说明数值法返回哪一支完全由初值决定,且边界呈分形;实测最大分支占 39%、最小占 0.9%、3.3% 不收敛。
- 最该记住的一个数字:数值解收敛后只有 40% 落在关节限位内。收敛 ≠ 可用,分支选择必须显式做,最好在整条轨迹上全局做。
- D. L. Pieper. The Kinematics of Manipulators Under Computer Control. PhD thesis, Stanford, 1968.(球腕解耦的出处)
- J. J. Craig. Introduction to Robotics: Mechanics and Control. 4th ed.(第 4 章逆运动学的标准教材推导)
- M. Raghavan, B. Roth. Inverse Kinematics of the General 6R Manipulator and Related Linkages. ASME JMD, 1993.(一般 6R 的 16 解)
- H.-Y. Lee, C.-G. Liang. A New Vector Theory for the Analysis of Spatial Mechanisms. Mechanism and Machine Theory, 1988.
- P. Beeson, B. Ames. TRAC-IK: An Open-Source Library for Improved Solving of Generic Inverse Kinematics. Humanoids 2015.(双求解器并行的工程方案)
- S. R. Buss. Introduction to Inverse Kinematics with Jacobian Transpose, Pseudoinverse and Damped Least Squares Methods. 2004.