gazebo_ros_moveit_planning_scene.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2013 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17 /*
18  * Desc: A plugin which publishes the gazebo world state as a MoveIt! planning scene
19  * Author: Jonathan Bohren
20  * Date: 15 May 2014
21  */
22 
23 #include <algorithm>
24 #include <assert.h>
25 
26 #include <boost/bind.hpp>
27 #include <boost/thread/mutex.hpp>
28 
29 #include <gazebo/common/common.hh>
30 
32 
33 namespace gazebo
34 {
35 
36 static std::string get_id(const physics::LinkPtr &link) {
37  return link->GetModel()->GetName() + "." + link->GetName();
38 }
39 
41 
43 // Constructor
45 {
46 }
47 
49 // Destructor
51 {
52 #if GAZEBO_MAJOR_VERSION >= 8
53 #else
54  event::Events::DisconnectWorldUpdateBegin(this->update_connection_);
55 #endif
56 
57  // Custom Callback Queue
58  this->queue_.clear();
59  this->queue_.disable();
60  this->rosnode_->shutdown();
61  this->callback_queue_thread_.join();
62 }
63 
65 // Load the controller
66 void GazeboRosMoveItPlanningScene::Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
67 {
68  // Get the world name.
69  this->world_ = _model->GetWorld();
70 
71  this->model_name_ = _model->GetName();
72 
73  // load parameters
74  if (_sdf->HasElement("robotNamespace")) {
75  this->robot_namespace_ = _sdf->GetElement("robotNamespace")->Get<std::string>() + "/";
76  } else {
77  this->robot_namespace_ = "";
78  }
79 
80  if (!_sdf->HasElement("robotName")) {
81  this->robot_name_ = _model->GetName();
82  } else {
83  this->robot_name_ = _sdf->GetElement("robotName")->Get<std::string>();
84  }
85 
86  if (!_sdf->HasElement("topicName")) {
87  this->topic_name_ = "planning_scene";
88  } else {
89  this->topic_name_ = _sdf->GetElement("topicName")->Get<std::string>();
90  }
91 
92  if (!_sdf->HasElement("sceneName")) {
93  this->scene_name_ = "";
94  } else {
95  this->scene_name_ = _sdf->GetElement("sceneName")->Get<std::string>();
96  }
97 
98  if (!_sdf->HasElement("updatePeriod")) {
99  this->publish_period_ = ros::Duration(0.0);
100  } else {
101  this->publish_period_ = ros::Duration(_sdf->GetElement("updatePeriod")->Get<double>());
102  }
103 
104 
105  // Make sure the ROS node for Gazebo has already been initialized
106  if (!ros::isInitialized())
107  {
108  ROS_FATAL_STREAM("A ROS node for Gazebo has not been initialized, unable to load plugin. "
109  << "Load the Gazebo system plugin 'libgazebo_ros_api_plugin.so' in the gazebo_ros package)");
110  return;
111  }
112 
113  this->rosnode_.reset(new ros::NodeHandle(this->robot_namespace_));
114 
116 
117  planning_scene_pub_ = this->rosnode_->advertise<moveit_msgs::PlanningScene>(
118  this->topic_name_, 1,
120 
121  // Custom Callback Queue for service
122  this->callback_queue_thread_ = boost::thread(
123  boost::bind(&GazeboRosMoveItPlanningScene::QueueThread, this));
124 
125  // Create service server
127  boost::function<bool(std_srvs::Empty::Request&, std_srvs::Empty::Response&)> srv_cb =
128  boost::bind(&GazeboRosMoveItPlanningScene::PublishPlanningSceneCB, this, _1, _2);
129  aso.init("publish_planning_scene", srv_cb);
130  aso.callback_queue = &this->queue_;
131 
132  publish_planning_scene_service_ = this->rosnode_->advertiseService(aso);
133 
134  // Publish the full scene on the next update
135  publish_full_scene_ = true;
136 
137  // New Mechanism for Updating every World Cycle
138  // Listen to the update event. This event is broadcast every
139  // simulation iteration.
140  this->update_connection_ = event::Events::ConnectWorldUpdateBegin(
141  boost::bind(&GazeboRosMoveItPlanningScene::UpdateCB, this));
142 }
143 
145 {
146  boost::mutex::scoped_lock lock(this->mutex_);
147  publish_full_scene_ = true;
148 }
149 
151 // Manually publish the full planninc scene
153  std_srvs::Empty::Request& req,
154  std_srvs::Empty::Response& resp)
155 {
156  boost::mutex::scoped_lock lock(this->mutex_);
157 
158  // Set flag to re-publish full scene
159  publish_full_scene_ = true;
160 
161  return true;
162 }
163 
165 // Update the controller
167 {
168  boost::mutex::scoped_lock lock(this->mutex_);
169 
170  using namespace gazebo::common;
171  using namespace gazebo::physics;
172 
173  if(!publish_full_scene_) {
175  return;
176  } else {
178  }
179  }
180 
181  // Iterate through the tracked models and clear their dynamic information
182  // This also sets objects to be removed if they currently aren't in the scene
183  for(std::map<std::string,moveit_msgs::CollisionObject>::iterator object_it = collision_object_map_.begin();
184  object_it != collision_object_map_.end();
185  ++object_it)
186  {
187  // Convenience reference
188  moveit_msgs::CollisionObject &object = object_it->second;
189 
190  // Mark for removal unless it's found in the gazebo world
191  object.operation = moveit_msgs::CollisionObject::REMOVE;
192 
193  // Clear shape information
194  object.primitives.clear();
195  object.primitive_poses.clear();
196 
197  object.meshes.clear();
198  object.mesh_poses.clear();
199 
200  object.planes.clear();
201  object.plane_poses.clear();
202  }
203 
204  // Iterate over all the models currently in the world
205 #if GAZEBO_MAJOR_VERSION >= 8
206  std::vector<ModelPtr> models = this->world_->Models();
207 #else
208  std::vector<ModelPtr> models = this->world_->GetModels();
209 #endif
210  for(std::vector<ModelPtr>::const_iterator model_it = models.begin();
211  model_it != models.end();
212  ++model_it)
213  {
214  const ModelPtr &model = *model_it;
215  const std::string model_name = model->GetName();
216 
217  // Don't declare collision objects for the robot links
218  if(model_name == model_name_) {
219  continue;
220  }
221 
222  // Iterate over all links in the model, and add collision objects from each one
223  // This adds meshes and primitives to:
224  // object.meshes,
225  // object.primitives, and
226  // object.planes
227  std::vector<LinkPtr> links = model->GetLinks();
228  for(std::vector<LinkPtr>::const_iterator link_it = links.begin();
229  link_it != links.end();
230  ++link_it)
231  {
232  const LinkPtr &link = *link_it;
233  const std::string id = get_id(link);
234 
235  // Check if the gazebo model is already in the collision object map
236  std::map<std::string, moveit_msgs::CollisionObject>::iterator found_collision_object =
237  collision_object_map_.find(id);
238 
239  // Create a new collision object representing this link if it's not in the map
240  if(found_collision_object == collision_object_map_.end() || publish_full_scene_){
241 
242  ROS_INFO("Creating collision object for model %s, this=%s, objects=%u",
243  model_name.c_str(),
244  model_name_.c_str(),
245  (unsigned int)collision_object_map_.size());
246 
247  moveit_msgs::CollisionObject new_object;
248  new_object.id = id;
249  new_object.header.frame_id = "world";
250  new_object.operation = moveit_msgs::CollisionObject::ADD;
251 
252  collision_object_map_[id] = new_object;
253  ROS_DEBUG_STREAM_NAMED("GazeboRosMoveItPlanningScene","Adding object: "<<id);
254  } else {
255  collision_object_map_[id].operation = moveit_msgs::CollisionObject::MOVE;
256  ROS_DEBUG_STREAM_NAMED("GazeboRosMoveItPlanningScene","Moving object: "<<id);
257  }
258 
259  // Get a reference to the object from the map
260  moveit_msgs::CollisionObject &object = collision_object_map_[id];
261 
262 #if GAZEBO_MAJOR_VERSION >= 8
263  ignition::math::Pose3d link_pose = link->WorldPose();
264 #else
265  ignition::math::Pose3d link_pose = link->GetWorldPose().Ign();
266 #endif
267  geometry_msgs::Pose link_pose_msg;
268  link_pose_msg.position.x = link_pose.Pos().X();
269  link_pose_msg.position.y = link_pose.Pos().Y();
270  link_pose_msg.position.z = link_pose.Pos().Z();
271  link_pose_msg.orientation.x = link_pose.Rot().X();
272  link_pose_msg.orientation.y = link_pose.Rot().Y();
273  link_pose_msg.orientation.z = link_pose.Rot().Z();
274  link_pose_msg.orientation.w = link_pose.Rot().W();
275  //ROS_DEBUG_STREAM_NAMED("GazeboRosMoveItPlanningScene",model_name << " (link): " <<link_pose_msg);
276 
277  // Get all the collision objects for this link
278  std::vector<CollisionPtr> collisions = link->GetCollisions();
279  for(std::vector<CollisionPtr>::const_iterator coll_it = collisions.begin();
280  coll_it != collisions.end();
281  ++coll_it)
282  {
283  const CollisionPtr &collision = *coll_it;
284  const ShapePtr shape = collision->GetShape();
285 
286  // NOTE: In gazebo 2.2.2 Collision::GetWorldPose() does not work
287 #if GAZEBO_MAJOR_VERSION >= 8
288  ignition::math::Pose3d collision_pose = collision->InitialRelativePose() + link_pose;
289 #else
290  ignition::math::Pose3d collision_pose = collision->GetInitialRelativePose().Ign() + link_pose;
291 #endif
292  geometry_msgs::Pose collision_pose_msg;
293  collision_pose_msg.position.x = collision_pose.Pos().X();
294  collision_pose_msg.position.y = collision_pose.Pos().Y();
295  collision_pose_msg.position.z = collision_pose.Pos().Z();
296  collision_pose_msg.orientation.x = collision_pose.Rot().X();
297  collision_pose_msg.orientation.y = collision_pose.Rot().Y();
298  collision_pose_msg.orientation.z = collision_pose.Rot().Z();
299  collision_pose_msg.orientation.w = collision_pose.Rot().W();
300  //ROS_DEBUG_STREAM_NAMED("GazeboRosMoveItPlanningScene",model_name << " (collision): " <<collision_pose_msg);
301 
302  // Always add pose information
303  if(shape->HasType(Base::MESH_SHAPE)) {
304  //object.mesh_poses.push_back(collision_pose_msg);
305  boost::shared_ptr<MeshShape> mesh_shape = boost::dynamic_pointer_cast<MeshShape>(shape);
306  std::string uri = mesh_shape->GetMeshURI();
307  const Mesh *mesh = MeshManager::Instance()->GetMesh(uri);
308  if(!mesh) {
309  gzwarn << "Shape has mesh type but mesh could not be retried from the MeshManager. Loading ad-hoc!" << std::endl;
310  gzwarn << " mesh uri: " <<uri<< std::endl;
311 
312  // Load the mesh ad-hoc if the manager doesn't have it
313  // this happens with model:// uris
314  mesh = MeshManager::Instance()->Load(uri);
315 
316  if(!mesh) {
317  gzwarn << "Mesh could not be loded: " << uri << std::endl;
318  continue;
319  }
320  }
321 
322  // Iterate over submeshes
323  unsigned n_submeshes = mesh->GetSubMeshCount();
324 
325  for(unsigned m=0; m < n_submeshes; m++) {
326 
327  const SubMesh *submesh = mesh->GetSubMesh(m);
328  unsigned n_vertices = submesh->GetVertexCount();
329 
330  switch(submesh->GetPrimitiveType())
331  {
332  case SubMesh::POINTS:
333  case SubMesh::LINES:
334  case SubMesh::LINESTRIPS:
335  // These aren't supported
336  break;
337  case SubMesh::TRIANGLES:
338  case SubMesh::TRISTRIPS:
339  object.mesh_poses.push_back(collision_pose_msg);
340  break;
341  case SubMesh::TRIFANS:
342  // Unsupported
343  gzerr << "TRIFANS not supported yet." << std::endl;
344  break;
345  };
346  }
347  } else if(shape->HasType(Base::PLANE_SHAPE)) {
348  object.plane_poses.push_back(collision_pose_msg);
349  } else { //if (!shape->HasType(Base::MESH_SHAPE)) {
350  object.primitive_poses.push_back(collision_pose_msg);
351  }
352 
353  // Only add geometric info if we haven't published it before
354  if(object.operation == moveit_msgs::CollisionObject::ADD || object.operation == moveit_msgs::CollisionObject::APPEND)
355  {
356  if(shape->HasType(Base::MESH_SHAPE))
357  {
358  // Get the mesh structure from the mesh shape
359  boost::shared_ptr<MeshShape> mesh_shape = boost::dynamic_pointer_cast<MeshShape>(shape);
360  std::string name = mesh_shape->GetName();
361  std::string uri = mesh_shape->GetMeshURI();
362 #if GAZEBO_MAJOR_VERSION >= 8
363  ignition::math::Vector3d scale = mesh_shape->Scale();
364 #else
365  ignition::math::Vector3d scale = mesh_shape->GetScale().Ign();
366 #endif
367  const Mesh *mesh = MeshManager::Instance()->GetMesh(uri);
368 
369  gzwarn << " mesh scale: " <<scale<< std::endl;
370  if(!mesh) {
371  gzwarn << "Shape has mesh type but mesh could not be retried from the MeshManager. Loading ad-hoc!" << std::endl;
372  gzwarn << " mesh uri: " <<uri<< std::endl;
373 
374  // Load the mesh ad-hoc if the manager doesn't have it
375  // this happens with model:// uris
376  mesh = MeshManager::Instance()->Load(uri);
377 
378  if(!mesh) {
379  gzwarn << "Mesh could not be loded: " << uri << std::endl;
380  continue;
381  }
382  }
383 
384  // Iterate over submeshes
385  unsigned n_submeshes = mesh->GetSubMeshCount();
386 
387  for(unsigned m=0; m < n_submeshes; m++) {
388 
389  const SubMesh *submesh = mesh->GetSubMesh(m);
390  unsigned n_vertices = submesh->GetVertexCount();
391 
392  switch(submesh->GetPrimitiveType())
393  {
394  case SubMesh::POINTS:
395  case SubMesh::LINES:
396  case SubMesh::LINESTRIPS:
397  // These aren't supported
398  break;
399  case SubMesh::TRIANGLES:
400  {
401  //gzwarn<<"TRIANGLES"<<std::endl;
402  shape_msgs::Mesh mesh_msg;
403  mesh_msg.vertices.resize(n_vertices);
404  mesh_msg.triangles.resize(n_vertices/3);
405 
406  for(size_t v=0; v < n_vertices; v++) {
407 
408  const int index = submesh->GetIndex(v);
409  const ignition::math::Vector3d vertex = submesh->Vertex(v);
410 
411  mesh_msg.vertices[index].x = vertex.X() * scale.X();
412  mesh_msg.vertices[index].y = vertex.Y() * scale.Y();
413  mesh_msg.vertices[index].z = vertex.Z() * scale.Z();
414 
415  mesh_msg.triangles[v/3].vertex_indices[v%3] = index;
416  }
417 
418  object.meshes.push_back(mesh_msg);
419  //object.mesh_poses.push_back(collision_pose_msg);
420  break;
421  }
422  case SubMesh::TRISTRIPS:
423  {
424  //gzwarn<<"TRISTRIPS"<<std::endl;
425  shape_msgs::Mesh mesh_msg;
426  mesh_msg.vertices.resize(n_vertices);
427  mesh_msg.triangles.resize(n_vertices-2);
428 
429  for(size_t v=0; v < n_vertices; v++) {
430  const int index = submesh->GetIndex(v);
431  const ignition::math::Vector3d vertex = submesh->Vertex(v);
432 
433  mesh_msg.vertices[index].x = vertex.X() * scale.X();
434  mesh_msg.vertices[index].y = vertex.Y() * scale.Y();
435  mesh_msg.vertices[index].z = vertex.Z() * scale.Z();
436 
437  if(v < n_vertices-2) mesh_msg.triangles[v].vertex_indices[0] = index;
438  if(v > 0 && v < n_vertices-1) mesh_msg.triangles[v-1].vertex_indices[1] = index;
439  if(v > 1) mesh_msg.triangles[v-2].vertex_indices[2] = index;
440  }
441 
442  object.meshes.push_back(mesh_msg);
443  //object.mesh_poses.push_back(collision_pose_msg);
444  break;
445  }
446  case SubMesh::TRIFANS:
447  // Unsupported
448  gzerr << "TRIFANS not supported yet." << std::endl;
449  break;
450  };
451  }
452  }
453  else if(shape->HasType(Base::PLANE_SHAPE))
454  {
455  // Plane
456  boost::shared_ptr<PlaneShape> plane_shape = boost::dynamic_pointer_cast<PlaneShape>(shape);
457  shape_msgs::Plane plane_msg;
458 
459 #if GAZEBO_MAJOR_VERSION >= 8
460  plane_msg.coef[0] = plane_shape->Normal().X();
461  plane_msg.coef[1] = plane_shape->Normal().Y();
462  plane_msg.coef[2] = plane_shape->Normal().Z();
463 #else
464  plane_msg.coef[0] = plane_shape->GetNormal().Ign().X();
465  plane_msg.coef[1] = plane_shape->GetNormal().Ign().Y();
466  plane_msg.coef[2] = plane_shape->GetNormal().Ign().Z();
467 #endif
468  plane_msg.coef[3] = 0; // This should be handled by the position of the collision object
469 
470  object.planes.push_back(plane_msg);
471  }
472  else
473  {
474  // Solid primitive
475  shape_msgs::SolidPrimitive primitive_msg;
476 
477  if(shape->HasType(Base::BOX_SHAPE)) {
478 
479  boost::shared_ptr<BoxShape> box_shape = boost::dynamic_pointer_cast<BoxShape>(shape);
480 
481  primitive_msg.type = primitive_msg.BOX;
482  primitive_msg.dimensions.resize(3);
483 #if GAZEBO_MAJOR_VERSION >= 8
484  primitive_msg.dimensions[0] = box_shape->Size().X();
485  primitive_msg.dimensions[1] = box_shape->Size().Y();
486  primitive_msg.dimensions[2] = box_shape->Size().Z();
487 #else
488  primitive_msg.dimensions[0] = box_shape->GetSize().Ign().X();
489  primitive_msg.dimensions[1] = box_shape->GetSize().Ign().Y();
490  primitive_msg.dimensions[2] = box_shape->GetSize().Ign().Z();
491 #endif
492  } else if(shape->HasType(Base::CYLINDER_SHAPE)) {
493 
494  boost::shared_ptr<CylinderShape> cylinder_shape = boost::dynamic_pointer_cast<CylinderShape>(shape);
495 
496  primitive_msg.type = primitive_msg.CYLINDER;
497  primitive_msg.dimensions.resize(2);
498  primitive_msg.dimensions[0] = cylinder_shape->GetLength();
499  primitive_msg.dimensions[1] = cylinder_shape->GetRadius();
500 
501  } else if(shape->HasType(Base::SPHERE_SHAPE)) {
502 
503  boost::shared_ptr<SphereShape> sphere_shape = boost::dynamic_pointer_cast<SphereShape>(shape);
504 
505  primitive_msg.type = primitive_msg.SPHERE;
506  primitive_msg.dimensions.resize(1);
507  primitive_msg.dimensions[0] = sphere_shape->GetRadius();
508 
509  } else {
510  // HEIGHTMAP_SHAPE, MAP_SHAPE, MULTIRAY_SHAPE, RAY_SHAPE
511  // Unsupported
512  continue;
513  }
514 
515  object.primitives.push_back(primitive_msg);
516  }
517  ROS_INFO("model %s has %zu links",model_name.c_str(),links.size());
518  ROS_INFO("model %s has %zu meshes, %zu mesh poses",
519  model_name.c_str(),
520  object.meshes.size(),
521  object.mesh_poses.size());
522  }
523  }
524  }
525  }
526 
527  // Clear the list of collision objects
529  planning_scene_msg_.robot_model_name = robot_name_;
530  planning_scene_msg_.is_diff = true;
531  planning_scene_msg_.world.collision_objects.clear();
532 
533  // Iterate through the objects we're already tracking
534  for(std::map<std::string,moveit_msgs::CollisionObject>::iterator object_it = collision_object_map_.begin();
535  object_it != collision_object_map_.end();)
536  {
537  // Update stamp
538  object_it->second.header.stamp = ros::Time::now();
539  // Add the object to the planning scene message
540  planning_scene_msg_.world.collision_objects.push_back(object_it->second);
541 
542  // Actually remove objects from being tracked
543  if(object_it->second.operation == moveit_msgs::CollisionObject::REMOVE) {
544  // Actually remove the collision object from the map
545  ROS_DEBUG_STREAM_NAMED("GazeboRosMoveItPlanningScene","Removing object: "<<object_it->second.id);
546  collision_object_map_.erase(object_it++);
547  } else {
548  ++object_it;
549  }
550 
551  }
552 
554 
555  // no more full scene
556  publish_full_scene_ = false;
557 }
558 
559 // Custom Callback Queue
561 // custom callback queue thread
563 {
564  static const double timeout = 0.01;
565 
566  while (this->rosnode_->ok())
567  {
568  this->queue_.callAvailable(ros::WallDuration(timeout));
569  }
570 }
571 
572 }
CallbackQueueInterface * callback_queue
static std::string get_id(const physics::LinkPtr &link)
void init(const std::string &_service, const boost::function< bool(MReq &, MRes &)> &_callback)
#define ROS_DEBUG_STREAM_NAMED(name, args)
void publish(const boost::shared_ptr< M > &message) const
ROSCPP_DECL bool isInitialized()
bool PublishPlanningSceneCB(std_srvs::Empty::Request &req, std_srvs::Empty::Response &resp)
publish the complete planning scene
moveit_msgs::PlanningScene planning_scene_msg_
Container for the planning scene.
boost::mutex mutex_
A mutex to lock access to fields that are used in ROS message callbacks.
physics::WorldPtr world_
A pointer to the gazebo world.
GZ_REGISTER_MODEL_PLUGIN(GazeboRosF3D)
std::string robot_namespace_
for setting ROS name space
#define ROS_FATAL_STREAM(args)
std::string scene_name_
The MoveIt scene name.
std::string topic_name_
ROS topic name inputs.
#define ROS_INFO(...)
void QueueThread()
The custom callback queue thread function.
boost::scoped_ptr< ros::NodeHandle > rosnode_
A pointer to the ROS node. A node will be instantiated if it does not exist.
std::map< std::string, moveit_msgs::CollisionObject > collision_object_map_
static Time now()
void Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
boost::thread callback_queue_thread_
Thead object for the running callback Thread.


gazebo_plugins
Author(s): John Hsu
autogenerated on Tue Apr 6 2021 02:19:39