机器人的URDF建模及其Rviz可视化
零、这一节你会学到什么
ROS 是一个机器人操作系统,但要让 ROS 认识你手里的机器人,首先得用一套"通用语言"把机器人描述清楚。这套语言就是 URDF(统一机器人描述格式)。
在这一节里,你将:
- 理解机器人的四大组成:从硬件结构到控制系统,学会如何把一个真实机器人拆解为可建模的模块
- 掌握 URDF 的核心语法:认识
<link>和<joint>两大标签,理解六种关节类型的区别与适用场景 - 亲手写一个移动机器人模型:从底盘到轮子,一步步搭建一个差速驱动机器人的 URDF 描述文件
- 在 Rviz2 中可视化你的机器人:编写 Launch 启动文件,在三维空间中旋转、缩放、观察你亲手"造"出来的机器人
前置知识:你已完成 ROS2 基础(01~03 课),理解工作空间、功能包、节点的基本概念。
🔍 反编译挑战:找一个你熟悉的机器人模型(TurtleBot3、机械臂、无人机……随你选),打开它的 URDF 文件,数一数有多少个 <link> 和 <joint>。然后画一张树状图,把它们的父子关系标出来。如果你能读懂一个复杂模型的 URDF 文件,恭喜你——你已经出师了!
一、机器人的组成:建模之前,先认识你的机器人
1.1 四大组成部分
在动手写 URDF 之前,你得先知道你要描述的"机器人"到底是什么。一台典型的机器人,无论它是扫地机、机械臂还是无人机,都可以拆解为四个系统:
| 组成部分 | 说明 | 在 URDF 中的对应 | 实例 |
|---|---|---|---|
| 硬件结构 | 底盘、外壳、支架、电机等实体部件 | <link> + <visual> | 圆柱底盘、轮子外形 |
| 驱动系统 | 电机驱动器、电源管理、传动机构 | <joint> + <axis> | 旋转关节、运动轴 |
| 传感系统 | 编码器、IMU、摄像头、激光雷达 | <link> + <gazebo> 插件 | 相机连杆、雷达支架 |
| 控制系统 | 计算平台(树莓派/工控机)和软件 | ROS2 节点 / Launch 文件 | 运动控制节点 |
把机器人想象成一个人:
- 硬件结构就是骨骼和肌肉——你看得见、摸得着的部分
- 驱动系统就是肌肉里的神经——指挥肌肉收缩和舒张
- 传感系统就是眼睛、耳朵、皮肤——感知外界发生了什么
- 控制系统就是大脑——收到信息后做决策:"前面有墙,该转弯了"
URDF 建模的过程,就是把"这个人"用 XML 语言描述给 ROS 听。先描述每个"骨头"(<link>),再描述骨头之间的"关节"(<joint>),最后告诉 ROS:这个人长这样,关节只能这么动。
为了让大家首先有一个直观的体验,我先给出一个"cheat sheet"。请确保 learning_urdf.zip 已放在当前目录 ~/ 下,然后依次运行下面的命令。这些命令做了四件事:
- 下载: 从我们的文件服务器,下载
learning_urdf.zip到~/目录下 - 解压:把压缩包解压到
learning_urdf文件夹 - 部署:将功能包复制到 ROS2 工作空间的
src目录 - 编译:用
colcon build编译整个工作空间 - 启动:用 launch 文件一键启动 Rviz 可视化
unzip ./learning_urdf.zip -d learning_urdf
mkdir -p ~/ros2_ws/src
cp ./learning_urdf ~/ros2_ws/src/ -r
cd ~/ros2_ws
colcon build
source install/setup.zsh
ros2 launch learning_urdf display.launch.py
如果一切顺利,你会看到 Rviz 窗口弹出来,里面显示着一个蓝色的双轮差速小车模型(如下图所示)。在左侧的 Displays 面板里,你可以看到 RobotModel 加载了一个 URDF 文件——就是我们现在正要学习的东西。试着在 Rviz 里拖拽视角,感受一下三维空间的机器人是什么样的。

有了这个直观印象之后,我们再回到理论,看看背后的核心思想。
1.2 建模的核心思想:连杆 + 关节
URDF 建模遵循一个极简的逻辑:
机器人 = 若干刚体(Link)+ 它们之间的运动约束(Joint)
- Link(连杆):机器人的"零件",是独立的刚体。底盘是一个 Link,左轮是一个 Link,右轮是另一个 Link
- Joint(关节):两个 Link 之间的"连接器",定义它们如何相对运动。比如"左轮可以绕 y 轴无限旋转"
这个思想非常接近现实世界的机械结构。你手臂的大臂是一个 Link,小臂是另一个 Link,手肘就是连接它们的 Joint。
二、URDF 统一机器人描述格式
2.1 什么是 URDF
URDF(Unified Robot Description Format,统一机器人描述格式)是 ROS 生态中专用的机器人模型描述语言。它使用 XML 格式,通过一系列标签和属性来描述机器人的外观、结构和运动关系。
URDF 是 ROS 世界的机器人的"DNA"。无论是 Rviz2 里的 3D 展示、Gazebo 里的物理仿真,还是 MoveIt2 的运动规划和 Nav2 的自主导航——它们都需要先通过 URDF 来认识你的机器人长什么样、关节怎么动。
2.2 URDF 文件的基本结构
一个完整的 URDF 文件,最外层由 <robot> 标签包裹,内部包含若干 <link> 和 <joint>:
<?xml version="1.0" ?>
<robot name="my_robot">
<!-- 描述每一个刚体 -->
<link name="base_link">
...
</link>
<!-- 描述每一对刚体之间的连接 -->
<joint name="wheel_joint" type="continuous">
...
</joint>
<link name="wheel_link">
...
</link>
<!-- 更多 link 和 joint... -->
</robot>
核心只有三样东西:
| 层级 | 标签 | 作用 |
|---|---|---|
| 根 | <robot name="..."> | 机器人的名字,整个模型文件的"身份证" |
| 刚体 | <link name="..."> | 描述一个独立的刚性部件 |
| 关节 | <joint name="..." type="..."> | 描述两个 link 之间的连接和运动关系 |
<link> 和 <joint> 的 name 属性在整个模型文件中必须唯一。ROS 的 TF(坐标变换)系统会使用这些名字来建立坐标系树,重名会导致坐标变换混乱。
建议命名风格:
- Link:
xxx_link(如base_link、left_wheel_link) - Joint:
xxx_joint(如left_wheel_joint)
2.3 Link 的描述:外观与碰撞
每个 <link> 标签描述机器人的一个刚体部分,包含外观属性和物理属性:
<link name="base_link">
<!-- ① 外观:在 Rviz2 中看起来什么样 -->
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<cylinder length="0.16" radius="0.20"/>
</geometry>
<material name="yellow">
<color rgba="1 0.4 0 1"/>
</material>
</visual>
<!-- ② 碰撞:用于碰撞检测(在 Gazebo 中计算碰撞时使用) -->
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<cylinder length="0.16" radius="0.20"/>
</geometry>
</collision>
<!-- ③ 惯性:质量和惯性张量(在 Gazebo 中进行物理仿真时使用) -->
<inertial>
<mass value="1.0"/>
<origin xyz="0 0 0" rpy="0 0 0"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.02"/>
</inertial>
</link>
visual — 外观
<visual> 决定机器人在 Rviz2 中"长什么样"。核心子标签:
| 子标签 | 说明 | 示例 |
|---|---|---|
<geometry> | 几何形状:box、cylinder、sphere 或 mesh(导入 3D 模型) | <cylinder length="0.16" radius="0.20"/> |
<origin> | 坐标系偏移:xyz 平移(米)+ rpy 旋转(弧度) | xyz="0 0 0.1" rpy="0 0 0" |
<material> | 颜色和材质 | <color rgba="1 0.4 0 1"/>(黄) |
rpy 是三个欧拉角的缩写,描述物体在三维空间中的旋转姿态:
| 字母 | 全称 | 中文 | 绕哪个轴旋转 | 类比 |
|---|---|---|---|---|
| R | Roll | 滚转 | X 轴 | 飞机侧身翻滚 |
| P | Pitch | 俯仰 | Y 轴 | 飞机抬头/低头 |
| Y | Yaw | 偏航 | Z 轴 | 飞机左转/右转 |
Yaw (Z)
↑
| Pitch (Y)
| ↗
| /
| /
|/________→ Roll (X)
单位是弧度(rad),不是度(°)。常用换算:
| 角度 | 弧度值 |
|---|---|
| 90° | (≈ π/2) |
| 180° | (≈ π) |
| 360° | (≈ 2π) |
| 0° |
所以 rpy="1.5707 0 0" 的意思是:绕 X 轴旋转 90°(把竖直的圆柱"放倒"),绕 Y 轴和 Z 轴不转。
欧拉角有旋转顺序之分。URDF 中 rpy="R P Y" 采用的是固定轴旋转(extrinsic / fixed-axis),顺序为:先绕 X 轴转 R,再绕 Y 轴转 P,最后绕 Z 轴转 Y。
简单记:RPY = X-Y-Z 顺序。
rgba="R G B A" 四个值都在 0~1 之间:
- R:红色分量
- G:绿色分量
- B:蓝色分量
- A:透明度(0 = 完全透明,1 = 完全不透明)
常用颜色速查:
- 🟡 黄色:
1 0.4 0 1 - ⚪ 白色:
1 1 1 1 - ⚫ 黑色:
0 0 0 1 - 🔵 蓝色:
0 0 1 1
collision — 碰撞
<collision> 决定机器人在物理仿真中如何与外界"碰撞"。结构和 <visual> 类似,但服务于不同的目的:
<visual>追求视觉真实感——可以用复杂的.stl网格模型<collision>追求计算效率——常用简化的几何体(圆柱、方盒)来近似
为什么分开?因为物理引擎每毫秒要计算成百上千次碰撞检测。用一个简化的圆柱代替复杂的 3D 网格,计算量可以降低一个数量级。
inertial — 惯性
<inertial> 描述刚体的质量分布和惯性特性,是 Gazebo 进行动力学仿真的数学基础。在 Rviz2 中单纯可视化时不需要这个标签,但进入 Gazebo 仿真后就必不可少。
这部分在 第 4.9 节:机器人的 Gazebo 仿真 中会详细展开。
2.4 Joint 的描述:六种关节类型
<joint> 连接两个 Link,并定义它们之间的运动关系。每个关节必须指定:
- 谁是 parent(父连杆),谁是 child(子连杆)
- 运动类型(六种)
- 运动轴(绕/沿哪个方向运动)
- 安装位置(两个连杆的坐标系之间如何偏移)
<joint name="left_wheel_joint" type="continuous">
<origin xyz="0 0.19 -0.05" rpy="0 0 0"/>
<parent link="base_link"/>
<child link="left_wheel_link"/>
<axis xyz="0 1 0"/>
<limit effort="100" velocity="10"/>
</joint>
ROS 定义了六种关节类型,覆盖了机器人中几乎所有的运动形式:
| 类型 | 运动方式 | 有无角度限制 | 典型应用 | 使用频率 |
|---|---|---|---|---|
| continuous | 绕轴无限旋转 | ❌ 无限制 | 移动机器人轮子、传送带 | ⭐⭐⭐ |
| revolute | 绕轴有限角度旋转 | ✅ 有上下限 | 机械臂关节、舵机 | ⭐⭐⭐ |
| prismatic | 沿轴直线滑动 | ✅ 有行程极限 | 直线推杆、电梯 | ⭐⭐ |
| fixed | 完全固定,不运动 | — | 传感器支架、外壳 | ⭐⭐⭐ |
| floating | 空间中六自由度自由运动 | ❌ | 无人机、漂浮物 | ⭐ |
| planar | 平面内三自由度运动 | ❌ | 平面移动平台 | ⭐ |
URDF 中的父子关系(<parent> → <child>)构建了一棵坐标系树:
- 父连杆的运动会带动子连杆一起运动
- 关节的运动只改变子连杆相对于父连杆的位置
底盘(base_link)通常是整棵树的根,所有其他零件都是它的"后代"。这棵树在 ROS 中通过 /tf(坐标变换)话题广播出去,是所有定位和导航算法的基础。
关节属性详解
| 属性标签 | 作用 | 示例 |
|---|---|---|
<origin> | 子连杆坐标系在父连杆坐标系中的位置和姿态 | xyz="0 0.19 -0.05" rpy="0 0 0" |
<parent> | 父连杆的名称 | link="base_link" |
<child> | 子连杆的名称 | link="left_wheel_link" |
<axis> | 运动轴方向(单位向量) | xyz="0 1 0"(绕 y 轴) |
<limit> | 运动限制(仅 revolute / prismatic) | lower="-1.57" upper="1.57" effort="10" velocity="3.14" |
ROS2 中 URDF 的标准单位:
- 长度:米(m)
- 角度:弧度(rad)——不是度(°)!
- 质量:千克(kg)
- 力/力矩:牛(N)/ 牛·米(N·m)
- 线速度:米/秒(m/s)
- 角速度:弧度/秒(rad/s)
所以 upper="3.14" 表示约 180°。写 upper="180" 意味着 180 弧度(约 10313°)——这几乎不可能达到。
三、创建你的第一个机器人模型
3.1 我们要建的机器人:mbot
下面我们以一款简单的差速驱动移动机器人为例,从零开始写它的 URDF 模型。
这个机器人叫 mbot,结构极其简单:
- 🟡 一个黄色圆柱底盘(半径 20cm,高 16cm)
- ⚪ 两个白色圆柱驱动轮(左右各一个,半径 6cm)
- ⚫ 两个黑色小球体万向轮(前后各一个,半径 1.5cm,起支撑作用)
总共 5 个 Link 和 4 个 Joint。
3.2 功能包结构
首先创建一个 ROS2 功能包来存放模型文件:
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
ros2 pkg create learning_urdf --build-type ament_python
ros2 pkg create 创建的是标准 Python 包的最小骨架,只包含 setup.py、package.xml、resource/、__init__.py 等文件。urdf/、meshes/、launch/、rviz/ 这些目录是 ROS 社区的约定俗成(convention),需要你手动创建。
在终端 ls 一下当前目录,你会看到只有:
learning_urdf package.xml resource setup.cfg setup.py test
别慌——下面的 mkdir 命令就是补齐这些目录的。
接下来,手动创建约定的子目录:
cd ~/ros2_ws/src/learning_urdf
mkdir -p urdf meshes launch rviz
创建后,功能包的完整文件结构如下:
learning_urdf/
├── urdf/ # 存放 URDF 模型文件
│ └── mbot_base.urdf # (我们接下来要写的文件)
├── meshes/ # 存放 3D 网格模型(.stl, .dae 等)
├── launch/ # 存放 Launch 启动文件
│ └── display.launch.py # (我们接下来要写的文件)
├── rviz/ # 存放 Rviz2 配置文件
│ └── display.rviz # (我们接下来要写的文件)
├── setup.py # ← 由 ros2 pkg create 生成
├── package.xml # ← 由 ros2 pkg create 生成
└── resource/ # ← 由 ros2 pkg create 生成
urdf/:存放.urdf或.xacro文件(xacro 是 URDF 的宏扩展版本,后续课程会讲)meshes/:存放 3D 模型文件(.stl、.dae、.obj),在<geometry>中用<mesh>标签引用launch/:存放.launch.py启动文件,一键启动多个节点rviz/:存放.rviz配置文件,保存 Rviz2 的窗口布局、显示项设置
3.3 编写 URDF 模型文件
在 urdf/mbot_base.urdf 中写入以下内容:
<?xml version="1.0" ?>
<robot name="mbot">
<!-- ========== 底盘 base_link ========== -->
<link name="base_link">
<visual>
<origin xyz=" 0 0 0" rpy="0 0 0" />
<geometry>
<cylinder length="0.16" radius="0.20"/>
</geometry>
<material name="yellow">
<color rgba="1 0.4 0 1"/>
</material>
</visual>
</link>
<!-- ========== 左驱动轮关节 ========== -->
<joint name="left_wheel_joint" type="continuous">
<origin xyz="0 0.19 -0.05" rpy="0 0 0"/>
<parent link="base_link"/>
<child link="left_wheel_link"/>
<axis xyz="0 1 0"/>
</joint>
<!-- ========== 左驱动轮 ========== -->
<link name="left_wheel_link">
<visual>
<origin xyz="0 0 0" rpy="1.5707 0 0" />
<geometry>
<cylinder radius="0.06" length="0.025"/>
</geometry>
<material name="white">
<color rgba="1 1 1 0.9"/>
</material>
</visual>
</link>
<!-- ========== 右驱动轮关节 ========== -->
<joint name="right_wheel_joint" type="continuous">
<origin xyz="0 -0.19 -0.05" rpy="0 0 0"/>
<parent link="base_link"/>
<child link="right_wheel_link"/>
<axis xyz="0 1 0"/>
</joint>
<!-- ========== 右驱动轮 ========== -->
<link name="right_wheel_link">
<visual>
<origin xyz="0 0 0" rpy="1.5707 0 0" />
<geometry>
<cylinder radius="0.06" length="0.025"/>
</geometry>
<material name="white">
<color rgba="1 1 1 0.9"/>
</material>
</visual>
</link>
<!-- ========== 前万向轮关节 ========== -->
<joint name="front_caster_joint" type="continuous">
<origin xyz="0.18 0 -0.095" rpy="0 0 0"/>
<parent link="base_link"/>
<child link="front_caster_link"/>
<axis xyz="0 1 0"/>
</joint>
<!-- ========== 前万向轮 ========== -->
<link name="front_caster_link">
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<sphere radius="0.015" />
</geometry>
<material name="black">
<color rgba="0 0 0 0.95"/>
</material>
</visual>
</link>
<!-- ========== 后万向轮关节 ========== -->
<joint name="back_caster_joint" type="continuous">
<origin xyz="-0.18 0 -0.095" rpy="0 0 0"/>
<parent link="base_link"/>
<child link="back_caster_link"/>
<axis xyz="0 1 0"/>
</joint>
<!-- ========== 后万向轮 ========== -->
<link name="back_caster_link">
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<sphere radius="0.015" />
</geometry>
<material name="black">
<color rgba="0 0 0 0.95"/>
</material>
</visual>
</link>
</robot>
3.4 模型文件逐段解析
让我们逐段拆解这个文件,理解每一个标签的含义:
① 底盘 base_link
底盘是整个机器人的"根",所有其他零件都通过 Joint 连接在它上面。
查看 3.3 节完整模型文件中底盘的定义(第 7-16 行):
- 几何形状:圆柱体,高 16cm(
length="0.16"),半径 20cm(radius="0.20") - 颜色:黄色(RGBA
1 0.4 0 1) - 坐标系:原点在底盘几何中心,无需偏移(
xyz="0 0 0")
② 驱动轮
以左驱动轮为例(右轮镜像对称),查看模型文件第 18-41 行:
- Joint 类型:
continuous—— 轮子可以无限旋转 - 安装位置:
xyz="0 0.19 -0.05"y=0.19:左轮在底盘中心左侧 19cm(右轮y=-0.19对称)z=-0.05:轮子在底盘中心下方 5cm
- 运动轴:
xyz="0 1 0"—— 绕 y 轴旋转 - 轮子姿态:
rpy="1.5707 0 0"—— 绕 x 轴旋转 π/2(90°),因为圆柱默认沿 z 轴,需要"放倒"才能像轮子一样滚动 - 轮子尺寸:半径 6cm,厚度 2.5cm
③ 万向轮
前万向轮是起支撑作用的从动轮,不提供驱动力,查看模型文件第 54-71 行:
- 安装位置:
xyz="0.18 0 -0.095"x=0.18:在底盘中心前方 18cm(后轮x=-0.18对称)z=-0.095:在底盘中心下方 9.5cm,比驱动轮略低
- 几何形状:球体(
sphere radius="0.015"),半径 1.5cm - 颜色:黑色
四、在 Rviz2 中可视化你的机器人
4.1 Rviz2 是什么
Rviz2(ROS Visualization 2)是 ROS2 的三维可视化工具。它可以实时显示机器人的 3D 模型、传感器数据(激光点云、摄像头图像)、路径规划结果等。在这里,我们用 Rviz2 来验证我们写的 URDF 模型是否正确。
4.2 编写 Launch 文件
创建一个 Launch 文件来一键启动 Rviz2 并加载我们的模型。在 launch/display.launch.py 中写入:
#!/usr/bin/env python3
"""
display.launch.py — 启动 Rviz2 并加载 mbot URDF 模型
"""
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
# ① 获取功能包路径
pkg_dir = get_package_share_directory('learning_urdf')
# ② URDF 文件路径
urdf_file = os.path.join(pkg_dir, 'urdf', 'mbot_base.urdf')
# ③ 读取 URDF 文件内容
with open(urdf_file, 'r') as f:
robot_description = f.read()
# ④ Rviz2 配置文件路径
rviz_config = os.path.join(pkg_dir, 'rviz', 'display.rviz')
return LaunchDescription([
# ── 启动 Robot State Publisher ──
# 作用:解析 URDF,发布 /robot_description 话题和 /tf 坐标变换
Node(
package='robot_state_publisher',
executable='robot_state_publisher',
name='robot_state_publisher',
parameters=[{
'robot_description': robot_description,
'publish_frequency': 30.0,
}]
),
# ── 启动 Joint State Publisher GUI ──
# 作用:提供一个滑块界面,手动拖动各个关节的角度
Node(
package='joint_state_publisher_gui',
executable='joint_state_publisher_gui',
name='joint_state_publisher_gui'
),
# ── 启动 Rviz2 ──
Node(
package='rviz2',
executable='rviz2',
name='rviz2',
arguments=['-d', rviz_config]
),
])
4.3 三个关键节点的作用
| 节点 | 作用 | 发布的话题 |
|---|---|---|
| robot_state_publisher | 读取 URDF 模型,计算每个 link 在空间中的位姿,发布坐标变换 | /tf、/robot_description |
| joint_state_publisher_gui | 提供一个带滑块的 GUI,允许你手动旋转/滑动每个关节 | /joint_states |
| rviz2 | 订阅 /tf 和 /robot_description,在三维窗口中渲染机器人模型 | —(订阅者) |
在真实机器人上,关节角度由编码器实时反馈。但在仿真和可视化中,我们还没有真正的编码器数据——Joint State Publisher 就是扮演这个角色,让你能手动"转动"轮子,看到它们在 Rviz2 中的运动。
GUI 中每个滑块对应 URDF 中一个非 fixed 类型的 joint。拖动滑块,对应的 link 就会在 Rviz2 中旋转。
4.4 更新 setup.py
编辑 setup.py,在 data_files 中声明需要安装的数据文件:
import os
from glob import glob
from setuptools import setup
package_name = 'learning_urdf'
setup(
name=package_name,
version='0.0.0',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
# 安装 urdf 文件
(os.path.join('share', package_name, 'urdf'),
glob('urdf/*.urdf')),
# 安装 launch 文件
(os.path.join('share', package_name, 'launch'),
glob('launch/*.launch.py')),
# 安装 rviz 配置
(os.path.join('share', package_name, 'rviz'),
glob('rviz/*.rviz')),
],
...
)
如果不在 data_files 中列出这些文件,colcon build 不会把它们安装到 install/ 目录。结果就是 Launch 文件找不到 URDF,启动失败。这是新手最常见的错误之一。
4.5 创建 Rviz2 配置文件
虽然可以先用空配置启动再手动添加 RobotModel 显示项,但为了方便,我们创建一个预设配置文件。最简单的方式是先不提供 rviz 配置文件,在 Rviz2 启动后手动配置,然后用 File → Save Config 保存。
创建一个最小配置文件 rviz/display.rviz(或者留空,使用 Rviz2 默认配置):
Panels:
- Class: rviz_common/Displays
Name: Displays
- Class: rviz_common/Views
Name: Views
Visualization Manager:
Displays:
- Class: rviz_default_plugins/Grid
Name: Grid
- Class: rviz_default_plugins/RobotModel
Name: RobotModel
Description Topic:
Value: /robot_description
Global Options:
Fixed Frame: base_link
Tools:
- Class: rviz_default_plugins/MoveCamera
4.6 编译并运行
▶ 编译功能包
cd ~/ros2_ws
colcon build --packages-select learning_urdf
预期输出:Summary: 1 package finished
▶ 启动
source ~/ros2_ws/install/setup.bash
ros2 launch learning_urdf display.launch.py
预期效果:
- Rviz2 窗口打开,显示一个三维坐标系
- 左侧 Displays 面板中出现 RobotModel
- 中央视窗显示一个黄色圆柱底盘 + 两侧白色轮子 + 前后黑色小球
- Joint State Publisher GUI 出现,你可以拖动滑块来旋转轮子
▶ 调试黄金三连
# 验证 1:URDF 文件语法是否正确?
# 使用 check_urdf 工具
check_urdf ~/ros2_ws/src/learning_urdf/urdf/mbot_base.urdf
# 预期输出:
# robot name is: mbot
# ---------- Successfully Parsed XML ---------------
# root Link: base_link has 4 child(ren)
# child(1): left_wheel_link
# child(2): right_wheel_link
# child(3): front_caster_link
# child(4): back_caster_link
# 验证 2:TF 树是否正确?
ros2 run tf2_tools view_frames
# 会生成 frames.pdf,打开看坐标系树是否和预期一致
# 验证 3:话题是否正常发布?
ros2 topic echo /tf
# 应该看到 base_link 到各个轮子的坐标变换在持续发布
4.7 使用 urdf_to_graphviz 查看模型结构
URDF 提供了 urdf_to_graphviz 工具,可以把模型结构画成一张图:
cd ~/ros2_ws/src/learning_urdf/urdf
urdf_to_graphviz mbot_base.urdf
运行后会生成 mbot_base.pdf,打开可以看到一张清晰的拓扑图:
当你面对一个陌生的 URDF 文件时,用三问法快速建立认知:
- 问结构:有多少个
<link>?(grep -c "<link " file.urdf) - 问关节:有多少个
<joint>?类型分别是什么?(grep "type=" file.urdf) - 问拓扑:用
urdf_to_graphviz或check_urdf画出父子关系图
三问之后,你对这个模型的"骨架"就有了基本认知。细节可以慢慢看。
五、常见几何体速查
URDF 中 <geometry> 支持以下基本几何形状:
| 形状 | 标签 | 参数 | 示意图 |
|---|---|---|---|
| 长方体 | <box> | size="x y z" | 📦 |
| 圆柱体 | <cylinder> | radius="r" length="l" | 🥫 |
| 球体 | <sphere> | radius="r" | ⚽ |
| 网格模型 | <mesh> | filename="path/to/model.stl" | 🗿 |
<!-- 长方体:长 1m,宽 0.5m,高 0.2m -->
<geometry>
<box size="1.0 0.5 0.2"/>
</geometry>
<!-- 圆柱体:半径 0.3m,高 1.0m(沿 z 轴) -->
<geometry>
<cylinder radius="0.3" length="1.0"/>
</geometry>
<!-- 球体:半径 0.5m -->
<geometry>
<sphere radius="0.5"/>
</geometry>
<!-- 导入外部 3D 模型(.stl / .dae / .obj) -->
<geometry>
<mesh filename="package://learning_urdf/meshes/chassis.stl"/>
</geometry>
<mesh> 文件路径的写法和坐标系注意事项路径格式:使用 package:// 协议引用 ROS 功能包中的文件:
filename="package://功能包名/相对路径/文件.stl"
坐标系问题:3D 模型文件(.stl)在导出时可能使用了不同的坐标系。如果模型在 Rviz2 中朝向不对,用 <origin rpy="..."> 做旋转变换。常见修正:
- 模型"躺倒"了?试试
rpy="1.5707 0 0"(绕 x 轴转 90°) - 模型"颠倒"了?试试
rpy="0 0 3.14159"(绕 z 轴转 180°)
六、总结与展望
这一节你掌握了什么
| 知识点 | 你学会了 |
|---|---|
| 机器人四大组成 | 硬件 / 驱动 / 传感 / 控制——建模前的"拆解思维" |
| URDF 核心标签 | <link> 描述刚体,<joint> 描述运动约束 |
| 六种关节类型 | continuous / revolute / prismatic / fixed / floating / planar |
| 手写 URDF 模型 | 从零编写 mbot 差速驱动机器人的完整描述文件 |
| Launch 文件 | 用 robot_state_publisher + joint_state_publisher_gui + rviz2 启动可视化 |
| Rviz2 调试 | check_urdf 验证语法,ros2 topic echo /tf 检查坐标变换 |
| 模型结构分析 | urdf_to_graphviz 画拓扑图,三问法快速理解陌生模型 |
下一步
你已经学会了如何用 URDF 描述一个机器人的"长相"和"骨架"。但光有静态模型还不够——
- 这个模型如何在 Gazebo 中真正动起来?需要加上 物理属性(
<inertial>、<collision>)和控制插件 - 如何给机器人装上传感器(激光雷达、摄像头),让它"看见"世界?
- 如何用
xacro宏来简化复杂模型的编写?
这些内容将在 第 4.9 节:机器人的 Gazebo 仿真 中一一展开。在那之前,建议你:
- 改参数:修改
mbot_base.urdf中的轮子半径、底盘尺寸,重新启动 Rviz2 观察效果变化 - 加零件:给机器人加一个立方体的"车顶"(用
<box>),用fixed关节固定在底盘上方 - 换颜色:把底盘改成蓝色,轮子改成红色——练习 RGBA 颜色的使用
- 画模型图:找一个你感兴趣的机器人模型(TurtleBot3 的 URDF 在网上有开源),用
urdf_to_graphviz画出它的结构,看看比自己写的复杂多少