{"id":123,"date":"2019-03-01T20:40:35","date_gmt":"2019-03-01T20:40:35","guid":{"rendered":"http:\/\/erdalpekel.de\/?p=123"},"modified":"2021-02-13T09:24:24","modified_gmt":"2021-02-13T09:24:24","slug":"panda-in-gazebo-constraint-aware-planning","status":"publish","type":"post","link":"https:\/\/erdalpekel.de\/?p=123","title":{"rendered":"MoveIt! &#8211; Constraint-aware planning"},"content":{"rendered":"\n<p>In the first article of this series I outlined the integration of the Panda robot from FRANKA EMIKA into the Gazebo simulation environment. We did so by modifying the packages franka_ros and libfranka which FRANKA EMIKA provides such that the additional information required by Gazebo was added to the robot model and the controller configuration. For a detailed look you can read the <a href=\"https:\/\/erdalpekel.de\/?p=55\">article<\/a>.<\/p>\n\n\n\n<p>In this post we are going to utilize MoveIt! in order to navigate Panda in a cluttered environment in the Gazebo simulation. I will provide you with sample json files that contain information about the objects the robot should avoid. We will spawn the robot directly into this environment.<\/p>\n\n\n\n<p>In MoveIt! we will add objects around the robot. These should raise awareness when moving. This way, we have the ability to put constraints on the robots motion planning depending on its environment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Implementation<\/h2>\n\n\n\n<p>We will implement a node called robot_control_node where we <\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>connect to the move group of the panda robots arm,<\/li><li>create the move group planning scene publisher,<\/li><li>read collision objects from the filesystem and<\/li><li>publish collision objects to the <em>MoveIt!<\/em> planning scene.<\/li><\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">System dependencies &amp; Preliminaries<\/h3>\n\n\n\n<p>Our dependencies are <a href=\"https:\/\/www.boost.org\/doc\/libs\/1_69_0\/libs\/filesystem\/doc\/index.htm\"><strong>boost filesystem<\/strong><\/a> for reading from the directory ~\/.panda_simulation and <a href=\"https:\/\/github.com\/open-source-parsers\/jsoncpp\"><strong>jsoncpp<\/strong><\/a> for parsing the collision objects files which we store as json files. Let&#8217;s have a look at a sample file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">{\n  \"dimensions\": {\n    \"x\": 2.0,\n    \"y\": 0.1,\n    \"z\": 2.5\n  },\n  \"position\": {\n    \"x\": -1.0,\n    \"y\": -0.6,\n    \"z\": 0.0\n  },\n  \"orientation\": {\n    \"w\": 1.0,\n    \"x\": 0.0,\n    \"y\": 0.0,\n    \"z\": 0.0\n  }\n}<\/code><\/pre>\n\n\n\n<p>The orientation is defined as a quaternion. <a href=\"https:\/\/quaternions.online\/\">Here<\/a> is my resource of choice for visualization of quaternions. I will outline the reference frame of the position field in a moment. Dimensions defines the dimensions of the bounding box that. Yes, we are going to define the collision objects as bounding boxes in this tutorial.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Project setup<\/h3>\n\n\n\n<p>We will use the <a href=\"https:\/\/github.com\/erdalpekel\/panda_simulation\">panda_simulation<\/a> repository from my last <a href=\"https:\/\/erdalpekel.de\/?p=55\">blog post<\/a> as a basis for our implementation. We will need to add the previously defined system dependencies as well as the some MoveIt! packages that we use in the new node to our <a href=\"https:\/\/github.com\/erdalpekel\/panda_simulation\/blob\/master\/CMakeLists.txt\">CMakeLists.txt<\/a> and also add the MoveIt! dependencies to our <a href=\"https:\/\/github.com\/erdalpekel\/panda_simulation\/blob\/master\/package.xml\">package.xml<\/a>. I will only mention the additional ROS dependencies introduced:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"vim\" class=\"language-vim\">moveit_core\nmoveit_visual_tools\nmoveit_ros_planning\nmoveit_ros_planning_interface<\/code><\/pre>\n\n\n\n<p>Our new node is called <em>robot_control_node<\/em> because connecting to the move group of panda&#8217;s arm gives us the ability to control the robot (which we will hopefully do in our next blog post!).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">ROS Node<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">1. Connecting to the move group of Panda&#8217;s arm<\/h4>\n\n\n\n<p>A ROS node that is supposed to connect to move group should spin asynchronously with <em><a href=\"http:\/\/wiki.ros.org\/roscpp\/Overview\/Callbacks%20and%20Spinning\">AsyncSpinner<\/a><\/em> for better compatibility with the nature asynchronous MoveIt! API calls. A suitable example for this is that issuing plan or move calls will presumably take a long time and should not block the process that the ROS node is running in.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp\">ros::init(argc, argv, \"robot_control_node\");\n\nros::NodeHandle node_handle;\nros::AsyncSpinner spinner(1);\nspinner.start();\n\nmoveit::planning_interface::MoveGroupInterface move_group_arm(PLANNING_GROUP_ARM);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">2. Create the move group planning scene publisher<\/h4>\n\n\n\n<p>This is crucial: Unfortunately it is extremely hard to find a mapping between MoveIt! core packages \/ modules and associated ROS topics. In our case the topic <em>\/planning_scene<\/em> takes our desired changes (<em>diff<\/em>) to the current planning scene of the planning scene. This is the interface to the MoveIt! Planning Scene ROS API. We will make our node sleep until there is actually a scene that subscribes to the diff that we want to publish. The <em>planning_scene<\/em> object that we define at the end is our interface to the planning scene. With it we are going to publish the collision objects in the correct format.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp\">ros::Publisher planning_scene_diff_publisher = node_handle.advertise&lt;moveit_msgs::PlanningScene&gt;(\"planning_scene\", 1);\nros::WallDuration sleep_t(0.5);\nwhile (planning_scene_diff_publisher.getNumSubscribers() &lt; 1)\n{\n  sleep_t.sleep();\n}\nmoveit_msgs::PlanningScene planning_scene;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">3. Read collision objects from  the filesystem<\/h4>\n\n\n\n<p>We are now ready to read json files defining collision objects from a predefined directory in the users home folder (~\/.panda_simulation) and publish the objects to the planning scene. The important part is the helper function that extracts the obstacles when given a json object:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp\">moveit_msgs::CollisionObject extractObstacleFromJson(Json::Value &amp;root, std::string name)\n{\n  moveit_msgs::CollisionObject collision_object;\n  collision_object.header.frame_id = \"world\";\n  collision_object.id = name;\n\n  const Json::Value dimensions = root[\"dimensions\"];\n  ROS_INFO_STREAM(\"Extracted dimensions: \" &lt;&lt; dimensions);\n  \/\/ Define a box to add to the world.\n  shape_msgs::SolidPrimitive primitive;\n  primitive.type = primitive.BOX;\n  primitive.dimensions.resize(3);\n  primitive.dimensions[0] = dimensions[\"x\"].asDouble();\n  primitive.dimensions[1] = dimensions[\"y\"].asDouble();\n  primitive.dimensions[2] = dimensions[\"z\"].asDouble();\n\n  const Json::Value position = root[\"position\"];\n  ROS_INFO_STREAM(\"Extracted position: \" &lt;&lt; position);\n\n  const Json::Value orientation = root[\"orientation\"];\n  ROS_INFO_STREAM(\"Extracted orientation: \" &lt;&lt; orientation);\n  \/\/ Define a pose for the box (specified relative to frame_id)\n  geometry_msgs::Pose box_pose;\n  box_pose.orientation.w = orientation[\"w\"].asDouble();\n  box_pose.orientation.x = orientation[\"x\"].asDouble();\n  box_pose.orientation.y = orientation[\"y\"].asDouble();\n  box_pose.orientation.z = orientation[\"z\"].asDouble();\n  box_pose.position.x = position[\"x\"].asDouble() + primitive.dimensions[0] \/ 2.0;\n  box_pose.position.y = position[\"y\"].asDouble() + primitive.dimensions[1] \/ 2.0;\n  box_pose.position.z = position[\"z\"].asDouble() + primitive.dimensions[2] \/ 2.0;\n\n  collision_object.primitives.push_back(primitive);\n  collision_object.primitive_poses.push_back(box_pose);\n  collision_object.operation = collision_object.ADD;\n\n  return std::move(collision_object);\n}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li>With collision_object.header.frame_id = &#8220;world&#8221; we define the reference coordinate system of the object<\/li><li><strong>The position of a bounding box is defined as it&#8217;s center in the planning scene! <\/strong>That&#8217;s why we add half of its dimension to its position<\/li><\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">4. Publish collision objects to the planning scene<\/h4>\n\n\n\n<p>We will finally publish the collision objects to the planning scene. This is done by adding collision objects to the <em>collision_objects <\/em>vector of the scene objects world member:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp\">\/\/ Publish the collision objects to the scene\nfor (const auto &amp;collision_object : collision_objects)\n{\n  collision_object.header.frame_id = move_group_arm.getPlanningFrame();\n  planning_scene.world.collision_objects.push_back(collision_object);\n}\n\nROS_INFO_STREAM(\"# collision objects \" &lt;&lt; planning_scene.world.collision_objects.size());\nplanning_scene.is_diff = true;\nplanning_scene_diff_publisher.publish(planning_scene);<\/code><\/pre>\n\n\n\n<p>It is also important to note that we are setting the <em>is_diff<\/em> member to true. This way we do not alter a state that another node might have set before.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Result<\/h2>\n\n\n\n<figure class=\"wp-block-image\"><img fetchpriority=\"high\" decoding=\"async\" width=\"763\" height=\"856\" src=\"https:\/\/erdalpekel.de\/wp-content\/uploads\/2019\/03\/RViz-collision-object.jpg\" alt=\"\" class=\"wp-image-140\" srcset=\"https:\/\/erdalpekel.de\/wp-content\/uploads\/2019\/03\/RViz-collision-object.jpg 763w, https:\/\/erdalpekel.de\/wp-content\/uploads\/2019\/03\/RViz-collision-object-267x300.jpg 267w\" sizes=\"(max-width: 763px) 100vw, 763px\" \/><\/figure>\n\n\n\n<p>The custom <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/erdalpekel\/panda_simulation\" target=\"_blank\">ROS package<\/a> as well as the modified <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/erdalpekel\/franka_ros\" target=\"_blank\">franka_ros<\/a> and <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/erdalpekel\/panda_moveit_config\" target=\"_blank\">panda_moveit_config<\/a> repositories that are needed for the simulation are available in my <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/erdalpekel\" target=\"_blank\">GitHub profile<\/a>.<\/p>\n\n\n\n<p>The next part of this series will be about implementing a ROS node that adds these collision objects to the GAZEBO simulation environment so that they can be part of the dynamics of the scene.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post we are going to utilize MoveIt! in order to navigate Panda in a cluttered environment in the Gazebo simulation.<\/p>\n","protected":false},"author":1,"featured_media":193,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10,6,9,5,3,8,7,4],"tags":[17,15,11],"class_list":["post-123","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c","category-gazebo","category-moveit","category-robot-operating-system-ros","category-robotics","category-ros","category-simulation","category-software-development","tag-motion-planning","tag-moveit","tag-ros"],"_links":{"self":[{"href":"https:\/\/erdalpekel.de\/index.php?rest_route=\/wp\/v2\/posts\/123","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/erdalpekel.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/erdalpekel.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/erdalpekel.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/erdalpekel.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=123"}],"version-history":[{"count":17,"href":"https:\/\/erdalpekel.de\/index.php?rest_route=\/wp\/v2\/posts\/123\/revisions"}],"predecessor-version":[{"id":339,"href":"https:\/\/erdalpekel.de\/index.php?rest_route=\/wp\/v2\/posts\/123\/revisions\/339"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/erdalpekel.de\/index.php?rest_route=\/wp\/v2\/media\/193"}],"wp:attachment":[{"href":"https:\/\/erdalpekel.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=123"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/erdalpekel.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=123"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/erdalpekel.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=123"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}