从零开始构建可视机器人模型
目标 了解如何构建可在 Rviz 中查看的机器人可视化模型
辅导水平: 中级
时间 20 分钟
备注
本教程假定您知道如何编写格式规范的 XML 代码
在本教程中,我们将制作一个外形酷似 R2D2 的机器人视觉模型。在后面的教程中,您将学习如何 阐明模式, 加入一些物理特性和 使用 xacro 生成更整洁的代码但现在,我们要把重点放在正确的几何图形上。
在继续之前,请确保您有 联合国家出版商 软件包。如果您安装了 urdf_tutorial 二进制文件,情况应该已经如此。如果没有,请更新您的安装以包含该软件包(使用 rosdep
来检查)。
本教程中提到的所有机器人模型(以及源文件)都可以在 urdf_tutorial 包装
一种形状
首先,我们只探讨一个简单的形状。这是一个最简单的 urdf。 [来源:01-myfirst.urdf]
<?xml版本="1.0"?>;
机器人 名称"我的第一次";>;
链接 名称"base_link";>;
视觉效果
<几何>;
气缸 长度="0.6"; 半径="0.2";/>;
</geometry>;
</visual>;
</link>;
</机器人>;
将 XML 翻译成英文,这是一个名为 我的第一
,只包含一个链接(又称部件),其视觉组件只是一个长 0.6 米、半径 0.2 米的圆柱体。对于一个简单的 "hello world"(你好世界)类型的示例来说,这看起来似乎有很多外层标签,但它会变得更加复杂,相信我。
要检查模型,请启动 display.launch.py
锉刀
ros2 launch urdf_tutorial display.launch.py model:=urdf/01-myfirst.urdf
这样做有三个目的:
加载指定的模型,并将其保存为
机器人状态发布者
节点。运行节点进行发布 sensor_msgs/msg/JointState 和变换(稍后详述)
使用配置文件启动 Rviz
启动后 display.launch.py
然后,RViz 就会向您显示以下内容:

- 需要注意的事项
固定框架是网格中心所在的变换框架。在这里,它是由我们的一个链接(base_link)定义的框架。
默认情况下,视觉元素(圆柱体)的原点位于其几何中心。因此,圆柱体的一半位于网格下方。
多种形状
现在我们来看看如何添加多个形状/链接。如果我们只是在 urdf 中添加更多链接元素,解析器将不知道把它们放在哪里。因此,我们必须添加关节。关节元素既可以指灵活的关节,也可以指不灵活的关节。我们先从不灵活或固定的关节开始。 [来源:02-multipleshapes.urdf]
<?xml版本="1.0"?>;
机器人 名称"多重形状";>;
链接 名称"base_link";>;
视觉效果
<几何>;
气缸 长度="0.6"; 半径="0.2";/>;
</geometry>;
</visual>;
</link>;
链接 名称"right_leg";>;
视觉效果
<几何>;
<box size="0.6 0.1 0.2";/>;
</geometry>;
</visual>;
</link>;
<joint 名称"base_to_right_leg"; type="固定";>;
<parent link="base_link";/>;
孩子 link="right_leg";/>;
</joint>;
</机器人>;
请注意我们是如何定义 0.6 米 x 0.1 米 x 0.2 米方框的
连接是以父节点和子节点来定义的。URDF 最终是一个只有一个根链接的树形结构。这意味着腿的位置取决于根链接的位置。
ros2 launch urdf_tutorial display.launch.py model:=urdf/02-multipleshapes.urdf

这两个图形相互重叠,因为它们共享同一个原点。如果我们想让它们不重叠,就必须定义更多的原点。
起源
R2D2 的腿连接到躯干上半部分的侧面。因此,我们要在这里指定 JOINT 的原点。此外,R2D2 的腿并不是连接在中间,而是连接在上半部分,因此我们也必须偏移腿的原点。我们还可以旋转腿部,使其直立。 [来源:03-origins.urdf]
<?xml版本="1.0"?>;
机器人 名称"起源";>;
链接 名称"base_link";>;
视觉效果
<几何>;
气缸 长度="0.6"; 半径="0.2";/>;
</geometry>;
</visual>;
</link>;
链接 名称"right_leg";>;
视觉效果
<几何>;
<box size="0.6 0.1 0.2";/>;
</geometry>;
原产地 rpy="0 1.57075 0"; xyz="0 0 -0.3";/>;
</visual>;
</link>;
<joint 名称"base_to_right_leg"; type="固定";>;
<parent link="base_link";/>;
孩子 link="right_leg";/>;
原产地 xyz="0 -0.22 0.25";/>;
</joint>;
</机器人>;
我们先来看看关节的原点。它是根据父参照系定义的。因此,我们在 y 方向的距离是-0.22 米(在我们的左侧,但相对于坐标轴是在右侧),在 z 方向的距离是 0.25 米(向上)。这意味着,无论子链接的视觉原点标签是什么,子链接的原点都将是向上和向右。由于我们没有指定 rpy(滚动俯仰偏航)属性,子帧将默认具有与父帧相同的方向。
现在,我们来看看这条腿的视觉原点,它有 xyz 和 rpy 偏移。这定义了视觉元素相对于原点的中心位置。由于我们希望支腿连接在顶部,因此我们将 Z 偏移量设置为-0.3 米,从而将原点向下偏移。由于我们希望腿的长部分与 Z 轴平行,因此我们将视觉部分绕 Y 轴旋转 PI/2。
ros2 launch urdf_tutorial display.launch.py model:=urdf/03-origins.urdf

启动文件运行的软件包将根据 URDF 为模型中的每个链接创建 TF 框架。Rviz 会使用这些信息来确定每个形状的显示位置。
如果给定的 URDF 链路不存在 TF 帧,那么它将被置于白色的原点(参考文献)。 相关问题).
物质女孩
"好吧,"我听到你说。"这很可爱,但不是每个人都有 B21。我的机器人和 R2D2 都不是红色的!"说得好让我们来看看材料标签。 [来源:04-materials.urdf]
<?xml版本="1.0"?>;
机器人 名称"材料";>;
材料 名称蓝色;>;
颜色 rgba="0 0 0.8 1";/>;
</material>;
材料 名称"白色";>;
颜色 rgba="1 1 1 1";/>;
</material>;
链接 名称"base_link";>;
视觉效果
<几何>;
气缸 长度="0.6"; 半径="0.2";/>;
</geometry>;
材料 名称蓝色;/>;
</visual>;
</link>;
链接 名称"right_leg";>;
视觉效果
<几何>;
<box size="0.6 0.1 0.2";/>;
</geometry>;
原产地 rpy="0 1.57075 0"; xyz="0 0 -0.3";/>;
材料 名称"白色";/>;
</visual>;
</link>;
<joint 名称"base_to_right_leg"; type="固定";>;
<parent link="base_link";/>;
孩子 link="right_leg";/>;
原产地 xyz="0 -0.22 0.25";/>;
</joint>;
链接 名称"左腿";>;
视觉效果
<几何>;
<box size="0.6 0.1 0.2";/>;
</geometry>;
原产地 rpy="0 1.57075 0"; xyz="0 0 -0.3";/>;
材料 名称"白色";/>;
</visual>;
</link>;
<joint 名称"base_too_left_leg"; type="固定";>;
<parent link="base_link";/>;
孩子 link="左腿";/>;
原产地 xyz="0 0.22 0.25";/>;
</joint>;
</机器人>;
身体现在是蓝色的。我们定义了一个名为 "蓝色 "的新材质,红色、绿色、蓝色和 alpha 通道分别定义为 0、0、0.8 和 1。所有值的范围都是 [0,1]。然后,base_link 的视觉元素就会引用该材质。白色材质的定义与此类似。
你也可以在视觉元素中定义材质标签,甚至在其他链接中引用它。不过,如果你重新定义它,根本不会有人抱怨。
您还可以使用纹理来指定用于为对象着色的图像文件
ros2 launch urdf_tutorial display.launch.py model:=urdf/04-materials.urdf

完成模型
现在,我们再为模型添加一些形状:脚、轮子和头。最值得注意的是,我们添加了一个球体和一些网格。我们还将添加一些稍后会用到的其他部件。 [来源:05-visual.urdf]
<?xml版本="1.0"?>;
机器人 名称"视觉";>;
材料 名称蓝色;>;
颜色 rgba="0 0 0.8 1";/>;
</material>;
材料 名称"黑色";>;
颜色 rgba="0 0 0 1";/>;
</material>;
材料 名称"白色";>;
颜色 rgba="1 1 1 1";/>;
</material>;
链接 名称"base_link";>;
视觉效果
<几何>;
气缸 长度="0.6"; 半径="0.2";/>;
</geometry>;
材料 名称蓝色;/>;
</visual>;
</link>;
链接 名称"right_leg";>;
视觉效果
<几何>;
<box size="0.6 0.1 0.2";/>;
</geometry>;
原产地 rpy="0 1.57075 0"; xyz="0 0 -0.3";/>;
材料 名称"白色";/>;
</visual>;
</link>;
<joint 名称"base_to_right_leg"; type="固定";>;
<parent link="base_link";/>;
孩子 link="right_leg";/>;
原产地 xyz="0 -0.22 0.25";/>;
</joint>;
链接 名称"right_base";>;
视觉效果
<几何>;
<box size="0.4 0.1 0.1";/>;
</geometry>;
材料 名称"白色";/>;
</visual>;
</link>;
<joint 名称"right_base_joint"; type="固定";>;
<parent link="right_leg";/>;
孩子 link="right_base";/>;
原产地 xyz="0 0 -0.6";/>;
</joint>;
链接 名称"right_front_wheel";>;
视觉效果
原产地 rpy="1.57075 0 0"; xyz="0 0 0";/>;
<几何>;
气缸 长度="0.1"; 半径="0.035";/>;
</geometry>;
材料 名称"黑色";/>;
</visual>;
</link>;
<joint 名称"right_front_wheel_joint"; type="固定";>;
<parent link="right_base";/>;
孩子 link="right_front_wheel";/>;
原产地 rpy="0 0 0"; xyz="0.133333333333 0 -0.085";/>;
</joint>;
链接 名称"right_back_wheel";>;
视觉效果
原产地 rpy="1.57075 0 0"; xyz="0 0 0";/>;
<几何>;
气缸 长度="0.1"; 半径="0.035";/>;
</geometry>;
材料 名称"黑色";/>;
</visual>;
</link>;
<joint 名称"right_back_wheel_joint"; type="固定";>;
<parent link="right_base";/>;
孩子 link="right_back_wheel";/>;
原产地 rpy="0 0 0"; xyz="-0.133333333333 0 -0.085";/>;
</joint>;
链接 名称"左腿";>;
视觉效果
<几何>;
<box size="0.6 0.1 0.2";/>;
</geometry>;
原产地 rpy="0 1.57075 0"; xyz="0 0 -0.3";/>;
材料 名称"白色";/>;
</visual>;
</link>;
<joint 名称"base_too_left_leg"; type="固定";>;
<parent link="base_link";/>;
孩子 link="左腿";/>;
原产地 xyz="0 0.22 0.25";/>;
</joint>;
链接 名称"left_base";>;
视觉效果
<几何>;
<box size="0.4 0.1 0.1";/>;
</geometry>;
材料 名称"白色";/>;
</visual>;
</link>;
<joint 名称"left_base_joint"; type="固定";>;
<parent link="左腿";/>;
孩子 link="left_base";/>;
原产地 xyz="0 0 -0.6";/>;
</joint>;
链接 名称"left_front_wheel";>;
视觉效果
原产地 rpy="1.57075 0 0"; xyz="0 0 0";/>;
<几何>;
气缸 长度="0.1"; 半径="0.035";/>;
</geometry>;
材料 名称"黑色";/>;
</visual>;
</link>;
<joint 名称"left_front_wheel_joint"; type="固定";>;
<parent link="left_base";/>;
孩子 link="left_front_wheel";/>;
原产地 rpy="0 0 0"; xyz="0.133333333333 0 -0.085";/>;
</joint>;
链接 名称"left_back_wheel";>;
视觉效果
原产地 rpy="1.57075 0 0"; xyz="0 0 0";/>;
<几何>;
气缸 长度="0.1"; 半径="0.035";/>;
</geometry>;
材料 名称"黑色";/>;
</visual>;
</link>;
<joint 名称"left_back_wheel_joint"; type="固定";>;
<parent link="left_base";/>;
孩子 link="left_back_wheel";/>;
原产地 rpy="0 0 0"; xyz="-0.133333333333 0 -0.085";/>;
</joint>;
<joint 名称"gripper_extension"; type="固定";>;
<parent link="base_link";/>;
孩子 link="gripper_pole";/>;
原产地 rpy="0 0 0"; xyz="0.19 0 0.2";/>;
</joint>;
链接 名称"gripper_pole";>;
视觉效果
<几何>;
气缸 长度="0.2"; 半径="0.01";/>;
</geometry>;
原产地 rpy="0 1.57075 0 "; xyz="0.1 0 0";/>;
</visual>;
</link>;
<joint 名称"left_gripper_joint"; type="固定";>;
原产地 rpy="0 0 0"; xyz="0.2 0.01 0";/>;
<parent link="gripper_pole";/>;
孩子 link="left_gripper";/>;
</joint>;
链接 名称"left_gripper";>;
视觉效果
原产地 rpy="0.0 0.0"; xyz="0 0 0";/>;
<几何>;
<mesh filename="package://urdf_tutorial/meshes/l_finger.dae";/>;
</geometry>;
</visual>;
</link>;
<joint 名称"left_tip_joint"; type="固定";>;
<parent link="left_gripper";/>;
孩子 link=quot;left_tip";/>;
</joint>;
链接 名称quot;left_tip";>;
视觉效果
原产地 rpy="0.0 0.0"; xyz="0.09137 0.00495 0";/>;
<几何>;
<mesh filename="package://urdf_tutorial/meshes/l_finger_tip.dae";/>;
</geometry>;
</visual>;
</link>;
<joint 名称"right_gripper_joint"; type="固定";>;
原产地 rpy="0 0 0"; xyz="0.2 -0.01 0";/>;
<parent link="gripper_pole";/>;
孩子 link="right_gripper";/>;
</joint>;
链接 名称"right_gripper";>;
视觉效果
原产地 rpy="-3.1415 0 0"; xyz="0 0 0";/>;
<几何>;
<mesh filename="package://urdf_tutorial/meshes/l_finger.dae";/>;
</geometry>;
</visual>;
</link>;
<joint 名称"right_tip_joint"; type="固定";>;
<parent link="right_gripper";/>;
孩子 link="right_tip";/>;
</joint>;
链接 名称"right_tip";>;
视觉效果
原产地 rpy="-3.1415 0 0"; xyz="0.09137 0.00495 0";/>;
<几何>;
<mesh filename="package://urdf_tutorial/meshes/l_finger_tip.dae";/>;
</geometry>;
</visual>;
</link>;
链接 名称"head";>;
视觉效果
<几何>;
<sphere 半径="0.2";/>;
</geometry>;
材料 名称"白色";/>;
</visual>;
</link>;
<joint 名称"head_swivel"; type="固定";>;
<parent link="base_link";/>;
孩子 link="head";/>;
原产地 xyz="0 0 0.3";/>;
</joint>;
链接 名称"box";>;
视觉效果
<几何>;
<box size="0.08 0.08 0.08";/>;
</geometry>;
材料 名称蓝色;/>;
</visual>;
</link>;
<joint 名称"tobox"; type="固定";>;
<parent link="head";/>;
孩子 link="box";/>;
原产地 xyz="0.1814 0 0.1414";/>;
</joint>;
</机器人>;
ros2 launch urdf_tutorial display.launch.py model:=urdf/05-visual.urdf

如何添加球体应该不难解释:
链接 名称"head";>;
视觉效果
<几何>;
<sphere 半径="0.2";/>;
</geometry>;
材料 名称"白色";/>;
</visual>;
</link>;
这里的网格是从 PR2 中借用的。它们是独立的文件,需要指定路径。您应该使用 package://NAME_OF_PACKAGE/path
符号。本教程的网格位于 urdf_tutorial
包中名为 meshes 的文件夹。
链接 名称"left_gripper";>;
视觉效果
原产地 rpy="0.0 0.0"; xyz="0 0 0";/>;
<几何>;
<mesh filename="package://urdf_tutorial/meshes/l_finger.dae";/>;
</geometry>;
</visual>;
</link>;
网格可以多种不同格式导入。STL 是比较常见的格式,但引擎也支持 DAE,它可以有自己的颜色数据,这意味着你不必指定颜色/材料。通常这些都是单独的文件。这些网格参照
.tif
文件也在网格文件夹中。也可以使用相对缩放参数或边界框尺寸来调整网格大小。
我们也可以在完全不同的软件包中引用网格。
就是这样。一个类似 R2D2 的 URDF 模型。现在你可以继续下一步了、 使其移动.