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