4. 正运动学建模:D-H参数法详解、建立连杆坐标系、正运动学方程推导

正运动学,说白了就是:给定关节角度,算出末端在哪儿。

我刚开始做人形机器人那会儿,总觉得这步是纯数学推导,跟实际工程关系不大。直到有一次,我调试一个双足平衡算法,发现脚底传感器数据跟模型预测的位置差了 5 厘米。查了两天,最后发现是 D-H 参数表里一个 a 值写反了。嗯,从那以后,我再也不敢小看这个建模步骤了。

这一章,我们就来把 D-H 参数法彻底讲透。你跟着我走一遍,保证能自己搭出任意构型机器人的正运动学模型。

4.1 D-H 参数法的核心思想

D-H 参数法,本质上是给每个关节建立一个坐标系,然后用 4 个参数来描述相邻坐标系之间的变换关系。这 4 个参数分别是:

  • θ (关节角):绕 Z 轴的旋转角度
  • d (连杆偏距):沿 Z 轴的平移距离
  • a (连杆长度):沿 X 轴的平移距离
  • α (连杆扭角):绕 X 轴的旋转角度

你想想看,一个刚体在空间中有 6 个自由度(3 个平移 + 3 个旋转)。但 D-H 法只用 4 个参数就描述了相邻连杆的位姿关系。为什么能省掉 2 个?因为 D-H 法对坐标系的建立方式做了约束——X 轴必须垂直于前一个 Z 轴。这个约束让两个自由度被隐含掉了。

我的习惯: 每次建立 D-H 坐标系前,我都会先在草稿纸上画出关节轴线。把 Z 轴方向定好,剩下的 X 轴和 Y 轴就顺理成章了。千万别一上来就填参数表,容易乱。

4.2 建立连杆坐标系的步骤

建立坐标系是 D-H 法里最容易出错的一步。我总结了一个「三步法」,你照着做,基本不会跑偏。

  1. 定 Z 轴:每个关节的 Z 轴沿着关节的旋转轴线方向。对于旋转关节,Z 轴就是旋转轴;对于移动关节,Z 轴就是平移方向。
  2. 定 X 轴:X 轴沿着相邻两个 Z 轴的公垂线方向,从当前 Z 轴指向下一个 Z 轴。如果两个 Z 轴相交,X 轴垂直于两个 Z 轴所在的平面。
  3. 定 Y 轴:Y 轴由右手定则确定,Y = Z × X。

这里有个坑,我踩过:基坐标系(第 0 号坐标系)的建立。基坐标系的 Z 轴通常与第一个关节的 Z 轴重合,但 X 轴可以任意选择,只要方便后续计算就行。我个人习惯把基坐标系的 X 轴指向机器人正前方。

我曾经犯过的错: 在建立人形机器人髋关节的坐标系时,我把左腿和右腿的 Z 轴方向搞反了。结果正运动学算出来,左腿的末端位置跑到了右腿那边。后来我养成了一个习惯:所有关节的 Z 轴方向必须统一,要么都指向机器人内部,要么都指向外部。

4.3 D-H 参数表填写

坐标系建好了,接下来就是填参数表。我们以人形机器人的一条腿为例,假设它有 6 个自由度(髋关节 3 个 + 膝关节 1 个 + 踝关节 2 个)。

连杆 i θ_i (关节角) d_i (连杆偏距) a_i (连杆长度) α_i (连杆扭角)
1 (髋关节偏摆) θ_1 0 0 -90°
2 (髋关节俯仰) θ_2 0 L1 0°
3 (髋关节滚动) θ_3 0 0 -90°
4 (膝关节俯仰) θ_4 0 L2 0°
5 (踝关节俯仰) θ_5 0 0 90°
6 (踝关节滚动) θ_6 0 0 0°

注意看,这里的 d_i 全部为 0。为什么?因为人形机器人的腿关节都是旋转关节,没有平移关节。如果你做的是工业机械臂,d_i 通常不为 0。

关键点: D-H 参数表中的 θ_i 是变量(对于旋转关节),而 d_i、a_i、α_i 是常量。正运动学的目标,就是把这些常量跟变量组合起来,算出末端位姿。

4.4 相邻连杆的变换矩阵

有了 D-H 参数,我们就可以写出相邻坐标系之间的齐次变换矩阵了。公式长这样:

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

展开成 4×4 矩阵形式:

| 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         |

这个矩阵,我建议你手推一遍。别偷懒。我当年在研究生阶段,把这个矩阵推了不下 20 遍,后来闭着眼睛都能写出来。为什么?因为后面所有的运动学计算,都基于这个矩阵。

4.5 正运动学方程推导

正运动学方程,就是把所有相邻变换矩阵乘起来:

T_0_n = T_1 * T_2 * T_3 * ... * T_n

对于人形机器人的一条腿,n=6,所以:

T_0_6 = T_1 * T_2 * T_3 * T_4 * T_5 * T_6

这个 T_0_6 矩阵的左上角 3×3 部分,就是末端(脚底)的姿态;右上角 3×1 部分,就是末端的位置。

实际工程中,我们很少手动去乘 6 个 4×4 矩阵。我一般用 MATLAB 的符号工具箱或者 Python 的 SymPy 来做符号推导。但有一点要注意:矩阵乘法不满足交换律,顺序一定不能错。

我的工程经验: 在写代码实现正运动学时,我会先写一个函数,输入是 D-H 参数表和一个关节角度向量,输出是末端位姿矩阵。然后我会用几个已知的关节角度组合(比如所有关节角度为 0)来验证结果。如果末端位置跟机械设计图纸上的尺寸对不上,那肯定是 D-H 参数或者坐标系方向有问题。

4.6 知识体系总览

下面这张图,把正运动学建模的整个流程串起来了。你对照着看,思路会更清晰。

正运动学建模流程 正运动学建模流程 1. 确定关节轴线 2. 建立连杆坐标系 3. 填写 D-H 参数表 4. 写出变换矩阵 5. 矩阵连乘 6. 得到末端位姿 说明: • 步骤 1-3 是准备工作,决定了模型的正确性 • 步骤 4-5 是数学推导,可以用符号计算工具辅助 • 步骤 6 是最终结果,用于后续的逆运动学、轨迹规划等

4.7 实战:用 Python 实现正运动学

理论讲完了,我们上手写代码。下面是一个简单的 Python 实现,输入 D-H 参数和关节角度,输出末端位姿矩阵。

import numpy as np

def dh_transform(theta, d, a, alpha):
    """
    计算单个 D-H 变换矩阵
    """
    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):
    """
    正运动学计算
    dh_params: [[d, a, alpha], ...] 每个连杆的常量参数
    joint_angles: [theta1, theta2, ...] 关节角度
    """
    T = np.eye(4)
    for i in range(len(joint_angles)):
        Ti = dh_transform(joint_angles[i], dh_params[i][0], 
                          dh_params[i][1], dh_params[i][2])
        T = T @ Ti
    return T

# 示例:人形机器人右腿 D-H 参数(简化版)
# 参数格式:[d, a, alpha]
dh_params = [
    [0, 0, -np.pi/2],   # 髋关节偏摆
    [0, 0.4, 0],        # 髋关节俯仰 (大腿长度 0.4m)
    [0, 0, -np.pi/2],   # 髋关节滚动
    [0, 0.4, 0],        # 膝关节俯仰 (小腿长度 0.4m)
    [0, 0, np.pi/2],    # 踝关节俯仰
    [0, 0, 0]           # 踝关节滚动
]

# 假设所有关节角度为 0
joint_angles = [0, 0, 0, 0, 0, 0]
T_end = forward_kinematics(dh_params, joint_angles)
print("末端位姿矩阵:")
print(T_end)
print("\n末端位置:", T_end[:3, 3])

运行这段代码,你会得到末端位置是 [0.8, 0, 0]。为什么是 0.8?因为大腿和小腿长度都是 0.4 米,伸直状态下总长就是 0.8 米。这个结果跟机械设计图纸对得上,说明我们的 D-H 参数和坐标系建立是正确的。

验证方法: 每次改完 D-H 参数,我都会用「零位验证法」——把所有关节角度设为零,看末端位置是否等于机械臂/腿的展开长度。如果对不上,一定是某个参数或者坐标系方向错了。

4.8 常见错误与避坑指南

  • Z 轴方向不一致:同一个机器人,所有关节的 Z 轴方向必须统一。我见过有人把左腿的 Z 轴朝上,右腿的 Z 轴朝下,结果正运动学算出来的两条腿长度不一样。
  • α 的符号搞反:α 的正负取决于 X 轴的旋转方向。用右手定则判断,别想当然。
  • 矩阵乘法顺序:T_0_n = T_1 * T_2 * ... * T_n,不是反过来。我刚开始写代码时,把乘法顺序写反了,结果末端位置飞到了天上去。
  • 忽略基坐标系:基坐标系的位置和方向会影响所有后续计算。建议把基坐标系固定在机器人躯干的几何中心。