Skip to content

搭建机器人

本教程介绍如何用 SDFormat 搭建机器人。我们将构建一个简单的两轮机器人。

可在 此处 查看本教程完成的 SDF 文件。

SDFormat(Simulation Description Format,仿真描述格式),有时缩写为 SDF,是一种 XML 格式,用于描述机器人仿真、可视化和控制中的对象与环境。

先构建一个简单的世界,再在其中搭建机器人。新建名为 building_robot.sdf 的文件,将以下代码复制进去。

<?xml version="1.0" ?>
<sdf version="1.10">
<world name="car_world">
<physics name="1ms" type="ignored">
<max_step_size>0.001</max_step_size>
<real_time_factor>1.0</real_time_factor>
</physics>
<plugin
filename="gz-sim-physics-system"
name="gz::sim::systems::Physics">
</plugin>
<plugin
filename="gz-sim-user-commands-system"
name="gz::sim::systems::UserCommands">
</plugin>
<plugin
filename="gz-sim-scene-broadcaster-system"
name="gz::sim::systems::SceneBroadcaster">
</plugin>
<light type="directional" name="sun">
<cast_shadows>true</cast_shadows>
<pose>0 0 10 0 0 0</pose>
<diffuse>0.8 0.8 0.8 1</diffuse>
<specular>0.2 0.2 0.2 1</specular>
<attenuation>
<range>1000</range>
<constant>0.9</constant>
<linear>0.01</linear>
<quadratic>0.001</quadratic>
</attenuation>
<direction>-0.5 0.1 -0.9</direction>
</light>
<model name="ground_plane">
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<plane>
<normal>0 0 1</normal>
</plane>
</geometry>
</collision>
<visual name="visual">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
<material>
<ambient>0.8 0.8 0.8 1</ambient>
<diffuse>0.8 0.8 0.8 1</diffuse>
<specular>0.8 0.8 0.8 1</specular>
</material>
</visual>
</link>
</model>
</world>
</sdf>

保存文件后,进入所在目录并启动仿真器:

gz sim building_robot.sdf

注意:文件可随意命名并保存在任意位置。

此时应看到一个仅含地面和太阳光的空世界。查看 World 演示 学习如何构建自己的世界。

在 </model> 标签下,按如下方式添加机器人模型:

<model name='vehicle_blue' canonical_link='chassis'>
<pose relative_to='world'>0 0 0 0 0 0</pose>

这里定义了模型的名称 vehicle_blue,该名称在同级标签(同一层级的其他标签或模型)中必须唯一。 每个模型可以指定一个链接(Link)作为 canonical_link,模型的隐式坐标系(frame)就附着在该链接上。若未定义,则第一个 <link> 默认为 canonical link。 <pose> 标签定义模型的位置和方向,relative_to 属性指定模型相对于其他坐标系的位姿。 若未定义 relative_to,模型的 <pose> 默认相对于世界(World)。

将位姿设为相对于 world。pose 标签内的值格式为 <pose>X Y Z R P Y</pose>,其中 X Y Z 表示坐标系的位置,R P Y 分别表示 roll、pitch、yaw 方向。 这里全部设为零,使模型坐标系与世界坐标系重合。

每个模型由若干链接(Link)组成,通过关节(Joint)连接在一起(也可以只有一个链接)。

<link name='chassis'>
<pose relative_to='__model__'>0.5 0 0.4 0 0 0</pose>

这里定义了第一个链接,即机器人的 底盘 (chassis),以及它相对于 模型 (model) 的位姿。

<inertial> <!--inertial properties of the link mass, inertia matrix-->
<mass>1.14395</mass>
<inertia>
<ixx>0.095329</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.381317</iyy>
<iyz>0</iyz>
<izz>0.476646</izz>
</inertia>
</inertial>

这里定义了底盘的惯性属性,包括 <mass>(质量)和 <inertia>(惯性矩阵)。基本形状的惯性矩阵值可使用这个 工具 计算。

<visual name='visual'>
<geometry>
<box>
<size>2.0 1.0 0.5</size>
</box>
</geometry>
<!--let's add color to our link-->
<material>
<ambient>0.0 0.0 1.0 1</ambient>
<diffuse>0.0 0.0 1.0 1</diffuse>
<specular>0.0 0.0 1.0 1</specular>
</material>
</visual>

顾名思义,<visual> 标签负责定义链接的外观。 在 <geometry> 标签内将链接形状定义为 <box>(长方体),并在 <size> 标签中指定长方体的三个尺寸(以米为单位)。 随后在 <material> 标签内定义链接的材质。 这里通过四组取值范围为 [0, 1] 的数字(红/绿/蓝/alpha)分别设置了 <ambient>、<diffuse> 和 <specular> 颜色。

<collision name='collision'>
<geometry>
<box>
<size>2.0 1.0 0.5</size>
</box>
</geometry>
</collision>
</link>
</model>

<collision> 标签定义链接的碰撞属性,即链接如何与其他对象发生碰撞,以及物理引擎对它的影响。

注意:<collision> 可以不同于视觉属性。例如,通常会使用更简单的碰撞模型来减少计算量。

将以上所有部分按顺序添加到世界文件中后,再次运行:

gz sim building_robot.sdf

模型应该呈现如下效果:

汽车底盘

在左上角工具栏中点击 Translate 图标,然后选择模型。 此时应看到三个坐标轴,如下图所示:

模型轴

这些就是模型的坐标轴,其中红色为 x 轴,绿色为 y 轴,蓝色为 z 轴。

接下来为机器人添加轮子。以下代码放在 </link> 标签之后、</model> 标签之前。属于同一模型的所有链接和关节都应在 </model> 之前定义。

<link name='left_wheel'>
<pose relative_to="chassis">-0.5 0.6 0 -1.5707 0 0</pose>
<inertial>
<mass>1</mass>
<inertia>
<ixx>0.043333</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.043333</iyy>
<iyz>0</iyz>
<izz>0.08</izz>
</inertia>
</inertial>

定义了链接名称 left_wheel,并指定其 <pose> relative_to(相对于)chassis 链接。 轮子需要放在底盘后部的左侧,因此 pose 的位置取值为 -0.5 0.6 0。 此外,轮子是圆柱体,但需要侧放。因此将方向值设为 -1.5707 0 0,即绕 x 轴旋转 -90 度(角度以弧度为单位)。 随后定义轮子的 inertial(惯性)属性:mass(质量)和 inertia(惯性矩阵)。

可视化与碰撞(Visualization and Collision)

Section titled “可视化与碰撞(Visualization and Collision)”
<visual name='visual'>
<geometry>
<cylinder>
<radius>0.4</radius>
<length>0.2</length>
</cylinder>
</geometry>
<material>
<ambient>1.0 0.0 0.0 1</ambient>
<diffuse>1.0 0.0 0.0 1</diffuse>
<specular>1.0 0.0 0.0 1</specular>
</material>
</visual>
<collision name='collision'>
<geometry>
<cylinder>
<radius>0.4</radius>
<length>0.2</length>
</cylinder>
</geometry>
</collision>
</link>

<visual> 和 <collision> 属性与上一个链接类似,只是链接形状是 <cylinder>(圆柱体),需要两个属性:圆柱体的 <radius>(半径)和 <length>(长度)。 保存文件并再次运行世界,模型应呈现如下效果:

左轮

<!--The same as left wheel but with different position-->
<link name='right_wheel'>
<pose relative_to="chassis">-0.5 -0.6 0 -1.5707 0 0</pose> <!--angles are in radian-->
<inertial>
<mass>1</mass>
<inertia>
<ixx>0.043333</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.043333</iyy>
<iyz>0</iyz>
<izz>0.08</izz>
</inertia>
</inertial>
<visual name='visual'>
<geometry>
<cylinder>
<radius>0.4</radius>
<length>0.2</length>
</cylinder>
</geometry>
<material>
<ambient>1.0 0.0 0.0 1</ambient>
<diffuse>1.0 0.0 0.0 1</diffuse>
<specular>1.0 0.0 0.0 1</specular>
</material>
</visual>
<collision name='collision'>
<geometry>
<cylinder>
<radius>0.4</radius>
<length>0.2</length>
</cylinder>
</geometry>
</collision>
</link>

右轮与左轮类似,仅位置不同。

定义任意坐标系(Defining an arbitrary frame)

Section titled “定义任意坐标系(Defining an arbitrary frame)”

自 SDF 1.7 起(Fortress 使用 SDF 1.8),可以定义任意坐标系(frame)。它需要两个属性:

  • name:坐标系的名称
  • attached_to:该坐标系所附着的坐标系或链接的名称。

下面为万向轮(caster wheel)添加一个坐标系,如下所示:

<frame name="caster_frame" attached_to='chassis'>
<pose>0.8 0 -0.2 0 0 0</pose>
</frame>

将坐标系命名为 caster_frame,并附着到 chassis 链接上,然后用 <pose> 标签定义该坐标系的位置和方向。 由于未使用 relative_to 属性,位姿相对于 attached_to 属性中指定的坐标系,本例中即 chassis。

<!--caster wheel-->
<link name='caster'>
<pose relative_to='caster_frame'/>
<inertial>
<mass>1</mass>
<inertia>
<ixx>0.016</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.016</iyy>
<iyz>0</iyz>
<izz>0.016</izz>
</inertia>
</inertial>
<visual name='visual'>
<geometry>
<sphere>
<radius>0.2</radius>
</sphere>
</geometry>
<material>
<ambient>0.0 1 0.0 1</ambient>
<diffuse>0.0 1 0.0 1</diffuse>
<specular>0.0 1 0.0 1</specular>
</material>
</visual>
<collision name='collision'>
<geometry>
<sphere>
<radius>0.2</radius>
</sphere>
</geometry>
</collision>
</link>

最后一个链接是 caster,其位姿相对于上面定义的 caster_frame 坐标系。 如你所见,这里直接关闭了 pose 标签,未定义位置或方向;此时链接的位姿与 relative_to 中的坐标系一致(即单位位姿,identity)。

在 <visual> 和 <collision> 标签中,使用了不同的形状 <sphere>(球体),它需要球体的 <radius>(半径)。

Section titled “用关节连接链接(Connecting links together)”

需要将这些链接连接起来,这正是 <joint> 标签的作用。<joint> 标签将两个链接连接在一起,并定义它们之间相对运动的方式。在 <joint> 标签内,需要定义要连接的两个链接以及它们之间的关系(运动方式)。

<joint name='left_wheel_joint' type='revolute'>
<pose relative_to='left_wheel'/>

第一个关节是 left_wheel_joint。它有两个属性:名称 name='left_wheel_joint' 和类型 type='revolute'。 revolute(旋转)类型提供带关节限位的 1 个旋转自由度。 关节的位姿与子链接的坐标系一致,即 left_wheel 坐标系。

<parent>chassis</parent>
<child>left_wheel</child>

每个关节将两个链接(刚体)连接在一起。 这里将 chassis 与 left_wheel 连接。 chassis 是父链接(parent link),left_wheel 是子链接(child link)。

<axis>
<xyz expressed_in='__model__'>0 1 0</xyz> <!--can be defined as any frame or even arbitrary frames-->
<limit>
<lower>-1.79769e+308</lower> <!--negative infinity-->
<upper>1.79769e+308</upper> <!--positive infinity-->
</limit>
</axis>
</joint>

这里定义了旋转轴。旋转轴可以是任何坐标系,不仅限于 parent(父)或 child(子)链接。 这里选择了相对于 model(模型)坐标系的 y 轴,因此 y 元素填 1,其他元素填 0。 对于 revolute 关节,需要在 <lower> 和 <upper> 标签中定义旋转角度的 <limits>(限位)。

注意:角度以弧度为单位。

right_wheel_joint 与左轮关节非常相似,只是关节的位姿不同。这个关节将 right_wheel 与 chassis 连接起来。

<joint name='right_wheel_joint' type='revolute'>
<pose relative_to='right_wheel'/>
<parent>chassis</parent>
<child>right_wheel</child>
<axis>
<xyz expressed_in='__model__'>0 1 0</xyz>
<limit>
<lower>-1.79769e+308</lower> <!--negative infinity-->
<upper>1.79769e+308</upper> <!--positive infinity-->
</limit>
</axis>
</joint>

对于万向轮,需要使用不同类型的关节。这里使用 type='ball',它提供 3 个旋转自由度。

<joint name='caster_wheel' type='ball'>
<parent>chassis</parent>
<child>caster</child>
</joint>

运行世界:

gz sim building_robot.sdf

模型应呈现如下效果:

双轮机器人

太棒了!第一个机器人搭建完成。可在 此处 了解更多关于 SDFormat 标签的详细信息。在下一个 教程 中,将学习如何让机器人移动起来。

本教程的视频演示可在 YouTube 频道观看:Gazebo 教程:搭建机器人。