4. 使用Xacro整理URDF文件

目标:学习使用Xacro减少URDF文件中代码量的一些技巧

教程级别:入门

到目前为止,如果您在家里将前几个教程中的所有这些步骤应用到您自己的机器人设计上,则您可能已经厌倦了进行各种数学运算来获得可以正确解析的非常简单的机器人描述。幸运的是,您可以使用xacro软件包以使您的机器人设计工作更加简单。该软件包可以做下列三件非常有用的事情:

 常量

● 简单的数学计算

● 宏

在本教程中,将会了解所有这些快捷功能以帮助减小URDF文件的整体大小,并使URDF文件更易于阅读和维护。

4.1 使用Xacro

顾名思义,xacro是一种用于XML的宏语言。xacro程序会运行所有的宏并输出结果。Xacro的典型用法如下所示:

xacro model.xacro > model.urdf

也可以在一个启动文件中自动生成urdf。这很方便,因为这样可以保持最新状态并且不会占用硬盘空间。但是,生成urdf确实需要花费时间,因此请注意您的启动文件可能会需要更长时间才能启动。

path_to_urdf = get_package_share_path('pr2_description') / 'robots' / 'pr2.urdf.xacro'
robot_state_publisher_node = launch_ros.actions.Node(
    package='robot_state_publisher',
    executable='robot_state_publisher',
    parameters=[{
        'robot_description': ParameterValue(
            Command(['xacro ', str(path_to_urdf)]), value_type=str
        )
    }]
)

在URDF文件的最前面必须指定一个命名空间,以便正确解析该文件。例如,下面的示例代码是有效xacro文件的前两行代码:

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="firefighter">

4.2 常量

下面来快速浏览一下R2D2机器人模型中的base_link

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

这里的信息有点冗余。在该代码中两次指定了圆柱体的长度和半径。更糟糕的是,如果想改变圆柱体的尺寸,需要在两个不同的地方进行修改。

幸运的是,xacro允许您指定充当常量的属性。可以用以下代码来代替上面的代码:

<xacro:property name="width" value="0.2" />
<xacro:property name="bodylen" value="0.6" />
<link name="base_link">
    <visual>
        <geometry>
            <cylinder radius="${width}" length="${bodylen}"/>
        </geometry>
        <material name="blue"/>
    </visual>
    <collision>
        <geometry>
            <cylinder radius="${width}" length="${bodylen}"/>
        </geometry>
    </collision>
</link>

● 这两个值在前两行中指定。但其实它们几乎可以在任何地方(假设是有效的XML)、任何层级、使用之前或使用之后定义。通常会在最前面定义。

● 在这段代码中没有在几何体(geometry)元素中指定实际的半径值,而是使用美元符号$和大括号{}来表示该值。

● 这段代码会生成与前面那段代码相同的代码。

这样就会用${}结构的内容值来替换${}。这意味着可以将其与属性中的其它文本进行组合:

<xacro:property name=”robotname” value=”marvin” />
<link name=”${robotname}s_leg” />

这会生成以下代码:

<link name=”marvins_leg” />

然而,${}结构中的内容不必只是一个属性,我们会在下一小节中对此进行展示。

4.3 数学计算

可以使用四个基本运算符(+、-、*、/)、一元减操作符和括号在${}结构内构建任意复杂的表达式。例如:

<cylinder radius="${wheeldiam/2}" length="0.1"/>
<origin xyz="${reflect*(width+.02)} 0 0.25" />

您还可以使用基本数学运算符之外的其它运算符,如sin和cos。

4.4 宏(Macros)

宏是xacro软件包中最大和最有用的组成部分。

4.4.1 简单宏

下面来看一个简单的无用宏:

<xacro:macro name="default_origin">
    <origin xyz="0 0 0" rpy="0 0 0"/>
</xacro:macro>
<xacro:default_origin />

(这个宏是无用的,因为如果不指定该原点,其值也是一样的。)此代码将会生成以下代码:

<origin rpy="0 0 0" xyz="0 0 0"/>

● 从技术上来说宏的名称并不是必需的元素,但需要指定宏名才能使用该宏。

● <xacro:$NAME /> 的每个实例都会被替换为xacro:macro标签的具体内容。

● 请注意,即使该原点的内容不完全相同(已切换了xyz和rpy这两个属性的顺序),但生成的XML也是等效的。

● 如果没有找到具有指定名称的xacro,则该宏不会被展开并且也不会生成错误消息。

4.4.2 参数化宏

您还可以参数化宏,以便这些宏不会每次都生成完全相同的文本。 当与数学计算功能进行组合时,其表达能力将会更加强大。

首先来举一个在R2D2机器人模型中使用的简单宏的示例:

<xacro:macro name="default_inertial" params="mass">
    <inertial>
            <mass value="${mass}" />
            <inertia ixx="1.0" ixy="0.0" ixz="0.0"
                 iyy="1.0" iyz="0.0"
                 izz="1.0" />
    </inertial>
</xacro:macro>

可以用下面这行代码来使用上面这段代码:

<xacro:default_inertial mass="10"/>

参数就像属性一样,可以在表达式中使用它们。

也可以使用整个块作为参数:

<xacro:macro name="blue_shape" params="name *shape">
    <link name="${name}">
        <visual>
            <geometry>
                <xacro:insert_block name="shape" />
            </geometry>
            <material name="blue"/>
        </visual>
        <collision>
            <geometry>
                <xacro:insert_block name="shape" />
            </geometry>
        </collision>
    </link>
</xacro:macro>

<xacro:blue_shape name="base_link">
    <cylinder radius=".42" length=".01" />
</xacro:blue_shape>

● 要指定一个块参数,请在其参数名称前包含一个*号。

● 可以使用insert_block命令来插入一个块。

● 可以根据需要多次插入该块。

4.5 实际使用

xacro语言在允许用户执行的操作方面相当灵活。除了上面显示的默认惯性宏之外,这里还有一些在R2D2机器人模型中使用xacro的有用方法。

要查看由xacro文件生成的模型,请运行与之前教程相同的命令:

ros2 launch urdf_tutorial display.launch.py model:=urdf/08-macroed.urdf.xacro

(该启动文件一直在运行xacro命令,但由于没有宏可以展开,所以没有关系)

4.5.1 腿部的宏

通常您会希望在不同位置创建多个外观相似的物体。可以使用宏和一些简单的数学运算来减少必须编写的代码量,就像下面对R2机器人的两条腿所做的那样:

<xacro:macro name="leg" params="prefix reflect">
    <link name="${prefix}_leg">
        <visual>
            <geometry>
                <box size="${leglen} 0.1 0.2"/>
            </geometry>
            <origin xyz="0 0 -${leglen/2}" rpy="0 ${pi/2} 0"/>
            <material name="white"/>
        </visual>
        <collision>
            <geometry>
                <box size="${leglen} 0.1 0.2"/>
            </geometry>
            <origin xyz="0 0 -${leglen/2}" rpy="0 ${pi/2} 0"/>
        </collision>
        <xacro:default_inertial mass="10"/>
    </link>

    <joint name="base_to_${prefix}_leg" type="fixed">
        <parent link="base_link"/>
        <child link="${prefix}_leg"/>
        <origin xyz="0 ${reflect*(width+.02)} 0.25" />
    </joint>
    <!-- A bunch of stuff cut -->
</xacro:macro>
<xacro:leg prefix="right" reflect="1" />
<xacro:leg prefix="left" reflect="-1" />

● 常见技巧1:使用名称前缀来定义获得两个名称相似的物体。

● 常见技巧2:使用数学来计算关节的原点。在可能会改变机器人尺寸的情况下,改变一个用某种数学运算来计算关节偏移量的属性会省去很多麻烦。

● 常见技巧3:使用一个反射(reflect)参数,并将其设置为1或-1。仔细查看在本示例中是如何使用反射参数以base_to_${prefix}_leg原点将腿放在身体两侧的。

英语原文地址:docs.ros.org/en/galacti