URDF(Unified Robot Description Format),这是机器人领域中用于描述机器人模型的标准 XML 格式。

1. URDF 概述

URDF 是 ROS(Robot Operating System)中用于描述机器人结构的标准格式。它使用 XML 格式定义机器人的:

  • 连杆(Links):机器人的刚性部件
  • 关节(Joints):连接连杆的运动副
  • 运动学结构:连杆与关节的层级关系
  • 物理属性:质量、惯性、碰撞体积等
  • 视觉属性:3D 模型外观

2. URDF 核心元素详解

2.1 基本结构

<?xml version="1.0"?>
<robot name="my_robot">
    <!-- 材料定义 -->
    <material name="blue">
        <color rgba="0 0 0.8 1"/>
    </material>
    
    <!-- 连杆定义 -->
    <link name="base_link">
        ...
    </link>
    
    <!-- 关节定义 -->
    <joint name="joint1" type="revolute">
        ...
    </joint>
    
    <!-- 传动装置(可选) -->
    <transmission name="trans1">
        ...
    </transmission>
</robot>

2.2 Link(连杆)详解

<link> 定义机器人的一个刚性部件,包含三个主要子元素:

<link name="link_name">
    <!-- 1. 惯性属性(动力学必需) -->
    <inertial>
        <origin xyz="0 0 0.5" rpy="0 0 0"/>  <!-- 质心相对于link坐标系 -->
        <mass value="10"/>                    <!-- 质量 (kg) -->
        <inertia ixx="0.4" ixy="0" ixz="0"   <!-- 惯性张量 (kg·m²) -->
                 iyy="0.4" iyz="0"
                 izz="0.2"/>
    </inertial>
    
    <!-- 2. 视觉属性(显示用) -->
    <visual>
        <origin xyz="0 0 0" rpy="0 0 0"/>    <!-- 视觉原点偏移 -->
        <geometry>
            <!-- 基本几何体 -->
            <box size="1 2 3"/>              <!-- 长方体 -->
            <cylinder radius="0.5" length="2"/> <!-- 圆柱体 -->
            <sphere radius="1"/>             <!-- 球体 -->
            <!-- 或外部网格 -->
            <mesh filename="package://pkg/mesh.dae" scale="1 1 1"/>
        </geometry>
        <material name="blue"/>              <!-- 引用或内联材质 -->
    </visual>
    
    <!-- 3. 碰撞属性(碰撞检测用,通常简化) -->
    <collision>
        <origin xyz="0 0 0" rpy="0 0 0"/>
        <geometry>
            <box size="1.1 2.1 3.1"/>        <!-- 通常比视觉模型简单 -->
        </geometry>
    </collision>
</link>

关键属性说明:

  • origin:使用 xyz(位置,单位米)和 rpy(roll-pitch-yaw 欧拉角,单位弧度)定义偏移
  • inertia:3x3 对称惯性矩阵的 6 个独立分量
  • mesh:支持 .dae(COLLADA)、.stl.obj 格式

2.3 Joint(关节)详解

<joint> 定义两个连杆之间的连接关系和运动约束:

<joint name="joint_name" type="revolute">
    <!-- 父连杆(参考坐标系) -->
    <parent link="parent_link_name"/>
    
    <!-- 子连杆(随关节运动) -->
    <child link="child_link_name"/>
    
    <!-- 关节坐标系原点(相对于父连杆) -->
    <origin xyz="0 0 1" rpy="0 0 0"/>
    
    <!-- 关节轴方向(相对于关节坐标系,单位向量) -->
    <axis xyz="0 0 1"/>
    
    <!-- 关节限制(部分类型必需) -->
    <limit lower="-3.14" upper="3.14" 
           effort="100" velocity="10"/>
    
    <!-- 动力学属性(可选) -->
    <dynamics damping="0.5" friction="0.1"/>
    
    <!-- 安全性限制(可选) -->
    <safety_controller soft_lower_limit="-3.0"
                       soft_upper_limit="3.0"
                       k_position="100"
                       k_velocity="10"/>
    
    <!-- 校准信息(可选) -->
    <calibration rising="0.0" falling="0.0"/>
    <mimic joint="other_joint" multiplier="1" offset="0"/>
</joint>

关节类型(type):

类型 说明 约束
revolute 旋转关节(有角度限制) <limit> 必需
continuous 连续旋转关节(无限制) 无上下限
prismatic 滑动关节(线性运动) <limit> 必需
fixed 固定关节(无运动) 常用于连接静态部件
floating 6自由度浮动关节 用于基座或浮动基
planar 平面运动关节(2自由度) 在平面内移动
spherical 球关节(3自由度旋转) 使用四元数表示

2.4 Transmission(传动装置)

用于连接关节与执行器(电机),在 Gazebo 仿真中必需:

<transmission name="arm_trans">
    <type>transmission_interface/SimpleTransmission</type>
    <joint name="arm_joint">
        <hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
    </joint>
    <actuator name="arm_motor">
        <hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
        <mechanicalReduction>1</mechanicalReduction>
    </actuator>
</transmission>

2.5 Gazebo 扩展标签

用于仿真环境的特定属性:

<!-- 在 <robot> 内 -->
<gazebo>
    <static>true</static>  <!-- 是否静态物体 -->
</gazebo>

<!-- 在 <link> 内 -->
<gazebo reference="link_name">
    <material>Gazebo/Orange</material>  <!-- Gazebo材质 -->
    <mu1>0.5</mu1>                      <!-- 摩擦系数 -->
    <mu2>0.5</mu2>
    <kp>1000000.0</kp>                  <!-- 接触刚度 -->
    <kd>1.0</kd>                        <!-- 接触阻尼 -->
    <selfCollide>true</selfCollide>     <!-- 自碰撞检测 -->
    <gravity>true</gravity>             <!-- 受重力影响 -->
</gazebo>

<!-- 在 <joint> 内 -->
<gazebo reference="joint_name">
    <provideFeedback>true</provideFeedback>
    <implicitSpringDamper>true</implicitSpringDamper>
</gazebo>

3. 完整示例:简易机械臂

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

    <!-- 基础材料 -->
    <material name="blue">
        <color rgba="0.0 0.0 0.8 1.0"/>
    </material>
    <material name="grey">
        <color rgba="0.5 0.5 0.5 1.0"/>
    </material>

    <!-- ========== 基座 ========== -->
    <link name="base_link">
        <visual>
            <geometry>
                <cylinder radius="0.2" length="0.1"/>
            </geometry>
            <material name="grey"/>
        </visual>
        <collision>
            <geometry>
                <cylinder radius="0.2" length="0.1"/>
            </geometry>
        </collision>
        <inertial>
            <mass value="5.0"/>
            <inertia ixx="0.052" ixy="0" ixz="0"
                     iyy="0.052" iyz="0"
                     izz="0.1"/>
        </inertial>
    </link>

    <!-- ========== 连杆1 ========== -->
    <link name="link1">
        <visual>
            <origin xyz="0 0 0.5" rpy="0 0 0"/>
            <geometry>
                <cylinder radius="0.05" length="1.0"/>
            </geometry>
            <material name="blue"/>
        </visual>
        <collision>
            <origin xyz="0 0 0.5" rpy="0 0 0"/>
            <geometry>
                <cylinder radius="0.05" length="1.0"/>
            </geometry>
        </collision>
        <inertial>
            <origin xyz="0 0 0.5" rpy="0 0 0"/>
            <mass value="2.0"/>
            <inertia ixx="0.168" ixy="0" ixz="0"
                     iyy="0.168" iyz="0"
                     izz="0.0025"/>
        </inertial>
    </link>

    <!-- 关节1:基座旋转 -->
    <joint name="joint1" type="revolute">
        <parent link="base_link"/>
        <child link="link1"/>
        <origin xyz="0 0 0.05" rpy="0 0 0"/>
        <axis xyz="0 0 1"/>
        <limit lower="-3.14" upper="3.14" effort="100" velocity="2.0"/>
        <dynamics damping="0.5" friction="0.1"/>
    </joint>

    <!-- ========== 连杆2 ========== -->
    <link name="link2">
        <visual>
            <origin xyz="0 0 0.4" rpy="0 0 0"/>
            <geometry>
                <box size="0.1 0.1 0.8"/>
            </geometry>
            <material name="grey"/>
        </visual>
        <collision>
            <origin xyz="0 0 0.4" rpy="0 0 0"/>
            <geometry>
                <box size="0.1 0.1 0.8"/>
            </geometry>
        </collision>
        <inertial>
            <origin xyz="0 0 0.4" rpy="0 0 0"/>
            <mass value="1.5"/>
            <inertia ixx="0.08" ixy="0" ixz="0"
                     iyy="0.08" iyz="0"
                     izz="0.0025"/>
        </inertial>
    </link>

    <!-- 关节2:俯仰关节 -->
    <joint name="joint2" type="revolute">
        <parent link="link1"/>
        <child link="link2"/>
        <origin xyz="0 0 1.0" rpy="0 0 0"/>
        <axis xyz="0 1 0"/>
        <limit lower="-1.57" upper="1.57" effort="50" velocity="1.0"/>
    </joint>

    <!-- ========== 末端执行器 ========== -->
    <link name="end_effector">
        <visual>
            <geometry>
                <sphere radius="0.05"/>
            </geometry>
            <material name="blue"/>
        </visual>
        <inertial>
            <mass value="0.5"/>
            <inertia ixx="0.0005" ixy="0" ixz="0"
                     iyy="0.0005" iyz="0"
                     izz="0.0005"/>
        </inertial>
    </link>

    <joint name="fixed_joint" type="fixed">
        <parent link="link2"/>
        <child link="end_effector"/>
        <origin xyz="0 0 0.8" rpy="0 0 0"/>
    </joint>

    <!-- 传动装置(用于Gazebo) -->
    <transmission name="trans1">
        <type>transmission_interface/SimpleTransmission</type>
        <joint name="joint1">
            <hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
        </joint>
        <actuator name="motor1">
            <hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
            <mechanicalReduction>1</mechanicalReduction>
        </actuator>
    </transmission>

    <transmission name="trans2">
        <type>transmission_interface/SimpleTransmission</type>
        <joint name="joint2">
            <hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
        </joint>
        <actuator name="motor2">
            <hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
            <mechanicalReduction>1</mechanicalReduction>
        </actuator>
    </transmission>

    <!-- Gazebo插件:ROS控制 -->
    <gazebo>
        <plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
            <robotNamespace>/simple_arm</robotNamespace>
        </plugin>
    </gazebo>

</robot>

4. URDF 的局限性与 Xacro

4.1 URDF 的局限性

  1. 代码重复:相似连杆/关节需重复编写
  2. 无参数化:无法使用变量和数学表达式
  3. 无条件逻辑:无法根据条件生成不同结构
  4. 无模块化:难以复用和组合子组件
  5. 闭链结构:无法描述并联机构(闭链运动学)

4.2 Xacro(XML Macros)

Xacro 是 URDF 的宏扩展,解决上述问题:

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

    <!-- ===== 属性定义(参数) ===== -->
    <xacro:property name="pi" value="3.14159"/>
    <xacro:property name="wheel_radius" value="0.1"/>
    <xacro:property name="wheel_width" value="0.05"/>
    <xacro:property name="chassis_length" value="0.5"/>

    <!-- ===== 宏定义(模板) ===== -->
    <xacro:macro name="wheel" params="prefix side reflect">
        <link name="${prefix}_wheel_link">
            <visual>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_width}"/>
                </geometry>
                <material name="black"/>
            </visual>
            <collision>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_width}"/>
                </geometry>
            </collision>
            <inertial>
                <mass value="0.5"/>
                <inertia ixx="${0.5 * 0.5 * wheel_radius * wheel_radius}" 
                         ixy="0" ixz="0"
                         iyy="${0.5 * 0.5 * wheel_radius * wheel_radius}" 
                         iyz="0"
                         izz="${0.5 * wheel_radius * wheel_radius}"/>
            </inertial>
        </link>
        
        <joint name="${prefix}_wheel_joint" type="continuous">
            <parent link="chassis"/>
            <child link="${prefix}_wheel_link"/>
            <origin xyz="${reflect * chassis_length/2} 0 ${wheel_radius}" 
                    rpy="${-pi/2} 0 0"/>
            <axis xyz="0 0 1"/>
        </joint>
    </xacro:macro>

    <!-- ===== 使用宏 ===== -->
    <xacro:wheel prefix="left" side="left" reflect="1"/>
    <xacro:wheel prefix="right" side="right" reflect="-1"/>

    <!-- ===== 数学运算 ===== -->
    <link name="chassis">
        <visual>
            <geometry>
                <box size="${chassis_length} 0.3 0.1"/>
            </geometry>
        </visual>
    </link>

    <!-- ===== 包含其他文件 ===== -->
    <xacro:include filename="$(find pkg)/urdf/sensors.urdf.xacro"/>
    <xacro:lidar_sensor parent="chassis"/>

</robot>

Xacro 编译命令:

# 将 xacro 转换为纯 URDF
rosrun xacro xacro robot.xacro > robot.urdf

# 或
xacro robot.xacro -o robot.urdf

5. 验证与可视化工具

5.1 语法检查

# 检查 URDF 语法
check_urdf robot.urdf

# 解析并显示结构
urdf_to_graphiz robot.urdf  # 生成 PDF 结构图

5.2 可视化工具

# RViz 可视化(ROS1)
roslaunch urdf_tutorial display.launch model:=robot.urdf

# 或使用 joint_state_publisher_gui 调整关节
roslaunch urdf_tutorial display.launch model:=robot.urdf gui:=true

5.3 Python 解析

import xml.etree.ElementTree as ET

# 解析 URDF
tree = ET.parse('robot.urdf')
root = tree.getroot()

# 遍历所有连杆
for link in root.findall('link'):
    name = link.get('name')
    print(f"Link: {name}")
    
    # 获取质量
    inertial = link.find('inertial')
    if inertial is not None:
        mass = inertial.find('mass')
        if mass is not None:
            print(f"  Mass: {mass.get('value')} kg")

# 遍历所有关节
for joint in root.findall('joint'):
    name = joint.get('name')
    jtype = joint.get('type')
    parent = joint.find('parent').get('link')
    child = joint.find('child').get('link')
    print(f"Joint: {name} ({jtype}) - {parent} -> {child}")

6. URDF vs SDF

特性 URDF SDF (Simulation Description Format)
设计目标 机器人描述(ROS) 通用仿真场景(Gazebo)
闭链结构 不支持 支持
多机器人 单机器人 支持多机器人/环境
传感器定义 有限 丰富
插件系统 简单 完整
世界描述 不支持 支持(光照、物理属性等)

转换工具:

# URDF 转 SDF
gz sdf -p robot.urdf > robot.sdf

7. 最佳实践

  1. 命名规范:使用有意义的名称(left_arm_joint 而非 joint1
  2. 坐标系一致性:遵循 REP-103 标准(x-前,y-左,z-上)
  3. 碰撞简化:使用基本几何体替代复杂网格进行碰撞检测
  4. 惯性准确性:确保质量和惯性张量基于真实物理参数
  5. 使用 Xacro:对于复杂机器人,始终使用 Xacro 提高可维护性
  6. 版本控制:将 URDF/Xacro 纳入版本控制系统
  7. 模块化设计:将复杂机器人拆分为多个 xacro 文件

URDF 是 ROS 机器人开发的基石,掌握它对于机器人建模、仿真和控制至关重要。对于更复杂的应用,建议结合 Xacro 和 SDF 使用。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐