从头开始用URDF构建视觉机器人模型 [待校准@8996]

Goal目标: Learn了解如何构建可以在Rviz中查看的机器人视觉模型 [待校准@8997]

教程级别: 初学者 [Alyssa@7088]

Note注意: This本教程假设您知道如何编写格式良好的XML代码 [待校准@8998]

在本教程中,我们将构建一个看起来有点像R2D2的机器人的视觉模型。在后面的教程中,您将学习如何 articulate the model, add in some physical properties, and generate neater code with xacro ,但是现在,我们将重点关注使视觉几何正确。 [待校准@8999]

在继续之前,确保你有 joint_state_publisher package installed. If you installed urdf_tutorial 二进制文件,应该已经是这样了。如果没有,请更新您的安装以包含该包 (使用 rosdep 检查)。 [待校准@9000]

本教程中提到的所有机器人模型 (以及源文件) 都可以在 urdf_tutorial 包中找到。 [待校准@9001]

为了确保正确解析urdf文件中定义的形状,需要将Linux环境变量 LC_NUMERIC 设置为 en_US.UTF-8 。每次打开终端时都必须这样做: [待校准@9002]

LC_NUMERIC="en_US.UTF-8"

要永久设置此环境变量,请在终端中执行以下命令: [待校准@9003]

echo 'export LC_NUMERIC="en_US.UTF-8"' >> ~/.bashrc

一个形状 [待校准@9004]

首先,我们将探索一个简单的形状。这是尽可能简单的urdf。 [Source: 01-myfirst.urdf] [待校准@9005]

<?xml version="1.0"?>
<robot name="myfirst">
  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      </geometry>
    </visual>
  </link>
</robot>

要将XML翻译成英语,这是一个名为 myfirst 的机器人,它只包含一个链接 (又名部分),其视觉成分只是一个长度为0.6米、半径为0.2米的圆柱体。对于一个简单的 “hello world” 类型的例子来说,这看起来像是很多封闭的标签,但是它会变得更加复杂,相信我。 [待校准@9006]

检查模型,launch的 display.launch.py 文件: [待校准@9007]

ros2 launch urdf_tutorial display.launch.py model:=urdf/01-myfirst.urdf

这做了三件事: [待校准@9008]

请注意,上面的launch命令假定您正在从 urdf_tutorial 包目录执行它 (即: urdf 目录是当前工作目录的直接子目录)。如果不是这种情况,到 01-myfirst.urdf 的相对路径将无效,一旦launcher尝试将urdf作为参数加载,您将收到一个错误。 [待校准@9012]

稍微修改的参数允许它工作,而不管当前的工作目录如何: [待校准@9013]

ros2 launch urdf_tutorial display.launch.py model:=`ros2 pkg prefix --share urdf_tutorial`/urdf/01-myfirst.urdf

你将把所有示例launch命令给出这些教程如果不运行从 urdf_tutorial 包位置。 [待校准@9014]

在launch display.launch.py 之后,你应该以RViz告终,向你展示以下内容: [待校准@9015]

我的第一张照片 `[待校准@9016] <http://dev.ros2.fishros.com/calibpage/#/home?msgid=9016>`_
需要注意的事项: [待校准@9017]
  • 固定帧是网格中心所在的变换帧。这里,它是由我们的一个链接base_link定义的帧。 [待校准@9018]

  • 默认情况下,视觉元素 (圆柱体) 的原点位于其几何图形的中心。因此,一半的圆柱体在网格下。 [待校准@9019]

多种形状 [待校准@9020]

现在让我们看看如何添加多个形状/链接。如果我们只是向urdf添加更多的链接元素,解析器将不知道将它们放在哪里。所以,我们必须增加关节。接缝元件可以指灵活和不灵活的接缝。我们将从不灵活或固定的关节开始。 [Source: 02-multipleshapes.urdf] [待校准@9021]

<?xml version="1.0"?>
<robot name="multipleshapes">
  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      </geometry>
    </visual>
  </link>

  <link name="right_leg">
    <visual>
      <geometry>
        <box size="0.6 0.1 0.2"/>
      </geometry>
    </visual>
  </link>

  <joint name="base_to_right_leg" type="fixed">
    <parent link="base_link"/>
    <child link="right_leg"/>
  </joint>

</robot>
  • 注意我们如何定义一个0.6米 × 0.1米 × 0.2米的盒子 [待校准@9022]

  • 关节是根据父母和孩子来定义的。URDF最终是一个具有一个根链接的树结构。这意味着腿的位置取决于base_link的位置。 [待校准@9023]

ros2 launch urdf_tutorial display.launch.py model:=urdf/02-multipleshapes.urdf
多种形状 `[待校准@9020] <http://dev.ros2.fishros.com/calibpage/#/home?msgid=9020>`_

两个形状相互重叠,因为它们共享相同的原点。如果我们希望它们不重叠,我们必须定义更多的起源。 [待校准@9024]

起源 [待校准@9025]

R2D2的腿附着在他躯干的上半部,在侧面。这就是我们指定关节的原点的地方。此外,它不会附着在腿的中间,而是附着在上部,所以我们也必须偏移腿的原点。我们也旋转腿,使它是直立的。 [Source: 03-origins.urdf] [待校准@9026]

<?xml version="1.0"?>
<robot name="origins">
  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      </geometry>
    </visual>
  </link>

  <link name="right_leg">
    <visual>
      <geometry>
        <box size="0.6 0.1 0.2"/>
      </geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
    </visual>
  </link>

  <joint name="base_to_right_leg" type="fixed">
    <parent link="base_link"/>
    <child link="right_leg"/>
    <origin xyz="0 -0.22 0.25"/>
  </joint>

</robot>
  • 让我们从检查关节的起源开始。它是根据父级的参考帧来定义的。因此,我们在y方向 (左侧,但相对于轴的右侧) 为-0.22米,在z方向 (向上) 为0.25米。这意味着子链接的原点将向上和向右,而不考虑子链接的视觉原点标签。由于我们没有指定rpy (滚距偏航) 属性,因此子帧将默认具有与父帧相同的方向。 [待校准@9027]

  • 现在,看看腿的视觉来源,它有xyz和rpy偏移。这定义了视觉元素相对于其原点的中心应该在哪里。由于我们希望支腿附着在顶部,我们通过将z偏移设置为-0.3米来向下偏移原点。并且由于我们希望腿的长部分与z轴平行,因此我们将视觉部分形式发票/2绕y轴旋转。 [待校准@9028]

ros2 launch urdf_tutorial display.launch.py model:=urdf/03-origins.urdf
起源截图 `[待校准@9029] <http://dev.ros2.fishros.com/calibpage/#/home?msgid=9029>`_
  • [需手动修复的语法]launch文件运行包,该包将根据您的URDF为模型中的每个链接创建TF帧。Rviz使用此信息来确定在哪里显示每个形状。 [待校准@9030]

  • 如果给定的URDF链接不存在TF帧,则它将以白色 (参考 related question ) 放置在原点。 [待校准@9031]

物质女孩 [待校准@9032]

“好吧,” 我听到你说。“那很可爱,但不是每个人都拥有b21。我的机器人和R2D2不是红色的!”这是一个很好的观点。让我们看看材料标签。 [Source: 04-materials.urdf] [待校准@9033]

<?xml version="1.0"?>
<robot name="materials">

  <material name="blue">
    <color rgba="0 0 0.8 1"/>
  </material>

  <material name="white">
    <color rgba="1 1 1 1"/>
  </material>

  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      </geometry>
      <material name="blue"/>
    </visual>
  </link>

  <link name="right_leg">
    <visual>
      <geometry>
        <box size="0.6 0.1 0.2"/>
      </geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
      <material name="white"/>
    </visual>
  </link>

  <joint name="base_to_right_leg" type="fixed">
    <parent link="base_link"/>
    <child link="right_leg"/>
    <origin xyz="0 -0.22 0.25"/>
  </joint>

  <link name="left_leg">
    <visual>
      <geometry>
        <box size="0.6 0.1 0.2"/>
      </geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
      <material name="white"/>
    </visual>
  </link>

  <joint name="base_to_left_leg" type="fixed">
    <parent link="base_link"/>
    <child link="left_leg"/>
    <origin xyz="0 0.22 0.25"/>
  </joint>

</robot>
  • 尸体现在是蓝色的。我们定义新材料调用了 “蓝色”,红色,绿色,蓝色和alpha通道定义为0,0,0.8和1。所有值都可以在 [0,1] 范围内。然后,此材质由base_link的视觉元素引用。白色材料的定义类似。 [待校准@9034]

  • 您还可以从视觉元素中定义材质标签,甚至在其他链接中引用它。如果你重新定义它,甚至没有人会抱怨。 [待校准@9035]

  • 您还可以使用纹理指定用于为对象着色的图像文件 [待校准@9036]

ros2 launch urdf_tutorial display.launch.py model:=urdf/04-materials.urdf
材料截图 `[待校准@9037] <http://dev.ros2.fishros.com/calibpage/#/home?msgid=9037>`_

完成模型 [待校准@9038]

现在我们用更多的形状来完成模型: 脚、轮子和头。最值得注意的是,我们添加了一个球体和一些网格。我们还将添加一些其他的作品,我们将在以后使用。 [Source: 05-visual.urdf] [待校准@9039]

<?xml version="1.0"?>
<robot name="visual">

  <material name="blue">
    <color rgba="0 0 0.8 1"/>
  </material>
  <material name="black">
    <color rgba="0 0 0 1"/>
  </material>
  <material name="white">
    <color rgba="1 1 1 1"/>
  </material>

  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      </geometry>
      <material name="blue"/>
    </visual>
  </link>

  <link name="right_leg">
    <visual>
      <geometry>
        <box size="0.6 0.1 0.2"/>
      </geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
      <material name="white"/>
    </visual>
  </link>

  <joint name="base_to_right_leg" type="fixed">
    <parent link="base_link"/>
    <child link="right_leg"/>
    <origin xyz="0 -0.22 0.25"/>
  </joint>

  <link name="right_base">
    <visual>
      <geometry>
        <box size="0.4 0.1 0.1"/>
      </geometry>
      <material name="white"/>
    </visual>
  </link>

  <joint name="right_base_joint" type="fixed">
    <parent link="right_leg"/>
    <child link="right_base"/>
    <origin xyz="0 0 -0.6"/>
  </joint>

  <link name="right_front_wheel">
    <visual>
      <origin rpy="1.57075 0 0" xyz="0 0 0"/>
      <geometry>
        <cylinder length="0.1" radius="0.035"/>
      </geometry>
      <material name="black"/>
    </visual>
  </link>
  <joint name="right_front_wheel_joint" type="fixed">
    <parent link="right_base"/>
    <child link="right_front_wheel"/>
    <origin rpy="0 0 0" xyz="0.133333333333 0 -0.085"/>
  </joint>

  <link name="right_back_wheel">
    <visual>
      <origin rpy="1.57075 0 0" xyz="0 0 0"/>
      <geometry>
        <cylinder length="0.1" radius="0.035"/>
      </geometry>
      <material name="black"/>
    </visual>
  </link>
  <joint name="right_back_wheel_joint" type="fixed">
    <parent link="right_base"/>
    <child link="right_back_wheel"/>
    <origin rpy="0 0 0" xyz="-0.133333333333 0 -0.085"/>
  </joint>

  <link name="left_leg">
    <visual>
      <geometry>
        <box size="0.6 0.1 0.2"/>
      </geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
      <material name="white"/>
    </visual>
  </link>

  <joint name="base_to_left_leg" type="fixed">
    <parent link="base_link"/>
    <child link="left_leg"/>
    <origin xyz="0 0.22 0.25"/>
  </joint>

  <link name="left_base">
    <visual>
      <geometry>
        <box size="0.4 0.1 0.1"/>
      </geometry>
      <material name="white"/>
    </visual>
  </link>

  <joint name="left_base_joint" type="fixed">
    <parent link="left_leg"/>
    <child link="left_base"/>
    <origin xyz="0 0 -0.6"/>
  </joint>

  <link name="left_front_wheel">
    <visual>
      <origin rpy="1.57075 0 0" xyz="0 0 0"/>
      <geometry>
        <cylinder length="0.1" radius="0.035"/>
      </geometry>
      <material name="black"/>
    </visual>
  </link>
  <joint name="left_front_wheel_joint" type="fixed">
    <parent link="left_base"/>
    <child link="left_front_wheel"/>
    <origin rpy="0 0 0" xyz="0.133333333333 0 -0.085"/>
  </joint>

  <link name="left_back_wheel">
    <visual>
      <origin rpy="1.57075 0 0" xyz="0 0 0"/>
      <geometry>
        <cylinder length="0.1" radius="0.035"/>
      </geometry>
      <material name="black"/>
    </visual>
  </link>
  <joint name="left_back_wheel_joint" type="fixed">
    <parent link="left_base"/>
    <child link="left_back_wheel"/>
    <origin rpy="0 0 0" xyz="-0.133333333333 0 -0.085"/>
  </joint>

  <joint name="gripper_extension" type="fixed">
    <parent link="base_link"/>
    <child link="gripper_pole"/>
    <origin rpy="0 0 0" xyz="0.19 0 0.2"/>
  </joint>

  <link name="gripper_pole">
    <visual>
      <geometry>
        <cylinder length="0.2" radius="0.01"/>
      </geometry>
      <origin rpy="0 1.57075 0 " xyz="0.1 0 0"/>
    </visual>
  </link>

  <joint name="left_gripper_joint" type="fixed">
    <origin rpy="0 0 0" xyz="0.2 0.01 0"/>
    <parent link="gripper_pole"/>
    <child link="left_gripper"/>
  </joint>

  <link name="left_gripper">
    <visual>
      <origin rpy="0.0 0 0" xyz="0 0 0"/>
      <geometry>
        <mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
      </geometry>
    </visual>
  </link>

  <joint name="left_tip_joint" type="fixed">
    <parent link="left_gripper"/>
    <child link="left_tip"/>
  </joint>

  <link name="left_tip">
    <visual>
      <origin rpy="0.0 0 0" xyz="0.09137 0.00495 0"/>
      <geometry>
        <mesh filename="package://urdf_tutorial/meshes/l_finger_tip.dae"/>
      </geometry>
    </visual>
  </link>
  <joint name="right_gripper_joint" type="fixed">
    <origin rpy="0 0 0" xyz="0.2 -0.01 0"/>
    <parent link="gripper_pole"/>
    <child link="right_gripper"/>
  </joint>

  <link name="right_gripper">
    <visual>
      <origin rpy="-3.1415 0 0" xyz="0 0 0"/>
      <geometry>
        <mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
      </geometry>
    </visual>
  </link>

  <joint name="right_tip_joint" type="fixed">
    <parent link="right_gripper"/>
    <child link="right_tip"/>
  </joint>

  <link name="right_tip">
    <visual>
      <origin rpy="-3.1415 0 0" xyz="0.09137 0.00495 0"/>
      <geometry>
        <mesh filename="package://urdf_tutorial/meshes/l_finger_tip.dae"/>
      </geometry>
    </visual>
  </link>

  <link name="head">
    <visual>
      <geometry>
        <sphere radius="0.2"/>
      </geometry>
      <material name="white"/>
    </visual>
  </link>
  <joint name="head_swivel" type="fixed">
    <parent link="base_link"/>
    <child link="head"/>
    <origin xyz="0 0 0.3"/>
  </joint>

  <link name="box">
    <visual>
      <geometry>
        <box size="0.08 0.08 0.08"/>
      </geometry>
      <material name="blue"/>
    </visual>
  </link>

  <joint name="tobox" type="fixed">
    <parent link="head"/>
    <child link="box"/>
    <origin xyz="0.1814 0 0.1414"/>
  </joint>
</robot>
ros2 launch urdf_tutorial display.launch.py model:=urdf/05-visual.urdf
视觉截图 `[待校准@9040] <http://dev.ros2.fishros.com/calibpage/#/home?msgid=9040>`_

如何添加球体应该是相当不言自明的: [待校准@9041]

<link name="head">
  <visual>
    <geometry>
      <sphere radius="0.2"/>
    </geometry>
    <material name="white"/>
  </visual>
</link>

这里的网格是从pr2借来的。它们是单独的文件,您必须为其指定路径。您应该使用 “package:// NAME_OF_PACKAGE/path” 表示法。本教程的网格位于 urdf_tutorial 包中调用网格的文件夹中。 [待校准@9042]

<link name="left_gripper">
  <visual>
    <origin rpy="0.0 0 0" xyz="0 0 0"/>
    <geometry>
      <mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
    </geometry>
  </visual>
</link>
  • 网格可以以多种不同格式导入。STL相当普遍,但引擎也支持DAE,它可以有自己的颜色数据,这意味着您不必指定颜色/材质。这些通常在单独的文件中。这些网格引用了网格文件夹中的 .tif 文件。 [待校准@9043]

  • 网格也可以使用相对缩放参数或边界框大小来确定大小。 [待校准@9044]

  • 我们也可以在一个完全不同的包中提到网格。 [待校准@9045]

给你。一个R2D2-like的URDF模型。现在你可以继续下一步了, making it move[待校准@9046]