Xacro 全详解(ROS机器人建模必备,适配机械臂/无人车,实操全覆盖)
Xacro(XML Macros)是 ROS 专为解决纯 URDF 痛点设计的建模格式,完全兼容URDF所有语法,核心新增「参数化、宏复用、数学运算」三大功能,能大幅减少重复代码、降低修改成本,是复杂机器人(六轴机械臂、无人机、无人车)建模的首选,下面从基础到进阶、语法到实操、避坑到调试,一次性讲透。
一、 Xacro 核心优势(对比URDF,为啥必学)
纯 URDF 建模的3个致命痛点,Xacro 全部解决,这也是它成为主流的核心原因:
1. 痛点1:重复代码过多(如六轴机械臂6个连杆,要写6套几乎一样的 <link> 标签)→ Xacro 用宏封装,1套模板重复调用,代码量减少80%
2. 痛点2:参数硬编码(改连杆长度要逐行找对应 <cylinder> 标签)→ Xacro 用全局参数,1处修改全程生效,零遗漏
3. 痛点3:无运算能力(关节位置要手动算“底座高度/2+连杆长度/2”)→ Xacro 支持算术运算+内置常量,自动计算,零出错
额外优势:支持模块化拆分、条件判断,复杂机器人(如带夹爪的机械臂)可分文件管理,维护更方便。
二、 Xacro 基础规范(必遵守,否则直接报错)
1. 文件格式要求
– 文件后缀:固定为 .xacro (如 six_axis_arm.xacro ,建议命名见名知意,关联机器人类型)
– 编码格式:UTF-8,避免中文乱码(注释尽量用英文,减少报错风险)
2. 根标签核心(唯一强制要求,重中之重)
Xacro 是 URDF 的扩展,必须在根标签 <robot> 中添加 Xacro命名空间声明,否则 ROS 解析器无法识别Xacro语法,固定格式不能改,复制直接用:
xml
<?xml version="1.0" encoding="UTF-8"?>
<!– 根标签:robot name自定义(机器人名称),命名空间必须原样复制,不能改 –>
<robot name="my_six_arm" xmlns:xacro="http://wiki.ros.org/xacro">
<!– 所有Xacro语法 + URDF标签,都嵌套在这个标签内 –>
</robot>
3. Xacro 与 URDF 转换(ROS必用,2种方式)
Xacro 文件无法被 ROS 直接解析(RVIZ/Gazebo只认URDF),必须转换成URDF格式,2种方式按需选,推荐第二种,高效无冗余
方式1:命令行手动转换(生成永久URDF文件,适合调试)
语法: xacro 你的Xacro文件路径 > 生成的URDF文件路径
示例(终端执行,适配功能包目录):
bash
# 进入功能包的urdf目录(先cd到自己的功能包下)
cd ~/catkin_ws/src/my_arm/urdf
# 转换:把six_arm.xacro转换成six_arm.urdf
xacro six_arm.xacro > six_arm.urdf
校验转换是否成功: check_urdf six_arm.urdf ,输出link和joint列表即成功。
方式2:启动文件直接调用(临时转换,推荐实战用)
在launch启动文件中,用 command 参数调用xacro工具,启动时自动转换,无需手动生成URDF,修改Xacro后重启launch即生效,效率拉满:
xml
<!– launch文件中配置,直接复制适配 –>
<launch>
<!– 加载机器人模型:自动转换xacro为urdf,无需手动生成 –>
<param name="robot_description"
command="$(find xacro)/xacro '$(find my_arm)/urdf/six_arm.xacro'"/>
</launch>
三、 Xacro 四大核心语法(从易到难,全覆盖,机械臂高频用)
所有Xacro语法都围绕「简化建模」设计,核心4个语法,学会就能独立建复杂机器人,每个语法配机械臂实操示例,直接套用。
语法1:全局参数定义与调用(最基础,必学)
核心作用:将机器人的通用参数(连杆长度/半径、质量、关节角度、限位值)统一定义,后续直接调用,改参数只改1处,避免全局修改遗漏。
1. 参数定义(3种方式,按需选择)
本质是「定义变量」,变量名自定义,值的单位和URDF一致(长度m、质量kg、角度rad、力N·m)
– 方式1:单参数定义(最常用,适合零散参数)
格式: <xacro:property name="参数名" value="参数值"/>
特点:一行定义一个参数,简洁直观,适合连杆长度、半径、关节限位等独立参数
– 方式2:块参数定义(适合一组关联参数,如关节限位、惯性矩阵)
格式:将一组关联参数封装成块,通过「参数组名.子项名」调用,避免零散参数过多混乱
xml
<xacro:property name="joint_limit"> <!– 参数组名:joint_limit –>
<lower>-3.14</lower> <!– 子项1:关节最小角度 –>
<upper>3.14</upper> <!– 子项2:关节最大角度 –>
<effort>3</effort> <!– 子项3:关节最大扭矩 –>
<velocity>2</velocity><!– 子项4:关节最大角速度 –>
</xacro:property>
– 方式3:引用参数定义(适合复用已有参数,减少重复定义)
格式: <xacro:property name="新参数名" value="${已有参数名}"/>
示例: <xacro:property name="link2_len" value="${link1_len}"/> (link2长度复用link1长度)
2. 参数调用(固定格式,无例外)
格式: ${参数名} ,直接嵌入到URDF标签的属性值中,支持嵌套调用(块参数用 ${参数组名.子项名} )
3. 机械臂实操示例(直接复制用)
xml
<!– 1. 定义全局参数(机械臂通用,一次定义,全程调用) –>
<xacro:property name="base_size" value="0.2 0.2 0.08"/> <!– 底座长宽高:x y z –>
<xacro:property name="link1_len" value="0.15"/> <!– 连杆1长度 –>
<xacro:property name="link2_len" value="0.14"/> <!– 连杆2长度 –>
<xacro:property name="link_radius" value="0.02"/> <!– 所有连杆半径(统一) –>
<xacro:property name="link_mass" value="0.2"/> <!– 单个连杆质量 –>
<xacro:property name="pi" value="3.1415926"/> <!– 手动定义π,也可直接用内置pi –>
<!– 块参数定义:关节通用限位 –>
<xacro:property name="joint_limit">
<lower>-${pi}</lower>
<upper>${pi}</upper>
<effort>3</effort>
<velocity>2</velocity>
</xacro:property>
<!– 2. 调用参数(替代硬编码,修改时只改上面的参数即可) –>
<!– 底座link:调用base_size参数 –>
<link name="base_link">
<visual>
<geometry><box size="${base_size}"/></geometry> <!– 调用全局参数 –>
<material name="gray"><color rgba="0.5 0.5 0.5 1"/></material>
</visual>
</link>
<!– 连杆1 link:调用link1_len、link_radius、link_mass参数 –>
<link name="link1">
<visual>
<geometry><cylinder length="${link1_len}" radius="${link_radius}"/></geometry>
</visual>
<inertial><mass value="${link_mass}"/></inertial> <!– 调用质量参数 –>
</link>
<!– 关节1:调用块参数joint_limit的子项 –>
<joint name="joint_base_link1" type="revolute">
<limit lower="${joint_limit.lower}" upper="${joint_limit.upper}"
effort="${joint_limit.effort}" velocity="${joint_limit.velocity}"/>
</joint>
语法2: 数学运算(核心加分项,告别手动计算)
Xacro 支持直接对参数做算术运算,无需提前手动计算数值(如关节位置=底座高度/2+连杆长度/2),减少计算错误,适配机械臂关节位姿、连杆尺寸的动态调整。
1. 支持的运算(优先级和数学一致,够用就行)
– 基础运算: +(加)、-(减)、*(乘)、/(除)
– 优先级控制:用 () 括号提升优先级(如 ${(a+b)/2} ,先加后除)
– 内置常量:直接用 pi (代表圆周率π,≈3.1415926),无需手动定义
2. 机械臂高频使用场景(核心是关节origin位姿计算)
机械臂关节的初始位置,大多需要计算「底座高度的一半+连杆长度的一半」,用数学运算直接写,不用手动算数值,示例如下:
xml
<!– 定义基础参数 –>
<xacro:property name="base_height" value="0.08"/> <!– 底座高度0.08m –>
<xacro:property name="link1_len" value="0.15"/> <!– 连杆1长度0.15m –>
<!– 关节origin z轴偏移:底座高度/2 + 连杆长度/2,直接运算,无需手动算0.04+0.075=0.115 –>
<joint name="joint_base_link1" type="revolute">
<!– xyz:x=0,y=0,z=底座半高+连杆半高,自动计算 –>
<origin xyz="0 0 ${base_height/2 + link1_len/2}" rpy="0 0 0"/>
<axis xyz="0 0 1"/> <!– 绕z轴旋转 –>
<limit lower="-pi" upper="pi"/> <!– 直接用内置pi,代表±180° –>
</joint>
<!– 复杂运算:带括号,先算减法再算除法 –>
<xacro:property name="link2_len" value="0.14"/>
<joint name="joint1_link2" type="revolute">
<origin xyz="0 0 ${(link1_len – link2_len)/2 + link2_len/2}" rpy="0 0 0"/>
</joint>
语法3: 宏定义与调用(Xacro核心,复杂建模必备)
核心作用:将机器人中重复的结构(如机械臂的“连杆+关节”组合、无人车的轮子+悬挂)封装成「宏模板」,后续调用时只需传参数,无需重复写相同代码,六轴机械臂6个关节,用宏只需调用6次,代码量直接减半。
1. 宏定义(封装重复结构,固定格式,3个核心要素)
格式: <xacro:macro name="宏名" params="参数列表"> 封装的重复代码 </xacro:macro>
– 核心要素1: name → 宏名称(自定义,见名知意,如 arm_link_joint ,代表机械臂连杆+关节)
– 核心要素2: params → 宏的输入参数(必填!多个参数用空格分隔,如 link_name parent_link child_link link_len ),参数是封装结构的可变部分(如连杆名、父link、子link、连杆长度)
– 核心要素3: 封装内容 → 重复的URDF结构(如1个 <link> +1个 <joint> ),可变部分用 ${参数名} 占位
2. 宏调用(一键复用,传参即可,无门槛)
格式: <xacro:宏名 参数1="值1" 参数2="值2" …/> ,按宏定义的 params 顺序传参,参数名必须和定义一致,少传会报错
3. 机械臂核心实操示例(六轴机械臂必用,直接复制)
机械臂的核心结构是「1个连杆(link)+1个旋转关节(joint)」,6个关节结构完全一致,仅连杆长度、名称不同,用宏封装后,调用6次即可完成建模,效率拉满:
xml
<!– 先定义全局通用参数(宏中可直接调用) –>
<xacro:property name="link_radius" value="0.02"/> <!– 连杆半径统一 –>
<xacro:property name="link_mass" value="0.2"/> <!– 连杆质量统一 –>
<!– 定义宏:封装「连杆link + 旋转关节joint」,适配六轴机械臂所有关节 –>
<!– params:宏的输入参数(link_name:连杆名;parent/child:父子link;link_len:连杆长;joint_name:关节名) –>
<xacro:macro name="arm_single_joint" params="link_name parent_link child_link link_len joint_name">
<!– 1. 封装连杆link(圆柱体,可变参数:link_name、link_len,其余固定) –>
<link name="${link_name}">
<!– 可视化属性(rviz显示) –>
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry><cylinder length="${link_len}" radius="${link_radius}"/></geometry>
<material name="gray"><color rgba="0.5 0.5 0.5 1"/></material>
</visual>
<!– 碰撞属性(gazebo仿真/碰撞检测,和visual一致即可) –>
<collision>
<geometry><cylinder length="${link_len}" radius="${link_radius}"/></geometry>
</collision>
<!– 惯性属性(gazebo仿真必需,否则模型浮空,参数固定即可) –>
<inertial>
<mass value="${link_mass}"/>
<origin xyz="0 0 0" rpy="0 0 0"/>
<inertia ixx="0.001" ixy="0" ixz="0" iyy="0.001" iyz="0" izz="0.0005"/>
</inertial>
</link>
<!– 2. 封装旋转关节joint(可变参数:parent/child、joint_name,其余固定) –>
<joint name="${joint_name}" type="revolute">
<parent link="${parent_link}"/> <!– 父link(可变) –>
<child link="${child_link}"/> <!– 子link(可变) –>
<origin xyz="0 0 ${link_len/2}" rpy="0 0 0"/> <!– 关节在连杆中点,自动计算 –>
<axis xyz="0 0 1"/> <!– 绕z轴旋转(可后续改成参数,适配不同关节轴) –>
<limit lower="-pi" upper="pi" effort="3" velocity="2"/> <!– 关节限位固定 –>
</joint>
</xacro:macro>
<!– 调用宏:六轴机械臂,调用6次即可,无需写6套link+joint,极简高效 –>
<!– 关节1:底座→连杆1,连杆长0.15m –>
<xacro:arm_single_joint link_name="link1" parent_link="base_link" child_link="link1" link_len="0.15" joint_name="joint_base_link1"/>
<!– 关节2:连杆1→连杆2,连杆长0.14m –>
<xacro:arm_single_joint link_name="link2" parent_link="link1" child_link="link2" link_len="0.14" joint_name="joint1_link2"/>
<!– 关节3:连杆2→连杆3,连杆长0.13m –>
<xacro:arm_single_joint link_name="link3" parent_link="link2" child_link="link3" link_len="0.13" joint_name="joint2_link3"/>
<!– 关节4:连杆3→连杆4,连杆长0.12m –>
<xacro:arm_single_joint link_name="link4" parent_link="link3" child_link="link4" link_len="0.12" joint_name="joint3_link4"/>
<!– 关节5:连杆4→连杆5,连杆长0.10m –>
<xacro:arm_single_joint link_name="link5" parent_link="link4" child_link="link5" link_len="0.10" joint_name="joint4_link5"/>
<!– 关节6:连杆5→连杆6(末端),连杆长0.08m –>
<xacro:arm_single_joint link_name="link6" parent_link="link5" child_link="link6" link_len="0.08" joint_name="joint5_link6"/>
语法4: 辅助语法(提升灵活性,复杂建模必用)
除了三大核心语法,Xacro还有2个高频辅助语法,适配复杂机器人建模,提升代码可读性和维护性。
1. 文件包含( <xacro:include> ):模块化拆分
核心作用:将复杂机器人拆分成多个子Xacro文件(如底座、机械臂主体、末端夹爪分别写),再通过 <xacro:include> 引入主文件,避免单个文件代码过长,维护更方便。
格式: <xacro:include filename="子Xacro文件路径"/> (路径用绝对路径或功能包相对路径)
示例(带夹爪的机械臂,分3个文件):
xml
<!– 主文件:six_arm_main.xacro –>
<robot name="six_arm_with_gripper" xmlns:xacro="http://wiki.ros.org/xacro">
<!– 引入子文件:底座、机械臂主体、末端夹爪 –>
<xacro:include filename="$(find my_arm)/urdf/sub/base.xacro"/>
<xacro:include filename="$(find my_arm)/urdf/sub/arm_body.xacro"/>
<xacro:include filename="$(find my_arm)/urdf/sub/gripper.xacro"/>
</robot>
2. 条件判断( <xacro:if> ):按需生成结构
核心作用:根据条件判断是否生成某部分结构(如区分左右连杆、是否加载夹爪),适配个性化建模需求。
格式: <xacro:if value="${判断条件}"> 满足条件时执行的代码 </xacro:if>
判断条件:支持 > (大于)、 < (小于)、 == (等于)、 != (不等于)
示例(根据连杆长度判断是否用红色材质):
xml
<xacro:property name="link_len" value="0.15"/>
<link name="link1">
<visual>
<geometry><cylinder length="${link_len}" radius="0.02"/></geometry>
<!– 条件判断:连杆长度>0.12m,用红色;否则用灰色 –>
<xacro:if value="${link_len > 0.12}">
<material name="red"><color rgba="1 0 0 1"/></material>
</xacro:if>
<xacro:if value="${link_len <= 0.12}">
<material name="gray"><color rgba="0.5 0.5 0.5 1"/></material>
</xacro:if>
</visual>
</link>
四、 Xacro 建模避坑指南(新手必看,少走90%弯路)
1. 命名空间漏加 → 报错“invalid element”:根标签 <robot> 必须加 xmlns:xacro="http://wiki.ros.org/xacro" ,复制粘贴最稳妥,不要手动写
2. 参数调用漏大括号 → 解析成字符串,模型错乱:调用参数必须用 ${参数名} ,缺一不可(如 ${link_len} ,不是 link_len )
3. 宏调用少传参数 → 报错“missing parameter”:调用宏时, params 定义的所有参数必须传值,一个都不能少
4. 运算优先级混乱 → 关节位置错误:复杂运算一定要用 () 括号明确优先级(如 ${(a+b)*c} ,不要写 ${a+b*c} )
5. 机器人结构闭环 → 报错“invalid tree structure”:和URDF一样,Xacro建模必须是树状结构,以 base_link 为根节点,每个子link只能有1个父link,不能出现A→B→C→A的闭环
6. Gazebo仿真模型浮空 → 惯性属性缺失:所有运动的link必须加 <inertial> 标签(宏封装时一定要包含),固定link(如底座)可省略
7. 中文注释乱码 → 解析报错:文件编码设为UTF-8,注释尽量用英文,避免中文乱码
五、 Xacro 完整流程(从建模到RVIZ显示,闭环实操)
以六轴机械臂为例,给你一套完整的实操流程,新手照做就能成功:
1. 新建Xacro文件:在功能包的 urdf 目录下,新建 six_arm.xacro ,写入根标签+全局参数+宏定义+宏调用
2. 校验语法:终端执行 xacro six_arm.xacro ,无报错即语法正确;再执行 xacro six_arm.xacro > six_arm.urdf ,用 check_urdf six_arm.urdf 校验URDF结构
3. 编写launch文件:新建 display.launch ,配置 robot_description 参数(自动转换Xacro),启动RVIZ
4. 启动查看:终端执行 roslaunch 功能包名 display.launch ,RVIZ中Fixed Frame设为 base_link ,添加RobotModel组件,即可看到机械臂模型
网硕互联帮助中心



评论前必须登录!
注册