Low Level Controllers
MoveIt通常会将操纵器的运动命令发布到关节轨迹控制器。本教程假设使用MoveGroup
控制机器人,而不是MoveItCpp
或MoveIt Servo
。最小设置如下:
- 一个YAML配置文件。我们建议将此
moveit_controllers.yaml
命名为“告诉”moveit哪些控制器可用,哪些关节与每个关节关联,以及moveit控制器接口类型(FollowJointTrajectory
或GripperCommand
)。控制器配置文件示例如下。
# MoveIt使用此配置进行控制器管理
trajectory_execution:
# 此参数缩放运动计划的执行持续时间。缩放因子为1.2表示计划可以比原始计划的时间长20%。
allowed_execution_duration_scaling: 1.2
# 目标持续时间设置了一个边距。在这种情况下,允许额外0.5秒来实现目标。
allowed_goal_duration_margin: 0.5
# 允许的机器人起始状态的容差。0.01的容差表示起始状态应在指定的起始状态的0.01单位范围内。
allowed_start_tolerance: 0.01
# 当设置为true时,MoveIt会监视计划轨迹的持续时间
trajectory_duration_monitoring: true
# 指定要使用的控制器管理器
moveit_controller_manager: moveit_simple_controller_manager/MoveItSimpleControllerManager
moveit_simple_controller_manager:
# 列出由此控制器管理器管理的控制器的名称。只有一个名为“panda_arm_controller”的控制器。
controller_names:
- panda_arm_controller
# "panda_arm_controller"的配置。
panda_arm_controller:
# 指定此控制器的动作命名空间。设置为“follow_joint_trajectory”,用于控制机器人关节的常见动作类型。
action_ns: follow_joint_trajectory
# 控制器的类型
type: FollowJointTrajectory
# 此控制器被视为默认控制器
default: true
# 列出由此控制器控制的关节的名称
joints:
- panda_joint1
- panda_joint2
- panda_joint3
- panda_joint4
- panda_joint5
- panda_joint6
- panda_joint7
- 启动文件。此启动文件必须加载
moveit_controllers
yaml文件并指定moveit_simple_controller_manager/MoveItSimpleControllerManager
。加载这些yaml文件后,它们将作为参数传递到“Move Group”节点。移动组启动文件示例:
import os
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch.conditions import IfCondition, UnlessCondition
from launch_ros.actions import Node
from launch.actions import ExecuteProcess
from ament_index_python.packages import get_package_share_directory
from moveit_configs_utils import MoveItConfigsBuilder
def generate_launch_description():
# 定义启动参数
tutorial_arg = DeclareLaunchArgument(
"rviz_tutorial", default_value="False", description="Tutorial flag"
)
db_arg = DeclareLaunchArgument(
"db", default_value="False", description="Database flag"
)
ros2_control_hardware_type = DeclareLaunchArgument(
"ros2_control_hardware_type",
default_value="mock_components",
description="ROS2 control hardware interface type to use for the launch file -- possible values: [mock_components, isaac]",
)
# 配置 MoveIt 插件
moveit_config = (
MoveItConfigsBuilder("moveit_resources_panda")
.robot_description(
file_path="config/panda.urdf.xacro",
mappings={
"ros2_control_hardware_type": LaunchConfiguration(
"ros2_control_hardware_type"
)
},
)
.robot_description_semantic(file_path="config/panda.srdf")
.trajectory_execution(file_path="config/gripper_moveit_controllers.yaml")
.planning_pipelines(
pipelines=["ompl", "chomp", "pilz_industrial_motion_planner", "stomp"]
)
.to_moveit_configs()
)
# 启动 MoveIt move_group节点/动作服务器
move_group_node = Node(
package="moveit_ros_move_group",
executable="move_group",
output="screen",
parameters=[moveit_config.to_dict()],
arguments=["--ros-args", "--log-level", "info"],
)
# 配置 RViz
tutorial_mode = LaunchConfiguration("rviz_tutorial")
rviz_base = os.path.join(
get_package_share_directory("moveit_resources_panda_moveit_config"), "launch"
)
rviz_full_config = os.path.join(rviz_base, "moveit.rviz")
rviz_empty_config = os.path.join(rviz_base, "moveit_empty.rviz")
rviz_node_tutorial = Node(
package="rviz2",
executable="rviz2",
name="rviz2",
output="log",
arguments=["-d", rviz_empty_config],
parameters=[
moveit_config.robot_description,
moveit_config.robot_description_semantic,
moveit_config.planning_pipelines,
moveit_config.robot_description_kinematics,
],
condition=IfCondition(tutorial_mode),
)
rviz_node = Node(
package="rviz2",
executable="rviz2",
name="rviz2",
output="log",
arguments=["-d", rviz_full_config],
parameters=[
moveit_config.robot_description,
moveit_config.robot_description_semantic,
moveit_config.planning_pipelines,
moveit_config.robot_description_kinematics,
moveit_config.joint_limits,
],
condition=UnlessCondition(tutorial_mode),
)
# 配置静态 TF
static_tf_node = Node(
package="tf2_ros",
executable="static_transform_publisher",
name="static_transform_publisher",
output="log",
arguments=["0.0", "0.0", "0.0", "0.0", "0.0", "0.0", "world", "panda_link0"],
)
# 发布 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 使用 FakeSystem 作为硬件
ros2_controllers_path = os.path.join(
get_package_share_directory("moveit_resources_panda_moveit_config"),
"config",
"ros2_controllers.yaml",
)
ros2_control_node = Node(
package="controller_manager",
executable="ros2_control_node",
parameters=[moveit_config.robot_description, ros2_controllers_path],
output="screen",
)
joint_state_broadcaster_spawner = Node(
package="controller_manager",
executable="spawner",
arguments=[
"joint_state_broadcaster",
"--controller-manager",
"/controller_manager",
],
)
panda_arm_controller_spawner = Node(
package="controller_manager",
executable="spawner",
arguments=["panda_arm_controller", "-c", "/controller_manager"],
)
panda_hand_controller_spawner = Node(
package="controller_manager",
executable="spawner",
arguments=["panda_hand_controller", "-c", "/controller_manager"],
)
# Warehouse mongodb 服务器配置
db_config = LaunchConfiguration("db")
mongodb_server_node = Node(
package="warehouse_ros_mongo",
executable="mongo_wrapper_ros.py",
parameters=[
{"warehouse_port": 33829},
{"warehouse_host": "localhost"},
{"warehouse_plugin": "warehouse_ros_mongo::MongoDatabaseConnection"},
],
output="screen",
condition=IfCondition(db_config),
)
return LaunchDescription(
[
tutorial_arg,
db_arg,
ros2_control_hardware_type,
rviz_node,
rviz_node_tutorial,
static_tf_node,
robot_state_publisher,
move_group_node,
ros2_control_node,
joint_state_broadcaster_spawner,
panda_arm_controller_spawner,
panda_hand_controller_spawner,
mongodb_server_node,
]
)
- 启动相应的
ros2_control
JointTranstrajectyControllers
。这与MoveIt2生态系统是分开的。ros2_control启动示例。每个JointTrajectoryController
都提供一个action interface。给定上面的yaml文件,MoveIt会自动连接到此action interface。 - 注意:并不一定要使用
ros2_control
。您可以编写一个专有的操作接口。但在实践中,99%的用户选择ros2_control
。
MoveIt Controller Managers
控制器管理器的基类称为MoveItControllerManager
(MICM)。MICM的一个子类为Ros2ControlManager
(R2CM),它是使用ros2_control
接口的最佳方式。R2CM可以解析来自MoveIt的轨迹命令中的关节名称,并激活对应的控制器。例如,它可以在同时控制单个关节组中的两个操纵器到单个操纵器之间自动切换。要使用R2CM,只需在启动文件中将moveit_manage_controllers
设置为true即可。R2CM启动文件示例。
MoveIt Controller Interfaces
上面描述了联合轨迹控制器动作界接口(joint trajectory controller action interface
)的启动。此外,MoveIt支持通过动作接口进行平行钳口夹持器控制。本节介绍这两个选项的参数。
FollowJointTrajectory
控制器接口
参数为:name:控制器的名称。
action_ns:控制器的操作命名空间。
type:正在使用的动作类型(此处为JointTrajectory)。
default:默认控制器是MoveIt为与特定关节集通信而选择的主控制器。
joints:由该接口寻址的所有关节的名称。GripperCommand
控制器接口
参数为:name:控制器的名称。
action_ns:控制器的操作命名空间。
type:正在使用的操作类型(此处为GripperCommand)。
default:默认控制器是MoveIt为与特定关节集通信而选择的主控制器。
joints:由该接口寻址的所有关节的名称。
command_joint:单个关节,控制夹持器的实际状态。这是发送到控制器的唯一值。必须是上面的关节之一。如果未指定,则将使用关节中的第一个。
parallel:设置此选项后,关节的大小应为2,命令将为两个关节的总和。
可选的允许轨迹执行持续时间参数
对于每个控制器,都可以选择设置allowed_execution_duration_scaling
和allowed_goal_duration_maring
参数。这些是全局值trajectory_execution/allowed_executtion_duration_scaling
和trajectory_execution/allowed_target_duration_maring
的控制器特定值的重写。与全局值相反,控制器特定的值不能在运行时动态重新配置。这些参数用于通过缩放预期执行持续时间并随后添加裕度来计算允许的轨迹执行持续时间。如果超过此持续时间,轨迹将被取消。控制器特定参数可设置如下:
controller_list:
- name: arm_controller
action_ns: follow_joint_trajectory
type: FollowJointTrajectory
allowed_execution_duration_scaling: 1.2
allowed_goal_duration_margin: 0.5
Debugging调试信息
机器人上的FollowJointTrajectory
或GripperCommand
接口必须在命名空间/name/action_ns
中进行通信。在上面的例子中,你应该能够在你的机器人上看到以下主题topics(使用ros2 topic list
):
- /panda_arm_controller/follow_joint_trajectory/goal
- /panda_arm_controller/follow_joint_trajectory/feedback
- /panda_arm_controller/follow_joint_trajectory/result
- /hand_controller/gripper_action/goal
- /hand_controller/gripper_action/feedback
- /hand_controller/gripper_action/result
您还应该能够看到(使用ros2 topic info topic_name
)机器人上的控制器以及move_group节点发布/订阅的主题。
重映射/joint_states主题
运行Move Group节点时,可能需要将topic/joint_state
重新映射到/arobot/joint_status
,否则MoveIt将不会收到来自关节的反馈。要执行此重新映射,您可以为节点制作一个简单的启动文件,如下所示:
<node pkg="moveit_ros_move_group" type="move_group" name="any_name" output="screen">
<remap from="joint_states" to="robot/joint_states"/>
</node>
或者,您可以创建一个具有正确主题名称的订阅者,然后通过使用该订阅者的回调来确保move group
的起始机器人状态对应于正确的关节角度。
轨迹执行管理器选项
有几个选项可用于调整MoveIt中执行管道的行为和安全检查。在moveit_config
包中,编辑trajectory_execution.launch.xml
文件以更改以下参数:
execution_duration_monitoring
:如果为false,则不会抛出错误,因为轨迹在low-level控制器侧完成的时间比预期的要长allowed_goal_durationmargin
:在触发轨迹取消之前允许超过预期的执行时间(在缩放后应用)allowed_start_tolerance
:用于验证轨迹的第一个点与当前机器人状态匹配的允许关节值公差。如果设置为零,将跳过机器人在执行后的停止等待
控制器管理器Example
MoveIt控制器管理器是您的自定义 low level控制器的接口,这有点用词不当。更好的方法是控制器接口。对于大多数使用情况,如果您的机器人控制器已经为FollowJointTrajectory
提供ROS操作,那么included MoveItSimpleControllerManager就足够了。如果您使用ros_control
,则included MoveItRosControlInterface也是理想的选择。
但是,对于某些应用程序,您可能需要更自定义的控制器管理器。这里提供了一个用于启动自定义控制器管理器的示例模板。
模拟仿真
如果你没有一个物理机器人,ros2_control
可以很容易地模拟一个。不需要Ignition或Gazebo;RViz就足够了。所有试例在ros2_control_demos repo中。
控制器切换和命名空间
所有控制器名称都以其ros_control
节点的名称空间为前缀。因此,控制器名称不应包含斜杠,并且不能命名为/。对于特定节点,MoveIt可以决定启动或停止哪些控制器。由于只有具有已注册分配器插件的控制器名称才能通过MoveIt进行处理,因此,如果要启动的控制器需要任何这些资源,MoveIt会根据其声明的资源来停止控制器。
多个节点的控制器
Ros2ControlManager
有一个变体,即Ros2Control MultiManager
。Ros2ControlMultiManager
可以用于多个ros_control
节点。它通过创建几个Ros2ControlManager
来工作,每个节点一个。它用它们各自的名称空间实例化它们,并负责适当的委派。若要使用,必须将其添加到启动文件中。
<param name="moveit_controller_manager" value="moveit_ros_control_interface::Ros2ControlMultiManager" />