Skip to main content

机器人的URDF建模及其Rviz可视化

零、这一节你会学到什么

ROS 是一个机器人操作系统,但要让 ROS 认识你手里的机器人,首先得用一套"通用语言"把机器人描述清楚。这套语言就是 URDF(统一机器人描述格式)。

在这一节里,你将:

  1. 理解机器人的四大组成:从硬件结构到控制系统,学会如何把一个真实机器人拆解为可建模的模块
  2. 掌握 URDF 的核心语法:认识 <link><joint> 两大标签,理解六种关节类型的区别与适用场景
  3. 亲手写一个移动机器人模型:从底盘到轮子,一步步搭建一个差速驱动机器人的 URDF 描述文件
  4. 在 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 已放在当前目录 ~/ 下,然后依次运行下面的命令。这些命令做了四件事:

  1. 下载: 从我们的文件服务器,下载 learning_urdf.zip~/ 目录下
  2. 解压:把压缩包解压到 learning_urdf 文件夹
  3. 部署:将功能包复制到 ROS2 工作空间的 src 目录
  4. 编译:用 colcon build 编译整个工作空间
  5. 启动:用 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 里拖拽视角,感受一下三维空间的机器人是什么样的。

Rviz显示URDF小车子2026-06-02 14-49-12.png

有了这个直观印象之后,我们再回到理论,看看背后的核心思想。

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_linkleft_wheel_link
  • Joint:xxx_joint(如 left_wheel_joint

每个 <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>几何形状:boxcylinderspheremesh(导入 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 — Roll, Pitch, Yaw(滚转、俯仰、偏航)

rpy 是三个欧拉角的缩写,描述物体在三维空间中的旋转姿态

字母全称中文绕哪个轴旋转类比
RRoll滚转X 轴飞机侧身翻滚
PPitch俯仰Y 轴飞机抬头/低头
YYaw偏航Z 轴飞机左转/右转
Yaw (Z)

| Pitch (Y)
| ↗
| /
| /
|/________→ Roll (X)

单位是弧度(rad),不是度(°)。常用换算:

角度弧度值
90°1.57071.5707(≈ π/2)
180°3.141593.14159(≈ π)
360°6.283196.28319(≈ 2π)
00

所以 rpy="1.5707 0 0" 的意思是:绕 X 轴旋转 90°(把竖直的圆柱"放倒"),绕 Y 轴和 Z 轴不转。

R、P、Y 的顺序很重要

欧拉角有旋转顺序之分。URDF 中 rpy="R P Y" 采用的是固定轴旋转(extrinsic / fixed-axis),顺序为:先绕 X 轴转 R,再绕 Y 轴转 P,最后绕 Z 轴转 Y。

简单记:RPY = X-Y-Z 顺序

RGBA 颜色格式

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 个 Link4 个 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 只会创建最小骨架

ros2 pkg create 创建的是标准 Python 包的最小骨架,只包含 setup.pypackage.xmlresource/__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 模型文件逐段解析

让我们逐段拆解这个文件,理解每一个标签的含义:

底盘是整个机器人的"根",所有其他零件都通过 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?

在真实机器人上,关节角度由编码器实时反馈。但在仿真和可视化中,我们还没有真正的编码器数据——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!

如果不在 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

预期效果

  1. Rviz2 窗口打开,显示一个三维坐标系
  2. 左侧 Displays 面板中出现 RobotModel
  3. 中央视窗显示一个黄色圆柱底盘 + 两侧白色轮子 + 前后黑色小球
  4. 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 的"三问法"

当你面对一个陌生的 URDF 文件时,用三问法快速建立认知:

  1. 问结构:有多少个 <link>?(grep -c "<link " file.urdf
  2. 问关节:有多少个 <joint>?类型分别是什么?(grep "type=" file.urdf
  3. 问拓扑:用 urdf_to_graphvizcheck_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 仿真 中一一展开。在那之前,建议你:

巩固练习
  1. 改参数:修改 mbot_base.urdf 中的轮子半径、底盘尺寸,重新启动 Rviz2 观察效果变化
  2. 加零件:给机器人加一个立方体的"车顶"(用 <box>),用 fixed 关节固定在底盘上方
  3. 换颜色:把底盘改成蓝色,轮子改成红色——练习 RGBA 颜色的使用
  4. 画模型图:找一个你感兴趣的机器人模型(TurtleBot3 的 URDF 在网上有开源),用 urdf_to_graphviz 画出它的结构,看看比自己写的复杂多少

参考链接