1. 机器人运动学基础:刚体变换、齐次坐标、DH参数法、正逆运动学求解
各位同学,欢迎来到《机器人轨迹规划全流程》的第一章。
说实话,运动学是整个机器人学的「地基」。你后面做轨迹规划、动力学控制、甚至是视觉伺服,都离不开这一章的内容。我见过不少新手,一上来就调PID、跑路径,结果机器人撞了都不知道为啥——说白了,就是运动学没搞透。
这一章,我会带你从最基础的刚体变换开始,一步步走到正逆运动学求解。嗯,内容不少,但都是硬货。
1.1 刚体变换:机器人的「骨架」怎么动?
先问一个问题:一个机械臂在空间里运动,本质上是什么在变?
答案是——刚体的位置和姿态。刚体,就是不会变形的物体。机器人的每个连杆,我们都可以看作一个刚体。
刚体变换,说白了就是描述一个刚体从A位置到B位置,怎么转、怎么移。它包含两部分:
- 旋转:描述刚体「朝向」的变化
- 平移:描述刚体「位置」的变化
我个人习惯把旋转矩阵记作 R,平移向量记作 t。那么一个完整的刚体变换可以写成:
p' = R * p + t
其中 p 是原始点坐标,p' 是变换后的坐标。
1.2 齐次坐标:把旋转和平移「打包」
你发现没有?上面的公式 p' = R*p + t 写起来有点啰嗦。而且旋转和平移是分开的,不方便做连续变换。
这时候,齐次坐标就派上用场了。
齐次坐标的核心思想很简单:给三维坐标加一个维度,变成四维。这样,旋转和平移就可以合并成一个 4x4 的矩阵:
| R t | | x |
| 0 1 | * | y |
| z |
| 1 |
这个 4x4 矩阵,就是齐次变换矩阵。它把旋转和平移「打包」在一起,一次矩阵乘法就能完成整个变换。
- 连续变换可以写成矩阵连乘:T = T1 * T2 * T3 ...
- 逆变换直接求矩阵逆就行,不用分开算旋转和平移
- 代码实现简单,一个矩阵搞定所有
我记得第一次用齐次坐标写代码时,感觉整个世界都清爽了。之前用欧拉角做连续旋转,各种万向锁、奇异性问题,换成齐次矩阵后,这些问题基本都绕开了。
1.3 DH参数法:给机器人「建模」的标准语言
好了,现在我们知道怎么描述一个刚体的运动了。但一个机械臂有6个、7个甚至更多连杆,怎么描述它们之间的关系?
Denavit-Hartenberg参数法,也就是DH参数法,就是干这个的。它用4个参数来描述相邻两个连杆之间的变换关系:
| 参数 | 符号 | 含义 |
|---|---|---|
| 连杆长度 | ai-1 | 沿xi-1轴,从zi-1到zi的距离 |
| 连杆扭角 | αi-1 | 绕xi-1轴,从zi-1到zi的角度 |
| 连杆偏距 | di | 沿zi轴,从xi-1到xi的距离 |
| 关节角 | θi | 绕zi轴,从xi-1到xi的角度 |
有了这4个参数,相邻连杆的变换矩阵就可以写成标准形式:
T_i = Rot(x, α_{i-1}) * Trans(x, a_{i-1}) * Rot(z, θ_i) * Trans(z, d_i)
你想想看,整个机械臂的末端位姿,就是把这些矩阵一个一个乘起来:
T_0n = T_1 * T_2 * ... * T_n
下面这张图展示了DH参数法的核心流程:
1.4 正运动学求解:已知关节角,求末端位姿
正运动学,就是已知每个关节的角度(或位移),求机器人末端在空间中的位置和姿态。
说白了,就是「输入关节角,输出末端位姿」。
求解方法我们已经有了——就是上面说的DH参数法。把每个关节的变换矩阵乘起来,得到的就是末端相对于基座的位姿。
- 建立DH参数表(每个关节一行)
- 根据当前关节角,计算每个关节的变换矩阵 T_i
- 连乘所有 T_i,得到 T_0n
- 从 T_0n 中提取位置向量和旋转矩阵
代码实现其实很直接。我习惯用Python写一个通用函数:
import numpy as np
def dh_transform(a, alpha, d, theta):
"""根据DH参数计算单个关节的变换矩阵"""
ct = np.cos(theta)
st = np.sin(theta)
ca = np.cos(alpha)
sa = np.sin(alpha)
T = np.array([
[ct, -st*ca, st*sa, a*ct],
[st, ct*ca, -ct*sa, a*st],
[0, sa, ca, d ],
[0, 0, 0, 1 ]
])
return T
def forward_kinematics(dh_params, joint_angles):
"""正运动学求解"""
T = np.eye(4)
for i in range(len(joint_angles)):
a, alpha, d = dh_params[i]
theta = joint_angles[i]
T_i = dh_transform(a, alpha, d, theta)
T = T @ T_i
return T
1.5 逆运动学求解:已知末端位姿,求关节角
逆运动学正好反过来——已知末端要到达的位置和姿态,反推每个关节应该转多少度。
这比正运动学难多了。为什么?因为:
- 解可能不唯一(同一个末端位姿,可能有多种关节角度组合)
- 可能无解(末端位姿超出了机器人的工作空间)
- 解析解只存在于特定构型的机器人(比如有相邻三轴交于一点的机器人)
求解方法主要有两种:
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 解析法(封闭解) | 速度快、精度高、所有解都能找到 | 需要机器人满足特定几何条件 | 工业机器人(如6轴机器人有封闭解) |
| 数值法(迭代法) | 通用性强,任何机器人都能用 | 速度慢、可能陷入局部最优、需要初值 | 冗余机器人、特殊构型机器人 |
对于常见的6轴工业机器人,因为有相邻三轴交于一点(腕部),可以用解析法求解。基本思路是:
- 先解前三个关节(决定腕部位置)
- 再解后三个关节(决定末端姿态)
- 组合成完整的关节角度
这里我给出一个简化的解析法框架:
def inverse_kinematics(T_target, dh_params):
"""
逆运动学求解(简化版)
假设机器人满足Pieper准则(相邻三轴交于一点)
"""
# 1. 从目标位姿矩阵中提取位置和姿态
position = T_target[:3, 3]
rotation = T_target[:3, :3]
# 2. 计算腕部位置(前三个关节决定)
wrist_pos = compute_wrist_position(position, rotation, dh_params)
# 3. 解前三个关节角
q1, q2, q3 = solve_first_three_joints(wrist_pos, dh_params)
# 4. 解后三个关节角
q4, q5, q6 = solve_last_three_joints(rotation, q1, q2, q3, dh_params)
return [q1, q2, q3, q4, q5, q6]
- 优先用解析法,速度快且稳定
- 如果必须用数值法,给一个好的初值(比如上一时刻的关节角)
- 始终检查解的可行性(关节限位、奇异位形)
- 保留多组解,让上层规划器选择最优的一组
好了,这一章的内容就到这里。运动学基础是后面所有章节的基石,尤其是DH参数法和正逆运动学求解,在轨迹规划中会反复用到。建议你把上面的代码自己跑一遍,改改参数,看看末端位姿怎么变——动手做一遍,比看十遍都管用。