机械臂正解(MDH)推导过程及python示例

一、Modified DH 参数简介(Khalil-Breteler 版本)

Modified DH 参数(MDH)与标准 Denavit-Hartenberg 参数(SDH)不同,它的连杆坐标系是按照如下规则建立的:

  1. zi−1z_{i-1}zi−1​ 轴:沿第 i−1i-1i−1 个关节轴方向。
  2. xix_ixi​ 轴:沿从 zi−1z_{i-1}zi−1​ 到 ziz_izi​ 的公垂线方向。
  3. 原点:位于 xix_ixi​ 与 zi−1z_{i-1}zi−1​ 的交点。
  4. 参数定义如下:
参数含义
θi\theta_iθi​绕 zi−1z_{i-1}zi−1​ 轴旋转,从 xi−1x_{i-1}xi−1​ 到 xix_ixi​ 的角度
did_idi​沿 zi−1z_{i-1}zi−1​ 轴从 xi−1x_{i-1}xi−1​ 到 xix_ixi​ 的平移
aia_iai​沿 xix_ixi​ 轴从 zi−1z_{i-1}zi−1​ 到 ziz_izi​ 的平移
αi\alpha_iαi​绕 xix_ixi​ 轴旋转,从 zi−1z_{i-1}zi−1​ 到 ziz_izi​ 的角度

二、MDH 变换的分解

MDH 的变换矩阵可以分解为如下四个基本变换步骤(按顺序):

  1. 绕 zi−1z_{i-1}zi−1​ 轴旋转 θi\theta_iθi​
    Rot(zi−1,θi) \text{Rot}(z_{i-1}, \theta_i) Rot(zi−1​,θi​)

  2. 沿 zi−1z_{i-1}zi−1​ 轴平移 did_idi​
    Trans(zi−1,di) \text{Trans}(z_{i-1}, d_i) Trans(zi−1​,di​)

  3. 绕 xix_ixi​ 轴旋转 αi\alpha_iαi​
    Rot(xi,αi) \text{Rot}(x_i, \alpha_i) Rot(xi​,αi​)

  4. 沿 xix_ixi​ 轴平移 aia_iai​
    Trans(xi,ai) \text{Trans}(x_i, a_i) Trans(xi​,ai​)

注意:这里的顺序是 Khalil-Breteler 版本的 MDH 定义。


三、逐个写出变换矩阵

1. 绕 zi−1z_{i-1}zi−1​ 轴旋转 θi\theta_iθi​

Rot(z,θ)=[cos⁡θ−sin⁡θ00sin⁡θcos⁡θ0000100001] \text{Rot}(z, \theta) = \begin{bmatrix} \cos\theta & -\sin\theta & 0 & 0 \\ \sin\theta & \cos\theta & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} Rot(z,θ)=​cosθsinθ00​−sinθcosθ00​0010​0001​​

2. 沿 zi−1z_{i-1}zi−1​ 轴平移 did_idi​

Trans(z,d)=[10000100001d0001] \text{Trans}(z, d) = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & d \\ 0 & 0 & 0 & 1 \end{bmatrix} Trans(z,d)=​1000​0100​0010​00d1​​

3. 绕 xix_ixi​ 轴旋转 αi\alpha_iαi​

Rot(x,α)=[10000cos⁡α−sin⁡α00sin⁡αcos⁡α00001] \text{Rot}(x, \alpha) = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos\alpha & -\sin\alpha & 0 \\ 0 & \sin\alpha & \cos\alpha & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} Rot(x,α)=​1000​0cosαsinα0​0−sinαcosα0​0001​​

4. 沿 xix_ixi​ 轴平移 aia_iai​

Trans(x,a)=[100a010000100001] \text{Trans}(x, a) = \begin{bmatrix} 1 & 0 & 0 & a \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} Trans(x,a)=​1000​0100​0010​a001​​


四、矩阵乘法合成变换矩阵

将以上四个变换按顺序相乘:

Tii−1=Trans(x,a)⋅Rot(x,α)⋅Trans(z,d)⋅Rot(z,θ) T_i^{i-1} = \text{Trans}(x, a) \cdot \text{Rot}(x, \alpha) \cdot \text{Trans}(z, d) \cdot \text{Rot}(z, \theta) Tii−1​=Trans(x,a)⋅Rot(x,α)⋅Trans(z,d)⋅Rot(z,θ)

逐个相乘:

步骤 1:先乘 Rot(z) 和 Trans(z)

T12=Trans(z,d)⋅Rot(z,θ)=[cos⁡θ−sin⁡θ00sin⁡θcos⁡θ00001d0001] T_{12} = \text{Trans}(z, d) \cdot \text{Rot}(z, \theta) = \begin{bmatrix} \cos\theta & -\sin\theta & 0 & 0 \\ \sin\theta & \cos\theta & 0 & 0 \\ 0 & 0 & 1 & d \\ 0 & 0 & 0 & 1 \end{bmatrix} T12​=Trans(z,d)⋅Rot(z,θ)=​cosθsinθ00​−sinθcosθ00​0010​00d1​​

步骤 2:乘 Rot(x, α)

T123=Rot(x,α)⋅T12=[cos⁡θ−sin⁡θ00sin⁡θcos⁡αcos⁡θcos⁡α−sin⁡α−dsin⁡αsin⁡θsin⁡αcos⁡θsin⁡αcos⁡αdcos⁡α0001] T_{123} = \text{Rot}(x, \alpha) \cdot T_{12} = \begin{bmatrix} \cos\theta & -\sin\theta & 0 & 0 \\ \sin\theta \cos\alpha & \cos\theta \cos\alpha & -\sin\alpha & -d \sin\alpha \\ \sin\theta \sin\alpha & \cos\theta \sin\alpha & \cos\alpha & d \cos\alpha \\ 0 & 0 & 0 & 1 \end{bmatrix} T123​=Rot(x,α)⋅T12​=​cosθsinθcosαsinθsinα0​−sinθcosθcosαcosθsinα0​0−sinαcosα0​0−dsinαdcosα1​​

步骤 3:乘 Trans(x, a)

Tii−1=Trans(x,a)⋅T123=[cos⁡θ−sin⁡θ0asin⁡θcos⁡αcos⁡θcos⁡α−sin⁡α−dsin⁡αsin⁡θsin⁡αcos⁡θsin⁡αcos⁡αdcos⁡α0001] T_i^{i-1} = \text{Trans}(x, a) \cdot T_{123} = \begin{bmatrix} \cos\theta & -\sin\theta & 0 & a \\ \sin\theta \cos\alpha & \cos\theta \cos\alpha & -\sin\alpha & -d \sin\alpha \\ \sin\theta \sin\alpha & \cos\theta \sin\alpha & \cos\alpha & d \cos\alpha \\ 0 & 0 & 0 & 1 \end{bmatrix} Tii−1​=Trans(x,a)⋅T123​=​cosθsinθcosαsinθsinα0​−sinθcosθcosαcosθsinα0​0−sinαcosα0​a−dsinαdcosα1​​


五、最终 MDH 矩阵表达式

这就是你函数中返回的变换矩阵:

Tii−1=[cos⁡θ−sin⁡θ0asin⁡θcos⁡αcos⁡θcos⁡α−sin⁡α−dsin⁡αsin⁡θsin⁡αcos⁡θsin⁡αcos⁡αdcos⁡α0001] T_i^{i-1} = \begin{bmatrix} \cos\theta & -\sin\theta & 0 & a \\ \sin\theta \cos\alpha & \cos\theta \cos\alpha & -\sin\alpha & -d \sin\alpha \\ \sin\theta \sin\alpha & \cos\theta \sin\alpha & \cos\alpha & d \cos\alpha \\ 0 & 0 & 0 & 1 \end{bmatrix} Tii−1​=​cosθsinθcosαsinθsinα0​−sinθcosθcosαcosθsinα0​0−sinαcosα0​a−dsinαdcosα1​​


六、Python 实现

import numpy as np
from typing import List, Tuple, Optional
from dataclasses import dataclass

def mdh_matrix_khalil(alpha: float, a: float, d: float, theta: float) -> np.ndarray:
    """
    计算 Khalil-Breteler 版本的 Modified DH 变换矩阵。
    参数:
        alpha: 扭转角 (弧度)
        a: 连杆长度
        d: 偏移量
        theta: 关节角 (弧度)
    返回:
        T: 4x4 齐次变换矩阵
    """
    ca, sa = np.cos(alpha), np.sin(alpha)
    ct, st = np.cos(theta), np.sin(theta)

    return np.array([
        [ct,       -st,        0,         a        ],
        [st * ca,  ct * ca,  -sa,       -sa * d    ],
        [st * sa,  ct * sa,   ca,        ca * d    ],
        [0,         0,        0,         1         ]
    ], dtype=np.float64)


def forward_kinematics_mdh_khalil(
    dh_params: List[Tuple[float, float, float, float]],
    joint_angles: List[float]
) -> List[np.ndarray]:
    """
    使用 Khalil 版本的 Modified DH 参数计算正向运动学。
    返回所有中间关节的变换矩阵。
    
    参数:
        dh_params: 每个连杆的 MDH 参数列表 [(alpha, a, d, theta_offset), ...]
        joint_angles: 各关节角度列表 [theta1, theta2, ...]
    返回:
        transforms: 每个关节相对于基坐标系的变换矩阵列表
    """
    if len(dh_params) != len(joint_angles):
        raise ValueError("DH 参数与关节角度数量不一致")

    T = np.eye(4)
    transforms = [T.copy()]  # 初始为基坐标系 {0}

    for i, (alpha, a, d, theta_offset) in enumerate(dh_params):
        theta = theta_offset + joint_angles[i]  # 添加关节角度
        T_i = mdh_matrix_khalil(alpha, a, d, theta)
        T = T @ T_i  # 累乘变换矩阵
        transforms.append(T)

    return transforms


# ======================
# 示例部分
# ======================
if __name__ == "__main__":
    np.set_printoptions(precision=4, suppress=True)

    # # 示例 DH 参数(3自由度机械臂,MDH格式)
    # dh_params = [
    #     (0, 0, 0, 0),     # 连杆1
    #     (0, 1, 0, 0),     # 连杆2
    #     (0, 1, 0, 0),      # 连杆3
    #     (0, 1, 0, 0)      # 连杆3
    # ]

    # # 关节角度输入(弧度值)
    # joint_angles = [np.pi/2, np.pi/2, np.pi/2,-np.pi/2]
        # 示例 DH 参数(3自由度机械臂,MDH格式)
    dh_params = [
        (0, 0, 265, 0),     # 连杆1
        (-np.pi/2, 0, 0, 0),     # 连杆2
        (0, 444, 0, 0)      # 连杆3
        # (-np.pi/2, 110, 470, 0)      # 连杆3
    ]

    # 关节角度输入(弧度值)
    joint_angles = [0, -np.pi/2, 0]
    

    # 计算所有关节的变换矩阵
    transforms = forward_kinematics_mdh_khalil(dh_params, joint_angles)

    # 提取末端执行器(最后一个关节)的变换矩阵
    T_end_effector = transforms[-1]

    # 提取位置和姿态
    position = T_end_effector[:3, 3]
    x, y, z = position
    rotation_matrix = T_end_effector[:3, :3]

    print("末端执行器在基坐标系 x0y0z0 下的位姿:")
    print(f"\n位置 (x, y, z): x={x:.4f}, y={y:.4f}, z={z:.4f}")
    print("\n姿态(旋转矩阵 R):")
    print(rotation_matrix)

注意:dh_params 为MDH的参数,joint_angles为各个关节的角度(弧度)。

Logo

立足具身智能前沿赛道,致力于搭建全球化、开源化、全栈式技术交流与实践共创平台。

更多推荐