【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 翻译成英文,这是一个名为 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 显示以下内容:
注意事项:
固定框架是网格中心所在的变换框架。在这里,它是由我们的一个链接 base_link 定义的框架。
视觉元素(圆柱体)的原点默认位于其几何中心。因此,圆柱体的一半位于网格下方。
多种形状
现在让我们看看如何添加多个形状/链接。如果我们只是向 urdf 中添加更多的链接元素,解析器将不知道将它们放在哪里。因此,我们必须添加关节。关节元素可以指灵活和不灵活的关节。我们将从不灵活的或固定的关节开始。[来源:02-multipleshapes.urdf]
注意我们如何定义一个 0.6 米 x 0.1 米 x 0.2 米的盒子。
关节是根据父节点和子节点来定义的。URDF 最终是一个具有一个根链接的树结构。这意味着腿的位置取决于 base_link 的位置。
ros2 launch urdf_tutorial display.launch.py model:=urdf/02-multipleshapes.urdf
这两个形状彼此重叠,因为它们共享相同的原点。如果我们不希望它们重叠,我们必须定义更多的原点。
原点 Origin
R2D2 的腿连接到躯干的上半部分,在侧面。所以我们将关节的原点指定在那里。此外,它不是连接到腿的中间,而是连接到上部,所以我们也必须为腿的原点设置偏移。我们还将腿旋转,使其直立。[来源:03-origins.urdf]
让我们首先检查关节的原点。它是根据父参考系定义的。因此,我们在 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
启动文件运行包,这些包将根据您的 URDF 为模型中的每个链接创建 TF 框架。Rviz 使用这些信息来确定显示每个形状的位置。
如果给定的 URDF 链接不存在 TF 框架,那么它将被放置在原点处显示为白色(参考相关问题)。
材质女孩
“好吧,”我听到你说。“那很可爱,但不是每个人都有 B21。我的机器人和 R2D2 不是红色的!” 这是一个很好的观点。让我们看看材质标签。[来源:04-materials.urdf]
现在身体是蓝色的。我们定义了一种称为“蓝色”的新材料,其红色、绿色、蓝色和 alpha 通道分别定义为 0、0、0.8 和 1。所有值都可以在 [0,1] 范围内。然后,该材料由 base_link 的视觉元素引用。白色材料的定义类似。
您还可以在视觉元素中定义材料标签,甚至在其他链接中引用它。不过,即使您重新定义它,也不会有人抱怨。
您还可以使用纹理来指定用于为对象着色的图像文件
ros2 launch urdf_tutorial display.launch.py model:=urdf/04-materials.urdf
完成模型
现在我们用一些更多的形状来完成模型:脚、轮子和头。最值得注意的是,我们添加了一个球体和一些网格。我们还会添加一些其他的部件,以便以后使用。[来源:05-visual.urdf]
ros2 launch urdf_tutorial display.launch.py model:=urdf/05-visual.urdf
如何添加球体应该是相当不言自明的
这里的网格是从 PR2 借来的。它们是单独的文件,你必须指定路径。你应该使用 package://NAME_OF_PACKAGE/path 符号。本教程的网格位于 urdf_tutorial 包中的一个名为 meshes 的文件夹中。