3. Xacro优化机械臂模型

任务目标

在ROS中,直接编写URDF描述多关节机械臂时,连杆尺寸、关节原点等参数散落各处,修改一处尺寸往往需要同步调整多个坐标,极易出错。本案例使用Xacro宏定义重构机械臂URDF,将连杆长度、半径等尺寸参数化,通过宏调用生成完整模型,实现“改一处参数、全模型联动更新”。

实现原理

Xacro(XML Macros)是URDF的预处理工具,支持属性定义、数学表达式和宏调用。核心思路:

  • 用 <xacro:property> 定义全局尺寸参数(如连杆长度、关节偏移)
  • 用 <xacro:macro> 封装重复的连杆+关节结构,通过参数传入不同尺寸
  • 用 ${} 语法进行数学运算,自动计算关节原点坐标

完整代码

创建 arm.xacro 文件,内容如下:

<?xml version="1.0"?>
<robot name="xacro_arm" xmlns:xacro="http://www.ros.org/wiki/xacro">

  <!-- 全局尺寸参数 -->
  <xacro:property name="base_radius" value="0.05" />
  <xacro:property name="link1_len" value="0.3" />
  <xacro:property name="link2_len" value="0.25" />
  <xacro:property name="link_radius" value="0.03" />
  <xacro:property name="joint_gap" value="0.02" />

  <!-- 材料定义 -->
  <material name="base_mat">
    <color rgba="0.8 0.2 0.2 1.0"/>
  </material>
  <material name="link_mat">
    <color rgba="0.2 0.4 0.8 1.0"/>
  </material>

  <!-- 宏:生成一个连杆+其末端旋转关节 -->
  <xacro:macro name="link_with_joint" params="prefix len parent_link origin_xyz origin_rpy axis">
    <link name="${prefix}_link">
      <visual>
        <geometry>
          <cylinder length="${len}" radius="${link_radius}"/>
        </geometry>
        <origin xyz="0 0 ${len/2}" rpy="0 0 0"/>
        <material name="link_mat"/>
      </visual>
      <collision>
        <geometry>
          <cylinder length="${len}" radius="${link_radius}"/>
        </geometry>
      </collision>
    </link>

    <joint name="${prefix}_joint" type="revolute">
      <parent link="${parent_link}"/>
      <child link="${prefix}_link"/>
      <origin xyz="${origin_xyz}" rpy="${origin_rpy}"/>
      <axis xyz="${axis}"/>
      <limit lower="-3.14" upper="3.14" effort="10" velocity="1.0"/>
    </joint>
  </xacro:macro>

  <!-- 基座 -->
  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.06" radius="${base_radius}"/>
      </geometry>
      <origin xyz="0 0 0.03" rpy="0 0 0"/>
      <material name="base_mat"/>
    </visual>
    <collision>
      <geometry>
        <cylinder length="0.06" radius="${base_radius}"/>
      </geometry>
    </collision>
  </link>

  <!-- 调用宏生成两个连杆 -->
  <xacro:link_with_joint prefix="link1" len="${link1_len}" parent_link="base_link"
                         origin_xyz="0 0 0.06" origin_rpy="0 0 0" axis="0 0 1"/>

  <xacro:link_with_joint prefix="link2" len="${link2_len}" parent_link="link1_link"
                         origin_xyz="0 0 ${link1_len + joint_gap}" origin_rpy="0 0 0" axis="0 1 0"/>

</robot>

运行与验证

环境依赖:ROS(Noetic或Melodic均可),需安装 ros-noetic-xacro(或对应版本)。

步骤1:将上述代码保存为 arm.xacro,然后执行Xacro展开为URDF:

rosrun xacro xacro arm.xacro > arm.urdf

步骤2:检查生成的URDF是否完整且无报错:

check_urdf arm.urdf

步骤3:在RViz中可视化验证模型结构:

roslaunch urdf_tutorial display.launch model:=arm.urdf

验证通过条件:

  • check_urdf 输出显示 Successfully parsed URDF,且列出3个link(base_link、link1_link、link2_link)和2个joint,无警告或错误。
  • RViz中显示红色基座和两节蓝色连杆,关节呈串联结构,拖动关节滑块时对应连杆绕轴旋转。
  • 修改 arm.xacro 顶部 link1_len 的值为 0.4,重新执行步骤1和2,确认 arm.urdf 中link1的cylinder长度变为0.4,且link2_joint的z坐标自动更新为 0.4 + 0.02 = 0.42,无需手动修改坐标。

关键说明

  • 宏参数 origin_xyz 和 origin_rpy 以字符串形式传入,Xacro会将其原样写入joint的origin标签,因此调用时需给出完整的三元组。
  • 第二个关节的z坐标使用 ${link1_len + joint_gap} 表达式,验证了参数化联动效果——修改全局参数后,所有依赖它的坐标自动重算。
  • 本例未包含末端执行器,如需扩展,只需再调用一次宏并传入新的prefix和尺寸即可,无需重复编写link/joint结构。