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文件,最后ROS自动生成TF树供你实时查询。每一步都依赖上一步的正确性。
嗯,这一章的内容就到这里。坐标系和变换是机器人学的基石,你花时间把它搞透,后面学运动学、动力学都会轻松很多。
可可精品资料库