在 MoveIt 中启动文件

许多 MoveIt 教程以及您在实际中会遇到的 MoveIt 包都使用 ROS 2 启动文件。

本教程将介绍一个典型的 Python 启动文件,该文件可设置一个有效的 MoveIt 示例。 我们将通过详细介绍我们的 入门教程启动文件 来实现这一点。

如果您不熟悉启动文件,请先参阅 ROS 2 文档

加载 MoveIt 配置

MoveIt 需要几个配置参数来包含机器人描述和语义描述文件(URDF 和 SRDF)、运动规划和运动学插件、轨迹执行等。 这些参数通常包含在 MoveIt 配置 包中。

引用 MoveIt 配置包的一个方便方法是使用 Python 启动文件中的 MoveItConfigsBuilder 实用程序,如下所示:

from moveit_configs_utils import MoveItConfigsBuilder

# Define xacro mappings for the robot description file
launch_arguments = {
    "robot_ip": "xxx.yyy.zzz.www",
    "use_fake_hardware": "true",
    "gripper": "robotiq_2f_85",
    "dof": "7",
}

# Load the robot configuration
moveit_config = (
    MoveItConfigsBuilder(
        "gen3", package_name="kinova_gen3_7dof_robotiq_2f_85_moveit_config"
    )
    .robot_description(mappings=launch_arguments)
    .trajectory_execution(file_path="config/moveit_controllers.yaml")
    .planning_scene_monitor(
        publish_robot_description=True, publish_robot_description_semantic=True
    )
    .planning_pipelines(
        pipelines=["ompl", "stomp", "pilz_industrial_motion_planner"]
    )
    .to_moveit_configs()
)

启动 Move Group

一旦加载了所有 MoveIt 配置参数,您就可以使用加载的整个 MoveIt 参数集启动 移动组 C++ 接口

from launch_ros.actions import Node

run_move_group_node = Node(
    package="moveit_ros_move_group",
    executable="move_group",
    output="screen",
    parameters=[moveit_config.to_dict()],
)

使用 RViz 进行可视化

RViz 快速入门 教程中所述,您可以使用 RViz 可视化您的机器人模型并执行运动规划任务。

以下代码使用启动参数接收 RViz 配置文件名,将其打包为已知包目录的相对路径,并在启动 RViz 可执行文件时将其指定为参数。

from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
from launch_ros.substitutions import FindPackageShare

# Get the path to the RViz configuration file
rviz_config_arg = DeclareLaunchArgument(
    "rviz_config",
    default_value="kinova_moveit_config_demo.rviz",
    description="RViz configuration file",
)
rviz_base = LaunchConfiguration("rviz_config")
rviz_config = PathJoinSubstitution(
    [FindPackageShare("moveit2_tutorials"), "launch", rviz_base]
)

# Launch RViz
rviz_node = Node(
    package="rviz2",
    executable="rviz2",
    name="rviz2",
    output="log",
    arguments=["-d", rviz_config],
    parameters=[
        moveit_config.robot_description,
        moveit_config.robot_description_semantic,
        moveit_config.robot_description_kinematics,
        moveit_config.planning_pipelines,
        moveit_config.joint_limits,
    ],
)

将变换发布到“tf2”

ROS 生态系统中的许多工具都使用“tf2 <https://docs.ros.org/en/rolling/Concepts/Intermediate/About-Tf2.html>”库来表示坐标变换,这是使用 MoveIt 进行运动规划的重要组成部分。

因此,我们的启动文件包括将固定(静态)和动态名称发布到“tf2”的节点。 在我们的例子中,我们需要:

  • “世界”框架和我们的机器人描述“base_link”基框架之间的静态变换。

  • “机器人状态发布者<https://github.com/ros/robot_state_publisher>”节点,用于监听机器人的关节状态,使用机器人的 URDF 模型计算框架变换,并将它们发布到“tf2”。

# Static TF
static_tf = Node(
    package="tf2_ros",
    executable="static_transform_publisher",
    name="static_transform_publisher",
    output="log",
    arguments=["--frame-id", "world", "--child-frame-id", "base_link"],
)

# Publish TF
robot_state_publisher = Node(
    package="robot_state_publisher",
    executable="robot_state_publisher",
    name="robot_state_publisher",
    output="both",
    parameters=[moveit_config.robot_description],
)

设置“ros2_control”以执行轨迹

MoveIt 通常会生成关节轨迹,然后可以通过将其发送到具有能够执行这些轨迹的控制器的机器人来执行这些轨迹。 最常见的是,我们连接到“ros2_control <https://control.ros.org/master/index.html>”库来实现这一点。

虽然“ros2_control”允许您连接到真实的机器人硬件,或基于物理的模拟器(如 Gazebo 或 NVIDIA Isaac Sim)中的机器人,但它还公开了“模拟组件<https://control.ros.org/master/doc/ros2_control/hardware_interface/doc/mock_components_userdoc.html>”功能,用于简单、理想化的模拟。 在我们的示例中,这是在 URDF 级别使用先前定义的“use_fake_hardware”xacro 参数配置的。 关键思想是,无论启动哪种硬件(模拟或真实),“ros2_control”的启动都保持不变。

启动“ros2_control”涉及启动控制器管理器节点,然后生成轨迹执行所需的控制器列表。

在我们的示例中,我们有:

  • 关节状态广播器,它发布机器人状态发布器将帧发送到“tf2”所需的关节状态。

  • 手臂执行器的关节轨迹控制器。

  • 平行钳口夹持器的夹持器动作控制器。

ros2_controllers_path = os.path.join(
    get_package_share_directory("kinova_gen3_7dof_robotiq_2f_85_moveit_config"),
    "config",
    "ros2_controllers.yaml",
)
ros2_control_node = Node(
    package="controller_manager",
    executable="ros2_control_node",
    parameters=[ros2_controllers_path],
    remappings=[
        ("/controller_manager/robot_description", "/robot_description"),
    ],
    output="both",
)

joint_state_broadcaster_spawner = Node(
    package="controller_manager",
    executable="spawner",
    arguments=[
        "joint_state_broadcaster",
        "--controller-manager",
        "/controller_manager",
    ],
)

arm_controller_spawner = Node(
    package="controller_manager",
    executable="spawner",
    arguments=["joint_trajectory_controller", "-c", "/controller_manager"],
)

hand_controller_spawner = Node(
    package="controller_manager",
    executable="spawner",
    arguments=["robotiq_gripper_controller", "-c", "/controller_manager"],
)

启动所有节点

最后,我们可以告诉我们的启动文件实际启动我们在前面部分描述的所有内容。

# ... all our imports go here

def generate_launch_description():

    # ... all our other code goes here

    return LaunchDescription(
        [
            rviz_config_arg,
            rviz_node,
            static_tf,
            robot_state_publisher,
            run_move_group_node,
            ros2_control_node,
            joint_state_broadcaster_spawner,
            arm_controller_spawner,
            hand_controller_spawner,
        ]
    )