ROS Moveit 配置全网最详细教程

目录

前言

Moveit的使用、配置和原理相关的内容较多,特别是assistant生成的moveit_config包,内容较多,在配置时容易让用户搞不清关系,导致配置过程艰难、漫长。

同时互联网的Moveit文档较为杂乱,配置方法也有区别,因此笔者在学习过程中梳理出了Moveit的使用、配置和原理教程,希望对后来人有所帮助。

提示: 本篇文章字数约94000字,阅读时间超2h,建议收藏作为moveit工具书来查阅使用。

作者: Herman Ye @Auromix
Auromix是一个机器人爱好者组织,欢迎参与我们Github上的开源项目

目录

  • Moveit的安装
  • Moveit的使用
  • config配置包的文件解析
  • Moveit的源码解析

Moveit的安装

笔者制作了Moveit一键配置安装来方便使用,这个一键配置安装脚本也会根据用户需求看是否额外下载Moveit的基础教程示例,辅助用户学习。

复制以下指令到命令行,一键进行配置安装

wget -O $HOME/moveit1_install.sh https://raw.githubusercontent.com/auromix/ros-install-one-click/main/moveit1_install.sh && sudo chmod +x $HOME/moveit1_install.sh && sudo bash $HOME/moveit1_install.sh && rm $HOME/moveit1_install.sh

Moveit的使用

根据作为Moveit一键配置安装的基础教程示例的Panda机械臂,有如下使用方式在RViz中进行简单使用。

roslaunch panda_moveit_config demo.launch
roslaunch panda_moveit_config demo_gazebo.launch

具体的使用方式,在使用Moveit一键配置安装脚本时会有提示。

config配置包的文件解析

robotname_moveit_config里面有太多的文件,通常会让用户感到头疼,以下对这些配置包里的各个内容作详细的解析,可根据需求查阅。
如果希望对config中的经典demo有所了解,推荐阅读demo.launchdemo_gazebo.launch文件切片解析

切片解析1: demo.launch

文件名为robot_moveit_config/launch/demo.launch,是Moveit的经典demo,在RViz中显示机器人模型并通过RViz的MotionPlanning插件来控制Moveit完成运动规划和轨迹控制。
以下为Moveit官方案例的panda_moveit_config/launch/demo.launch完整代码:

<launch>
  <arg name="arm_id" default="panda" />
  <!-- specify the planning pipeline -->
  <arg name="pipeline" default="ompl" />

  <!-- By default, we do not start a database (it can be large) -->
  <arg name="db" default="false" />
  <!-- Allow user to specify database location -->
  <arg name="db_path" default="$(find panda_moveit_config)/default_warehouse_mongo_db" />

  <!-- By default, we are not in debug mode -->
  <arg name="debug" default="false" />

  <!-- By default we will load the gripper -->
  <arg name="load_gripper" default="true" />

  <!-- By default, we will load or override the robot_description -->
  <arg name="load_robot_description" default="true"/>

  <!-- Choose controller manager: fake, simple, or ros_control -->
  <arg name="moveit_controller_manager" default="fake" />
  <!-- Set execution mode for fake execution controllers -->
  <arg name="fake_execution_type" default="interpolate" />
  <!-- Transmission used for joint control: position, velocity, or effort -->
  <arg name="transmission" />                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                

  <!-- By default, hide joint_state_publisher's GUI in 'fake' controller_manager mode -->
  <arg name="use_gui" default="false" />
  <arg name="use_rviz" default="true" />
  <!-- Use rviz config for MoveIt tutorial -->
  <arg name="rviz_tutorial" default="false" />

  <!-- If needed, broadcast static tf for robot root -->
  <node pkg="tf2_ros" type="static_transform_publisher" name="virtual_joint_broadcaster_0" args="0 0 0 0 0 0 world $(arg arm_id)_link0" />



  <group if="$(eval arg('moveit_controller_manager') == 'fake')">
    <!-- We do not have a real robot connected, so publish fake joint states via a joint_state_publisher
         MoveIt's fake controller's joint states are considered via the 'source_list' parameter -->
    <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" unless="$(arg use_gui)">
      <rosparam param="source_list">[move_group/fake_controller_joint_states]</rosparam>
    </node>
    <!-- If desired, a GUI version is available allowing to move the simulated robot around manually
         This corresponds to moving around the real robot without the use of MoveIt. -->
    <node name="joint_state_publisher" pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" if="$(arg use_gui)">
      <rosparam param="source_list">[move_group/fake_controller_joint_states]</rosparam>
    </node>

    <!-- Given the published joint states, publish tf for the robot links -->
    <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" respawn="true" output="screen" />
  </group>

  <!-- Run the main MoveIt executable without trajectory execution (we do not have controllers configured by default) -->
  <include file="$(dirname)/move_group.launch" pass_all_args="true">
    <arg name="allow_trajectory_execution" value="true" />
    <arg name="info" value="true" />
  </include>

  <!-- Run Rviz and load the default config to see the state of the move_group node -->
  <include file="$(dirname)/moveit_rviz.launch" if="$(arg use_rviz)">
    <arg name="rviz_tutorial" value="$(arg rviz_tutorial)"/>
    <arg name="rviz_config" value="$(dirname)/moveit.rviz"/>
    <arg name="debug" value="$(arg debug)"/>
  </include>

  <!-- If database loading was enabled, start mongodb as well -->
  <include file="$(dirname)/default_warehouse_db.launch" if="$(arg db)">
    <arg name="moveit_warehouse_database_path" value="$(arg db_path)"/>
  </include>

</launch>

对于代码中的各个部分,有以下解析:

arm_id

  <arg name="arm_id" default="panda" />
  # 机器人的标识符。这个参数指定在机器人有多个实现时使用哪一个。
  # 当多机器人协同时,标识符可以用来区分它们。默认值设置为“panda”

pipeline

  <arg name="pipeline" default="ompl" />
  # 机器人运动规划的管道。
  # MoveIt提供了几种规划算法,例如OMPL、SBPL等。此参数允许用户选择使用哪种算法进行运动规划。默认值为“ompl”。

关于OMPL(Open Motion Planning Library)算法,可参考OMPL官方文档、OMPL Primer

db&db_path

  <!-- By default, we do not start a database (it can be large) -->
  <arg name="db" default="false" />
  <!-- Allow user to specify database location -->
  <arg name="db_path" default="$(find panda_moveit_config)/default_warehouse_mongo_db" />
  # db:指定是否启动运动规划数据库。
  # 如果设为true,MoveIt会启动MongoDB数据库来存储或检索运动规划数据。默认值为false。
  # db_path:指定运动规划数据库的路径。
  # 这个参数允许用户指定MongoDB数据库的位置。默认值设置为“$(find panda_moveit_config)/default_warehouse_mongo_db”。

运动规划数据通常是指用于机器人或移动设备规划运动路径的数据,例如,目标位置、机器人当前位置、避障信息等。
在MoveIt中,Warehouse的作用是提供持久化的存储方式,以保存完整的计划场景和机器人状态。通过使用适当的存储插件(如warehouse_ros_mongowarehouse_ros_sqlite),用户可以将场景和状态保存到MongoDBSQLite等不同的后端数据库中。这使得用户可以在不同的时间和地点重新加载和使用保存的场景和状态。

除了提供持久化存储的功能之外,Warehouse还可以用于数据查询、过滤和排序。通过使用MoveIt提供的接口,用户可以方便地从Warehouse中检索和获取他们所需要的场景和状态。这对于机器人操作中的实时计划和决策非常有用,因为它可以快速地检索到特定的场景和状态,而无需每次都重新计算或重新生成它们。

MongoDB是一个流行的文档式(NoSQL)数据库,它以二进制JSON格式存储数据。与传统的关系型数据库不同,MongoDB的结构灵活,适合存储半结构化数据或任意类型的文档。

关于在Moveit中使用数据库来存储和调用运动规划数据,可参考Moveit1 Warehouse MangoDB

debug

  <!-- By default, we are not in debug mode -->
  <arg name="debug" default="false" />
  # debug:指定是否启用RViz调试模式。如果设为true,则启用RViz中的调试模式。默认为false。
  # 该参数也会被传递给move_group.launch,用于开启move_group的GDB调试。

RViz debug mode可以帮助开发人员诊断和解决问题。在调试模式下,Rviz可以显示更多的调试信息,例如ROS消息的内容和接收频率,帧率信息,以及RViz可视化中使用的资源和内存使用情况等。

这些信息可以帮助开发人员快速定位和解决问题,例如调试节点之间的通信问题、可视化资源的使用情况等。同时,调试模式还可以显式地显示Rviz中各种可视化元素的名称,标签和坐标信息, 以便更好的理解和调整要素的位置动态。

load_gripper

  <!-- By default we will load the gripper -->
  <arg name="load_gripper" default="true" />
  # load_gripper:指定是否加载机器人夹爪的控制器。此参数用于加载和配置夹爪的运动控制器。默认值为true。
  # 该参数将通过 pass_all_args="true" 属性被传递给move_group.launch

load_robot_description

  <!-- By default, we will load or override the robot_description -->
  <arg name="load_robot_description" default="true"/>
  # 指定是否加载或覆盖机器人描述。MoveIt需要知道机器人的描述才能进行规划和控制。
  # 这个参数用于加载机器人的URDF文件或覆盖已有的机器人描述。默认值为true。
  # 该参数将通过 pass_all_args="true" 属性被传递给move_group.launch

load_robot_description将机器人的描述文件(通常为urdf或sdf格式)加载到ROS参数服务器中。如果load_robot_description参数为true,则会加载或覆盖先前设置的机器人描述文件。如果为false,则使用先前加载的机器人描述文件。

robot_description的发布通过robot_state_publisher节点来实现。该节点从参数服务器中获取机器人的描述信息,计算机器人每个联动部件的变换,并发布机器人的tf树和关节状态信息。 move_group节点接收tf和关节状态信息,用于运动规划和执行。

moveit_controller_manager

  <!-- Choose controller manager: fake, simple, or ros_control -->
  <arg name="moveit_controller_manager" default="fake" />
  # moveit_controller_manager:选择控制器管理器的类型。
  # 控制器管理器用于加载和配置机器人的控制器。
  # MoveIt提供了几种类型的控制器管理器,包括“fake”,“simple”和“ros_control”。默认值为“fake”。

MoveIt提供的控制器管理器包括以下三种类型:

  1. fake: 这种类型的控制器仅模拟运动,不与真实机器人进行通信。它通常用于快速测试和演示,对于仿真,通常使用fake控制器来模拟运动。

  2. simple: 这种类型的控制器与机器人进行通信,但仅提供了基本控制,例如直线/圆弧插值等。它适用于一些较简单的机器人。

  3. ros_control: 这是一种更灵活的控制器类型,可支持各种机器人和控制器硬件。它提供了更高级别的控制接口,例如电机控制器接口和传感器读取接口。
    根据应用场景和机器人的要求,使用不同类型的控制器管理器。
    ros_control是机器人强大的控制器,可参考ros_control WIKI文档和ros_control源代码


图片来源:ROS WIKI ros_control

fake_execution_type

  <!-- Set execution mode for fake execution controllers -->
<arg name="fake_execution_type" default="interpolate" />
  # fake_execution_type:设置虚拟控制器的执行模式。
  # 如果选择“fake”控制器管理器,则使用虚拟控制器进行模拟运动。
  # 此参数指定用于虚拟运动的执行模式,包括“interpolate”,“last point。默认值为“interpolate”。

interpolate:该选项表示MoveIt假设控制器将在轨迹的每个目标点之间进行插值。这种方式可以模拟连续的轨迹执行过程。

last point:此选项表示MoveIt假设控制器将直接跳到轨迹的最后一个目标点。这种方式可以模拟机器人快速执行任务。
launch/fake_moveit_controller_manager.launch.xml文件中发现了这两种描述,不确定是否有第三种via points来和官方文档中关于fake controller的描述匹配。
但在Moveit官方文档中有关于fake controller的详细描述,可参考Moveit1 Noetic官方文档

MoveIt提供了一系列虚拟轨迹控制器,可用于模拟。其中,虚拟控制器的配置文件位于 config/fake_controllers.yaml

可以根据需要调整以下控制器类型:

  • interpolate: 在经过关键点时执行平稳插补,默认用于可视化。
  • via points: 遍历关键点,但不插补它们之间的点,用于可视化调试。
  • last point: 直接跳转到轨迹的最后一个点,用于离线基准测试。

虚拟控制器类型信息可在 fake_controllers.yaml 文件中配置。对于每个控制器,都需要指定名称、类型和涉及的关节。其中,频率为 rate: 10,可用于插补控制器。但在对夹爪进行控制时,关节为空列表 []

示例:

rate: 10
controller_list:
  - name: fake_arm_controller
    type: interpolate
    joints:
      - joint_1
      - joint_2
      - joint_3
      - joint_4
      - joint_5
      - joint_6
  - name: fake_gripper_controller
    joints:
      []

transmission

  <!-- Transmission used for joint control: position, velocity, or effort -->
  <arg name="transmission" /> 
  # 设置用于关节控制的传输类型。这个参数用来选择传输类型,例如position、velocity或effort。
  # 默认情况下,这个参数未设置,不用理会。    

use_gui

  <!-- By default, hide joint_state_publisher's GUI in 'fake' controller_manager mode -->
  <arg name="use_gui" default="false" />

  # use_gui:指定是否显示joint_state_publisher的GUI界面。
  # 如果设为true,则会在启动期间打开一个窗口,显示机器人的关节姿态。默认值为false。

在MoveIt的demo.launch中,设置了一个默认的假控制器管理器(fake controller manager)模式,这意味着没有实际的控制器与机械臂连接。

在这种模式下,joint_state_publisher发布的关节状态信息是通过fake_controller_joint_states话题获得,隐藏其图形用户界面(GUI)可以避免用户误操作。因此,默认情况下隐藏joint_state_publisher的GUI可以增加系统的可靠性。

use_rviz

  <arg name="use_rviz" default="true" />
  # use_rviz:指定是否启用RViz。如果此参数设为true,则MoveIt将启动RViz进行可视化。默认值为true。
  <!-- Use rviz config for MoveIt tutorial -->
  <arg name="rviz_tutorial" default="false" />
  # rviz_tutorial:指定是否使用RViz配置进行MoveIt教程演示。
  # 如果设为true,则MoveIt将加载RViz演示配置。默认值为false。

虚拟关节静态TF节点

  <!-- If needed, broadcast static tf for robot root -->
  <node pkg="tf2_ros" type="static_transform_publisher" name="virtual_joint_broadcaster_0" args="0 0 0 0 0 0 world $(arg arm_id)_link0" />
  # 广播虚拟关节的静态变换
  # 将world坐标系映射到机器人的物理坐标系中的起点$(arg arm_id)_link0

通过使用虚拟关节,引入一个虚拟的“基准”点,来描述机器人在其环境中的位置,可以将机器人的关节状态映射到物理世界中的位置和姿态,以便进行逆运动学计算,规划器可以使用这些信息来规划运动轨迹或生成机器人姿态。

关节状态及机器人整体状态

  <group if="$(eval arg('moveit_controller_manager') == 'fake')">
    <!-- We do not have a real robot connected, so publish fake joint states via a joint_state_publisher
         MoveIt's fake controller's joint states are considered via the 'source_list' parameter -->
    <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" unless="$(arg use_gui)">
      <rosparam param="source_list">[move_group/fake_controller_joint_states]</rosparam>
    </node>
    <!-- If desired, a GUI version is available allowing to move the simulated robot around manually
         This corresponds to moving around the real robot without the use of MoveIt. -->
    <node name="joint_state_publisher" pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" if="$(arg use_gui)">
      <rosparam param="source_list">[move_group/fake_controller_joint_states]</rosparam>
    </node>

    <!-- Given the published joint states, publish tf for the robot links -->
    <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" respawn="true" output="screen" />
  </group>
 # 如果moveit_controller_manager的类型是fake
 # 则启动joint_state_publisher和robot_state_publisher
 # 默认不启用joint_state_publisher_gui,以防用户在图形化窗口不小心调节了关节状态值
roslaunch xml

如果不熟悉这个代码片段里用到的ROS1 launch XML语言,可参考ROS1 Launch文档

group的作用

这一个节点组group的作用是当Moveit的控制器管理器被设为fake类型时,该节点组会发布虚拟的机器人的关节状态/joint_states,然后通过机器人状态发布器发布虚拟机器人的/tf话题,以便在 RViz 订阅该/tf话题并在RViz中显示虚拟机器人的状态。

在这个group中,与robot_state_publisher一起使用的还有joint_state_publisher节点,它用于模拟发布关节状态信息。joint_state_publisher会定期发布sensor_msgs/JointState类型的/joint_states话题,其中包含机器人各个关节的状态信息。robot_state_publisher会订阅这些消息,并根据机器人的URDF模型计算机器人各个部件的位姿信息,并发布/tf话题,最终完成机器人状态的更新和发布。

图解各节点关系

rqt_graph可知在这个demo中的各个节点及话题关系:

  1. /move_group 节点发布/move_group/fake_controller_joint_states话题
  2. /joint_state_publisher节点订阅/move_group/fake_controller_joint_states话题
  3. /joint_state_publisher节点发布/joint_state话题
  4. /robot_state_publisher节点订阅/joint_state话题
  5. /robot_state_publisher节点发布/tf话题
  6. 虚拟关节静态TF节点发布/tf话题
  7. /move_group订阅/tf话题,类型为
  8. RViz订阅/tf话题

joint_state_publisher

Joint State Publisher是一个 ROS 包,用于发布机器人非固定关节的关节状态/joint_states, 话题类型为sensor_msgs/JointState
在读取机器人的URDF 描述 robot_description 参数后,它会识别所有非固定关节,创建具有这些非固定关节的 JointState 消息,来设置和发布机器人关节状态值joint state values
它可以与 robot_state_publisher 一起使用,以发布所有关节状态的变换。

joint_state_publisher的输入

joint_state_publisher订阅来自参数服务器的robot_description,找到机器人描述中的所有非固定关节,并发布带有这些关节状态值的sensor_msgs/JointState类型消息。

joint_state_publisher可将source_list作为输入,这是一个带有多个话题名的字符串列表,默认为空,将需要订阅的各个话题名填入其中,这些要订阅的话题是关于关节状态值的,话题类型也为sensor_msgs/JointState

在GUI模式下,joint_state_publisher_gui能够接收来自joint_state_publisher_gui图形化窗口工具的直接关节状态值(比如角度),这个状态值由用户拖动角度条来赋予。

在这个Moveit的案例中,/joint_state_publisher节点订阅了来自/move_group/move_group/fake_controller_joint_states话题,source_list参数的内容为[move_group/fake_controller_joint_states]

joint_state_publisher的输出

joint_state_publisher节点发布包含机器人关节name,位置position,速度velocity和力度级别effort等的/joint_states话题,话题类型为sensor_msgs/JointState

robot_state_publisher

Robot State Publisher是一个ROS包,负责发布机器人整体运动学链的状态信息,包括关节和链路名称、父子关系以及每个链路的位置和方向等信息。该包对于在 RViz 或其他可视化工具中可视化机器人姿态至关重要。

它利用参数服务器中的robot_description 参数指定的通用机器人描述格式(URDF)和来自 /joint_states 话题,话题类型为sensor_msgs/msg/JointState的关节状态值组,来计算机器人的正向运动学,并发布/tf话题。

robot_state_publisher的输入

robot_state_publisher在启动时会从参数服务器中的robot_description 加载机器人的运动学树模型URDF,可以通过启动文件传递robot_description参数,其值为机器人的URDF描述字符串。

同时,robot_state_publisher要订阅joint_states话题,获取每个关节的状态值信息。
这些关节状态信息joint states用于更新运动学树模型,进而计算出机器人各个杆件Link的3D位姿信息Pose

robot_state_publisher的输出

对于固定关节,robot_state_publisher将发布/tf_static话题,类型为tf2_msgs/msg/TFMessage
对于可动关节,robot_state_publisher发布/tf话题,类型为tf2_msgs/msg/TFMessage
固定关节的位姿信息会在节点启动时发布到/tf_static话题,这些信息将在历史记录中保存。而可动关节的位姿信息会在/joint_states话题接收到相应关节状态的更新时,及时发布到/tf话题中。

关于具体的使用例子,可以查看Gihub robot_state_publisher


图片来源:ROS WIKI robot_state_publisher

加载move_group

  <!-- Run the main MoveIt executable without trajectory execution (we do not have controllers configured by default) -->
  <include file="$(dirname)/move_group.launch" pass_all_args="true">
    <arg name="allow_trajectory_execution" value="true" />
    <arg name="info" value="true" />
  </include>
  # 启动move_group.launch来加载move_group相关内容
  # 通过pass_all_args="true" 将demo.launch文件的所有arg参数传递给move_group.launch作为参数
  # 设置 allow_trajectory_execution 为 true,
  # 可以让 move_group 在运行过程中尝试让机器人执行这些预定义的轨迹
  # 但如果该参数设置为 false,则只会规划但不会执行规划的轨迹,机器人将保持静止
  # 此功能对于测试和调试非常有用,因为它允许操纵轨迹,而无需在机器人上实际执行它们
  # 它在关注安全的情况下也很有用,因为它提供了一种防止意外执行危险轨迹的方法
  # 如果将 info 设置为 true,则 move_group 会在控制台输出调试信息

pass_all_args="true"是将所有的Father Launch传入的参数都传递给Child Launch的一个属性。

在MoveIt的demo.launch文件中,pass_all_args="true"被用于将Father Launch的所有arg参数传递给Child Launch,这意味着,Child Launch可以获取到来自Father Launch的所有参数,并继承它们。

在这个案例中,也就是将demo.launch的所有arg内参传递给move_group.launch
注意,如果不设置pass_all_args="true"Child Launch将只接收在include标记中明确列举的参数。只传递include标记中明确列举的参数有助于在Launch嵌套时控制参数不发生混乱。

加载RViz

  <!-- Run Rviz and load the default config to see the state of the move_group node -->
  <include file="$(dirname)/moveit_rviz.launch" if="$(arg use_rviz)">
    <arg name="rviz_tutorial" value="$(arg rviz_tutorial)"/>
    <arg name="rviz_config" value="$(dirname)/moveit.rviz"/>
    <arg name="debug" value="$(arg debug)"/>
  </include>
  # 当use_rviz=true时运行moveit_rviz.launch文件
  # 并传递参数rviz_tutorial用于选择是否使用Moveit RViz教学模式
  # rviz_config的值用于打开同目录下的/moveit.rviz配置文件
  # debug的值用来设置是否开启RViz的debug模式

加载数据库

  <!-- If database loading was enabled, start mongodb as well -->
  <include file="$(dirname)/default_warehouse_db.launch" if="$(arg db)">
    <arg name="moveit_warehouse_database_path" value="$(arg db_path)"/>
  </include>
  # 当参数db=true时,运行default_warehouse_db.launch
  # 向default_warehouse_db.launch传入参数moveit_warehouse_database_path,参数值为该数据库的路径

切片解析2: move_group.launch

文件名为robot_moveit_config/launch/move_group.launch,用于启动move_group节点和相关的功能,move_group节点是MoveIt软件包中的一个关键组件,它提供了一种接口,用于执行MoveIt的各种功能,例如规划、执行、运动学计算等。
它通过与运动控制硬件和规划器交互,实现机器人运动的规划和执行。
move_group.launch文件在panda_moveit_config/launch/demo.launch中作为Child Launch文件被启动。

以下为Moveit官方案例的panda_moveit_config/launch/move_group.launch完整代码:

<launch>

  <!-- GDB Debug Option -->
  <arg name="debug" default="false" />
  <arg unless="$(arg debug)" name="launch_prefix" value="" />
  <arg     if="$(arg debug)" name="launch_prefix"
           value="gdb -x $(dirname)/gdb_settings.gdb --ex run --args" />

  <!-- Verbose Mode Option -->
  <arg name="info" default="$(arg debug)" />
  <arg unless="$(arg info)" name="command_args" value="" />
  <arg     if="$(arg info)" name="command_args" value="--debug" />

  <!-- move_group settings -->
  <arg name="pipeline" default="ompl" />
  <arg name="allow_trajectory_execution" default="true"/>
  <arg name="moveit_controller_manager" default="simple" />
  <arg name="fake_execution_type" default="interpolate"/>
  <arg name="max_safe_path_cost" default="1"/>
  <arg name="publish_monitored_planning_scene" default="true"/>

  <arg name="capabilities" default=""/>
  <arg name="disable_capabilities" default=""/>

  <!--Other settings-->
  <arg name="load_gripper" default="true" />
  <arg name="transmission" default="effort" />
  <arg name="arm_id" default="panda" />

  <arg name="load_robot_description" default="true" />
  <!-- load URDF, SRDF and joint_limits configuration -->
  <include file="$(dirname)/planning_context.launch">
    <arg name="load_robot_description" value="$(arg load_robot_description)" />
    <arg name="load_gripper" value="$(arg load_gripper)" />
    <arg name="arm_id" value="$(arg arm_id)" />
  </include>

  <!-- Planning Pipelines -->
  <group ns="move_group/planning_pipelines">

    <!-- OMPL -->
    <include file="$(dirname)/planning_pipeline.launch.xml">
      <arg name="pipeline" value="ompl" />
      <arg name="arm_id" value="$(arg arm_id)" />
    </include>

    <!-- CHOMP -->
    <include file="$(dirname)/planning_pipeline.launch.xml">
      <arg name="pipeline" value="chomp" />
      <arg name="arm_id" value="$(arg arm_id)" />
    </include>

    <!-- Pilz Industrial Motion -->
    <include file="$(dirname)/planning_pipeline.launch.xml">
      <arg name="pipeline" value="pilz_industrial_motion_planner" />
      <arg name="arm_id" value="$(arg arm_id)" />
    </include>

    <!-- Support custom planning pipeline -->
    <include if="$(eval arg('pipeline') not in ['ompl', 'chomp', 'pilz_industrial_motion_planner'])"
             file="$(dirname)/planning_pipeline.launch.xml">
      <arg name="pipeline" value="$(arg pipeline)" />
      <arg name="arm_id" value="$(arg arm_id)" />
    </include>
  </group>

  <!-- Trajectory Execution Functionality -->
  <include ns="move_group" file="$(dirname)/trajectory_execution.launch.xml" pass_all_args="true" if="$(arg allow_trajectory_execution)">
    <arg name="moveit_manage_controllers" value="true" />
  </include>

  <!-- Sensors Functionality -->
  <include ns="move_group" file="$(dirname)/sensor_manager.launch.xml" if="$(arg allow_trajectory_execution)">
    <arg name="moveit_sensor_manager" value="panda" />
  </include>

  <!-- Start the actual move_group node/action server -->
  <node name="move_group" launch-prefix="$(arg launch_prefix)" pkg="moveit_ros_move_group" type="move_group" respawn="false" output="screen" args="$(arg command_args)">
    <!-- Set the display variable, in case OpenGL code is used internally -->
    <env name="DISPLAY" value="$(optenv DISPLAY :0)" />

    <param name="allow_trajectory_execution" value="$(arg allow_trajectory_execution)"/>
    <param name="sense_for_plan/max_safe_path_cost" value="$(arg max_safe_path_cost)"/>
    <param name="default_planning_pipeline" value="$(arg pipeline)" />
    <param name="capabilities" value="$(arg capabilities)" />
    <param name="disable_capabilities" value="$(arg disable_capabilities)" />

    <!-- Publish the planning scene of the physical robot so that rviz plugin can know actual robot -->
    <param name="planning_scene_monitor/publish_planning_scene" value="$(arg publish_monitored_planning_scene)" />
    <param name="planning_scene_monitor/publish_geometry_updates" value="$(arg publish_monitored_planning_scene)" />
    <param name="planning_scene_monitor/publish_state_updates" value="$(arg publish_monitored_planning_scene)" />
    <param name="planning_scene_monitor/publish_transforms_updates" value="$(arg publish_monitored_planning_scene)" />
  </node>

</launch>

GDB

  <!-- GDB Debug Option -->
  <arg name="debug" default="false" />
  <arg unless="$(arg debug)" name="launch_prefix" value="" />
  <arg     if="$(arg debug)" name="launch_prefix"
           value="gdb -x $(dirname)/gdb_settings.gdb --ex run --args" />
  # GDB Debug Option:用于设置是否启用GDB调试。
  # 当 GDB debug模式关闭时,launch_prefix值为空
  # 当 GDB debug模式开启时,launch_launch_prefix为GDB相关命令

GNU symbolic debugger(GDB),是 Linux 平台下最常用的一款程序调试器。GDB 编译器通常以 gdb 命令的形式在终端(Shell)中使用。

调试工具可使被调试程序在指定代码处暂停运行,并查看当前程序的运行状态(例如当前变量的值,函数的执行结果等),也就是断点调试
通过调试可以了解程序中出现的逻辑错误。
ubuntu是自带GDB调试工具的:

test@ubuntu:~$ gdb -v  # Check the version of GDB
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

在这个代码片段中
gdb: 是 GNU 调试器(GDB)的命令,它用于调试程序并跟踪其执行过程。

gdb_settings.gdb包含一系列的GDB命令和调试设置,用于在调试过程中自动执行一些操作。
这些命令脚本文件可以包含启动GDB会话时要执行的初始化命令,设置断点,指定观察点,配置调试选项,执行一系列的调试操作以及其他自定义的GDB命令。通过编写调试脚本,可以自动执行一系列的调试操作,以节省手动输入命令的时间和精力。
panda_moveit_config/launch/文件夹下并未发现该文件,可能会自动生成或者Moveit的开发者不希望用户使用

gdb -x $(dirname)/gdb_settings.gdb中的-x使得gdb_settings.gdb脚本文件被加载到GDB中,这将使GDB执行gdb_settings.gdb脚本文件文件中定义的命令和操作。
--ex run选项告诉 GDB 在启动调试器后立即执行 run 命令,使需要调试的程序开始运行。
--args 选项后面可以跟随要调试的程序及其参数。

在这个案例中,通过启用debug模式,使得launch_prefix为GDB相关内容,这个前缀将在 <node name="move_group" launch-prefix="$(arg launch_prefix)" pkg="moveit_ros_move_group" type="move_group" respawn="false" output="screen" args="$(arg command_args)">中被使用,也就是在启动move_group节点时会被作为launch-prefix传入。

info模式

  <!-- Verbose Mode Option -->
  <arg name="info" default="$(arg debug)" />
  <arg unless="$(arg info)" name="command_args" value="" />
  <arg     if="$(arg info)" name="command_args" value="--debug" />
  # Verbose Mode Option:用于设置是否启用详细模式。
  # 当开启详细模式时,move_group会在console输出更多信息,帮助用户了解move_group中发生的事情
  # info:用于指示是否启用详细模式的参数,默认与debug参数相同。
  # 当开启debug时,verbose详细模式也将被默认开启
  # 如果详细模式开启,则command_args参数值为--debug

在这个案例中,move_group节点启动时将使用command_args参数作为参数传入move_group节点:
<node name="move_group" launch-prefix="$(arg launch_prefix)" pkg="moveit_ros_move_group" type="move_group" respawn="false" output="screen" args="$(arg command_args)">

info参数在demo.launch中作为参数被pass_all_args="true"传入到move_group.launch中作为参数。

pipeline

  <!-- move_group settings -->
  <arg name="pipeline" default="ompl" />
  # 机器人运动规划的管道。
  # MoveIt提供了几种规划算法,例如OMPL、SBPL等。此参数允许用户选择使用哪种算法进行运动规划。默认值为“ompl”。

关于OMPL(Open Motion Planning Library)算法,可参考OMPL官方文档、OMPL Primer
在这个案例中,pipeline参数在demo.launch中作为参数被pass_all_args="true"传入到move_group.launch中作为参数。

allow_trajectory_execution

  <arg name="allow_trajectory_execution" default="true"/>
  # 设置 allow_trajectory_execution 为 true,
  # 可以让 move_group 在运行过程中尝试让机器人执行这些预定义的轨迹
  # 但如果该参数设置为 false,则只会规划但不会执行规划的轨迹,机器人将保持静止
  # 此功能对于测试和调试非常有用,因为它允许操纵轨迹,而无需在机器人上实际执行它们
  # 它在关注安全的情况下也很有用,因为它提供了一种防止意外执行危险轨迹的方法

在这个案例中,allow_trajectory_execution参数在demo.launch中作为include file="$(dirname)/move_group.launch"arg参数被传入到move_group.launch中作为参数。

moveit_controller_manager

  <arg name="moveit_controller_manager" default="simple" />
  # moveit_controller_manager:选择控制器管理器的类型,在move_group中默认值为“simple”。
  # 控制器管理器用于加载和配置机器人的控制器。
  # MoveIt提供了几种类型的控制器管理器,包括“fake”,“simple”和“ros_control”。

MoveIt提供的控制器管理器包括以下三种类型:

  1. fake: 这种类型的控制器仅模拟运动,不与真实机器人进行通信。它通常用于快速测试和演示,对于仿真,通常使用fake控制器来模拟运动。

  2. simple: 这种类型的控制器与机器人进行通信,但仅提供了基本控制,例如直线/圆弧插值等。它适用于一些较简单的机器人。

  3. ros_control: 这是一种更灵活的控制器类型,可支持各种机器人和控制器硬件。它提供了更高级别的控制接口,例如电机控制器接口和传感器读取接口。
    根据应用场景和机器人的要求,使用不同类型的控制器管理器。

在这个案例中,moveit_controller_manager参数在demo.launch中通过pass_all_args="true"被传入到move_group.launch中作为参数。

move_group.launch中这个参数默认为simple,而在demo.launch中为fake,这是因为demo.launch是单纯用于RViz中测试MotionPlanning插件的,通过demo.launch来启动move_group.launch时,控制器的类型为fake

fake_execution_type

<arg name="fake_execution_type" default="interpolate" />
  # fake_execution_type:设置虚拟控制器的执行模式。
  # 如果选择“fake”控制器管理器,则使用虚拟控制器进行模拟运动。
  # 此参数指定用于虚拟运动的执行模式,包括“interpolate”,“last point。默认值为“interpolate”。

interpolate:该选项表示MoveIt假设控制器将在轨迹的每个目标点之间进行插值。这种方式可以模拟连续的轨迹执行过程。

last point:此选项表示MoveIt假设控制器将直接跳到轨迹的最后一个目标点。这种方式可以模拟机器人快速执行任务。
launch/fake_moveit_controller_manager.launch.xml文件中发现了这两种描述,不确定是否有第三种via points来和官方文档中关于fake controller的描述匹配。
但在Moveit官方文档中有关于fake controller的详细描述,可参考Moveit1 Noetic官方文档

MoveIt提供了一系列虚拟轨迹控制器,可用于模拟。其中,虚拟控制器的配置文件位于 config/fake_controllers.yaml

可以根据需要调整以下控制器类型:

  • interpolate: 在经过关键点时执行平稳插补,默认用于可视化。
  • via points: 遍历关键点,但不插补它们之间的点,用于可视化调试。
  • last point: 直接跳转到轨迹的最后一个点,用于离线基准测试。

虚拟控制器类型信息可在 fake_controllers.yaml 文件中配置。对于每个控制器,都需要指定名称、类型和涉及的关节。其中,频率为 rate: 10,可用于插补控制器。但在对夹爪进行控制时,关节为空列表 []

示例:

rate: 10
controller_list:
  - name: fake_arm_controller
    type: interpolate
    joints:
      - joint_1
      - joint_2
      - joint_3
      - joint_4
      - joint_5
      - joint_6
  - name: fake_gripper_controller
    joints:
      []

max_safe_path_cost

  <arg name="max_safe_path_cost" default="1"/>
  # max_safe_path_cost:最大安全路径成本,默认为1。
  # 作为参数sense_for_plan/max_safe_path_cost的值被传入move_group节点
  # 这个参数值将影响move_group路径规划的行为。
  # 目前没有发现该值的使用标准和方式,可以不理会。

max_safe_path_cost参数用于设置移动组(MoveGroup)中的最大安全路径成本参数sense_for_plan/max_safe_path_cost。这个参数定义了移动组在规划机器人路径时所能接受的最大路径成本。路径成本是基于路径上的障碍物、碰撞风险等因素计算得出的。

当进行路径规划时,MoveIt会根据给定的目标设置和约束条件尝试找到一条满足安全性要求的路径。如果生成的路径的总成本(代价)超过了max_safe_path_cost参数指定的阈值,那么MoveIt将认为该路径不是安全的,将停止搜索更多的路径。这有助于避免规划出不安全或代价过高的路径。

较低的最大安全路径成本阈值会导致规划器更加谨慎并更多地考虑避免碰撞和障碍物,因为很容易到达最大的安全成本阈值,变得不安全。

而较高的最大安全路径成本可以帮助增加规划器生成有效路径的能力,因为有更加宽容的安全路径成本范围可供规划器去生成路径。

通过设置max_safe_path_cost参数,可以限制规划器为机器人生成的路径选择最安全的路径。

publish_monitored_planning_scene

  <arg name="publish_monitored_planning_scene" default="true"/>
  # 是否发布监视的规划场景,默认为true。

在MoveIt的move_group.launch中,<arg name="publish_monitored_planning_scene" default="true"/>用于设置是否发布监视的的规划场景。

如果该参数被设置为true,发布监视的规划场景被启用,它会将当前的规划场景发布到特定的话题,其他节点或工具可以通过订阅该话题以获取最新的规划场景信息,监视的规划场景包含有关机器人、障碍物、规划请求和其他相关信息的实时数据,
当开启时,用户或系统可以实时监视、分析和响应规划场景的变化,从而进行相应的处理,这对于可视化、调试和其他用途非常有用。

MoveIt的move_group节点会在规划过程中发布监视的规划场景,包括planning_scene_monitor/publish_planning_sceneplanning_scene_monitor/publish_geometry_updatesplanning_scene_monitor/publish_state_updatesplanning_scene_monitor/publish_transforms_updates

capabilities

  <arg name="capabilities" default=""/>
  <arg name="disable_capabilities" default=""/>
  # 用于设置运动规划组(move_group)的功能和禁用功能的选项
  # 无需理会

<arg name="capabilities">用于指定在运动规划组中启用的功能。这些功能包括例如允许规划运动轨迹、执行运动轨迹、执行单个运动目标等。可以通过在<arg name="capabilities">中设置相应的值来启用特定的功能。

<arg name="disable_capabilities">用于禁用运动规划组中的某些功能。通过在<arg name="disable_capabilities">中设置功能的值,可以禁用规划组中不需要的功能。这对于限制或简化运动规划组的功能很有用。

这些选项允许根据应用程序的需求灵活地配置和定制MoveIt的运动规划组的功能。

load_gripper

  <!--Other settings-->
  <arg name="load_gripper" default="true" />
  # 指定是否加载机器人夹爪的控制器。此参数用于加载和配置夹爪的运动控制器。默认值为true。

在这个案例中,load_gripperdemo.launch通过pass_all_args="true"传入move_group.launch

transmission

  <arg name="transmission" default="effort" />
  # 设置用于关节控制的传输类型。这个参数用来选择传输类型,例如position、velocity或effort。
  # 默认情况下,这个参数在move_group中被设置为"effort"

在MoveGroup中,<arg name="transmission" default="effort" />是一个参数,用于指定机械臂的传动类型。此参数指定了机械臂控制器(controller)使用的传动系统类型,默认为”effort”(力/扭矩传动)。

传动类型的选择会影响机械臂在MoveGroup中的控制方式。具体的传动类型包括:

  • Effort Transmission(力/扭矩传动):该传动类型假定机械臂的控制输入是力/扭矩,用于控制关节的扭矩或力。适用于需要对关节施加特定力或扭矩来实现精确控制和力感知的应用。
  • Velocity(速度)适用于控制执行器以特定的速度运动。它可用于需要执行平滑、连续运动的任务。
  • Position(位置)适用于控制执行器移动到特定位置或关节角度。它可用于需要执行准确位置控制的任务。

如果任务需要施加特定的力或扭矩,可以选择effort控制方式。
如果任务需要平滑连续的运动,可以选择velocity控制方式。
如果任务需要精确的位置控制,可以选择position控制方式
选择合适的传动类型取决于机械臂的具体配置和要求。在配置MoveGroup时,可以根据机械臂的传动系统设置相应的参数,以确保正确的控制信号传递给机械臂。

在这个案例中,transmissiondemo.launch通过pass_all_args="true"传入move_group.launch,在demo.launch中该值为空,也就是使用默认的值为effort

arm_id

  <arg name="arm_id" default="panda" />
  # 机器人的标识符。这个参数指定在机器人有多个实现时使用哪一个。
  # 当多机器人协同时,标识符可以用来区分它们。默认值设置为“panda”

load_robot_description

  <arg name="load_robot_description" default="true" />
  # 指定是否加载或覆盖机器人描述及joint_limits文件。MoveIt需要知道机器人的描述才能进行规划和控制。
  # 这个参数用于加载机器人的URDF文件或覆盖已有的机器人描述。默认值为true。

load_robot_description将机器人的描述文件(通常为urdf或sdf格式)加载到ROS参数服务器中。如果load_robot_description参数为true,则会加载或覆盖先前设置的机器人描述文件。如果为false,则使用先前已经加载了的机器人描述文件。
robot_description的发布通过robot_state_publisher节点来实现。该节点从参数服务器中获取机器人的描述信息,计算机器人每个联动部件的变换,并发布机器人的tf树和关节状态信息。 move_group节点接收tf和关节状态信息,用于运动规划和执行。

在这个案例中,load_robot_descriptiondemo.launch通过pass_all_args="true"传入move_group.launch

URDF/SRDF/joint_limits配置

  <!-- load URDF, SRDF and joint_limits configuration -->
  <include file="$(dirname)/planning_context.launch">
    <arg name="load_robot_description" value="$(arg load_robot_description)" />
    <arg name="load_gripper" value="$(arg load_gripper)" />
    <arg name="arm_id" value="$(arg arm_id)" />
  </include>

嵌套的include指令会调用planning_context.launch文件,并将load_robot_descriptionload_gripperarm_id参数传递给它。

planning_context.launch文件的作用是加载URDF(Unified Robot Description Format)SRDF(Semantic Robot Description Format)和关节限制配置joint_limits configuration等相关文件,为机器人的运动规划上下文planning context创建所需的配置和环境。

运动规划管道

 <!-- Planning Pipelines -->
  <group ns="move_group/planning_pipelines">

    <!-- OMPL -->
    <include file="$(dirname)/planning_pipeline.launch.xml">
      <arg name="pipeline" value="ompl" />
      <arg name="arm_id" value="$(arg arm_id)" />
    </include>

    <!-- CHOMP -->
    <include file="$(dirname)/planning_pipeline.launch.xml">
      <arg name="pipeline" value="chomp" />
      <arg name="arm_id" value="$(arg arm_id)" />
    </include>

    <!-- Pilz Industrial Motion -->
    <include file="$(dirname)/planning_pipeline.launch.xml">
      <arg name="pipeline" value="pilz_industrial_motion_planner" />
      <arg name="arm_id" value="$(arg arm_id)" />
    </include>

    <!-- Support custom planning pipeline -->
    <include if="$(eval arg('pipeline') not in ['ompl', 'chomp', 'pilz_industrial_motion_planner'])"
             file="$(dirname)/planning_pipeline.launch.xml">
      <arg name="pipeline" value="$(arg pipeline)" />
      <arg name="arm_id" value="$(arg arm_id)" />
    </include>
  </group>
  # 启动OMPL规划器
  # 启动CHOMP规划器
  # 启动Pilz Industrial Motion规划器
  # 当还有其他自定义的pipeline时,再启动自定义规划器
  # 自定义规划器的文件为 planning_pipeline.launch.xml
  # 启动的规划器包括预定义的规划器(OMPL、CHOMP和Pilz Industrial Motion)以及自定义规划器
同时加载多个规划器的原因

同时启动这三个规划器的目的是为了提供多种选择和灵活性,以适应不同的运动规划需求和算法偏好。每个规划器都有其独特的算法和特点,可以在不同的场景下产生较好的规划结果。

尽管这三个规划器都被加载,但在实际使用过程中,通常只会选择其中一个规划器进行规划任务

这是因为move_group节点启动时,会选择默认的规划器,这个默认的规划器即是用户传入的pipeline参数,只有与其值匹配的规划器才会真正执行规划任务。

 <param name="default_planning_pipeline" value="$(arg pipeline)" />

因此,只有其中一个规划器会被激活,不会发生冲突。通过在配置文件中选择合适的规划器,并将对应的pipeline参数设置为相应的值,可以确保只有需要的规划器被启动和使用。
这种设计让用户能够灵活选择和切换规划器,以满足其特定的需求和实际情况。

同时,对于GUI控制,通过在RVizMotionPlanning插件中的Context部分可以切换规划

轨迹执行器

  <!-- Trajectory Execution Functionality -->
  <include ns="move_group" file="$(dirname)/trajectory_execution.launch.xml" pass_all_args="true" if="$(arg allow_trajectory_execution)">
    <arg name="moveit_manage_controllers" value="true" />
  </include>
  # 当allow_trajectory_execution=true时,也就是允许轨迹执行时
  # 启动trajectory_execution.launch.xml文件
  # 这个文件负责运行MoveIt的轨迹执行功能
  # 将moveit_manage_controllers参数设置为`true`表示由MoveIt来管理控制器

文件trajectory_execution.launch.xml用于配置MoveIt的轨迹执行器trajectory_execution。而moveit_manage_controllers参数用于控制MoveIt对底层机器人控制器的管理方式。

具体来说,
moveit_manage_controllers="true"意味着MoveIt将管理整个机器人控制系统(包括底层的控制器),并负责确保控制器在需要时启动,并在不需要时关闭。这是最常用的设置,尤其是在使用单一机器人控制器的情况下。

moveit_manage_controllers="false"表示MoveIt不负责底层机器人控制器的启管理工作。这意味着用户需要自行处理底层控制器的管理。这种设置适用于那些已经具有独立的控制器管理系统的用户,或者在使用多个独立控制器的复杂机器人系统中。

通过配置moveit_manage_controllers参数,可以根据实际情况选择是让MoveIt管理机器人控制器,还是由用户自行管理。

传感器管理器

  <!-- Sensors Functionality -->
  <include ns="move_group" file="$(dirname)/sensor_manager.launch.xml" if="$(arg allow_trajectory_execution)">
    <arg name="moveit_sensor_manager" value="panda" />
  </include>
  # 用于管理各个传感器
  # 当允许轨迹控制时才启动传感器管理器
  # 参数moveit_sensor_manager的作用是指定要使用的传感器管理器的名称或标识符
  # 该参数的值用于告知MoveIt系统应该使用哪个传感器管理器来处理与传感器设备的交互
moveit_sensor_manager

传感器管理器moveit_sensor_manager是Moveit中一个负责与传感器设备通信和数据处理的组件。不同的传感器设备可能需要不同的传感器管理器来处理其数据格式、通信接口等特定要求。通过moveit_sensor_manager,可以灵活地配置和切换传感器管理器,以适应不同的传感器设备或需求。

allow_trajectory_execution

allow_trajectory_execution为真的情况下,才需要加载传感器管理器。
这是因为轨迹执行阶段需要使用传感器数据来监测和调整实际的运动执行过程。
如果不执行轨迹,或者不需要基于传感器数据进行实时监测和调整,那么加载传感器管理器可能是不必要的,因此使用allow_trajectory_execution作为启动条件可以根据需要有选择地加载和使用传感器管理器。

sensor_manager.launch.xml

sensor_manager.launch.xml的作用是管理MoveIt中的传感器,它用于配置和启动与MoveIt相关的传感器设备。这可能包括类似深度相机、激光扫描仪或其他传感器设备。该文件定义了传感器设备的参数,例如传感器的类型、发布的话题以及相关的参数设置。

move_group.launch中调用sensor_manager.launch.xml的目的是允许MoveIt系统与传感器设备进行交互,以便在运动规划和执行过程中获取感知数据。通过将传感器启动文件包含到move_group.launch中,MoveGroup节点可以与传感器节点进行通信,并使用传感器数据对运动规划和执行进行增强或调整。

move_group节点

  <!-- Start the actual move_group node/action server -->
  <node name="move_group" launch-prefix="$(arg launch_prefix)" pkg="moveit_ros_move_group" type="move_group" respawn="false" output="screen" args="$(arg command_args)">
    # 根据GDB调试器开关的参数作为launch-prefix
    # launch-prefix用于指定在启动节点时添加的前缀命令。这通常用于设置环境变量或传递特定的命令行参数
    # 运行moveit_ros_move_group包中的move_group文件
    # respawn指定节点是否在结束后重新启动。在这里设置为"false",意味着节点在结束后不会重新启动。
    # output指定输出打印到屏幕上,也就是终端窗口里
    # args="$(arg command_args)"用于传递额外的命令行参数给节点。
    # 此处的command_args参数值是--debug
    # 意味着当debug模式开启时会提供详细信息输出模式
X 服务器

X服务器(X Server)是一个用于图形显示的软件服务,它是在LinuxUnix系统中实现图形用户界面(GUI)的基本组件之一。X服务器管理图形显示设备(如显示器、键盘、鼠标等),接收用户输入并将图形界面渲染到显示器上。
在现代的Linux系统中,常用的X服务器实现是X.Org Server

Ubuntu系统所使用的是Xserver - X Window System display server

X Window System由客户端和服务端组成,服务端X Server负责图形显示,而客户端库X Client根据系统设置的DISPLAY环境变量,将图形显示请求发送给相应的X Server
只需要在远端开启一个X Server,并在目标机器上相应的设置DISPLAY变量,即可完成图形的远程显示。

常见的应用情景是:

ssh -X username@ubuntu-server-ip

在使用ssh -X时,通过 Secure Shell(SSH)进行 X11转发,用户可以在远程服务器上运行图形界面程序,并将其显示到本地计算机上,而无需在本地安装图形界面软件。

这意味着用户可以通过SSH 连接到机器人上进行远程服务器管理,同时在本地计算机上查看和操作远程的图形界面程序,图形界面将通过SSH隧道和X11转发显示在使用的主计算机上。

Display
    <!-- Set the display variable, in case OpenGL code is used internally -->
    <env name="DISPLAY" value="$(optenv DISPLAY :0)" />

在ROS中,用于控制机器人的软件通常是在高级计算机上运行的,而不是边缘端,通常图像并不在边缘端显示。
当涉及到在图形界面上显示或操作时(例如可视化机器人模型、运动规划的可视化结果等),通常会使用OpenGL库进行绘图操作。

设置DISPLAY环境变量是为了确保move_group节点内部的OpenGL代码能够正确地显示图形界面DISPLAY环境变量指定了X Server的地址,它告诉程序在哪里显示图形界面。
<env>是ROS Launch文件中用来设置环境变量的标签。
optenv是ROS Launch文件中的一个函数,用于从系统环境变量中获取值并提供默认值

Linux系统中(例如Ubuntu),DISPLAY环境变量指示了X Server的位置,它的格式通常是hostname:display_number.screen_number。对于本地X Server,一般使用:0来表示默认的第一个显示屏。

$(optenv DISPLAY :0)表示从系统环境变量中获取DISPLAY的值,如果没有找到则使用默认值:0
在这段代码中,通过标签将DISPLAY环境变量设置为$(optenv DISPLAY :0)

这样一来,当move_group节点需要在图形界面上显示结果时,它会使用设置好的DISPLAY环境变量来与X服务器进行通信,以确保OpenGL代码能够正确地渲染和显示图形界面。这样用户就可以通过图形界面来查看和操作机器人的运动规划结果。

move_group的其他参数
    <param name="allow_trajectory_execution" value="$(arg allow_trajectory_execution)"/>
    <param name="sense_for_plan/max_safe_path_cost" value="$(arg max_safe_path_cost)"/>
    <param name="default_planning_pipeline" value="$(arg pipeline)" />
    <param name="capabilities" value="$(arg capabilities)" />
    <param name="disable_capabilities" value="$(arg disable_capabilities)" />
    # 以下为传入move_group节点的参数,他们在此前被介绍过
    # allow_trajectory_execution 允许轨迹执行
    # sense_for_plan/max_safe_path_cost 最大安全路径代价值
    # default_planning_pipeline 默认的规划流水线
    # capabilities 功能 无需理会
    # disable_capabilities 禁止功能 无需理会
move_group发布实际机器人的规划场景的参数
    <!-- Publish the planning scene of the physical robot so that rviz plugin can know actual robot -->
    <param name="planning_scene_monitor/publish_planning_scene" value="$(arg publish_monitored_planning_scene)" />
    <param name="planning_scene_monitor/publish_geometry_updates" value="$(arg publish_monitored_planning_scene)" />
    <param name="planning_scene_monitor/publish_state_updates" value="$(arg publish_monitored_planning_scene)" />
    <param name="planning_scene_monitor/publish_transforms_updates" value="$(arg publish_monitored_planning_scene)" />
  </node>

move_group节点通过发布实际机器人的规划场景,使得RViz能够了解实际机器人的规划场景,需要传入move_group节点的参数包括以下,这些参数将控制对应的话题的发布:
planning_scene_monitor/publish_planning_scene参数用于发布当前规划场景的信息。它将当前的规划场景以消息的形式发布出去,允许其他节点(如可视化工具或运动规划器)订阅并获取当前的规划场景信息。这样可以实时地将最新的场景信息传递给其他节点,以便它们做出相应的决策。

planning_scene_monitor/publish_geometry_updates参数,用于发布物体几何信息的更新。当物体的几何形状发生变化(例如对象被添加、移除、形状发生变化),该话题将更新的几何信息发布出去。这样其他节点可以根据几何更新来调整规划场景,使其保持最新状态。

planning_scene_monitor/publish_state_updates参数,用于发布运动状态的更新。当机器人的状态发生变化(例如关节位置修改,联动状态更新),该话题将机器人的状态信息发布出去。其他节点可以订阅该话题以获取最新的机器人状态信息,以便做出相应的决策。

planning_scene_monitor/publish_transforms_updates参数,用于发布坐标变换的更新。当与机器人相关的坐标变换发生改变时,该话题将变换的更新信息发布出去。其他节点可以订阅该话题以获取最新的坐标变换信息,以便在规划和执行过程中使用正确的坐标变换。

这些参数对应开启关闭的话题的使用可以实现实时的场景更新和状态反馈,使得不同节点之间可以共享和协调规划场景信息,提供更有效的运动规划和执行能力。

切片解析4: planning_context.launch

planning_context.launch文件的作用是加载机器人描述URDF(Unified Robot Description Format)、语义描述SRDF(Semantic Robot Description Format)和关节限制配置joint_limits、笛卡尔限制cartesian_limits、运动学设置等相关文件,为机器人的运动规划安排好所需的配置和环境。

planning_context.launch文件在move_group.launch中被作为嵌套的launch文件调用,并从move_group.launch中获取了参数load_robot_descriptionload_gripperarm_id
完整的代码如下:

<launch>
  <!-- By default we do not overwrite the URDF. Change the following to true to change the default behavior -->
  <arg name="load_gripper" default="true" />
  <arg name="load_robot_description" default="false"/>
  <arg name="arm_id" default="panda" />

  <!-- The name of the parameter under which the URDF is loaded -->
  <arg name="robot_description" default="robot_description"/>

  <!-- Load universal robot description format (URDF) -->
  <param name="$(arg robot_description)" command="xacro '$(find franka_description)/robots/panda/panda.urdf.xacro' hand:=$(arg load_gripper) arm_id:=$(arg arm_id)" if="$(arg load_robot_description)" />

  <!-- The semantic description that corresponds to the URDF -->
  <param name="$(arg robot_description)_semantic" command="xacro '$(find panda_moveit_config)/config/panda.srdf.xacro' hand:=$(arg load_gripper) arm_id:=$(arg arm_id)" />

  <!-- Load updated joint limits (override information from URDF) -->
  <group ns="$(arg robot_description)_planning">
    <rosparam command="load" file="$(find panda_moveit_config)/config/joint_limits.yaml" subst_value="true" />
    <rosparam command="load" file="$(find panda_moveit_config)/config/cartesian_limits.yaml" subst_value="true"/>
  </group>

  <!-- Load default settings for kinematics; these settings are overridden by settings in a node's namespace -->
  <group ns="$(arg robot_description)_kinematics">
    <rosparam command="load" file="$(find panda_moveit_config)/config/kinematics.yaml" subst_value="true"/>
  </group>

</launch>

传入参数

  <!-- By default we do not overwrite the URDF. Change the following to true to change the default behavior -->
  <arg name="load_gripper" default="true" />
  <arg name="load_robot_description" default="false"/>
  <arg name="arm_id" default="panda" />
  # 是否加载夹爪
  # 是否加载URDF模型
  # 机械臂的id,用作识别机器人的标识

载入模型

    <!-- The name of the parameter under which the URDF is loaded -->
    <arg name="robot_description" default="robot_description"/>
    # robot_description参数用于存储加载的机器人的URDF描述对应的参数名,无需理会
  <!-- Load universal robot description format (URDF) -->
    <param name="$(arg robot_description)" command="xacro '$(find franka_description)/robots/panda/panda.urdf.xacro' hand:=$(arg load_gripper) arm_id:=$(arg arm_id)" if="$(arg load_robot_description)" />
# 将URDF文件加载为ROS参数
# 这个URDF文件是由xacro命令从panda.urdf.xacro文件来生成的
# 之前引入的hand和arm_id被传给xacro命令作为参数

如果使用一键安装配置脚本安装了franka_description,则可以在/opt/ros/noetic/share/franka_description/robots/panda目录下找到panda.urdf.xacro

xacro是一个XML宏语言。在这个情况下,xacro被用来处理URDF(Unified Robot Description Format)文件,使得URDF文件更加模块化和易于管理。

hand:=$(arg load_gripper)arm_id:=$(arg arm_id)将会被传入指定的xacro文件中,这些参数在xacro文件中被用来根据需求生成特定的URDF配置。

panda.urdf.xacro

<?xml version='1.0' encoding='utf-8'?>
# XML的版本和编码声明。所有的XML文件都会以这个声明开始
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="panda">
# 定义一个名为“panda”的机器人。xmlns:xacro指定了xacro命名空间的URL
  <xacro:include filename="$(find franka_description)/robots/common/franka_robot.xacro"/>
# 引入另一个xacro文件,路径是通过find指令找到的
# 这是一种模块化设计,允许将机器人模型分割为更小、更易于管理的部分
  <xacro:arg name="arm_id" default="panda" />
# 定义参数名为"arm_id",并设置其默认值为"panda",如果有外部值传入,则为外部传入的值

  <xacro:franka_robot arm_id="$(arg arm_id)"
                 joint_limits="${xacro.load_yaml('$(find franka_description)/robots/panda/joint_limits.yaml')}">
# 调用franka_robot.xacro宏,并将参数arm_id和joint_limits传入
  </xacro:franka_robot>

</robot>

franka_robot.xacro

panda.urdf.xacro所包含的franka_robot.xacro中,对于hand的调用有判断如下:

    <xacro:if value="$(arg hand)">
      <xacro:include filename="$(find franka_description)/robots/common/franka_hand.xacro"/>
      <xacro:franka_hand
          arm_id="$(arg arm_id)"
          rpy="0 0 ${-pi/4}"
          tcp_xyz="$(arg tcp_xyz)"
          tcp_rpy="$(arg tcp_rpy)"
          connected_to="$(arg arm_id)_link8"
          safety_distance="0.03"
          gazebo="$(arg gazebo)"
       />
    </xacro:if>

因此,hand:=$(arg load_gripper)arm_id:=$(arg arm_id)将会被传入指定的xacro文件中,用作判断是否需要加载夹爪以及设置arm_id。

载入SRDF

    <!-- The semantic description that corresponds to the URDF -->
    <param name="$(arg robot_description)_semantic" command="xacro '$(find panda_moveit_config)/config/panda.srdf.xacro' hand:=$(arg load_gripper) arm_id:=$(arg arm_id)" />
# 加载SRDF (Semantic Robot Description Format) 文件到ROS参数服务器

SRDF文件通常包含了关于机器人的高级信息,在Moveit的案例中,它由SetupAssistant生成,包含例如组、链等内容。SRDF文件也是由xacro命令从xacro宏转化的。

关节限位和笛卡尔限制

用于覆盖URDF中的相关限位信息

    <!-- Load updated joint limits (override information from URDF) -->
    <group ns="$(arg robot_description)_planning">
      <rosparam command="load" file="$(find panda_moveit_config)/config/joint_limits.yaml" subst_value="true" />
      <rosparam command="load" file="$(find panda_moveit_config)/config/cartesian_limits.yaml" subst_value="true"/>
    </group>
# 加载限位数据到ROS参数服务器的robot_description_planning参数

运动学相关设置

    <!-- Load default settings for kinematics; these settings are overridden by settings in a node's namespace -->
    <group ns="$(arg robot_description)_kinematics">
      <rosparam command="load" file="$(find panda_moveit_config)/config/kinematics.yaml" subst_value="true"/>
    </group>
# 加载运动学相关参数到ROS参数服务器的robot_description_kinematics参数    

切片解析5:planning_pipeline.launch.xml

这个文件在move_group.launch中关于pipeline的部分被调用,它用于调用对应的<pipeline_name>_pipeline.launch.xml,例如ompl_planning_pipeline.launch.xml
move_group.launch,它调用了四个pipeline,包括omplchomppilz_industrial_motion_planner自定义pipeline、可以将它视作各种pipeline调用的统一的接口,以下是这个文件的内容:

<launch>

  <!-- This file makes it easy to include different planning pipelines;
       It is assumed that all planning pipelines are named XXX_planning_pipeline.launch  -->

  <arg name="pipeline" default="ompl" />
  <arg name="arm_id" default="panda" />

  <include ns="$(arg pipeline)" file="$(dirname)/$(arg pipeline)_planning_pipeline.launch.xml" pass_all_args="true"/>

</launch>

例如,当传入的pipeline参数为ompl时,启动对应的ompl_planning_pipeline.launch.xml文件,这使得不同规划库的planning_pipeline.launch.xml易于管理,通过planning_pipeline.launch.xml来专门进行调用。

切片解析6: ompl_planning_pipeline.launch.xml

<launch>

    <!-- The request adapters (plugins) used when planning with OMPL. ORDER MATTERS! -->
    <arg name="planning_adapters"
         default="default_planner_request_adapters/AddTimeParameterization
                  default_planner_request_adapters/ResolveConstraintFrames
                  default_planner_request_adapters/FixWorkspaceBounds
                  default_planner_request_adapters/FixStartStateBounds
                  default_planner_request_adapters/FixStartStateCollision
                  default_planner_request_adapters/FixStartStatePathConstraints"
                  />
  
    <arg name="start_state_max_bounds_error" default="0.1" />
    <arg name="jiggle_fraction" default="0.05" />
    <arg name="arm_id" default="panda" />
  
    <param name="planning_plugin" value="ompl_interface/OMPLPlanner" />
    <param name="request_adapters" value="$(arg planning_adapters)" />
    <param name="start_state_max_bounds_error" value="$(arg start_state_max_bounds_error)" />
    <param name="jiggle_fraction" value="$(arg jiggle_fraction)" />
  
    <!-- Add MoveGroup capabilities specific to this pipeline -->
    <!-- <param name="capabilities" value="" /> -->
  
    <rosparam command="load" file="$(find panda_moveit_config)/config/ompl_planning.yaml" subst_value="true"/>
  
  </launch>

规划适配器插件

    <!-- The request adapters (plugins) used when planning with OMPL. ORDER MATTERS! -->
    <arg name="planning_adapters"
         default="default_planner_request_adapters/AddTimeParameterization
                  default_planner_request_adapters/ResolveConstraintFrames
                  default_planner_request_adapters/FixWorkspaceBounds
                  default_planner_request_adapters/FixStartStateBounds
                  default_planner_request_adapters/FixStartStateCollision
                  default_planner_request_adapters/FixStartStatePathConstraints"
                  />

定义了一个名为planning_adapters的参数,并为其设置了默认值。此默认值是一个列表。

在MoveIt中,规划适配器(planning adapters) 是指一种特定的插件,用于在规划请求发送到规划器之前规划器生成路径后修改规划请求规划响应

在上述代码中,planning_adapters参数包含了六个默认的适配器,它们分别负责处理不同类型的问题。例如,AddTimeParameterization用于给规划的轨迹添加时间参数,这是因为大多数规划器只关心空间,而不关心时间。
其他适配器例如FixWorkspaceBoundsFixStartStateBoundsFixStartStateCollisionFixStartStatePathConstraintsResolveConstraintFrames等,分别用于修正工作空间边界,修正开始状态边界,修正开始状态碰撞,修正开始状态路径约束以及解决约束帧问题。

其他参数

<arg name="start_state_max_bounds_error" default="0.1" />
# 机器人开始状态的最大边界错误
# 默认值被设置为0.1

在运动规划的过程中,机器人的当前状态是其开始状态。
由于传感器的误差和其他的不确定性因素,这个开始状态可能与机器人的实际状态存在一些差距。这个参数就是用来限制这个差距的,如果超过这个值,MoveIt就会尝试修复开始状态,使其满足这个边界误差要求。

<arg name="jiggle_fraction" default="0.05" />
# 开始状态调整时所允许的最大变化幅度
# 默认值被设置为0.05

这个参数在修复开始状态时非常重要。
如果由于某些原因,机器人的开始状态不能满足运动规划的要求(例如,机器人的开始状态在一个碰撞状态),MoveIt会尝试微调(“jiggle”)机器人的关节,使得机器人的开始状态满足规划的要求。
这个参数表示这个微调过程中,每个关节所允许的最大变化幅度,以关节的运动范围的百分比表示。
例如,如果设为0.01,那么在微调过程中,每个关节的角度都只能在其运动范围的1%以内变化。

<arg name="arm_id" default="panda" />
# 机械臂id,用于指定运动规划所涉及的机器臂

载入到ROS参数服务器的参数

<param name="planning_plugin" value="ompl_interface/OMPLPlanner" />
# 设置ROS参数planning_plugin的值为ompl_interface/OMPLPlanner
# 这表示运动规划将使用OMPL库进行
<param name="request_adapters" value="$(arg planning_adapters)" />
<param name="start_state_max_bounds_error" value="$(arg start_state_max_bounds_error)" />
<param name="jiggle_fraction" value="$(arg jiggle_fraction)" />
# 将之前设置的arg参数值作为值填入这几个ROS参数服务器的参数
<rosparam command="load" file="$(find panda_moveit_config)/config/ompl_planning.yaml" subst_value="true"/>
# 加载ompl_planning.yaml文件
# 该文件包含了用于OMPL运动规划库的具体参数配置

切片解析7: trajectory_execution.launch.xml

trajectory_execution.launch.xml配置了运动轨迹执行的一些参数

<launch>
    <!-- This file summarizes all settings required for trajectory execution  -->
  
    <!-- Define moveit controller manager plugin: fake, simple, or ros_control -->
    <arg name="moveit_controller_manager" />
    <arg name="fake_execution_type" default="interpolate" />
  
    <!-- Flag indicating whether MoveIt is allowed to load/unload  or switch controllers -->
    <arg name="moveit_manage_controllers" default="true"/>
    <param name="moveit_manage_controllers" value="$(arg moveit_manage_controllers)"/>
  
    <!-- When determining the expected duration of a trajectory, this multiplicative factor is applied to get the allowed duration of execution -->
    <param name="trajectory_execution/allowed_execution_duration_scaling" value="1.2"/> <!-- default 1.2 -->
    <!-- Allow more than the expected execution time before triggering a trajectory cancel (applied after scaling) -->
    <param name="trajectory_execution/allowed_goal_duration_margin" value="0.5"/> <!-- default 0.5 -->
    <!-- Allowed joint-value tolerance for validation that trajectory's first point matches current robot state -->
    <param name="trajectory_execution/allowed_start_tolerance" value="0.01"/> <!-- default 0.01 -->
  
    <!-- We use pass_all_args=true here to pass fake_execution_type, which is required by fake controllers, but not by real-robot controllers.
         As real-robot controller_manager.launch files shouldn't be required to define this argument, we use the trick of passing all args. -->
    <include file="$(dirname)/$(arg moveit_controller_manager)_moveit_controller_manager.launch.xml" pass_all_args="true" />
  
  </launch>

控制器管理者

    <!-- Define moveit controller manager plugin: fake, simple, or ros_control -->
<arg name="moveit_controller_manager" />
# moveit_controller_manager参数用于指定MoveIt!控制器管理器插件的名称
# 可选的值为:fake, simple, or ros_control

MoveIt提供的控制器管理器包括以下三种类型:

  1. fake: 这种类型的控制器仅模拟运动,不与真实机器人进行通信。它通常用于快速测试和演示,对于仿真,通常使用fake控制器来模拟运动。

  2. simple: 这种类型的控制器与机器人进行通信,但仅提供了基本控制,例如直线/圆弧插值等。它适用于一些较简单的机器人。

  3. ros_control: 这是一种更灵活的控制器类型,可支持各种机器人和控制器硬件。它提供了更高级别的控制接口,例如电机控制器接口和传感器读取接口。
    根据应用场景和机器人的要求,使用不同类型的控制器管理器。
    ros_control是机器人强大的控制器,可参考ros_control WIKI文档和ros_control源代码

虚拟控制器执行方式

<arg name="fake_execution_type" default="interpolate" />
  # fake_execution_type:设置虚拟控制器的执行模式。
  # 如果选择“fake”控制器管理器,则使用虚拟控制器进行模拟运动。
  # 此参数指定用于虚拟运动的执行模式,包括“interpolate”,“last point。默认值为“interpolate”。

interpolate:该选项表示MoveIt假设控制器将在轨迹的每个目标点之间进行插值。这种方式可以模拟连续的轨迹执行过程。

last point:此选项表示MoveIt假设控制器将直接跳到轨迹的最后一个目标点。这种方式可以模拟机器人快速执行任务。
launch/fake_moveit_controller_manager.launch.xml文件中发现了这两种描述,不确定是否有第三种via points来和官方文档中关于fake controller的描述匹配。
但在Moveit官方文档中有关于fake controller的详细描述,可参考Moveit1 Noetic官方文档

MoveIt提供了一系列虚拟轨迹控制器,可用于模拟。其中,虚拟控制器的配置文件位于 config/fake_controllers.yaml

可以根据需要调整以下控制器类型:

  • interpolate: 在经过关键点时执行平稳插补,默认用于可视化。
  • via points: 遍历关键点,但不插补它们之间的点,用于可视化调试。
  • last point: 直接跳转到轨迹的最后一个点,用于离线基准测试。

虚拟控制器类型信息可在 fake_controllers.yaml 文件中配置。对于每个控制器,都需要指定名称、类型和涉及的关节。其中,频率为 rate: 10,可用于插补控制器。但在对夹爪进行控制时,关节为空列表 []

示例:

rate: 10
controller_list:
  - name: fake_arm_controller
    type: interpolate
    joints:
      - joint_1
      - joint_2
      - joint_3
      - joint_4
      - joint_5
      - joint_6
  - name: fake_gripper_controller
    joints:
      []

控制器们的管理权限

    <!-- Flag indicating whether MoveIt is allowed to load/unload  or switch controllers -->
    <arg name="moveit_manage_controllers" default="true"/>
    <param name="moveit_manage_controllers" value="$(arg moveit_manage_controllers)"/>

move_gruop.launchmoveit_manage_controllers参数被设置为true,表示由MoveIt来管理控制器。
该参数随后传递到trajectory_execution.launch.xml,定义了一个参数并将其设置为一个ROS参数,参数名为moveit_manage_controllers,默认值为”true”。
当该参数为”true”时,MoveIt将有权限来加载/卸载或者切换控制器
不同的任务或不同阶段的任务可能需要使用不同的控制器。例如,一种控制器可能用于精确位置控制,而另一种可能用于力控制。通过动态切换控制器,MoveIt!可以更好地适应不同的任务需求。
因此,当运行在真实机器人或者使用了ros_control的仿真器上时,通常需要这个选项。

轨迹执行的限制参数

<!-- When determining the expected duration of a trajectory, this multiplicative factor is applied to get the allowed duration of execution -->
<param name="trajectory_execution/allowed_execution_duration_scaling" value="1.2"/> <!-- default 1.2 -->

allowed_execution_duration_scaling参数是允许的运动轨迹执行时间的缩放因子,默认值是1.2。这个参数用于在计算运动轨迹的期望时间时,会乘上这个缩放因子,得出允许的执行时间。

<!-- Allow more than the expected execution time before triggering a trajectory cancel (applied after scaling) -->
<param name="trajectory_execution/allowed_goal_duration_margin" value="0.5"/> <!-- default 0.5 -->

allowed_goal_duration_margin参数是允许的运动轨迹执行时间的容忍范围,默认值是0.5秒。如果轨迹执行时间超出了期望时间加上这个容忍范围,那么就会触发取消轨迹的操作。

<!-- Allowed joint-value tolerance for validation that trajectory's first point matches current robot state -->
<param name="trajectory_execution/allowed_start_tolerance" value="0.01"/> <!-- default 0.01 -->

allowed_start_tolerance参数是允许的运动轨迹起始点的关节值容忍范围,默认值是0.1。MoveIt!会检查轨迹的起始点是否与当前机器人的状态相符,如果差异超过这个容忍范围,那么就会认为轨迹不合法。

控制器管理器启动文件的调用

    <!-- We use pass_all_args=true here to pass fake_execution_type, which is required by fake controllers, but not by real-robot controllers.
         As real-robot controller_manager.launch files shouldn't be required to define this argument, we use the trick of passing all args. -->
    <include file="$(dirname)/$(arg moveit_controller_manager)_moveit_controller_manager.launch.xml" pass_all_args="true" />

moveit_controller_managerdemo.launch中指定为fake,经由pass_all_args="true"传递给move_group.launch,覆盖掉了move_group.launch中默认的moveit_controller_manager参数值simple,随后由move_group.launch通过pass_all_args="true"传递给trajectory_execution.launch.xml,在trajectory_execution.launch.xml中用来选择该参数指定的的控制器类型。

比如moveit_controller_manager参数为fake,就会调用fake_moveit_controller_manager.launch.xml文件。

切片解析8: fake_moveit_controller_manager.launch.xml

fake_moveit_controller_manager.launch.xmltrajectory_execution.launch.xml中被调用,原因是moveit_controller_manager参数为fake,所以fake_moveit_controller_manager.launch.xml在三个控制器管理者(fake, simple, ros_control)中被选取了。

它用于启动一个仿真控制器。

<launch>

    <!-- execute the trajectory in 'interpolate' mode or jump to goal position in 'last point' mode -->
    <arg name="fake_execution_type" default="interpolate" />
  
    <!-- Set the param that trajectory_execution_manager needs to find the controller plugin -->
    <param name="moveit_controller_manager" value="moveit_fake_controller_manager/MoveItFakeControllerManager"/>
  
    <!-- The rest of the params are specific to this plugin -->
    <rosparam subst_value="true" file="$(find panda_moveit_config)/config/fake_controllers.yaml"/>
  
  </launch>

subst_value="true"的作用是对 launch 文件中的路径进行替换。当 subst_value 设置为 true 时,launch 文件会在加载参数文件之前对其路径中的 $(find panda_moveit_config) 进行替换,将其替换为实际的 ROS 包路径。
默认情况下,如果没有提供 command 属性,rosparam 元素将执行 command="load" 的操作

虚拟控制器执行方式

    <!-- execute the trajectory in 'interpolate' mode or jump to goal position in 'last point' mode -->
    <arg name="fake_execution_type" default="interpolate" />
# fake_execution_type参数的值决定了执行轨迹的方式
# "interpolate"表示在模拟环境中,机器人会执行完整的轨迹
# 如果值设置为"last point",那么机器人将直接跳到目标位置。

ROS参数服务器的控制器管理者参数

    <!-- Set the param that trajectory_execution_manager needs to find the controller plugin -->
    <param name="moveit_controller_manager" value="moveit_fake_controller_manager/MoveItFakeControllerManager"/>
# 设置ROS参数moveit_controller_manager
# 值为moveit_fake_controller_manager/MoveItFakeControllerManager
# 这个参数是用于指定控制器管理器的插件名称,这里使用的是MoveIt提供的虚拟控制器

加载fake_controllers.yaml到参数服务器

    <!-- The rest of the params are specific to this plugin -->
    <rosparam subst_value="true" file="$(find panda_moveit_config)/config/fake_controllers.yaml"/>
# 加载了/config/fake_controllers.yaml配置文件
# 这个YAML文件包含了模拟控制器的配置信息

subst_value="true"的作用是对 launch 文件中的路径进行替换。当 subst_value 设置为 true 时,launch 文件会在加载参数文件之前对其路径中的 $(find panda_moveit_config) 进行替换,将其替换为实际的 ROS 包路径。
默认情况下,如果没有提供 command 属性,rosparam 元素将执行 command="load" 的操作

config/fake_controllers.yaml

controller_list:
  - name: fake_$(arg arm_id)_arm_controller
    type: $(arg fake_execution_type)
    joints:
      - $(arg arm_id)_joint1
      - $(arg arm_id)_joint2
      - $(arg arm_id)_joint3
      - $(arg arm_id)_joint4
      - $(arg arm_id)_joint5
      - $(arg arm_id)_joint6
      - $(arg arm_id)_joint7

  - name: fake_$(arg arm_id)_hand_controller
    type: $(arg fake_execution_type)
    joints:
      - $(arg arm_id)_finger_joint1

initial:  # Define initial robot poses per group
  - group: $(arg arm_id)_arm
    pose: ready
  - group: $(arg arm_id)_hand
    pose: open

fake_controllers.yaml文件定义了一些虚拟控制器和初始机器人姿态,用于ROS MoveIt中的运动规划和控制。

  1. controller_list:这是一个控制器列表,其中定义了两个虚拟控制器,分别是fake_$(arg arm_id)_arm_controllerfake_$(arg arm_id)_hand_controller。这些控制器用于模拟机器人的运动控制。

    • name:控制器的名称,其中包含了$(arg arm_id)的参数替换,即根据实际参数值动态生成不同的控制器名称。
    • type:控制器的类型,其中包含了$(arg fake_execution_type)的参数替换,即根据实际参数值动态设置不同的控制器类型。
    • joints:控制器控制的关节列表,其中包含了$(arg arm_id)的参数替换,即根据实际参数值动态生成不同的关节名称。
  2. initial:这是一个初始机器人姿态的列表,定义了机器人的起始状态。在这个例子中,定义了两个初始姿态,分别是$(arg arm_id)_arm$(arg arm_id)_hand

    • group:姿态所属的机器人组,其中包含了$(arg arm_id)的参数替换,即根据实际参数值动态生成不同的机器人组名称。
    • pose:姿态的名称,表示机器人的状态。在这个例子中,分别为readyopen

这个文件的具体内容是根据实际参数值动态生成的,参数的值取决于运行时的配置。通过使用这些虚拟控制器和初始姿态,可以在ROS MoveIt中模拟和控制具有不同关节和组的机器人。

切片解析9: sensor_manager.launch.xml

这个启动文件负责初始化传感器管理器,包括加载传感器类型,设定Octomap参数,设定传感器的最大探测距离,并包含特定机器人(Panda)的传感器管理器的启动文件

<launch>

    <!-- This file makes it easy to include the settings for sensor managers -->
  
    <!-- Params for 3D sensors config: '' | pointcloud | depthmap -->
    <arg name="sensor_type" default="" />
    <rosparam if="$(eval arg('sensor_type')  != '')" command="load" file="$(find panda_moveit_config)/config/sensors_kinect_$(arg sensor_type).yaml" />
  
    <!-- Params for the octomap monitor -->
    <!--  <param name="octomap_frame" type="string" value="some frame in which the robot moves" /> -->
    <param name="octomap_frame" type="string" value="camera_rgb_optical_frame" />
    <param name="octomap_resolution" type="double" value="0.025" />
    <param name="max_range" type="double" value="5.0" />
  
    <!-- Load the robot specific sensor manager; this sets the moveit_sensor_manager ROS parameter -->
    <arg name="moveit_sensor_manager" default="panda" />
    <include file="$(dirname)/$(arg moveit_sensor_manager)_moveit_sensor_manager.launch.xml" />
  
  </launch>

加载传感器到ROS参数服务器

    <!-- Params for 3D sensors config: '' | pointcloud | depthmap -->
    <arg name="sensor_type" default="" />
    <rosparam if="$(eval arg('sensor_type')  != '')" command="load" file="$(find panda_moveit_config)/config/sensors_kinect_$(arg sensor_type).yaml" />
# 通过设置"sensor_type"的参数来设定使用的传感器类型
# 支持的传感器类型为depthmap、空和pointcloud
# 其默认值为空
# 如果默认值不为空将载入对应的sensors_kinect_$(arg sensor_type).yaml到ROS参数服务器

config/sensors_kinect_depthmap.yaml

以调用sensors_kinect_depthmap.yaml为例

sensors:
  - sensor_plugin: occupancy_map_monitor/DepthImageOctomapUpdater
    image_topic: /camera/depth_registered/image_raw
    queue_size: 5
    near_clipping_plane_distance: 0.3
    far_clipping_plane_distance: 5.0
    shadow_threshold: 0.2
    padding_scale: 4.0
    padding_offset: 0.03
    max_update_rate: 1.0
    filtered_cloud_topic: filtered_cloud
    ns: kinect

YAML 是一种可读性高、适用于配置文件、交换数据、定义语言或序列化对象等场景的数据序列化格式。它的语法设计得易于阅读和编写。
在YAML中,缩进必须使用空格,不能使用制表符。同一层级的元素必须有相同的缩进。

  • - 符号:表示一个列表项的开始。在这个文件中,- sensor_plugin: occupancy_map_monitor/DepthImageOctomapUpdater 表示 “sensors” 这个键对应的值是一个列表,该列表的一个元素开始于此。在 - 之后的内容表示这个列表元素的内容。

这个YAML文件是用于配置Panda机械臂在ROS MoveIt中使用的深度图像传感器Kinect。

  1. sensor_plugin: occupancy_map_monitor/DepthImageOctomapUpdater

    这一行指定了处理传感器数据的插件。在这里使用occupancy_map_monitor/DepthImageOctomapUpdater插件来更新Octomap。Octomap是一种3D网格地图,由占用的、空闲的和未知的单元格构成,用于机器人的环境感知和导航。

  2. image_topic: /camera/depth_registered/image_raw

    这一行定义了深度图像的话题名。话题是ROS中实现消息传递的方式,订阅/camera/depth_registered/image_raw话题以接收深度图像。

  3. queue_size: 5

    这一行设定了消息队列的大小。在这里,如果有5条消息正在等待处理,那么来自/camera/depth_registered/image_raw的新消息将被丢弃。

  4. near_clipping_plane_distance: 0.3

    这一行设定了近剪裁面距离,这是深度图像有效区域的最近边界。小于这个距离的数据会被忽略。

  5. far_clipping_plane_distance: 5.0

    这一行设定了远剪裁面距离,这是深度图像有效区域的最远边界。大于这个距离的数据会被忽略。

  6. shadow_threshold: 0.2

    这一行设定了阴影阈值。这个值用来判断一个像素是否在另一个像素的阴影中。阈值越小,检测到的阴影越多。

  7. padding_scale: 4.0 and padding_offset: 0.03

    这两行设定了对深度图像的填充。填充是一种处理方法,用于增加物体周围的空间,以避免机器人与物体的碰撞。

  8. max_update_rate: 1.0

    这一行设定了最大更新率。在这里,深度图像的处理速度被限制为每秒最多一次。

  9. filtered_cloud_topic: filtered_cloud

    这一行定义了过滤后的点云数据的话题名。经过处理的深度图像会被转换为点云,并发布到这个话题。

  10. ns: kinect

    这一行设定了命名空间(Namespace),在这里是kinect。命名空间用于ROS话题、服务等的组织,使得它们能够在复杂系统中更容易地被管理和定位。

总的来说,这个YAML文件定义了深度图像传感器的一些关键配置,使得MoveIt可以正确地处理和使用深度图像数据。

config/sensors_kinect_pointcloud.yaml
sensors:
  - sensor_plugin: occupancy_map_monitor/PointCloudOctomapUpdater
    point_cloud_topic: /camera/depth_registered/points
    max_range: 5.0
    point_subsample: 1
    padding_offset: 0.1
    padding_scale: 1.0
    max_update_rate: 1.0
    filtered_cloud_topic: filtered_cloud
    ns: kinect

这个YAML文件是用于配置ROS MoveIt的点云传感器,特别是对Kinect设备的配置。下面是这些参数的详细解释:

  1. sensor_plugin: occupancy_map_monitor/PointCloudOctomapUpdater

    这一行指定了处理传感器数据的插件。在这里使用occupancy_map_monitor/PointCloudOctomapUpdater插件来根据点云数据更新Octomap。Octomap是一种3D网格地图,用于机器人的环境感知和导航。

  2. point_cloud_topic: /camera/depth_registered/points

    这一行定义了点云数据的话题名。话题是ROS中实现消息传递的方式,这里订阅/camera/depth_registered/points话题以接收点云数据。

  3. max_range: 5.0

    这一行设定了传感器的最大探测距离,值为5.0,单位也通常是米。超过这个距离的物体不会被传感器检测到。

  4. point_subsample: 1

    这一行设定了点云的采样率。此处设置为1,表示每个点都会被采样。如果设置为比1大的值,例如10,那么每10个点只有一个点会被采样。

  5. padding_offset: 0.1 and padding_scale: 1.0

    这两行设定了对点云的填充。填充是一种处理方法,用于增加物体周围的空间,以避免机器人与物体的碰撞。

  6. max_update_rate: 1.0

    这一行设定了最大更新率。在这里,点云的处理速度被限制为每秒最多一次。

  7. filtered_cloud_topic: filtered_cloud

    这一行定义了过滤后的点云数据的话题名。经过处理的点云数据会被发布到这个话题。

点云和深度图的区别

深度图像和点云都是描述三维空间中的物体的数据结构,深度相机可以生成深度图像和点云两种数据,但深度图像和点云的处理方法和用途有所不同,选择哪种数据结构取决于你的具体需求。

深度图像是一个二维数组,每个元素的值代表该像素点到相机的距离。深度图像是由深度相机,如Kinect或Intel RealSense等设备,通过测量每个像素点的深度信息生成的。它为每个像素提供一个单一的深度值,这些值共同构成一个深度图。深度图的优点是数据结构简单,易于处理和存储,但是对于某些复杂的3D空间表达可能不够精确。


图源于microsoft kinect

点云则是一个在三维空间中分布的点的集合,每个点包含其空间坐标(X,Y,Z)。点云通常通过激光雷达(LiDAR)或者深度相机生成。与深度图像相比,点云更直接地表示了三维空间的结构,能够更好地处理复杂的三维几何问题,但是数据量大,处理复杂度高。

图源自researchgate

根据机器人系统的硬件配置和任务需求,可能会选择使用深度图像或者点云。如果系统中有深度相机,并且任务要求处理速度快,数据量小,那么可能更适合使用深度图像。应该使用config/sensors_kinect_depthmap.yaml配置文件。

如果系统中有激光雷达或者需要精确的三维空间表示,那么点云可能是更好的选择。应该使用config/sensors_kinect_pointcloud.yaml配置文件。

    <!-- Params for the octomap monitor -->
    <!--  <param name="octomap_frame" type="string" value="some frame in which the robot moves" /> -->
    <param name="octomap_frame" type="string" value="camera_rgb_optical_frame" />
# 定义了Octomap的参考坐标系。Octomap是一种用于机器人3D感知的数据结构
# 这里将它的参考坐标系设为了"camera_rgb_optical_frame"
# 这个参考坐标系通常是由RGB相机提供的

每一个传感器读取或机器人运动的数据都必须关联到一个特定的参考坐标系。

这些Frame连接在一起形成了一个Frames tree,它是机器人在现实世界中感知自我位置和外部环境的基础。

在这里,octomap_frame就是Octomap所使用的参考坐标系。
这个参数的值camera_rgb_optical_frame可能是Kinect摄像头传感器的坐标系,它定义了摄像头的位置和方向。

Octomap是一种用于3D环境建模的数据结构,是一种八叉树Octree的应用。Octomap可以通过传感器数据(如深度相机、激光雷达等)来创建和更新3D环境的模型。
在Octomap中,环境被划分为立方体的单元格,每个单元格可以存储关于该空间的信息,如是否被占用(即有物体存在)。
Octomap是一种稀疏的数据结构,只有在有物体存在或者被传感器探测到的区域才会创建单元格,这意味着它只在有物体存在的地方存储数据,使得内存使用更加有效率、高效地处理大规模的环境。
八叉树Octree常常与其他的空间划分结构如kd树、二叉空间划分树(BSP tree)、四叉树(Quadtree,为二维的版本)等进行比较。下面是八叉树相比于其他空间数据结构的一些优缺点:
优点:

  1. 空间效率:八叉树有助于减少内存的使用。它通过在需要详细描述的空间区域(例如,物体所在的地方)创建更细的划分,并在空旷或均匀的区域使用较粗的划分,从而实现了空间效率。

  2. 查询效率:在处理空间查询时(如范围搜索、最近邻搜索等),八叉树可以提供较高的效率。这是因为它能快速地排除掉不可能包含查询结果的大块区域。

  3. 分层和多分辨率表示:八叉树的层次化特性使得它能够支持分层和多分辨率的空间表示,这在许多应用中是非常有用的,例如LOD(Level of Detail)渲染、碰撞检测、路径规划等。

缺点:

  1. 构建和更新开销:构建和更新八叉树可能会花费一定的计算开销,尤其是在动态环境中。因为每当物体移动或场景发生变化时,八叉树可能需要进行重建或更新。

  2. 不适合处理特定模式的数据:对于某些特定模式的数据,例如高度平面化的数据或线性分布的数据,八叉树可能不如其他结构如kd树或BSP树那么高效。

  3. 不均衡的分区:由于八叉树的划分方式是均匀的,因此在处理一些空间分布极不均匀的数据时,可能会导致树的结构非常不平衡,这可能影响查询效率。

    <param name="octomap_resolution" type="double" value="0.025" />
# 设定了Octomap的分辨率,值为0.025,一般单位是米。
# 这个值决定了Octomap中每个voxel体素的大小

Voxel(Volume Pixel)体素是一种在三维空间中表示数据的单位,类似于二维图像中的像素(Pixel)。一个Voxel代表了三维空间中的一个小立方体区域。在Octomap中,每个Voxel就是一个单元格,可以存储关于这个小区域的信息,例如这个区域是否被占用。Voxel的大小(也就是立方体的边长)决定了3D模型的分辨率:Voxel越小,能够表示的细节就越丰富,但同时也需要更多的计算资源和存储空间。

<param name="max_range" type="double" value="5.0" />
# 设定了传感器的最大探测距离,值为5.0,单位也通常是米
# 超过这个距离的物体将被屏蔽

启动robotname_moveit_sensor_manager.launch.xml

特定机器人的传感器相关启动文件将被调用,这个特定机器人由参数<arg name="moveit_sensor_manager" default="panda" />来确定。

    <!-- Load the robot specific sensor manager; this sets the moveit_sensor_manager ROS parameter -->
    <arg name="moveit_sensor_manager" default="panda" />
    <include file="$(dirname)/$(arg moveit_sensor_manager)_moveit_sensor_manager.launch.xml" />
panda_moveit_sensor_manager.launch.xml

并无内容,这是在sensor_manager.launch.xml中被调用的特定机器人的panda_moveit_sensor_manager.launch.xml

<launch>
</launch>

切片解析10:moveit_rviz.launch

该特定的launch文件是用于启动RViz。

<launch>

  <arg name="debug" default="false" />
  <arg unless="$(arg debug)" name="launch_prefix" value="" />
  <arg     if="$(arg debug)" name="launch_prefix" value="gdb --ex run --args" />

  <!--Retrieve the right rviz config file-->
  <arg name="rviz_tutorial" default="false" />
  <arg name="rviz_config" default="$(dirname)/moveit.rviz" />

  <arg if="$(eval rviz_config=='')" name="command_args" value="" />
  <arg if="$(eval rviz_config!='' and not rviz_tutorial)" name="command_args" value="-d $(arg rviz_config)" />
  <arg if="$(eval rviz_tutorial)" name="command_args" value="-d $(dirname)/moveit_empty.rviz" />

  <node name="$(anon rviz)" launch-prefix="$(arg launch_prefix)" pkg="rviz" type="rviz" respawn="false"
        args="$(arg command_args)" output="screen">
  </node>

</launch>

debug设置

  <arg name="debug" default="false" />
  <arg unless="$(arg debug)" name="launch_prefix" value="" />
  <arg     if="$(arg debug)" name="launch_prefix" value="gdb --ex run --args" />
# 定义了一个参数debug,默认值为false
# 该值从demo.launch中通过pass_all_args="true"继承给moveit_rviz.launch
# 如果不debug就正常启动,launch_prefix=""
# 如果要debug就将launch_prefix设置为gdb --ex run --args

如果debugtruelaunch_prefix的值将为gdb --ex run --args,这会使得launch文件在GDB(GNU调试器)环境下运行,便于调试。否则,launch_prefix为空。

RViz配置

  <!--Retrieve the right rviz config file-->
  <arg name="rviz_tutorial" default="false" />
  <arg name="rviz_config" default="$(dirname)/moveit.rviz" />

rviz_tutorial参数默认值为false,用于开启RViz示教模式(载入空的RViz配置文件)
该参数在demo.launch中通过pass_all_args="true"继承给moveit_rviz.launch

rviz_config默认值为当前目录下的moveit.rviz文件,以.rviz结尾的文件为RViz的配置文件,被用于设定RViz的显示参数,也可以在。

Panels:
  - Class: rviz/Displays
    Help Height: 84
    Name: Displays
    Property Tree Widget:
      Expanded:
        - /MotionPlanning1
      Splitter Ratio: 0.5
    Tree Height: 226
  - Class: rviz/Help
    Name: Help
  - Class: rviz/Views
    Expanded:
      - /Current View1
    Name: Views
    Splitter Ratio: 0.5
Visualization Manager:
  Class: ""
  Displays:
    - Alpha: 0.5
      Cell Size: 1
      Class: rviz/Grid
      Color: 160; 160; 164
      Enabled: true
      Line Style:
        Line Width: 0.03
        Value: Lines
      Name: Grid
      Normal Cell Count: 0
      Offset:
        X: 0
        Y: 0
        Z: 0
      Plane: XY
      Plane Cell Count: 10
      Reference Frame: <Fixed Frame>
      Value: true
    - Class: moveit_rviz_plugin/MotionPlanning
      Enabled: true
      Name: MotionPlanning
      Planned Path:
        Links: ~
        Loop Animation: true
        Robot Alpha: 0.5
        Show Robot Collision: false
        Show Robot Visual: true
        Show Trail: false
        State Display Time: 0.05 s
        Trajectory Topic: move_group/display_planned_path
      Planning Metrics:
        Payload: 1
        Show Joint Torques: false
        Show Manipulability: false
        Show Manipulability Index: false
        Show Weight Limit: false
      Planning Request:
        Colliding Link Color: 255; 0; 0
        Goal State Alpha: 1
        Goal State Color: 250; 128; 0
        Interactive Marker Size: 0
        Joint Violation Color: 255; 0; 255
        Query Goal State: true
        Query Start State: false
        Show Workspace: false
        Start State Alpha: 1
        Start State Color: 0; 255; 0
      Planning Scene Topic: move_group/monitored_planning_scene
      Robot Description: robot_description
      Scene Geometry:
        Scene Alpha: 1
        Show Scene Geometry: true
        Voxel Coloring: Z-Axis
        Voxel Rendering: Occupied Voxels
      Scene Robot:
        Attached Body Color: 150; 50; 150
        Links: ~
        Robot Alpha: 0.5
        Show Scene Robot: true
      Value: true
  Enabled: true
  Global Options:
    Background Color: 48; 48; 48
    Fixed Frame: panda_link0
  Name: root
  Tools:
    - Class: rviz/Interact
      Hide Inactive Objects: true
    - Class: rviz/MoveCamera
    - Class: rviz/Select
  Value: true
  Views:
    Current:
      Class: rviz/Orbit
      Distance: 2.0
      Enable Stereo Rendering:
        Stereo Eye Separation: 0.06
        Stereo Focal Distance: 1
        Swap Stereo Eyes: false
        Value: false
      Field of View: 0.75
      Focal Point:
        X: -0.1
        Y: 0.25
        Z: 0.30
      Focal Shape Fixed Size: true
      Focal Shape Size: 0.05
      Invert Z Axis: false
      Name: Current View
      Near Clip Distance: 0.01
      Pitch: 0.5
      Target Frame: panda_link0
      Yaw: -0.6232355833053589
    Saved: ~
Window Geometry:
  Displays:
    collapsed: false
  Height: 848
  Help:
    collapsed: false
  Hide Left Dock: false
  Hide Right Dock: false
  MotionPlanning:
    collapsed: false
  MotionPlanning - Trajectory Slider:
    collapsed: false
  QMainWindow State: 000000ff00000000fd0000000100000000000001f0000002f6fc0200000007fb000000100044006900730070006c006100790073010000003d00000173000000c900fffffffb0000000800480065006c00700000000342000000bb0000006e00fffffffb0000000a00560069006500770073000000010c000000a4000000a400fffffffb0000000c00430061006d00650072006100000002ff000001610000000000000000fb0000001e004d006f00740069006f006e00200050006c0061006e006e0069006e00670100000374000001890000000000000000fb00000044004d006f00740069006f006e0050006c0061006e006e0069006e00670020002d0020005400720061006a006500630074006f0072007900200053006c00690064006500720000000000ffffffff0000001600000016fb0000001c004d006f00740069006f006e0050006c0061006e006e0069006e006701000001b60000017d0000017d00ffffff00000315000002f600000001000000020000000100000002fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
  Views:
    collapsed: false
  Width: 1291
  X: 454
  Y: 25

moveit.rviz文件中包含了一系列的面板(panels),显示器(displays)和视图(views)。面板是RViz的界面元素,显示器则是用于在3D环境中展示数据的元素,视图则是控制3D环境的观察点的参数。

RViz配置文件的选择

 <arg if="$(eval rviz_config=='')" name="command_args" value="" />
  <arg if="$(eval rviz_config!='' and not rviz_tutorial)" name="command_args" value="-d $(arg rviz_config)" />
  <arg if="$(eval rviz_tutorial)" name="command_args" value="-d $(dirname)/moveit_empty.rviz" />

参数command_args。它的值取决于rviz_config的值以及rviz_tutorial参数的值。如果rviz_config为空,即配置文件不存在,则command_args为空。
如果rviz_config不为空且rviz_tutorialfalse,即配置文件存在,但并不开启示教模式,则command_args的值为-d $(arg rviz_config),这会让rviz加载指定的rviz配置文件。
如果rviz_tutorialtrue,则command_args的值为-d $(dirname)/moveit_empty.rviz,加载一个空的rviz配置文件。

启动RViz

  <node name="$(anon rviz)" launch-prefix="$(arg launch_prefix)" pkg="rviz" type="rviz" respawn="false"
        args="$(arg command_args)" output="screen">

节点名称由$(anon rviz)生成,它会生成一个唯一的、匿名的节点名。launch-prefix就是之前定义的launch_prefix参数,决定了是否已GDB调试来启动这个节点。

anon是ROS的特殊命令,用于确保每次启动的节点有一个独一无二的名字,这样就可以在同一ROS系统中同时启动多个这样的节点,而不会因为节点名字的冲突导致错误。

关于$(anon rviz)中的rviz,这个部分只是一个前缀,ROS会在字符rviz后面附加一个独一无二的字符串来生成节点名。选择rviz作为前缀是为了使生成的名字有更好的可读性,能清楚地知道这个节点与rviz有关。

比如,使用$(anon rviz)可能会生成如下的节点名:rviz_25742_1546445566103。在这个名字中,rviz是指定的前缀,后面的数字是ROS自动生成的,用来确保名字的唯一性。

pkgtype分别表示ROS包名和类型名,这里都是rviz。
respawn参数设为false,意味着如果rviz节点停止,它不会自动重启。
args是之前定义的command_args参数,它指定了rviz启动时的命令行参数为空或者moveit.rvizmoveit_empty.rviz
output参数设为screen,表示rviz的输出将被发送到控制台。

切片解析11:demo_gazebo.launch


文件名为robot_moveit_config/launch/demo_gazebo.launch,是Moveit的经典demo,在RViz中显示机器人模型并通过RViz的MotionPlanning插件来控制Moveit完成运动规划和轨迹控制,同时在Gazebo中进行联合仿真,模仿真实机械臂的控制。

以下为Moveit官方案例的panda_moveit_config/launch/demo_gazebo.launch完整代码:

<launch>
  <!-- specify the planning pipeline -->
  <arg name="pipeline" default="ompl" />

  <!-- Panda specific options -->
  <arg name="load_gripper" default="true" />
  <arg name="transmission" default="effort" />

  <!-- Gazebo specific options -->
  <arg name="gazebo_gui" default="true" />
  <arg name="paused" default="false" />

  <!-- Launch the gazebo simulator and spawn the robot -->
  <include file="$(find franka_gazebo)/launch/panda.launch" pass_all_args="true">
    <arg name="headless" value="$(eval not arg('gazebo_gui'))" />
    <arg name="use_gripper" default="$(arg load_gripper)" />
    <arg name="controller" default="$(arg transmission)_joint_trajectory_controller" />
  </include>

  <include file="$(dirname)/demo.launch" pass_all_args="true">
    <!-- robot description is loaded by gazebo.launch, to enable Gazebo features -->
    <arg name="load_robot_description" value="false" />
    <!-- MoveItSimpleControllerManager provides ros_control's JointTrajectory controllers
         as well as GripperCommand actions -->
    <arg name="moveit_controller_manager" value="simple" />
  </include>
</launch>

切片分析如下:

运动规划流水线

  <!-- specify the planning pipeline -->
  <arg name="pipeline" default="ompl" />
# 设定运动规划流水线为ompl运动规划库

机械臂相关基本参数设置

  <!-- Panda specific options -->
  <arg name="load_gripper" default="true" />
# 加载夹爪,该参数被传递给franka_gazebo/launch/panda.launch
  <arg name="transmission" default="effort" />
# 将传动方式设置为effort力控

Gazebo设置

  <!-- Gazebo specific options -->
  <arg name="gazebo_gui" default="true" />
# 设置gazebo_gui参数为true
# gazebo默认将显示图形化界面
  <arg name="paused" default="false" />
# 在启动时,默认不暂停仿真模拟器的时间在0s
# 这个参数其实可能在后续会被覆盖掉
# 不确定在传入文件时是否只给第一次赋值还是会将传入文件的所有该参数均赋值
# 如果只给第一次赋值,那么这个参数是无效的
# 如果给所有都赋值,那么这个参数是有效的

启动Gazebo

  <!-- Launch the gazebo simulator and spawn the robot -->
  <include file="$(find franka_gazebo)/launch/panda.launch" pass_all_args="true">
    <arg name="headless" value="$(eval not arg('gazebo_gui'))" />
    <arg name="use_gripper" default="$(arg load_gripper)" />
    <arg name="controller" default="$(arg transmission)_joint_trajectory_controller" />
  </include>

导入了franka_gazebo/launch/panda.launch文件,该文件用于在 Gazebo 模拟器中加载 Panda 机器人,并为其配置一系列参数和控制器。
franka_gazebo/launch/panda.launch文件传递以上已经设置的所有参数。
根据gazebo_gui的值设置参数headless
根据load_gripper的值设置参数use_gripper
根据传动方式transmission设置参数controller,以effort为例,这里的controller被设定为effort_joint_trajectory_controller

franka_gazebo/launch/panda.launch

该文件是franka_gazebo包里的内容,要成功运行demo_gazebo.launch需要先下载安装这个包

sudo apt install ros-noetic-franka-gazebo

该文件安装后的路径为:/opt/ros/noetic/share/franka_gazebo/launch/panda.launch

这个文件的主要作用是在 Gazebo 模拟器中加载和配置 Panda 机器人,启动控制器,以及在需要时启动 RViz 和交互标记,顺便展示这个文件的详细内容,其中已经有官方详尽的注释了,写得很漂亮,建议参考:

<?xml version="1.0"?>
<launch>

  <!-- Gazebo & GUI Configuration -->
  <arg name="gazebo"      default="true"  doc="Should the gazebo simulation be launched? Use false in case if you want to include this file and launch gazebo yourself" />
  <arg name="headless"    default="false" doc="Should the gazebo GUI be launched?" />
  <arg name="paused"      default="false" doc="Should the simulation directly be stopped at 0s?" />
  <arg name="world"       default="worlds/empty.world" doc="Filename to a SDF World for gazebo to use" />
  <arg name="rviz"        default="false" doc="Should RVIz be launched?" />

  <!-- Robot Customization -->
  <arg name="arm_id"      default="panda" doc="Name of the panda robot to spawn" />
  <arg name="use_gripper" default="true"  doc="Should a franka hand be mounted on the flange?" />
  <arg name="controller"  default=" "     doc="Which example controller should be started? (One of {cartesian_impedance,model,force,joint_position,joint_velocity}_example_controller)" />
  <arg name="x"           default="0"     doc="How far forward to place the base of the robot in [m]?" />
  <arg name="y"           default="0"     doc="How far leftwards to place the base of the robot in [m]?" />
  <arg name="z"           default="0"     doc="How far upwards to place the base of the robot in [m]?" />
  <arg name="roll"        default="0"     doc="How much to rotate the base of the robot around its X-axis in [rad]?" />
  <arg name="pitch"       default="0"     doc="How much to rotate the base of the robot around its Y-axis in [rad]?" />
  <arg name="yaw"         default="0"     doc="How much to rotate the base of the robot around its Z-axis in [rad]?" />
  <arg name="xacro_args"  default=""      doc="Additional arguments to pass to panda.urdf.xacro" />
  <arg name="initial_joint_positions"
       doc="Initial joint configuration of the panda. Specify as a list of name/value pairs in form of '-J [name-of-joint] [value-in-rad]'. Default is a 90 degree bend in the elbow"
       default="-J $(arg arm_id)_joint1 0
                -J $(arg arm_id)_joint2 -0.785398163
                -J $(arg arm_id)_joint3 0
                -J $(arg arm_id)_joint4 -2.35619449
                -J $(arg arm_id)_joint5 0
                -J $(arg arm_id)_joint6 1.57079632679
                -J $(arg arm_id)_joint7 0.785398163397
                -J $(arg arm_id)_finger_joint1 0.001
                -J $(arg arm_id)_finger_joint2 0.001"
       />
  <arg name="interactive_marker" default="$(eval arg('controller') == 'cartesian_impedance_example_controller')" doc="Should the interactive marker node be started?" />

  <include file="$(find gazebo_ros)/launch/empty_world.launch" if="$(arg gazebo)">
    <arg name="world_name" value="$(arg world)"/>
    <!-- Always start in paused mode, and only unpause when spawning the model -->
    <arg name="paused" value="true"/>
    <arg name="gui" value="$(eval not arg('headless'))"/>
    <arg name="use_sim_time" value="true"/>
  </include>

  <param name="robot_description"
         command="xacro $(find franka_description)/robots/panda/panda.urdf.xacro
                  gazebo:=true
                  hand:=$(arg use_gripper)
                  arm_id:=$(arg arm_id)
                  xyz:='$(arg x) $(arg y) $(arg z)'
                  rpy:='$(arg roll) $(arg pitch) $(arg yaw)'
                  $(arg xacro_args)">
  </param>

  <rosparam file="$(find franka_gazebo)/config/franka_hw_sim.yaml" subst_value="true" />
  <rosparam file="$(find franka_gazebo)/config/sim_controllers.yaml" subst_value="true" />

  <param name="m_ee" value="0.76" if="$(arg use_gripper)" />

  <arg name="unpause" value="$(eval '' if arg('paused') else '-unpause')" />
  <node name="$(arg arm_id)_model_spawner"
        pkg="gazebo_ros"
        type="spawn_model"
        args="-param robot_description -urdf -model $(arg arm_id) $(arg unpause)
              $(arg initial_joint_positions)
              "/>

  <!-- Spawn required ROS controllers -->
  <node pkg="controller_manager"
        type="spawner"
        name="$(arg arm_id)_gripper_spawner"
        if="$(arg use_gripper)"
        args="franka_gripper"
        respawn="false"
  />

  <!-- spawns the controller after the robot was put into its initial joint pose -->
  <node pkg="controller_manager"
        type="spawner"
        name="$(arg arm_id)_controller_spawner"
        respawn="false" output="screen"
        args="--wait-for initialized franka_state_controller $(arg controller)"
  />

  <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" />
  <node name="joint_state_publisher" type="joint_state_publisher" pkg="joint_state_publisher">
    <rosparam param="source_list">[franka_state_controller/joint_states, franka_gripper/joint_states] </rosparam>
    <param name="rate" value="30"/>
  </node>

  <!-- Start only if cartesian_impedance_example_controller -->
  <node name="interactive_marker"
        pkg="franka_example_controllers"
        type="interactive_marker.py"
        if="$(arg interactive_marker)">
    <param name="link_name" value="$(arg arm_id)_link0" />
    <remap to="cartesian_impedance_example_controller/equilibrium_pose" from="equilibrium_pose" />
  </node>

  <node  pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/rviz/franka_description_with_marker.rviz" if="$(arg rviz)"/>

</launch>
  <include file="$(dirname)/demo.launch" pass_all_args="true">
    <!-- robot description is loaded by gazebo.launch, to enable Gazebo features -->
    <arg name="load_robot_description" value="false" />
    <!-- MoveItSimpleControllerManager provides ros_control's JointTrajectory controllers
         as well as GripperCommand actions -->
    <arg name="moveit_controller_manager" value="simple" />
  </include>
# 启动moveit_config/launch/demo.launch
# 在demo.launch中不加载robot_description因为在之前的 panda.launch 文件中已经加载过了
# 设置moveit_controller_manager为simple因为仿真可以视作简单的现实,因此不使用fake
# 使用simple类型的控制器管理器来管理和交互机器人的各个关节控制器

切片解析12:gazebo.launch

demo_gazebo.launch文件中启动的是/opt/ros/noetic/share/franka_gazebo/launch/panda.launch,因为gazebo相关的启动文件通常放在机器人的robotname_gazebo文件夹下,同时franka官方也删除了panda_moveit_config/launch文件夹下的gazebo.launch文件。
其实在moveit_config/launch下也存在一个gazebo相关的启动文件: gazebo.launch,它会在setupAssistant阶段被创建。


重新建立一个简单的机器人,生成的gazebo.launch代码如下:

<?xml version="1.0"?>
<launch>
  <!-- Gazebo options -->
  <arg name="gazebo_gui" default="true" doc="Start Gazebo GUI"/>
  <arg name="paused" default="false" doc="Start Gazebo paused"/>
  <arg name="world_name" default="worlds/empty.world" doc="Gazebo world file"/>
  <arg name="world_pose" default="-x 0 -y 0 -z 0 -R 0 -P 0 -Y 0" doc="Pose to spawn the robot at"/>
  <arg name="initial_joint_positions" default=" -J panda_joint1 0 -J panda_joint2 0 -J panda_joint3 0 -J panda_joint4 -1.5708 -J panda_joint5 0 -J panda_joint6 0 -J panda_joint7 0" doc="Initial joint configuration of the robot"/>

  <!-- Start Gazebo paused to allow the controllers to pickup the initial pose -->
  <include file="$(find gazebo_ros)/launch/empty_world.launch" pass_all_args="true">
    <arg name="paused" value="true"/>
  </include>

  <!-- Set the robot urdf on the parameter server -->
  <param name="robot_description" textfile="$(find test_arm_moveit_config)/config/gazebo_panda.urdf" />

  <!-- Unpause the simulation after loading the robot model -->
  <arg name="unpause" value="$(eval '' if arg('paused') else '-unpause')" />

  <!-- Spawn the robot in Gazebo -->
  <node name="spawn_gazebo_model" pkg="gazebo_ros" type="spawn_model" args="-urdf -param robot_description -model robot $(arg unpause) $(arg world_pose) $(arg initial_joint_positions)"
    respawn="false" output="screen" />

  <!-- Load the controller parameters onto the parameter server -->
  <rosparam file="$(find test_arm_moveit_config)/config/gazebo_controllers.yaml" />
  <include file="$(dirname)/ros_controllers.launch"/>

  <!-- Spawn the Gazebo ROS controllers -->
  <node name="gazebo_controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="joint_state_controller" />

  <!-- Given the published joint states, publish tf for the robot links -->
  <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" respawn="true" output="screen" />
</launch>

gazebo的启动参数

  <!-- Gazebo options -->
  <arg name="gazebo_gui" default="true" doc="Start Gazebo GUI"/>
  <arg name="paused" default="false" doc="Start Gazebo paused"/>
  <arg name="world_name" default="worlds/empty.world" doc="Gazebo world file"/>
  <arg name="world_pose" default="-x 0 -y 0 -z 0 -R 0 -P 0 -Y 0" doc="Pose to spawn the robot at"/>
  <arg name="initial_joint_positions" default=" -J panda_joint1 0 -J panda_joint2 0 -J panda_joint3 0 -J panda_joint4 -1.5708 -J panda_joint5 0 -J panda_joint6 0 -J panda_joint7 0" doc="Initial joint configuration of the robot"/>
# 设置一些Gazebo需要的参数
# 设置初始的Gazebo中机械臂各关节的姿态

以暂停模式启动gazebo

  <!-- Start Gazebo paused to allow the controllers to pickup the initial pose -->
  <include file="$(find gazebo_ros)/launch/empty_world.launch" pass_all_args="true">
    <arg name="paused" value="true"/>
  </include>
# 加载gazebo的空世界,同时暂停在0s来方便控制器获取到初始位的姿态值

模拟器在Gazebo初始加载后是暂停的。
这是为了让控制器有足够的时间获取机器人的初始姿态。
如果不先暂停模拟器,开始运行的模拟器中的机器人模型可能会在控制器有机会接收到初始姿态前就已经开始移动了,这可能会导致不正确的行为或是模拟器错误。

加载机器人描述文件到参数服务器

 <!-- Set the robot urdf on the parameter server -->
  <param name="robot_description" textfile="$(find test_arm_moveit_config)/config/gazebo_panda.urdf" />
# 加载机器人描述文件到参数服务器

这个文件描述了机器人的模型,包括链接(links)、关节(joints)和其他特性。robot_description是许多ROS节点(包括robot_state_publishermove_group)需要的参数。

unpause参数的设置

  <!-- Unpause the simulation after loading the robot model -->
  <arg name="unpause" value="$(eval '' if arg('paused') else '-unpause')" />

设置一个参数unpause,如果paused为真(也就是Gazebo在启动后是暂停的),那么unpause就是空字符串,否则是-unpause
这是因为在加载机器人模型后,如果模拟器最初没有被暂停,那么需要取消暂停以开始模拟。这行设置用于在适当的时候执行这个操作。
这意味着只有在模拟器被暂停时,参数 unpause 才会包含 -unpause 字符串,这样在 spawn_gazebo_model 节点中就会将模拟器从暂停状态恢复过来。反之,如果模拟器一开始就没有被暂停,那么 unpause 参数将为空字符串,即不会对模拟器的状态产生影响。

诞生机器人模型

  <!-- Spawn the robot in Gazebo -->
  <node name="spawn_gazebo_model" pkg="gazebo_ros" type="spawn_model" args="-urdf -param robot_description -model robot $(arg unpause) $(arg world_pose) $(arg initial_joint_positions)"
    respawn="false" output="screen" />
  • args="-urdf -param robot_description -model robot $(arg unpause) $(arg world_pose) $(arg initial_joint_positions)"是传递给spawn_model节点的参数。

    • -urdf: 表示下一个参数robot_description是URDF(Unified Robot Description Format,统一机器人描述格式)格式的,这个文件通常已经从.xacro转化为.urdf到参数服务器了。
    • -param robot_description: ROS参数服务器中的参数,它包含了描述机器人模型的URDF文件的内容。
    • -model robot: 为机器人模型在Gazebo中设置了名称,这里的名称是robot
    • $(arg unpause): 这是前面定义的一个参数,它可能是空字符串(当模拟开始时并未发生过暂停,也就是没有任何影响),或者是-unpause(当模拟开始时暂停了,此时模型加载后需要解除暂停)。
    • $(arg world_pose): 这是机器人模型在Gazebo世界中的初始姿态。
    • $(arg initial_joint_positions): 这是机器人模型的初始关节位置。
  • respawn="false": 这个选项表示,如果该节点因任何原因停止运行,ROS不应尝试重新启动它。

  • output="screen": 这表示节点的输出应该被打印到屏幕。这对于调试和监控节点的运行情况很有用。

这个代码片段将URDF格式的机器人模型加载到Gazebo模拟器中,模型的初始位置和关节状态由相应的参数定义。并且,根据unpause参数的值,会在模型加载后解除Gazebo模拟器的0s暂停状态。

加载控制器参数到参数服务器

 <!-- Load the controller parameters onto the parameter server -->
  <rosparam file="$(find test_arm_moveit_config)/config/gazebo_controllers.yaml" />
# 将config/gazebo_controllers.yaml文件加载到参数服务器
gazebo_controllers.yaml
# Publish joint_states
joint_state_controller:
  type: joint_state_controller/JointStateController
  publish_rate: 50

gazebo_controllers.yaml配置文为ROS中的控制器管理器(controller_manager)定义了将要管理的控制器及其相关参数。

此处定义了一个名为joint_state_controller的控制器。

  • joint_state_controller: 是该控制器的名称,这个名称将被控制器管理器用来引用这个控制器。

  • type: joint_state_controller/JointStateController 定义了控制器的类型。在这个例子中,控制器的类型是 JointStateController,它的任务是读取每个关节的状态(位置,速度,和力矩)并发布到joint_states话题。这个话题通常被robot_state_publisher节点订阅,后者用这些信息来更新机器人模型的状态,并将该状态发布到tf(transform)话题。

  • publish_rate: 50JointStateController 控制器的一个参数,它定义了控制器应该以每秒50次的频率发布关节状态信息。

启动ros_controllers.launch

<include file="$(dirname)/ros_controllers.launch"/>
# 引用了ros_controllers.launch在此处启动

这个没啥用,因为传入的控制器内容为空,所以也没有启动对应的控制器,可能是Moveit的作者想区分ros下的普通控制器和gazebo的控制器,也有可能是真实机械臂和gazebo的仿真需要做数字孪生同步进行,才有了这样的区别,仅作参考。

ros_controllers.launch
<?xml version="1.0"?>
<launch>

  <!-- Load joint controller configurations from YAML file to parameter server -->
  <rosparam file="$(find panda_moveit_config)/config/ros_controllers.yaml" command="load"  subst_value="true"/>

  <!-- Load and start the controllers -->
  <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen"
        args="$(arg transmission)_joint_trajectory_controller" />
</launch>

ros_controllers.launchros_controllers.yaml里的控制器的配置加载到参数服务器

随后启动controller_manager包的spawner来生成控制器。
这个节点的参数$(arg transmission)_joint_trajectory_controller指定了需要启动的控制器类型,假如此处为effort,则为effort__joint_trajectory_controller类型的控制器。

demo_gazebo.launch文件中该值被传入,随后被传给gazebo.launch,随后再传给ros_controllers.launch并在此处被应用为effort,使得传动方式为力控

spawner节点的参数是$(arg transmission)_joint_trajectory_controller。在这个案例中,这意味着它会试图启动名为effort_joint_trajectory_controller的控制器。

ros_controllers.yaml

该文件为空,没有内容

启动gazebo_controllers.yaml中的控制器

  <!-- Spawn the Gazebo ROS controllers -->
  <node name="gazebo_controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="joint_state_controller" />

在此前gazebo_controllers.yaml中的控制器已经被加载到参数服务器,随后在此处被启动。
controller_manager控制器管理者包中的spawner节点将名为joint_state_controller的控制器启动(joint_state_controller在gazebo_controllers.yaml中存在)

发布机器人状态

  <!-- Given the published joint states, publish tf for the robot links -->
  <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" respawn="true" output="screen" />
</launch>

robot_state_publisher节点会发布机器人的关节状态,并生成tf(transform)消息,用于追踪机器人各link的位姿。

切片解析13:joystick_control.launch

使用手柄来控制,整活可以参考moveit_ros的手柄教程,此处不作延申。

<launch>
  <!-- See moveit_ros/visualization/doc/joystick.rst for documentation -->

  <arg name="dev" default="/dev/input/js0" />

  <!-- Launch joy node -->
  <node pkg="joy" type="joy_node" name="joy">
    <param name="dev" value="$(arg dev)" /> <!-- Customize this to match the location your joystick is plugged in on-->
    <param name="deadzone" value="0.2" />
    <param name="autorepeat_rate" value="40" />
    <param name="coalesce_interval" value="0.025" />
  </node>

  <!-- Launch python interface -->
  <node pkg="moveit_ros_visualization" type="moveit_joy.py" output="screen" name="moveit_joy"/>

</launch>

这个launch文件用于在ROS系统中被用于设置使用游戏手柄(joystick)来控制移动的机器人。

启动joy_node节点来处理游戏手柄的输入

  1. dev – 这是游戏手柄设备的路径,默认为/dev/input/js0。这个路径可能需要根据具体系统进行更改。

  2. deadzone – 死区阈值,如果手柄的位移小于这个值,那么它将被忽略,以避免由于手柄的微小移动导致的误操作。这个值默认为0.2。

  3. autorepeat_rate – 这是自动重复的频率,单位是Hz,默认为40。这表示如果手柄的某个按钮被按住不放,那么这个节点将每秒生成40个相同的消息。

  4. coalesce_interval – 这是合并时间间隔,单位是秒,默认为0.025。如果在这个时间间隔内,有多个输入事件到达,那么这个节点将把它们合并成一个事件。

然后,这个launch文件启动另一个节点moveit_joy.py,这是一个Python接口,用于将游戏手柄的输入转换为MoveIt!可以理解的控制信号。

切片解析14:run_benchmark_ompl.launch

用于ompl库的性能评估任务

<launch>

  <!-- This argument must specify the list of .cfg files to process for benchmarking -->
  <arg name="cfg" />

  <!-- Load URDF -->
  <include file="$(dirname)/planning_context.launch">
    <arg name="load_robot_description" value="true"/>
  </include>

  <!-- Start the database -->
  <include file="$(dirname)/warehouse.launch">
    <arg name="moveit_warehouse_database_path" value="moveit_ompl_benchmark_warehouse"/>
  </include>

  <!-- Start Benchmark Executable -->
  <node name="$(anon moveit_benchmark)" pkg="moveit_ros_benchmarks" type="moveit_run_benchmark" args="$(arg cfg) --benchmark-planners" respawn="false" output="screen">
    <rosparam command="load" file="$(find panda_moveit_config)/config/ompl_planning.yaml"/>
  </node>

</launch>

cfg

  <!-- This argument must specify the list of .cfg files to process for benchmarking -->
  <arg name="cfg" />

定义了一个命令行参数,此参数指定要进行基准测试的.cfg文件列表。

启动planning_context.launch

  <!-- Load URDF -->
  <include file="$(dirname)/planning_context.launch">
    <arg name="load_robot_description" value="true"/>
  </include>
# 加载机器人描述文件,启动启动planning_context.launch

启动数据库

  <!-- Start the database -->
  <include file="$(dirname)/warehouse.launch">
    <arg name="moveit_warehouse_database_path" value="moveit_ompl_benchmark_warehouse"/>
  </include>

warehouse.launch文件用于启动MoveIt!的数据库服务。这个服务主要用于存储和检索运动规划问题,解决方案,状态等。
moveit_warehouse_database_path为数据库的路径。

  <!-- Start Benchmark Executable -->
  <node name="$(anon moveit_benchmark)" pkg="moveit_ros_benchmarks" type="moveit_run_benchmark" args="$(arg cfg) --benchmark-planners" respawn="false" output="screen">
    <rosparam command="load" file="$(find panda_moveit_config)/config/ompl_planning.yaml"/>
  </node>

anon moveit_benchmarkanon会给定独特的后缀,方便多个moveit_benchmark任务不重名地进行,启动moveit_ros_benchmarks包的moveit_run_benchmark节点,--benchmark-planners标志,表示需要基准测试规划器。
cfg参数在此前被定义,但在文件中没有赋值,所以要从外部命令行中指定这个参数的值,例如:

roslaunch package_name run_benchmark_ompl.launch cfg:=/path/to/your/config/file.cfg

这样,cfg参数就被赋值为/path/to/your/config/file.cfg,这个路径将会作为参数传递给moveit_run_benchmark节点。

同时在启动这个节点时加载参数ompl_planning.yaml到ROS参数服务器,用于读取ompl的设置,方便任务评估。

切片解析15:franka_control.launch

<?xml version="1.0"?>
<launch>
  <arg name="robot_ip" />
  <arg name="load_gripper" />

  <!-- Launch real-robot control -->
  <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true" />

  <!-- By default use joint position controllers -->
  <arg name="transmission" default="position" />
  <!-- Start ROS controllers -->
  <include file="$(dirname)/ros_controllers.launch" pass_all_args="true" />

  <!-- as well as MoveIt demo -->
  <include file="$(dirname)/demo.launch" pass_all_args="true">
    <!-- robot description is loaded by franka_control.launch -->
    <arg name="load_robot_description" value="false" />
    <!-- MoveItSimpleControllerManager provides ros_control's JointTrajectory controllers
         as well as GripperCommand actions -->
    <arg name="moveit_controller_manager" value="simple" />
  </include>
</launch>

加载真实机械臂控制

  <!-- Launch real-robot control -->
  <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true" />

Franka Emika Panda 是一个常用于研究和教学的七自由度机器人臂,也就是本篇所使用的demo机械臂Panda
启动franka_control包的franka_control.launch并传递所有参数(如机械臂的IP和是否加载夹爪),franka_control.launch文件用于启动控制Franka Emika Panda实体机器人。

真实机械臂franka_control.launch

如果已经用一键配置安装脚本配过了,那么可以在/opt/ros/noetic/share/franka_control/launch路径下找到franka_control.launch,内容如下:

<?xml version="1.0" ?>
<launch>
  <arg name="robot_ip" />
  <arg name="robot" default="panda" doc="choose your robot. Possible values: [panda, fr3]"/>
  <arg name="arm_id" default="$(arg robot)" />
  <arg name="load_gripper" default="true" />
  <arg name="xacro_args" default="" />

  <param name="robot_description" command="$(find xacro)/xacro $(find franka_description)/robots/$(arg robot)/$(arg robot).urdf.xacro hand:=$(arg load_gripper) arm_id:=$(arg arm_id) $(arg xacro_args)"/>

  <include file="$(find franka_gripper)/launch/franka_gripper.launch" if="$(arg load_gripper)">
    <arg name="robot_ip" value="$(arg robot_ip)" />
    <arg name="arm_id"   value="$(arg arm_id)" />
  </include>

  <node name="franka_control" pkg="franka_control" type="franka_control_node" output="screen" required="true">
    <rosparam command="load" file="$(find franka_control)/config/franka_control_node.yaml" subst_value="true" />
    <param name="robot_ip" value="$(arg robot_ip)" />
  </node>

  <rosparam command="load" file="$(find franka_control)/config/default_controllers.yaml" subst_value="true" />
  <node name="state_controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="franka_state_controller"/>
  <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" output="screen"/>
  <node name="joint_state_publisher" type="joint_state_publisher" pkg="joint_state_publisher" output="screen">
    <rosparam if="$(arg load_gripper)" param="source_list">[franka_state_controller/joint_states, franka_gripper/joint_states] </rosparam>
    <rosparam unless="$(arg load_gripper)" param="source_list">[franka_state_controller/joint_states] </rosparam>
    <param name="rate" value="30"/>
  </node>
</launch>

简单地解释部分内容:

  <param name="robot_description" command="$(find xacro)/xacro $(find franka_description)/robots/$(arg robot)/$(arg robot).urdf.xacro hand:=$(arg load_gripper) arm_id:=$(arg arm_id) $(arg xacro_args)"/>
# 加载了robot_description到ROS参数服务器
# 具体的模型内容通过参数hand:=$(arg load_gripper) arm_id:=$(arg arm_id) $(arg xacro_args)在xacro宏里进行选择
# 比如是否加载夹爪和其他的xacro_args需求
  <include file="$(find franka_gripper)/launch/franka_gripper.launch" if="$(arg load_gripper)">
    <arg name="robot_ip" value="$(arg robot_ip)" />
    <arg name="arm_id"   value="$(arg arm_id)" />
  </include>
# 加载夹爪节点
# 不再拓展讲,有兴趣的自己看
  <node name="franka_control" pkg="franka_control" type="franka_control_node" output="screen" required="true">
    <rosparam command="load" file="$(find franka_control)/config/franka_control_node.yaml" subst_value="true" />
    <param name="robot_ip" value="$(arg robot_ip)" />
  </node>
# 启动franka_control_node控制节点
# 载入相关配置参数franka_control_node.yaml
 <rosparam command="load" file="$(find franka_control)/config/default_controllers.yaml" subst_value="true" />
  <node name="state_controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="franka_state_controller"/>
# 载入控制器参数default_controllers.yaml到ROS参数服务器
# 使用控制器管理者的spawner来启动franka_state_controller
  <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" output="screen"/>
  <node name="joint_state_publisher" type="joint_state_publisher" pkg="joint_state_publisher" output="screen">
    <rosparam if="$(arg load_gripper)" param="source_list">[franka_state_controller/joint_states, franka_gripper/joint_states] </rosparam>
    <rosparam unless="$(arg load_gripper)" param="source_list">[franka_state_controller/joint_states] </rosparam>
    <param name="rate" value="30"/>
  </node>
# 加载机器人状态发布器robot_state_publisher节点
# 加载机器人关节状态发布器joint_state_publisher节点

启用位置控制类型的controllers

 <!-- By default use joint position controllers -->
  <arg name="transmission" default="position" />
  <!-- Start ROS controllers -->
  <include file="$(dirname)/ros_controllers.launch" pass_all_args="true" />

启用位置控制类型的controllers,也就是名为:position_joint_trajectory_controller的控制器,目前不确定该控制器被加载到ROS参数服务器中,但是在simple_moveit_controllers.yaml中可以发现如果使用simple类型的控制器管理者,名为$(arg transmission)_joint_trajectory_controller的控制器参数将会被加载到ROS参数服务器,这意味着当时能使用simple时,这个控制器能被正确地加载。

simple_moveit_controllers.yaml
controller_list:
  - name: $(arg transmission)_joint_trajectory_controller
    action_ns: follow_joint_trajectory
    type: FollowJointTrajectory
    default: True
    joints:
      - $(arg arm_id)_joint1
      - $(arg arm_id)_joint2
      - $(arg arm_id)_joint3
      - $(arg arm_id)_joint4
      - $(arg arm_id)_joint5
      - $(arg arm_id)_joint6
      - $(arg arm_id)_joint7
  - name: franka_gripper
    action_ns: gripper_action
    type: GripperCommand
    default: True
    joints:
      - $(arg arm_id)_finger_joint1

启动RViz窗口

  <!-- as well as MoveIt demo -->
  <include file="$(dirname)/demo.launch" pass_all_args="true">
    <!-- robot description is loaded by franka_control.launch -->
    <arg name="load_robot_description" value="false" />
    <!-- MoveItSimpleControllerManager provides ros_control's JointTrajectory controllers
         as well as GripperCommand actions -->
    <arg name="moveit_controller_manager" value="simple" />
  </include>

启动经典的demo.launch,猜测是用于RViz中Motion_planning插件拖拽控制实体机械臂。

切片解析16:setup_assistant.launch

<!-- Re-launch the MoveIt Setup Assistant with this configuration package already loaded -->
<launch>

  <!-- Debug Info -->
  <arg name="debug" default="false" />
  <arg unless="$(arg debug)" name="launch_prefix" value="" />
  <arg     if="$(arg debug)" name="launch_prefix" value="gdb --ex run --args" />

  <!-- Run -->
  <node pkg="moveit_setup_assistant" type="moveit_setup_assistant" name="moveit_setup_assistant"
        args="--config_pkg=panda_moveit_config"
        launch-prefix="$(arg launch_prefix)"
        required="true"
        output="screen" />

</launch>

传入--config_pkg=panda_moveit_config参数,使得Moveit SetupAssistant能够直接加载这个moveit_config包的内容,通常用于重配包。
当然,直接打开Moveit SetupAssistant手动载入也是一样的,怎么方便怎么来。

其他切片

pandu_moveit_config包中还有其他的一些独有的文件,这在普通的moveit_config包里没有,但是比较有用。
比如说CHOMP、LERP和STOMP是用于机器人路径规划的不同算法。在这个情况下,demo_chomp.launchdemo_lerp.launchdemo_stomp.launch 这些文件是用来启动和展示这些不同路径规划算法的。

  1. demo_chomp.launch: CHOMP (Collision-Heuristic Optimization for Motion Planning) 是一种机器人路径规划算法,它基于启发式优化来规划路径,避免与环境中的对象碰撞。这个 demo 文件会启动一个使用 CHOMP 算法进行路径规划的例子。

  2. demo_lerp.launch: LERP (Linear Interpolation) 是最简单的路径规划算法之一,它只是简单地在机器人的当前位置和目标位置之间生成一条直线。但是,它没有考虑到环境中的障碍物,所以这个算法可能并不适合所有的情况。这个 demo 文件会启动一个使用 LERP 算法进行路径规划的例子。

  3. demo_stomp.launch: STOMP (Stochastic Trajectory Optimization for Motion Planning) 是另一种机器人路径规划算法,它使用随机优化方法来规划路径。与 CHOMP 不同的是,STOMP 会考虑到机器人的动态性质,以及路径规划中的噪声和不确定性。这个 demo 文件会启动一个使用 STOMP 算法进行路径规划的例子。

这三个 .launch 文件是用来演示如何使用 MoveIt 和 ROS 来使用不同的路径规划算法的。选择哪种算法取决于你的特定需求和机器人的特性。

Moveit的源码解析

在config配置包的文件解析中,有较多参数是导入到了ROS的参数服务器,但具体的实现和调用过程对用户是不透明的,如果需要弄懂就需要去深入moveit的源代码,鉴于此篇文章长度太长,所以moveit源码解析将放在另一篇文章,并在此处附上链接
TODO:moveit源码解析的链接

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
心中带点小风骚的头像心中带点小风骚普通用户
上一篇 2023年12月6日
下一篇 2023年12月6日

相关推荐