【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 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 文件:

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对
# 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对象
ros2 launch urdf_tutorial display.launch.py model:=urdf/01-myfirst.urdf

这做了三件事:

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

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

  • 使用配置文件启动 Rviz

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

9299cebb9c4c34cd04671f00f7dab656.png

  •  注意事项:

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

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

c9a39c5a5e14ff28da4878fe56a3045a.png

 多种形状

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

<?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 的位置。

ros2 launch urdf_tutorial display.launch.py model:=urdf/02-multipleshapes.urdf

bee5cd49edea7c74fa669c0beea1e0ed.png

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

原点 Origin 

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

<?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。

ros2 launch urdf_tutorial display.launch.py model:=urdf/03-origins.urdf

019ae057b7546c763320c7278d8b39f2.png

  • 启动文件运行包,这些包将根据您的 URDF 为模型中的每个链接创建 TF 框架。Rviz 使用这些信息来确定显示每个形状的位置。

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

材质女孩

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

<?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 的视觉元素引用。白色材料的定义类似。

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

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

ros2 launch urdf_tutorial display.launch.py model:=urdf/04-materials.urdf

c6328aec10244f094b4032da3aef0bd8.png

完成模型 

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

<?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>
<!-- 结束机器人定义 -->
ros2 launch urdf_tutorial display.launch.py model:=urdf/05-visual.urdf

054d1585ddebde2610f06296970c4157.png

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

<link name="head">
  <visual>
    <geometry>
      <sphere radius="0.2"/>
    </geometry>
    <material name="white"/>
  </visual>
</link>

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

<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 文件。

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

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

73d5be227de4ea1a24aa1080a4754275.png

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

  • 15
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是一个关于ROS Noetic软件包依赖关系的问题。其中,下列软件包的依赖关系尚不足够满足要求,无法安装: ros-noetic-desktop-full: 依赖于 ros-noetic-desktop,但它不会被安装。 依赖于 ros-noetic-perception,但它不会被安装。 依赖于 ros-noetic-simulators,但它不会被安装。 依赖于 ros-noetic-urdf-sim-tu,但它不会被安装。 ### 回答2: 这个错误提示是说明在安装 ros-noetic-desktop-full 软件包时,发现它需要依赖一些其他的软件包,但是这些软件包未被安装。其中,ros-noetic-desktop、ros-noetic-perception、ros-noetic-simulators 和 ros-noetic-urdf-sim-tu 是四个未满足依赖关系的软件包。 这个错误提示一般是由于软件源的问题所导致的。在安装软件包时,系统会从软件源中查找该软件包以及它所需的依赖关系。如果软件源中不存在某个软件包的依赖关系,则会提示这个错误信息。 要解决这个问题,可以尝试以下几个方法: 1. 更新软件源:可通过修改软件源配置文件或使用软件源管理工具来更新软件源。更新后再次尝试安装软件包,看是否能够解决依赖关系问题。 2. 手动安装依赖关系:如果更新软件源后仍然无法解决依赖关系问题,可以尝试手动安装依赖关系。按照依赖关系的提示,逐个安装这四个软件包。安装完成后再次尝试安装 ros-noetic-desktop-full 软件包,看是否能够正常安装。 3. 使用 aptitude 命令安装:aptitude 命令可以自动处理依赖关系,可能会更好地解决这个问题。可以通过运行以下命令安装 ros-noetic-desktop-full 软件包: sudo aptitude install ros-noetic-desktop-full 以上是我的回答,希望能对你有所帮助。如果你还有其他问题,请随时回复。 ### 回答3: 这个问题意味着在安装 ros-noetic-desktop-full 软件包时,计算机无法满足所有需要的依赖关系。这些依赖关系包括 ros-noetic-desktop、ros-noetic-perception、ros-noetic-simulators 和 ros-noetic-urdf-sim-tu。 在解决这个问题之前,我们需要了解什么是依赖关系。在软件工程中,依赖关系指的是一个软件包需要另一个软件包才能正常运行的情况。例如,在 ROS 中,ros-noetic-desktop-full 需要依赖其他的软件包才能提供完整的功能。 为了解决这个问题,我们可以使用以下方法: 1. 更新软件包源列表。我们可以更新软件包源列表,这有助于计算机查找所需的软件包。在 Ubuntu 系统中,我们可以使用以下命令更新软件包源列表:sudo apt-get update。 2. 安装依赖关系。我们可以尝试单独安装缺失的依赖关系。在 ROS 中,我们可以使用以下命令安装缺失的软件包:sudo apt-get install ros-noetic-desktop ros-noetic-perception ros-noetic-simulators ros-noetic-urdf-sim-tu。 3. 检查软件包仓库。某些情况下,软件包源可能已经过时或不再受支持。我们可以检查软件包仓库,查看软件包是否可用。在 Ubuntu 系统中,我们可以使用以下命令查看软件包仓库:apt-cache search ros-noetic-desktop-full。 总之,无法满足依赖关系的问题是常见的,在解决这个问题之前,我们需要了解依赖关系的概念,并掌握一些解决方法。在 ROS 中,我们可以使用更新软件包源列表、安装依赖关系和检查软件包仓库等方法解决问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值