ROS2机器人仿真:urdf模型、gaezbo仿真

🕒 2025-09-18 📁 ROS系统 👤 laumy 🔥 206 热度

机器URDF模型

URDF 的全称是 Unified Robot Description Format(统一机器人描述格式)。它是 ROS / ROS2 系统里专门用来描述机器人结构和属性的一种 XML 格式文件。简单来说,URDF 就是“机器人说明书”,告诉 ROS:这个机器人长什么样、由哪些零件组成、它们之间怎么连接。

URDF核心作用是建模机器人、仿真可视化、运动学与动力学计算。一个带轮式的机器人URDF示例:

<robot name="simple_bot">
  <!-- 车体 -->
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.5 0.3 0.1"/>
      </geometry>
    </visual>
  </link>

  <!-- 左轮 -->
  <link name="left_wheel"/>
  <joint name="left_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="left_wheel"/>
    <origin xyz="0.2 0.15 0"/>
    <axis xyz="0 1 0"/>
  </joint>

  <!-- 右轮 -->
  <link name="right_wheel"/>
  <joint name="right_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="right_wheel"/>
    <origin xyz="0.2 -0.15 0"/>
    <axis xyz="0 1 0"/>
  </joint>
</robot>

创建一个URDF

(1)创建一个包

ros2 pkg create --build-type ament_python learn_urdf --dependencies rclpy robot_state_publisher joint_state_publisher_gui rviz2

(2)新建urdf和launch目录

主要用于存放URDF和launch文件。

cd learn_urdf
mkdir urdf launch

(3)编写urdf文件

进入urdf目录,创建simple_bot.urdf模型文件。

<?xml version="1.0"?>
<robot name="simple_bot">

  <!-- 车体 -->
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.5 0.3 0.1"/> <!-- 长0.5m 宽0.3m 高0.1m -->
      </geometry>
      <material name="gray">
        <color rgba="0.7 0.7 0.7 1.0"/>
      </material>
    </visual>
  </link>

  <!-- 左轮 -->
  <link name="left_wheel">
    <visual>
      <geometry>
        <cylinder radius="0.05" length="0.02"/> <!-- 半径0.05m 厚度0.02m -->
      </geometry>
      <!-- 旋转90度,让圆柱变成“轮子”横放 -->
      <origin xyz="0 0 0" rpy="1.5708 0 0"/>
      <material name="black">
        <color rgba="0 0 0 1.0"/>
      </material>
    </visual>
  </link>

  <joint name="left_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="left_wheel"/>
    <origin xyz="0.2 0.15 0"/> <!-- 相对于车体的位置 -->
    <axis xyz="0 0 1"/>        <!-- 绕Z轴旋转 -->
  </joint>

  <!-- 右轮 -->
  <link name="right_wheel">
    <visual>
      <geometry>
        <cylinder radius="0.05" length="0.02"/>
      </geometry>
      <origin xyz="0 0 0" rpy="1.5708 0 0"/>
      <material name="black">
        <color rgba="0 0 0 1.0"/>
      </material>
    </visual>
  </link>

  <joint name="right_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="right_wheel"/>
    <origin xyz="0.2 -0.15 0"/>
    <axis xyz="0 0 1"/>  <!-- 改成绕 Z 轴旋转 -->
  </joint>

</robot>

(4)创建launch文件

进入launch目录,编写display.launch.py文件

from launch import LaunchDescription
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory
import os

def generate_launch_description():
    # 找到 URDF 文件路径
    urdf_file = os.path.join(
        get_package_share_directory('learn_urdf'),
        'urdf',
        'simple_bot.urdf'
    )

    # 读取 URDF 文件
    with open(urdf_file, 'r') as infp:
        robot_desc = infp.read()

    # robot_state_publisher 节点
    rsp_node = Node(
        package='robot_state_publisher',
        executable='robot_state_publisher',
        output='screen',
        parameters=[{'robot_description': robot_desc}]
    )

    # joint_state_publisher_gui 节点(带GUI,可以动关节)
    jsp_node = Node(
        package='joint_state_publisher_gui',
        executable='joint_state_publisher_gui',
        name='joint_state_publisher_gui',
        output='screen'
    )

    # rviz2 节点
    rviz_node = Node(
        package='rviz2',
        executable='rviz2',
        name='rviz2',
        output='screen'
    )

    return LaunchDescription([rsp_node, jsp_node, rviz_node])

(5)配置setup.py

from setuptools import setup
import os
from glob import glob
......
    data_files=[
        # 让 ROS2 知道这个包的安装位置
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),

        # 安装 launch 文件
        (os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')),

        # 安装 urdf 文件
        (os.path.join('share', package_name, 'urdf'), glob('urdf/*.urdf')),
    ],
......

找到 setup.py,把里面的 data_files 部分改成上面那样,主要加入导入的模块。

(6)编译运行

cd ~/dev_ws

colcon build

source install/setup.bash

ros2 launch learn_urdf display.launch.py

执行上面命令后,就可以看到运行了rviz2,然后配置一下rviz2即可显示模型。

最后的效果就是这样,可以通过joint state publish调整轮子方向。

XACRO模型优化

XACRO是XML Macros,它是ROS 中对 URDF 的扩展,可以理解为 “带变量和函数的 URDF”。普通 URDF 是纯 XML,很死板,写起来很长;XACRO 在 URDF 的基础上加了变量、宏、表达式计算、条件/循环。

如下示例一个普通的URDF

<link name="leg1">
  <visual><geometry><cylinder radius="0.05" length="0.3"/></geometry></visual>
</link>

<link name="leg2">
  <visual><geometry><cylinder radius="0.05" length="0.3"/></geometry></visual>
</link>

有很多重复,如果用XACRO

<xacro:macro name="leg" params="name">
  <link name="${name}">
    <visual>
      <geometry>
        <cylinder radius="0.05" length="0.3"/>
      </geometry>
    </visual>
  </link>
</xacro:macro>

<xacro:leg name="leg1"/>
<xacro:leg name="leg2"/>

机器模型动起来

如果要让创建的模型能够动起来,那就要在Gazebo加载模型,然后通过/cmd_vel控制就可以让机器动起来了。

Gazebo是如何加载机器的模型了?

首先在xxx.launch.py中将机器的描述文件.xacro展开为标准的.urdf XML内容。然后会通过 robot_state_publisher 节点把这个 URDF 存到 ROS 参数服务器里/robot_description。

import xacro
robot_desc = xacro.process_file('simple_bot.urdf.xacro').toxml()

其次,Gazebo并不能直接解析 URDF,它使用的是 SDF (Simulation Description Format)。需要通过spawn_entity.py 读取 URDF → 转成 SDF。因此在launch文件中有看到spawn_entity.py。

ros2 run gazebo_ros spawn_entity.py -topic robot_description -entity simple_bot

最后Gazebo 根据 SDF 构建物理模型,比如SDF的link、joint等等。

运动控制

这里直接就不在演示完整创建过程了,直接使用示例程序。

ros2 launch learning_gazebo_harmonic load_urdf_into_gazebo_harmonic.launch.py

ros2 run teleop_twist_keyboard teleop_twist_keyboard

执行上面两个命令,就可以在控制终端i/j/k/l在仿真环境中控制机器人移动了。

相机仿真

可以给机器装上相机

ros2 launch learning_gazebo_harmonic load_mbot_camera_into_gazebo_harmonic.launch.py

ros2 run rviz2 rviz2

雷达仿真

ros2 launch learning_gazebo_harmonic load_mbot_lidar_into_gazebo_harmonic.launch.py

ros2 run rviz2 rviz2

附录:本文主要来自《ROS2智能机器人开发实践》笔记

发表你的看法

\t