3、DH参数建模:标准DH与改进DH的区别、连杆坐标系建立规则、参数表提取方法、代码实现DH变换矩阵

好,咱们进入第三章。DH参数建模,这可以说是机器人运动学的“通用语言”。不管你用啥机器人,UR、KUKA还是自己攒的六轴,想算逆解,第一步就是把机械臂的几何关系用数学描述清楚。

我个人习惯把DH参数比作“机械臂的身份证”。每个关节、每根连杆,都有四个固定参数。只要这四个数对了,末端位姿就能算出来。但这里有个坑——DH参数其实有两个流派:标准DH和改进DH。很多初学者在这上面栽跟头。

3.1 标准DH vs 改进DH:到底差在哪?

先看一张对比表,把核心区别说清楚。

对比项 标准DH (Classic DH) 改进DH (Modified DH)
坐标系附着位置 连杆i的坐标系固连在连杆i的首端(前一个关节) 连杆i的坐标系固连在连杆i的末端(后一个关节)
变换顺序 绕x轴旋转 → 沿x轴平移 → 绕z轴旋转 → 沿z轴平移 沿x轴平移 → 绕x轴旋转 → 沿z轴平移 → 绕z轴旋转
参数定义 αi-1, ai-1, di, θi αi-1, ai-1, di, θi(符号一样,但物理含义略有偏移)
适用场景 串联机器人,树形结构 串联、并联、树形结构,尤其是闭环链
我的经验 早期教材多用,但容易在相邻关节轴线平行时出现奇异 现代机器人库(如ROS、Pinocchio)默认用改进DH,更鲁棒

你可能会问:“为啥要搞两套?” 说白了,标准DH是先绕x转再沿x移,改进DH是先沿x移再绕x转。顺序不同,导致坐标系附着位置不同。我在项目中遇到过,用标准DH建模一个六轴协作机器人,在关节5和关节6轴线平行时,参数突然跳变,调试了半天才发现是DH模型选错了。

⚠ 避坑指南: 我曾经因为混用标准DH和改进DH,导致正解算出来末端位置差了10厘米。记住:一旦选定一种,全链路必须统一。我建议新手直接上改进DH,因为ROS和大多数开源库都支持它,社区资源多。

3.2 连杆坐标系建立规则

不管用哪种DH,建立坐标系都有固定套路。我总结了一个“三步法”,你照着做基本不会错。

  1. 找关节轴: 画出所有关节的旋转轴(或移动轴)线。这些线是z轴的基础。
  2. 定z轴: 关节i的轴线就是坐标系{i}的zi轴。方向任意,但建议统一指向末端。
  3. 定x轴: 这是最容易出错的一步。xi轴是zi-1和zi的公垂线,方向从zi-1指向zi。如果两轴相交,xi垂直于两轴所在平面。

嗯,这里要注意:如果zi-1和zi平行,公垂线不唯一。这时候我习惯选一个让后续参数尽量简单的方向,比如让ai-1 = 0。

💡 核心原则: 坐标系{i}的原点位于zi和zi-1的公垂线与zi的交点。如果两轴相交,原点就在交点。

3.3 参数表提取方法

坐标系建好了,接下来就是填参数表。四个参数的定义如下:

  • αi-1(连杆扭转角): 从zi-1绕xi-1旋转到zi的角度。右手定则。
  • ai-1(连杆长度): 沿xi-1方向,从zi-1到zi的距离。永远是正值。
  • di(连杆偏距): 沿zi方向,从xi-1到xi的距离。可正可负。
  • θi(关节角): 从xi-1绕zi旋转到xi的角度。对于旋转关节,这是变量。

我一般会画一个表格,把每个关节的四个参数填进去。比如一个典型的六轴工业机器人,参数表长这样:

关节 i αi-1 (rad) ai-1 (mm) di (mm) θi (rad)
1 0 0 0.3 θ1
2 -π/2 0.2 0 θ2
3 0 0.8 0 θ3
4 -π/2 0.1 0.8 θ4
5 π/2 0 0 θ5
6 -π/2 0 0.1 θ6

你想想看,有了这张表,机械臂的几何模型就完全确定了。剩下的就是矩阵乘法。

3.4 代码实现DH变换矩阵

理论说完了,上代码。我习惯用C语言在STM32上实现,因为效率高、可控性强。下面是一个标准的改进DH变换矩阵生成函数。

#include <math.h>

// 定义4x4齐次变换矩阵
typedef struct {
    float data[4][4];
} Matrix4x4;

// 改进DH:根据四个参数生成变换矩阵 i-1T_i
Matrix4x4 dh_transform_mod(float alpha, float a, float d, float theta) {
    Matrix4x4 T;
    float ct = cosf(theta);
    float st = sinf(theta);
    float ca = cosf(alpha);
    float sa = sinf(alpha);

    // 行优先填充
    T.data[0][0] = ct;      T.data[0][1] = -st;     T.data[0][2] = 0;      T.data[0][3] = a;
    T.data[1][0] = st*ca;   T.data[1][1] = ct*ca;   T.data[1][2] = -sa;    T.data[1][3] = -sa*d;
    T.data[2][0] = st*sa;   T.data[2][1] = ct*sa;   T.data[2][2] = ca;     T.data[2][3] = ca*d;
    T.data[3][0] = 0;       T.data[3][1] = 0;       T.data[3][2] = 0;      T.data[3][3] = 1;

    return T;
}

// 标准DH:变换矩阵略有不同
Matrix4x4 dh_transform_classic(float alpha, float a, float d, float theta) {
    Matrix4x4 T;
    float ct = cosf(theta);
    float st = sinf(theta);
    float ca = cosf(alpha);
    float sa = sinf(alpha);

    T.data[0][0] = ct;      T.data[0][1] = -st*ca;  T.data[0][2] = st*sa;   T.data[0][3] = a*ct;
    T.data[1][0] = st;      T.data[1][1] = ct*ca;   T.data[1][2] = -ct*sa;  T.data[1][3] = a*st;
    T.data[2][0] = 0;       T.data[2][1] = sa;      T.data[2][2] = ca;      T.data[2][3] = d;
    T.data[3][0] = 0;       T.data[3][1] = 0;       T.data[3][2] = 0;       T.data[3][3] = 1;

    return T;
}
🔧 实战技巧: 在STM32上跑这个函数,建议把cosf/sinf换成查表法或CORDIC算法,能省下不少CPU周期。我曾在F407上做过测试,纯浮点三角函数占用了正解计算70%的时间。

有了单个变换矩阵,正解就是连乘:0T6 = 0T1 * 1T2 * ... * 5T6。代码实现就是循环调用矩阵乘法。

3.5 知识体系总览

最后,我用一张SVG图把本章的核心逻辑串起来。你一看就明白DH参数建模的全流程。

DH参数建模知识体系 标准DH (Classic) 改进DH (Modified) 连杆坐标系建立规则 找关节轴 → 定z轴 → 定x轴 → 定原点 参数表提取:α, a, d, θ 代码实现:DH变换矩阵 → 正解连乘 💡 核心:参数表是机械臂的“数学基因”,变换矩阵是“表达方式”

嗯,这张图把本章的脉络理清了。从选择DH类型开始,到建立坐标系、提取参数表,最后用代码生成变换矩阵。每一步都有坑,但只要你按这个流程走,就不会乱。

📌 本章核心要点:
  • 标准DH和改进DH的变换顺序不同,导致坐标系附着位置不同。选一种,用到底。
  • 坐标系建立遵循“三步法”:找轴、定z、定x。平行轴时注意公垂线选择。
  • 参数表是机械臂的“数学基因”,四个参数(α, a, d, θ)唯一确定相邻连杆关系。
  • 代码实现时,注意三角函数精度和计算效率。STM32上建议优化数学库。