【ROS2】中级:URDF-从头开始构建可见机器人模型

URDF(统一机器人描述格式)是一种用于在 ROS 中指定机器人几何和组织的文件格式。

  • 从头开始构建可见机器人模型

  • 构建一个可移动的机器人模型

  • 添加物理和碰撞属性

  • 使用 Xacro 清理您的代码

  • 使用 URDF 与 robot_state_publisher

  • 生成 URDF 文件

从头开始构建visual机器人模型

目标:学习如何构建一个可以在 Rviz 中查看的机器人visual模型

教程级别:中级

时间:20 分钟

目录

  • 一种形状

  • 多种形状

  • 起源

  • 材质女孩

  • 完成模型

便条

本教程假设您知道如何编写格式良好的 XML 代码

在本教程中,我们将构建一个大致看起来像 R2D2 的机器人视觉模型。在后续教程中,您将学习如何表达模型 https://docs.ros.org/en/jazzy/Tutorials/Intermediate/URDF/Building-a-Movable-Robot-Model-with-URDF.html ,添加一些物理属性 https://docs.ros.org/en/jazzy/Tutorials/Intermediate/URDF/Adding-Physical-and-Collision-Properties-to-a-URDF-Model.html ,并使用 xacro 生成更整洁的代码 https://docs.ros.org/en/jazzy/Tutorials/Intermediate/URDF/Using-Xacro-to-Clean-Up-a-URDF-File.html ,但现在,我们将专注于使视觉几何正确。

在继续之前,请确保已安装 joint_state_publisher 软件包https://index.ros.org/p/joint_state_publisher 。如果您安装了 urdf_tutorial 二进制文件 https://index.ros.org/p/urdf_tutorial/ ,这应该已经是这种情况。如果没有,请更新您的安装以包含该软件包(使用 rosdep 进行检查)。

本教程中提到的所有机器人模型(以及源文件)都可以在 urdf_tutorial 包中找到。https://github.com/ros/urdf_tutorial/tree/ros2/ 源码下载

一种形状

首先,我们将探索一个简单的形状。这是你能制作的最简单的 urdf 之一。[来源:01-myfirst.urdf]

xml 复制代码
<?xml version="1.0"?> <!-- 声明 XML 版本为 1.0 -->
<robot name="myfirst"> <!-- 定义一个名为 "myfirst" 的机器人 -->
  <link name="base_link"> <!-- 定义一个名为 "base_link" 的链接 -->
    <visual> <!-- 定义视觉元素 -->
      <geometry> <!-- 定义几何形状 -->
        <cylinder length="0.6" radius="0.2"/> <!-- 定义一个长度为 0.6,半径为 0.2 的圆柱体 -->
      </geometry>
    </visual>
  </link>
</robot>

要将 XML 翻译成英文,这是一个名为 myfirst 的机器人,它只包含一个Link(即部分),其视觉组件只是一个长 0.6 米、半径 0.2 米的圆柱体。这对于一个简单的"hello world"类型的示例来说,可能看起来有很多封闭标签,但它会变得更复杂,相信我。

要检查模型,请启动 display.launch.py 文件:

python 复制代码
from launch import LaunchDescription  # 从launch模块导入LaunchDescription类
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription  # 从launch.actions模块导入DeclareLaunchArgument和IncludeLaunchDescription类
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution  # 从launch.substitutions模块导入LaunchConfiguration和PathJoinSubstitution类
from launch_ros.substitutions import FindPackageShare  # 从launch_ros.substitutions模块导入FindPackageShare类


def generate_launch_description():  # 定义一个名为generate_launch_description的函数
    ld = LaunchDescription()  # 创建一个LaunchDescription对象


    urdf_tutorial_path = FindPackageShare('urdf_tutorial')  # 查找urdf_tutorial包的共享路径
    default_model_path = PathJoinSubstitution(['urdf', '01-myfirst.urdf'])  # 拼接默认的URDF模型路径
    default_rviz_config_path = PathJoinSubstitution([urdf_tutorial_path, 'rviz', 'urdf.rviz'])  # 拼接默认的RViz配置文件路径


    # 这些参数是为了向后兼容而保留的
    gui_arg = DeclareLaunchArgument(name='gui', default_value='true', choices=['true', 'false'],
                                    description='Flag to enable joint_state_publisher_gui')  # 声明一个名为gui的启动参数,默认值为true,可选值为true或false,描述为启用joint_state_publisher_gui的标志
    ld.add_action(gui_arg)  # 将gui_arg添加到LaunchDescription对象中
    rviz_arg = DeclareLaunchArgument(name='rvizconfig', default_value=default_rviz_config_path,
                                     description='Absolute path to rviz config file')  # 声明一个名为rvizconfig的启动参数,默认值为default_rviz_config_path,描述为RViz配置文件的绝对路径
    ld.add_action(rviz_arg)  # 将rviz_arg添加到LaunchDescription对象中


    # 这个参数的含义与以前的版本略有不同
    ld.add_action(DeclareLaunchArgument(name='model', default_value=default_model_path,
                                        description='Path to robot urdf file relative to urdf_tutorial package'))  # 声明一个名为model的启动参数,默认值为default_model_path,描述为相对于urdf_tutorial包的机器人URDF文件路径


    ld.add_action(IncludeLaunchDescription(
        PathJoinSubstitution([FindPackageShare('urdf_launch'), 'launch', 'display.launch.py']),  # 包含另一个启动文件display.launch.py
        launch_arguments={
            'urdf_package': 'urdf_tutorial',  # 设置urdf_package参数为urdf_tutorial
            'urdf_package_path': LaunchConfiguration('model'),  # 设置urdf_package_path参数为model启动参数的值
            'rviz_config': LaunchConfiguration('rvizconfig'),  # 设置rviz_config参数为rvizconfig启动参数的值
            'jsp_gui': LaunchConfiguration('gui')}.items()  # 设置jsp_gui参数为gui启动参数的值
    ))


    return ld  # 返回LaunchDescription对
python 复制代码
# display.launch.py
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.actions import IncludeLaunchDescription
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution


from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare


# 生成启动描述函数
def generate_launch_description():
    ld = LaunchDescription()  # 创建一个LaunchDescription对象


    urdf_launch_package = FindPackageShare('urdf_launch')  # 查找urdf_launch包的共享路径


    # 添加启动参数,用于启用joint_state_publisher_gui
    ld.add_action(DeclareLaunchArgument(name='jsp_gui', default_value='true', choices=['true', 'false'],
                                        description='Flag to enable joint_state_publisher_gui'))


    # 设置rviz配置文件的默认路径
    default_rviz_config_path = PathJoinSubstitution([urdf_launch_package, 'config', 'urdf.rviz'])
    ld.add_action(DeclareLaunchArgument(name='rviz_config', default_value=default_rviz_config_path,
                                        description='Absolute path to rviz config file'))


    # 由于https://github.com/ros2/launch/issues/313,需要手动传递配置
    ld.add_action(IncludeLaunchDescription(
        PathJoinSubstitution([urdf_launch_package, 'launch', 'description.launch.py']),
        launch_arguments={
            'urdf_package': LaunchConfiguration('urdf_package'),
            'urdf_package_path': LaunchConfiguration('urdf_package_path')}.items()
    ))


    # 根据gui参数,启动joint_state_publisher或joint_state_publisher_gui
    ld.add_action(Node(
        package='joint_state_publisher',
        executable='joint_state_publisher',
        condition=UnlessCondition(LaunchConfiguration('jsp_gui'))
    ))


    ld.add_action(Node(
        package='joint_state_publisher_gui',
        executable='joint_state_publisher_gui',
        condition=IfCondition(LaunchConfiguration('jsp_gui'))
    ))


    # 启动rviz2节点
    ld.add_action(Node(
        package='rviz2',
        executable='rviz2',
        output='screen',
        arguments=['-d', LaunchConfiguration('rviz_config')],
    ))
    return ld  # 返回LaunchDescription对象
nginx 复制代码
ros2 launch urdf_tutorial display.launch.py model:=urdf/01-myfirst.urdf

这做了三件事:

  • 加载指定的模型并将其保存为 robot_state_publisher 节点的参数。

  • 运行节点以发布 sensor_msgs/msg/JointState 和变换(稍后会详细介绍)

  • 使用配置文件启动 Rviz

启动 display.launch.py 后,您应该会看到 RViz 显示以下内容:

  • 注意事项:

    • 固定框架是网格中心所在的变换框架。在这里,它是由我们的一个链接 base_link 定义的框架。

    • 视觉元素(圆柱体)的原点默认位于其几何中心。因此,圆柱体的一半位于网格下方。

多种形状

现在让我们看看如何添加多个形状/链接。如果我们只是向 urdf 中添加更多的链接元素,解析器将不知道将它们放在哪里。因此,我们必须添加关节。关节元素可以指灵活和不灵活的关节。我们将从不灵活的或固定的关节开始。[来源:02-multipleshapes.urdf]

xml 复制代码
<?xml version="1.0"?>
<!-- 定义XML版本 -->
<robot name="multipleshapes">
  <!-- 定义机器人名称为multipleshapes -->
  <link name="base_link">
    <!-- 定义一个名为base_link的链接 -->
    <visual>
      <!-- 定义视觉元素 -->
      <geometry>
        <!-- 定义几何形状 -->
        <cylinder length="0.6" radius="0.2"/>
        <!-- 定义一个圆柱体,长度为0.6,半径为0.2 -->
      </geometry>
    </visual>
  </link>


  <link name="right_leg">
    <!-- 定义一个名为right_leg的链接 -->
    <visual>
      <!-- 定义视觉元素 -->
      <geometry>
        <!-- 定义几何形状 -->
        <box size="0.6 0.1 0.2"/>
        <!-- 定义一个长方体,尺寸为0.6x0.1x0.2 -->
      </geometry>
    </visual>
  </link>


  <joint name="base_to_right_leg" type="fixed">
    <!-- 定义一个名为base_to_right_leg的关节,类型为固定 -->
    <parent link="base_link"/>
    <!-- 定义父链接为base_link -->
    <child link="right_leg"/>
    <!-- 定义子链接为right_leg -->
  </joint>


</robot>
<!-- 结束机器人定义 -->
  • 注意我们如何定义一个 0.6 米 x 0.1 米 x 0.2 米的盒子。

  • 关节是根据父节点和子节点来定义的。URDF 最终是一个具有一个根链接的树结构。这意味着腿的位置取决于 base_link 的位置。

nginx 复制代码
ros2 launch urdf_tutorial display.launch.py model:=urdf/02-multipleshapes.urdf

这两个形状彼此重叠,因为它们共享相同的原点。如果我们不希望它们重叠,我们必须定义更多的原点。

原点 Origin

R2D2 的腿连接到躯干的上半部分,在侧面。所以我们将关节的原点指定在那里。此外,它不是连接到腿的中间,而是连接到上部,所以我们也必须为腿的原点设置偏移。我们还将腿旋转,使其直立。[来源:03-origins.urdf]

xml 复制代码
<?xml version="1.0"?>
<robot name="origins">
  <!-- 定义一个名为base_link的链接 -->
  <link name="base_link">
    <visual>
      <geometry>
        <!-- 定义一个圆柱体,长度为0.6,半径为0.2 -->
        <cylinder length="0.6" radius="0.2"/>
      </geometry>
    </visual>
  </link>


  <!-- 定义一个名为right_leg的链接 -->
  <link name="right_leg">
    <visual>
      <geometry>
        <!-- 定义一个长方体,尺寸为0.6 0.1 0.2 -->
        <box size="0.6 0.1 0.2"/>
      </geometry>
      <!-- 设置视觉元素的原点,绕Y轴旋转90度,沿Z轴平移-0.3 -->
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
    </visual>
  </link>


  <!-- 定义一个名为base_to_right_leg的固定关节 -->
  <joint name="base_to_right_leg" type="fixed">
    <!-- 父链接为base_link -->
    <parent link="base_link"/>
    <!-- 子链接为right_leg -->
    <child link="right_leg"/>
    <!-- 设置关节的原点,沿Y轴平移-0.22,沿Z轴平移0.25 -->
    <origin xyz="0 -0.22 0.25"/>
  </joint>


</robot>
  • 让我们首先**检查关节的原点。**它是根据父参考系定义的。因此,我们在 y 方向上是 -0.22 米(向我们的左边,但相对于轴向右),在 z 方向上是 0.25 米(向上)。这意味着子 link 的原点将向上和向右,无论子链接的视觉原点标签如何。由于我们没有指定 rpy(滚转俯仰偏航)属性,子框架默认将具有与父框架相同的方向。

  • 现在,看看腿的视觉原点,它有一个 xyz 和 rpy 偏移。这定义了视觉元素的中心相对于其原点的位置。由于我们希望腿部连接在顶部,我们通过将 z 偏移设置为 -0.3 米来向下偏移原点。由于我们希望腿的长部分与 z 轴平行,我们将视觉部分绕 Y 轴旋转 PI/2。

nginx 复制代码
ros2 launch urdf_tutorial display.launch.py model:=urdf/03-origins.urdf
  • 启动文件运行包,这些包将根据您的 URDF 为模型中的每个链接创建 TF 框架。Rviz 使用这些信息来确定显示每个形状的位置。

  • **如果给定的 URDF 链接不存在 TF 框架,那么它将被放置在原点处显示为白色(**参考相关问题)。

材质女孩

"好吧,"我听到你说。"那很可爱,但不是每个人都有 B21。我的机器人和 R2D2 不是红色的!" 这是一个很好的观点。让我们看看材质标签。[来源:04-materials.urdf]

xml 复制代码
<?xml version="1.0"?>
<!-- 定义XML版本 -->
<robot name="materials">
  <!-- 定义机器人名称为materials -->


  <material name="blue">
    <!-- 定义一个名为blue的材质 -->
    <color rgba="0 0 0.8 1"/>
    <!-- 定义颜色为蓝色,RGBA值为(0, 0, 0.8, 1) -->
  </material>


  <material name="white">
    <!-- 定义一个名为white的材质 -->
    <color rgba="1 1 1 1"/>
    <!-- 定义颜色为白色,RGBA值为(1, 1, 1, 1) -->
  </material>


  <link name="base_link">
    <!-- 定义一个名为base_link的链接 -->
    <visual>
      <!-- 定义视觉元素 -->
      <geometry>
        <!-- 定义几何形状 -->
        <cylinder length="0.6" radius="0.2"/>
        <!-- 定义一个圆柱体,长度为0.6,半径为0.2 -->
      </geometry>
      <material name="blue"/>
      <!-- 使用名为blue的材质 -->
    </visual>
  </link>


  <link name="right_leg">
    <!-- 定义一个名为right_leg的链接 -->
    <visual>
      <!-- 定义视觉元素 -->
      <geometry>
        <!-- 定义几何形状 -->
        <box size="0.6 0.1 0.2"/>
        <!-- 定义一个长方体,尺寸为0.6x0.1x0.2 -->
      </geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
      <!-- 定义视觉元素的原点,绕x轴旋转0度,绕y轴旋转1.57075弧度,绕z轴旋转0度,位置为(0, 0, -0.3) -->
      <material name="white"/>
      <!-- 使用名为white的材质 -->
    </visual>
  </link>


  <joint name="base_to_right_leg" type="fixed">
    <!-- 定义一个名为base_to_right_leg的关节,类型为固定 -->
    <parent link="base_link"/>
    <!-- 定义父链接为base_link -->
    <child link="right_leg"/>
    <!-- 定义子链接为right_leg -->
    <origin xyz="0 -0.22 0.25"/>
    <!-- 定义关节的原点,位置为(0, -0.22, 0.25) -->
  </joint>


  <link name="left_leg">
    <!-- 定义一个名为left_leg的链接 -->
    <visual>
      <!-- 定义视觉元素 -->
      <geometry>
        <!-- 定义几何形状 -->
        <box size="0.6 0.1 0.2"/>
        <!-- 定义一个长方体,尺寸为0.6x0.1x0.2 -->
      </geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
      <!-- 定义视觉元素的原点,绕x轴旋转0度,绕y轴旋转1.57075弧度,绕z轴旋转0度,位置为(0, 0, -0.3) -->
      <material name="white"/>
      <!-- 使用名为white的材质 -->
    </visual>
  </link>


  <joint name="base_to_left_leg" type="fixed">
    <!-- 定义一个名为base_to_left_leg的关节,类型为固定 -->
    <parent link="base_link"/>
    <!-- 定义父链接为base_link -->
    <child link="left_leg"/>
    <!-- 定义子链接为left_leg -->
    <origin xyz="0 0.22 0.25"/>
    <!-- 定义关节的原点,位置为(0, 0.22, 0.25) -->
  </joint>


</robot>
<!-- 结束机器人定义 -->
  • 现在身体是蓝色的。我们定义了一种称为"蓝色"的新材料,其红色、绿色、蓝色和 alpha 通道分别定义为 0、0、0.8 和 1。所有值都可以在 [0,1] 范围内。然后,该材料由 base_link 的视觉元素引用。白色材料的定义类似。

  • 您还可以在视觉元素中定义材料标签,甚至在其他链接中引用它。不过,即使您重新定义它,也不会有人抱怨。

  • 您还可以使用纹理来指定用于为对象着色的图像文件

nginx 复制代码
ros2 launch urdf_tutorial display.launch.py model:=urdf/04-materials.urdf

完成模型

现在我们用一些更多的形状来完成模型:脚、轮子和头。最值得注意的是,我们添加了一个球体和一些网格。我们还会添加一些其他的部件,以便以后使用。[来源:05-visual.urdf]

xml 复制代码
<?xml version="1.0"?>
<!-- 定义XML版本 -->
<robot name="visual">
  <!-- 定义机器人名称为visual -->


  <material name="blue">
    <!-- 定义一个名为blue的材质 -->
    <color rgba="0 0 0.8 1"/>
    <!-- 定义颜色为蓝色,RGBA值为(0, 0, 0.8, 1) -->
  </material>
  <material name="black">
    <!-- 定义一个名为black的材质 -->
    <color rgba="0 0 0 1"/>
    <!-- 定义颜色为黑色,RGBA值为(0, 0, 0, 1) -->
  </material>
  <material name="white">
    <!-- 定义一个名为white的材质 -->
    <color rgba="1 1 1 1"/>
    <!-- 定义颜色为白色,RGBA值为(1, 1, 1, 1) -->
  </material>


  <link name="base_link">
    <!-- 定义一个名为base_link的链接 -->
    <visual>
      <!-- 定义视觉元素 -->
      <geometry>
        <!-- 定义几何形状 -->
        <cylinder length="0.6" radius="0.2"/>
        <!-- 定义一个圆柱体,长度为0.6,半径为0.2 -->
      </geometry>
      <material name="blue"/>
      <!-- 使用名为blue的材质 -->
    </visual>
  </link>


  <link name="right_leg">
    <!-- 定义一个名为right_leg的链接 -->
    <visual>
      <!-- 定义视觉元素 -->
      <geometry>
        <!-- 定义几何形状 -->
        <box size="0.6 0.1 0.2"/>
        <!-- 定义一个长方体,尺寸为0.6x0.1x0.2 -->
      </geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
      <!-- 定义视觉元素的原点,绕x轴旋转0度,绕y轴旋转1.57075弧度,绕z轴旋转0度,位置为(0, 0, -0.3) -->
      <material name="white"/>
      <!-- 使用名为white的材质 -->
    </visual>
  </link>


  <joint name="base_to_right_leg" type="fixed">
    <!-- 定义一个名为base_to_right_leg的关节,类型为固定 -->
    <parent link="base_link"/>
    <!-- 定义父链接为base_link -->
    <child link="right_leg"/>
    <!-- 定义子链接为right_leg -->
    <origin xyz="0 -0.22 0.25"/>
    <!-- 定义关节的原点,位置为(0, -0.22, 0.25) -->
  </joint>


  <link name="right_base">
    <!-- 定义一个名为right_base的链接 -->
    <visual>
      <!-- 定义视觉元素 -->
      <geometry>
        <!-- 定义几何形状 -->
        <box size="0.4 0.1 0.1"/>
        <!-- 定义一个长方体,尺寸为0.4x0.1x0.1 -->
      </geometry>
      <material name="white"/>
      <!-- 使用名为white的材质 -->
    </visual>
  </link>


  <joint name="right_base_joint" type="fixed">
    <!-- 定义一个名为right_base_joint的关节,类型为固定 -->
    <parent link="right_leg"/>
    <!-- 定义父链接为right_leg -->
    <child link="right_base"/>
    <!-- 定义子链接为right_base -->
    <origin xyz="0 0 -0.6"/>
    <!-- 定义关节的原点,位置为(0, 0, -0.6) -->
  </joint>


  <link name="right_front_wheel">
    <!-- 定义一个名为right_front_wheel的链接 -->
    <visual>
      <!-- 定义视觉元素 -->
      <origin rpy="1.57075 0 0" xyz="0 0 0"/>
      <!-- 定义视觉元素的原点,绕x轴旋转1.57075弧度,绕y轴旋转0度,绕z轴旋转0度,位置为(0, 0, 0) -->
      <geometry>
        <!-- 定义几何形状 -->
        <cylinder length="0.1" radius="0.035"/>
        <!-- 定义一个圆柱体,长度为0.1,半径为0.035 -->
      </geometry>
      <material name="black"/>
      <!-- 使用名为black的材质 -->
    </visual>
  </link>
  <joint name="right_front_wheel_joint" type="fixed">
    <!-- 定义一个名为right_front_wheel_joint的关节,类型为固定 -->
    <parent link="right_base"/>
    <!-- 定义父链接为right_base -->
    <child link="right_front_wheel"/>
    <!-- 定义子链接为right_front_wheel -->
    <origin rpy="0 0 0" xyz="0.133333333333 0 -0.085"/>
    <!-- 定义关节的原点,绕x轴旋转0度,绕y轴旋转0度,绕z轴旋转0度,位置为(0.133333333333, 0, -0.085) -->
  </joint>


  <link name="right_back_wheel">
    <!-- 定义一个名为right_back_wheel的链接 -->
    <visual>
      <!-- 定义视觉元素 -->
      <origin rpy="1.57075 0 0" xyz="0 0 0"/>
      <!-- 定义视觉元素的原点,绕x轴旋转1.57075弧度,绕y轴旋转0度,绕z轴旋转0度,位置为(0, 0, 0) -->
      <geometry>
        <!-- 定义几何形状 -->
        <cylinder length="0.1" radius="0.035"/>
        <!-- 定义一个圆柱体,长度为0.1,半径为0.035 -->
      </geometry>
      <material name="black"/>
      <!-- 使用名为black的材质 -->
    </visual>
  </link>
  <joint name="right_back_wheel_joint" type="fixed">
    <!-- 定义一个名为right_back_wheel_joint的关节,类型为固定 -->
    <parent link="right_base"/>
    <!-- 定义父链接为right_base -->
    <child link="right_back_wheel"/>
    <!-- 定义子链接为right_back_wheel -->
    <origin rpy="0 0 0" xyz="-0.133333333333 0 -0.085"/>
    <!-- 定义关节的原点,绕x轴旋转0度,绕y轴旋转0度,绕z轴旋转0度,位置为(-0.133333333333, 0, -0.085) -->
  </joint>


  <link name="left_leg">
    <!-- 定义一个名为left_leg的链接 -->
    <visual>
      <!-- 定义视觉元素 -->
      <geometry>
        <!-- 定义几何形状 -->
        <box size="0.6 0.1 0.2"/>
        <!-- 定义一个长方体,尺寸为0.6x0.1x0.2 -->
      </geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
      <!-- 定义视觉元素的原点,绕x轴旋转0度,绕y轴旋转1.57075弧度,绕z轴旋转0度,位置为(0, 0, -0.3) -->
      <material name="white"/>
      <!-- 使用名为white的材质 -->
    </visual>
  </link>


  <joint name="base_to_left_leg" type="fixed">
    <!-- 定义一个名为base_to_left_leg的关节,类型为固定 -->
    <parent link="base_link"/>
    <!-- 定义父链接为base_link -->
    <child link="left_leg"/>
    <!-- 定义子链接为left_leg -->
    <origin xyz="0 0.22 0.25"/>
    <!-- 定义关节的原点,位置为(0, 0.22, 0.25) -->
  </joint>


  <link name="left_base">
    <!-- 定义一个名为left_base的链接 -->
    <visual>
      <!-- 定义视觉元素 -->
      <geometry>
        <!-- 定义几何形状 -->
        <box size="0.4 0.1 0.1"/>
        <!-- 定义一个长方体,尺寸为0.4x0.1x0.1 -->
      </geometry>
      <material name="white"/>
      <!-- 使用名为white的材质 -->
    </visual>
  </link>


<joint name="left_base_joint" type="fixed">
  <!-- 定义一个名为left_base_joint的关节,类型为固定 -->
  <parent link="left_leg"/>
  <!-- 定义父链接为left_leg -->
  <child link="left_base"/>
  <!-- 定义子链接为left_base -->
  <origin xyz="0 0 -0.6"/>
  <!-- 定义关节的原点,位置为(0, 0, -0.6) -->
</joint>


<link name="left_front_wheel">
  <!-- 定义一个名为left_front_wheel的链接 -->
  <visual>
    <!-- 定义视觉元素 -->
    <origin rpy="1.57075 0 0" xyz="0 0 0"/>
    <!-- 定义视觉元素的原点,绕x轴旋转1.57075弧度,绕y轴旋转0度,绕z轴旋转0度,位置为(0, 0, 0) -->
    <geometry>
      <!-- 定义几何形状 -->
      <cylinder length="0.1" radius="0.035"/>
      <!-- 定义一个圆柱体,长度为0.1,半径为0.035 -->
    </geometry>
    <material name="black"/>
    <!-- 使用名为black的材质 -->
  </visual>
</link>
<joint name="left_front_wheel_joint" type="fixed">
  <!-- 定义一个名为left_front_wheel_joint的关节,类型为固定 -->
  <parent link="left_base"/>
  <!-- 定义父链接为left_base -->
  <child link="left_front_wheel"/>
  <!-- 定义子链接为left_front_wheel -->
  <origin rpy="0 0 0" xyz="0.133333333333 0 -0.085"/>
  <!-- 定义关节的原点,绕x轴旋转0度,绕y轴旋转0度,绕z轴旋转0度,位置为(0.133333333333, 0, -0.085) -->
</joint>


<link name="left_back_wheel">
  <!-- 定义一个名为left_back_wheel的链接 -->
  <visual>
    <!-- 定义视觉元素 -->
    <origin rpy="1.57075 0 0" xyz="0 0 0"/>
    <!-- 定义视觉元素的原点,绕x轴旋转1.57075弧度,绕y轴旋转0度,绕z轴旋转0度,位置为(0, 0, 0) -->
    <geometry>
      <!-- 定义几何形状 -->
      <cylinder length="0.1" radius="0.035"/>
      <!-- 定义一个圆柱体,长度为0.1,半径为0.035 -->
    </geometry>
    <material name="black"/>
    <!-- 使用名为black的材质 -->
  </visual>
</link>
<joint name="left_back_wheel_joint" type="fixed">
  <!-- 定义一个名为left_back_wheel_joint的关节,类型为固定 -->
  <parent link="left_base"/>
  <!-- 定义父链接为left_base -->
  <child link="left_back_wheel"/>
  <!-- 定义子链接为left_back_wheel -->
  <origin rpy="0 0 0" xyz="-0.133333333333 0 -0.085"/>
  <!-- 定义关节的原点,绕x轴旋转0度,绕y轴旋转0度,绕z轴旋转0度,位置为(-0.133333333333, 0, -0.085) -->
</joint>


<joint name="gripper_extension" type="fixed">
  <!-- 定义一个名为gripper_extension的关节,类型为固定 -->
  <parent link="base_link"/>
  <!-- 定义父链接为base_link -->
  <child link="gripper_pole"/>
  <!-- 定义子链接为gripper_pole -->
  <origin rpy="0 0 0" xyz="0.19 0 0.2"/>
  <!-- 定义关节的原点,位置为(0.19, 0, 0.2) -->
</joint>


<link name="gripper_pole">
  <!-- 定义一个名为gripper_pole的链接 -->
  <visual>
    <!-- 定义视觉元素 -->
    <geometry>
      <!-- 定义几何形状 -->
      <cylinder length="0.2" radius="0.01"/>
      <!-- 定义一个圆柱体,长度为0.2,半径为0.01 -->
    </geometry>
    <origin rpy="0 1.57075 0" xyz="0.1 0 0"/>
    <!-- 定义视觉元素的原点,绕x轴旋转0度,绕y轴旋转1.57075弧度,绕z轴旋转0度,位置为(0.1, 0, 0) -->
  </visual>
</link>


<joint name="left_gripper_joint" type="fixed">
  <!-- 定义一个名为left_gripper_joint的关节,类型为固定 -->
  <origin rpy="0 0 0" xyz="0.2 0.01 0"/>
  <!-- 定义关节的原点,绕x轴旋转0度,绕y轴旋转0度,绕z轴旋转0度,位置为(0.2, 0.01, 0) -->
  <parent link="gripper_pole"/>
  <!-- 定义父链接为gripper_pole -->
  <child link="left_gripper"/>
  <!-- 定义子链接为left_gripper -->
</joint>


<link name="left_gripper">
  <!-- 定义一个名为left_gripper的链接 -->
  <visual>
    <!-- 定义视觉元素 -->
    <origin rpy="0.0 0 0" xyz="0 0 0"/>
    <!-- 定义视觉元素的原点,绕x轴旋转0度,绕y轴旋转0度,绕z轴旋转0度,位置为(0, 0, 0) -->
    <geometry>
      <!-- 定义几何形状 -->
      <mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
      <!-- 使用外部网格文件定义几何形状,文件路径为package://urdf_tutorial/meshes/l_finger.dae -->
    </geometry>
  </visual>
</link>


<joint name="left_tip_joint" type="fixed">
  <!-- 定义一个名为left_tip_joint的关节,类型为固定 -->
  <parent link="left_gripper"/>
  <!-- 定义父链接为left_gripper -->
  <child link="left_tip"/>
  <!-- 定义子链接为left_tip -->
</joint>


<link name="left_tip">
  <!-- 定义一个名为left_tip的链接 -->
  <visual>
    <!-- 定义视觉元素 -->
    <origin rpy="0.0 0 0" xyz="0.09137 0.00495 0"/>
    <!-- 定义视觉元素的原点,绕x轴旋转0度,绕y轴旋转0度,绕z轴旋转0度,位置为(0.09137, 0.00495, 0) -->
    <geometry>
      <!-- 定义几何形状 -->
      <mesh filename="package://urdf_tutorial/meshes/l_finger_tip.dae"/>
      <!-- 使用外部网格文件定义几何形状,文件路径为package://urdf_tutorial/meshes/l_finger_tip.dae -->
    </geometry>
  </visual>
</link>


<joint name="right_gripper_joint" type="fixed">
  <!-- 定义一个名为right_gripper_joint的关节,类型为固定 -->
  <origin rpy="0 0 0" xyz="0.2 -0.01 0"/>
  <!-- 定义关节的原点,绕x轴旋转0度,绕y轴旋转0度,绕z轴旋转0度,位置为(0.2, -0.01, 0) -->
  <parent link="gripper_pole"/>
  <!-- 定义父链接为gripper_pole -->
  <child link="right_gripper"/>
  <!-- 定义子链接为right_gripper -->
</joint>


<link name="right_gripper">
  <!-- 定义一个名为right_gripper的链接 -->
  <visual>
    <!-- 定义视觉元素 -->
    <origin rpy="-3.1415 0 0" xyz="0 0 0"/>
    <!-- 定义视觉元素的原点,绕x轴旋转-3.1415弧度,绕y轴旋转0度,绕z轴旋转0度,位置为(0, 0, 0) -->
    <geometry>
      <!-- 定义几何形状 -->
      <mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
      <!-- 使用外部网格文件定义几何形状,文件路径为package://urdf_tutorial/meshes/l_finger.dae -->
    </geometry>
  </visual>
</link>


<joint name="right_tip_joint" type="fixed">
  <!-- 定义一个名为right_tip_joint的关节,类型为固定 -->
  <parent link="right_gripper"/>
  <!-- 定义父链接为right_gripper -->
  <child link="right_tip"/>
  <!-- 定义子链接为right_tip -->
</joint>


<link name="right_tip">
  <!-- 定义一个名为right_tip的链接 -->
  <visual>
    <!-- 定义视觉元素 -->
    <origin rpy="-3.1415 0 0" xyz="0.09137 0.00495 0"/>
    <!-- 定义视觉元素的原点,绕x轴旋转-3.1415弧度,绕y轴旋转0度,绕z轴旋转0度,位置为(0.09137, 0.00495, 0) -->
    <geometry>
      <!-- 定义几何形状 -->
      <mesh filename="package://urdf_tutorial/meshes/l_finger_tip.dae"/>
      <!-- 使用外部网格文件定义几何形状,文件路径为package://urdf_tutorial/meshes/l_finger_tip.dae -->
    </geometry>
  </visual>
</link>


<link name="head">
  <!-- 定义一个名为head的链接 -->
  <visual>
    <!-- 定义视觉元素 -->
    <geometry>
      <!-- 定义几何形状 -->
      <sphere radius="0.2"/>
      <!-- 定义一个球体,半径为0.2 -->
    </geometry>
    <material name="white"/>
    <!-- 使用名为white的材质 -->
  </visual>
</link>
<joint name="head_swivel" type="fixed">
  <!-- 定义一个名为head_swivel的关节,类型为固定 -->
  <parent link="base_link"/>
  <!-- 定义父链接为base_link -->
  <child link="head"/>
  <!-- 定义子链接为head -->
  <origin xyz="0 0 0.3"/>
  <!-- 定义关节的原点,位置为(0, 0, 0.3) -->
</joint>


<link name="box">
  <!-- 定义一个名为box的链接 -->
  <visual>
    <!-- 定义视觉元素 -->
    <geometry>
      <!-- 定义几何形状 -->
      <box size="0.08 0.08 0.08"/>
      <!-- 定义一个长方体,尺寸为0.08x0.08x0.08 -->
    </geometry>
    <material name="blue"/>
    <!-- 使用名为blue的材质 -->
  </visual>
</link>


<joint name="tobox" type="fixed">
  <!-- 定义一个名为tobox的关节,类型为固定 -->
  <parent link="head"/>
  <!-- 定义父链接为head -->
  <child link="box"/>
  <!-- 定义子链接为box -->
  <origin xyz="0.1814 0 0.1414"/>
  <!-- 定义关节的原点,位置为(0.1814, 0, 0.1414) -->
</joint>
</robot>
<!-- 结束机器人定义 -->
nginx 复制代码
ros2 launch urdf_tutorial display.launch.py model:=urdf/05-visual.urdf

如何添加球体应该是相当不言自明的

xml 复制代码
<link name="head">
  <visual>
    <geometry>
      <sphere radius="0.2"/>
    </geometry>
    <material name="white"/>
  </visual>
</link>

这里的网格是从 PR2 借来的。它们是单独的文件,你必须指定路径。你应该使用 package://NAME_OF_PACKAGE/path 符号。本教程的网格位于 urdf_tutorial 包中的一个名为 meshes 的文件夹中。

xml 复制代码
<link name="left_gripper">
  <visual>
    <origin rpy="0.0 0 0" xyz="0 0 0"/>
    <geometry>
      <mesh filename="package://urdf_tutorial/meshes/l_finger.dae"/>
    </geometry>
  </visual>
</link>
  • 这些网格可以以多种不同的格式导入。STL 是相当常见的,但引擎也支持 DAE,它可以有自己的颜色数据,这意味着你不必指定颜色/材料。通常这些在单独的文件中。这些网格引用了网格文件夹中的 .tif 文件。

  • 网格也可以使用相对缩放参数或边界框大小进行调整。

  • 我们也可以引用一个完全不同包中的网格。

就是这样。一个类似 R2D2 的 URDF 模型。现在你可以继续下一步,让它动起来。https://docs.ros.org/en/jazzy/Tutorials/Intermediate/URDF/Building-a-Movable-Robot-Model-with-URDF.html

相关推荐
ZOMI酱28 分钟前
【AI系统】模型转换基本介绍
人工智能
CodeDevMaster40 分钟前
LangChain之检索增强生成RAG
人工智能·python·llm
今天又是学习2 小时前
深度学习5
人工智能·深度学习
新加坡内哥谈技术2 小时前
RAG架构类型
大数据·人工智能·语言模型·chatgpt
Topstip2 小时前
iOS 19 重大更新泄露,将带来更“聪明”的 Siri 挑战 ChatGPT
人工智能·ios·ai·chatgpt
Nerinic2 小时前
深度学习基础1
人工智能·深度学习
数字扫地僧2 小时前
深度学习与知识图谱嵌入的结合:从理论到实践
人工智能·深度学习·知识图谱
真理Eternal3 小时前
手搓人工智能—聚类分析(下)谱系聚类与K-mean聚类
人工智能·机器学习
ZOMI酱3 小时前
【AI系统】昇腾 AI 架构介绍
人工智能·架构
说私域3 小时前
精准零售驱动下的中国零售业变革与“开源 2+1 链动小程序”应用探究
人工智能·小程序·开源