moveit2
The MoveIt Motion Planning Framework for ROS 2.
collision_env_bullet.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2019, Jens Petit
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 the copyright holder 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: Jens Petit */
36 
41 #include <functional>
42 #include <bullet/btBulletCollisionCommon.h>
43 #include <rclcpp/logger.hpp>
44 #include <rclcpp/logging.hpp>
45 
46 namespace collision_detection
47 {
48 const std::string CollisionDetectorAllocatorBullet::NAME("Bullet");
49 const double MAX_DISTANCE_MARGIN = 99;
50 
52 
53 CollisionEnvBullet::CollisionEnvBullet(const moveit::core::RobotModelConstPtr& model, double padding, double scale)
54  : CollisionEnv(model, padding, scale)
55 {
56  // request notifications about changes to new world
57  observer_handle_ = getWorld()->addObserver(
58  [this](const World::ObjectConstPtr& object, World::Action action) { notifyObjectChange(object, action); });
59 
60  for (const std::pair<const std::string, urdf::LinkSharedPtr>& link : robot_model_->getURDF()->links_)
61  {
62  addLinkAsCollisionObject(link.second);
63  }
64 }
65 
66 CollisionEnvBullet::CollisionEnvBullet(const moveit::core::RobotModelConstPtr& model, const WorldPtr& world,
67  double padding, double scale)
68  : CollisionEnv(model, world, padding, scale)
69 {
70  // request notifications about changes to new world
71  observer_handle_ = getWorld()->addObserver(
72  [this](const World::ObjectConstPtr& object, World::Action action) { notifyObjectChange(object, action); });
73 
74  for (const std::pair<const std::string, urdf::LinkSharedPtr>& link : robot_model_->getURDF()->links_)
75  {
76  addLinkAsCollisionObject(link.second);
77  }
78 
79  getWorld()->notifyObserverAllObjects(observer_handle_, World::CREATE);
80 }
81 
82 CollisionEnvBullet::CollisionEnvBullet(const CollisionEnvBullet& other, const WorldPtr& world)
83  : CollisionEnv(other, world)
84 {
85  // request notifications about changes to new world
86  observer_handle_ = getWorld()->addObserver(
87  [this](const World::ObjectConstPtr& object, World::Action action) { notifyObjectChange(object, action); });
88 
89  for (const std::pair<const std::string, urdf::LinkSharedPtr>& link : other.robot_model_->getURDF()->links_)
90  {
91  addLinkAsCollisionObject(link.second);
92  }
93 
94  // get notifications any objects already in the new world
95  getWorld()->notifyObserverAllObjects(observer_handle_, World::CREATE);
96 }
97 
99 {
100  getWorld()->removeObserver(observer_handle_);
101 }
102 
104  const moveit::core::RobotState& state) const
105 {
106  checkSelfCollisionHelper(req, res, state, nullptr);
107 }
108 
110  const moveit::core::RobotState& state,
111  const AllowedCollisionMatrix& acm) const
112 {
113  checkSelfCollisionHelper(req, res, state, &acm);
114 }
115 
117  const moveit::core::RobotState& state,
118  const AllowedCollisionMatrix* acm) const
119 {
120  std::lock_guard<std::mutex> guard(collision_env_mutex_);
121 
122  std::vector<collision_detection_bullet::CollisionObjectWrapperPtr> cows;
123  addAttachedObjects(state, cows);
124 
125  if (req.distance)
126  {
127  manager_->setContactDistanceThreshold(MAX_DISTANCE_MARGIN);
128  }
129 
130  for (const collision_detection_bullet::CollisionObjectWrapperPtr& cow : cows)
131  {
132  manager_->addCollisionObject(cow);
133  manager_->setCollisionObjectsTransform(
134  cow->getName(), state.getAttachedBody(cow->getName())->getGlobalCollisionBodyTransforms()[0]);
135  }
136 
137  // updating link positions with the current robot state
138  for (const std::string& link : active_)
139  {
140  manager_->setCollisionObjectsTransform(link, state.getCollisionBodyTransform(link, 0));
141  }
142 
143  manager_->contactTest(res, req, acm, true);
144 
145  for (const collision_detection_bullet::CollisionObjectWrapperPtr& cow : cows)
146  {
147  manager_->removeCollisionObject(cow->getName());
148  }
149 }
150 
152  const moveit::core::RobotState& state) const
153 {
154  checkRobotCollisionHelper(req, res, state, nullptr);
155 }
156 
158  const moveit::core::RobotState& state,
159  const AllowedCollisionMatrix& acm) const
160 {
161  checkRobotCollisionHelper(req, res, state, &acm);
162 }
163 
165  const moveit::core::RobotState& state1,
166  const moveit::core::RobotState& state2) const
167 {
168  checkRobotCollisionHelperCCD(req, res, state1, state2, nullptr);
169 }
170 
172  const moveit::core::RobotState& state1,
173  const moveit::core::RobotState& state2,
174  const AllowedCollisionMatrix& acm) const
175 {
176  checkRobotCollisionHelperCCD(req, res, state1, state2, &acm);
177 }
178 
180  const moveit::core::RobotState& state,
181  const AllowedCollisionMatrix* acm) const
182 {
183  std::lock_guard<std::mutex> guard(collision_env_mutex_);
184 
185  if (req.distance)
186  {
187  manager_->setContactDistanceThreshold(MAX_DISTANCE_MARGIN);
188  }
189 
190  std::vector<collision_detection_bullet::CollisionObjectWrapperPtr> attached_cows;
191  addAttachedObjects(state, attached_cows);
193 
194  for (const collision_detection_bullet::CollisionObjectWrapperPtr& cow : attached_cows)
195  {
196  manager_->addCollisionObject(cow);
197  manager_->setCollisionObjectsTransform(
198  cow->getName(), state.getAttachedBody(cow->getName())->getGlobalCollisionBodyTransforms()[0]);
199  }
200 
201  manager_->contactTest(res, req, acm, false);
202 
203  for (const collision_detection_bullet::CollisionObjectWrapperPtr& cow : attached_cows)
204  {
205  manager_->removeCollisionObject(cow->getName());
206  }
207 }
208 
210  const moveit::core::RobotState& state1,
211  const moveit::core::RobotState& state2,
212  const AllowedCollisionMatrix* acm) const
213 {
214  std::lock_guard<std::mutex> guard(collision_env_mutex_);
215 
216  std::vector<collision_detection_bullet::CollisionObjectWrapperPtr> attached_cows;
217  addAttachedObjects(state1, attached_cows);
218 
219  for (const collision_detection_bullet::CollisionObjectWrapperPtr& cow : attached_cows)
220  {
221  manager_CCD_->addCollisionObject(cow);
222  manager_CCD_->setCastCollisionObjectsTransform(
223  cow->getName(), state1.getAttachedBody(cow->getName())->getGlobalCollisionBodyTransforms()[0],
224  state2.getAttachedBody(cow->getName())->getGlobalCollisionBodyTransforms()[0]);
225  }
226 
227  for (const std::string& link : active_)
228  {
229  manager_CCD_->setCastCollisionObjectsTransform(link, state1.getCollisionBodyTransform(link, 0),
230  state2.getCollisionBodyTransform(link, 0));
231  }
232 
233  manager_CCD_->contactTest(res, req, acm, false);
234 
235  for (const collision_detection_bullet::CollisionObjectWrapperPtr& cow : attached_cows)
236  {
237  manager_CCD_->removeCollisionObject(cow->getName());
238  }
239 }
240 
242  const moveit::core::RobotState& /*state*/) const
243 {
244  RCLCPP_INFO(getLogger(), "distanceSelf is not implemented for Bullet.");
245 }
246 
248  const moveit::core::RobotState& /*state*/) const
249 {
250  RCLCPP_INFO(getLogger(), "distanceRobot is not implemented for Bullet.");
251 }
252 
254 {
255  std::vector<collision_detection_bullet::CollisionObjectType> collision_object_types;
256 
257  for (const shapes::ShapeConstPtr& shape : obj->shapes_)
258  {
259  if (shape->type == shapes::MESH)
260  {
261  collision_object_types.push_back(collision_detection_bullet::CollisionObjectType::CONVEX_HULL);
262  }
263  else
264  {
265  collision_object_types.push_back(collision_detection_bullet::CollisionObjectType::USE_SHAPE_TYPE);
266  }
267  }
268 
269  auto cow = std::make_shared<collision_detection_bullet::CollisionObjectWrapper>(
271  collision_object_types, false);
272 
273  manager_->addCollisionObject(cow);
274  manager_CCD_->addCollisionObject(cow->clone());
275 }
276 
277 void CollisionEnvBullet::updateManagedObject(const std::string& id)
278 {
279  if (getWorld()->hasObject(id))
280  {
281  auto it = getWorld()->find(id);
282  if (manager_->hasCollisionObject(id))
283  {
284  manager_->removeCollisionObject(id);
285  manager_CCD_->removeCollisionObject(id);
286  addToManager(it->second.get());
287  }
288  else
289  {
290  addToManager(it->second.get());
291  }
292  }
293  else
294  {
295  if (manager_->hasCollisionObject(id))
296  {
297  manager_->removeCollisionObject(id);
298  manager_CCD_->removeCollisionObject(id);
299  }
300  }
301 }
302 
303 void CollisionEnvBullet::setWorld(const WorldPtr& world)
304 {
305  if (world == getWorld())
306  return;
307 
308  // turn off notifications about old world
309  getWorld()->removeObserver(observer_handle_);
310 
311  CollisionEnv::setWorld(world);
312 
313  // request notifications about changes to new world
314  observer_handle_ = getWorld()->addObserver(
315  [this](const World::ObjectConstPtr& object, World::Action action) { notifyObjectChange(object, action); });
316 
317  // get notifications any objects already in the new world
318  getWorld()->notifyObserverAllObjects(observer_handle_, World::CREATE);
319 }
320 
321 void CollisionEnvBullet::notifyObjectChange(const ObjectConstPtr& obj, World::Action action)
322 {
323  std::lock_guard<std::mutex> guard(collision_env_mutex_);
324  if (action == World::DESTROY)
325  {
326  manager_->removeCollisionObject(obj->id_);
327  manager_CCD_->removeCollisionObject(obj->id_);
328  }
329  else
330  {
331  updateManagedObject(obj->id_);
332  }
333 }
334 
336  std::vector<collision_detection_bullet::CollisionObjectWrapperPtr>& cows) const
337 {
338  std::vector<const moveit::core::AttachedBody*> attached_bodies;
339  state.getAttachedBodies(attached_bodies);
340 
341  for (const moveit::core::AttachedBody*& body : attached_bodies)
342  {
343  const EigenSTL::vector_Isometry3d& attached_body_transform = body->getGlobalCollisionBodyTransforms();
344 
345  std::vector<collision_detection_bullet::CollisionObjectType> collision_object_types(
347 
348  try
349  {
350  collision_detection_bullet::CollisionObjectWrapperPtr cow =
351  std::make_shared<collision_detection_bullet::CollisionObjectWrapper>(
352  body->getName(), collision_detection::BodyType::ROBOT_ATTACHED, body->getShapes(),
353  attached_body_transform, collision_object_types, body->getTouchLinks());
354  cows.push_back(cow);
355  }
356  catch (std::exception&)
357  {
358  RCLCPP_ERROR_STREAM(getLogger(), "Not adding " << body->getName() << " due to bad arguments.");
359  }
360  }
361 }
362 
363 void CollisionEnvBullet::updatedPaddingOrScaling(const std::vector<std::string>& links)
364 {
365  for (const std::string& link : links)
366  {
367  if (robot_model_->getURDF()->links_.find(link) != robot_model_->getURDF()->links_.end())
368  {
369  addLinkAsCollisionObject(robot_model_->getURDF()->links_[link]);
370  }
371  else
372  {
373  RCLCPP_ERROR(getLogger(), "Updating padding or scaling for unknown link: '%s'", link.c_str());
374  }
375  }
376 }
377 
379  const moveit::core::RobotState& state, const collision_detection_bullet::BulletDiscreteBVHManagerPtr& manager) const
380 {
381  // updating link positions with the current robot state
382  for (const std::string& link : active_)
383  {
384  // select the first of the transformations for each link (composed of multiple shapes...)
385  manager->setCollisionObjectsTransform(link, state.getCollisionBodyTransform(link, 0));
386  }
387 }
388 
389 void CollisionEnvBullet::addLinkAsCollisionObject(const urdf::LinkSharedPtr& link)
390 {
391  if (!link->collision_array.empty())
392  {
393  const std::vector<urdf::CollisionSharedPtr>& col_array =
394  link->collision_array.empty() ? std::vector<urdf::CollisionSharedPtr>(1, link->collision) :
395  link->collision_array;
396 
397  std::vector<shapes::ShapeConstPtr> shapes;
399  std::vector<collision_detection_bullet::CollisionObjectType> collision_object_types;
400 
401  for (const auto& i : col_array)
402  {
403  if (i && i->geometry)
404  {
405  shapes::ShapePtr shape = collision_detection_bullet::constructShape(i->geometry.get());
406 
407  if (shape)
408  {
409  if (fabs(getLinkScale(link->name) - 1.0) >= std::numeric_limits<double>::epsilon() ||
410  fabs(getLinkPadding(link->name)) >= std::numeric_limits<double>::epsilon())
411  {
412  shape->scaleAndPadd(getLinkScale(link->name), getLinkPadding(link->name));
413  }
414 
415  shapes.push_back(shape);
416  shape_poses.push_back(collision_detection_bullet::urdfPose2Eigen(i->origin));
417 
418  if (shape->type == shapes::MESH)
419  {
420  collision_object_types.push_back(collision_detection_bullet::CollisionObjectType::CONVEX_HULL);
421  }
422  else
423  {
424  collision_object_types.push_back(collision_detection_bullet::CollisionObjectType::USE_SHAPE_TYPE);
425  }
426  }
427  }
428  }
429 
430  if (manager_->hasCollisionObject(link->name))
431  {
432  manager_->removeCollisionObject(link->name);
433  manager_CCD_->removeCollisionObject(link->name);
434  }
435 
436  try
437  {
438  collision_detection_bullet::CollisionObjectWrapperPtr cow =
439  std::make_shared<collision_detection_bullet::CollisionObjectWrapper>(
440  link->name, collision_detection::BodyType::ROBOT_LINK, shapes, shape_poses, collision_object_types, true);
441  manager_->addCollisionObject(cow);
442  manager_CCD_->addCollisionObject(cow->clone());
443  active_.push_back(cow->getName());
444  }
445  catch (std::exception&)
446  {
447  RCLCPP_ERROR_STREAM(getLogger(), "Not adding " << link->name << " due to bad arguments.");
448  }
449  }
450 }
451 
452 } // end of namespace collision_detection
Definition of a structure for the allowed collision matrix. All elements in the collision world are r...
collision_detection_bullet::BulletCastBVHManagerPtr manager_CCD_
Handles continuous robot world collision checks.
void setWorld(const WorldPtr &world) override
void updateTransformsFromState(const moveit::core::RobotState &state, const collision_detection_bullet::BulletDiscreteBVHManagerPtr &manager) const
Updates the poses of the objects in the manager according to given robot state.
void distanceSelf(const DistanceRequest &req, DistanceResult &res, const moveit::core::RobotState &state) const override
The distance to self-collision given the robot is at state state.
void updatedPaddingOrScaling(const std::vector< std::string > &links) override
Updates the collision objects saved in the manager to reflect a new padding or scaling of the robot l...
std::vector< std::string > active_
The active links where active refers to the group which can collide with everything.
void checkRobotCollisionHelperCCD(const CollisionRequest &req, CollisionResult &res, const moveit::core::RobotState &state1, const moveit::core::RobotState &state2, const AllowedCollisionMatrix *acm) const
void addAttachedObjects(const moveit::core::RobotState &state, std::vector< collision_detection_bullet::CollisionObjectWrapperPtr > &cows) const
All of the attached objects in the robot state are wrapped into bullet collision objects.
void checkRobotCollisionHelper(const CollisionRequest &req, CollisionResult &res, const moveit::core::RobotState &state, const AllowedCollisionMatrix *acm) const
void checkRobotCollision(const CollisionRequest &req, CollisionResult &res, const moveit::core::RobotState &state) const override
Check whether the robot model is in collision with the world. Any collisions between a robot link and...
void checkSelfCollision(const CollisionRequest &req, CollisionResult &res, const moveit::core::RobotState &state) const override
Check for robot self collision. Any collision between any pair of links is checked for,...
void checkSelfCollisionHelper(const CollisionRequest &req, CollisionResult &res, const moveit::core::RobotState &state, const AllowedCollisionMatrix *acm) const
Bundles the different checkSelfCollision functions into a single function.
void distanceRobot(const DistanceRequest &req, DistanceResult &res, const moveit::core::RobotState &state) const override
Compute the distance between a robot and the world.
void addLinkAsCollisionObject(const urdf::LinkSharedPtr &link)
Construts a bullet collision object out of a robot link.
collision_detection_bullet::BulletDiscreteBVHManagerPtr manager_
Handles self collision checks.
void updateManagedObject(const std::string &id)
Updates a managed collision object with its world representation.
void addToManager(const World::Object *obj)
Adds a world object to the collision managers.
Provides the interface to the individual collision checking libraries.
Definition: collision_env.h:52
virtual void setWorld(const WorldPtr &world)
moveit::core::RobotModelConstPtr robot_model_
The kinematic model corresponding to this collision model.
const std::map< std::string, double > & getLinkScale() const
Get the link scaling as a map (from link names to scale value)
const std::map< std::string, double > & getLinkPadding() const
Get the link paddings as a map (from link names to padding value)
Represents an action that occurred on an object in the world. Several bits may be set indicating seve...
Definition: world.h:265
Object defining bodies that can be attached to robot links.
Definition: attached_body.h:58
const EigenSTL::vector_Isometry3d & getGlobalCollisionBodyTransforms() const
Get the global transforms (in world frame) for the collision bodies. The returned transforms are guar...
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition: robot_state.h:90
const Eigen::Isometry3d & getCollisionBodyTransform(const std::string &link_name, std::size_t index)
Get the link transform w.r.t. the root link (model frame) of the RobotModel. This is typically the ro...
Definition: robot_state.h:1286
void getAttachedBodies(std::vector< const AttachedBody * > &attached_bodies) const
Get all bodies attached to the model corresponding to this state.
const AttachedBody * getAttachedBody(const std::string &name) const
Get the attached body named name. Return nullptr if not found.
@ ROBOT_LINK
A link on the robot.
@ ROBOT_ATTACHED
A body attached to a robot link.
@ WORLD_OBJECT
A body in the environment.
Eigen::Isometry3d urdfPose2Eigen(const urdf::Pose &pose)
std::vector< T, Eigen::aligned_allocator< T > > AlignedVector
Definition: basic_types.h:37
@ USE_SHAPE_TYPE
Infer the type from the type specified in the shapes::Shape class.
@ CONVEX_HULL
Use the mesh in shapes::Shape but make it a convex hulls collision object (if not convex it will be c...
shapes::ShapePtr constructShape(const urdf::Geometry *geom)
Definition: world.h:49
Representation of a collision checking request.
bool distance
If true, compute proximity distance.
Representation of a collision checking result.
Representation of a distance-reporting request.
Result of a distance request.
A representation of an object.
Definition: world.h:79
EigenSTL::vector_Isometry3d global_shape_poses_
The poses of the corresponding entries in shapes_, relative to the world frame.
Definition: world.h:106
EIGEN_MAKE_ALIGNED_OPERATOR_NEW std::string id_
The id for this object.
Definition: world.h:87
std::vector< shapes::ShapeConstPtr > shapes_
All the shapes making up this object.
Definition: world.h:96