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