collision_scene_fcl.cpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2018, University of Edinburgh
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of nor the names of its contributors may be used to
14 // endorse or promote products derived from this software without specific
15 // prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
28 //
29 
31 #include <exotica_core/factory.h>
32 
33 #include <ros/ros.h>
34 
36 
37 namespace fcl_convert
38 {
39 fcl::Transform3f KDL2fcl(const KDL::Frame& frame)
40 {
41  return fcl::Transform3f(fcl::Matrix3f(frame.M.data[0], frame.M.data[1], frame.M.data[2], frame.M.data[3], frame.M.data[4], frame.M.data[5], frame.M.data[6], frame.M.data[7], frame.M.data[8]), fcl::Vec3f(frame.p.x(), frame.p.y(), frame.p.z()));
42 }
43 }
44 
45 namespace exotica
46 {
48 {
49  if (debug_) HIGHLIGHT_NAMED("CollisionSceneFCL", "FCL version: " << FCL_VERSION);
50 }
51 
52 void CollisionSceneFCL::UpdateCollisionObjects(const std::map<std::string, std::weak_ptr<KinematicElement>>& objects)
53 {
55  fcl_cache_.clear();
56  fcl_objects_.resize(objects.size());
57  long i = 0;
58  for (const auto& object : objects)
59  {
60  std::shared_ptr<fcl::CollisionObject> new_object;
61 
62  // const auto& cache_entry = fcl_cache_.find(object.first);
63  // TODO: There is currently a bug with the caching causing proxies not
64  // to update. The correct fix would be to update the user data, for now
65  // disable use of the cache.
66  // if (true) // (cache_entry == fcl_cache_.end())
67  //{
68  new_object = ConstructFclCollisionObject(i, object.second.lock());
69  fcl_cache_[object.first] = new_object;
70  //}
71  // else
72  // {
73  // new_object = cache_entry->second;
74  // }
75  fcl_objects_[i++] = new_object.get();
76  }
77 }
78 
80 {
81  for (fcl::CollisionObject* collision_object : fcl_objects_)
82  {
83  std::shared_ptr<KinematicElement> element = kinematic_elements_[reinterpret_cast<long>(collision_object->getUserData())].lock();
84  if (!element)
85  {
86  ThrowPretty("Expired pointer, this should not happen - make sure to call UpdateCollisionObjects() after UpdateSceneFrames()");
87  }
88  collision_object->setTransform(fcl_convert::KDL2fcl(element->frame));
89  collision_object->computeAABB();
90  }
91 }
92 
93 // This function was copied from 'moveit_core/collision_detection_fcl/src/collision_common.cpp'
94 // https://github.com/ros-planning/moveit/blob/indigo-devel/moveit_core/collision_detection_fcl/src/collision_common.cpp#L512
95 std::shared_ptr<fcl::CollisionObject> CollisionSceneFCL::ConstructFclCollisionObject(long kinematic_element_id, std::shared_ptr<KinematicElement> element)
96 {
97  shapes::ShapeConstPtr shape = element->shape;
98 
99  // Apply scaling and padding
100  if (element->is_robot_link || element->closest_robot_link.lock())
101  {
102  if (robot_link_scale_ != 1.0 || robot_link_padding_ > 0.0)
103  {
104  shapes::ShapePtr scaled_shape(shape->clone());
105  scaled_shape->scaleAndPadd(robot_link_scale_, robot_link_padding_);
106  shape = scaled_shape;
107  }
108  }
109  else
110  {
111  if (world_link_scale_ != 1.0 || world_link_padding_ > 0.0)
112  {
113  shapes::ShapePtr scaled_shape(shape->clone());
114  scaled_shape->scaleAndPadd(world_link_scale_, world_link_padding_);
115  shape = scaled_shape;
116  }
117  }
118 
119 // Uses `std::shared_ptr` if ROS version >= ROS_KINETIC
120 #if ROS_VERSION_MINIMUM(1, 12, 0)
121  std::shared_ptr<fcl::CollisionGeometry> geometry;
122 #else
124 #endif
125  switch (shape->type)
126  {
127  case shapes::PLANE:
128  {
129  auto p = dynamic_cast<const shapes::Plane*>(shape.get());
130  geometry.reset(new fcl::Plane(p->a, p->b, p->c, p->d));
131  }
132  break;
133  case shapes::SPHERE:
134  {
135  auto s = dynamic_cast<const shapes::Sphere*>(shape.get());
136  geometry.reset(new fcl::Sphere(s->radius));
137  }
138  break;
139  case shapes::BOX:
140  {
141  auto s = dynamic_cast<const shapes::Box*>(shape.get());
142  const double* size = s->size;
143  geometry.reset(new fcl::Box(size[0], size[1], size[2]));
144  }
145  break;
146  case shapes::CYLINDER:
147  {
148  auto s = dynamic_cast<const shapes::Cylinder*>(shape.get());
149  bool degenerate_capsule = (s->length <= 2 * s->radius);
150  if (!replace_cylinders_with_capsules_ || degenerate_capsule)
151  {
152  geometry.reset(new fcl::Cylinder(s->radius, s->length));
153  }
154  else
155  {
156  geometry.reset(new fcl::Capsule(s->radius, s->length - 2 * s->radius));
157  }
158  }
159  break;
160  case shapes::CONE:
161  {
162  auto s = dynamic_cast<const shapes::Cone*>(shape.get());
163  geometry.reset(new fcl::Cone(s->radius, s->length));
164  }
165  break;
166  case shapes::MESH:
167  {
168  auto g = new fcl::BVHModel<fcl::OBBRSS>();
169  auto mesh = dynamic_cast<const shapes::Mesh*>(shape.get());
170  if (mesh->vertex_count > 0 && mesh->triangle_count > 0)
171  {
172  std::vector<fcl::Triangle> tri_indices(mesh->triangle_count);
173  for (unsigned int i = 0; i < mesh->triangle_count; ++i)
174  tri_indices[i] =
175  fcl::Triangle(mesh->triangles[3 * i], mesh->triangles[3 * i + 1], mesh->triangles[3 * i + 2]);
176 
177  std::vector<fcl::Vec3f> points(mesh->vertex_count);
178  for (unsigned int i = 0; i < mesh->vertex_count; ++i)
179  points[i] = fcl::Vec3f(mesh->vertices[3 * i], mesh->vertices[3 * i + 1], mesh->vertices[3 * i + 2]);
180 
181  g->beginModel();
182  g->addSubModel(points, tri_indices);
183  g->endModel();
184  }
185  geometry.reset(g);
186  }
187  break;
188  case shapes::OCTREE:
189  {
190  auto g = dynamic_cast<const shapes::OcTree*>(shape.get());
191  geometry.reset(new fcl::OcTree(g->octree));
192  }
193  break;
194  default:
195  ThrowPretty("This shape type (" << ((int)shape->type) << ") is not supported using FCL yet");
196  }
197  geometry->computeLocalAABB();
198  geometry->setUserData(reinterpret_cast<void*>(kinematic_element_id));
199  std::shared_ptr<fcl::CollisionObject> ret(new fcl::CollisionObject(geometry));
200  ret->setUserData(reinterpret_cast<void*>(kinematic_element_id));
201 
202  return ret;
203 }
204 
205 bool CollisionSceneFCL::IsAllowedToCollide(fcl::CollisionObject* o1, fcl::CollisionObject* o2, bool self, CollisionSceneFCL* scene)
206 {
207  std::shared_ptr<KinematicElement> e1 = scene->kinematic_elements_[reinterpret_cast<long>(o1->getUserData())].lock();
208  std::shared_ptr<KinematicElement> e2 = scene->kinematic_elements_[reinterpret_cast<long>(o2->getUserData())].lock();
209 
210  bool isRobot1 = e1->is_robot_link || e1->closest_robot_link.lock();
211  bool isRobot2 = e2->is_robot_link || e2->closest_robot_link.lock();
212  // Don't check collisions between world objects
213  if (!isRobot1 && !isRobot2) return false;
214  // Skip self collisions if requested
215  if (isRobot1 && isRobot2 && !self) return false;
216  // Skip collisions between shapes within the same objects
217  if (e1->parent.lock() == e2->parent.lock()) return false;
218  // Skip collisions between bodies attached to the same object
219  if (e1->closest_robot_link.lock() && e2->closest_robot_link.lock() && e1->closest_robot_link.lock() == e2->closest_robot_link.lock()) return false;
220 
221  if (isRobot1 && isRobot2)
222  {
223  const std::string& name1 = e1->closest_robot_link.lock() ? e1->closest_robot_link.lock()->segment.getName() : e1->parent.lock()->segment.getName();
224  const std::string& name2 = e2->closest_robot_link.lock() ? e2->closest_robot_link.lock()->segment.getName() : e2->parent.lock()->segment.getName();
225  return scene->acm_.getAllowedCollision(name1, name2);
226  }
227  return true;
228 }
229 
230 void CollisionSceneFCL::CheckCollision(fcl::CollisionObject* o1, fcl::CollisionObject* o2, CollisionData* data)
231 {
232  data->request.num_max_contacts = 1000;
233  data->result.clear();
234  fcl::collide(o1, o2, data->request, data->result);
235  if (data->safe_distance > 0.0 && o1->getAABB().distance(o2->getAABB()) < data->safe_distance)
236  {
237  fcl::DistanceRequest req;
238  fcl::DistanceResult res;
239  req.enable_nearest_points = false;
240  fcl::distance(o1, o2, req, res);
241  // Add fake contact when distance is smaller than the safety distance.
242  if (res.min_distance < data->safe_distance) data->result.addContact(fcl::Contact());
243  }
244 }
245 
246 bool CollisionSceneFCL::CollisionCallback(fcl::CollisionObject* o1, fcl::CollisionObject* o2, void* data)
247 {
248  CollisionData* data_ = reinterpret_cast<CollisionData*>(data);
249 
250  if (!IsAllowedToCollide(o1, o2, data_->self, data_->scene)) return false;
251 
252  CheckCollision(o1, o2, data_);
253  return data_->result.isCollision();
254 }
255 
256 bool CollisionSceneFCL::IsStateValid(bool self, double safe_distance)
257 {
259 
260  std::shared_ptr<fcl::BroadPhaseCollisionManager> manager(new fcl::DynamicAABBTreeCollisionManager());
261  manager->registerObjects(fcl_objects_);
262  CollisionData data(this);
263  data.self = self;
264  data.safe_distance = safe_distance;
265  manager->collide(&data, &CollisionSceneFCL::CollisionCallback);
266  return !data.result.isCollision();
267 }
268 
269 bool CollisionSceneFCL::IsCollisionFree(const std::string& o1, const std::string& o2, double safe_distance)
270 {
272 
273  std::vector<fcl::CollisionObject*> shapes1;
274  std::vector<fcl::CollisionObject*> shapes2;
275  for (fcl::CollisionObject* o : fcl_objects_)
276  {
277  std::shared_ptr<KinematicElement> e = kinematic_elements_[reinterpret_cast<long>(o->getUserData())].lock();
278  if (e->segment.getName() == o1 || e->parent.lock()->segment.getName() == o1) shapes1.push_back(o);
279  if (e->segment.getName() == o2 || e->parent.lock()->segment.getName() == o2) shapes2.push_back(o);
280  }
281  if (shapes1.size() == 0) ThrowPretty("Can't find object '" << o1 << "'!");
282  if (shapes2.size() == 0) ThrowPretty("Can't find object '" << o2 << "'!");
283  CollisionData data(this);
284  data.safe_distance = safe_distance;
285  for (fcl::CollisionObject* s1 : shapes1)
286  {
287  for (fcl::CollisionObject* s2 : shapes2)
288  {
289  CheckCollision(s1, s2, &data);
290  if (data.result.isCollision()) return false;
291  }
292  }
293  return true;
294 }
295 
296 Eigen::Vector3d CollisionSceneFCL::GetTranslation(const std::string& name)
297 {
298  for (fcl::CollisionObject* object : fcl_objects_)
299  {
300  std::shared_ptr<KinematicElement> element = kinematic_elements_[reinterpret_cast<long>(object->getUserData())].lock();
301  if (element->segment.getName() == name)
302  {
303  return Eigen::Map<Eigen::Vector3d>(element->frame.p.data);
304  }
305  }
306  ThrowPretty("Robot not found!");
307 }
308 
310 {
311  std::vector<std::string> tmp;
312  for (fcl::CollisionObject* object : fcl_objects_)
313  {
314  std::shared_ptr<KinematicElement> element = kinematic_elements_[reinterpret_cast<long>(object->getUserData())].lock();
315  if (!element->closest_robot_link.lock())
316  {
317  tmp.push_back(element->segment.getName());
318  }
319  }
320  return tmp;
321 }
322 
324 {
325  std::vector<std::string> tmp;
326  for (fcl::CollisionObject* object : fcl_objects_)
327  {
328  std::shared_ptr<KinematicElement> element = kinematic_elements_[reinterpret_cast<long>(object->getUserData())].lock();
329  if (element->closest_robot_link.lock())
330  {
331  tmp.push_back(element->segment.getName());
332  }
333  }
334  return tmp;
335 }
336 }
void UpdateCollisionObjectTransforms() override
Updates collision object transformations from the kinematic tree.
std::shared_ptr< fcl::CollisionObject > ConstructFclCollisionObject(long i, std::shared_ptr< KinematicElement > element)
XmlRpcServer s
#define ThrowPretty(m)
std::shared_ptr< Shape > ShapePtr
double z() const
std::vector< std::weak_ptr< KinematicElement > > kinematic_elements_
std::vector< Val > GetValuesFromMap(const std::map< Key, Val > &map)
Rotation M
std::map< std::string, std::shared_ptr< fcl::CollisionObject > > fcl_cache_
static bool CollisionCallback(fcl::CollisionObject *o1, fcl::CollisionObject *o2, void *data)
std::vector< std::string > GetCollisionRobotLinks() override
Gets the collision robot links.
#define REGISTER_COLLISION_SCENE_TYPE(TYPE, DERIV)
double y() const
double x() const
fcl::Transform3f KDL2fcl(const KDL::Frame &frame)
std::vector< std::string > GetCollisionWorldLinks() override
Gets the collision world links.
void UpdateCollisionObjects(const std::map< std::string, std::weak_ptr< KinematicElement >> &objects) override
Creates the collision scene from kinematic elements.
bool always_externally_updated_collision_scene_
std::vector< fcl::CollisionObject * > fcl_objects_
Eigen::Vector3d GetTranslation(const std::string &name) override
bool IsCollisionFree(const std::string &o1, const std::string &o2, double safe_distance=0.0) override
#define HIGHLIGHT_NAMED(name, x)
AllowedCollisionMatrix acm_
bool IsStateValid(bool self=true, double safe_distance=0.0) override
Check if the whole robot is valid (collision only).
static bool IsAllowedToCollide(fcl::CollisionObject *o1, fcl::CollisionObject *o2, bool self, CollisionSceneFCL *scene)
static void CheckCollision(fcl::CollisionObject *o1, fcl::CollisionObject *o2, CollisionData *data)
bool getAllowedCollision(const std::string &name1, const std::string &name2) const
double data[9]
std::shared_ptr< const Shape > ShapeConstPtr


exotica_collision_scene_fcl
Author(s):
autogenerated on Wed Jul 1 2020 03:33:49