moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
world.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2013, 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: Acorn Pooley, Ioan Sucan */
36
38#include <geometric_shapes/check_isometry.h>
39#include <rclcpp/logger.hpp>
40#include <rclcpp/logging.hpp>
42
43namespace collision_detection
44{
45namespace
46{
47rclcpp::Logger getLogger()
48{
49 return moveit::getLogger("moveit.core.collision_detection_world");
50}
51} // namespace
52
54{
55}
56
57World::World(const World& other)
58{
59 objects_ = other.objects_;
60}
61
63{
64 while (!observers_.empty())
65 removeObserver(observers_.front());
66}
67
68inline void World::addToObjectInternal(const ObjectPtr& obj, const shapes::ShapeConstPtr& shape,
69 const Eigen::Isometry3d& shape_pose)
70{
71 obj->shapes_.push_back(shape);
72 ASSERT_ISOMETRY(shape_pose) // unsanitized input, could contain a non-isometry
73 obj->shape_poses_.push_back(shape_pose);
74 obj->global_shape_poses_.push_back(obj->pose_ * shape_pose);
75}
76
77void World::addToObject(const std::string& object_id, const Eigen::Isometry3d& pose,
78 const std::vector<shapes::ShapeConstPtr>& shapes,
79 const EigenSTL::vector_Isometry3d& shape_poses)
80{
81 if (shapes.size() != shape_poses.size())
82 {
83 RCLCPP_ERROR(getLogger(),
84 "Number of shapes and number of poses do not match. Not adding this object to collision world.");
85 return;
86 }
87
88 if (shapes.empty())
89 return;
90
91 int action = ADD_SHAPE;
92
93 ObjectPtr& obj = objects_[object_id];
94 if (!obj)
95 {
96 obj = std::make_shared<Object>(object_id);
97 action |= CREATE;
98 obj->pose_ = pose;
99 }
100 else
101 ensureUnique(obj);
102
103 for (std::size_t i = 0; i < shapes.size(); ++i)
104 addToObjectInternal(obj, shapes[i], shape_poses[i]);
105
106 notify(obj, Action(action));
107}
108
109std::vector<std::string> World::getObjectIds() const
110{
111 std::vector<std::string> ids;
112 ids.reserve(objects_.size());
113 for (const auto& object : objects_)
114 ids.push_back(object.first);
115 return ids;
116}
117
118World::ObjectConstPtr World::getObject(const std::string& object_id) const
119{
120 const auto it = objects_.find(object_id);
121 if (it == objects_.end())
122 {
123 return ObjectConstPtr();
124 }
125 else
126 {
127 return it->second;
128 }
129}
130
131void World::ensureUnique(ObjectPtr& obj)
132{
133 if (obj && !obj.unique())
134 obj = std::make_shared<Object>(*obj);
135}
136
137bool World::hasObject(const std::string& object_id) const
138{
139 return objects_.find(object_id) != objects_.end();
140}
141
142bool World::knowsTransform(const std::string& name) const
143{
144 // Check object names first
145 const std::map<std::string, ObjectPtr>::const_iterator it = objects_.find(name);
146 if (it != objects_.end())
147 {
148 return true;
149 }
150 else // Then objects' subframes
151 {
152 for (const std::pair<const std::string, ObjectPtr>& object : objects_)
153 {
154 // if "object name/" matches start of object_id, we found the matching object
155 // rfind searches name for object.first in the first index (returns 0 if found)
156 if (name.rfind(object.first, 0) == 0 && name[object.first.length()] == '/')
157 {
158 return object.second->global_subframe_poses_.find(name.substr(object.first.length() + 1)) !=
159 object.second->global_subframe_poses_.end();
160 }
161 }
162 }
163 return false;
164}
165
166const Eigen::Isometry3d& World::getTransform(const std::string& name) const
167{
168 bool found;
169 const Eigen::Isometry3d& result = getTransform(name, found);
170 if (!found)
171 throw std::runtime_error("No transform found with name: " + name);
172 return result;
173}
174
175const Eigen::Isometry3d& World::getTransform(const std::string& name, bool& frame_found) const
176{
177 // assume found
178 frame_found = true;
179
180 const std::map<std::string, ObjectPtr>::const_iterator it = objects_.find(name);
181 if (it != objects_.end())
182 {
183 return it->second->pose_;
184 }
185 else // Search within subframes
186 {
187 for (const std::pair<const std::string, ObjectPtr>& object : objects_)
188 {
189 // if "object name/" matches start of object_id, we found the matching object
190 // rfind searches name for object.first in the first index (returns 0 if found)
191 if (name.rfind(object.first, 0) == 0 && name[object.first.length()] == '/')
192 {
193 const auto it = object.second->global_subframe_poses_.find(name.substr(object.first.length() + 1));
194 if (it != object.second->global_subframe_poses_.end())
195 {
196 return it->second;
197 }
198 }
199 }
200 }
201
202 // we need a persisting isometry for the API
203 static const Eigen::Isometry3d IDENTITY_TRANSFORM = Eigen::Isometry3d::Identity();
204 frame_found = false;
205 return IDENTITY_TRANSFORM;
206}
207
208const Eigen::Isometry3d& World::getGlobalShapeTransform(const std::string& object_id, const int shape_index) const
209{
210 const auto it = objects_.find(object_id);
211 if (it != objects_.end())
212 {
213 return it->second->global_shape_poses_[shape_index];
214 }
215 else
216 {
217 RCLCPP_ERROR_STREAM(getLogger(), "Could not find global shape transform for object " << object_id);
218 static const Eigen::Isometry3d IDENTITY_TRANSFORM = Eigen::Isometry3d::Identity();
219 return IDENTITY_TRANSFORM;
220 }
221}
222
223const EigenSTL::vector_Isometry3d& World::getGlobalShapeTransforms(const std::string& object_id) const
224{
225 const auto it = objects_.find(object_id);
226 if (it != objects_.end())
227 {
228 return it->second->global_shape_poses_;
229 }
230 else
231 {
232 RCLCPP_ERROR_STREAM(getLogger(), "Could not find global shape transforms for object " << object_id);
233 static const EigenSTL::vector_Isometry3d IDENTITY_TRANSFORM_VECTOR;
234 return IDENTITY_TRANSFORM_VECTOR;
235 }
236}
237
238bool World::moveShapeInObject(const std::string& object_id, const shapes::ShapeConstPtr& shape,
239 const Eigen::Isometry3d& shape_pose)
240{
241 const auto it = objects_.find(object_id);
242 if (it != objects_.end())
243 {
244 const unsigned int n = it->second->shapes_.size();
245 for (unsigned int i = 0; i < n; ++i)
246 {
247 if (it->second->shapes_[i] == shape)
248 {
249 ensureUnique(it->second);
250 ASSERT_ISOMETRY(shape_pose) // unsanitized input, could contain a non-isometry
251 it->second->shape_poses_[i] = shape_pose;
252 it->second->global_shape_poses_[i] = it->second->pose_ * shape_pose;
253
254 notify(it->second, MOVE_SHAPE);
255 return true;
256 }
257 }
258 }
259 return false;
260}
261
262bool World::moveShapesInObject(const std::string& object_id, const EigenSTL::vector_Isometry3d& shape_poses)
263{
264 auto it = objects_.find(object_id);
265 if (it != objects_.end())
266 {
267 if (shape_poses.size() == it->second->shapes_.size())
268 {
269 for (std::size_t i = 0; i < shape_poses.size(); ++i)
270 {
271 ASSERT_ISOMETRY(shape_poses[i]) // unsanitized input, could contain a non-isometry
272 it->second->shape_poses_[i] = shape_poses[i];
273 it->second->global_shape_poses_[i] = it->second->pose_ * shape_poses[i];
274 }
275 notify(it->second, MOVE_SHAPE);
276 return true;
277 }
278 }
279 return false;
280}
281
282bool World::moveObject(const std::string& object_id, const Eigen::Isometry3d& transform)
283{
284 const auto it = objects_.find(object_id);
285 if (it == objects_.end())
286 return false;
287 if (transform.isApprox(Eigen::Isometry3d::Identity()))
288 return true; // object already at correct location
289
290 ASSERT_ISOMETRY(transform) // unsanitized input, could contain a non-isometry
291 return setObjectPose(object_id, transform * it->second->pose_);
292}
293
294bool World::setObjectPose(const std::string& object_id, const Eigen::Isometry3d& pose)
295{
296 ASSERT_ISOMETRY(pose); // unsanitized input, could contain a non-isometry
297 ObjectPtr& obj = objects_[object_id];
298 int action;
299 if (!obj)
300 {
301 obj = std::make_shared<Object>(object_id);
302 action = CREATE;
303 }
304 else
305 {
306 ensureUnique(obj);
307 action = obj->shapes_.empty() ? 0 : MOVE_SHAPE;
308 }
309
310 obj->pose_ = pose;
311 updateGlobalPosesInternal(obj);
312 notify(obj, Action(action));
313 return true;
314}
315
316bool World::removeShapeFromObject(const std::string& object_id, const shapes::ShapeConstPtr& shape)
317{
318 const auto it = objects_.find(object_id);
319 if (it != objects_.end())
320 {
321 const unsigned int n = it->second->shapes_.size();
322 for (unsigned int i = 0; i < n; ++i)
323 {
324 if (it->second->shapes_[i] == shape)
325 {
326 ensureUnique(it->second);
327 it->second->shapes_.erase(it->second->shapes_.begin() + i);
328 it->second->shape_poses_.erase(it->second->shape_poses_.begin() + i);
329 it->second->global_shape_poses_.erase(it->second->global_shape_poses_.begin() + i);
330
331 if (it->second->shapes_.empty())
332 {
333 notify(it->second, DESTROY);
334 objects_.erase(it);
335 }
336 else
337 {
338 notify(it->second, REMOVE_SHAPE);
339 }
340 return true;
341 }
342 }
343 }
344 return false;
345}
346
347bool World::removeObject(const std::string& object_id)
348{
349 const auto it = objects_.find(object_id);
350 if (it != objects_.end())
351 {
352 notify(it->second, DESTROY);
353 objects_.erase(it);
354 return true;
355 }
356 return false;
357}
358
360{
361 notifyAll(DESTROY);
362 objects_.clear();
363}
364
365bool World::setSubframesOfObject(const std::string& object_id, const moveit::core::FixedTransformsMap& subframe_poses)
366{
367 const auto obj_pair = objects_.find(object_id);
368 if (obj_pair == objects_.end())
369 {
370 return false;
371 }
372 for (const auto& t : subframe_poses)
373 {
374 ASSERT_ISOMETRY(t.second) // unsanitized input, could contain a non-isometry
375 }
376 obj_pair->second->subframe_poses_ = subframe_poses;
377 obj_pair->second->global_subframe_poses_ = subframe_poses;
378 updateGlobalPosesInternal(obj_pair->second, false, true);
379 return true;
380}
381
382void World::updateGlobalPosesInternal(ObjectPtr& obj, bool update_shape_poses, bool update_subframe_poses)
383{
384 // Update global shape poses
385 if (update_shape_poses)
386 {
387 for (unsigned int i = 0; i < obj->global_shape_poses_.size(); ++i)
388 obj->global_shape_poses_[i] = obj->pose_ * obj->shape_poses_[i];
389 }
390
391 // Update global subframe poses
392 if (update_subframe_poses)
393 {
394 for (auto it_global_pose = obj->global_subframe_poses_.begin(), it_local_pose = obj->subframe_poses_.begin(),
395 end_poses = obj->global_subframe_poses_.end();
396 it_global_pose != end_poses; ++it_global_pose, ++it_local_pose)
397 {
398 it_global_pose->second = obj->pose_ * it_local_pose->second;
399 }
400 }
401}
402
404{
405 const auto o = new Observer(callback);
406 observers_.push_back(o);
407 return ObserverHandle(o);
408}
409
411{
412 for (auto obs = observers_.begin(); obs != observers_.end(); ++obs)
413 {
414 if (*obs == observer_handle.observer_)
415 {
416 delete *obs;
417 observers_.erase(obs);
418 return;
419 }
420 }
421}
422
423void World::notifyAll(Action action)
424{
425 for (std::map<std::string, ObjectPtr>::const_iterator it = objects_.begin(); it != objects_.end(); ++it)
426 notify(it->second, action);
427}
428
429void World::notify(const ObjectConstPtr& obj, Action action)
430{
431 for (Observer* observer : observers_)
432 observer->callback_(obj, action);
433}
434
435void World::notifyObserverAllObjects(const ObserverHandle observer_handle, Action action) const
436{
437 for (auto observer : observers_)
438 {
439 if (observer == observer_handle.observer_)
440 {
441 // call the callback for each object
442 for (const auto& object : objects_)
443 observer->callback_(object.second, action);
444 break;
445 }
446 }
447}
448
449} // end of namespace collision_detection
Represents an action that occurred on an object in the world. Several bits may be set indicating seve...
Definition world.hpp:268
Maintain a representation of the environment.
Definition world.hpp:59
const Eigen::Isometry3d & getTransform(const std::string &name) const
Get the transform to an object or subframe with given name. If name does not exist,...
Definition world.cpp:166
void removeObserver(const ObserverHandle observer_handle)
remove a notifier callback
Definition world.cpp:410
std::function< void(const ObjectConstPtr &, Action)> ObserverCallbackFn
Definition world.hpp:304
bool hasObject(const std::string &object_id) const
Check if a particular object exists in the collision world.
Definition world.cpp:137
bool removeObject(const std::string &object_id)
Remove a particular object. If there are no external pointers to the corresponding instance of Object...
Definition world.cpp:347
bool moveShapeInObject(const std::string &object_id, const shapes::ShapeConstPtr &shape, const Eigen::Isometry3d &shape_pose)
Update the pose of a shape in an object. Shape equality is verified by comparing pointers....
Definition world.cpp:238
void notifyObserverAllObjects(const ObserverHandle observer_handle, Action action) const
Definition world.cpp:435
bool removeShapeFromObject(const std::string &object_id, const shapes::ShapeConstPtr &shape)
Remove shape from object. Shape equality is verified by comparing pointers. Ownership of the object i...
Definition world.cpp:316
const Eigen::Isometry3d & getGlobalShapeTransform(const std::string &object_id, int shape_index) const
Get the global transform to a shape of an object with multiple shapes. shape_index is the index of th...
Definition world.cpp:208
void addToObject(const std::string &object_id, const Eigen::Isometry3d &pose, const std::vector< shapes::ShapeConstPtr > &shapes, const EigenSTL::vector_Isometry3d &shape_poses)
Add a pose and shapes to an object in the map. This function makes repeated calls to addToObjectInter...
Definition world.cpp:77
World()
Constructor.
Definition world.cpp:53
bool moveShapesInObject(const std::string &object_id, const EigenSTL::vector_Isometry3d &shape_poses)
Update the pose of all shapes in an object. Shape size is verified. Returns true on success.
Definition world.cpp:262
bool moveObject(const std::string &object_id, const Eigen::Isometry3d &transform)
Move the object pose (thus moving all shapes and subframes in the object) according to the given tran...
Definition world.cpp:282
ObserverHandle addObserver(const ObserverCallbackFn &callback)
register a callback function for notification of changes. callback will be called right after any cha...
Definition world.cpp:403
bool setObjectPose(const std::string &object_id, const Eigen::Isometry3d &pose)
Set the pose of an object. The pose is specified in the world frame.
Definition world.cpp:294
bool setSubframesOfObject(const std::string &object_id, const moveit::core::FixedTransformsMap &subframe_poses)
Set subframes on an object. The frames are relative to the object pose.
Definition world.cpp:365
bool knowsTransform(const std::string &name) const
Check if an object or subframe with given name exists in the collision world. A subframe name needs t...
Definition world.cpp:142
void clearObjects()
Clear all objects. If there are no other pointers to corresponding instances of Objects,...
Definition world.cpp:359
ObjectConstPtr getObject(const std::string &object_id) const
Get a particular object.
Definition world.cpp:118
const EigenSTL::vector_Isometry3d & getGlobalShapeTransforms(const std::string &object_id) const
Get the global transforms to the shapes of an object. This function is used to construct the collisio...
Definition world.cpp:223
std::vector< std::string > getObjectIds() const
Get the list of Object ids.
Definition world.cpp:109
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...
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition logger.cpp:79