< >
Home » ROS2与Navigation2入门教程 » ROS2与Navigation2入门教程-设置URDF

ROS2与Navigation2入门教程-设置URDF

说明:

  • 介绍如何使用URDF,为该机器人的URDF添加运动学属性
  • 本教程中的完整源代码可以在navigation2_tutorials存储库中的sam_bot_description软件包下找到。
  • 请注意,该存储库包含完成本指南中所有教程后的完整源代码。

URDF和机器人状态发布者(Robot State Publisher)软件包

  • 正如上一教程中所述,Navigation2的要求之一就是从base_link坐标系到各种传感器坐标系和参考坐标系的坐标变换。这个坐标变换树的范围可以是一棵简单的树,从base_link到laser_link只有一个链接,也可以是由位于不同位置上的多个传感器组成的树,每个传感器都有其自己的坐标系。创建多个发布者节点来处理所有这些坐标系变换可能会变得乏味。因此可以使用Robot State Publisher软件包来发布这些坐标变换。

  • Robot State Publisher是一个ROS 2软件包,该软件包会与tf2软件包进行交互以发布所有必要的坐标变换,这些坐标变换可以直接从机器人的几何形状和结构中推导出来。需要为该软件包提供正确的URDF文件,这样就会自动处理这些坐标变换的发布。这对于复杂的坐标变换非常有用,但仍然建议使用更简单的坐标变换树。

  • URDF是一种表示机器人模型的XML文件。本教程中URDF主要用于构建与机器人几何体相关的坐标变换树,但URDF还有很多其他用途。一个示例就是URFD如何通过定义材质和网格等视觉组件,在RVIZ(一款用于ROS的3D可视化工具软件)中可视化机器人模型。另一个示例就是如何使用URDF来定义机器人的物理属性。然后将这些物理属性用于物理仿真程序(例如Gazebo),以仿真机器人如何在环境中进行交互。

  • URDF的另一个主要特性就是它还支持Xacro(XML宏),以帮助用户创建更短且可读的XML文件来帮助定义复杂机器人。可以使用这些宏来消除在URDF中重复一些XML块的需求。Xacro还可用于定义能在整个URDF中重复使用的配置常量。

设置环境

  • 本指南假设您已经熟悉ROS 2以及如何设置您的开发环境,因此可以轻松地完成本节中的各个步骤。

  • 首先来安装本教程中将会使用的一些其它ROS 2软件包。命令为:

sudo apt install ros-<ros2-distro>-joint-state-publisher-gui
sudo apt install ros-<ros2-distro>-xacro
  • 接下来,为您的项目创建一个目录,初始化一个ROS2工作空间并为您的机器人命名。
  • 对于我们的机器人,我们把它叫做sam_bot。
ros2 pkg create --build-type ament_cmake sam_bot_description

编写URDF

  • 现在已经设置好了项目的工作空间,下面可以直接开始编写URDF。后面将要尝试构建的机器人其图像如下图所示:

请输入图片描述
请输入图片描述

  • 首先在src/description目录创建一个名为sam_bot_description.urdf的文件,并输入以下内容作为该文件的初始内容:
<?xml version="1.0"?>
<robot name="sam_bot"     xmlns:xacro="http://ros.org/wiki/xacro">

</robot>
  • *注:下面的代码段应放在标签内。建议按照本教程中介绍的相同顺序添加它们。
  • 这里还包含了一些行号,以让您大致了解在何处输入该代码。
  • 这可能与您正在编写的实际文件不同,具体取决于您对空格的使用。
  • 另请注意,行号假定您正在输入的代码与本指南中显示的代码相同。
  • 接下来,使用XAcro属性定义一些将在整个URDF中重复使用的常量。
  • 代码如下所示:
  <!-- Define robot constants -->
  <xacro:property name="base_width" value="0.31"/>
  <xacro:property name="base_length" value="0.42"/>
  <xacro:property name="base_height" value="0.18"/>

  <xacro:property name="wheel_radius" value="0.10"/>
  <xacro:property name="wheel_width" value="0.04"/>
  <xacro:property name="wheel_ygap" value="0.025"/>
  <xacro:property name="wheel_zoff" value="0.05"/>
  <xacro:property name="wheel_xoff" value="0.12"/>

  <xacro:property name="caster_xoff" value="0.14"/>
  • 这里简要说明一下这些属性在urdf中代表什么。属性base_*都是用来定义机器人主机架或底盘尺寸的。属性wheel_radius和wheel_width定义机器人两个后轮的形状(半径和厚度)。属性wheel_ygap定义沿y轴调整车轮和底盘之间的间距,而属性wheel_zoff和wheel_xoff则定义沿z轴和x 轴正确地定位后轮。最后,属性caster_xoff定义沿x轴定位前脚轮。

  • 然后来定义base_link,这个链接是一个大的方盒,将作为机器人的主底盘。在URDF中,link元素用于描述机器人的刚性部件或组件。这样机器人状态发布者软件包就可以利用这些定义来确定每个链接的坐标系并发布它们之间的坐标变换。

  • 这里还会定义该链接的一些视觉属性,Gazebo和Rviz等工具可以使用这些视觉属性向我们展示机器人的3D模型。在这些属性中,用于描述该链接的形状,而则描述其颜色。

  • 下面的代码块中使用${property}语法从之前定义的机器人常量代码块访问base属性。此外,还将主底盘的材质颜色设置为Cyan(青色)。请注意,在标签下设置了以下这些参数,这样它们将仅用作视觉参数,而不会影响任何碰撞或物理属性。

   <!-- Robot Base -->
  <link name="base_link">
    <visual>
      <geometry>
        <box size="${base_length} ${base_width}     ${base_height}"/>
      </geometry>
      <material name="Cyan">
        <color rgba="0 1.0 1.0 1.0"/>
      </material>
    </visual>
  </link>
  • 接下来会定义一个base_footprint链接。链接base_footprint是一个没有尺寸或碰撞区域的虚拟(非物理)链接。其主要目的是使各种软件包确定机器人投影到地面的中心。例如,Navigation2使用此链接来确定其避障算法中使用的圆形足迹的中心。同样,这里将该链接设置为没有尺寸,并设置机器人投影到地平面时机器人中心所在的位置。

  • 在定义base_link后,又会添加一个连接到base_link的关节。在 URDF中,joint元素可用于描述坐标系之间的运动学和动力学属性。本示例中会定义一个具有适当偏移量的fixed(固定类型)关节,以根据上述描述将base_footprint链接放置在正确的位置。请记住,当从主底盘中心投影时,我们希望将base_footprint设置在地平面上,这样会得到wheel_radius和wheel_zoff的总和,以获得z轴上的正确位置。

   <!-- Robot Footprint -->
  <link name="base_footprint"/>

  <joint name="base_joint" type="fixed">
    <parent link="base_link"/>
    <child link="base_footprint"/>
    <origin xyz="0.0 0.0 ${-(wheel_radius+wheel_zoff)}" rpy="0 0 0"/>
  </joint>
  • 现在要为机器人添加两个大的驱动轮。为了使代码更加清晰并避免重复,这里会使用宏来定义一个代码块,该代码块将使用不同的参数进行重复。这里宏会有3个参数:prefix只是为链接和关节名称添加前缀,而x_reflect和y_reflect允许分别相对于x和y轴翻转车轮的位置。在这个宏中,还可以定义单个车轮的视觉属性。最后,还会定义一个continuous(连续类型)的关节,以允许车轮绕某个轴自由旋转。 这个关节还会将车轮在适当位置连接到base_link上。

  • 在此代码块的末尾,会使用刚刚通过xacro:wheel标签创建的宏实例化两个车轮。

  • 请注意,还会定义一些参数以使机器人尾部两侧各有一个车轮。

   <!-- Wheels -->
  <xacro:macro name="wheel" params="prefix x_reflect y_reflect">
    <link name="${prefix}_link">
      <visual>
        <origin xyz="0 0 0" rpy="${pi/2} 0 0"/>
        <geometry>
            <cylinder radius="${wheel_radius}" length="${wheel_width}"/>
        </geometry>
        <material name="Gray">
          <color rgba="0.5 0.5 0.5 1.0"/>
        </material>
      </visual>
    </link>

    <joint name="${prefix}_joint" type="continuous">
      <parent link="base_link"/>
      <child link="${prefix}_link"/>
      <origin xyz="${x_reflect*wheel_xoff} ${y_reflect*(base_width/2+wheel_ygap)} ${-wheel_zoff}" rpy="0 0 0"/>
      <axis xyz="0 1 0"/>
    </joint>
  </xacro:macro>

  <xacro:wheel prefix="drivewhl_l" x_reflect="-1" y_reflect="1" />
  <xacro:wheel prefix="drivewhl_r" x_reflect="-1" y_reflect="-1" />
  • 接下来,会在机器人前面添加一个脚轮。这里会把这个车轮建模为一个球体以保持简单。同样也会定义该脚轮的几何形状、材质和关节以将其在适当位置连接到base_link。
  <!-- Caster Wheel -->
  <link name="front_caster">
    <visual>
      <geometry>
        <sphere radius="${(wheel_radius+wheel_zoff-(base_height/2))}"/>
      </geometry>
      <material name="Cyan">
        <color rgba="0 1.0 1.0 1.0"/>
      </material>
    </visual>
  </link>

  <joint name="caster_joint" type="fixed">
    <parent link="base_link"/>
    <child link="front_caster"/>
    <origin xyz="${caster_xoff} 0.0 ${-(base_height/2)}" rpy="0 0 0"/>
  • 就是这样!为一个简单差分驱动机器人构建好了一个URDF。
  • 下一节中会重点关注构建包含该URDF的ROS软件包、启动机器人状态发布者以及在RVIz中可视化该机器人。

构建和启动

  • 本节首先会添加构建这个项目时所需的一些依赖包。
  • 打开本项目的根目录,并将以下行添加到package.xml文件中(最好添加在 <buildtool_depend>标签之后):
<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>
  • 然后来创建启动文件。ROS 2使用启动文件来启动软件包中的必要节点。在本项目的根目录下,创建一个名为launch的子目录,并在该子目录中创建一个display.launch.py文件。下面这个启动文件会启动ROS 2中的一个机器人发布者节点,该节点使用上面编写的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
])
  • 为了在进行可视化时让事情变得更加简单,这里会提供一个RVIz 配置文件,在启动软件包时会加载该配置文件。这个配置文件使用适当的设置初始化RVIz,以便可以在机器人启动后立即查看该机器人。在本项目根目录下创建一个名为rviz的子目录,并在该子目录中创建一个名为urdf_config.rviz的文件。

  • 将以下代码段复制粘贴到urdf_config.rviz文件中:

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) 这一行上面:

install(
DIRECTORY src launch rviz
DESTINATION share/${PROJECT_NAME}
)
  • 现在可以用colcon构建该项目。进入项目根目录并执行以下命令:
colcon build
. install/setup.bash
  • 构建成功后,执行以下命令来安装该ROS 2软件包并启动该项目:
ros2 launch sam_bot_description display.launch.py
  • 现在ROS 2应该会启动一个机器人发布者节点并使用上面编写的URDF启动RVIZ。
  • 下一节中将会使用RVIZ来查看该机器人

使用RVIZ进行可视化

  • RVIZ是一款机器人可视化工具软件,允许用户使用URDF查看机器人的3D模型。使用上一节中的命令成功启动后,RVIZ现在应该在您的计算机屏幕上可见,并且看起来应该如下图所示。可能需要四处移动并操纵视图以仔细查看您的机器人

请输入图片描述

  • 如您所见,已经成功创建了一个简单的差分驱动机器人并在RVIz中对其进行了可视化。并非必须在RVIz中可视化您的机器人,但这是一个好的步骤以查看是否正确定义了机器人的URDF。这有助于确保机器人状态发布者正在发布正确的坐标变换。

  • 您可能已经注意到还启动了另一个窗口——这是关节状态发布者的GUI。关节状态发布者是另一个ROS 2软件包,用于发布非固定类型关节的状态。可以通过该小的GUI操作该发布者,而且关节的新位姿将会反映在RVIz中。滑动两个车轮中任何一个的滑动条都会旋转这些关节。当在关节状态发布者(Joint State Publisher)GUI中滑动滑块时,可以通过浏览RVIZ来看到关节正在旋转。

请输入图片描述

  • 至此,由于已经实现了为简单的差分驱动机器人创建URDF这一目标,您可能已决定停止继续学习本教程。机器人状态发布者现在正在发布派生自URDF的坐标变换。现在,其他软件包(例如Nav2)可以使用这些坐标变换来获取有关机器人形状和结构的信息。但是,为了在仿真中正确使用这个URDF,还需要一些物理属性以便机器人像真实机器人一样对物理环境做出反应。可视化字段只能用于可视化,而不能用于碰撞,因此您的机器人会直接穿过障碍物。下一节中会将这些物理属性添加到该URDF中。

添加物理属性

  • 作为本指南的附加部分,这一节中会修改当前的URDF以包含机器人的一些运动学属性。这些信息可能会被诸如Gazebo等物理仿真程序用于对机器人在虚拟环境中的行为方式进行建模和仿真。

  • 首先来定义一些宏,这些宏包含本项目中要使用的几何图元(geometric primitives)的惯性属性。

  • 将下面的代码段放置在URDF中的常量部分之后:

   <!-- Define intertial property macros  -->
  <xacro:macro name="box_inertia" params="m w h d">
    <inertial>
      <origin xyz="0 0 0" rpy="${pi/2} 0 ${pi/2}"/>
      <mass value="${m}"/>
      <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)}"/>
    </inertial>
  </xacro:macro>

  <xacro:macro name="cylinder_inertia" params="m r h">
    <inertial>
      <origin xyz="0 0 0" rpy="${pi/2} 0 0" />
      <mass value="${m}"/>
      <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)}"/>
    </inertial>
  </xacro:macro>

  <xacro:macro name="sphere_inertia" params="m r">
    <inertial>
      <mass value="${m}"/>
      <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)}"/>
    </inertial>
  </xacro:macro>
  • 首先会使用标签向base_link添加碰撞区域。还会使用前面定义的box_inertia宏为base_link添加一些惯性属性。

  • 将以下代码段复制放入URDF中base_link的标签内:

    <collision>
      <geometry>
        <box size="${base_length} ${base_width} ${base_height}"/>
      </geometry>
    </collision>

    <xacro:box_inertia m="15" w="${base_width}" d="${base_length}" h="${base_height}"/>
  • 接着对车轮宏执行相同的操作。将以下代码段复制放入URDF中车轮宏的标签内:
   <collision>
        <origin xyz="0 0 0" rpy="${pi/2} 0 0"/>
        <geometry>
          <cylinder radius="${wheel_radius}" length="${wheel_width}"/>
        </geometry>
      </collision>

      <xacro:cylinder_inertia m="0.5" r="${wheel_radius}" h="${wheel_width}"/>
  • 最后来为球形脚轮添加类似的属性。
  • 将以下代码段复制放入URDF中脚轮的标签内:
    <collision>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <geometry>
        <sphere radius="${(wheel_radius+wheel_zoff-(base_height/2))}"/>
      </geometry>
    </collision>

    <xacro:sphere_inertia m="0.5" r="${(wheel_radius+wheel_zoff-(base_height/2))}"/>
  • *注:这里没有向base_footprint链接添加任何惯性或碰撞属性,这是因为它是一个虚拟和非物理的链接。

  • 构建该项目,然后使用上一节中的相同命令启动RViz。

  • 命令为:

colcon build
. install/setup.bash
ros2 launch sam_bot_description display.launch.py
  • 可以通过在RVIZ左面板中的RobotModel下启用Collision Enabled来验证是否正确设置了碰撞区域(如果还将Visual Enabled关闭掉可能会更容易查看)。

  • 本教程中定义了一个与视觉属性相似的碰撞区域。

  • 请注意,情况可能并非总是如此,因为可能会根据机器人的外观选择更简单的碰撞区域。

请输入图片描述

  • 现在将不得不在这里停住,因为需要设置更多组件才能在Gazebo中实际开始对该机器人进行仿真。后面会在这些软件包的设置指南课程中回到这个项目,而且一旦进入仿真章节,就会最终看到该机器人在虚拟环境中移动。这项工作中缺少的主要组件是仿真机器人控制器所需的仿真插件。在后续相关章节中会介绍这些插件并将它们添加到这个URDF中。

结束语

  • 本教程中已成功为简单的差分驱动机器人创建了URDF。

  • 还设置了一个ROS 2项目,用于启动机器人发布者节点,然后使用该URDF发布了机器人的坐标变换。

  • 本教程还使用RViz来可视化该机器人,以验证该URDF是否正确。

  • 最后,在URDF中添加了一些物理属性,以便为机器人仿真做好准备。

  • 请随意使用本教程作为您自己的机器人模板。请记住,您的主要目标是发布从base_link到sensor_frames的正确坐标变换。完成这些设置后,可以继续阅读其他设置指南。

参考:

  • https://navigation.ros.org/setup_guides/urdf/setup_urdf.html

纠错,疑问,交流: 请进入讨论区点击加入Q群

获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号


标签: ros2与navigation2入门教程