3. 机器人建模与URDF

🤖 URDF 建模核心脉络 URDF 基础语法 link / joint / robot 几何 & 惯性 & 碰撞 <visual> <collision> 连杆 & 关节定义 固定 / 旋转 / 连续 父→子 坐标变换 运动学树 xacro 优化 宏定义 / 数学运算 参数化复用 → Rviz2 可视化 最终在 Rviz2 中实时显示机器人模型

好,咱们进入第三章。说到机器人建模,URDF 就是 ROS 世界里的“乐高说明书”。你想想看,没有模型,SLAM 和导航都不知道你的机器人长什么样、轮子在哪、激光雷达装多高。我个人习惯先把 URDF 基础啃透,后面调导航参数才不慌。

3.1 URDF 基础语法

URDF 全称 Unified Robot Description Format,说白了就是 XML 格式的机器人描述文件。根标签永远是 <robot>,里面主要装两种东西:link(连杆)和 joint(关节)。

我记得第一次写 URDF 时,把 link 和 joint 搞反了,结果 Rviz2 里机器人直接散架。后来养成了习惯:先画树状图,再写代码。

最简 URDF 骨架:
<robot name="my_robot">
    <link name="base_link">
        <visual>
            <geometry>
                <box size="0.4 0.3 0.1"/>
            </geometry>
        </visual>
    </link>
    <joint name="base_to_wheel" type="fixed">
        <parent link="base_link"/>
        <child link="left_wheel"/>
        <origin xyz="0.2 0 -0.05"/>
    </joint>
</robot>

每个 link 里可以定义 visual(可视化外观)、collision(碰撞模型)和 inertial(惯性参数)。导航中碰撞模型尤其重要——我曾经因为偷懒没写 collision,导致导航规划时机器人“穿模”穿过障碍物。

3.2 连杆与关节定义

关节类型有六种,但咱们做轮式机器人最常用的是 fixed(固定关节)和 continuous(连续旋转关节,比如轮子)。joint 里必须指定 parent 和 child,这就构成了机器人的运动学树。

关节类型说明典型用途
fixed刚性连接,无自由度底盘与激光雷达支架
revolute绕单轴旋转,有角度限位关节臂、舵机
continuous绕单轴无限旋转车轮、全向轮
prismatic沿单轴平移升降机构、滑轨
floating6自由度浮动无人机、多机器人
planar平面内3自由度全向底盘(较少用)
定义车轮关节时,记得把 <axis xyz="0 0 1"/> 设置正确。我遇到过好几次轮子转轴方向反了,机器人原地打转——检查 axis 是最快的排障方法。

3.3 xacro 优化:告别重复劳动

URDF 写多了你会发现,左右轮子除了名字和坐标,其他几乎一样。这时候 xacro 就派上用场了。xacro 是 URDF 的宏预处理工具,支持数学运算、条件判断、宏定义。

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="robot">
    <xacro:macro name="wheel" params="name x y">
        <link name="${name}">
            <visual>
                <geometry><cylinder radius="0.05" length="0.03"/></geometry>
            </visual>
        </link>
        <joint name="${name}_joint" type="continuous">
            <parent link="base_link"/>
            <child link="${name}"/>
            <origin xyz="${x} ${y} -0.02"/>
            <axis xyz="0 1 0"/>
        </joint>
    </xacro:macro>

    <xacro:wheel name="left_wheel" x="0.15" y="0.2"/>
    <xacro:wheel name="right_wheel" x="0.15" y="-0.2"/>
</robot>

你看,用宏定义之后,加两个轮子只需要两行。我个人习惯把传感器、轮子、支架都写成独立的 xacro 文件,然后用 <xacro:include> 组合。这样维护起来特别清爽。

xacro 文件后缀名建议用 .xacro,但 launch 文件中引用时要用 urdf 类型。我曾经在这里卡了半小时——launch 里写错后缀,Rviz2 一直报错找不到模型。

3.4 在 Rviz2 中可视化模型

模型写好了,怎么看到它?用 robot_state_publisher 节点把 URDF 发布到 TF 树,然后在 Rviz2 中添加 RobotModel 显示。我常用的 launch 文件长这样:

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='robot_state_publisher',
            executable='robot_state_publisher',
            arguments=['my_robot.urdf']
        ),
        Node(
            package='joint_state_publisher_gui',
            executable='joint_state_publisher_gui'
        ),
        Node(
            package='rviz2',
            executable='rviz2',
            arguments=['-d', 'my_config.rviz']
        )
    ])

启动后,你应该能在 Rviz2 中看到机器人模型。如果模型显示为红色或报错“No transform from …”,八成是 TF 树没连上。检查 joint 的 parent 和 child 名称是否一致——我犯过把 base_link 拼成 base_linkk 的低级错误。

避坑指南(来自我的血泪史):
  • 所有 link 和 joint 名称不要用中文、空格、特殊符号。
  • inertial 参数不能省略,否则 gazebo 仿真会崩溃。对于不动的 link,给一个极小的惯性值就行。
  • 使用 check_urdf 工具验证文件:check_urdf my_robot.urdf,它会输出树状结构,一眼看出断链。

嗯,URDF 建模其实不难,但细节特别多。我每次搭建新机器人,都会先花半小时把模型调通,再开始搞 SLAM 和导航。模型准了,后面所有环节都顺。