4. 坐标系与变换:连杆坐标系定义、DH参数简介、从URDF到TF树的映射关系

好,咱们进入正题。这一章聊的是机械臂的「骨架」和「关节」怎么用数学描述出来。说白了,就是给机械臂的每一根骨头(连杆)都贴上坐标标签,然后告诉计算机它们之间怎么动。

我刚开始接触机器人时,觉得坐标系这东西太抽象了。直到有一次调试一个六轴臂,发现末端执行器总是偏了5毫米,查了两天才发现是某个连杆的坐标系定义反了。嗯,从那以后我再也不敢小看这一步了。

4.1 连杆坐标系定义——给每根骨头贴标签

机械臂由一系列刚体(连杆)通过关节连接而成。每个连杆都需要一个自己的坐标系。你想想看,如果没有坐标系,你怎么描述「肘关节弯曲了30度」?

定义连杆坐标系时,我习惯遵循一个原则:坐标系的原点放在关节轴上。具体来说:

  • 基坐标系:固定在机械臂底座上,通常Z轴向上,X轴指向机器人前方。这是所有坐标的「老大哥」。
  • 连杆坐标系 {i}:固定在连杆 i 上,随连杆一起运动。它的Z轴沿着关节 i+1 的轴线方向。
  • 工具坐标系:固定在末端执行器上,比如夹爪、焊枪。这是最终干活的那个点。

核心要点:每个连杆坐标系只描述它自己的位置和姿态。相邻坐标系之间的变换关系,才是我们真正要算的东西。

我在项目中遇到过一个问题:一个协作臂的末端夹爪总是抓不准零件。后来发现是工具坐标系定义时,把夹爪的中心点偏了2毫米。你想想看,2毫米在工业现场可能就是报废一个工件。所以,坐标系定义一定要精确到毫米级。

4.2 DH参数简介——四个参数搞定一切

DH参数(Denavit-Hartenberg参数)是机器人学里最经典的建模方法。说白了,就是用四个参数来描述两个相邻连杆坐标系之间的变换关系。

为什么是四个?因为三维空间里两个坐标系之间的变换本来需要6个参数(3个平移+3个旋转),但DH参数利用了关节轴的特殊性,把问题简化了。

四个参数分别是:

参数 符号 含义 我的理解
连杆长度 ai 沿Xi轴,从Zi到Zi+1的距离 两根关节轴之间的「最短距离」
连杆扭角 αi 绕Xi轴,从Zi到Zi+1的转角 两根关节轴之间的「夹角」
关节距离 di 沿Zi轴,从Xi-1到Xi的距离 沿关节轴方向的「偏移量」
关节转角 θi 绕Zi轴,从Xi-1到Xi的转角 关节的「旋转角度」

小技巧:我记这四个参数有个口诀——「长扭距转」。长度、扭角、距离、转角。每次写DH表时默念一遍,不容易漏。

举个例子,一个简单的两连杆机械臂,DH参数表可能是这样的:

连杆 | a (m) | α (rad) | d (m) | θ (rad)
------|-------|---------|-------|--------
1     | 0.5   | 0       | 0     | θ1
2     | 0.4   | 0       | 0     | θ2

你看,只有θ是变量,其他都是固定值。这就是DH参数的精髓——把关节运动抽象成一个旋转变量。

我曾经踩过一个坑:DH参数有两种约定——标准DH和改进DH。标准DH把坐标系建在连杆的「前一个」关节上,改进DH建在「后一个」关节上。如果你混着用,算出来的变换矩阵会完全不对。我建议你选一种就坚持用到底,别换来换去。

4.3 从URDF到TF树的映射关系

URDF(Unified Robot Description Format)是ROS里描述机器人的XML格式。TF(Transform)是ROS里管理坐标系变换的框架。两者之间的关系,说白了就是:URDF定义了「有什么」,TF定义了「怎么动」。

URDF里每个连杆对应一个坐标系,每个关节对应一个变换。当你加载一个URDF文件时,ROS会自动生成一棵TF树。这棵树的结构和URDF里的关节树完全一致。

映射规则:

  • URDF中的每个 <link> 对应TF树中的一个坐标系
  • URDF中的每个 <joint> 对应TF树中两个坐标系之间的变换
  • 关节的 origin 标签定义了变换的平移和旋转
  • 关节的 axis 标签定义了旋转轴的方向

举个例子,一个URDF片段:

<joint name="shoulder_pan_joint" type="revolute">
  <parent link="base_link"/>
  <child link="shoulder_link"/>
  <origin xyz="0 0 0.1" rpy="0 0 0"/>
  <axis xyz="0 0 1"/>
</joint>

这个关节告诉ROS:从 base_link 到 shoulder_link,先平移 (0, 0, 0.1),然后绕Z轴旋转。在TF树里,这就是一个 TransformStamped 消息,包含 parent_frame_id="base_link",child_frame_id="shoulder_link",以及对应的平移和旋转。

注意:URDF里的 rpy 顺序是 Z-Y-X(绕固定轴),而TF里用的是四元数。ROS会自动帮你转换,但如果你手动写代码,一定要搞清楚顺序。我曾经在这里吃过亏,写了一个自定义的TF发布器,结果机械臂在空中画了个8字形——完全不是我要的轨迹。

TF树的优势在于:你不需要手动计算坐标变换。只要发布正确的TF消息,ROS的 tf2 库会自动帮你维护所有坐标系之间的关系。比如你想知道「末端夹爪相对于基座的位置」,直接调用 lookupTransform 就行。

我个人习惯在调试时用 tf2_echo 命令实时查看TF树。比如:

ros2 run tf2_ros tf2_echo base_link tool0

这条命令会实时输出 tool0 相对于 base_link 的位置和姿态。如果发现数值跳变或者不连续,那大概率是URDF里的关节定义有问题。

4.4 知识体系总览

下面这张图是我自己画的,把这一章的核心逻辑串起来了。你一看就明白:

坐标系与变换知识体系 连杆坐标系定义 DH参数建模 URDF → TF树 基坐标系 / 连杆 / 工具 Z轴沿关节轴线 a, α, d, θ 四个参数 标准DH vs 改进DH link → 坐标系 joint → 变换关系 核心:用数学描述机械臂的「骨架」和「关节」 坐标系定义 → DH参数 → URDF描述 → TF树实时变换

你看,整个流程是串起来的:先定义每个连杆的坐标系,然后用DH参数描述相邻坐标系的关系,接着把这些信息写进URDF文件,最后ROS自动生成TF树供你实时查询。每一步都依赖上一步的正确性。

嗯,这一章的内容就到这里。坐标系和变换是机器人学的基石,你花时间把它搞透,后面学运动学、动力学都会轻松很多。

可可精品资料库