搭建机器人
本教程介绍如何用 SDFormat 搭建机器人。我们将构建一个简单的两轮机器人。
可在 此处 查看本教程完成的 SDF 文件。
什么是 SDF
Section titled “什么是 SDF”SDFormat(Simulation Description Format,仿真描述格式),有时缩写为 SDF,是一种 XML 格式,用于描述机器人仿真、可视化和控制中的对象与环境。
构建一个世界(World)
Section titled “构建一个世界(World)”先构建一个简单的世界,再在其中搭建机器人。新建名为 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)
Section titled “构建一个模型(Model)”在 </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)
Section titled “构成机器人的链接(Link)”每个模型由若干链接(Link)组成,通过关节(Joint)连接在一起(也可以只有一个链接)。
底盘(Chassis)
Section titled “底盘(Chassis)” <link name='chassis'> <pose relative_to='__model__'>0.5 0 0.4 0 0 0</pose>这里定义了第一个链接,即机器人的 底盘 (chassis),以及它相对于 模型 (model) 的位姿。
惯性属性(Inertial properties)
Section titled “惯性属性(Inertial properties)” <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 and collision)
Section titled “视觉与碰撞(Visual and collision)” <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 轴。
左轮(Left wheel)
Section titled “左轮(Left wheel)”接下来为机器人添加轮子。以下代码放在 </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>(长度)。
保存文件并再次运行世界,模型应呈现如下效果:

右轮(Right wheel)
Section titled “右轮(Right wheel)”<!--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)
Section titled “万向轮(Caster wheel)”<!--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>(半径)。
用关节连接链接(Connecting links together)
Section titled “用关节连接链接(Connecting links together)”需要将这些链接连接起来,这正是 <joint> 标签的作用。<joint> 标签将两个链接连接在一起,并定义它们之间相对运动的方式。在 <joint> 标签内,需要定义要连接的两个链接以及它们之间的关系(运动方式)。
左轮关节(Left wheel joint)
Section titled “左轮关节(Left wheel 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)
Section titled “右轮关节(Right wheel joint)”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>万向轮关节(Caster wheel joint)
Section titled “万向轮关节(Caster wheel 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 教程:搭建机器人。