ROS2 XACRO建模
参考博客:
https://blog.csdn.net/qq_36914987/article/details/111309304
https://blog.csdn.net/m0_67517854/article/details/131479039
URDF是机器人模型描述的统一格式,但是它却有很多缺点,比如
模型冗长,重复内容太多。比如机器人底盘的左右轮(下图代码的left_wheel_link和right_wheel_link),需要重复编写几乎一样的代码,导致重复代码过多,效率低下。
不便于参数修改和计算。由于没有宏定义,当需要修改模型的参数时,往往牵一发而动全身。另外,URDF也不能进行类似的参数计算。
为了弥补URDF格式的这些缺点,人们提出了改进版的URDF——XACRO格式。该格式很好地解决了URDF格式的不足,使得机器人的模型描述变得更加灵活和容易。其特点如下:
简化模型描述:创建宏定义和文件包含。
提供可编程接口:变量,常量,数学计算,条件语句等。
1.【常量定义】
<!--常量定义-->
<xacro:property name="M_PI" value="3.1415926"/>
通过xacro:property属性定义了一个名为“M_PI”的常量,其值为"3.1415926"。
【常量使用】
<!--参考系-->
<origin xyz="0 0 0" rpy="${M_PI/2} 0 0" />
常量的使用方法采用美元符==$+{}==的形式来调用。
2.【宏定义】
<!--宏定义-->
<xacro:macro name="name1" params="a b c">
......
</xacro:macro>
【宏调用】
<!--宏调用-->
<xacro:name1 a="xxx" b="xxx" c="xxx" />
这里需要注意的是,从ubuntu20.04开始,xacro的宏调用需要在宏名前添加前缀xacro:,否则模型不能在rviz中正常显示。
3.【文件包含】
<!--文件包含-->
<xacro:include filename="$(find mbot_description)/urdf/mbot_base_gazebo.xacro" />
为了便于模块化管理,xacro提供了文件包含的功能。这样就可以在不同的文件中对不同的部件进行建模,最后在通过文件包含进行整合。
新建工程
1、创建功能包
ros2 pkg create robot_xacro --build-type ament_cmake
2、添加xacro代码
# 进入功能包目录
cd robot_xacro
# 创建urdf rviz launch三个目录
mkdir urdf rviz launch
创建结果如下:
robot_xacro ├── CMakeLists.txt ├── include │ └── robot_xacro ├── launch ├── package.xml ├── rviz ├── src └── urdf |
修改CMakeLists.txt文件
cmake_minimum_required(VERSION 3.8) project(robot_xacro)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic) endif()
# find dependencies find_package(ament_cmake REQUIRED) # uncomment the following section in order to fill in # further dependencies manually. # find_package(<dependency> REQUIRED)
if(BUILD_TESTING) find_package(ament_lint_auto REQUIRED) # the following line skips the linter which checks for copyrights # comment the line when a copyright and license is added to all source files set(ament_cmake_copyright_FOUND TRUE) # the following line skips cpplint (only works in a git repo) # comment the line when this package is in a git repo and when # a copyright and license is added to all source files set(ament_cmake_cpplint_FOUND TRUE) ament_lint_auto_find_test_dependencies() endif()
# 安装 launch/rviz/urdf 目录到安装空间 install( DIRECTORY launch rviz urdf DESTINATION share/${PROJECT_NAME} )
ament_package()
|
然后编译我们的工程
colcon build --packages-select robot_xacro
如下:

在package.xml文件中添加以下代码:
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>robot_xacro</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="grb@todo.todo">grb</maintainer>
<license>TODO: License declaration</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<!-- 添加下面代码 -->
<exec_depend>ros2launch</exec_depend>
<exec_depend>xacro</exec_depend>
<exec_depend>robot_state_publisher</exec_depend>
<exec_depend>joint_state_publisher</exec_depend>
<exec_depend>rviz2</exec_depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
urdf文件夹下新建base_urdf.xacro文件,代码如下:
<!--
使用 xacro 优化 URDF 版的小车底盘实现:
实现思路
1.将一些常量、变量封装为 xacro:property
比如:PI 值、小车底盘半径、离地间距、车轮半径、宽度 ....
2.使用 宏 封装驱动轮以及支撑轮实现,调用相关宏生成驱动轮与支撑轮
-->
<!-- 根标签,必须声明 xmlns:xacro -->
<robot name="my_base" xmlns:xacro="http://www.ros.org/wiki/xacro">
<!-- 封装变量、常量 -->
<xacro:property name="PI" value="3.141"/>
<!-- 宏:黑色设置 -->
<material name="black">
<color rgba="0.0 0.0 0.0 1.0" />
</material>
<!-- 底盘属性 -->
<xacro:property name="base_footprint_radius" value="0.001" /> <!-- base_footprint 半径 -->
<xacro:property name="base_link_radius" value="0.1" /> <!-- base_link 半径 -->
<xacro:property name="base_link_length" value="0.08" /> <!-- base_link 长 -->
<xacro:property name="earth_space" value="0.015" /> <!-- 离地间距 -->
<!-- 底盘 -->
<link name="base_footprint">
<visual>
<geometry>
<sphere radius="${base_footprint_radius}" />
</geometry>
</visual>
</link>
<link name="base_link">
<visual>
<geometry>
<cylinder radius="${base_link_radius}" length="${base_link_length}" />
</geometry>
<origin xyz="0 0 0" rpy="0 0 0" />
<material name="yellow">
<color rgba="0.8 0.8 0.0 1.0" />
</material>
</visual>
</link>
<joint name="base_link2base_footprint" type="fixed">
<parent link="base_footprint" />
<child link="base_link" />
<origin xyz="0 0 ${earth_space + base_link_length / 2 }" />
</joint>
<!-- 驱动轮 -->
<!-- 驱动轮属性 -->
<xacro:property name="wheel_radius" value="0.0325" /><!-- 半径 -->
<xacro:property name="wheel_length" value="0.015" /><!-- 宽度 -->
<!-- 驱动轮宏实现 -->
<xacro:macro name="add_wheels" params="name flag">
<link name="${name}_wheel">
<visual>
<geometry>
<cylinder radius="${wheel_radius}" length="${wheel_length}" />
</geometry>
<origin xyz="0.0 0.0 0.0" rpy="${PI / 2} 0.0 0.0" />
<material name="black" />
</visual>
</link>
<joint name="${name}_wheel2base_link" type="continuous">
<parent link="base_link" />
<child link="${name}_wheel" />
<origin xyz="0 ${flag * base_link_radius} ${-(earth_space + base_link_length / 2 - wheel_radius) }" />
<axis xyz="0 1 0" />
</joint>
</xacro:macro>
<xacro:add_wheels name="left" flag="1" />
<xacro:add_wheels name="right" flag="-1" />
<!-- 支撑轮 -->
<!-- 支撑轮属性 -->
<xacro:property name="support_wheel_radius" value="0.0075" /> <!-- 支撑轮半径 -->
<!-- 支撑轮宏 -->
<xacro:macro name="add_support_wheel" params="name flag" >
<link name="${name}_wheel">
<visual>
<geometry>
<sphere radius="${support_wheel_radius}" />
</geometry>
<origin xyz="0 0 0" rpy="0 0 0" />
<material name="black" />
</visual>
</link>
<joint name="${name}_wheel2base_link" type="continuous">
<parent link="base_link" />
<child link="${name}_wheel" />
<origin xyz="${flag * (base_link_radius - support_wheel_radius)} 0 ${-(base_link_length / 2 + earth_space / 2)}" />
<axis xyz="1 1 1" />
</joint>
</xacro:macro>
<xacro:add_support_wheel name="front" flag="1" />
<xacro:add_support_wheel name="back" flag="-1" />
</robot>
urdf文件夹下新建camera_urdf.xacro文件,代码如下
<!-- 摄像头相关的 xacro 文件 -->
<robot name="my_camera" xmlns:xacro="http://www.ros.org/wiki/xacro">
<!-- 摄像头属性 -->
<xacro:property name="camera_length" value="0.01" /> <!-- 摄像头长度(x) -->
<xacro:property name="camera_width" value="0.025" /> <!-- 摄像头宽度(y) -->
<xacro:property name="camera_height" value="0.025" /> <!-- 摄像头高度(z) -->
<xacro:property name="camera_x" value="0.08" /> <!-- 摄像头安装的x坐标 -->
<xacro:property name="camera_y" value="0.0" /> <!-- 摄像头安装的y坐标 -->
<xacro:property name="camera_z" value="${base_link_length / 2 + camera_height / 2}" /> <!-- 摄像头安装的z坐标:底盘高度 / 2 + 摄像头高度 / 2 -->
<!-- 摄像头关节以及link -->
<link name="camera">
<visual>
<geometry>
<box size="${camera_length} ${camera_width} ${camera_height}" />
</geometry>
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
<material name="black" />
</visual>
</link>
<joint name="camera2base_link" type="fixed">
<parent link="base_link" />
<child link="camera" />
<origin xyz="${camera_x} ${camera_y} ${camera_z}" />
</joint>
</robot>
urdf文件夹下新建laser_urdf.xacro文件,代码如下
<!--
小车底盘添加雷达
-->
<robot name="my_laser" xmlns:xacro="http://www.ros.org/wiki/xacro">
<!-- 雷达支架 -->
<xacro:property name="support_length" value="0.15" /> <!-- 支架长度 -->
<xacro:property name="support_radius" value="0.01" /> <!-- 支架半径 -->
<xacro:property name="support_x" value="0.0" /> <!-- 支架安装的x坐标 -->
<xacro:property name="support_y" value="0.0" /> <!-- 支架安装的y坐标 -->
<xacro:property name="support_z" value="${base_link_length / 2 + support_length / 2}" /> <!-- 支架安装的z坐标:底盘高度 / 2 + 支架高度 / 2 -->
<link name="support">
<visual>
<geometry>
<cylinder radius="${support_radius}" length="${support_length}" />
</geometry>
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
<material name="red">
<color rgba="0.8 0.8 0.8 1.0" />
</material>
</visual>
</link>
<joint name="support2base_link" type="fixed">
<parent link="base_link" />
<child link="support" />
<origin xyz="${support_x} ${support_y} ${support_z}" />
</joint>
<!-- 雷达属性 -->
<xacro:property name="laser_length" value="0.05" /> <!-- 雷达长度 -->
<xacro:property name="laser_radius" value="0.03" /> <!-- 雷达半径 -->
<xacro:property name="laser_x" value="0.0" /> <!-- 雷达安装的x坐标 -->
<xacro:property name="laser_y" value="0.0" /> <!-- 雷达安装的y坐标 -->
<xacro:property name="laser_z" value="${support_length / 2 + laser_length / 2}" /> <!-- 雷达安装的z坐标:支架高度 / 2 + 雷达高度 / 2 -->
<!-- 雷达关节以及link -->
<link name="laser">
<visual>
<geometry>
<cylinder radius="${laser_radius}" length="${laser_length}" />
</geometry>
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
<material name="black" />
</visual>
</link>
<joint name="laser2support" type="fixed">
<parent link="support" />
<child link="laser" />
<origin xyz="${laser_x} ${laser_y} ${laser_z}" />
</joint>
</robot>
urdf文件夹下新建lcar_urdf.xacro文件,代码如下
<!-- 组合小车底盘、摄像头与雷达 -->
<robot name="my_robot_car" xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:include filename="base_urdf.xacro" />
<xacro:include filename="camera_urdf.xacro" />
<xacro:include filename="laser_urdf.xacro" />
</robot>
在launch文件夹下新建robot_car_xacro.launch.py文件
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from ament_index_python.packages import get_package_share_directory
from launch_ros.parameter_descriptions import ParameterValue
from launch.substitutions import Command
def generate_launch_description():
model = DeclareLaunchArgument(name="model",default_value=get_package_share_directory("robot_xacro") + "/urdf/lcar_urdf.xacro")
p_value = ParameterValue(Command(["xacro ",LaunchConfiguration("model")]))
robot_state_pub = Node(package="robot_state_publisher",
executable="robot_state_publisher",
parameters=[{"robot_description":p_value}] #robot_description的值p_value其实就是urdf文件的内容
)
joint_state_pub = Node(package="joint_state_publisher",executable="joint_state_publisher")
rviz2 = Node(package="rviz2",executable="rviz2")
return LaunchDescription([model,robot_state_pub,joint_state_pub,rviz2])
最后目录结构如下:

构建并测试
# 返回src工作空间,构建包
colcon build --packages-select robot_xacro
# Source工作空间
source install/setup.bash
# 启动可视化
ros2 launch robot_xacro robot_car_xacro.launch.py
运行结果如下:
