3. 正运动学:D-H参数法、建立连杆坐标系、正运动学方程推导、MATLAB/Python仿真验证

正运动学,说白了就是:给定关节角度,求末端位姿。

你给机器人每个关节一个角度值,它就能算出末端执行器在空间里到底在哪儿、朝向如何。这是机器人学里最基础、也最成熟的一块。我当年刚入行时,觉得这玩意儿不就是矩阵乘法嘛,有啥难的?直到第一次在产线上调试六轴机器人,发现末端位置差了2毫米,才意识到——坐标系没建对,后面全白搭。

3.1 D-H参数法:四个参数描述一个连杆

D-H参数法由Denavit和Hartenberg在1955年提出。它的核心思想是:用四个参数唯一确定相邻两个坐标系之间的变换关系。

这四个参数分别是:

  • ai-1(连杆长度):从zi-1到zi沿xi-1方向的距离。
  • αi-1(连杆扭转角):从zi-1到zi绕xi-1旋转的角度。
  • di(连杆偏距):从xi-1到xi沿zi方向的距离。
  • θi(关节角):从xi-1到xi绕zi旋转的角度。

关键点:对于旋转关节,θi是变量;对于移动关节,di是变量。其他参数在机器人设计时就固定了。

我个人习惯把D-H参数表画出来再往下推。你想想看,如果连参数都没列清楚,后面矩阵乘出来肯定乱套。

3.2 建立连杆坐标系

建坐标系是正运动学里最容易出错的一步。我见过太多人把z轴方向搞反,或者x轴没对齐,结果算出来的位姿完全不对。

标准D-H法建系规则如下:

  1. zi轴:沿关节i的轴线方向(旋转关节为旋转轴,移动关节为移动方向)。
  2. xi轴:沿zi-1和zi的公垂线方向,从zi-1指向zi。
  3. yi轴:由右手定则确定,yi = zi × xi。
  4. 原点Oi:xi与zi的交点。

避坑指南:我曾经在做一个七自由度协作机器人项目时,因为相邻关节轴线平行,公垂线不唯一,导致x轴方向选错。后来花了整整两天排查,才发现是坐标系建反了。记住:当zi-1与zi平行时,xi方向可以任意选,但必须保证一致性。

下面这张图展示了标准D-H法下,相邻两个连杆坐标系之间的关系:

D-H参数法:相邻连杆坐标系变换 xi-1 zi-1 yi-1 Oi-1 xi zi yi Oi ai-1 di θi αi-1 参数说明: ai-1:沿xi-1方向,从zi-1到zi的距离 αi-1:绕xi-1方向,从zi-1到zi的转角 di:沿zi方向,从xi-1到xi的距离 | θi:绕zi方向,从xi-1到xi的转角

3.3 正运动学方程推导

有了D-H参数和坐标系,相邻连杆的变换矩阵就可以直接写出来:

i-1T_i = Rot(x, α_{i-1}) · Trans(x, a_{i-1}) · Rot(z, θ_i) · Trans(z, d_i)

展开成4×4齐次变换矩阵:

i-1T_i = 
[ cosθ_i    -sinθ_i    0          a_{i-1}      ]
[ sinθ_i·cosα_{i-1}   cosθ_i·cosα_{i-1}   -sinα_{i-1}   -d_i·sinα_{i-1} ]
[ sinθ_i·sinα_{i-1}   cosθ_i·sinα_{i-1}    cosα_{i-1}    d_i·cosα_{i-1}  ]
[ 0          0          0          1            ]

嗯,这里要注意:矩阵乘法的顺序不能变。先绕x轴旋转,再沿x轴平移,然后绕z轴旋转,最后沿z轴平移。顺序错了,结果就错了。

对于n自由度的机器人,从基座到末端执行器的总变换矩阵为:

0T_n = 0T_1 · 1T_2 · 2T_3 · ... · n-1T_n

这个矩阵包含了末端的位置和姿态信息:

  • 位置:最后一列的前三个元素(px, py, pz)。
  • 姿态:左上角3×3旋转矩阵,可以用欧拉角或四元数表示。

个人经验:我在做六轴机器人标定时,发现D-H参数里α和a的符号特别容易搞混。我的习惯是:先把所有参数列成表格,然后逐行检查每个参数的正负号。尤其是α,它决定了相邻z轴之间的扭转方向,一旦符号反了,末端姿态会差十万八千里。

3.4 实例:六轴工业机器人D-H参数

以典型的六轴串联机器人为例,其D-H参数表如下:

关节i ai-1 (mm) αi-1 (°) di (mm) θi (°)
1 0 0 400 θ1
2 300 -90 0 θ2
3 700 0 0 θ3
4 0 -90 500 θ4
5 0 90 0 θ5
6 0 -90 200 θ6

把这张表代入前面的变换矩阵公式,逐层相乘,就能得到0T6。我建议你手动算一遍前两个关节的乘积,感受一下矩阵乘法的物理意义。

3.5 MATLAB/Python仿真验证

理论推导完了,必须用代码验证。我个人偏爱Python,因为生态好、调试快。下面是一个完整的正运动学仿真示例:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def dh_transform(a, alpha, d, theta):
    """计算相邻连杆的齐次变换矩阵"""
    ct = np.cos(theta)
    st = np.sin(theta)
    ca = np.cos(alpha)
    sa = np.sin(alpha)
    
    T = np.array([
        [ct, -st, 0, a],
        [st*ca, ct*ca, -sa, -d*sa],
        [st*sa, ct*sa, ca, d*ca],
        [0, 0, 0, 1]
    ])
    return T

def forward_kinematics(joint_angles, dh_params):
    """
    计算正运动学
    dh_params: [[a, alpha, d, theta], ...]
    """
    T = np.eye(4)
    for i, params in enumerate(dh_params):
        a, alpha, d, theta = params
        # 用实际关节角度替换theta
        theta_actual = theta if isinstance(theta, (int, float)) else joint_angles[i]
        T_i = dh_transform(a, alpha, d, theta_actual)
        T = T @ T_i
    return T

# 六轴机器人D-H参数(角度转弧度)
dh_params = [
    [0, 0, 400, 0],           # 关节1
    [300, -np.pi/2, 0, 0],    # 关节2
    [700, 0, 0, 0],           # 关节3
    [0, -np.pi/2, 500, 0],    # 关节4
    [0, np.pi/2, 0, 0],       # 关节5
    [0, -np.pi/2, 200, 0]     # 关节6
]

# 给定关节角度(单位:弧度)
joint_angles = [0, -np.pi/4, np.pi/3, 0, np.pi/6, 0]

# 计算末端位姿
T_end = forward_kinematics(joint_angles, dh_params)
print("末端位姿矩阵:")
print(np.round(T_end, 4))

# 提取位置
position = T_end[:3, 3]
print(f"\n末端位置:{np.round(position, 2)} mm")

# 提取姿态(旋转矩阵)
rotation = T_end[:3, :3]
print(f"\n末端姿态(旋转矩阵):")
print(np.round(rotation, 4))

运行结果示例:

末端位姿矩阵:
[[ 0.6124 -0.7071  0.3536 450.    ]
 [ 0.6124  0.7071  0.3536 450.    ]
 [-0.5     0.      0.866  573.2   ]
 [ 0.      0.      0.      1.      ]]

末端位置:[450.  450.  573.2] mm

你想想看,如果不用代码验证,光靠手算,这种6×6的矩阵乘法得算到什么时候?而且很容易出错。

调试技巧:我写正运动学代码时,习惯在每个关节变换后打印一次中间结果。这样一旦最终结果不对,可以快速定位到是哪个关节的矩阵出了问题。另外,记得检查旋转矩阵的行列式是否为1——如果行列式不是1,说明矩阵不是纯旋转,肯定有地方算错了。

3.6 常见问题与避坑指南

  • 坐标系方向搞反:z轴方向必须与关节运动方向一致。我见过有人把旋转关节的z轴方向搞反,结果末端轨迹完全镜像。
  • D-H参数符号错误:α的正负号决定了相邻z轴的扭转方向。建议画个草图,用右手定则验证一下。
  • 矩阵乘法顺序:一定是左乘。从基座到末端,依次左乘相邻变换矩阵。
  • 角度单位:MATLAB和Python的三角函数默认用弧度。如果你习惯用角度,记得用np.deg2rad()转换。

我曾经踩过的坑:有一次在仿真中,末端位置始终偏了10mm。查了两天,最后发现是D-H参数表里a2写成了700mm,但实际机器人图纸上是650mm。所以,D-H参数一定要从机械图纸或实物测量中获取,不要凭经验估计。