“🎆🎆🎆这是一场盛大的开始!🎆🎆🎆”
本文章是基于赵虚左老师的ROS教程的学习总结,属于作者的学习笔记。如有错误不足,请不吝指点,十分感谢!😊😊😊
xacro介绍
概念
Xacro 是 XML Macros 的缩写,Xacro 是一种 XML 宏语言,是可编程的 XML。
原理
Xacro 可以声明变量,可以通过数学运算求解,使用流程控制控制执行顺序,还可以通过类似函数的实现,封装固定的逻辑,将逻辑中需要的可变的数据以参数的方式暴露出去,从而提高代码复用率以及程序的安全性。
作用
较之于纯粹的 URDF 实现,可以编写更安全、精简、易读性更强的机器人模型文件,且可以提高编写效率。
语法详解
xacro 提供了可编程接口,类似于计算机语言,包括变量声明调用、函数声明与调用等语法实现。在使用 xacro 生成 urdf 时,根标签robot中必须包含命名空间声明:xmlns:xacro="http://wiki.ros.org/xacro"
1.属性与算数运算 用于封装 URDF 中的一些字段,比如: PAI 值,小车的尺寸,轮子半径 …
属性定义
<xacro:property name="xxxx" value="yyyy" />
属性调用
${属性名称}
算数运算
${数学表达式}
2.宏 类似于函数实现,提高代码复用率,优化代码结构,提高安全性宏定义
<xacro:macro name="宏名称" params="参数列表(多参数之间使用空格分隔)">
..... 参数调用格式: ${参数名}
</xacro:macro>
宏调用
<xacro:宏名称 参数1=xxx 参数2=xxx/>
3.文件包含 机器人由多部件组成,不同部件可能封装为单独的 xacro 文件,最后再将不同的文件集成,组合为完整机器人,可以使用文件包含实现文件包含
<robot name="xxx" xmlns:xacro="http://wiki.ros.org/xacro"> <xacro:include filename="my_base.xacro" /> <xacro:include filename="my_camera.xacro" /> <xacro:include filename="my_laser.xacro" /> .... </robot>
具体实现
部署流程:(最好是利用
include
标签的功能用不同的组成模块来组合为总体机器人文件)
分别编写不同组成模块的代码。(将需要的模型拆解构利用模块化思想)(其中需要注意的是其实每一个模块的
robot
标签的name
是可以不同的,关键的是launch
文件中的param
name
是独特的。后面会利用到。 )编写
launch
文件集成rviz
查看效果(注意转换坐标系)。
<robot name="mycar" xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:property name="footprint_radius" value="0.001" />
<!-- base_footprint -->
<link name="base_footprint">
<visual>
<geometry>
<sphere radius="${footprint_radius}" />
</geometry>
</visual>
</link>
<xacro:property name="base_radius" value="0.1" />
<xacro:property name="base_length" value="0.08" />
<xacro:property name="lidi_hight" value="0.015" />
<xacro:property name="base_joint_z" value="${base_length/2+lidi_hight}" />
<!-- base_link -->
<link name="base_link" >
<visual>
<geometry>
<cylinder radius="0.1" length="0.08" />
</geometry>
<origin xyz="0 0 0 " rpy="0 0 0" />
<material name="base_color">
<color rgba="0 0.5 0.8 0.8" />
</material>
</visual>
</link>
<joint name="link2footprint" type="fixed">
<parent link="base_footprint" />
<child link="base_link" />
<!-- -->
<origin xyz="0 0 0.055" rpy="0 0 0" />
</joint>
<!-- 3. wheel -->
<xacro:property name="wheel_radius" value="0.0325" />
<xacro:property name="wheel_length" value="0.015" />
<xacro:property name="PI" value="3.1415927" />
<xacro:property name="wheel_joint_z" value="${(base_length / 2 +lidi_hight - wheel_radius) * -1}" />
<!--
wheel_name:left or right
flag: 1 or -1
-->
<xacro:macro name="wheel_func" params="wheel_name flag">
<!-- link & joint -->
<link name="${wheel_name}_wheel">
<visual>
<geometry>
<cylinder radius="${wheel_radius}" length="${wheel_length}" />
</geometry>
<origin xyz="0 0 0" rpy="${PI / 2} 0 0" />
<material name="black">
<color rgba="0.0 0.0 0.0 0.9" />
</material>
</visual>
</link>
<!--
joint
-->
<joint name="${wheel_name}_wheel2base_link" type="continuous">
<parent link="base_link" />
<child link="${wheel_name}_wheel" />
<origin xyz="0 ${0.1 * flag} ${wheel_joint_z}" />
<axis xyz="0 1 0" />
</joint>
</xacro:macro>
<xacro:wheel_func wheel_name="left" flag="1" />
<xacro:wheel_func wheel_name="right" flag="-1" />
<!-- 4.universal_wheel -->
<xacro:property name="small_wheel_radius" value="0.0075" />
<xacro:property name="small_joint_z" value="${(base_length / 2 +lidi_hight - small_wheel_radius) * -1}" />
<xacro:macro name="universal_wheel_func" params="universal_wheel_name flag">
<link name="${universal_wheel_name}_wheel">
<visual>
<geometry>
<sphere radius="${small_wheel_radius}" />
</geometry>
<origin xyz="0 0 0" rpy="0 0 0" />
<material name="universal_wheel_color">
<color rgba="0 0 0 0.8" />
</material>
</visual>
</link>
<joint name ="${universal_wheel_name}2_link" type="continuous">
<parent link="base_link" />
<child link="${universal_wheel_name}_wheel" />
<origin xyz="${0.08 * flag} 0 ${small_joint_z}" rpy="0 0 0" />
<axis xyz="0 1 0" />
</joint>
</xacro:macro>
<xacro:universal_wheel_func universal_wheel_name="front" flag="1" />
<xacro:universal_wheel_func universal_wheel_name="back" flag="-1" />
</robot>
<robot name="mycar" xmlns:xacro="http://www.ros.org/wiki/xacro">
<!-- camera -->
<!-- 1.paramter -->
<!--
link: height width length
joint: x y z
-->
<xacro:property name="camera_length" value="0.02" />
<xacro:property name="camera_width" value="0.05" />
<xacro:property name="camera_height" value="0.05" />
<xacro:property name="joint_camera_x" value="0.08" />
<xacro:property name="joint_camera_y" value="0" />
<xacro:property name="joint_camera_z" value="${base_length / 2+camera_height / 2}" />
<!-- 2.link -->
<link name="camera">
<visual>
<geometry>
<box size="${camera_length} ${camera_width} ${camera_height}" />
</geometry>
<material name="black">
<color rgba=" 0 0 0 1" />
</material>
</visual>
</link>
<!-- 3.joint -->
<joint name="camera2base" type="fixed">
<parent link="base_link" />
<child link="camera" />
<origin xyz="${joint_camera_x} ${joint_camera_y} ${joint_camera_z}" rpy="0 0 0" />
</joint>
</robot>
<robot name="mycar" xmlns:xacro="http://www.ros.org/wiki/xacro">
<!-- laser -->
<!-- paramter -->
<!--
1.support:
radius:0.01 length:0.15
2.laser
radius:0.03 length:0.05
x y z
-->
<!-- 1.support -->
<!-- 1.1 link -->
<xacro:property name="support_radius" value="0.01" />
<xacro:property name="support_length" value="0.15" />
<link name="support">
<visual>
<geometry>
<cylinder radius="${support_radius}" length="${support_length}" />
</geometry>
<material name="red">
<color rgba="1 0 0 0.6" />
</material>
</visual>
</link>
<!-- 1.2 joint -->
<joint name="support2base" type="fixed">
<parent link="base_link" />
<child link="support" />
<origin xyz="0 0 ${base_length / 2 + support_length / 2}" rpy="0 0 0 " />
</joint>
<!-- 2.laser -->
<!-- 2.1 link -->
<xacro:property name="laser_radius" value="0.03" />
<xacro:property name="laser_length" value="0.05" />
<link name="laser">
<visual>
<geometry>
<cylinder radius="${laser_radius}" length="${laser_length}" />
</geometry>
<material name="black">
<color rgba="0 0 0 0.6" />
</material>
</visual>
</link>
<!-- 2.2 joint-->
<joint name="laser2support" type="fixed">
<parent link="support" />
<child link="laser" />
<origin xyz="0 0 ${support_length / 2 + laser_length / 2}" rpy="0 0 0" />
</joint>
</robot>
<robot name="mycar" xmlns:xacro="http://www.ros.org/wiki/xacro">
<!-- include base camera laser xacro file -->
<xacro:include filename="demo05_car_base.xacro" />
<xacro:include filename="demo06_car_camera.xacro" />
<xacro:include filename="demo07_car_laser.xacro" />
</robot>
<launch>
<!--1.在参数服务器中载入urdf文件-->
<!--textfile : 直接指向urdf 将整个urdf转入到参数服务器中-->
<param name="robot_description" command="$(find xacro)/xacro '$(find urdf01_rviz)/urdf/xacro/car.xacro'" />
<!-- 2.启动 rviz -->
<node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdf01_rviz)/config/show_mycar.rviz"/>
<!-- 机器人以及关节发布节点 需要着重注意 -->
<node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" />
<node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" />
<!-- 添加控制关节运动节点 -->
<!-- <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" /> -->
</launch>
仿真部署过程中的错误解决
检查方案
在编写xacro文件时,难免出现错误,但是对于xml文件来说它不会直接告诉你那里是有错误的或者是错在哪里,这个这个标签化编程语言的一些局限。
为了在完成一个阶段后来检查错误。我们可以使用ros中的xacro
转urdf
功能包来排查错误:1. 保存编写好的
xacro
文件后,在xacro目录下打开终端,并输入rosrun xacro xacro (需要检查的文件).xacro
查看是否转为urdf文件,如果转化错误的话,在期间可以检查错误内容和大致位置。
如果转化成功的话便会有如下显示(文件没有语法错误):
2. 或者使用ros自带的工具实现语法检查。(前提是将
xacro
文件转为urdf
文件—>先将 xacro 文件解析成 urdf 文件:rosrun xacro xacro xxx.xacro > xxx.urdf
)
check_urdf
语法检查
进入urdf
文件所属目录,调用:check_urdf urdf
文件,如果不抛出异常,说明文件合法,否则非法。
错误解决
- 类似这种错误一般都是代码中包含中文注释的问题
- launch文件报错:
具体可以为如下几种情况:
1.xml文件转义格式错误 即$(find xacro)/xacro
后面的功能包路径需要用' '
括起来。
2.文件路径错误,需要再仔细检查。
3.xacro文件的命名有问题:将文件后缀名更改:从.urdf.xacro
—>.xacro
运行成功。