2. 机器人运动学基础:位姿描述与齐次变换,D-H参数法建立运动学模型,正运动学与逆运动学求解

各位同学,欢迎来到第二章。这一章是整个轨迹规划的基石。说白了,你要让机器人动起来,首先得知道它现在在哪、胳膊怎么伸的。这就是运动学要解决的问题。

我个人习惯把运动学比作「给机器人拍X光片」——我们不关心它为什么有力气,只关心骨头之间的相对位置和角度。嗯,这个比喻可能不太严谨,但你记住这个感觉就好。

2.1 位姿描述:位置与姿态

机器人学里,描述一个物体在空间中的状态,需要两样东西:位置姿态。合起来叫位姿

  • 位置:用三维坐标 (x, y, z) 表示。比如机器人末端在空间中的某个点。
  • 姿态:用旋转矩阵、欧拉角或四元数表示。描述这个物体是正着、歪着还是倒着。

我在项目中遇到过一个问题:一个六轴机器人抓取工件时,明明位置对了,但姿态偏了0.5度,结果工件卡在夹具里出不来。你看,姿态的精度有时候比位置还关键。

重要概念:一个刚体在空间中的自由度是6个(3个平移 + 3个旋转)。所以描述位姿,最少需要6个独立参数。

2.2 齐次变换矩阵

为什么要用齐次变换?你想想看,如果位置用3x1向量,旋转用3x3矩阵,那你要做一次坐标变换,就得分开算旋转和平移,很麻烦。齐次变换矩阵把两者统一成4x4矩阵,一次乘法搞定所有。

齐次变换矩阵 T 的形式如下:

T = [ R   p ]
    [ 0   1 ]

其中 R 是 3x3 旋转矩阵,p 是 3x1 位置向量。最后一行是 [0 0 0 1],这是齐次坐标的固定格式。

举个例子,坐标系 {B} 相对于坐标系 {A} 的描述:

^A_T_B = [ ^A_R_B   ^A_p_B ]
         [   0        1    ]

这个矩阵可以连续乘。比如从基座到末端,中间经过关节1、2、3... 每个关节一个变换矩阵,乘起来就是末端相对于基座的位姿。这就是正运动学的核心思想。

我的小技巧:写代码时,我习惯把齐次变换矩阵封装成一个类,包含旋转矩阵和平移向量。这样调试的时候,可以单独打印旋转部分和平移部分,方便定位问题。

2.3 D-H参数法:建立运动学模型

D-H参数法,全称Denavit-Hartenberg参数法。这是机器人学里最经典的运动学建模方法。我刚开始学的时候觉得它很绕,后来发现其实就是四个参数描述两个相邻关节之间的关系。

四个参数分别是:

参数 符号 含义
连杆长度 ai 沿xi轴,从zi到zi+1的距离
连杆扭角 αi 绕xi轴,从zi到zi+1的转角
连杆偏距 di 沿zi轴,从xi-1到xi的距离
关节转角 θi 绕zi轴,从xi-1到xi的转角

对于旋转关节,θi是变量;对于移动关节,di是变量。其他三个参数是固定的,由机器人结构决定。

我曾经在调试一个SCARA机器人时,发现D-H参数表里一个α的符号写反了,结果正运动学算出来的末端位置差了十几毫米。查了两天才找到问题。嗯,D-H参数表一定要反复核对。

相邻关节的变换矩阵公式:

T_i = Rot(z, θ_i) * Trans(z, d_i) * Trans(x, a_i) * Rot(x, α_i)

展开后:

T_i = [ cosθ_i   -sinθ_i*cosα_i   sinθ_i*sinα_i   a_i*cosθ_i ]
      [ sinθ_i    cosθ_i*cosα_i  -cosθ_i*sinα_i   a_i*sinθ_i ]
      [    0          sinα_i          cosα_i          d_i     ]
      [    0            0               0              1      ]

注意:D-H参数有两种约定——标准D-H和改进D-H。区别在于坐标系建立的位置不同。我个人习惯用标准D-H,但如果你用ROS,它默认是改进D-H。混用会出大问题,切记!

2.4 正运动学求解

正运动学,就是已知关节角度(或位移),求末端位姿。说白了,你告诉机器人每个关节转多少度,它告诉你手在哪。

对于n轴机器人,正运动学公式很简单:

^0_T_n = T_1 * T_2 * T_3 * ... * T_n

其中T_i是第i个关节的D-H变换矩阵。乘出来的结果是一个4x4齐次变换矩阵,包含了末端的位置和姿态。

举个例子,一个六轴机器人,给定六个关节角度θ1到θ6,代入D-H参数表,依次计算T1到T6,然后乘起来。就这么简单。

代码实现也很直接:

def forward_kinematics(theta, dh_params):
    # dh_params: [a, alpha, d, theta_offset]
    T = np.eye(4)
    for i in range(len(theta)):
        a, alpha, d, offset = dh_params[i]
        theta_i = theta[i] + offset
        Ti = dh_transform(a, alpha, d, theta_i)
        T = T @ Ti
    return T

我在项目中用这个函数做过实时正运动学计算,在100Hz的控制周期里跑,完全没问题。计算量其实很小。

2.5 逆运动学求解

逆运动学就麻烦多了。已知末端位姿,求关节角度。说白了,你告诉机器人手要放到哪,它自己算每个关节该转多少。

为什么麻烦?因为逆运动学通常有多个解,甚至无解。比如一个六轴机器人,同一个末端位姿可能有8组关节角度解。你想想看,肘关节可以朝上也可以朝下,手腕可以翻转也可以不翻转,组合起来就多了。

求解方法主要有两种:

  • 解析法:通过几何或代数推导出封闭解。速度快,但只适用于满足Pieper准则的机器人(相邻三个关节轴交于一点)。大多数工业六轴机器人满足这个条件。
  • 数值法:用迭代优化求解,比如牛顿-拉夫森法。通用性强,但速度慢,且可能不收敛。

我个人偏好解析法。为什么?因为稳定。数值法在奇异点附近容易发散,而解析法只要公式推导正确,结果就是确定的。

以典型的六轴工业机器人为例,逆运动学求解步骤大致如下:

  1. 从末端位姿反推腕部中心位置(因为最后三个关节决定姿态)
  2. 根据腕部中心位置求解前三个关节角度(通常有2-4组解)
  3. 根据前三个关节角度和末端姿态,求解后三个关节角度
  4. 组合所有可能的解,剔除超出关节限位的解
  5. 从剩余解中选择最优解(比如关节运动量最小的那个)

避坑指南:我曾经在逆运动学求解时,没有处理奇异点。结果机器人在某个位姿附近突然关节速度突变,差点撞到工件。后来我加了一个奇异点检测,当接近奇异位形时,切换到数值法并限制关节速度。嗯,这个坑踩得值。

2.6 运动学在实际项目中的应用

讲完理论,说说实际怎么用。运动学在工业机器人里无处不在:

  • 示教编程:操作员拖动示教器,系统实时计算正运动学,显示末端位姿。
  • 离线编程:在软件里规划路径,用逆运动学把路径点转换成关节角度序列。
  • 轨迹插补:在笛卡尔空间插补时,每个插补点都要做一次逆运动学,得到关节角度。
  • 碰撞检测:用正运动学实时计算各连杆的位置,判断是否与环境碰撞。

我记得有一次做焊接机器人项目,焊缝是一条空间曲线。我们在笛卡尔空间均匀采样了1000个点,每个点做逆运动学求解。结果发现有些点无解——因为超出了机器人的工作空间。后来调整了工件摆放位置才解决。所以,做轨迹规划前,一定要先确认目标位姿在机器人的可达范围内。

实用建议:写运动学代码时,先把正运动学写好并验证正确。然后用正运动学生成大量随机关节角度对应的末端位姿,作为逆运动学测试的样本。这样能快速发现逆运动学代码的bug。

好了,这一章的内容就到这里。运动学是机器人学的「内功」,基础打牢了,后面学轨迹规划、动力学、控制才会顺手。下一章我们讲轨迹插补的具体算法,到时候会大量用到今天学的齐次变换和运动学求解。