MoveIt! 学习笔记5- MoveGroup PlanningScene ROS API 在RVIZ环境中添加删除物品

此博文主要是用来记录ROS-Kinetic 中,用于机器人轨迹规划的MoveIt功能包的学习记录。 

英文原版教程见此链接:http://docs.ros.org/en/kinetic/api/moveit_tutorials/html/doc/move_group_interface/move_group_interface_tutorial.html

 引: MoveGroup PlanningScene ROS API 的主要功能是,定义一个将要添加到RVIZ环境中的物品,并在RVIZ中显示。

         同时,在使用RVIZ进行抓取,放下的仿真时,也需要用这个教程,在抓取完成时,将物品与机器人夹爪链接在一起,在机器人夹爪放开物品后,再将物品与机器人夹爪解除绑定。

官方教程主要以代码实例为主,所以,在下边的代码中,主要通过注释的方式,解释代码含义,通过代码实例,学习MoveIt内部内容。

/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2012, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************/

/* Author: Sachin Chitta, Michael Lautman */

#include <ros/ros.h>
#include <geometry_msgs/Pose.h>

// MoveIt!
#include <moveit_msgs/PlanningScene.h>
#include <moveit_msgs/AttachedCollisionObject.h>
#include <moveit_msgs/GetStateValidity.h>
#include <moveit_msgs/DisplayRobotState.h>
#include <moveit_msgs/ApplyPlanningScene.h>

#include <moveit/robot_model_loader/robot_model_loader.h>
#include <moveit/robot_state/robot_state.h>
#include <moveit/robot_state/conversions.h>

#include <moveit_visual_tools/moveit_visual_tools.h>

int main(int argc, char** argv)
{
  ros::init(argc, argv, "planning_scene_ros_api_tutorial");
  ros::AsyncSpinner spinner(1);
  spinner.start();

  ros::NodeHandle node_handle;

  //PlanningSceneRosAPI这个功能包在本教程中,主要功能是在RVIZ中显示一个box,将这个box链接在ROBOT上,解除链接,然后再移除这个box
 
  //Part0: 注意!!重要, 这个moveit_visual_tools工具箱,主要功能是在RVIZ界面中显示信息/轨迹等内容
  moveit_visual_tools::MoveItVisualTools visual_tools("panda_link0");
  visual_tools.deleteAllMarkers();

  // ROS API
  // ^^^^^^^
  // ROS API的功能是:规划一个不同于当前显示环境的一个场景
  //
  //Part1:创建一个Publisher,用于发送planning_scene(规划场景)
  //       并且等待有Subscriber订阅这个topic后,再进行下一步操作
  // Advertise the required topic
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // We create a publisher and wait for subscribers
  // Note that this topic may need to be remapped in the launch file
  ros::Publisher planning_scene_diff_publisher = node_handle.advertise<moveit_msgs::PlanningScene>("planning_scene", 1);
  ros::WallDuration sleep_t(0.5);
  while (planning_scene_diff_publisher.getNumSubscribers() < 1)
  {
    sleep_t.sleep();
  }
  //等待操作人员按按钮,或者输入
  visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to start the demo");



  //Part2:定义一个将被链接到Robot并显示在RVIZ中的物品对象


  //Step2.1 创建被连接的对象,确定链接的link,确定连接后,被连接物体的位姿
  moveit_msgs::AttachedCollisionObject attached_object;    //声明连接对象
  attached_object.link_name = "panda_leftfinger";          //确定物品将要连接到的link名
  /* The header must contain a valid TF frame*/
  attached_object.object.header.frame_id = "panda_leftfinger";
  /* The id of the object */
  attached_object.object.id = "box";

  /* A default pose */
  geometry_msgs::Pose pose;
  pose.orientation.w = 1.0;

  //Step2.2 创建一个Box对象,并将前边设置的位置,名称,位姿等参数进行输入
  /* Define a box to be attached */
  shape_msgs::SolidPrimitive primitive;                    //定义一个box
  primitive.type = primitive.BOX;
  primitive.dimensions.resize(3);
  primitive.dimensions[0] = 0.1;
  primitive.dimensions[1] = 0.1;
  primitive.dimensions[2] = 0.1;

  attached_object.object.primitives.push_back(primitive);
  attached_object.object.primitive_poses.push_back(pose);

  // step2.3 创建一个向RVIZ中添加物品的对象
  attached_object.object.operation = attached_object.object.ADD;

  //step2.4由于要进行抓取和放置的仿真,因此需要禁用碰撞检测
  attached_object.touch_links = std::vector<std::string>{ "panda_hand", "panda_leftfinger", "panda_rightfinger" };




  // Part3: 创建一个planningScene场景对象,并将box添加进来
  ROS_INFO("Adding the object into the world at the location of the hand.");
  moveit_msgs::PlanningScene planning_scene;
  planning_scene.world.collision_objects.push_back(attached_object.object);
  planning_scene.is_diff = true;
  planning_scene_diff_publisher.publish(planning_scene); //使用的是publisher
  visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo");

  // Interlude: Synchronous vs Asynchronous updates
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // There are two separate mechanisms available to interact
  // with the move_group node using diffs:
  //
  // * Send a diff via a rosservice call and block until
  //   the diff is applied (synchronous update)
  // * Send a diff via a topic, continue even though the diff
  //   might not be applied yet (asynchronous update)
  //
  // While most of this tutorial uses the latter mechanism (given the long sleeps
  // inserted for visualization purposes asynchronous updates do not pose a problem),
  // it would is perfectly justified to replace the planning_scene_diff_publisher
  // by the following service client:
  ros::ServiceClient planning_scene_diff_client =
      node_handle.serviceClient<moveit_msgs::ApplyPlanningScene>("apply_planning_scene");
  planning_scene_diff_client.waitForExistence();
  // and send the diffs to the planning scene via a service call:
  moveit_msgs::ApplyPlanningScene srv;
  srv.request.scene = planning_scene;
  planning_scene_diff_client.call(srv);
  // Note that this does not continue until we are sure the diff has been applied.
  //



  // Part4: 将添加到RVIZ的box,连接到机器人本体上
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // 当我们需要使用RVIZ进行机器人抓取仿真时,在抓取发生时,我们所做的实际上就是将物品attach到机器人上;
  // 当release之后,我们再将物品detach下来即可
  // 为了不出差错, 链接操作需要分两步进行

  //* Step4.1 首先将RVIZ环境中已经存在的object移除
  moveit_msgs::CollisionObject remove_object;
  remove_object.id = "box";
  remove_object.header.frame_id = "panda_link0";
  remove_object.operation = remove_object.REMOVE;
  
  //* Step4.2 在添加物品之前,首先要求人,这个diff message是否已经被清空?否则将报错
  /* Carry out the REMOVE + ATTACH operation */
  ROS_INFO("Attaching the object to the hand and removing it from the world.");
  planning_scene.world.collision_objects.clear();
  planning_scene.world.collision_objects.push_back(remove_object);
  planning_scene.robot_state.attached_collision_objects.push_back(attached_object);
  planning_scene_diff_publisher.publish(planning_scene);

  visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo");


  // Part5: 将物品从robot上,解除绑定
  //* Step5.1 :将已经添加的object移除
  moveit_msgs::AttachedCollisionObject detach_object;
  detach_object.object.id = "box";
  detach_object.link_name = "panda_link8";
  detach_object.object.operation = attached_object.object.REMOVE;

 //* Step5.2 :将添加box时,所用的对象清空
  ROS_INFO("Detaching the object from the robot and returning it to the world.");
  planning_scene.robot_state.attached_collision_objects.clear();
  planning_scene.robot_state.attached_collision_objects.push_back(detach_object);
  planning_scene.robot_state.is_diff = true;
  planning_scene.world.collision_objects.clear();
  planning_scene.world.collision_objects.push_back(attached_object.object);
  planning_scene.is_diff = true;
  planning_scene_diff_publisher.publish(planning_scene);

  visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo");

  // Part6: 将物品从rviz环境中清除
  ROS_INFO("Removing the object from the world.");
  planning_scene.robot_state.attached_collision_objects.clear();
  planning_scene.world.collision_objects.clear();
  planning_scene.world.collision_objects.push_back(remove_object);
  planning_scene_diff_publisher.publish(planning_scene);
  // END_TUTORIAL

  visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to end the demo");

  ros::shutdown();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42503785/article/details/111829956