设置URDF

在本指南中,我们将为一个简单的差动驱动机器人 创建统一机器人描述格式 的(URDF) 文件,让您亲身体验使用 URDF。我们还将设置 robot state publisher 并在 RVIZ 中可视化我们的模型。最后,我们将为我们的机器人 URDF 添加一些运动学属性,以便为模拟做好准备。这些步骤对于表示 用于导航的机器人 的所有传感器、硬件和机器人变换是必要的。 [校准@songhuangong]

参见

本教程中的完整源代码可以在 sam_bot_description 包下的 navigation2_tutorials 存储库中找到。 请注意,在完成本指南中的所有教程后,存储库包含完整的代码。 [校准@songhuangong]

URDF 和 Robot State Publisher [校准@songhuangong]

正如在上一教程中所讨论的,Navigation2 的要求之一是从 base_link 转换为各种传感器和参考框架。这种变换树的范围可以从只有一个从 base_linklaser_link 链接的简单树,也可以是由位于不同位置的多个传感器组成的树,每个传感器都有自己的坐标系。创建多个发布者来处理所有这些坐标系转换可能会变得乏味。因此,我们将使用 Robot State Publisher 包来发布我们的转换。 [校准@songhuangong]

Robot State Publisher 是 ROS 2 的一个包,它与 tf2 包交互以发布所有必要的变换,这些变换可以直接从机器人的几何结构和结构中推断出来。我们需要为它提供正确的 URDF,它会自动处理发布转换。这对于复杂的转换非常有用,但仍然推荐用于简单的转换树。 [校准@songhuangong]

统一机器人描述格式 (URDF) 是一个表示机器人模型的 XML 文件。在本教程中,它将主要用于构建与机器人几何相关的变换树,但它也有其他用途。一个例子是如何通过定义材料和网格等视觉组件,在 RVIZ(一种 ROS 的 3D 可视化工具)中可视化您的机器人模型。另一个例子是如何使用 URDF 来定义机器人的物理属性。然后,这些属性将用于 Gazebo 等物理模拟器中,以模拟您的机器人在环境中的交互方式。 [校准@songhuangong]

URDF 的另一个主要特点是它还支持 Xacro(XML 宏),以帮助您创建更短且可读的 XML,以帮助定义复杂的机器人。我们可以使用这些宏来消除在我们的 URDF 中重复 XML 块的需要。 Xacro 在定义可在整个 URDF 中定义重用的配置常量方面也很有用。 [校准@songhuangong]

参见

如果您想了解更多关于 URDF 和 Robot State Publisher 的信息,我们鼓励您查看官方的 URDF 文档`Robot State Publisher Documentation < http://wiki.ros.org/robot_state_publisher>`__ [校准@songhuangong]

环境设置 [校准@songhuangong]

在本指南中,我们假设您已经熟悉 ROS 2 以及如何设置您的开发环境,因此我们将轻松完成本节中的步骤。 [校准@songhuangong]

让我们从安装一些额外的 ROS 2 包开始,我们将在本教程中使用这些包。 [校准@songhuangong]

sudo apt install ros-<ros2-distro>-joint-state-publisher-gui
sudo apt install ros-<ros2-distro>-xacro

接下来,为您的项目创建一个目录,初始化一个 ROS 2 工作区并为您的机器人命名。对于我们来说,我们将其称为 sam_bot[校准@songhuangong]

ros2 pkg create --build-type ament_cmake sam_bot_description

编写URDF

参见

本节旨在为您提供一个适合初学者的关于为您的机器人构建 URDF 的介绍。如果您想了解更多关于 URDF 和 XAcro 的信息,我们建议您查看官方的 URDF 文档 [校准@songhuangong]

现在我们已经设置了项目工作区,让我们直接开始编写 URDF。下面是我们将尝试构建的机器人的形象。 [校准@songhuangong]

../../_images/base-bot_1.png ../../_images/base-bot_2.png

首先,在 src/description 下创建一个名为 sam_bot_description.urdf 的文件,并输入以下内容作为文件的初始内容。 [校准@songhuangong]

1<?xml version="1.0"?>
2<robot name="sam_bot" xmlns:xacro="http://ros.org/wiki/xacro">
3
4
5
6</robot>

备注

以下代码片段应放置在 <robot> 标签内。我们建议按照本教程中介绍的顺序添加它们。我们还提供了一些行号,让您大致了解在哪里输入代码。这可能与您正在编写的实际文件不同,具体取决于您对空格的使用。另请注意,行号假定您正在输入本指南中显示的代码。 [校准@songhuangong]

接下来,让我们使用XAcro属性定义一些常量,这些常量将在整个 URDF 中重复使用。 [校准@songhuangong]

 4  <!-- Define robot constants -->
 5  <xacro:property name="base_width" value="0.31"/>
 6  <xacro:property name="base_length" value="0.42"/>
 7  <xacro:property name="base_height" value="0.18"/>
 8
 9  <xacro:property name="wheel_radius" value="0.10"/>
10  <xacro:property name="wheel_width" value="0.04"/>
11  <xacro:property name="wheel_ygap" value="0.025"/>
12  <xacro:property name="wheel_zoff" value="0.05"/>
13  <xacro:property name="wheel_xoff" value="0.12"/>
14
15  <xacro:property name="caster_xoff" value="0.14"/>

这里简要讨论一下这些特性将在我们的urdf中代表什么。 base_* 属性决定了机器人主底盘的尺寸。 wheel_radiuswheel_width 定义了机器人的两个后轮的形状。 wheel_ygap 沿着y轴调整车轮和底盘之间的间隙,同时 wheel_zoffwheel_xoff 沿着z轴和x轴适当地定位后轮。最后, caster_xoff 沿着x轴定位前轮。 [校准@songhuangong]

然后让我们定义我们的 base_link ——这个链接将是一个大盒子,将充当我们机器人的主机架。在 URDF 中,link 元素描述了我们机器人的刚性部件或组件。然后 robot state publisher 利用这些定义来确定每个链接的坐标系并发布它们之间的转换。 [校准@songhuangong]

我们还将定义链接的一些视觉属性,这些属性可以被 Gazebo 和 Rviz 等工具用来展示机器人的 3D 模型。这些属性包括描述链接形状的 <geometry> 和描述链接颜色的 <material>[校准@songhuangong]

对于下面的代码块,我们从使用之前定义的 ${property} 语法,访问机器人常量 base 属性。此外,我们还将主机箱的材质颜色设置为 Cyan 。请注意,我们在 <visual> 标签下设置了这些参数,因此它们将仅作为不影响任何碰撞或物理属性的视觉参数应用。 [校准@songhuangong]

17  <!-- Robot Base -->
18  <link name="base_link">
19    <visual>
20      <geometry>
21        <box size="${base_length} ${base_width} ${base_height}"/>
22      </geometry>
23      <material name="Cyan">
24        <color rgba="0 1.0 1.0 1.0"/>
25      </material>
26    </visual>
27  </link>

接下来,让我们定义一个 base_footprint 链接。 base_footprint 链是一个虚拟 (非物理) 链,没有维度或碰撞区域。其主要目的是使各种组件能够确定投影到地面的机器人的中心。例如,Navigation2使用此链接来确定其避障算法中使用的圆形Footprint的中心。同样,我们将此链接设置为无尺寸,并且将机器人的中心投影到地平面时位于的那个位置。 [校准@songhuangong]

在定义了我们的 base_link 之后,我们添加了一个关节来将它连接到 base_link 。在 URDF 中, joint 元素描述了坐标系之间的运动学和动态特性。对于这种情况,我们将定义一个带有适当偏移量的 fixed 关节,以根据上面的描述将我们的 base_footprint 放置在适当的位置。请记住,当从地盘的中心投影时,我们想将我们的 base_footprint 设置为地平面,因此我们得到了 wheel_radiuswheel_zoff 的总和,以获得沿z轴的适当位置。 [校准@songhuangong]

29  <!-- Robot Footprint -->
30  <link name="base_footprint"/>
31
32  <joint name="base_joint" type="fixed">
33    <parent link="base_link"/>
34    <child link="base_footprint"/>
35    <origin xyz="0.0 0.0 ${-(wheel_radius+wheel_zoff)}" rpy="0 0 0"/>
36  </joint>

现在,我们将为我们的机器人添加两个大驱动轮。为了使我们的代码更简洁并避免重复,我们将使用宏来定义一个代码块,它将通过不同的参数进行重复的定义。我们的宏将有 3 个参数:prefix ,它只是为我们的链接和关节名称添加一个前缀,以及 x_reflecty_reflect ,它们分别相对x 和 y 轴,允许我们翻转轮子的位置 。在这个宏中,我们还可以定义单个轮子的视觉属性。最后,我们还将定义一个 continuous 关节,以允许我们的轮子绕轴自由旋转。这个关节还将我们的轮子连接到适当位置的 base_link[校准@songhuangong]

在此代码块的末尾,我们将使用刚刚通过 xacro:wheel 标签创建的宏来实例化两个轮子。请注意,我们还将参数定义为在机器人后部两侧各有一个轮子。 [校准@songhuangong]

38  <!-- Wheels -->
39  <xacro:macro name="wheel" params="prefix x_reflect y_reflect">
40    <link name="${prefix}_link">
41      <visual>
42        <origin xyz="0 0 0" rpy="${pi/2} 0 0"/>
43        <geometry>
44            <cylinder radius="${wheel_radius}" length="${wheel_width}"/>
45        </geometry>
46        <material name="Gray">
47          <color rgba="0.5 0.5 0.5 1.0"/>
48        </material>
49      </visual>
50    </link>
51
52    <joint name="${prefix}_joint" type="continuous">
53      <parent link="base_link"/>
54      <child link="${prefix}_link"/>
55      <origin xyz="${x_reflect*wheel_xoff} ${y_reflect*(base_width/2+wheel_ygap)} ${-wheel_zoff}" rpy="0 0 0"/>
56      <axis xyz="0 1 0"/>
57    </joint>
58  </xacro:macro>
59
60  <xacro:wheel prefix="drivewhl_l" x_reflect="-1" y_reflect="1" />
61  <xacro:wheel prefix="drivewhl_r" x_reflect="-1" y_reflect="-1" />

接下来,我们将在机器人的前面添加一个脚轮。我们将把这个轮子建模为一个球体以保持简单。同样,我们定义了车轮的几何形状、材料和关节,以便在适当的位置将其连接到 base_link[校准@songhuangong]

63  <!-- Caster Wheel -->
64  <link name="front_caster">
65    <visual>
66      <geometry>
67        <sphere radius="${(wheel_radius+wheel_zoff-(base_height/2))}"/>
68      </geometry>
69      <material name="Cyan">
70        <color rgba="0 1.0 1.0 1.0"/>
71      </material>
72    </visual>
73  </link>
74
75  <joint name="caster_joint" type="fixed">
76    <parent link="base_link"/>
77    <child link="front_caster"/>
78    <origin xyz="${caster_xoff} 0.0 ${-(base_height/2)}" rpy="0 0 0"/>
79  </joint>

就这样!我们为简单的差动驱动机器人构建了 URDF。在下一节中,我们将重点构建包含我们的 URDF 的 ROS 包,启动 robot state publisher ,并在 RVIz 中可视化机器人。 [校准@songhuangong]

Build 和 Launch [校准@songhuangong]

参见

本教程的启动文件改编自官方的 URDF Tutorials for ROS 2 [校准@songhuangong]

让我们通过添加一些依赖项来开始本节,一旦我们构建了这个项目,将需要它。打开您的项目目录的根目录并将以下行添加到您的 package.xml (最好在 <buildtool_depend> 标签之后) [校准@songhuangong]

<exec_depend>joint_state_publisher</exec_depend>
<exec_depend>joint_state_publisher_gui</exec_depend>
<exec_depend>robot_state_publisher</exec_depend>
<exec_depend>rviz</exec_depend>
<exec_depend>xacro</exec_depend>

接下来,让我们创建 launch 文件。 ROS 2 使用 launch 文件来为我们的包启动必要的节点。从项目的根目录创建一个名为 launch``的目录 以及一个名为 ``display.launch.py 文件。下面的启动文件在 ROS 2 中启动了一个 robot publisher 节点,该节点使用我们的 URDF 发布我们机器人的变换。此外,启动文件还会自动启动 RVIZ,因此我们可以按照 URDF 定义来可视化我们的机器人。将下面的代码段复制并粘贴到您的 ``display.launch.py`

import launch
from launch.substitutions import Command, LaunchConfiguration
import launch_ros
import os

def generate_launch_description():
    pkg_share = launch_ros.substitutions.FindPackageShare(package='sam_bot_description').find('sam_bot_description')
    default_model_path = os.path.join(pkg_share, 'src/description/sam_bot_description.urdf')
    default_rviz_config_path = os.path.join(pkg_share, 'rviz/urdf_config.rviz')

    robot_state_publisher_node = launch_ros.actions.Node(
        package='robot_state_publisher',
        executable='robot_state_publisher',
        parameters=[{'robot_description': Command(['xacro ', LaunchConfiguration('model')])}]
    )
    joint_state_publisher_node = launch_ros.actions.Node(
        package='joint_state_publisher',
        executable='joint_state_publisher',
        name='joint_state_publisher',
        condition=launch.conditions.UnlessCondition(LaunchConfiguration('gui'))
    )
    joint_state_publisher_gui_node = launch_ros.actions.Node(
        package='joint_state_publisher_gui',
        executable='joint_state_publisher_gui',
        name='joint_state_publisher_gui',
        condition=launch.conditions.IfCondition(LaunchConfiguration('gui'))
    )
    rviz_node = launch_ros.actions.Node(
        package='rviz2',
        executable='rviz2',
        name='rviz2',
        output='screen',
        arguments=['-d', LaunchConfiguration('rvizconfig')],
    )

    return launch.LaunchDescription([
        launch.actions.DeclareLaunchArgument(name='gui', default_value='True',
                                            description='Flag to enable joint_state_publisher_gui'),
        launch.actions.DeclareLaunchArgument(name='model', default_value=default_model_path,
                                            description='Absolute path to robot urdf file'),
        launch.actions.DeclareLaunchArgument(name='rvizconfig', default_value=default_rviz_config_path,
                                            description='Absolute path to rviz config file'),
        joint_state_publisher_node,
        joint_state_publisher_gui_node,
        robot_state_publisher_node,
        rviz_node
    ])

参见

关于 ROS 2 中启动系统的更多信息,可以查看官方的 ROS 2 Launch System Documentation [校准@songhuangong]

当我们开始可视化时,为了让事情变得更简单,我们提供了一个 RVIz 配置文件,当我们启动我们的包时将加载它。此配置文件使用适当的设置初始化 RVIz,因此您可以在机器人启动后立即查看它。在项目的根目录中创建一个名为 rviz 的目录,并在其下创建一个名为 urdf_config.rviz 的文件。将以下内容作为 urdf_config.rviz 的内容 [校准@songhuangong]

Panels:
  - Class: rviz_common/Displays
    Help Height: 78
    Name: Displays
    Property Tree Widget:
      Expanded:
        - /Global Options1
        - /Status1
        - /RobotModel1/Links1
        - /TF1
      Splitter Ratio: 0.5
    Tree Height: 557
Visualization Manager:
  Class: ""
  Displays:
    - Alpha: 0.5
      Cell Size: 1
      Class: rviz_default_plugins/Grid
      Color: 160; 160; 164
      Enabled: true
      Name: Grid
    - Alpha: 0.6
      Class: rviz_default_plugins/RobotModel
      Description Topic:
        Depth: 5
        Durability Policy: Volatile
        History Policy: Keep Last
        Reliability Policy: Reliable
        Value: /robot_description
      Enabled: true
      Name: RobotModel
      Visual Enabled: true
    - Class: rviz_default_plugins/TF
      Enabled: true
      Name: TF
      Marker Scale: 0.3
      Show Arrows: true
      Show Axes: true
      Show Names: true
  Enabled: true
  Global Options:
    Background Color: 48; 48; 48
    Fixed Frame: base_link
    Frame Rate: 30
  Name: root
  Tools:
    - Class: rviz_default_plugins/Interact
      Hide Inactive Objects: true
    - Class: rviz_default_plugins/MoveCamera
    - Class: rviz_default_plugins/Select
    - Class: rviz_default_plugins/FocusCamera
    - Class: rviz_default_plugins/Measure
      Line color: 128; 128; 0
  Transformation:
    Current:
      Class: rviz_default_plugins/TF
  Value: true
  Views:
    Current:
      Class: rviz_default_plugins/Orbit
      Name: Current View
      Target Frame: <Fixed Frame>
      Value: Orbit (rviz)
    Saved: ~

最后,让我们修改项目根目录中的 CMakeLists.txt 文件,以包含我们刚刚在包安装过程中创建的文件。将以下代码段添加到 CMakeLists.txt 文件中,最好在 if(BUILD_TESTING) 行上方: [校准@songhuangong]

install(
  DIRECTORY src launch rviz
  DESTINATION share/${PROJECT_NAME}
)

我们现在准备使用 colcon 构建我们的项目。导航到项目根目录并执行以下命令。 [校准@songhuangong]

colcon build
. install/setup.bash

构建成功后,执行以下命令安装 ROS 2 包并启动我们的项目。 [校准@songhuangong]

ros2 launch sam_bot_description display.launch.py

ROS 2 现在应该启动机器人发布者节点并使用我们的 URDF 启动 RVIZ。我们将在下一节中使用 RVIZ 来看看我们的机器人。 [校准@songhuangong]

使用 RVIZ 可视化 [校准@songhuangong]

RVIZ 是一个机器人可视化工具,它允许我们使用其 URDF 查看机器人的 3D 模型。使用上一节中的命令成功启动后,RVIZ 现在应该在您的屏幕上可见,并且应该如下图所示。您可能需要四处走动并操纵视图以更好地了解您的机器人。 [校准@songhuangong]

../../_images/base-bot_3.png

如您所见,我们已经成功创建了一个简单的差动驱动机器人,并在 RVIz 中对其进行了可视化。没有必要在 RVIz 中可视化您的机器人,但这是一个很好的步骤,可以查看您是否正确定义了 URDF。这有助于确定 robot state publisher 发布是正确的转换。 [校准@songhuangong]

您可能已经注意到启动的另一个窗口 - 这是 joint state publisher 的 GUI。 joint state publisher 是另一个 ROS 2 包,它为我们的非固定关节发布状态。您可以通过小 GUI 操作此发布者,关节的新姿势将反映在 RVIz 中。滑动两个轮子中的任何一个的杆都会旋转这些关节。当您在 Joint State Publisher GUI 中扫动滑块时,您可以通过查看 RVIZ 来了解这一点。 [校准@songhuangong]

../../_images/base-bot_4.png

备注

我们不会与 Nav2 的这个包进行太多互动,但如果您想了解更多关于联合国家发布者的信息,请随时查看官方的 Joint State Publisher Documentation[校准@songhuangong]

此时,您可能已经决定停止学习本教程,因为我们已经实现了为简单的差动驱动机器人创建 URDF 的目标。robot state publisher 现在正在发布源自URDF的转换。现在,其他包(例如 Nav2)可以使用这些转换来获取有关机器人形状和结构的信息。但是,要在模拟中正确使用此 URDF,我们需要物理属性,以便机器人像真实机器人一样对物理环境做出反应。可视化字段仅用于可视化,不用于碰撞,因此您的机器人将直接穿过障碍物。我们将在下一节中将这些属性添加到我们的 URDF 中。 [校准@songhuangong]

添加物理属性 [待校准@1951]

作为本指南的附加部分,我们将修改当前的 URDF 以包含我们机器人的一些运动学属性。 Gazebo 等物理模拟器可以使用此信息来建模和模拟我们的机器人在虚拟环境中的行为方式。 [校准@songhuangong]

让我们首先定义包含我们在项目中使用的几何图元的惯性属性的宏。将下面的代码片段放在 URDF 中的常量部分之后: [校准@songhuangong]

17  <!-- Define intertial property macros  -->
18  <xacro:macro name="box_inertia" params="m w h d">
19    <inertial>
20      <origin xyz="0 0 0" rpy="${pi/2} 0 ${pi/2}"/>
21      <mass value="${m}"/>
22      <inertia ixx="${(m/12) * (h*h + d*d)}" ixy="0.0" ixz="0.0" iyy="${(m/12) * (w*w + d*d)}" iyz="0.0" izz="${(m/12) * (w*w + h*h)}"/>
23    </inertial>
24  </xacro:macro>
25
26  <xacro:macro name="cylinder_inertia" params="m r h">
27    <inertial>
28      <origin xyz="0 0 0" rpy="${pi/2} 0 0" />
29      <mass value="${m}"/>
30      <inertia ixx="${(m/12) * (3*r*r + h*h)}" ixy = "0" ixz = "0" iyy="${(m/12) * (3*r*r + h*h)}" iyz = "0" izz="${(m/2) * (r*r)}"/>
31    </inertial>
32  </xacro:macro>
33
34  <xacro:macro name="sphere_inertia" params="m r">
35    <inertial>
36      <mass value="${m}"/>
37      <inertia ixx="${(2/5) * m * (r*r)}" ixy="0.0" ixz="0.0" iyy="${(2/5) * m * (r*r)}" iyz="0.0" izz="${(2/5) * m * (r*r)}"/>
38    </inertial>
39  </xacro:macro>

让我们先使用 <collision> 标签在我们的 base_link 上增加碰撞区域。我们还将使用我们之前定义的box_inertia宏为我们的 base_link 添加一些惯性特性。在我们的URDF中,在 base_link 的``<link name="base_link">`` 标签中包含以下代码片段。 [校准@songhuangong]

52    <collision>
53      <geometry>
54        <box size="${base_length} ${base_width} ${base_height}"/>
55      </geometry>
56    </collision>
57
58    <xacro:box_inertia m="15" w="${base_width}" d="${base_length}" h="${base_height}"/>

接下来,让我们对车轮宏执行相同的操作。在 URDF 中车轮宏的 <link name="${prefix}_link"> 标签中包含以下代码片段。 [校准@songhuangong]

83      <collision>
84        <origin xyz="0 0 0" rpy="${pi/2} 0 0"/>
85        <geometry>
86          <cylinder radius="${wheel_radius}" length="${wheel_width}"/>
87        </geometry>
88      </collision>
89
90      <xacro:cylinder_inertia m="0.5" r="${wheel_radius}" h="${wheel_width}"/>

最后,让我们将类似的属性添加到我们的球形脚轮中。在 URDF 中,我们的脚轮标签中 <link name="front_caster"> 包含以下内容。 [校准@songhuangong]

114    <collision>
115      <origin xyz="0 0 0" rpy="0 0 0"/>
116      <geometry>
117        <sphere radius="${(wheel_radius+wheel_zoff-(base_height/2))}"/>
118      </geometry>
119    </collision>
120
121    <xacro:sphere_inertia m="0.5" r="${(wheel_radius+wheel_zoff-(base_height/2))}"/>

备注

我们没有向我们的 base_footprint 链接添加任何惯性或碰撞属性,因为它一个虚拟和非物理链接。 [校准@songhuangong]

构建您的项目,然后使用上一节中的相同命令启动 RViz。 [校准@songhuangong]

colcon build
. install/setup.bash
ros2 launch sam_bot_description display.launch.py

您可以通过在左侧窗格的 RobotModel 下启用 Collision Enabled 来验证您是否正确设置了碰撞区域(如果您关闭了 Visual Enabled 可能更容易看出来)。在本教程中,我们定义了一个类似于我们的视觉属性的碰撞区域。请注意,情况可能并非总是如此,因为您可能会根据机器人的外观选择更简单的碰撞区域。 [校准@songhuangong]

../../_images/base-bot_5.png

现在,我们将不得不在这里停下来,因为我们需要设置更多组件才能真正开始在 Gazebo 中模拟我们的机器人。在这些设置指南的过程中,我们将回到这个项目,一旦我们进入模拟部分,我们最终将看到我们的机器人在虚拟环境中移动。这项工作缺少的主要组件是模拟机器人控制器所需的模拟插件。我们将在适当的部分介绍这些并将它们添加到此 URDF。 [校准@songhuangong]

小结 [校准@songhuangong]

就是这样。在本教程中,您已成功为简单的差动驱动机器人创建了 URDF。您还设置了启动 robot publisher 节点的 ROS 2 项目,然后使用您的 URDF 发布机器人的变换。我们还使用 RViz 来可视化我们的机器人,以验证我们的 URDF 是否正确。最后,我们在 URDF 中添加了一些物理属性,以便为模拟做准备。 [校准@songhuangong]

请随意使用本教程作为您自己的机器人的模板。请记住,您的主要目标是发布从 base_linksensor_frames 的正确转换。设置完成后,您可以继续阅读我们的其他设置指南。 [校准@songhuangong]