moveit2
The MoveIt Motion Planning Framework for ROS 2.
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>
41 #include <moveit/utils/logger.hpp>
42 
43 namespace collision_detection
44 {
45 namespace
46 {
47 rclcpp::Logger getLogger()
48 {
49  return moveit::getLogger("collision_detection_world");
50 }
51 } // namespace
52 
54 {
55 }
56 
57 World::World(const World& other)
58 {
59  objects_ = other.objects_;
60 }
61 
63 {
64  while (!observers_.empty())
65  removeObserver(observers_.front());
66 }
67 
68 inline 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 
77 void 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 
109 std::vector<std::string> World::getObjectIds() const
110 {
111  std::vector<std::string> ids;
112  for (const auto& object : objects_)
113  ids.push_back(object.first);
114  return ids;
115 }
116 
117 World::ObjectConstPtr World::getObject(const std::string& object_id) const
118 {
119  const auto it = objects_.find(object_id);
120  if (it == objects_.end())
121  {
122  return ObjectConstPtr();
123  }
124  else
125  {
126  return it->second;
127  }
128 }
129 
130 void World::ensureUnique(ObjectPtr& obj)
131 {
132  if (obj && !obj.unique())
133  obj = std::make_shared<Object>(*obj);
134 }
135 
136 bool World::hasObject(const std::string& object_id) const
137 {
138  return objects_.find(object_id) != objects_.end();
139 }
140 
141 bool World::knowsTransform(const std::string& name) const
142 {
143  // Check object names first
144  const std::map<std::string, ObjectPtr>::const_iterator it = objects_.find(name);
145  if (it != objects_.end())
146  {
147  return true;
148  }
149  else // Then objects' subframes
150  {
151  for (const std::pair<const std::string, ObjectPtr>& object : objects_)
152  {
153  // if "object name/" matches start of object_id, we found the matching object
154  // rfind searches name for object.first in the first index (returns 0 if found)
155  if (name.rfind(object.first, 0) == 0 && name[object.first.length()] == '/')
156  {
157  return object.second->global_subframe_poses_.find(name.substr(object.first.length() + 1)) !=
158  object.second->global_subframe_poses_.end();
159  }
160  }
161  }
162  return false;
163 }
164 
165 const Eigen::Isometry3d& World::getTransform(const std::string& name) const
166 {
167  bool found;
168  const Eigen::Isometry3d& result = getTransform(name, found);
169  if (!found)
170  throw std::runtime_error("No transform found with name: " + name);
171  return result;
172 }
173 
174 const Eigen::Isometry3d& World::getTransform(const std::string& name, bool& frame_found) const
175 {
176  // assume found
177  frame_found = true;
178 
179  const std::map<std::string, ObjectPtr>::const_iterator it = objects_.find(name);
180  if (it != objects_.end())
181  {
182  return it->second->pose_;
183  }
184  else // Search within subframes
185  {
186  for (const std::pair<const std::string, ObjectPtr>& object : objects_)
187  {
188  // if "object name/" matches start of object_id, we found the matching object
189  // rfind searches name for object.first in the first index (returns 0 if found)
190  if (name.rfind(object.first, 0) == 0 && name[object.first.length()] == '/')
191  {
192  const auto it = object.second->global_subframe_poses_.find(name.substr(object.first.length() + 1));
193  if (it != object.second->global_subframe_poses_.end())
194  {
195  return it->second;
196  }
197  }
198  }
199  }
200 
201  // we need a persisting isometry for the API
202  static const Eigen::Isometry3d IDENTITY_TRANSFORM = Eigen::Isometry3d::Identity();
203  frame_found = false;
204  return IDENTITY_TRANSFORM;
205 }
206 
207 const Eigen::Isometry3d& World::getGlobalShapeTransform(const std::string& object_id, const int shape_index) const
208 {
209  const auto it = objects_.find(object_id);
210  if (it != objects_.end())
211  {
212  return it->second->global_shape_poses_[shape_index];
213  }
214  else
215  {
216  RCLCPP_ERROR_STREAM(getLogger(), "Could not find global shape transform for object " << object_id);
217  static const Eigen::Isometry3d IDENTITY_TRANSFORM = Eigen::Isometry3d::Identity();
218  return IDENTITY_TRANSFORM;
219  }
220 }
221 
222 const EigenSTL::vector_Isometry3d& World::getGlobalShapeTransforms(const std::string& object_id) const
223 {
224  const auto it = objects_.find(object_id);
225  if (it != objects_.end())
226  {
227  return it->second->global_shape_poses_;
228  }
229  else
230  {
231  RCLCPP_ERROR_STREAM(getLogger(), "Could not find global shape transforms for object " << object_id);
232  static const EigenSTL::vector_Isometry3d IDENTITY_TRANSFORM_VECTOR;
233  return IDENTITY_TRANSFORM_VECTOR;
234  }
235 }
236 
237 bool World::moveShapeInObject(const std::string& object_id, const shapes::ShapeConstPtr& shape,
238  const Eigen::Isometry3d& shape_pose)
239 {
240  const auto it = objects_.find(object_id);
241  if (it != objects_.end())
242  {
243  const unsigned int n = it->second->shapes_.size();
244  for (unsigned int i = 0; i < n; ++i)
245  {
246  if (it->second->shapes_[i] == shape)
247  {
248  ensureUnique(it->second);
249  ASSERT_ISOMETRY(shape_pose) // unsanitized input, could contain a non-isometry
250  it->second->shape_poses_[i] = shape_pose;
251  it->second->global_shape_poses_[i] = it->second->pose_ * shape_pose;
252 
253  notify(it->second, MOVE_SHAPE);
254  return true;
255  }
256  }
257  }
258  return false;
259 }
260 
261 bool World::moveObject(const std::string& object_id, const Eigen::Isometry3d& transform)
262 {
263  const auto it = objects_.find(object_id);
264  if (it == objects_.end())
265  return false;
266  if (transform.isApprox(Eigen::Isometry3d::Identity()))
267  return true; // object already at correct location
268 
269  ASSERT_ISOMETRY(transform) // unsanitized input, could contain a non-isometry
270  return setObjectPose(object_id, transform * it->second->pose_);
271 }
272 
273 bool World::setObjectPose(const std::string& object_id, const Eigen::Isometry3d& pose)
274 {
275  ASSERT_ISOMETRY(pose); // unsanitized input, could contain a non-isometry
276  ObjectPtr& obj = objects_[object_id];
277  int action;
278  if (!obj)
279  {
280  obj = std::make_shared<Object>(object_id);
281  action = CREATE;
282  }
283  else
284  {
285  ensureUnique(obj);
286  action = obj->shapes_.empty() ? 0 : MOVE_SHAPE;
287  }
288 
289  obj->pose_ = pose;
290  updateGlobalPosesInternal(obj);
291  notify(obj, Action(action));
292  return true;
293 }
294 
295 bool World::removeShapeFromObject(const std::string& object_id, const shapes::ShapeConstPtr& shape)
296 {
297  const auto it = objects_.find(object_id);
298  if (it != objects_.end())
299  {
300  const unsigned int n = it->second->shapes_.size();
301  for (unsigned int i = 0; i < n; ++i)
302  {
303  if (it->second->shapes_[i] == shape)
304  {
305  ensureUnique(it->second);
306  it->second->shapes_.erase(it->second->shapes_.begin() + i);
307  it->second->shape_poses_.erase(it->second->shape_poses_.begin() + i);
308  it->second->global_shape_poses_.erase(it->second->global_shape_poses_.begin() + i);
309 
310  if (it->second->shapes_.empty())
311  {
312  notify(it->second, DESTROY);
313  objects_.erase(it);
314  }
315  else
316  {
317  notify(it->second, REMOVE_SHAPE);
318  }
319  return true;
320  }
321  }
322  }
323  return false;
324 }
325 
326 bool World::removeObject(const std::string& object_id)
327 {
328  const auto it = objects_.find(object_id);
329  if (it != objects_.end())
330  {
331  notify(it->second, DESTROY);
332  objects_.erase(it);
333  return true;
334  }
335  return false;
336 }
337 
339 {
340  notifyAll(DESTROY);
341  objects_.clear();
342 }
343 
344 bool World::setSubframesOfObject(const std::string& object_id, const moveit::core::FixedTransformsMap& subframe_poses)
345 {
346  const auto obj_pair = objects_.find(object_id);
347  if (obj_pair == objects_.end())
348  {
349  return false;
350  }
351  for (const auto& t : subframe_poses)
352  {
353  ASSERT_ISOMETRY(t.second) // unsanitized input, could contain a non-isometry
354  }
355  obj_pair->second->subframe_poses_ = subframe_poses;
356  obj_pair->second->global_subframe_poses_ = subframe_poses;
357  updateGlobalPosesInternal(obj_pair->second, false, true);
358  return true;
359 }
360 
361 void World::updateGlobalPosesInternal(ObjectPtr& obj, bool update_shape_poses, bool update_subframe_poses)
362 {
363  // Update global shape poses
364  if (update_shape_poses)
365  {
366  for (unsigned int i = 0; i < obj->global_shape_poses_.size(); ++i)
367  obj->global_shape_poses_[i] = obj->pose_ * obj->shape_poses_[i];
368  }
369 
370  // Update global subframe poses
371  if (update_subframe_poses)
372  {
373  for (auto it_global_pose = obj->global_subframe_poses_.begin(), it_local_pose = obj->subframe_poses_.begin(),
374  end_poses = obj->global_subframe_poses_.end();
375  it_global_pose != end_poses; ++it_global_pose, ++it_local_pose)
376  {
377  it_global_pose->second = obj->pose_ * it_local_pose->second;
378  }
379  }
380 }
381 
383 {
384  const auto o = new Observer(callback);
385  observers_.push_back(o);
386  return ObserverHandle(o);
387 }
388 
390 {
391  for (auto obs = observers_.begin(); obs != observers_.end(); ++obs)
392  {
393  if (*obs == observer_handle.observer_)
394  {
395  delete *obs;
396  observers_.erase(obs);
397  return;
398  }
399  }
400 }
401 
402 void World::notifyAll(Action action)
403 {
404  for (std::map<std::string, ObjectPtr>::const_iterator it = objects_.begin(); it != objects_.end(); ++it)
405  notify(it->second, action);
406 }
407 
408 void World::notify(const ObjectConstPtr& obj, Action action)
409 {
410  for (Observer* observer : observers_)
411  observer->callback_(obj, action);
412 }
413 
415 {
416  for (auto observer : observers_)
417  {
418  if (observer == observer_handle.observer_)
419  {
420  // call the callback for each object
421  for (const auto& object : objects_)
422  observer->callback_(object.second, action);
423  break;
424  }
425  }
426 }
427 
428 } // 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.h:265
Maintain a representation of the environment.
Definition: world.h: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:165
void removeObserver(const ObserverHandle observer_handle)
remove a notifier callback
Definition: world.cpp:389
std::function< void(const ObjectConstPtr &, Action)> ObserverCallbackFn
Definition: world.h:301
bool hasObject(const std::string &object_id) const
Check if a particular object exists in the collision world.
Definition: world.cpp:136
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:326
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:237
void notifyObserverAllObjects(const ObserverHandle observer_handle, Action action) const
Definition: world.cpp:414
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:295
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:207
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 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:261
ObserverHandle addObserver(const ObserverCallbackFn &callback)
register a callback function for notification of changes. callback will be called right after any cha...
Definition: world.cpp:382
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:273
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:344
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:141
void clearObjects()
Clear all objects. If there are no other pointers to corresponding instances of Objects,...
Definition: world.cpp:338
ObjectConstPtr getObject(const std::string &object_id) const
Get a particular object.
Definition: world.cpp:117
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:222
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...
Definition: transforms.h:53
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition: logger.cpp:79
name
Definition: setup.py:7
Definition: world.h:49