4. 运动学基础(下):逆运动学——从末端位姿反解关节角度。多解问题与奇异点分析
4.1 逆运动学:从“手”到“关节”的逆向推理
上一章我们聊了正运动学,说白了就是给定关节角度,算出末端执行器在哪。那逆运动学正好反过来——我知道末端要走到哪个位置、摆成什么姿态,反过来求每个关节该转多少度。
这在实际工程中才是真正要用的。你想想看,我们编程的时候,不可能去手动调每个关节的角度。我们只会说:“去抓那个螺丝刀”,然后系统自己算出关节角度。这就是逆运动学干的事。
我个人习惯把逆运动学比作“解方程”。正运动学是代入已知数求结果,逆运动学是已知结果反推未知数。但问题在于——这个方程往往不是线性的,而且解不唯一。
4.2 解析法与数值法:两条路怎么选?
求解逆运动学,主要有两条路:解析法和数值法。
解析法,就是通过数学推导,直接写出关节角度的表达式。比如对于六轴机器人,如果满足“后三轴交于一点”的条件(也就是存在腕部中心点),就可以用解析法求解。我在项目中遇到过一台老式的六轴焊接机器人,它的腕部结构就是典型的球形腕,用解析法算起来非常快,一个周期不到1毫秒。
数值法,则是用迭代逼近的方式去算。比如牛顿-拉夫森法、雅可比矩阵伪逆法。这种方法通用性强,什么结构的机器人都能用,但缺点是计算量大,而且可能不收敛。
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 解析法 | 速度快、精度高、解结构清晰 | 依赖机器人结构,通用性差 | 工业六轴、SCARA等标准构型 |
| 数值法 | 通用性强,适用于任意构型 | 计算慢、可能不收敛、需要初值 | 冗余机器人、特殊构型 |
我个人建议:能用解析法就用解析法。实在不行再上数值法。因为解析法算出来的解是确定的,你还能分析出有多少组解。数值法有时候算着算着就跑到另一个解上去了,你还不知道。
4.3 多解问题:同一个位置,多种姿势
逆运动学最让人头疼的问题之一就是多解。同一个末端位姿,可能对应好几组关节角度。
举个例子,一个六轴机器人要到达空间中的某个点,它可以“肘部朝上”也可以“肘部朝下”,可以“手腕翻转”也可以“手腕不翻转”。这些不同的关节组合,都能让末端到达同一个位置。
为什么会这样?因为机器人关节的运动范围通常是360度或者更大,同一个空间位置可以通过不同的关节组合来实现。
我曾经遇到过一个问题:一台码垛机器人在抓取箱子时,突然从“肘部朝上”切换到了“肘部朝下”,结果箱子甩出去了。后来我在代码里加了“关节空间连续性检查”,强制要求相邻两个周期的关节角度变化不能超过某个阈值。嗯,这个问题就再也没出现过。
4.4 奇异点分析:机器人的“死穴”
奇异点,是逆运动学里绕不开的话题。说白了,就是在某些位姿下,机器人会失去某个方向的运动能力。
从数学上看,奇异点对应的是雅可比矩阵的行列式为零。这时候,末端执行器的微小运动,会导致某个关节的速度趋于无穷大——这在实际中是不可能的,所以机器人就会“卡住”或者剧烈抖动。
常见的奇异点有三种:
- 腕部奇异点: 关节4和关节6的轴线共线,导致腕部无法绕某个方向旋转。
- 肩部奇异点: 关节1和关节2的轴线共线,导致肩关节锁死。
- 肘部奇异点: 关节2和关节3的轴线共线,导致肘关节无法伸展。
我记得有一次调试一台喷涂机器人,在喷一个曲面时,机器人突然剧烈抖动,差点把喷枪甩飞。我一看日志,发现它正好经过了一个腕部奇异点。后来我改了一下路径规划,让机器人绕开那个区域,问题就解决了。
4.5 知识体系框架
下面这张图,是我自己整理的逆运动学知识体系。你可以把它当作一个思维导图来看。
4.6 代码示例:解析法求解SCARA机器人逆运动学
下面是一个SCARA机器人的逆运动学求解示例。SCARA结构简单,适合用来理解解析法的思路。
// SCARA机器人逆运动学解析求解
// 已知:末端位置(x, y, z),末端姿态(绕Z轴旋转角度phi)
// 求解:关节1角度(theta1),关节2角度(theta2),关节3位移(d3),关节4角度(theta4)
#include <math.h>
typedef struct {
double theta1; // 关节1角度 (rad)
double theta2; // 关节2角度 (rad)
double d3; // 关节3位移 (mm)
double theta4; // 关节4角度 (rad)
} SCARA_Solution;
// 机器人参数
const double L1 = 300.0; // 大臂长度 (mm)
const double L2 = 200.0; // 小臂长度 (mm)
int solveSCARA(double x, double y, double z, double phi,
SCARA_Solution *sol, int elbow_up) {
// 1. 计算关节2角度
double cos_theta2 = (x*x + y*y - L1*L1 - L2*L2) / (2 * L1 * L2);
if (fabs(cos_theta2) > 1.0) {
return -1; // 无解,目标点超出工作空间
}
// 肘部朝上或朝下
double sin_theta2 = elbow_up ? sqrt(1 - cos_theta2*cos_theta2)
: -sqrt(1 - cos_theta2*cos_theta2);
sol->theta2 = atan2(sin_theta2, cos_theta2);
// 2. 计算关节1角度
double k1 = L1 + L2 * cos_theta2;
double k2 = L2 * sin_theta2;
sol->theta1 = atan2(y, x) - atan2(k2, k1);
// 3. 关节3位移(直接等于Z方向偏移)
sol->d3 = -z; // 假设基座在Z=0,末端向下为正
// 4. 关节4角度(末端姿态减去前两个关节的贡献)
sol->theta4 = phi - sol->theta1 - sol->theta2;
return 0; // 求解成功
}
elbow_up参数用来选择“肘部朝上”还是“肘部朝下”。这就是多解问题的典型处理方式——把选择权交给上层逻辑。
4.7 奇异点检测与处理
在实际的控制器中,我会在每一个控制周期都做一次奇异点检测。方法很简单:计算雅可比矩阵的行列式,如果绝对值小于某个阈值,就认为进入了奇异区域。
// 奇异点检测示例
double det = computeJacobianDeterminant(joint_angles);
if (fabs(det) < SINGULARITY_THRESHOLD) {
// 进入奇异区域,切换策略
// 策略1:限制关节速度
// 策略2:在笛卡尔空间做阻尼最小二乘
// 策略3:重新规划路径,绕开奇异点
enterSingularityAvoidanceMode();
}
嗯,这里要提醒一句:阈值不能设得太小,否则检测不到;也不能设得太大,否则正常运动也被误判为奇异。我一般取0.01到0.05之间,具体要看机器人的尺寸和关节速度范围。
好了,逆运动学的内容就讲到这里。多解问题和奇异点分析,是实际工程中必须面对的两个坎。跨过去,你的机器人就能跑得又稳又准。