moveit2
The MoveIt Motion Planning Framework for ROS 2.
planning_scene.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2011, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Ioan Sucan */
36 
37 #include <boost/algorithm/string.hpp>
41 #include <geometric_shapes/shape_operations.h>
48 #include <octomap_msgs/conversions.h>
49 #include <rclcpp/logger.hpp>
50 #include <rclcpp/logging.hpp>
51 #include <tf2_eigen/tf2_eigen.hpp>
52 #include <memory>
53 #include <set>
54 
55 namespace planning_scene
56 {
57 static const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit_planning_scene.planning_scene");
58 
59 const std::string PlanningScene::OCTOMAP_NS = "<octomap>";
60 const std::string PlanningScene::DEFAULT_SCENE_NAME = "(noname)";
61 
62 namespace utilities
63 {
69 void poseMsgToEigen(const geometry_msgs::msg::Pose& msg, Eigen::Isometry3d& out)
70 {
71  Eigen::Translation3d translation(msg.position.x, msg.position.y, msg.position.z);
72  Eigen::Quaterniond quaternion(msg.orientation.w, msg.orientation.x, msg.orientation.y, msg.orientation.z);
73  quaternion.normalize();
74  out = translation * quaternion;
75 }
76 
78 bool readPoseFromText(std::istream& in, Eigen::Isometry3d& pose)
79 {
80  double x, y, z, rx, ry, rz, rw;
81  if (!(in >> x >> y >> z))
82  {
83  RCLCPP_ERROR(LOGGER, "Improperly formatted translation in scene geometry file");
84  return false;
85  }
86  if (!(in >> rx >> ry >> rz >> rw))
87  {
88  RCLCPP_ERROR(LOGGER, "Improperly formatted rotation in scene geometry file");
89  return false;
90  }
91  pose = Eigen::Translation3d(x, y, z) * Eigen::Quaterniond(rw, rx, ry, rz);
92  return true;
93 }
94 
96 void writePoseToText(std::ostream& out, const Eigen::Isometry3d& pose)
97 {
98  out << pose.translation().x() << ' ' << pose.translation().y() << ' ' << pose.translation().z() << '\n';
99  Eigen::Quaterniond r(pose.linear());
100  out << r.x() << ' ' << r.y() << ' ' << r.z() << ' ' << r.w() << '\n';
101 }
102 } // namespace utilities
103 
105 {
106 public:
107  SceneTransforms(const PlanningScene* scene) : Transforms(scene->getRobotModel()->getModelFrame()), scene_(scene)
108  {
109  }
110 
111  bool canTransform(const std::string& from_frame) const override
112  {
113  return scene_->knowsFrameTransform(from_frame);
114  }
115 
116  bool isFixedFrame(const std::string& frame) const override
117  {
118  if (frame.empty())
119  return false;
120  if (Transforms::isFixedFrame(frame))
121  return true;
122  if (frame[0] == '/')
123  {
124  return knowsObjectFrame(frame.substr(1));
125  }
126  else
127  {
128  return knowsObjectFrame(frame);
129  }
130  }
131 
132  const Eigen::Isometry3d& getTransform(const std::string& from_frame) const override
133  { // the call below also calls Transforms::getTransform() too
134  return scene_->getFrameTransform(from_frame);
135  }
136 
137 private:
138  // Returns true if frame_id is the name of an object or the name of a subframe on an object
139  bool knowsObjectFrame(const std::string& frame_id) const
140  {
141  return scene_->getWorld()->knowsTransform(frame_id);
142  }
143 
144  const PlanningScene* scene_;
145 };
146 
147 PlanningScene::PlanningScene(const moveit::core::RobotModelConstPtr& robot_model,
148  const collision_detection::WorldPtr& world)
149 
150  : robot_model_(robot_model), world_(world), world_const_(world)
151 {
152  initialize();
153 }
154 
155 PlanningScene::PlanningScene(const urdf::ModelInterfaceSharedPtr& urdf_model,
156  const srdf::ModelConstSharedPtr& srdf_model, const collision_detection::WorldPtr& world)
157  : world_(world), world_const_(world)
158 {
159  if (!urdf_model)
160  throw moveit::ConstructException("The URDF model cannot be nullptr");
161 
162  if (!srdf_model)
163  throw moveit::ConstructException("The SRDF model cannot be nullptr");
164 
165  robot_model_ = std::make_shared<moveit::core::RobotModel>(urdf_model, srdf_model);
166  if (!robot_model_ || !robot_model_->getRootJoint())
167  {
168  robot_model_ = nullptr;
169  throw moveit::ConstructException("Could not create RobotModel");
170  }
171 
172  initialize();
173 }
174 
176 {
177  if (current_world_object_update_callback_)
178  world_->removeObserver(current_world_object_update_observer_handle_);
179 }
180 
181 void PlanningScene::initialize()
182 {
183  name_ = DEFAULT_SCENE_NAME;
184 
185  scene_transforms_ = std::make_shared<SceneTransforms>(this);
186 
187  robot_state_ = std::make_shared<moveit::core::RobotState>(robot_model_);
188  robot_state_->setToDefaultValues();
189  robot_state_->update();
190 
191  acm_ = std::make_shared<collision_detection::AllowedCollisionMatrix>(*getRobotModel()->getSRDF());
192 
194 }
195 
196 PlanningScene::PlanningScene(const PlanningSceneConstPtr& parent) : parent_(parent)
197 {
198  if (!parent_)
199  throw moveit::ConstructException("nullptr parent pointer for planning scene");
200 
201  if (!parent_->getName().empty())
202  name_ = parent_->getName() + "+";
203 
204  robot_model_ = parent_->robot_model_;
205 
206  // maintain a separate world. Copy on write ensures that most of the object
207  // info is shared until it is modified.
208  world_ = std::make_shared<collision_detection::World>(*parent_->world_);
209  world_const_ = world_;
210 
211  // record changes to the world
212  world_diff_ = std::make_shared<collision_detection::WorldDiff>(world_);
213 
214  allocateCollisionDetector(parent_->collision_detector_->alloc_, parent_->collision_detector_);
215  collision_detector_->copyPadding(*parent_->collision_detector_);
216 }
217 
218 PlanningScenePtr PlanningScene::clone(const PlanningSceneConstPtr& scene)
219 {
220  PlanningScenePtr result = scene->diff();
221  result->decoupleParent();
222  result->setName(scene->getName());
223  return result;
224 }
225 
226 PlanningScenePtr PlanningScene::diff() const
227 {
228  return PlanningScenePtr(new PlanningScene(shared_from_this()));
229 }
230 
231 PlanningScenePtr PlanningScene::diff(const moveit_msgs::msg::PlanningScene& msg) const
232 {
233  PlanningScenePtr result = diff();
234  result->setPlanningSceneDiffMsg(msg);
235  return result;
236 }
237 
238 void PlanningScene::CollisionDetector::copyPadding(const PlanningScene::CollisionDetector& src)
239 {
240  cenv_->setLinkPadding(src.getCollisionEnv()->getLinkPadding());
241  cenv_->setLinkScale(src.getCollisionEnv()->getLinkScale());
242 }
243 
244 void PlanningScene::allocateCollisionDetector(const collision_detection::CollisionDetectorAllocatorPtr& allocator,
245  const CollisionDetectorPtr& parent_detector)
246 {
247  // Temporarily keep pointer to the previous (if any) collision detector to copy padding from
248  CollisionDetectorPtr prev_coll_detector = collision_detector_;
249 
250  // Construct a fresh CollisionDetector and store allocator
251  collision_detector_ = std::make_shared<CollisionDetector>();
252  collision_detector_->alloc_ = allocator;
253 
254  // If parent_detector is specified, copy-construct collision environments (copies link shapes and attached objects)
255  // Otherwise, construct new collision environment from world and robot model
256  if (parent_detector)
257  {
258  collision_detector_->cenv_ = collision_detector_->alloc_->allocateEnv(parent_detector->cenv_, world_);
259  collision_detector_->cenv_unpadded_ =
260  collision_detector_->alloc_->allocateEnv(parent_detector->cenv_unpadded_, world_);
261  }
262  else
263  {
264  collision_detector_->cenv_ = collision_detector_->alloc_->allocateEnv(world_, getRobotModel());
265  collision_detector_->cenv_unpadded_ = collision_detector_->alloc_->allocateEnv(world_, getRobotModel());
266 
267  // Copy padding to collision_detector_->cenv_
268  if (prev_coll_detector)
269  collision_detector_->copyPadding(*prev_coll_detector);
270  }
271 
272  // Assign const pointers
273  collision_detector_->cenv_const_ = collision_detector_->cenv_;
274  collision_detector_->cenv_unpadded_const_ = collision_detector_->cenv_unpadded_;
275 }
276 
277 const collision_detection::CollisionEnvConstPtr&
278 PlanningScene::getCollisionEnv(const std::string& collision_detector_name) const
279 {
280  if (collision_detector_name != getCollisionDetectorName())
281  {
282  RCLCPP_ERROR(LOGGER, "Could not get CollisionRobot named '%s'. Returning active CollisionRobot '%s' instead",
283  collision_detector_name.c_str(), collision_detector_->alloc_->getName().c_str());
284  return collision_detector_->getCollisionEnv();
285  }
286 
287  return collision_detector_->getCollisionEnv();
288 }
289 
290 const collision_detection::CollisionEnvConstPtr&
291 PlanningScene::getCollisionEnvUnpadded(const std::string& collision_detector_name) const
292 {
293  if (collision_detector_name != getCollisionDetectorName())
294  {
295  RCLCPP_ERROR(LOGGER,
296  "Could not get CollisionRobotUnpadded named '%s'. "
297  "Returning active CollisionRobotUnpadded '%s' instead",
298  collision_detector_name.c_str(), collision_detector_->alloc_->getName().c_str());
299  return collision_detector_->getCollisionEnvUnpadded();
300  }
301 
302  return collision_detector_->getCollisionEnvUnpadded();
303 }
304 
306 {
307  if (!parent_)
308  return;
309 
310  // clear everything, reset the world, record diffs
311  world_ = std::make_shared<collision_detection::World>(*parent_->world_);
312  world_const_ = world_;
313  world_diff_ = std::make_shared<collision_detection::WorldDiff>(world_);
314  if (current_world_object_update_callback_)
315  current_world_object_update_observer_handle_ = world_->addObserver(current_world_object_update_callback_);
316 
317  // Reset collision detector to the the parent's version
318  allocateCollisionDetector(parent_->collision_detector_->alloc_, parent_->collision_detector_);
319 
320  scene_transforms_.reset();
321  robot_state_.reset();
322  acm_.reset();
323  object_colors_.reset();
324  object_types_.reset();
325 }
326 
327 void PlanningScene::pushDiffs(const PlanningScenePtr& scene)
328 {
329  if (!parent_)
330  return;
331 
332  if (scene_transforms_)
333  scene->getTransformsNonConst().setAllTransforms(scene_transforms_->getAllTransforms());
334 
335  if (robot_state_)
336  {
337  scene->getCurrentStateNonConst() = *robot_state_;
338  // push colors and types for attached objects
339  std::vector<const moveit::core::AttachedBody*> attached_objs;
340  robot_state_->getAttachedBodies(attached_objs);
341  for (const moveit::core::AttachedBody* attached_obj : attached_objs)
342  {
343  if (hasObjectType(attached_obj->getName()))
344  scene->setObjectType(attached_obj->getName(), getObjectType(attached_obj->getName()));
345  if (hasObjectColor(attached_obj->getName()))
346  scene->setObjectColor(attached_obj->getName(), getObjectColor(attached_obj->getName()));
347  }
348  }
349 
350  if (acm_)
351  scene->getAllowedCollisionMatrixNonConst() = *acm_;
352 
353  collision_detection::CollisionEnvPtr active_cenv = scene->getCollisionEnvNonConst();
354  active_cenv->setLinkPadding(collision_detector_->cenv_->getLinkPadding());
355  active_cenv->setLinkScale(collision_detector_->cenv_->getLinkScale());
356 
357  if (world_diff_)
358  {
359  for (const std::pair<const std::string, collision_detection::World::Action>& it : *world_diff_)
360  {
361  if (it.second == collision_detection::World::DESTROY)
362  {
363  scene->world_->removeObject(it.first);
364  scene->removeObjectColor(it.first);
365  scene->removeObjectType(it.first);
366  }
367  else
368  {
369  const collision_detection::World::Object& obj = *world_->getObject(it.first);
370  scene->world_->removeObject(obj.id_);
371  scene->world_->addToObject(obj.id_, obj.pose_, obj.shapes_, obj.shape_poses_);
372  if (hasObjectColor(it.first))
373  scene->setObjectColor(it.first, getObjectColor(it.first));
374  if (hasObjectType(it.first))
375  scene->setObjectType(it.first, getObjectType(it.first));
376 
377  scene->world_->setSubframesOfObject(obj.id_, obj.subframe_poses_);
378  }
379  }
380  }
381 }
382 
385 {
386  if (getCurrentState().dirtyCollisionBodyTransforms())
387  {
389  }
390  else
391  {
392  checkCollision(req, res, getCurrentState());
393  }
394 }
395 
398  const moveit::core::RobotState& robot_state) const
399 {
400  checkCollision(req, res, robot_state, getAllowedCollisionMatrix());
401 }
402 
405 {
406  if (getCurrentState().dirtyCollisionBodyTransforms())
407  {
409  }
410  else
411  {
412  checkSelfCollision(req, res, getCurrentState());
413  }
414 }
415 
418  const moveit::core::RobotState& robot_state,
420 {
421  // check collision with the world using the padded version
422  getCollisionEnv()->checkRobotCollision(req, res, robot_state, acm);
423 
424  // do self-collision checking with the unpadded version of the robot
425  if (!res.collision || (req.contacts && res.contacts.size() < req.max_contacts))
426  getCollisionEnvUnpadded()->checkSelfCollision(req, res, robot_state, acm);
427 }
428 
431 {
432  if (getCurrentState().dirtyCollisionBodyTransforms())
433  {
435  }
436  else
437  {
439  }
440 }
441 
444  const moveit::core::RobotState& robot_state,
446 {
447  // check collision with the world using the unpadded version
448  getCollisionEnvUnpadded()->checkRobotCollision(req, res, robot_state, acm);
449 
450  // do self-collision checking with the unpadded version of the robot
451  if (!res.collision || (req.contacts && res.contacts.size() < req.max_contacts))
452  {
453  getCollisionEnvUnpadded()->checkSelfCollision(req, res, robot_state, acm);
454  }
455 }
456 
458 {
459  if (getCurrentState().dirtyCollisionBodyTransforms())
460  {
462  }
463  else
464  {
466  }
467 }
468 
470  const moveit::core::RobotState& robot_state,
472  const std::string& group_name) const
473 {
475  req.contacts = true;
476  req.max_contacts = getRobotModel()->getLinkModelsWithCollisionGeometry().size() + 1;
477  req.max_contacts_per_pair = 1;
478  req.group_name = group_name;
480  checkCollision(req, res, robot_state, acm);
481  res.contacts.swap(contacts);
482 }
483 
484 void PlanningScene::getCollidingLinks(std::vector<std::string>& links)
485 {
486  if (getCurrentState().dirtyCollisionBodyTransforms())
487  {
489  }
490  else
491  {
493  }
494 }
495 
496 void PlanningScene::getCollidingLinks(std::vector<std::string>& links, const moveit::core::RobotState& robot_state,
498 {
500  getCollidingPairs(contacts, robot_state, acm);
501  links.clear();
502  for (collision_detection::CollisionResult::ContactMap::const_iterator it = contacts.begin(); it != contacts.end();
503  ++it)
504  {
505  for (const collision_detection::Contact& contact : it->second)
506  {
508  links.push_back(contact.body_name_1);
510  links.push_back(contact.body_name_2);
511  }
512  }
513 }
514 
515 const collision_detection::CollisionEnvPtr& PlanningScene::getCollisionEnvNonConst()
516 {
517  return collision_detector_->cenv_;
518 }
519 
521 {
522  if (!robot_state_)
523  {
524  robot_state_ = std::make_shared<moveit::core::RobotState>(parent_->getCurrentState());
525  robot_state_->setAttachedBodyUpdateCallback(current_state_attached_body_callback_);
526  }
527  robot_state_->update();
528  return *robot_state_;
529 }
530 
531 moveit::core::RobotStatePtr PlanningScene::getCurrentStateUpdated(const moveit_msgs::msg::RobotState& update) const
532 {
533  auto state = std::make_shared<moveit::core::RobotState>(getCurrentState());
535  return state;
536 }
537 
539 {
540  current_state_attached_body_callback_ = callback;
541  if (robot_state_)
542  robot_state_->setAttachedBodyUpdateCallback(callback);
543 }
544 
546 {
547  if (current_world_object_update_callback_)
548  world_->removeObserver(current_world_object_update_observer_handle_);
549  if (callback)
550  current_world_object_update_observer_handle_ = world_->addObserver(callback);
551  current_world_object_update_callback_ = callback;
552 }
553 
555 {
556  if (!acm_)
557  acm_ = std::make_shared<collision_detection::AllowedCollisionMatrix>(parent_->getAllowedCollisionMatrix());
558  return *acm_;
559 }
560 
562 {
563  // Trigger an update of the robot transforms
565  return static_cast<const PlanningScene*>(this)->getTransforms();
566 }
567 
569 {
570  // Trigger an update of the robot transforms
572  if (!scene_transforms_)
573  {
574  // The only case when there are no transforms is if this planning scene has a parent. When a non-const version of
575  // the planning scene is requested, a copy of the parent's transforms is forced
576  scene_transforms_ = std::make_shared<SceneTransforms>(this);
577  scene_transforms_->setAllTransforms(parent_->getTransforms().getAllTransforms());
578  }
579  return *scene_transforms_;
580 }
581 
582 void PlanningScene::getPlanningSceneDiffMsg(moveit_msgs::msg::PlanningScene& scene_msg) const
583 {
584  scene_msg.name = name_;
585  scene_msg.robot_model_name = getRobotModel()->getName();
586  scene_msg.is_diff = true;
587 
588  if (scene_transforms_)
589  {
590  scene_transforms_->copyTransforms(scene_msg.fixed_frame_transforms);
591  }
592  else
593  {
594  scene_msg.fixed_frame_transforms.clear();
595  }
596 
597  if (robot_state_)
598  {
599  moveit::core::robotStateToRobotStateMsg(*robot_state_, scene_msg.robot_state);
600  }
601  else
602  {
603  scene_msg.robot_state = moveit_msgs::msg::RobotState();
604  }
605  scene_msg.robot_state.is_diff = true;
606 
607  if (acm_)
608  {
609  acm_->getMessage(scene_msg.allowed_collision_matrix);
610  }
611  else
612  {
613  scene_msg.allowed_collision_matrix = moveit_msgs::msg::AllowedCollisionMatrix();
614  }
615 
616  collision_detector_->cenv_->getPadding(scene_msg.link_padding);
617  collision_detector_->cenv_->getScale(scene_msg.link_scale);
618 
619  scene_msg.object_colors.clear();
620  if (object_colors_)
621  {
622  unsigned int i = 0;
623  scene_msg.object_colors.resize(object_colors_->size());
624  for (ObjectColorMap::const_iterator it = object_colors_->begin(); it != object_colors_->end(); ++it, ++i)
625  {
626  scene_msg.object_colors[i].id = it->first;
627  scene_msg.object_colors[i].color = it->second;
628  }
629  }
630 
631  scene_msg.world.collision_objects.clear();
632  scene_msg.world.octomap = octomap_msgs::msg::OctomapWithPose();
633 
634  if (world_diff_)
635  {
636  bool do_omap = false;
637  for (const std::pair<const std::string, collision_detection::World::Action>& it : *world_diff_)
638  {
639  if (it.first == OCTOMAP_NS)
640  {
641  do_omap = true;
642  }
643  else if (it.second == collision_detection::World::DESTROY)
644  {
645  // if object became attached, it should not be recorded as removed here
646  if (!std::count_if(scene_msg.robot_state.attached_collision_objects.cbegin(),
647  scene_msg.robot_state.attached_collision_objects.cend(),
648  [&it](const moveit_msgs::msg::AttachedCollisionObject& aco) {
649  return aco.object.id == it.first &&
650  aco.object.operation == moveit_msgs::msg::CollisionObject::ADD;
651  }))
652  {
653  moveit_msgs::msg::CollisionObject co;
654  co.header.frame_id = getPlanningFrame();
655  co.id = it.first;
656  co.operation = moveit_msgs::msg::CollisionObject::REMOVE;
657  scene_msg.world.collision_objects.push_back(co);
658  }
659  }
660  else
661  {
662  scene_msg.world.collision_objects.emplace_back();
663  getCollisionObjectMsg(scene_msg.world.collision_objects.back(), it.first);
664  }
665  }
666  if (do_omap)
667  getOctomapMsg(scene_msg.world.octomap);
668  }
669 
670  // Ensure all detached collision objects actually get removed when applying the diff
671  // Because RobotState doesn't handle diffs (yet), we explicitly declare attached objects
672  // as removed, if they show up as "normal" collision objects but were attached in parent
673  for (const auto& collision_object : scene_msg.world.collision_objects)
674  {
675  if (parent_ && parent_->getCurrentState().hasAttachedBody(collision_object.id))
676  {
677  moveit_msgs::msg::AttachedCollisionObject aco;
678  aco.object.id = collision_object.id;
679  aco.object.operation = moveit_msgs::msg::CollisionObject::REMOVE;
680  scene_msg.robot_state.attached_collision_objects.push_back(aco);
681  }
682  }
683 }
684 
685 namespace
686 {
687 class ShapeVisitorAddToCollisionObject : public boost::static_visitor<void>
688 {
689 public:
690  ShapeVisitorAddToCollisionObject(moveit_msgs::msg::CollisionObject* obj) : boost::static_visitor<void>(), obj_(obj)
691  {
692  }
693 
694  void setPoseMessage(const geometry_msgs::msg::Pose* pose)
695  {
696  pose_ = pose;
697  }
698 
699  void operator()(const shape_msgs::msg::Plane& shape_msg) const
700  {
701  obj_->planes.push_back(shape_msg);
702  obj_->plane_poses.push_back(*pose_);
703  }
704 
705  void operator()(const shape_msgs::msg::Mesh& shape_msg) const
706  {
707  obj_->meshes.push_back(shape_msg);
708  obj_->mesh_poses.push_back(*pose_);
709  }
710 
711  void operator()(const shape_msgs::msg::SolidPrimitive& shape_msg) const
712  {
713  obj_->primitives.push_back(shape_msg);
714  obj_->primitive_poses.push_back(*pose_);
715  }
716 
717 private:
718  moveit_msgs::msg::CollisionObject* obj_;
719  const geometry_msgs::msg::Pose* pose_;
720 };
721 } // namespace
722 
723 bool PlanningScene::getCollisionObjectMsg(moveit_msgs::msg::CollisionObject& collision_obj, const std::string& ns) const
724 {
725  collision_detection::CollisionEnv::ObjectConstPtr obj = world_->getObject(ns);
726  if (!obj)
727  return false;
728  collision_obj.header.frame_id = getPlanningFrame();
729  collision_obj.pose = tf2::toMsg(obj->pose_);
730  collision_obj.id = ns;
731  collision_obj.operation = moveit_msgs::msg::CollisionObject::ADD;
732 
733  ShapeVisitorAddToCollisionObject sv(&collision_obj);
734  for (std::size_t j = 0; j < obj->shapes_.size(); ++j)
735  {
736  shapes::ShapeMsg sm;
737  if (constructMsgFromShape(obj->shapes_[j].get(), sm))
738  {
739  geometry_msgs::msg::Pose p = tf2::toMsg(obj->shape_poses_[j]);
740  sv.setPoseMessage(&p);
741  boost::apply_visitor(sv, sm);
742  }
743  }
744 
745  if (!collision_obj.primitives.empty() || !collision_obj.meshes.empty() || !collision_obj.planes.empty())
746  {
747  if (hasObjectType(collision_obj.id))
748  collision_obj.type = getObjectType(collision_obj.id);
749  }
750  for (const auto& frame_pair : obj->subframe_poses_)
751  {
752  collision_obj.subframe_names.push_back(frame_pair.first);
753  geometry_msgs::msg::Pose p;
754  p = tf2::toMsg(frame_pair.second);
755  collision_obj.subframe_poses.push_back(p);
756  }
757 
758  return true;
759 }
760 
761 void PlanningScene::getCollisionObjectMsgs(std::vector<moveit_msgs::msg::CollisionObject>& collision_objs) const
762 {
763  collision_objs.clear();
764  const std::vector<std::string>& ids = world_->getObjectIds();
765  for (const std::string& id : ids)
766  {
767  if (id != OCTOMAP_NS)
768  {
769  collision_objs.emplace_back();
770  getCollisionObjectMsg(collision_objs.back(), id);
771  }
772  }
773 }
774 
775 bool PlanningScene::getAttachedCollisionObjectMsg(moveit_msgs::msg::AttachedCollisionObject& attached_collision_obj,
776  const std::string& ns) const
777 {
778  std::vector<moveit_msgs::msg::AttachedCollisionObject> attached_collision_objs;
779  getAttachedCollisionObjectMsgs(attached_collision_objs);
780  for (moveit_msgs::msg::AttachedCollisionObject& it : attached_collision_objs)
781  {
782  if (it.object.id == ns)
783  {
784  attached_collision_obj = it;
785  return true;
786  }
787  }
788  return false;
789 }
790 
792  std::vector<moveit_msgs::msg::AttachedCollisionObject>& attached_collision_objs) const
793 {
794  std::vector<const moveit::core::AttachedBody*> attached_bodies;
795  getCurrentState().getAttachedBodies(attached_bodies);
796  attachedBodiesToAttachedCollisionObjectMsgs(attached_bodies, attached_collision_objs);
797 }
798 
799 bool PlanningScene::getOctomapMsg(octomap_msgs::msg::OctomapWithPose& octomap) const
800 {
801  octomap.header.frame_id = getPlanningFrame();
802  octomap.octomap = octomap_msgs::msg::Octomap();
803 
805  if (map)
806  {
807  if (map->shapes_.size() == 1)
808  {
809  const shapes::OcTree* o = static_cast<const shapes::OcTree*>(map->shapes_[0].get());
810  octomap_msgs::fullMapToMsg(*o->octree, octomap.octomap);
811  octomap.origin = tf2::toMsg(map->shape_poses_[0]);
812  return true;
813  }
814  RCLCPP_ERROR(LOGGER, "Unexpected number of shapes in octomap collision object. Not including '%s' object",
815  OCTOMAP_NS.c_str());
816  }
817  return false;
818 }
819 
820 void PlanningScene::getObjectColorMsgs(std::vector<moveit_msgs::msg::ObjectColor>& object_colors) const
821 {
822  object_colors.clear();
823 
824  unsigned int i = 0;
825  ObjectColorMap cmap;
826  getKnownObjectColors(cmap);
827  object_colors.resize(cmap.size());
828  for (ObjectColorMap::const_iterator it = cmap.begin(); it != cmap.end(); ++it, ++i)
829  {
830  object_colors[i].id = it->first;
831  object_colors[i].color = it->second;
832  }
833 }
834 
835 void PlanningScene::getPlanningSceneMsg(moveit_msgs::msg::PlanningScene& scene_msg) const
836 {
837  scene_msg.name = name_;
838  scene_msg.is_diff = false;
839  scene_msg.robot_model_name = getRobotModel()->getName();
840  getTransforms().copyTransforms(scene_msg.fixed_frame_transforms);
841 
843  getAllowedCollisionMatrix().getMessage(scene_msg.allowed_collision_matrix);
844  getCollisionEnv()->getPadding(scene_msg.link_padding);
845  getCollisionEnv()->getScale(scene_msg.link_scale);
846 
847  getObjectColorMsgs(scene_msg.object_colors);
848 
849  // add collision objects
850  getCollisionObjectMsgs(scene_msg.world.collision_objects);
851 
852  // get the octomap
853  getOctomapMsg(scene_msg.world.octomap);
854 }
855 
856 void PlanningScene::getPlanningSceneMsg(moveit_msgs::msg::PlanningScene& scene_msg,
857  const moveit_msgs::msg::PlanningSceneComponents& comp) const
858 {
859  scene_msg.is_diff = false;
860  if (comp.components & moveit_msgs::msg::PlanningSceneComponents::SCENE_SETTINGS)
861  {
862  scene_msg.name = name_;
863  scene_msg.robot_model_name = getRobotModel()->getName();
864  }
865 
866  if (comp.components & moveit_msgs::msg::PlanningSceneComponents::TRANSFORMS)
867  getTransforms().copyTransforms(scene_msg.fixed_frame_transforms);
868 
869  if (comp.components & moveit_msgs::msg::PlanningSceneComponents::ROBOT_STATE_ATTACHED_OBJECTS)
870  {
871  moveit::core::robotStateToRobotStateMsg(getCurrentState(), scene_msg.robot_state, true);
872  for (moveit_msgs::msg::AttachedCollisionObject& attached_collision_object :
873  scene_msg.robot_state.attached_collision_objects)
874  {
875  if (hasObjectType(attached_collision_object.object.id))
876  {
877  attached_collision_object.object.type = getObjectType(attached_collision_object.object.id);
878  }
879  }
880  }
881  else if (comp.components & moveit_msgs::msg::PlanningSceneComponents::ROBOT_STATE)
882  {
883  moveit::core::robotStateToRobotStateMsg(getCurrentState(), scene_msg.robot_state, false);
884  }
885 
886  if (comp.components & moveit_msgs::msg::PlanningSceneComponents::ALLOWED_COLLISION_MATRIX)
887  getAllowedCollisionMatrix().getMessage(scene_msg.allowed_collision_matrix);
888 
889  if (comp.components & moveit_msgs::msg::PlanningSceneComponents::LINK_PADDING_AND_SCALING)
890  {
891  getCollisionEnv()->getPadding(scene_msg.link_padding);
892  getCollisionEnv()->getScale(scene_msg.link_scale);
893  }
894 
895  if (comp.components & moveit_msgs::msg::PlanningSceneComponents::OBJECT_COLORS)
896  getObjectColorMsgs(scene_msg.object_colors);
897 
898  // add collision objects
899  if (comp.components & moveit_msgs::msg::PlanningSceneComponents::WORLD_OBJECT_GEOMETRY)
900  {
901  getCollisionObjectMsgs(scene_msg.world.collision_objects);
902  }
903  else if (comp.components & moveit_msgs::msg::PlanningSceneComponents::WORLD_OBJECT_NAMES)
904  {
905  const std::vector<std::string>& ids = world_->getObjectIds();
906  scene_msg.world.collision_objects.clear();
907  scene_msg.world.collision_objects.reserve(ids.size());
908  for (const std::string& id : ids)
909  {
910  if (id != OCTOMAP_NS)
911  {
912  moveit_msgs::msg::CollisionObject co;
913  co.id = id;
914  if (hasObjectType(co.id))
915  co.type = getObjectType(co.id);
916  scene_msg.world.collision_objects.push_back(co);
917  }
918  }
919  }
920 
921  // get the octomap
922  if (comp.components & moveit_msgs::msg::PlanningSceneComponents::OCTOMAP)
923  getOctomapMsg(scene_msg.world.octomap);
924 }
925 
926 void PlanningScene::saveGeometryToStream(std::ostream& out) const
927 {
928  out << name_ << '\n';
929  const std::vector<std::string>& ids = world_->getObjectIds();
930  for (const std::string& id : ids)
931  {
932  if (id != OCTOMAP_NS)
933  {
934  collision_detection::CollisionEnv::ObjectConstPtr obj = world_->getObject(id);
935  if (obj)
936  {
937  out << "* " << id << '\n'; // New object start
938  // Write object pose
939  utilities::writePoseToText(out, obj->pose_);
940 
941  // Write shapes and shape poses
942  out << obj->shapes_.size() << '\n'; // Number of shapes
943  for (std::size_t j = 0; j < obj->shapes_.size(); ++j)
944  {
945  shapes::saveAsText(obj->shapes_[j].get(), out);
946  // shape_poses_ is valid isometry by contract
947  utilities::writePoseToText(out, obj->shape_poses_[j]);
948  if (hasObjectColor(id))
949  {
950  const std_msgs::msg::ColorRGBA& c = getObjectColor(id);
951  out << c.r << ' ' << c.g << ' ' << c.b << ' ' << c.a << '\n';
952  }
953  else
954  out << "0 0 0 0" << '\n';
955  }
956 
957  // Write subframes
958  out << obj->subframe_poses_.size() << '\n'; // Number of subframes
959  for (auto& pose_pair : obj->subframe_poses_)
960  {
961  out << pose_pair.first << '\n'; // Subframe name
962  utilities::writePoseToText(out, pose_pair.second); // Subframe pose
963  }
964  }
965  }
966  }
967  out << '.' << '\n';
968 }
969 
971 {
972  return loadGeometryFromStream(in, Eigen::Isometry3d::Identity()); // Use no offset
973 }
974 
975 bool PlanningScene::loadGeometryFromStream(std::istream& in, const Eigen::Isometry3d& offset)
976 {
977  if (!in.good() || in.eof())
978  {
979  RCLCPP_ERROR(LOGGER, "Bad input stream when loading scene geometry");
980  return false;
981  }
982  // Read scene name
983  std::getline(in, name_);
984 
985  // Identify scene format version for backwards compatibility of parser
986  auto pos = in.tellg(); // remember current stream position
987  std::string line;
988  do
989  {
990  std::getline(in, line);
991  } while (in.good() && !in.eof() && (line.empty() || line[0] != '*')); // read * marker
992  std::getline(in, line); // next line determines format
993  boost::algorithm::trim(line);
994  // new format: line specifies position of object, with spaces as delimiter -> spaces indicate new format
995  // old format: line specifies number of shapes
996  bool uses_new_scene_format = line.find(' ') != std::string::npos;
997  in.seekg(pos);
998 
999  Eigen::Isometry3d pose; // Transient
1000  do
1001  {
1002  std::string marker;
1003  in >> marker;
1004  if (!in.good() || in.eof())
1005  {
1006  RCLCPP_ERROR(LOGGER, "Bad input stream when loading marker in scene geometry");
1007  return false;
1008  }
1009  if (marker == "*") // Start of new object
1010  {
1011  std::string object_id;
1012  std::getline(in, object_id);
1013  if (!in.good() || in.eof())
1014  {
1015  RCLCPP_ERROR(LOGGER, "Bad input stream when loading object_id in scene geometry");
1016  return false;
1017  }
1018  boost::algorithm::trim(object_id);
1019 
1020  // Read in object pose (added in the new scene format)
1021  pose.setIdentity();
1022  if (uses_new_scene_format && !utilities::readPoseFromText(in, pose))
1023  {
1024  RCLCPP_ERROR(LOGGER, "Failed to read object pose from scene file");
1025  return false;
1026  }
1027  pose = offset * pose; // Transform pose by input pose offset
1028  world_->setObjectPose(object_id, pose);
1029 
1030  // Read in shapes
1031  unsigned int shape_count;
1032  in >> shape_count;
1033  for (std::size_t i = 0; i < shape_count && in.good() && !in.eof(); ++i)
1034  {
1035  const auto shape = shapes::ShapeConstPtr(shapes::constructShapeFromText(in));
1036  if (!shape)
1037  {
1038  RCLCPP_ERROR(LOGGER, "Failed to load shape from scene file");
1039  return false;
1040  }
1041  if (!utilities::readPoseFromText(in, pose))
1042  {
1043  RCLCPP_ERROR(LOGGER, "Failed to read pose from scene file");
1044  return false;
1045  }
1046  double r, g, b, a;
1047  if (!(in >> r >> g >> b >> a))
1048  {
1049  RCLCPP_ERROR(LOGGER, "Improperly formatted color in scene geometry file");
1050  return false;
1051  }
1052  if (shape)
1053  {
1054  world_->addToObject(object_id, shape, pose);
1055  if (r > 0.0f || g > 0.0f || b > 0.0f || a > 0.0f)
1056  {
1057  std_msgs::msg::ColorRGBA color;
1058  color.r = r;
1059  color.g = g;
1060  color.b = b;
1061  color.a = a;
1062  setObjectColor(object_id, color);
1063  }
1064  }
1065  }
1066 
1067  // Read in subframes (added in the new scene format)
1068  if (uses_new_scene_format)
1069  {
1071  unsigned int subframe_count;
1072  in >> subframe_count;
1073  for (std::size_t i = 0; i < subframe_count && in.good() && !in.eof(); ++i)
1074  {
1075  std::string subframe_name;
1076  in >> subframe_name;
1077  if (!utilities::readPoseFromText(in, pose))
1078  {
1079  RCLCPP_ERROR(LOGGER, "Failed to read subframe pose from scene file");
1080  return false;
1081  }
1082  subframes[subframe_name] = pose;
1083  }
1084  world_->setSubframesOfObject(object_id, subframes);
1085  }
1086  }
1087  else if (marker == ".")
1088  {
1089  // Marks the end of the scene geometry;
1090  return true;
1091  }
1092  else
1093  {
1094  RCLCPP_ERROR(LOGGER, "Unknown marker in scene geometry file: %s ", marker.c_str());
1095  return false;
1096  }
1097  } while (true);
1098 }
1099 
1100 void PlanningScene::setCurrentState(const moveit_msgs::msg::RobotState& state)
1101 {
1102  // The attached bodies will be processed separately by processAttachedCollisionObjectMsgs
1103  // after robot_state_ has been updated
1104  moveit_msgs::msg::RobotState state_no_attached(state);
1105  state_no_attached.attached_collision_objects.clear();
1106 
1107  if (parent_)
1108  {
1109  if (!robot_state_)
1110  {
1111  robot_state_ = std::make_shared<moveit::core::RobotState>(parent_->getCurrentState());
1112  robot_state_->setAttachedBodyUpdateCallback(current_state_attached_body_callback_);
1113  }
1114  moveit::core::robotStateMsgToRobotState(getTransforms(), state_no_attached, *robot_state_);
1115  }
1116  else
1117  moveit::core::robotStateMsgToRobotState(*scene_transforms_, state_no_attached, *robot_state_);
1118 
1119  for (std::size_t i = 0; i < state.attached_collision_objects.size(); ++i)
1120  {
1121  if (!state.is_diff && state.attached_collision_objects[i].object.operation != moveit_msgs::msg::CollisionObject::ADD)
1122  {
1123  RCLCPP_ERROR(LOGGER,
1124  "The specified RobotState is not marked as is_diff. "
1125  "The request to modify the object '%s' is not supported. Object is ignored.",
1126  state.attached_collision_objects[i].object.id.c_str());
1127  continue;
1128  }
1129  processAttachedCollisionObjectMsg(state.attached_collision_objects[i]);
1130  }
1131 }
1132 
1134 {
1135  getCurrentStateNonConst() = state;
1136 }
1137 
1139 {
1140  if (!parent_)
1141  return;
1142 
1143  // This child planning scene did not have its own copy of frame transforms
1144  if (!scene_transforms_)
1145  {
1146  scene_transforms_ = std::make_shared<SceneTransforms>(this);
1147  scene_transforms_->setAllTransforms(parent_->getTransforms().getAllTransforms());
1148  }
1149 
1150  if (!robot_state_)
1151  {
1152  robot_state_ = std::make_shared<moveit::core::RobotState>(parent_->getCurrentState());
1153  robot_state_->setAttachedBodyUpdateCallback(current_state_attached_body_callback_);
1154  }
1155 
1156  if (!acm_)
1157  acm_ = std::make_shared<collision_detection::AllowedCollisionMatrix>(parent_->getAllowedCollisionMatrix());
1158 
1159  world_diff_.reset();
1160 
1161  if (!object_colors_)
1162  {
1163  ObjectColorMap kc;
1164  parent_->getKnownObjectColors(kc);
1165  object_colors_ = std::make_unique<ObjectColorMap>(kc);
1166  }
1167  else
1168  {
1169  ObjectColorMap kc;
1170  parent_->getKnownObjectColors(kc);
1171  for (ObjectColorMap::const_iterator it = kc.begin(); it != kc.end(); ++it)
1172  {
1173  if (object_colors_->find(it->first) == object_colors_->end())
1174  (*object_colors_)[it->first] = it->second;
1175  }
1176  }
1177 
1178  if (!object_types_)
1179  {
1180  ObjectTypeMap kc;
1181  parent_->getKnownObjectTypes(kc);
1182  object_types_ = std::make_unique<ObjectTypeMap>(kc);
1183  }
1184  else
1185  {
1186  ObjectTypeMap kc;
1187  parent_->getKnownObjectTypes(kc);
1188  for (ObjectTypeMap::const_iterator it = kc.begin(); it != kc.end(); ++it)
1189  {
1190  if (object_types_->find(it->first) == object_types_->end())
1191  (*object_types_)[it->first] = it->second;
1192  }
1193  }
1194 
1195  parent_.reset();
1196 }
1197 
1198 bool PlanningScene::setPlanningSceneDiffMsg(const moveit_msgs::msg::PlanningScene& scene_msg)
1199 {
1200  bool result = true;
1201 
1202  RCLCPP_DEBUG(LOGGER, "Adding planning scene diff");
1203  if (!scene_msg.name.empty())
1204  name_ = scene_msg.name;
1205 
1206  if (!scene_msg.robot_model_name.empty() && scene_msg.robot_model_name != getRobotModel()->getName())
1207  {
1208  RCLCPP_WARN(LOGGER, "Setting the scene for model '%s' but model '%s' is loaded.",
1209  scene_msg.robot_model_name.c_str(), getRobotModel()->getName().c_str());
1210  }
1211 
1212  // there is at least one transform in the list of fixed transform: from model frame to itself;
1213  // if the list is empty, then nothing has been set
1214  if (!scene_msg.fixed_frame_transforms.empty())
1215  {
1216  if (!scene_transforms_)
1217  scene_transforms_ = std::make_shared<SceneTransforms>(this);
1218  scene_transforms_->setTransforms(scene_msg.fixed_frame_transforms);
1219  }
1220 
1221  // if at least some joints have been specified, we set them
1222  if (!scene_msg.robot_state.multi_dof_joint_state.joint_names.empty() ||
1223  !scene_msg.robot_state.joint_state.name.empty() || !scene_msg.robot_state.attached_collision_objects.empty())
1224  setCurrentState(scene_msg.robot_state);
1225 
1226  // if at least some links are mentioned in the allowed collision matrix, then we have an update
1227  if (!scene_msg.allowed_collision_matrix.entry_names.empty())
1228  acm_ = std::make_shared<collision_detection::AllowedCollisionMatrix>(scene_msg.allowed_collision_matrix);
1229 
1230  if (!scene_msg.link_padding.empty() || !scene_msg.link_scale.empty())
1231  {
1232  collision_detector_->cenv_->setPadding(scene_msg.link_padding);
1233  collision_detector_->cenv_->setScale(scene_msg.link_scale);
1234  }
1235 
1236  // if any colors have been specified, replace the ones we have with the specified ones
1237  for (const moveit_msgs::msg::ObjectColor& object_color : scene_msg.object_colors)
1238  setObjectColor(object_color.id, object_color.color);
1239 
1240  // process collision object updates
1241  for (const moveit_msgs::msg::CollisionObject& collision_object : scene_msg.world.collision_objects)
1242  result &= processCollisionObjectMsg(collision_object);
1243 
1244  // if an octomap was specified, replace the one we have with that one
1245  if (!scene_msg.world.octomap.octomap.data.empty())
1246  processOctomapMsg(scene_msg.world.octomap);
1247 
1248  return result;
1249 }
1250 
1251 bool PlanningScene::setPlanningSceneMsg(const moveit_msgs::msg::PlanningScene& scene_msg)
1252 {
1253  RCLCPP_DEBUG(LOGGER, "Setting new planning scene: '%s'", scene_msg.name.c_str());
1254  name_ = scene_msg.name;
1255 
1256  if (!scene_msg.robot_model_name.empty() && scene_msg.robot_model_name != getRobotModel()->getName())
1257  {
1258  RCLCPP_WARN(LOGGER, "Setting the scene for model '%s' but model '%s' is loaded.",
1259  scene_msg.robot_model_name.c_str(), getRobotModel()->getName().c_str());
1260  }
1261 
1262  if (parent_)
1263  decoupleParent();
1264 
1265  object_types_.reset();
1266  scene_transforms_->setTransforms(scene_msg.fixed_frame_transforms);
1267  setCurrentState(scene_msg.robot_state);
1268  acm_ = std::make_shared<collision_detection::AllowedCollisionMatrix>(scene_msg.allowed_collision_matrix);
1269  collision_detector_->cenv_->setPadding(scene_msg.link_padding);
1270  collision_detector_->cenv_->setScale(scene_msg.link_scale);
1271  object_colors_ = std::make_unique<ObjectColorMap>();
1272  for (const moveit_msgs::msg::ObjectColor& object_color : scene_msg.object_colors)
1273  setObjectColor(object_color.id, object_color.color);
1274  world_->clearObjects();
1275  return processPlanningSceneWorldMsg(scene_msg.world);
1276 }
1277 
1278 bool PlanningScene::processPlanningSceneWorldMsg(const moveit_msgs::msg::PlanningSceneWorld& world)
1279 {
1280  bool result = true;
1281  for (const moveit_msgs::msg::CollisionObject& collision_object : world.collision_objects)
1282  result &= processCollisionObjectMsg(collision_object);
1283  processOctomapMsg(world.octomap);
1284  return result;
1285 }
1286 
1287 bool PlanningScene::usePlanningSceneMsg(const moveit_msgs::msg::PlanningScene& scene_msg)
1288 {
1289  if (scene_msg.is_diff)
1290  {
1291  return setPlanningSceneDiffMsg(scene_msg);
1292  }
1293  else
1294  {
1295  return setPlanningSceneMsg(scene_msg);
1296  }
1297 }
1298 
1299 collision_detection::OccMapTreePtr createOctomap(const octomap_msgs::msg::Octomap& map)
1300 {
1301  std::shared_ptr<collision_detection::OccMapTree> om =
1302  std::make_shared<collision_detection::OccMapTree>(map.resolution);
1303  if (map.binary)
1304  {
1305  octomap_msgs::readTree(om.get(), map);
1306  }
1307  else
1308  {
1309  std::stringstream datastream;
1310  if (!map.data.empty())
1311  {
1312  datastream.write(reinterpret_cast<const char*>(&map.data[0]), map.data.size());
1313  om->readData(datastream);
1314  }
1315  }
1316  return om;
1317 }
1318 
1319 void PlanningScene::processOctomapMsg(const octomap_msgs::msg::Octomap& map)
1320 {
1321  // each octomap replaces any previous one
1322  world_->removeObject(OCTOMAP_NS);
1323 
1324  if (map.data.empty())
1325  return;
1326 
1327  if (map.id != "OcTree")
1328  {
1329  RCLCPP_ERROR(LOGGER, "Received octomap is of type '%s' but type 'OcTree' is expected.", map.id.c_str());
1330  return;
1331  }
1332 
1333  std::shared_ptr<collision_detection::OccMapTree> om = createOctomap(map);
1334  if (!map.header.frame_id.empty())
1335  {
1336  const Eigen::Isometry3d& t = getFrameTransform(map.header.frame_id);
1337  world_->addToObject(OCTOMAP_NS, std::make_shared<const shapes::OcTree>(om), t);
1338  }
1339  else
1340  {
1341  world_->addToObject(OCTOMAP_NS, std::make_shared<const shapes::OcTree>(om), Eigen::Isometry3d::Identity());
1342  }
1343 }
1344 
1346 {
1347  const std::vector<std::string>& object_ids = world_->getObjectIds();
1348  for (const std::string& object_id : object_ids)
1349  {
1350  if (object_id != OCTOMAP_NS)
1351  {
1352  world_->removeObject(object_id);
1353  removeObjectColor(object_id);
1354  removeObjectType(object_id);
1355  }
1356  }
1357 }
1358 
1359 void PlanningScene::processOctomapMsg(const octomap_msgs::msg::OctomapWithPose& map)
1360 {
1361  // each octomap replaces any previous one
1362  world_->removeObject(OCTOMAP_NS);
1363 
1364  if (map.octomap.data.empty())
1365  return;
1366 
1367  if (map.octomap.id != "OcTree")
1368  {
1369  RCLCPP_ERROR(LOGGER, "Received octomap is of type '%s' but type 'OcTree' is expected.", map.octomap.id.c_str());
1370  return;
1371  }
1372 
1373  std::shared_ptr<collision_detection::OccMapTree> om = createOctomap(map.octomap);
1374 
1375  const Eigen::Isometry3d& t = getFrameTransform(map.header.frame_id);
1376  Eigen::Isometry3d p;
1377  utilities::poseMsgToEigen(map.origin, p);
1378  p = t * p;
1379  world_->addToObject(OCTOMAP_NS, std::make_shared<const shapes::OcTree>(om), p);
1380 }
1381 
1382 void PlanningScene::processOctomapPtr(const std::shared_ptr<const octomap::OcTree>& octree, const Eigen::Isometry3d& t)
1383 {
1385  if (map)
1386  {
1387  if (map->shapes_.size() == 1)
1388  {
1389  // check to see if we have the same octree pointer & pose.
1390  const shapes::OcTree* o = static_cast<const shapes::OcTree*>(map->shapes_[0].get());
1391  if (o->octree == octree)
1392  {
1393  // if the pose changed, we update it
1394  if (map->shape_poses_[0].isApprox(t, std::numeric_limits<double>::epsilon() * 100.0))
1395  {
1396  if (world_diff_)
1397  {
1400  }
1401  }
1402  else
1403  {
1404  shapes::ShapeConstPtr shape = map->shapes_[0];
1405  map.reset(); // reset this pointer first so that caching optimizations can be used in CollisionWorld
1406  world_->moveShapeInObject(OCTOMAP_NS, shape, t);
1407  }
1408  return;
1409  }
1410  }
1411  }
1412  // if the octree pointer changed, update the structure
1413  world_->removeObject(OCTOMAP_NS);
1414  world_->addToObject(OCTOMAP_NS, std::make_shared<const shapes::OcTree>(octree), t);
1415 }
1416 
1417 bool PlanningScene::processAttachedCollisionObjectMsg(const moveit_msgs::msg::AttachedCollisionObject& object)
1418 {
1419  if (object.object.operation == moveit_msgs::msg::CollisionObject::ADD &&
1420  !getRobotModel()->hasLinkModel(object.link_name))
1421  {
1422  RCLCPP_ERROR(LOGGER, "Unable to attach a body to link '%s' (link not found)", object.link_name.c_str());
1423  return false;
1424  }
1425 
1426  if (object.object.id == OCTOMAP_NS)
1427  {
1428  RCLCPP_ERROR(LOGGER, "The ID '%s' cannot be used for collision objects (name reserved)", OCTOMAP_NS.c_str());
1429  return false;
1430  }
1431 
1432  if (!robot_state_) // there must be a parent in this case
1433  {
1434  robot_state_ = std::make_shared<moveit::core::RobotState>(parent_->getCurrentState());
1435  robot_state_->setAttachedBodyUpdateCallback(current_state_attached_body_callback_);
1436  }
1437  robot_state_->update();
1438 
1439  // The ADD/REMOVE operations follow this order:
1440  // STEP 1: Get info about the object from either the message or the world/RobotState
1441  // STEP 2: Remove the object from the world/RobotState if necessary
1442  // STEP 3: Put the object in the RobotState/world
1443 
1444  if (object.object.operation == moveit_msgs::msg::CollisionObject::ADD ||
1445  object.object.operation == moveit_msgs::msg::CollisionObject::APPEND)
1446  {
1447  const moveit::core::LinkModel* link_model = getRobotModel()->getLinkModel(object.link_name);
1448  if (link_model)
1449  {
1450  // items to build the attached object from (filled from existing world object or message)
1451  Eigen::Isometry3d object_pose_in_link;
1452  std::vector<shapes::ShapeConstPtr> shapes;
1453  EigenSTL::vector_Isometry3d shape_poses;
1454  moveit::core::FixedTransformsMap subframe_poses;
1455 
1456  // STEP 1: Obtain info about object to be attached.
1457  // If it is in the world, message contents are ignored.
1458 
1459  collision_detection::CollisionEnv::ObjectConstPtr obj_in_world = world_->getObject(object.object.id);
1460  if (object.object.operation == moveit_msgs::msg::CollisionObject::ADD && object.object.primitives.empty() &&
1461  object.object.meshes.empty() && object.object.planes.empty())
1462  {
1463  if (obj_in_world)
1464  {
1465  RCLCPP_DEBUG(LOGGER, "Attaching world object '%s' to link '%s'", object.object.id.c_str(),
1466  object.link_name.c_str());
1467 
1468  object_pose_in_link = robot_state_->getGlobalLinkTransform(link_model).inverse() * obj_in_world->pose_;
1469  shapes = obj_in_world->shapes_;
1470  shape_poses = obj_in_world->shape_poses_;
1471  subframe_poses = obj_in_world->subframe_poses_;
1472  }
1473  else
1474  {
1475  RCLCPP_ERROR(LOGGER,
1476  "Attempting to attach object '%s' to link '%s' but no geometry specified "
1477  "and such an object does not exist in the collision world",
1478  object.object.id.c_str(), object.link_name.c_str());
1479  return false;
1480  }
1481  }
1482  else // If object is not in the world, use the message contents
1483  {
1484  Eigen::Isometry3d header_frame_to_object_pose;
1485  if (!shapesAndPosesFromCollisionObjectMessage(object.object, header_frame_to_object_pose, shapes, shape_poses))
1486  return false;
1487  const Eigen::Isometry3d world_to_header_frame = getFrameTransform(object.object.header.frame_id);
1488  const Eigen::Isometry3d link_to_header_frame =
1489  robot_state_->getGlobalLinkTransform(link_model).inverse() * world_to_header_frame;
1490  object_pose_in_link = link_to_header_frame * header_frame_to_object_pose;
1491 
1492  Eigen::Isometry3d subframe_pose;
1493  for (std::size_t i = 0; i < object.object.subframe_poses.size(); ++i)
1494  {
1495  utilities::poseMsgToEigen(object.object.subframe_poses[i], subframe_pose);
1496  std::string name = object.object.subframe_names[i];
1497  subframe_poses[name] = subframe_pose;
1498  }
1499  }
1500 
1501  if (shapes.empty())
1502  {
1503  RCLCPP_ERROR(LOGGER, "There is no geometry to attach to link '%s' as part of attached body '%s'",
1504  object.link_name.c_str(), object.object.id.c_str());
1505  return false;
1506  }
1507 
1508  if (!object.object.type.db.empty() || !object.object.type.key.empty())
1509  setObjectType(object.object.id, object.object.type);
1510 
1511  // STEP 2: Remove the object from the world (if it existed)
1512  if (obj_in_world && world_->removeObject(object.object.id))
1513  {
1514  if (object.object.operation == moveit_msgs::msg::CollisionObject::ADD)
1515  {
1516  RCLCPP_DEBUG(LOGGER, "Removing world object with the same name as newly attached object: '%s'",
1517  object.object.id.c_str());
1518  }
1519  else
1520  {
1521  RCLCPP_WARN(LOGGER,
1522  "You tried to append geometry to an attached object "
1523  "that is actually a world object ('%s'). World geometry is ignored.",
1524  object.object.id.c_str());
1525  }
1526  }
1527 
1528  // STEP 3: Attach the object to the robot
1529  if (object.object.operation == moveit_msgs::msg::CollisionObject::ADD ||
1530  !robot_state_->hasAttachedBody(object.object.id))
1531  {
1532  if (robot_state_->clearAttachedBody(object.object.id))
1533  {
1534  RCLCPP_DEBUG(LOGGER,
1535  "The robot state already had an object named '%s' attached to link '%s'. "
1536  "The object was replaced.",
1537  object.object.id.c_str(), object.link_name.c_str());
1538  }
1539  robot_state_->attachBody(object.object.id, object_pose_in_link, shapes, shape_poses, object.touch_links,
1540  object.link_name, object.detach_posture, subframe_poses);
1541  RCLCPP_DEBUG(LOGGER, "Attached object '%s' to link '%s'", object.object.id.c_str(), object.link_name.c_str());
1542  }
1543  else // APPEND: augment to existing attached object
1544  {
1545  const moveit::core::AttachedBody* ab = robot_state_->getAttachedBody(object.object.id);
1546 
1547  // Allow overriding the body's pose if provided, otherwise keep the old one
1548  if (moveit::core::isEmpty(object.object.pose))
1549  object_pose_in_link = ab->getPose(); // Keep old pose
1550 
1551  shapes.insert(shapes.end(), ab->getShapes().begin(), ab->getShapes().end());
1552  shape_poses.insert(shape_poses.end(), ab->getShapePoses().begin(), ab->getShapePoses().end());
1553  subframe_poses.insert(ab->getSubframes().begin(), ab->getSubframes().end());
1554  trajectory_msgs::msg::JointTrajectory detach_posture =
1555  object.detach_posture.joint_names.empty() ? ab->getDetachPosture() : object.detach_posture;
1556 
1557  std::set<std::string> touch_links = ab->getTouchLinks();
1558  touch_links.insert(std::make_move_iterator(object.touch_links.begin()),
1559  std::make_move_iterator(object.touch_links.end()));
1560 
1561  robot_state_->clearAttachedBody(object.object.id);
1562  robot_state_->attachBody(object.object.id, object_pose_in_link, shapes, shape_poses, touch_links,
1563  object.link_name, detach_posture, subframe_poses);
1564  RCLCPP_DEBUG(LOGGER, "Appended things to object '%s' attached to link '%s'", object.object.id.c_str(),
1565  object.link_name.c_str());
1566  }
1567  return true;
1568  }
1569  else
1570  {
1571  RCLCPP_ERROR(LOGGER, "Robot state is not compatible with robot model. This could be fatal.");
1572  }
1573  }
1574  else if (object.object.operation == moveit_msgs::msg::CollisionObject::REMOVE) // == DETACH
1575  {
1576  // STEP 1: Get info about the object from the RobotState
1577  std::vector<const moveit::core::AttachedBody*> attached_bodies;
1578  if (object.object.id.empty())
1579  {
1580  const moveit::core::LinkModel* link_model =
1581  object.link_name.empty() ? nullptr : getRobotModel()->getLinkModel(object.link_name);
1582  if (link_model)
1583  { // if we have a link model specified, only fetch bodies attached to this link
1584  robot_state_->getAttachedBodies(attached_bodies, link_model);
1585  }
1586  else
1587  {
1588  robot_state_->getAttachedBodies(attached_bodies);
1589  }
1590  }
1591  else // A specific object id will be removed.
1592  {
1593  const moveit::core::AttachedBody* body = robot_state_->getAttachedBody(object.object.id);
1594  if (body)
1595  {
1596  if (!object.link_name.empty() && (body->getAttachedLinkName() != object.link_name))
1597  {
1598  RCLCPP_ERROR_STREAM(LOGGER, "The AttachedCollisionObject message states the object is attached to "
1599  << object.link_name << ", but it is actually attached to "
1600  << body->getAttachedLinkName()
1601  << ". Leave the link_name empty or specify the correct link.");
1602  return false;
1603  }
1604  attached_bodies.push_back(body);
1605  }
1606  }
1607 
1608  // STEP 2+3: Remove the attached object(s) from the RobotState and put them in the world
1609  for (const moveit::core::AttachedBody* attached_body : attached_bodies)
1610  {
1611  const std::string& name = attached_body->getName();
1612  if (world_->hasObject(name))
1613  {
1614  RCLCPP_WARN(LOGGER,
1615  "The collision world already has an object with the same name as the body about to be detached. "
1616  "NOT adding the detached body '%s' to the collision world.",
1617  object.object.id.c_str());
1618  }
1619  else
1620  {
1621  const Eigen::Isometry3d& pose = attached_body->getGlobalPose();
1622  world_->addToObject(name, pose, attached_body->getShapes(), attached_body->getShapePoses());
1623  world_->setSubframesOfObject(name, attached_body->getSubframes());
1624  RCLCPP_DEBUG(LOGGER, "Detached object '%s' from link '%s' and added it back in the collision world",
1625  name.c_str(), object.link_name.c_str());
1626  }
1627 
1628  robot_state_->clearAttachedBody(name);
1629  }
1630  if (!attached_bodies.empty() || object.object.id.empty())
1631  return true;
1632  }
1633  else if (object.object.operation == moveit_msgs::msg::CollisionObject::MOVE)
1634  {
1635  RCLCPP_ERROR(LOGGER, "Move for attached objects not yet implemented");
1636  }
1637  else
1638  {
1639  RCLCPP_ERROR(LOGGER, "Unknown collision object operation: %d", object.object.operation);
1640  }
1641 
1642  return false;
1643 }
1644 
1645 bool PlanningScene::processCollisionObjectMsg(const moveit_msgs::msg::CollisionObject& object)
1646 {
1647  if (object.id == OCTOMAP_NS)
1648  {
1649  RCLCPP_ERROR(LOGGER, "The ID '%s' cannot be used for collision objects (name reserved)", OCTOMAP_NS.c_str());
1650  return false;
1651  }
1652 
1653  if (object.operation == moveit_msgs::msg::CollisionObject::ADD ||
1654  object.operation == moveit_msgs::msg::CollisionObject::APPEND)
1655  {
1656  return processCollisionObjectAdd(object);
1657  }
1658  else if (object.operation == moveit_msgs::msg::CollisionObject::REMOVE)
1659  {
1660  return processCollisionObjectRemove(object);
1661  }
1662  else if (object.operation == moveit_msgs::msg::CollisionObject::MOVE)
1663  {
1664  return processCollisionObjectMove(object);
1665  }
1666 
1667  RCLCPP_ERROR(LOGGER, "Unknown collision object operation: %d", object.operation);
1668  return false;
1669 }
1670 
1671 bool PlanningScene::shapesAndPosesFromCollisionObjectMessage(const moveit_msgs::msg::CollisionObject& object,
1672  Eigen::Isometry3d& object_pose,
1673  std::vector<shapes::ShapeConstPtr>& shapes,
1674  EigenSTL::vector_Isometry3d& shape_poses)
1675 {
1676  if (object.primitives.size() < object.primitive_poses.size())
1677  {
1678  RCLCPP_ERROR(LOGGER, "More primitive shape poses than shapes in collision object message.");
1679  return false;
1680  }
1681  if (object.meshes.size() < object.mesh_poses.size())
1682  {
1683  RCLCPP_ERROR(LOGGER, "More mesh poses than meshes in collision object message.");
1684  return false;
1685  }
1686  if (object.planes.size() < object.plane_poses.size())
1687  {
1688  RCLCPP_ERROR(LOGGER, "More plane poses than planes in collision object message.");
1689  return false;
1690  }
1691 
1692  const int num_shapes = object.primitives.size() + object.meshes.size() + object.planes.size();
1693  shapes.reserve(num_shapes);
1694  shape_poses.reserve(num_shapes);
1695 
1696  utilities::poseMsgToEigen(object.pose, object_pose);
1697 
1698  bool switch_object_pose_and_shape_pose = false;
1699  if (num_shapes == 1)
1700  {
1701  if (moveit::core::isEmpty(object.pose))
1702  {
1703  switch_object_pose_and_shape_pose = true; // If the object pose is not set but the shape pose is,
1704  // use the shape's pose as the object pose.
1705  }
1706  }
1707 
1708  auto append = [&object_pose, &shapes, &shape_poses,
1709  &switch_object_pose_and_shape_pose](shapes::Shape* s, const geometry_msgs::msg::Pose& pose_msg) {
1710  if (!s)
1711  return;
1712  Eigen::Isometry3d pose;
1713  utilities::poseMsgToEigen(pose_msg, pose);
1714  if (!switch_object_pose_and_shape_pose)
1715  {
1716  shape_poses.emplace_back(std::move(pose));
1717  }
1718  else
1719  {
1720  shape_poses.emplace_back(std::move(object_pose));
1721  object_pose = pose;
1722  }
1723  shapes.emplace_back(shapes::ShapeConstPtr(s));
1724  };
1725 
1726  auto treat_shape_vectors = [&append](const auto& shape_vector, // the shape_msgs of each type
1727  const auto& shape_poses_vector, // std::vector<const geometry_msgs::Pose>
1728  const std::string& shape_type) {
1729  if (shape_vector.size() > shape_poses_vector.size())
1730  {
1731  RCLCPP_DEBUG_STREAM(LOGGER, "Number of " << shape_type
1732  << " does not match number of poses "
1733  "in collision object message. Assuming identity.");
1734  for (std::size_t i = 0; i < shape_vector.size(); ++i)
1735  {
1736  if (i >= shape_poses_vector.size())
1737  {
1738  append(shapes::constructShapeFromMsg(shape_vector[i]),
1739  geometry_msgs::msg::Pose()); // Empty shape pose => Identity
1740  }
1741  else
1742  append(shapes::constructShapeFromMsg(shape_vector[i]), shape_poses_vector[i]);
1743  }
1744  }
1745  else
1746  {
1747  for (std::size_t i = 0; i < shape_vector.size(); ++i)
1748  append(shapes::constructShapeFromMsg(shape_vector[i]), shape_poses_vector[i]);
1749  }
1750  };
1751 
1752  treat_shape_vectors(object.primitives, object.primitive_poses, std::string("primitive_poses"));
1753  treat_shape_vectors(object.meshes, object.mesh_poses, std::string("meshes"));
1754  treat_shape_vectors(object.planes, object.plane_poses, std::string("planes"));
1755  return true;
1756 }
1757 
1758 bool PlanningScene::processCollisionObjectAdd(const moveit_msgs::msg::CollisionObject& object)
1759 {
1760  if (!knowsFrameTransform(object.header.frame_id))
1761  {
1762  RCLCPP_ERROR_STREAM(LOGGER, "Unknown frame: " << object.header.frame_id);
1763  return false;
1764  }
1765 
1766  if (object.primitives.empty() && object.meshes.empty() && object.planes.empty())
1767  {
1768  RCLCPP_ERROR(LOGGER, "There are no shapes specified in the collision object message");
1769  return false;
1770  }
1771 
1772  // replace the object if ADD is specified instead of APPEND
1773  if (object.operation == moveit_msgs::msg::CollisionObject::ADD && world_->hasObject(object.id))
1774  world_->removeObject(object.id);
1775 
1776  const Eigen::Isometry3d& world_to_object_header_transform = getFrameTransform(object.header.frame_id);
1777  Eigen::Isometry3d header_to_pose_transform;
1778  std::vector<shapes::ShapeConstPtr> shapes;
1779  EigenSTL::vector_Isometry3d shape_poses;
1780  if (!shapesAndPosesFromCollisionObjectMessage(object, header_to_pose_transform, shapes, shape_poses))
1781  return false;
1782  const Eigen::Isometry3d object_frame_transform = world_to_object_header_transform * header_to_pose_transform;
1783 
1784  world_->addToObject(object.id, object_frame_transform, shapes, shape_poses);
1785 
1786  if (!object.type.key.empty() || !object.type.db.empty())
1787  setObjectType(object.id, object.type);
1788 
1789  // Add subframes
1791  Eigen::Isometry3d subframe_pose;
1792  for (std::size_t i = 0; i < object.subframe_poses.size(); ++i)
1793  {
1794  utilities::poseMsgToEigen(object.subframe_poses[i], subframe_pose);
1795  std::string name = object.subframe_names[i];
1796  subframes[name] = subframe_pose;
1797  }
1798  world_->setSubframesOfObject(object.id, subframes);
1799  return true;
1800 }
1801 
1802 bool PlanningScene::processCollisionObjectRemove(const moveit_msgs::msg::CollisionObject& object)
1803 {
1804  if (object.id.empty())
1805  {
1807  }
1808  else
1809  {
1810  if (!world_->removeObject(object.id))
1811  {
1812  RCLCPP_WARN_STREAM(LOGGER,
1813  "Tried to remove world object '" << object.id << "', but it does not exist in this scene.");
1814  return false;
1815  }
1816 
1817  removeObjectColor(object.id);
1818  removeObjectType(object.id);
1819  }
1820  return true;
1821 }
1822 
1823 bool PlanningScene::processCollisionObjectMove(const moveit_msgs::msg::CollisionObject& object)
1824 {
1825  if (world_->hasObject(object.id))
1826  {
1827  if (!object.primitives.empty() || !object.meshes.empty() || !object.planes.empty())
1828  {
1829  RCLCPP_WARN(LOGGER, "Move operation for object '%s' ignores the geometry specified in the message.",
1830  object.id.c_str());
1831  }
1832 
1833  const Eigen::Isometry3d& world_to_object_header_transform = getFrameTransform(object.header.frame_id);
1834  Eigen::Isometry3d header_to_pose_transform;
1835 
1836  utilities::poseMsgToEigen(object.pose, header_to_pose_transform);
1837 
1838  const Eigen::Isometry3d object_frame_transform = world_to_object_header_transform * header_to_pose_transform;
1839  world_->setObjectPose(object.id, object_frame_transform);
1840  return true;
1841  }
1842 
1843  RCLCPP_ERROR(LOGGER, "World object '%s' does not exist. Cannot move.", object.id.c_str());
1844  return false;
1845 }
1846 
1847 const Eigen::Isometry3d& PlanningScene::getFrameTransform(const std::string& frame_id) const
1848 {
1849  return getFrameTransform(getCurrentState(), frame_id);
1850 }
1851 
1852 const Eigen::Isometry3d& PlanningScene::getFrameTransform(const std::string& frame_id)
1853 {
1854  if (getCurrentState().dirtyLinkTransforms())
1855  {
1856  return getFrameTransform(getCurrentStateNonConst(), frame_id);
1857  }
1858  else
1859  {
1860  return getFrameTransform(getCurrentState(), frame_id);
1861  }
1862 }
1863 
1864 const Eigen::Isometry3d& PlanningScene::getFrameTransform(const moveit::core::RobotState& state,
1865  const std::string& frame_id) const
1866 {
1867  if (!frame_id.empty() && frame_id[0] == '/')
1868  {
1869  // Recursively call itself without the slash in front of frame name
1870  return getFrameTransform(frame_id.substr(1));
1871  }
1872 
1873  bool frame_found;
1874  const Eigen::Isometry3d& t1 = state.getFrameTransform(frame_id, &frame_found);
1875  if (frame_found)
1876  return t1;
1877 
1878  const Eigen::Isometry3d& t2 = getWorld()->getTransform(frame_id, frame_found);
1879  if (frame_found)
1880  return t2;
1881  return getTransforms().Transforms::getTransform(frame_id);
1882 }
1883 
1884 bool PlanningScene::knowsFrameTransform(const std::string& frame_id) const
1885 {
1886  return knowsFrameTransform(getCurrentState(), frame_id);
1887 }
1888 
1889 bool PlanningScene::knowsFrameTransform(const moveit::core::RobotState& state, const std::string& frame_id) const
1890 {
1891  if (!frame_id.empty() && frame_id[0] == '/')
1892  return knowsFrameTransform(frame_id.substr(1));
1893 
1894  if (state.knowsFrameTransform(frame_id))
1895  return true;
1896  if (getWorld()->knowsTransform(frame_id))
1897  return true;
1898  return getTransforms().Transforms::canTransform(frame_id);
1899 }
1900 
1901 bool PlanningScene::hasObjectType(const std::string& object_id) const
1902 {
1903  if (object_types_)
1904  {
1905  if (object_types_->find(object_id) != object_types_->end())
1906  return true;
1907  }
1908  if (parent_)
1909  return parent_->hasObjectType(object_id);
1910  return false;
1911 }
1912 
1913 const object_recognition_msgs::msg::ObjectType& PlanningScene::getObjectType(const std::string& object_id) const
1914 {
1915  if (object_types_)
1916  {
1917  ObjectTypeMap::const_iterator it = object_types_->find(object_id);
1918  if (it != object_types_->end())
1919  return it->second;
1920  }
1921  if (parent_)
1922  return parent_->getObjectType(object_id);
1923  static const object_recognition_msgs::msg::ObjectType EMPTY;
1924  return EMPTY;
1925 }
1926 
1927 void PlanningScene::setObjectType(const std::string& object_id, const object_recognition_msgs::msg::ObjectType& type)
1928 {
1929  if (!object_types_)
1930  object_types_ = std::make_unique<ObjectTypeMap>();
1931  (*object_types_)[object_id] = type;
1932 }
1933 
1934 void PlanningScene::removeObjectType(const std::string& object_id)
1935 {
1936  if (object_types_)
1937  object_types_->erase(object_id);
1938 }
1939 
1941 {
1942  kc.clear();
1943  if (parent_)
1944  parent_->getKnownObjectTypes(kc);
1945  if (object_types_)
1946  {
1947  for (ObjectTypeMap::const_iterator it = object_types_->begin(); it != object_types_->end(); ++it)
1948  kc[it->first] = it->second;
1949  }
1950 }
1951 
1952 bool PlanningScene::hasObjectColor(const std::string& object_id) const
1953 {
1954  if (object_colors_)
1955  {
1956  if (object_colors_->find(object_id) != object_colors_->end())
1957  return true;
1958  }
1959  if (parent_)
1960  return parent_->hasObjectColor(object_id);
1961  return false;
1962 }
1963 
1964 const std_msgs::msg::ColorRGBA& PlanningScene::getObjectColor(const std::string& object_id) const
1965 {
1966  if (object_colors_)
1967  {
1968  ObjectColorMap::const_iterator it = object_colors_->find(object_id);
1969  if (it != object_colors_->end())
1970  return it->second;
1971  }
1972  if (parent_)
1973  return parent_->getObjectColor(object_id);
1974  static const std_msgs::msg::ColorRGBA EMPTY;
1975  return EMPTY;
1976 }
1977 
1979 {
1980  kc.clear();
1981  if (parent_)
1982  parent_->getKnownObjectColors(kc);
1983  if (object_colors_)
1984  {
1985  for (ObjectColorMap::const_iterator it = object_colors_->begin(); it != object_colors_->end(); ++it)
1986  kc[it->first] = it->second;
1987  }
1988 }
1989 
1990 void PlanningScene::setObjectColor(const std::string& object_id, const std_msgs::msg::ColorRGBA& color)
1991 {
1992  if (object_id.empty())
1993  {
1994  RCLCPP_ERROR(LOGGER, "Cannot set color of object with empty object_id.");
1995  return;
1996  }
1997  if (!object_colors_)
1998  object_colors_ = std::make_unique<ObjectColorMap>();
1999  (*object_colors_)[object_id] = color;
2000 }
2001 
2002 void PlanningScene::removeObjectColor(const std::string& object_id)
2003 {
2004  if (object_colors_)
2005  object_colors_->erase(object_id);
2006 }
2007 
2008 bool PlanningScene::isStateColliding(const moveit_msgs::msg::RobotState& state, const std::string& group,
2009  bool verbose) const
2010 {
2013  return isStateColliding(s, group, verbose);
2014 }
2015 
2016 bool PlanningScene::isStateColliding(const std::string& group, bool verbose)
2017 {
2018  if (getCurrentState().dirtyCollisionBodyTransforms())
2019  {
2020  return isStateColliding(getCurrentStateNonConst(), group, verbose);
2021  }
2022  else
2023  {
2024  return isStateColliding(getCurrentState(), group, verbose);
2025  }
2026 }
2027 
2028 bool PlanningScene::isStateColliding(const moveit::core::RobotState& state, const std::string& group, bool verbose) const
2029 {
2031  req.verbose = verbose;
2032  req.group_name = group;
2034  checkCollision(req, res, state);
2035  return res.collision;
2036 }
2037 
2038 bool PlanningScene::isStateFeasible(const moveit_msgs::msg::RobotState& state, bool verbose) const
2039 {
2040  if (state_feasibility_)
2041  {
2044  return state_feasibility_(s, verbose);
2045  }
2046  return true;
2047 }
2048 
2049 bool PlanningScene::isStateFeasible(const moveit::core::RobotState& state, bool verbose) const
2050 {
2051  if (state_feasibility_)
2052  return state_feasibility_(state, verbose);
2053  return true;
2054 }
2055 
2056 bool PlanningScene::isStateConstrained(const moveit_msgs::msg::RobotState& state,
2057  const moveit_msgs::msg::Constraints& constr, bool verbose) const
2058 {
2061  return isStateConstrained(s, constr, verbose);
2062 }
2063 
2065  const moveit_msgs::msg::Constraints& constr, bool verbose) const
2066 {
2067  kinematic_constraints::KinematicConstraintSetPtr ks(
2069  ks->add(constr, getTransforms());
2070  if (ks->empty())
2071  {
2072  return true;
2073  }
2074  else
2075  {
2076  return isStateConstrained(state, *ks, verbose);
2077  }
2078 }
2079 
2080 bool PlanningScene::isStateConstrained(const moveit_msgs::msg::RobotState& state,
2081  const kinematic_constraints::KinematicConstraintSet& constr, bool verbose) const
2082 {
2085  return isStateConstrained(s, constr, verbose);
2086 }
2087 
2089  const kinematic_constraints::KinematicConstraintSet& constr, bool verbose) const
2090 {
2091  return constr.decide(state, verbose).satisfied;
2092 }
2093 
2094 bool PlanningScene::isStateValid(const moveit::core::RobotState& state, const std::string& group, bool verbose) const
2095 {
2096  static const moveit_msgs::msg::Constraints EMP_CONSTRAINTS;
2097  return isStateValid(state, EMP_CONSTRAINTS, group, verbose);
2098 }
2099 
2100 bool PlanningScene::isStateValid(const moveit_msgs::msg::RobotState& state, const std::string& group, bool verbose) const
2101 {
2102  static const moveit_msgs::msg::Constraints EMP_CONSTRAINTS;
2103  return isStateValid(state, EMP_CONSTRAINTS, group, verbose);
2104 }
2105 
2106 bool PlanningScene::isStateValid(const moveit_msgs::msg::RobotState& state, const moveit_msgs::msg::Constraints& constr,
2107  const std::string& group, bool verbose) const
2108 {
2111  return isStateValid(s, constr, group, verbose);
2112 }
2113 
2114 bool PlanningScene::isStateValid(const moveit::core::RobotState& state, const moveit_msgs::msg::Constraints& constr,
2115  const std::string& group, bool verbose) const
2116 {
2117  if (isStateColliding(state, group, verbose))
2118  return false;
2119  if (!isStateFeasible(state, verbose))
2120  return false;
2121  return isStateConstrained(state, constr, verbose);
2122 }
2123 
2125  const kinematic_constraints::KinematicConstraintSet& constr, const std::string& group,
2126  bool verbose) const
2127 {
2128  if (isStateColliding(state, group, verbose))
2129  return false;
2130  if (!isStateFeasible(state, verbose))
2131  return false;
2132  return isStateConstrained(state, constr, verbose);
2133 }
2134 
2135 bool PlanningScene::isPathValid(const moveit_msgs::msg::RobotState& start_state,
2136  const moveit_msgs::msg::RobotTrajectory& trajectory, const std::string& group,
2137  bool verbose, std::vector<std::size_t>* invalid_index) const
2138 {
2139  static const moveit_msgs::msg::Constraints EMP_CONSTRAINTS;
2140  static const std::vector<moveit_msgs::msg::Constraints> EMP_CONSTRAINTS_VECTOR;
2141  return isPathValid(start_state, trajectory, EMP_CONSTRAINTS, EMP_CONSTRAINTS_VECTOR, group, verbose, invalid_index);
2142 }
2143 
2144 bool PlanningScene::isPathValid(const moveit_msgs::msg::RobotState& start_state,
2145  const moveit_msgs::msg::RobotTrajectory& trajectory,
2146  const moveit_msgs::msg::Constraints& path_constraints, const std::string& group,
2147  bool verbose, std::vector<std::size_t>* invalid_index) const
2148 {
2149  static const std::vector<moveit_msgs::msg::Constraints> EMP_CONSTRAINTS_VECTOR;
2150  return isPathValid(start_state, trajectory, path_constraints, EMP_CONSTRAINTS_VECTOR, group, verbose, invalid_index);
2151 }
2152 
2153 bool PlanningScene::isPathValid(const moveit_msgs::msg::RobotState& start_state,
2154  const moveit_msgs::msg::RobotTrajectory& trajectory,
2155  const moveit_msgs::msg::Constraints& path_constraints,
2156  const moveit_msgs::msg::Constraints& goal_constraints, const std::string& group,
2157  bool verbose, std::vector<std::size_t>* invalid_index) const
2158 {
2159  std::vector<moveit_msgs::msg::Constraints> goal_constraints_vector(1, goal_constraints);
2160  return isPathValid(start_state, trajectory, path_constraints, goal_constraints_vector, group, verbose, invalid_index);
2161 }
2162 
2163 bool PlanningScene::isPathValid(const moveit_msgs::msg::RobotState& start_state,
2164  const moveit_msgs::msg::RobotTrajectory& trajectory,
2165  const moveit_msgs::msg::Constraints& path_constraints,
2166  const std::vector<moveit_msgs::msg::Constraints>& goal_constraints,
2167  const std::string& group, bool verbose, std::vector<std::size_t>* invalid_index) const
2168 {
2172  t.setRobotTrajectoryMsg(start, trajectory);
2173  return isPathValid(t, path_constraints, goal_constraints, group, verbose, invalid_index);
2174 }
2175 
2177  const moveit_msgs::msg::Constraints& path_constraints,
2178  const std::vector<moveit_msgs::msg::Constraints>& goal_constraints,
2179  const std::string& group, bool verbose, std::vector<std::size_t>* invalid_index) const
2180 {
2181  bool result = true;
2182  if (invalid_index)
2183  invalid_index->clear();
2185  ks_p.add(path_constraints, getTransforms());
2186  std::size_t n_wp = trajectory.getWayPointCount();
2187  for (std::size_t i = 0; i < n_wp; ++i)
2188  {
2189  const moveit::core::RobotState& st = trajectory.getWayPoint(i);
2190 
2191  bool this_state_valid = true;
2192  if (isStateColliding(st, group, verbose))
2193  this_state_valid = false;
2194  if (!isStateFeasible(st, verbose))
2195  this_state_valid = false;
2196  if (!ks_p.empty() && !ks_p.decide(st, verbose).satisfied)
2197  this_state_valid = false;
2198 
2199  if (!this_state_valid)
2200  {
2201  if (invalid_index)
2202  {
2203  invalid_index->push_back(i);
2204  }
2205  else
2206  {
2207  return false;
2208  }
2209  result = false;
2210  }
2211 
2212  // check goal for last state
2213  if (i + 1 == n_wp && !goal_constraints.empty())
2214  {
2215  bool found = false;
2216  for (const moveit_msgs::msg::Constraints& goal_constraint : goal_constraints)
2217  {
2218  if (isStateConstrained(st, goal_constraint))
2219  {
2220  found = true;
2221  break;
2222  }
2223  }
2224  if (!found)
2225  {
2226  if (verbose)
2227  RCLCPP_INFO(LOGGER, "Goal not satisfied");
2228  if (invalid_index)
2229  invalid_index->push_back(i);
2230  result = false;
2231  }
2232  }
2233  }
2234  return result;
2235 }
2236 
2238  const moveit_msgs::msg::Constraints& path_constraints,
2239  const moveit_msgs::msg::Constraints& goal_constraints, const std::string& group,
2240  bool verbose, std::vector<std::size_t>* invalid_index) const
2241 {
2242  std::vector<moveit_msgs::msg::Constraints> goal_constraints_vector(1, goal_constraints);
2243  return isPathValid(trajectory, path_constraints, goal_constraints_vector, group, verbose, invalid_index);
2244 }
2245 
2247  const moveit_msgs::msg::Constraints& path_constraints, const std::string& group,
2248  bool verbose, std::vector<std::size_t>* invalid_index) const
2249 {
2250  static const std::vector<moveit_msgs::msg::Constraints> EMP_CONSTRAINTS_VECTOR;
2251  return isPathValid(trajectory, path_constraints, EMP_CONSTRAINTS_VECTOR, group, verbose, invalid_index);
2252 }
2253 
2254 bool PlanningScene::isPathValid(const robot_trajectory::RobotTrajectory& trajectory, const std::string& group,
2255  bool verbose, std::vector<std::size_t>* invalid_index) const
2256 {
2257  static const moveit_msgs::msg::Constraints EMP_CONSTRAINTS;
2258  static const std::vector<moveit_msgs::msg::Constraints> EMP_CONSTRAINTS_VECTOR;
2259  return isPathValid(trajectory, EMP_CONSTRAINTS, EMP_CONSTRAINTS_VECTOR, group, verbose, invalid_index);
2260 }
2261 
2262 void PlanningScene::getCostSources(const robot_trajectory::RobotTrajectory& trajectory, std::size_t max_costs,
2263  std::set<collision_detection::CostSource>& costs, double overlap_fraction) const
2264 {
2265  getCostSources(trajectory, max_costs, std::string(), costs, overlap_fraction);
2266 }
2267 
2268 void PlanningScene::getCostSources(const robot_trajectory::RobotTrajectory& trajectory, std::size_t max_costs,
2269  const std::string& group_name, std::set<collision_detection::CostSource>& costs,
2270  double overlap_fraction) const
2271 {
2273  creq.max_cost_sources = max_costs;
2274  creq.group_name = group_name;
2275  creq.cost = true;
2276  std::set<collision_detection::CostSource> cs;
2277  std::set<collision_detection::CostSource> cs_start;
2278  std::size_t n_wp = trajectory.getWayPointCount();
2279  for (std::size_t i = 0; i < n_wp; ++i)
2280  {
2282  checkCollision(creq, cres, trajectory.getWayPoint(i));
2283  cs.insert(cres.cost_sources.begin(), cres.cost_sources.end());
2284  if (i == 0)
2285  cs_start.swap(cres.cost_sources);
2286  }
2287 
2288  if (cs.size() <= max_costs)
2289  {
2290  costs.swap(cs);
2291  }
2292  else
2293  {
2294  costs.clear();
2295  std::size_t i = 0;
2296  for (std::set<collision_detection::CostSource>::iterator it = cs.begin(); i < max_costs; ++it, ++i)
2297  costs.insert(*it);
2298  }
2299 
2300  collision_detection::removeCostSources(costs, cs_start, overlap_fraction);
2301  collision_detection::removeOverlapping(costs, overlap_fraction);
2302 }
2303 
2304 void PlanningScene::getCostSources(const moveit::core::RobotState& state, std::size_t max_costs,
2305  std::set<collision_detection::CostSource>& costs) const
2306 {
2307  getCostSources(state, max_costs, std::string(), costs);
2308 }
2309 
2310 void PlanningScene::getCostSources(const moveit::core::RobotState& state, std::size_t max_costs,
2311  const std::string& group_name,
2312  std::set<collision_detection::CostSource>& costs) const
2313 {
2315  creq.max_cost_sources = max_costs;
2316  creq.group_name = group_name;
2317  creq.cost = true;
2319  checkCollision(creq, cres, state);
2320  cres.cost_sources.swap(costs);
2321 }
2322 
2323 void PlanningScene::printKnownObjects(std::ostream& out) const
2324 {
2325  const std::vector<std::string>& objects = getWorld()->getObjectIds();
2326  std::vector<const moveit::core::AttachedBody*> attached_bodies;
2327  getCurrentState().getAttachedBodies(attached_bodies);
2328 
2329  // Output
2330  out << "-----------------------------------------\n";
2331  out << "PlanningScene Known Objects:\n";
2332  out << " - Collision World Objects:\n ";
2333  for (const std::string& object : objects)
2334  {
2335  out << "\t- " << object << '\n';
2336  }
2337 
2338  out << " - Attached Bodies:\n";
2339  for (const moveit::core::AttachedBody* attached_body : attached_bodies)
2340  {
2341  out << "\t- " << attached_body->getName() << '\n';
2342  }
2343  out << "-----------------------------------------\n";
2344 }
2345 
2346 } // end of namespace planning_scene
Definition of a structure for the allowed collision matrix. All elements in the collision world are r...
void getMessage(moveit_msgs::msg::AllowedCollisionMatrix &msg) const
Get the allowed collision matrix as a message.
World::ObjectConstPtr ObjectConstPtr
std::function< void(const ObjectConstPtr &, Action)> ObserverCallbackFn
Definition: world.h:301
A class that contains many different constraints, and can check RobotState *versus the full set....
bool empty() const
Returns whether or not there are any constraints in the set.
bool add(const moveit_msgs::msg::Constraints &c, const moveit::core::Transforms &tf)
Add all known constraints.
ConstraintEvaluationResult decide(const moveit::core::RobotState &state, bool verbose=false) const
Determines whether all constraints are satisfied by state, returning a single evaluation result.
This may be thrown during construction of objects if errors occur.
Definition: exceptions.h:46
Object defining bodies that can be attached to robot links.
Definition: attached_body.h:58
const std::string & getAttachedLinkName() const
Get the name of the link this body is attached to.
Definition: attached_body.h:92
const std::set< std::string > & getTouchLinks() const
Get the links that the attached body is allowed to touch.
const trajectory_msgs::msg::JointTrajectory & getDetachPosture() const
Return the posture that is necessary for the object to be released, (if any). This is useful for exam...
const moveit::core::FixedTransformsMap & getSubframes() const
Get subframes of this object (relative to the object pose). The returned transforms are guaranteed to...
const std::vector< shapes::ShapeConstPtr > & getShapes() const
Get the shapes that make up this attached body.
const Eigen::Isometry3d & getPose() const
Get the pose of the attached body relative to the parent link.
Definition: attached_body.h:80
const EigenSTL::vector_Isometry3d & getShapePoses() const
Get the shape poses (the transforms to the shapes of this body, relative to the pose)....
A link from the robot. Contains the constant transform applied to the link and its geometry.
Definition: link_model.h:72
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition: robot_state.h:90
void getAttachedBodies(std::vector< const AttachedBody * > &attached_bodies) const
Get all bodies attached to the model corresponding to this state.
const Eigen::Isometry3d & getFrameTransform(const std::string &frame_id, bool *frame_found=nullptr)
Get the transformation matrix from the model frame (root of model) to the frame identified by frame_i...
void update(bool force=false)
Update all transforms.
bool knowsFrameTransform(const std::string &frame_id) const
Check if a transformation matrix from the model frame (root of model) to frame frame_id is known.
Provides an implementation of a snapshot of a transform tree that can be easily queried for transform...
Definition: transforms.h:59
Transforms(const Transforms &)=delete
Transforms cannot be copy-constructed.
void copyTransforms(std::vector< geometry_msgs::msg::TransformStamped > &transforms) const
Get a vector of all the transforms as ROS messages.
Definition: transforms.cpp:172
This class maintains the representation of the environment as seen by a planning instance....
void getAttachedCollisionObjectMsgs(std::vector< moveit_msgs::msg::AttachedCollisionObject > &attached_collision_objs) const
Construct a vector of messages (attached_collision_objects) with the attached collision object data f...
bool usePlanningSceneMsg(const moveit_msgs::msg::PlanningScene &scene)
Call setPlanningSceneMsg() or setPlanningSceneDiffMsg() depending on how the is_diff member of the me...
void getPlanningSceneMsg(moveit_msgs::msg::PlanningScene &scene) const
Construct a message (scene) with all the necessary data so that the scene can be later reconstructed ...
collision_detection::AllowedCollisionMatrix & getAllowedCollisionMatrixNonConst()
Get the allowed collision matrix.
bool isStateFeasible(const moveit_msgs::msg::RobotState &state, bool verbose=false) const
Check if a given state is feasible, in accordance to the feasibility predicate specified by setStateF...
static PlanningScenePtr clone(const PlanningSceneConstPtr &scene)
Clone a planning scene. Even if the scene scene depends on a parent, the cloned scene will not.
bool processCollisionObjectMsg(const moveit_msgs::msg::CollisionObject &object)
void setCurrentState(const moveit_msgs::msg::RobotState &state)
Set the current robot state to be state. If not all joint values are specified, the previously mainta...
moveit::core::RobotStatePtr getCurrentStateUpdated(const moveit_msgs::msg::RobotState &update) const
Get a copy of the current state with components overwritten by the state message update.
const std::string & getName() const
Get the name of the planning scene. This is empty by default.
const Eigen::Isometry3d & getFrameTransform(const std::string &id) const
Get the transform corresponding to the frame id. This will be known if id is a link name,...
const object_recognition_msgs::msg::ObjectType & getObjectType(const std::string &id) const
void getObjectColorMsgs(std::vector< moveit_msgs::msg::ObjectColor > &object_colors) const
Construct a vector of messages (object_colors) with the colors of the objects from the planning_scene...
const collision_detection::CollisionEnvPtr & getCollisionEnvNonConst()
Get the representation of the collision robot This can be used to set padding and link scale on the a...
bool getCollisionObjectMsg(moveit_msgs::msg::CollisionObject &collision_obj, const std::string &ns) const
Construct a message (collision_object) with the collision object data from the planning_scene for the...
const std::string & getPlanningFrame() const
Get the frame in which planning is performed.
bool isPathValid(const moveit_msgs::msg::RobotState &start_state, const moveit_msgs::msg::RobotTrajectory &trajectory, const std::string &group="", bool verbose=false, std::vector< std::size_t > *invalid_index=nullptr) const
Check if a given path is valid. Each state is checked for validity (collision avoidance and feasibili...
void checkCollision(const collision_detection::CollisionRequest &req, collision_detection::CollisionResult &res)
Check whether the current state is in collision, and if needed, updates the collision transforms of t...
bool knowsFrameTransform(const std::string &id) const
Check if a transform to the frame id is known. This will be known if id is a link name,...
void getCollisionObjectMsgs(std::vector< moveit_msgs::msg::CollisionObject > &collision_objs) const
Construct a vector of messages (collision_objects) with the collision object data for all objects in ...
moveit::core::RobotState & getCurrentStateNonConst()
Get the state at which the robot is assumed to be.
bool isStateValid(const moveit_msgs::msg::RobotState &state, const std::string &group="", bool verbose=false) const
Check if a given state is valid. This means checking for collisions and feasibility....
void checkCollisionUnpadded(const collision_detection::CollisionRequest &req, collision_detection::CollisionResult &res)
Check whether the current state is in collision, but use a collision_detection::CollisionRobot instan...
void processOctomapMsg(const octomap_msgs::msg::OctomapWithPose &map)
void getPlanningSceneDiffMsg(moveit_msgs::msg::PlanningScene &scene) const
Fill the message scene with the differences between this instance of PlanningScene with respect to th...
void getKnownObjectColors(ObjectColorMap &kc) const
bool loadGeometryFromStream(std::istream &in)
Load the geometry of the planning scene from a stream.
PlanningScenePtr diff() const
Return a new child PlanningScene that uses this one as parent.
const collision_detection::CollisionEnvConstPtr & getCollisionEnvUnpadded() const
Get the active collision detector for the robot.
bool setPlanningSceneDiffMsg(const moveit_msgs::msg::PlanningScene &scene)
Apply changes to this planning scene as diffs, even if the message itself is not marked as being a di...
bool processAttachedCollisionObjectMsg(const moveit_msgs::msg::AttachedCollisionObject &object)
bool processPlanningSceneWorldMsg(const moveit_msgs::msg::PlanningSceneWorld &world)
void setObjectColor(const std::string &id, const std_msgs::msg::ColorRGBA &color)
const collision_detection::AllowedCollisionMatrix & getAllowedCollisionMatrix() const
Get the allowed collision matrix.
void getKnownObjectTypes(ObjectTypeMap &kc) const
PlanningScene(const PlanningScene &)=delete
PlanningScene cannot be copy-constructed.
bool hasObjectColor(const std::string &id) const
bool getOctomapMsg(octomap_msgs::msg::OctomapWithPose &octomap) const
Construct a message (octomap) with the octomap data from the planning_scene.
void clearDiffs()
Clear the diffs accumulated for this planning scene, with respect to: the parent PlanningScene (if it...
void setAttachedBodyUpdateCallback(const moveit::core::AttachedBodyCallback &callback)
Set the callback to be triggered when changes are made to the current scene state.
void setObjectType(const std::string &id, const object_recognition_msgs::msg::ObjectType &type)
void printKnownObjects(std::ostream &out=std::cout) const
Outputs debug information about the planning scene contents.
const std::string getCollisionDetectorName() const
void pushDiffs(const PlanningScenePtr &scene)
If there is a parent specified for this scene, then the diffs with respect to that parent are applied...
bool shapesAndPosesFromCollisionObjectMessage(const moveit_msgs::msg::CollisionObject &object, Eigen::Isometry3d &object_pose_in_header_frame, std::vector< shapes::ShapeConstPtr > &shapes, EigenSTL::vector_Isometry3d &shape_poses)
Takes the object message and returns the object pose, shapes and shape poses. If the object pose is e...
bool hasObjectType(const std::string &id) const
void decoupleParent()
Make sure that all the data maintained in this scene is local. All unmodified data is copied from the...
void allocateCollisionDetector(const collision_detection::CollisionDetectorAllocatorPtr &allocator)
Allocate a new collision detector and replace the previous one if there was any.
void getCostSources(const robot_trajectory::RobotTrajectory &trajectory, std::size_t max_costs, std::set< collision_detection::CostSource > &costs, double overlap_fraction=0.9) const
Get the top max_costs cost sources for a specified trajectory. The resulting costs are stored in cost...
const moveit::core::RobotState & getCurrentState() const
Get the state at which the robot is assumed to be.
void removeAllCollisionObjects()
Clear all collision objects in planning scene.
const collision_detection::WorldConstPtr & getWorld() const
Get the representation of the world.
bool isStateColliding(const std::string &group="", bool verbose=false)
Check if the current state is in collision (with the environment or self collision)....
const moveit::core::Transforms & getTransforms() const
Get the set of fixed transforms from known frames to the planning frame.
bool isStateConstrained(const moveit_msgs::msg::RobotState &state, const moveit_msgs::msg::Constraints &constr, bool verbose=false) const
Check if a given state satisfies a set of constraints.
bool setPlanningSceneMsg(const moveit_msgs::msg::PlanningScene &scene)
Set this instance of a planning scene to be the same as the one serialized in the scene message,...
bool getAttachedCollisionObjectMsg(moveit_msgs::msg::AttachedCollisionObject &attached_collision_obj, const std::string &ns) const
Construct a message (attached_collision_object) with the attached collision object data from the plan...
void saveGeometryToStream(std::ostream &out) const
Save the geometry of the planning scene to a stream, as plain text.
void getCollidingLinks(std::vector< std::string > &links)
Get the names of the links that are involved in collisions for the current state.
const moveit::core::RobotModelConstPtr & getRobotModel() const
Get the kinematic model for which the planning scene is maintained.
moveit::core::Transforms & getTransformsNonConst()
Get the set of fixed transforms from known frames to the planning frame.
void checkSelfCollision(const collision_detection::CollisionRequest &req, collision_detection::CollisionResult &res)
Check whether the current state is in self collision.
const collision_detection::CollisionEnvConstPtr & getCollisionEnv() const
Get the active collision environment.
void removeObjectColor(const std::string &id)
static const std::string OCTOMAP_NS
static const std::string DEFAULT_SCENE_NAME
void setCollisionObjectUpdateCallback(const collision_detection::World::ObserverCallbackFn &callback)
Set the callback to be triggered when changes are made to the current scene world.
void getCollidingPairs(collision_detection::CollisionResult::ContactMap &contacts)
Get the names of the links that are involved in collisions for the current state. Update the link tra...
const std_msgs::msg::ColorRGBA & getObjectColor(const std::string &id) const
friend struct CollisionDetector
Enumerates the available collision detectors.
void processOctomapPtr(const std::shared_ptr< const octomap::OcTree > &octree, const Eigen::Isometry3d &t)
void removeObjectType(const std::string &id)
bool isFixedFrame(const std::string &frame) const override
Check whether a frame stays constant as the state of the robot model changes. This is true for any tr...
const Eigen::Isometry3d & getTransform(const std::string &from_frame) const override
Get transform for from_frame (w.r.t target frame)
SceneTransforms(const PlanningScene *scene)
bool canTransform(const std::string &from_frame) const override
Check whether data can be transformed from a particular frame.
Maintain a sequence of waypoints and the time durations between these waypoints.
RobotTrajectory & setRobotTrajectoryMsg(const moveit::core::RobotState &reference_state, const trajectory_msgs::msg::JointTrajectory &trajectory)
Copy the content of the trajectory message into this class. The trajectory message itself is not requ...
const moveit::core::RobotState & getWayPoint(std::size_t index) const
@ ROBOT_LINK
A link on the robot.
std::shared_ptr< OccMapTree > OccMapTreePtr
void removeCostSources(std::set< CostSource > &cost_sources, const std::set< CostSource > &cost_sources_to_remove, double overlap_fraction)
void removeOverlapping(std::set< CostSource > &cost_sources, double overlap_fraction)
void robotStateToRobotStateMsg(const RobotState &state, moveit_msgs::msg::RobotState &robot_state, bool copy_attached_bodies=true)
Convert a MoveIt robot state to a robot state message.
bool isEmpty(const moveit_msgs::msg::PlanningScene &msg)
Check if a message includes any information about a planning scene, or whether it is empty.
void attachedBodiesToAttachedCollisionObjectMsgs(const std::vector< const AttachedBody * > &attached_bodies, std::vector< moveit_msgs::msg::AttachedCollisionObject > &attached_collision_objs)
Convert AttachedBodies to AttachedCollisionObjects.
std::map< std::string, Eigen::Isometry3d, std::less< std::string >, Eigen::aligned_allocator< std::pair< const std::string, Eigen::Isometry3d > > > FixedTransformsMap
Map frame names to the transformation matrix that can transform objects from the frame name to the pl...
Definition: transforms.h:53
std::function< void(AttachedBody *body, bool attached)> AttachedBodyCallback
Definition: attached_body.h:51
bool robotStateMsgToRobotState(const Transforms &tf, const moveit_msgs::msg::RobotState &robot_state, RobotState &state, bool copy_attached_bodies=true)
Convert a robot state msg (with accompanying extra transforms) to a MoveIt robot state.
void update(moveit::core::RobotState *self, bool force, std::string &category)
Definition: robot_state.cpp:47
void poseMsgToEigen(const geometry_msgs::msg::Pose &msg, Eigen::Isometry3d &out)
void writePoseToText(std::ostream &out, const Eigen::Isometry3d &pose)
Write a pose to text.
bool readPoseFromText(std::istream &in, Eigen::Isometry3d &pose)
Read a pose from text.
This namespace includes the central class for representing planning contexts.
std::map< std::string, std_msgs::msg::ColorRGBA > ObjectColorMap
A map from object names (e.g., attached bodies, collision objects) to their colors.
std::map< std::string, object_recognition_msgs::msg::ObjectType > ObjectTypeMap
A map from object names (e.g., attached bodies, collision objects) to their types.
collision_detection::OccMapTreePtr createOctomap(const octomap_msgs::msg::Octomap &map)
std::string append(const std::string &left, const std::string &right)
name
Definition: setup.py:7
Definition: world.h:49
Representation of a collision checking request.
std::string group_name
The group name to check collisions for (optional; if empty, assume the complete robot)....
bool verbose
Flag indicating whether information about detected collisions should be reported.
std::size_t max_cost_sources
When costs are computed, this value defines how many of the top cost sources should be returned.
bool contacts
If true, compute contacts. Otherwise only a binary collision yes/no is reported.
bool cost
If true, a collision cost is computed.
std::size_t max_contacts
Overall maximum number of contacts to compute.
std::size_t max_contacts_per_pair
Maximum number of contacts to compute per pair of bodies (multiple bodies may be in contact at differ...
Representation of a collision checking result.
ContactMap contacts
A map returning the pairs of body ids in contact, plus their contact details.
std::map< std::pair< std::string, std::string >, std::vector< Contact > > ContactMap
std::set< CostSource > cost_sources
These are the individual cost sources when costs are computed.
bool collision
True if collision was found, false otherwise.
Definition of a contact point.
std::string body_name_2
The id of the second body involved in the contact.
std::string body_name_1
The id of the first body involved in the contact.
BodyType body_type_1
The type of the first body involved in the contact.
BodyType body_type_2
The type of the second body involved in the contact.
A representation of an object.
Definition: world.h:79
moveit::core::FixedTransformsMap subframe_poses_
Transforms from the object pose to subframes on the object. Use them to define points of interest on ...
Definition: world.h:112
Eigen::Isometry3d pose_
The object's pose. All shapes and subframes are defined relative to this frame. This frame is returne...
Definition: world.h:91
EIGEN_MAKE_ALIGNED_OPERATOR_NEW std::string id_
The id for this object.
Definition: world.h:87
EigenSTL::vector_Isometry3d shape_poses_
The poses of the corresponding entries in shapes_, relative to the object pose.
Definition: world.h:101
std::vector< shapes::ShapeConstPtr > shapes_
All the shapes making up this object.
Definition: world.h:96
bool satisfied
Whether or not the constraint or constraints were satisfied.