3 · 坐标系与变换

做机器人开发,坐标系就是你的“世界观”。
我个人习惯把URDF里的坐标系想象成一个个小坐标架,每个link都抱着一个。你想想看,如果这些架子之间关系乱了,机器人肯定“精神分裂”。

3.1 机器人坐标系定义

URDF里每个都有一个自己的坐标系,原点在哪儿?方向朝哪?全由你定。但有个潜规则:右手系。X向前,Y向左,Z向上——这是ROS里的“标准姿势”。

我记得刚入行时,有次把Z轴搞反了,结果仿真里机械臂直接往地里钻。嗯,从那以后我每次定义坐标系都会默念一遍“右手定则”。

🔹 核心原则
· 每个link一个坐标系,原点通常设在关节中心或几何中心。
· 坐标系方向尽量与机器人“自然姿态”对齐。
· 世界坐标系(map/odom)一般固定,Z轴向上。

3.2 父子关系 —— 关节就是“脐带”

URDF里连接两个link,形成父子树。父link坐标系固定,子link坐标系相对父link做变换。
说白了,关节就是描述“儿子在爸爸身上哪儿、怎么转”。

我在项目里见过有人把父子关系搞反,结果整个机器人像提线木偶一样乱晃。记住:父link是“不动”的参考,子link是“动”的那一方。

  • 固定关节 (fixed):子坐标系相对父坐标系永远不变。比如相机支架。
  • 旋转关节 (revolute):子坐标系绕父坐标系的某个轴旋转。比如肘关节。
  • 移动关节 (prismatic):子坐标系沿父坐标系的某个轴平移。比如升降台。
💡 避坑指南
我曾经在写六轴机械臂时,把joint的<origin>写错了,导致第三轴和第四轴“打架”。后来我养成了一个习惯:每加一个joint,就在Rviz里看一眼TF树,确认父子关系。

3.3 TF树与URDF的关联

TF(Transform)树是ROS里管理所有坐标系关系的“活地图”。URDF定义的是机器人的“静态骨架”,而TF树发布的是实时变换。
你想想看,URDF告诉TF“我的关节长什么样”,TF告诉其他节点“现在每个link在哪儿”。

我经常把TF树比作族谱:base_link是老祖宗,其他link都是子孙。每个joint就是一条“血缘关系”。

坐标系 · 父子关系 · TF树 坐标系定义 右手系 · 原点 · 方向 每个link独立坐标架 父子关系 joint连接 · 树形结构 父固定,子相对变换 TF树 实时变换 · 广播 URDF提供静态骨架 URDF → TF 映射逻辑 • 每个link → TF树中的一个坐标系(frame) • 每个joint → TF树中的变换(transform),由joint origin + 动态值组成 • robot_state_publisher 自动读取URDF并发布TF 三者合一:机器人空间推理的基石

3.4 实战:在URDF里定义坐标系变换

看一个最简单的二连杆结构。父link叫base_link,子link叫arm_link,中间一个旋转关节。

<link name="base_link">
  <visual>
    <geometry><box size="0.2 0.2 0.1"/></geometry>
    <origin xyz="0 0 0" rpy="0 0 0"/>
  </visual>
</link>

<joint name="arm_joint" type="revolute">
  <parent link="base_link"/>
  <child link="arm_link"/>
  <origin xyz="0 0 0.1" rpy="0 0 0"/>   <!-- 子坐标系在父Z正上方0.1米 -->
  <axis xyz="0 0 1"/>                    <!-- 绕Z轴旋转 -->
</joint>

<link name="arm_link">
  <visual>
    <geometry><cylinder length="0.3" radius="0.03"/></geometry>
    <origin xyz="0 0 0.15" rpy="0 0 0"/> <!-- 圆柱中心在link坐标系Z正半轴 -->
  </visual>
</link>

注意<origin>里的xyz和rpy。它们定义了子坐标系相对于父坐标系的偏移和旋转。
我个人习惯把rpy写成“先绕X转,再绕Y,最后绕Z”,也就是ROS里标准的欧拉角顺序。

⚠️ 常见翻车点
很多人把<origin>写在link里和joint里搞混。记住:
· link的origin:定义几何体在link坐标系下的位置。
· joint的origin:定义子link坐标系相对于父link坐标系的变换。
我曾经在调试时把这两个写反,结果机器人看起来像“骨折”了一样。

3.5 用TF树验证你的URDF

启动robot_state_publisher后,用tf_echo或view_frames就能看到实时变换。
我每次写完URDF都会运行:

rosrun tf tf_echo base_link arm_link

如果输出的平移和旋转跟你预期一致,那基本稳了。如果不一致……嗯,回去检查<origin>吧。

🔧 调试小技巧
在Rviz里添加TF显示,把“Frame”选成base_link,然后观察每个link的坐标轴。如果某个link的坐标轴歪了,那一定是joint的rpy写错了。我靠这招至少省了十几个小时的排查时间。

说到底,坐标系和变换就是URDF的“语法”。你掌握了父子关系和TF树的关联,后面写复杂模型就像搭积木一样自然。