使用Xacro清理URDF文件 [待校准@9075]
Goal目标: Learn学习一些技巧,使用Xacro减少URDF文件中的代码量 [待校准@9076]
教程级别: 初学者 [Alyssa@7088]
到目前为止,如果你在家里用自己的机器人设计来完成所有这些步骤,你可能会厌倦做各种各样的数学运算来获得非常简单的机器人描述来正确解析。幸运的是,你可以使用 xacro 包装让你的生活更简单。它做了三件非常有帮助的事情。 [待校准@9077]
常数 [待校准@9078]
简单数学 [待校准@9079]
在本教程中,我们将介绍所有这些快捷方式,以帮助减小URDF文件的整体大小并使其更易于阅读和维护。 [待校准@9081]
内容
使用Xacro [待校准@9082]
顾名思义, xacro 是XML的宏语言。xacro程序运行所有宏并输出结果。典型用法如下所示: [待校准@9083]
xacro model.xacro > model.urdf
您还可以自动调用y在launch文件中生成urdf。这很方便,因为它保持最新,不会占用硬盘空间。但是,生成它确实需要时间,因此请注意,您的launch文件可能需要更长的时间才能启动。 [待校准@9084]
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文件的前两行: [待校准@9085]
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="firefighter">
常数 [待校准@9078]
让我们快速看一下R2D2中的base_link。 [待校准@9086]
<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>
这里的信息有点多余。我们两次指定圆柱体的长度和半径。更糟糕的是,如果我们想改变这一点,我们需要在两个不同的地方这样做。 [待校准@9087]
幸运的是,xacro允许您指定充当常量的属性。相反,我们可以编写上面的代码。 [待校准@9088]
<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) 、任何级别、在它们被使用之前或之后被定义。通常他们在顶端。 [待校准@9089]
我们使用美元符号和花括号来表示值,而不是在几何元素中指定实际半径。 [待校准@9090]
该代码将生成与上面所示相同的代码。 [待校准@9091]
然后使用 ${} 构造的内容的值替换 ${}。这意味着您可以将其与属性中的其他文本组合。 [待校准@9092]
<xacro:property name=”robotname” value=”marvin” />
<link name=”${robotname}s_leg” />
这将产生 [待校准@9093]
<link name=”marvins_leg” />
然而,${} 中的内容不一定只是一个属性,这将我们带到了下一个要点... [待校准@9094]
数学 [待校准@9095]
您可以使用四个基本操作 (+,-,*,/) 、一元减号和括号在 ${} 构造中构建任意复杂表达式。示例: [待校准@9096]
<cylinder radius="${wheeldiam/2}" length="0.1"/>
<origin xyz="${reflect*(width+.02)} 0 0.25" />
你也可以使用更多的基本数学运算,如 sin
和 cos
。 [待校准@9097]
宏 [待校准@9080]
这是xacro包最大、最有用的组件。 [待校准@9098]
简单宏 [待校准@9099]
让我们来看看一个简单的无用宏。 [待校准@9100]
<xacro:macro name="default_origin">
<origin xyz="0 0 0" rpy="0 0 0"/>
</xacro:macro>
<xacro:default_origin />
(这是没有用的,因为如果未指定原点,则它具有与此相同的值。)此代码将生成以下内容。 [待校准@9101]
<origin rpy="0 0 0" xyz="0 0 0"/>
该名称不是techni调用y必需元素,但您需要指定它才能使用它。 [待校准@9102]
“<xacro:$ NAME /> `` is replaced with the contents of the `` xacro: macro” 标签的每个实例。 [待校准@9103]
请注意,即使它不完全相同 (两个属性已切换顺序),生成的XML也是等效的。 [待校准@9104]
如果找不到具有指定名称的xacro,它将不会被扩展,也不会生成错误。 [待校准@9105]
参数化宏 [待校准@9106]
您还可以参数化宏,使它们不会每次都生成相同的文本。当与数学功能相结合时,这甚至更加强大。 [待校准@9107]
首先,让我们以R2D2中使用的简单宏为例。 [待校准@9108]
<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>
这可以与代码一起使用 [待校准@9109]
<xacro:default_inertial mass="10"/>
参数就像属性一样,您可以在表达式中使用它们 [待校准@9110]
您也可以使用整个块作为参数。 [待校准@9111]
<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>
要指定块参数,请在其参数名称前包含星号。 [待校准@9112]
可以使用insert_block命令插入块 [待校准@9113]
任意多次插入块。 [待校准@9114]
实用 [待校准@9115]
xacro语言在允许你做的事情上相当灵活。除了上面显示的默认惯性宏之外,这里还有一些在 R2D2 model 中使用xacro的有用方法。 [待校准@9116]
要查看xacro文件生成的模型,请运行与前面教程相同的命令: [待校准@9117]
ros2 launch urdf_tutorial display.launch.py model:=urdf/08-macroed.urdf.xacro
(launch文件一直在运行xacro命令,但是由于没有要扩展的宏,所以没关系) [待校准@9118]
腿部宏 [待校准@9119]
通常,您希望在不同位置创建多个外观相似的对象。您可以使用宏和一些简单的数学来减少您必须编写的代码量,就像我们使用R2的两条腿一样。 [待校准@9120]
<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: 使用名称前缀获取两个类似名称的对象。 [待校准@9121]
常见技巧2: 用数学计算联合起源。在你改变机器人大小的情况下,用一些数学来改变一个属性来计算关节偏移将会省去很多麻烦。 [待校准@9122]
常见技巧3: 使用反射参数,并将其设置为1或-1。看看我们如何使用反射参数将腿放在底部 _ to _ $ {前缀} _ 腿原点的身体两侧。 [待校准@9123]