gazebo_ros_moveit_planning_scene.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2013 Open Source Robotics Foundation
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  *
00016 */
00017 /*
00018  * Desc: A plugin which publishes the gazebo world state as a MoveIt! planning scene
00019  * Author: Jonathan Bohren
00020  * Date: 15 May 2014
00021  */
00022 
00023 #include <algorithm>
00024 #include <assert.h>
00025 
00026 #include <boost/bind.hpp>
00027 #include <boost/thread/mutex.hpp>
00028 
00029 #include <gazebo/common/common.hh>
00030 
00031 #include <gazebo_plugins/gazebo_ros_moveit_planning_scene.h>
00032 
00033 namespace gazebo
00034 {
00035 GZ_REGISTER_MODEL_PLUGIN(GazeboRosMoveItPlanningScene);
00036 
00038 // Constructor
00039 GazeboRosMoveItPlanningScene::GazeboRosMoveItPlanningScene()
00040 {
00041 }
00042 
00044 // Destructor
00045 GazeboRosMoveItPlanningScene::~GazeboRosMoveItPlanningScene()
00046 {
00047   event::Events::DisconnectWorldUpdateBegin(this->update_connection_);
00048 
00049   // Custom Callback Queue
00050   this->queue_.clear();
00051   this->queue_.disable();
00052   this->rosnode_->shutdown();
00053   this->callback_queue_thread_.join();
00054 }
00055 
00057 // Load the controller
00058 void GazeboRosMoveItPlanningScene::Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
00059 {
00060   // Get the world name.
00061   this->world_ = _model->GetWorld();
00062 
00063   this->model_name_ = _model->GetName();
00064   
00065   // load parameters
00066   if (_sdf->HasElement("robotNamespace")) {
00067     this->robot_namespace_ = _sdf->GetElement("robotNamespace")->Get<std::string>() + "/";
00068   } else {
00069     this->robot_namespace_ = "";
00070   }
00071 
00072   if (!_sdf->HasElement("robotName")) {
00073     this->robot_name_ = _model->GetName();
00074   } else {
00075     this->robot_name_ = _sdf->GetElement("robotName")->Get<std::string>();
00076   }
00077 
00078   if (!_sdf->HasElement("topicName")) {
00079     this->topic_name_ = "planning_scene";
00080   }  else {
00081     this->topic_name_ = _sdf->GetElement("topicName")->Get<std::string>();
00082   }
00083 
00084   if (!_sdf->HasElement("sceneName")) {
00085     this->scene_name_ = "";
00086   } else {
00087     this->scene_name_ = _sdf->GetElement("sceneName")->Get<std::string>();
00088   }
00089 
00090   if (!_sdf->HasElement("updatePeriod")) {
00091     this->publish_period_ = ros::Duration(0.0);
00092   } else {
00093     this->publish_period_ = ros::Duration(_sdf->GetElement("updatePeriod")->Get<double>());
00094   }
00095 
00096 
00097   // Make sure the ROS node for Gazebo has already been initialized
00098   if (!ros::isInitialized())
00099   {
00100     ROS_FATAL_STREAM("A ROS node for Gazebo has not been initialized, unable to load plugin. "
00101       << "Load the Gazebo system plugin 'libgazebo_ros_api_plugin.so' in the gazebo_ros package)");
00102     return;
00103   }
00104 
00105   this->rosnode_.reset(new ros::NodeHandle(this->robot_namespace_));
00106 
00107   last_publish_time_ = ros::Time(0,0);
00108 
00109   planning_scene_pub_ = this->rosnode_->advertise<moveit_msgs::PlanningScene>(this->topic_name_, 1);
00110 
00111   // Custom Callback Queue
00112   /*
00113    *ros::SubscribeOptions so = ros::SubscribeOptions::create<geometry_msgs::Wrench>(
00114    *  this->topic_name_,1,
00115    *  boost::bind( &GazeboRosMoveItPlanningScene::UpdateObjectForce,this,_1),
00116    *  ros::VoidPtr(), &this->queue_);
00117    *this->sub_ = this->rosnode_->subscribe(so);
00118    */
00119 
00120   // Custom Callback Queue
00121   this->callback_queue_thread_ = boost::thread( boost::bind( &GazeboRosMoveItPlanningScene::QueueThread,this ) );
00122 
00123   // Create service server
00124   ros::AdvertiseServiceOptions aso;
00125   boost::function<bool(std_srvs::Empty::Request&, std_srvs::Empty::Response&)> srv_cb =
00126     boost::bind(&GazeboRosMoveItPlanningScene::PublishPlanningSceneCB, this, _1, _2);
00127   aso.init("publish_planning_scene", srv_cb);
00128   aso.callback_queue = &this->queue_;
00129 
00130   publish_planning_scene_service_ = this->rosnode_->advertiseService(aso);
00131 
00132   // Publish the full scene on the next update
00133   publish_full_scene_ = false;
00134 
00135   // New Mechanism for Updating every World Cycle
00136   // Listen to the update event. This event is broadcast every
00137   // simulation iteration.
00138   this->update_connection_ = event::Events::ConnectWorldUpdateBegin(
00139       boost::bind(&GazeboRosMoveItPlanningScene::UpdateCB, this));
00140 }
00141 
00143 // Manually publish the full planninc scene
00144 bool GazeboRosMoveItPlanningScene::PublishPlanningSceneCB(
00145     std_srvs::Empty::Request& req,
00146     std_srvs::Empty::Response& resp)
00147 {
00148   boost::mutex::scoped_lock lock(this->mutex_);
00149 
00150   // Set flag to re-publish full scene
00151   publish_full_scene_ = true;
00152 
00153   return true;
00154 }
00155 
00157 // Update the controller
00158 void GazeboRosMoveItPlanningScene::UpdateCB()
00159 {
00160   boost::mutex::scoped_lock lock(this->mutex_);
00161 
00162   using namespace gazebo::common;
00163   using namespace gazebo::physics;
00164 
00165   if(!publish_full_scene_) {
00166     if(publish_period_.isZero() || (ros::Time::now() - last_publish_time_) < publish_period_) {
00167       return;
00168     } else {
00169       last_publish_time_ = ros::Time::now();
00170     }
00171   } else {
00172     publish_full_scene_ = false;
00173   }
00174 
00175   // Iterate through the tracked models and clear their dynamic information
00176   // This also sets objects to be removed if they currently aren't in the scene
00177   for(std::map<std::string,moveit_msgs::CollisionObject>::iterator object_it = collision_object_map_.begin();
00178       object_it != collision_object_map_.end();
00179       ++object_it)
00180   {
00181     // Convenience reference
00182     moveit_msgs::CollisionObject &object = object_it->second;
00183 
00184     // Mark for removal unless it's found in the gazebo world
00185     object.operation = moveit_msgs::CollisionObject::REMOVE;
00186 
00187     // Clear shape information
00188     object.primitives.clear();
00189     object.primitive_poses.clear();
00190 
00191     object.meshes.clear();
00192     object.mesh_poses.clear();
00193 
00194     object.planes.clear();
00195     object.plane_poses.clear();
00196   }
00197 
00198   // Iterate over all the models currently in the world
00199   std::vector<ModelPtr> models = this->world_->GetModels();
00200   for(std::vector<ModelPtr>::const_iterator model_it = models.begin();
00201       model_it != models.end();
00202       ++model_it)
00203   {
00204     const ModelPtr &model = *model_it;
00205     const std::string model_name = model->GetName();
00206 
00207     // Don't declare the robot as a collision object
00208     if(model_name == model_name_) { 
00209       continue;
00210     }
00211 
00212     // Check if the gazebo model is already in the collision object map
00213     std::map<std::string, moveit_msgs::CollisionObject>::iterator found_collision_object = 
00214       collision_object_map_.find(model_name);
00215 
00216     // Create a new collision object representing this gazebo model if it's not in the map
00217     if(found_collision_object == collision_object_map_.end()) {
00218       moveit_msgs::CollisionObject new_object;
00219       new_object.id = model_name;
00220       new_object.header.frame_id = "world";
00221       new_object.operation = moveit_msgs::CollisionObject::ADD;
00222 
00223       collision_object_map_[model_name] = new_object;
00224       ROS_DEBUG_STREAM_NAMED("GazeboRosMoveItPlanningScene","Adding object: "<<model_name);
00225     } else {
00226 
00227       collision_object_map_[model_name].operation = moveit_msgs::CollisionObject::MOVE;
00228       ROS_DEBUG_STREAM_NAMED("GazeboRosMoveItPlanningScene","Moving object: "<<model_name);
00229     }
00230 
00231     // Get a reference to the object from the map
00232     moveit_msgs::CollisionObject &object = collision_object_map_[model_name];
00233 
00234     // Iterate over all links in the model, and add collision objects from each one
00235     // This adds meshes and primitives to:
00236     //  object.meshes,
00237     //  object.primitives, and
00238     //  object.planes
00239     std::vector<LinkPtr> links = model->GetLinks(); 
00240     for(std::vector<LinkPtr>::const_iterator link_it = links.begin();
00241         link_it != links.end();
00242         ++link_it)
00243     {
00244       const LinkPtr &link = *link_it;
00245 
00246       gazebo::math::Pose link_pose = link->GetWorldPose();
00247       geometry_msgs::Pose link_pose_msg;
00248       link_pose_msg.position.x = link_pose.pos.x;
00249       link_pose_msg.position.y = link_pose.pos.y;
00250       link_pose_msg.position.z = link_pose.pos.z;
00251       link_pose_msg.orientation.x = link_pose.rot.x;
00252       link_pose_msg.orientation.y = link_pose.rot.y;
00253       link_pose_msg.orientation.z = link_pose.rot.z;
00254       link_pose_msg.orientation.w = link_pose.rot.w;
00255       //ROS_DEBUG_STREAM_NAMED("GazeboRosMoveItPlanningScene",model_name << " (link): " <<link_pose_msg);
00256 
00257       // Get all the collision objects for this link
00258       std::vector<CollisionPtr> collisions = link->GetCollisions();
00259       for(std::vector<CollisionPtr>::const_iterator coll_it = collisions.begin();
00260           coll_it != collisions.end();
00261           ++coll_it)
00262       {
00263         const CollisionPtr &collision = *coll_it;
00264         const ShapePtr shape = collision->GetShape();
00265 
00266         // NOTE: In gazebo 2.2.2 Collision::GetWorldPose() does not work
00267         gazebo::math::Pose collision_pose = collision->GetRelativePose()*link_pose;
00268         geometry_msgs::Pose collision_pose_msg;
00269         collision_pose_msg.position.x = collision_pose.pos.x;
00270         collision_pose_msg.position.y = collision_pose.pos.y;
00271         collision_pose_msg.position.z = collision_pose.pos.z;
00272         collision_pose_msg.orientation.x = collision_pose.rot.x;
00273         collision_pose_msg.orientation.y = collision_pose.rot.y;
00274         collision_pose_msg.orientation.z = collision_pose.rot.z;
00275         collision_pose_msg.orientation.w = collision_pose.rot.w;
00276         //ROS_DEBUG_STREAM_NAMED("GazeboRosMoveItPlanningScene",model_name << " (collision): " <<collision_pose_msg);
00277         
00278         // Always add pose information
00279         if(shape->HasType(Base::MESH_SHAPE)) {
00280           object.mesh_poses.push_back(collision_pose_msg);
00281         } else if(shape->HasType(Base::PLANE_SHAPE)) {
00282           object.plane_poses.push_back(collision_pose_msg);
00283         } else {
00284           object.primitive_poses.push_back(collision_pose_msg);
00285         }
00286 
00287         // Only add geometric info if we haven't published it before
00288         if(object.operation == moveit_msgs::CollisionObject::ADD || object.operation == moveit_msgs::CollisionObject::APPEND) 
00289         {
00290           if(shape->HasType(Base::MESH_SHAPE)) 
00291           {
00292             // Get the mesh structure from the mesh shape
00293             boost::shared_ptr<MeshShape> mesh_shape = boost::dynamic_pointer_cast<MeshShape>(shape);
00294             std::string name = mesh_shape->GetName();
00295             std::string uri = mesh_shape->GetMeshURI();
00296             const Mesh *mesh = MeshManager::Instance()->GetMesh(uri);
00297 
00298             if(!mesh) {
00299               gzwarn << "Shape has mesh type but mesh could not be retried from the MeshManager. Loading ad-hoc!" << std::endl;
00300               gzwarn << " mesh uri: " <<uri<< std::endl;
00301 
00302               // Load the mesh ad-hoc if the manager doesn't have it
00303               // this happens with model:// uris
00304               mesh = MeshManager::Instance()->Load(uri);
00305 
00306               if(!mesh) {
00307                 gzwarn << "Mesh could not be loded: " << uri << std::endl;
00308                 continue;
00309               }
00310             } 
00311 
00312             // Iterate over submeshes
00313             unsigned n_submeshes = mesh->GetSubMeshCount();
00314 
00315             for(unsigned m=0; m < n_submeshes; m++) {
00316 
00317               const SubMesh *submesh = mesh->GetSubMesh(m);
00318               unsigned n_vertices = submesh->GetVertexCount();
00319 
00320               switch(submesh->GetPrimitiveType()) 
00321               {
00322                 case SubMesh::POINTS:
00323                 case SubMesh::LINES:
00324                 case SubMesh::LINESTRIPS:
00325                   // These aren't supported
00326                   break;
00327                 case SubMesh::TRIANGLES:
00328                   {
00329                     //gzwarn<<"TRIANGLES"<<std::endl;
00330                     shape_msgs::Mesh mesh_msg;
00331                     mesh_msg.vertices.resize(n_vertices);
00332                     mesh_msg.triangles.resize(n_vertices/3);
00333 
00334                     for(size_t v=0; v < n_vertices; v++) {
00335 
00336                       const int index = submesh->GetIndex(v);
00337                       const gazebo::math::Vector3 vertex = submesh->GetVertex(v);
00338 
00339                       mesh_msg.vertices[index].x = vertex.x;
00340                       mesh_msg.vertices[index].y = vertex.y;
00341                       mesh_msg.vertices[index].z = vertex.z;
00342 
00343                       mesh_msg.triangles[v/3].vertex_indices[v%3] = index;
00344                     }
00345 
00346                     object.meshes.push_back(mesh_msg);
00347                     break;
00348                   }
00349                 case SubMesh::TRISTRIPS:
00350                   {
00351                     //gzwarn<<"TRISTRIPS"<<std::endl;
00352                     shape_msgs::Mesh mesh_msg;
00353                     mesh_msg.vertices.resize(n_vertices);
00354                     mesh_msg.triangles.resize(n_vertices-2);
00355 
00356                     for(size_t v=0; v < n_vertices; v++) {
00357                       const int index = submesh->GetIndex(v);
00358                       const gazebo::math::Vector3 vertex = submesh->GetVertex(v);
00359 
00360                       mesh_msg.vertices[index].x = vertex.x;
00361                       mesh_msg.vertices[index].y = vertex.y;
00362                       mesh_msg.vertices[index].z = vertex.z;
00363 
00364                       if(v < n_vertices-2) mesh_msg.triangles[v].vertex_indices[0] = index;
00365                       if(v > 0 && v < n_vertices-1) mesh_msg.triangles[v-1].vertex_indices[1] = index;
00366                       if(v > 1) mesh_msg.triangles[v-2].vertex_indices[2] = index;
00367                     }
00368 
00369                     object.meshes.push_back(mesh_msg);
00370                     break;
00371                   }
00372                 case SubMesh::TRIFANS:
00373                   // Unsupported
00374                   gzerr << "TRIFANS not supported yet." << std::endl;
00375                   break;
00376               };
00377             }
00378           } 
00379           else if(shape->HasType(Base::PLANE_SHAPE)) 
00380           {
00381             // Plane
00382             boost::shared_ptr<PlaneShape> plane_shape = boost::dynamic_pointer_cast<PlaneShape>(shape);
00383             shape_msgs::Plane plane_msg;
00384 
00385             plane_msg.coef[0] = plane_shape->GetNormal().x;
00386             plane_msg.coef[1] = plane_shape->GetNormal().y;
00387             plane_msg.coef[2] = plane_shape->GetNormal().z;
00388             plane_msg.coef[3] = 0; // This should be handled by the position of the collision object
00389 
00390             object.planes.push_back(plane_msg);
00391           }
00392           else 
00393           {
00394             // Solid primitive
00395             shape_msgs::SolidPrimitive primitive_msg;
00396 
00397             if(shape->HasType(Base::BOX_SHAPE)) {
00398 
00399               boost::shared_ptr<BoxShape> box_shape = boost::dynamic_pointer_cast<BoxShape>(shape);
00400 
00401               primitive_msg.type = primitive_msg.BOX;
00402               primitive_msg.dimensions.resize(3);
00403               primitive_msg.dimensions[0] = box_shape->GetSize().x;
00404               primitive_msg.dimensions[1] = box_shape->GetSize().y;
00405               primitive_msg.dimensions[2] = box_shape->GetSize().z;
00406 
00407             } else if(shape->HasType(Base::CYLINDER_SHAPE)) {
00408 
00409               boost::shared_ptr<CylinderShape> cylinder_shape = boost::dynamic_pointer_cast<CylinderShape>(shape);
00410 
00411               primitive_msg.type = primitive_msg.CYLINDER;
00412               primitive_msg.dimensions.resize(2);
00413               primitive_msg.dimensions[0] = cylinder_shape->GetLength();
00414               primitive_msg.dimensions[1] = cylinder_shape->GetRadius();
00415 
00416             } else if(shape->HasType(Base::SPHERE_SHAPE)) {
00417 
00418               boost::shared_ptr<SphereShape> sphere_shape = boost::dynamic_pointer_cast<SphereShape>(shape);
00419 
00420               primitive_msg.type = primitive_msg.SPHERE;
00421               primitive_msg.dimensions.resize(1);
00422               primitive_msg.dimensions[0] = sphere_shape->GetRadius();
00423 
00424             } else {
00425               // HEIGHTMAP_SHAPE, MAP_SHAPE, MULTIRAY_SHAPE, RAY_SHAPE   
00426               // Unsupported
00427               continue;
00428             }
00429 
00430             object.primitives.push_back(primitive_msg);
00431           }
00432         }
00433       }
00434     }
00435   }
00436   
00437   // Clear the list of collision objects
00438   planning_scene_msg_.name = scene_name_;
00439   planning_scene_msg_.robot_model_name = robot_name_;
00440   planning_scene_msg_.is_diff = true;
00441   planning_scene_msg_.world.collision_objects.clear();
00442 
00443   // Iterate through the objects we're already tracking
00444   for(std::map<std::string,moveit_msgs::CollisionObject>::iterator object_it = collision_object_map_.begin();
00445       object_it != collision_object_map_.end();)
00446   {
00447     // Add the object to the planning scene message
00448     planning_scene_msg_.world.collision_objects.push_back(object_it->second);
00449     
00450     // Actually remove objects from being tracked
00451     if(object_it->second.operation == moveit_msgs::CollisionObject::REMOVE) {
00452       // Actually remove the collision object from the map
00453       ROS_DEBUG_STREAM_NAMED("GazeboRosMoveItPlanningScene","Removing object: "<<object_it->second.id);
00454       collision_object_map_.erase(object_it++);
00455     } else {
00456       ++object_it;
00457     }
00458 
00459   }
00460 
00461   planning_scene_pub_.publish(planning_scene_msg_);
00462 }
00463 
00464 // Custom Callback Queue
00466 // custom callback queue thread
00467 void GazeboRosMoveItPlanningScene::QueueThread()
00468 {
00469   static const double timeout = 0.01;
00470 
00471   while (this->rosnode_->ok())
00472   {
00473     this->queue_.callAvailable(ros::WallDuration(timeout));
00474   }
00475 }
00476 
00477 }


gazebo_plugins
Author(s): John Hsu
autogenerated on Fri Aug 28 2015 10:47:25