本教程基于ROS官方xacro教程中jade版本ROS翻译
Xacro(XML Macros)Xacro是一种XML宏语言。 使用xacro,您可以通过使用宏命令构建更精悍短小但又具有更高可读性的XML文件,这种宏命令可以扩展达到更大的XML表达范围。
- 维护状态:正在开发中
- 维护方:Morgan Quigley
- 作者:Stuart Glaser, William Woodall, Robert Haschke
- 许可证:BSD
- 漏洞和特征汇报链接:https://github.com/ros/xacro/issues
- 源:git https://github.com/ros/xacro.git (branch: jade-devel)
目录
- 1.案例
- 2.属性和属性块
- 3.数学表达式
- 4.条件块
- 5.Rospack命令
- 6.宏命令
- 6.1默认参数
- 6.2局部属性
- 7.包含其他xacro文件
- 8.YAML语言支持
- 9.用CMakeLists.txt进行构建
- 10.元素和属性
- 11.处理订单
- 12.已弃用的语法
此包在处理大型XML文档(如机器人说明)时最为有用。 它在如urdf的包中大量使用。 通过看下面的例子,本教程教您如何使用xacro来简化urdf文件。
参考以下的Xacro XML片段:
"pr2_arm" params="suffix parent reflect">
"${suffix}" reflect="${reflect}" parent="${parent}" />
"${suffix}" reflect="${reflect}" parent="elbow_flex_${suffix}" />
"left" reflect="1" parent="torso" />
"right" reflect="-1" parent="torso" />
上面的片段扩展成为下面的样子:
"left" reflect="1" parent="torso" />
"left" reflect="1" parent="elbow_flex_left" />
"right" reflect="-1" parent="torso" />
"right" reflect="-1" parent="elbow_flex_right" />
如果我们还定义了pr2_upperarm和pr2_forearm的宏,那么这个片段可以扩展以描述整个机器人臂。
本页的其余部分描述了xacro的功能。
属性是可以插入到XML文档中的任何位置的值。 属性块是XML的名称片段,可以插入允许XML的任何位置。 两者都使用属性标签来定义值。属性标记不能在xacro:宏中声明。以下示例将显示如何声明和使用属性:
property name="the_radius" value="2.1" />
property name="the_length" value="4.5" />
"cylinder" radius="${the_radius}" length="${the_length}" />
通过将名称放在dollared-braces( )中,你可以将两个属性值插入到几何表达式中。如果你想要一个文本“ {”,你应该将其转义为“$$ {”。
下面是使用属性块的示例:
<xacro:property name="front_left_origin">
<origin xyz="0.3 0 0" rpy="0 0 0" />
xacro:property>
<pr2_wheel name="front_left_wheel">
<xacro:insert_block name="front_left_origin" />
pr2_wheel>
在dollared-braces($ {})中,您还可以编写简单的数学表达式。 目前,该结构支持基本算术和变量替换。 下面是一个例子:
<xacro:property name="pi" value="3.1415926535897931" />
<circle circumference="${2.5 * pi}" />
自ROS Jade以来,Xacro使用python来评估包含在dollared-braces($ {})中的表达式。 这允许用户使用更复杂的算术表达式。 此外,一些基本常数,例如 pi,已经被预定义过了:
"R" value="2" />
"alpha" value="${30/180*pi}" />
"${2 * pi * R}" pos="${sin(alpha)} ${cos(alpha)}" />
自从ROS Hydro以来,Xacro有类似于roslaunch的条件块。 这对于可配置的机器人或加载不同的Gazebo插件等事情很有用。 它遵循以下语法:
if value="" >
<... some xml code here ...>
if>
"">
<... some xml code here ...>
表达式需要计算结果为“0”,“1”,“true”或“false”,否则将抛出错误。
ROS Jade中更强大的评估功能允许使用更复杂的表达式。 几乎任何python表达式的计算结果都是可行的:
"var" value="useit"/>
if value="${var == 'useit'}"/>
if value="${var.startswith('use') and var.endswith('it')}"/>
"allowed" value="[1,2,3]"/>
if value="${1 in allowed}"/>
Xacro允许你使用某些rospack命令和dollared括号($())。
"$(find xacro)" />
"$(arg myvar)" />
Xacro目前支持roslaunch使用替换args支持的所有rospack命令。 参数需要在命令行中使用myvar:= true语法指定。
自从ROS Indigo,它也可以定义默认值如下:
"myvar" default="false"/>
使用上面的定义语句,你可以像下面这样运行xacro:
<param name="robot_description" command="$(find xacro)/xacro.py $(arg model) myvar:=true" />
xacro的主要特性是它对宏的支持。 使用宏标签定义宏,并指定宏名称和参数列表。 参数列表应以空格分隔。 它们变成宏观本地属性。
<xacro:macro name="pr2_caster" params="suffix *origin **content **anothercontent">
<joint name="caster_${suffix}_joint">
<axis xyz="0 0 1" />
joint>
<link name="caster_${suffix}">
<xacro:insert_block name="origin" />
<xacro:insert_block name="content" />
<xacro:insert_block name="anothercontent" />
link>
xacro:macro>
<xacro:pr2_caster suffix="front_left">
<pose xyz="0 1 0" rpy="0 0 0" />
<container>
<color name="yellow"/>
<mass>0.1mass>
container>
<another>
<inertial>
<origin xyz="0 0 0.5" rpy="0 0 0"/>
<mass value="1"/>
<inertia ixx="100" ixy="0" ixz="0" iyy="100" iyz="0" izz="100" />
inertial>
another>
xacro:pr2_caster>
该示例声明了一个宏“pr2_caster”,它有两个参数:suffix和origin。 请注意,“origin”已加星标。 这表明origin是一个块参数,而不是一个简单的文本参数。 向前看pr2_caster的使用。 后缀属性在pr2_caster标记中定义为属性,但没有定义origin属性。 相反,origin指的是第一个元素(在这种情况下是“pose”块)。 双星号版本(“content”,“anothercontent”)允许插入在随后可用的元素(在上面的示例中分别是“container”,“another”)中传递的任意数量的元素。 此示例扩展为以下内容:
<joint name="caster_front_left_joint">
<axis xyz="0 0 1" />
joint>
<link name="caster_front_left">
<pose xyz="0 1 0" rpy="0 0 0" />
<color name="yellow" />
<mass>0.1mass>
<inertial>
<origin xyz="0 0 0.5" rpy="0 0 0"/>
<mass value="1"/>
<inertia ixx="100" ixy="0" ixz="0" iyy="100" iyz="0" izz="100" />
inertial>
link>
将按指定的顺序处理多个块参数:
<xacro:macro name="reorder" params="*first *second">
<xacro:insert_block name="second"/>
<xacro:insert_block name="first"/>
xacro:macro>
<reorder>
<first/>
<second/>
reorder>
宏可能包含其他宏。 外部宏将首先展开,然后内部宏将展开。 例如:
<a>
<xacro:macro name="foo" params="x">
<in_foo the_x="${x}" />
xacro:macro>
<xacro:macro name="bar" params="y">
<in_bar>
<xacro:foo x="${y}" />
in_bar>
xacro:macro>
<xacro:bar y="12" />
a>
变成:
<a>
<in_bar>
<in_foo the_x="12.0"/>
in_bar>
a>
宏参数可以有默认值:
"foo" params="x:=${x} y:=${2*y} z:=0"/>
如果默认值包含评估表达式,则将在实例化时评估它们。
通常,您需要将外部变量传递到本地宏参数(如上面的x)。 要简化此任务,可以使用^语法:
"foo" params="p1 p2:=expr_a p3:=^ p4:=^|expr_b">
插入符号^表示使用外部scope属性(具有相同名称)。 管| 表示如果属性未在外部范围中定义,则使用给定的回退。
在宏中定义的属性和宏在此宏的本地,即在外部不可见。 使用可选属性scope =“parent | global”,属性定义可以导出到宏的父作用域(或全局作用域)。
您可以使用xacro:include标记来包含其他xacro文件:
<xacro:include filename="$(find package)/other_file.xacro" />
<xacro:include filename="other_file.xacro" />
<xacro:include filename="$(cwd)/other_file.xacro" />
文件“other_file.xacro”将被xacro包含和扩展。 Jade中的新功能:相对文件名相对于当前处理的文件进行解释。 注意:当在宏中包含文件时,不是宏定义,而是宏调用文件是处理包含! $(cwd)显式允许访问当前工作目录中的文件。
为了避免各种包含文件的属性和宏之间的名称冲突,可以为包含的文件指定命名空间 - 提供属性ns:
<xacro:include filename="other_file.xacro" ns="namespace"/>
访问命名空间宏和属性是通过预先命名空间来实现的,用点分隔:
${namespace.property}
属性可以是用python语法过度声明的字典或列表,如下所示:
property name="props" value="${dict(a=1, b=2, c=3)}"/>
property name="numbers" value="${[1,2,3,4]}"/>
或者从YAML文件中加载,如下:
"props" value="${load_yaml('props.yaml')}"/
注意,评估括号$ {}区分评价和纯文本定义。 校准数据是从YAML加载的理想候选。
以下代码段显示如何在程序包的申明期间使用xacro:
# Generate .world files from .world.xacro files
find_package(xacro REQUIRED)
# You can also add xacro to the list of catkin packages:
# find_package(catkin REQUIRED COMPONENTS ... xacro)
# Xacro files
file(GLOB xacro_files ${CMAKE_CURRENT_SOURCE_DIR}/worlds/*.world.xacro)
foreach(it ${xacro_files})
# remove .xacro extension
string(REGEX MATCH "(.*)[.]xacro$" unused ${it})
set(output_filename ${CMAKE_MATCH_1})
# create a rule to generate ${output_filename} from {it}
xacro_add_xacro_file(${it} ${output_filename})
list(APPEND world_files ${output_filename})
endforeach(it)
# add an abstract target to actually trigger the builds
add_custom_target(media_files ALL DEPENDS ${world_files})
虽然这个cmake代码提供了对目标名称和构建顺序的完全控制,但还有一个easyilities宏:
file(GLOB xacro_files worlds/*.world.xacro)
xacro_add_files(${xacro_files} TARGET media_files)
要使用动态定义的名称添加元素或属性,可以使用特殊的xacro标记
"${element_name}" [other attributes]>
[content]
"${attribute_name}" value="${attribute_value}"/>
Classicly Xacro首先加载所有包含项,然后处理所有属性和宏定义,最后实例化宏并评估表达式。 因此,后期定义的属性或宏定义将覆盖先前的定义。 此外,条件标签和对宏或属性定义以及包含其他文件没有影响。
自ROS Jade以来,Xacro提供了命令行选项–inorder,允许以读取顺序处理整个文档。 因此,将使用目前为止看到的属性或宏的最新定义。 这是一个更直观的评估过程,提供了一些不错的新功能:
因为 - 顺序处理更强大,在未来Jade以后的版本,新的处理风格将成为默认风格,所以你应该检查你的xacro文件的兼容性。 通常,两种加工方式应该给出相同的结果。 你可以很容易地像下面这样检查:
rosrun xacro xacro file.xacro > /tmp/old.xml
rosrun xacro xacro --inorder file.xacro > /tmp/new.xml
diff /tmp/old.xml /tmp/new.xml
如果结果显示出任何差异,你应检查并调整您的xacro文件。 常见的原因是校准数据后期进行了加载(作为属性)。 在这种情况下,只需将加载行为向前移动,即在使用之前进行校准数据的加载。 为了方便搜索错误放置的属性定义,可以使用选项–check-order运行xacro。 如果有任何有问题的属性,它们将在stderr上列出:
Document is incompatible to --inorder processing.
The following properties were redefined after usage:
foo redefined in issues.xacro
使用命令行选项-vv或-vvv,可以增加详细程度级别以记录属性的所有定义。
虽然在以前的版本中,没有命名空间前缀的xacro标签能够被接受并使用,但是这种草率的语法是我们应当强烈反对的,因为它阻止在最终的XML中使用这些标签。 从Jade开始,这种语法已被弃用,你应该相应地更新你的文件。 以下脚本将为您更新文件:
find . -iname "*.xacro" | xargs sed -i 's#<\([/]\?\)\(if\|unless\|include\|arg\|property\|macro\|insert_block\)#<\1xacro:\2#g'