39 #define CONTINUOUS_COLLISION_USE_ADVANCED_SETTINGS 50 ret.translation() = Eigen::Map<const Eigen::Vector3d>(frame.
p.
data);
51 ret.linear() = Eigen::Map<const Eigen::Matrix3d>(frame.
M.
data);
57 Eigen::Map<Eigen::Vector3d>(frame.
p.
data) = tf.translation();
58 Eigen::Map<Eigen::Matrix3d>(frame.
M.
data) = tf.linear().matrix();
63 return e->is_robot_link || e->closest_robot_link.lock();
92 auto world_links_to_exclude_from_collision_scene =
scene_.lock()->get_world_links_to_exclude_from_collision_scene();
93 for (
const auto&
object : objects)
97 if (world_links_to_exclude_from_collision_scene.count(
object.first) > 0)
99 if (
debug_)
HIGHLIGHT_NAMED(
"CollisionSceneFCLLatest::UpdateCollisionObject",
object.first <<
" is excluded, skipping.");
103 if (
debug_)
HIGHLIGHT_NAMED(
"CollisionSceneFCLLatest::UpdateCollisionObject",
"Creating " <<
object.first);
134 for (fcl::CollisionObjectd* collision_object :
fcl_objects_)
136 if (!collision_object)
140 std::shared_ptr<KinematicElement> element =
kinematic_elements_[
reinterpret_cast<long>(collision_object->getUserData())].lock();
143 ThrowPretty(
"Expired pointer, this should not happen - make sure to call UpdateCollisionObjects() after UpdateSceneFrames()");
147 if (std::isnan(element->frame.p.data[0]) || std::isnan(element->frame.p.data[1]) || std::isnan(element->frame.p.data[2]))
149 ThrowPretty(
"Transform for " << element->segment.getName() <<
" contains NaNs.");
153 collision_object->computeAABB();
183 if (static_cast<int>(shape->type) < 6)
189 std::shared_ptr<fcl::CollisionGeometryd> geometry;
195 geometry.reset(
new fcl::Planed(p->a, p->b, p->c, p->d));
201 geometry.reset(
new fcl::Sphered(
s->radius));
207 const double* size =
s->size;
208 geometry.reset(
new fcl::Boxd(size[0], size[1], size[2]));
214 bool degenerate_capsule = (
s->length <= 2 *
s->radius);
217 geometry.reset(
new fcl::Cylinderd(
s->radius,
s->length));
221 geometry.reset(
new fcl::Capsuled(
s->radius,
s->length - 2 *
s->radius));
228 geometry.reset(
new fcl::Coned(
s->radius,
s->length));
233 auto g =
new fcl::BVHModel<fcl::OBBRSSd>();
234 auto mesh =
dynamic_cast<const shapes::Mesh*
>(shape.get());
235 if (mesh->vertex_count > 0 && mesh->triangle_count > 0)
237 std::vector<fcl::Triangle> tri_indices(mesh->triangle_count);
238 for (
unsigned int i = 0; i < mesh->triangle_count; ++i)
240 fcl::Triangle(mesh->triangles[3 * i], mesh->triangles[3 * i + 1], mesh->triangles[3 * i + 2]);
242 std::vector<fcl::Vector3d> points(mesh->vertex_count);
243 for (
unsigned int i = 0; i < mesh->vertex_count; ++i)
244 points[i] = fcl::Vector3d(mesh->vertices[3 * i], mesh->vertices[3 * i + 1], mesh->vertices[3 * i + 2]);
247 g->addSubModel(points, tri_indices);
256 geometry.reset(
new fcl::OcTreed(
ToStdPtr(g->octree)));
260 ThrowPretty(
"This shape type (" << ((
int)shape->type) <<
") is not supported using FCL yet");
262 geometry->computeLocalAABB();
263 geometry->setUserData(reinterpret_cast<void*>(kinematic_element_id));
264 std::shared_ptr<fcl::CollisionObjectd> ret(
new fcl::CollisionObjectd(geometry));
265 ret->setUserData(reinterpret_cast<void*>(kinematic_element_id));
278 if (!isRobot1 && !isRobot2)
return false;
280 if (isRobot1 && isRobot2 && !
self)
return false;
282 if (e1->parent.lock() == e2->parent.lock())
return false;
284 if (e1->closest_robot_link.lock() && e2->closest_robot_link.lock() && e1->closest_robot_link.lock() == e2->closest_robot_link.lock())
return false;
286 if (isRobot1 && isRobot2)
288 const std::string& name1 = e1->closest_robot_link.lock() ? e1->closest_robot_link.lock()->segment.getName() : e1->parent.lock()->segment.getName();
289 const std::string& name2 = e2->closest_robot_link.lock() ? e2->closest_robot_link.lock()->segment.getName() : e2->parent.lock()->segment.getName();
297 std::shared_ptr<KinematicElement> e1 = scene->
kinematic_elements_[
reinterpret_cast<long>(o1->getUserData())].lock();
298 std::shared_ptr<KinematicElement> e2 = scene->
kinematic_elements_[
reinterpret_cast<long>(o2->getUserData())].lock();
303 if (!isRobot1 && !isRobot2)
return false;
305 if (isRobot1 && isRobot2 && !
self)
return false;
307 if (e1->parent.lock() == e2->parent.lock())
return false;
309 if (e1->closest_robot_link.lock() && e2->closest_robot_link.lock() && e1->closest_robot_link.lock() == e2->closest_robot_link.lock())
return false;
311 if (isRobot1 && isRobot2)
313 const std::string& name1 = e1->closest_robot_link.lock() ? e1->closest_robot_link.lock()->segment.getName() : e1->parent.lock()->segment.getName();
314 const std::string& name2 = e2->closest_robot_link.lock() ? e2->closest_robot_link.lock()->segment.getName() : e2->parent.lock()->segment.getName();
322 data->
request.num_max_contacts = 1000;
323 data->
request.gjk_solver_type = fcl::GST_LIBCCD;
328 fcl::DistanceRequestd req;
329 fcl::DistanceResultd res;
330 req.enable_nearest_points =
false;
331 fcl::distance(o1, o2, req, res);
344 return data_->
result.isCollision();
360 fcl::CollisionRequestd tmp_req;
361 fcl::CollisionResultd tmp_res;
362 tmp_req.num_max_contacts = 1000;
363 tmp_req.enable_contact =
true;
372 tmp_req.gjk_tolerance = 2e-12;
373 tmp_req.gjk_solver_type = fcl::GJKSolverType::GST_LIBCCD;
375 fcl::collide(o1, o2, tmp_req, tmp_res);
378 if (tmp_res.isCollision())
382 if ((o1->getObjectType() == fcl::OBJECT_TYPE::OT_GEOM && o2->getObjectType() == fcl::OBJECT_TYPE::OT_BVH) || (o1->getObjectType() == fcl::OBJECT_TYPE::OT_BVH && o2->getObjectType() == fcl::OBJECT_TYPE::OT_GEOM))
388 std::vector<fcl::Contactd> contacts;
389 tmp_res.getContacts(contacts);
390 if (!contacts.empty())
392 size_t deepest_penetration_depth_index = -1;
393 double deepest_penetration_depth = -1;
394 for (
size_t i = 0; i < contacts.size(); ++i)
396 if (std::abs(contacts[i].penetration_depth) > deepest_penetration_depth)
398 deepest_penetration_depth = std::abs(contacts[i].penetration_depth);
399 deepest_penetration_depth_index = i;
403 const fcl::Contactd& contact = tmp_res.getContact(deepest_penetration_depth_index);
406 fcl::Vector3d normal = -contact.normal;
409 double signed_distance = -std::abs(contact.penetration_depth);
411 if (signed_distance > 0)
ThrowPretty(
"In collision but positive signed distance? " << signed_distance);
419 const fcl::Vector3d p_WAc{contact.pos + 0.5 * signed_distance * normal};
420 const fcl::Vector3d p_WBc{contact.pos - 0.5 * signed_distance * normal};
436 ThrowPretty(
"[This should not happen] In contact but did not return any contact points.");
441 data->
request.enable_nearest_points =
true;
442 data->
request.enable_signed_distance =
true;
443 data->
request.distance_tolerance = 1e-6;
444 data->
request.gjk_solver_type = fcl::GST_LIBCCD;
447 double min_dist = fcl::distance(o1, o2, data->
request, data->
result);
450 bool touching_contact =
false;
452 if (min_dist != data->
result.min_distance)
458 if (min_dist == -1 || std::abs(min_dist) < 1e-9)
460 touching_contact =
true;
468 if (o1->getObjectType() == fcl::OBJECT_TYPE::OT_GEOM && o2->getObjectType() == fcl::OBJECT_TYPE::OT_BVH)
482 if (std::isnan(c1(0)) || std::isnan(c1(1)) || std::isnan(c1(2)) || std::isnan(c2(0)) || std::isnan(c2(1)) || std::isnan(c2(2)))
488 if (data->
request.gjk_solver_type == fcl::GST_LIBCCD)
491 "Contact1 between " << p.
e1->segment.getName() <<
" and " << p.
e2->segment.getName() <<
" contains NaN" 492 <<
", where ShapeType1: " << p.
e1->shape->type <<
" and ShapeType2: " << p.
e2->shape->type <<
" and distance: " << p.
distance <<
" and solver: " << data->
request.gjk_solver_type);
494 if ((std::isnan(c1(0)) || std::isnan(c1(1)) || std::isnan(c1(2))) && p.
e1->shape->type == shapes::ShapeType::SPHERE) c1 = p.
e1->frame.p;
495 if ((std::isnan(c2(0)) || std::isnan(c2(1)) || std::isnan(c2(2))) && p.
e2->shape->type == shapes::ShapeType::SPHERE) c2 = p.
e1->frame.p;
501 "Contact1 between " << p.
e1->segment.getName() <<
" and " << p.
e2->segment.getName() <<
" contains NaN" 502 <<
", where ShapeType1: " << p.
e1->shape->type <<
" and ShapeType2: " << p.
e2->shape->type <<
" and distance: " << p.
distance <<
" and solver: " << data->
request.gjk_solver_type);
503 HIGHLIGHT(
"c1:" << data->
result.nearest_points[0](0) <<
"," << data->
result.nearest_points[0](1) <<
"," << data->
result.nearest_points[0](2));
504 HIGHLIGHT(
"c2:" << data->
result.nearest_points[1](0) <<
"," << data->
result.nearest_points[1](1) <<
"," << data->
result.nearest_points[1](2));
512 if (touching_contact)
546 return !data.
result.isCollision();
554 std::vector<fcl::CollisionObjectd*> shapes1;
555 std::vector<fcl::CollisionObjectd*> shapes2;
558 std::shared_ptr<KinematicElement> e =
kinematic_elements_[
reinterpret_cast<long>(o->getUserData())].lock();
561 if (e->segment.getName() == o1 || e->parent.lock()->segment.getName() == o1) shapes1.push_back(o);
562 if (e->segment.getName() == o2 || e->parent.lock()->segment.getName() == o2) shapes2.push_back(o);
564 if (shapes1.size() == 0)
ThrowPretty(
"Can't find object '" << o1 <<
"'!");
565 if (shapes2.size() == 0)
ThrowPretty(
"Can't find object '" << o2 <<
"'!");
568 for (fcl::CollisionObjectd* s1 : shapes1)
570 for (fcl::CollisionObjectd* s2 : shapes2)
573 if (data.
result.isCollision())
return false;
594 std::vector<fcl::CollisionObjectd*> shapes1;
595 std::vector<fcl::CollisionObjectd*> shapes2;
598 std::shared_ptr<KinematicElement> e =
kinematic_elements_[
reinterpret_cast<long>(o->getUserData())].lock();
601 if (e->segment.getName() == o1 || e->parent.lock()->segment.getName() == o1) shapes1.push_back(o);
602 if (e->segment.getName() == o2 || e->parent.lock()->segment.getName() == o2) shapes2.push_back(o);
604 if (shapes1.size() == 0)
ThrowPretty(
"Can't find object '" << o1 <<
"'!");
605 if (shapes2.size() == 0)
ThrowPretty(
"Can't find object '" << o2 <<
"'!");
607 for (fcl::CollisionObjectd* s1 : shapes1)
609 for (fcl::CollisionObjectd* s2 : shapes2)
623 const std::string& o1,
const bool&
self,
const bool& disable_collision_scene_update)
627 std::vector<fcl::CollisionObjectd*> shapes1;
628 std::vector<fcl::CollisionObjectd*> shapes2;
636 std::shared_ptr<KinematicElement> e =
kinematic_elements_[
reinterpret_cast<long>(o->getUserData())].lock();
638 if (e->segment.getName() == o1 || e->parent.lock()->segment.getName() == o1)
639 shapes1.push_back(o);
644 for (fcl::CollisionObjectd* o : fcl_objects_)
646 std::shared_ptr<KinematicElement> e =
kinematic_elements_[
reinterpret_cast<long>(o->getUserData())].lock();
648 if (e->segment.getName() != o1 || e->parent.lock()->segment.getName() != o1)
650 bool allowedToCollide =
false;
651 for (fcl::CollisionObjectd* o1_shape : shapes1)
655 allowedToCollide =
true;
660 if (allowedToCollide) shapes2.push_back(o);
665 if (shapes1.size() == 0 || shapes2.size() == 0)
return data.
proxies;
667 for (fcl::CollisionObjectd* s1 : shapes1)
669 for (fcl::CollisionObjectd* s2 : shapes2)
681 std::vector<CollisionProxy> proxies;
682 for (
const auto& o1 : objects)
696 for (
auto it2 : fcl_robot_objects_map_)
701 for (
auto o1 : it1.second)
703 for (
auto o2 : it2.second)
706 if (o1->getAABB().distance(o2->getAABB()) < check_margin)
731 for (
auto o1 : it1.second)
733 for (
auto o2 : it2.second)
736 if (o1->getAABB().distance(o2->getAABB()) < check_margin)
751 return Eigen::Map<Eigen::Vector3d>(element->frame.p.data);
772 fcl::CollisionObjectd* shape1 =
nullptr;
773 fcl::CollisionObjectd* shape2 =
nullptr;
777 std::shared_ptr<KinematicElement> e =
kinematic_elements_[
reinterpret_cast<long>(o->getUserData())].lock();
778 if (e->segment.getName() == o1)
784 if (e->segment.getName() == o2)
791 if (shape1 ==
nullptr)
ThrowPretty(
"o1 not found.");
792 if (shape2 ==
nullptr)
ThrowPretty(
"o2 not found.");
797 if (!allowedToCollide)
809 if (!tf1_beg_fcl.matrix().allFinite())
811 std::stringstream ss;
812 ss << std::setprecision(20);
813 ss <<
"[tf1_beg_fcl] is not finite\n" 814 << tf1_beg_fcl.matrix() <<
"\n" 816 throw std::logic_error(ss.str());
818 if (!tf1_end_fcl.matrix().allFinite())
820 std::stringstream ss;
821 ss << std::setprecision(20);
822 ss <<
"[tf1_end_fcl] is not finite\n" 823 << tf1_end_fcl.matrix() <<
"\n" 825 throw std::logic_error(ss.str());
827 if (!tf2_beg_fcl.matrix().allFinite())
829 std::stringstream ss;
830 ss << std::setprecision(20);
831 ss <<
"[tf2_beg_fcl] is not finite\n" 832 << tf2_beg_fcl.matrix() <<
"\n" 834 throw std::logic_error(ss.str());
836 if (!tf2_end_fcl.matrix().allFinite())
838 std::stringstream ss;
839 ss << std::setprecision(20);
840 ss <<
"[tf2_end_fcl] is not finite\n" 841 << tf2_end_fcl.matrix() <<
"\n" 843 throw std::logic_error(ss.str());
856 fcl::ContinuousCollisionRequestd request = fcl::ContinuousCollisionRequestd();
858 #ifdef CONTINUOUS_COLLISION_USE_ADVANCED_SETTINGS 859 request.num_max_iterations = 100;
860 request.toc_err = 1e-5;
866 request.ccd_motion_type = fcl::CCDMotionType::CCDM_SCREW;
871 request.ccd_solver_type = fcl::CCDC_NAIVE;
874 if (shape1->getObjectType() == fcl::OBJECT_TYPE::OT_GEOM && shape2->getObjectType() == fcl::OBJECT_TYPE::OT_GEOM)
876 request.ccd_solver_type = fcl::CCDC_CONSERVATIVE_ADVANCEMENT;
880 fcl::ContinuousCollisionResultd result;
881 double time_of_contact = fcl::continuousCollide(
882 shape1->collisionGeometry().get(), tf1_beg_fcl, tf1_end_fcl,
883 shape2->collisionGeometry().get(), tf2_beg_fcl, tf2_end_fcl,
886 #ifdef CONTINUOUS_COLLISION_DEBUG 887 HIGHLIGHT_NAMED(
"ContinuousCollisionResult",
"return=" << time_of_contact <<
" is_collide: " << result.is_collide <<
" time_of_contact: " << result.time_of_contact <<
" contact_tf1: " << result.contact_tf1.translation().transpose() <<
" contact_tf2: " << result.contact_tf2.translation().transpose());
889 (void)time_of_contact;
892 if (result.is_collide)
894 if (!result.contact_tf1.matrix().allFinite())
896 std::stringstream ss;
897 ss <<
"result.contact_tf1 is not finite\n" 898 << result.contact_tf1.matrix() <<
"\n";
899 throw std::logic_error(ss.str());
901 if (!result.contact_tf2.matrix().allFinite())
903 std::stringstream ss;
904 ss <<
"result.contact_tf2 is not finite\n" 905 << result.contact_tf2.matrix() <<
"\n";
906 throw std::logic_error(ss.str());
918 fcl::DistanceRequestd distance_req;
919 fcl::DistanceResultd distance_res;
920 distance_req.enable_nearest_points =
true;
921 distance_req.enable_signed_distance =
true;
923 distance_req.gjk_solver_type = fcl::GST_LIBCCD;
926 double min_dist = fcl::distance(shape1, shape2, distance_req, distance_res);
932 fcl::CollisionRequestd contact_req;
933 contact_req.enable_contact =
true;
934 contact_req.num_max_contacts = 1000;
935 contact_req.gjk_tolerance = 2e-12;
936 contact_req.gjk_solver_type = fcl::GJKSolverType::GST_LIBCCD;
937 fcl::CollisionResultd contact_res;
938 size_t num_contacts = fcl::collide(shape1->collisionGeometry().get(), result.contact_tf1, shape2->collisionGeometry().get(), result.contact_tf2, contact_req, contact_res);
939 if (num_contacts > 0)
941 std::vector<fcl::Contactd> contacts;
942 contact_res.getContacts(contacts);
944 for (
const auto& contact : contacts)
948 if (!contact.pos.allFinite())
950 std::stringstream ss;
951 ss << std::setprecision(20);
952 ss <<
"Error with configuration" 953 <<
"\n Shape 1: " << shape1->collisionGeometry().get()
955 << result.contact_tf1.matrix()
956 <<
"\n Shape 2: " << shape2->collisionGeometry().get()
958 << result.contact_tf2.matrix()
959 <<
"\n Solver: " << contact_req.gjk_solver_type;
960 throw std::logic_error(ss.str());
968 #ifdef CONTINUOUS_COLLISION_DEBUG 983 #ifdef CONTINUOUS_COLLISION_DEBUG bool IsAllowedToCollide(const std::string &o1, const std::string &o2, const bool &self) override
std::vector< std::shared_ptr< fcl::CollisionObjectd > > fcl_cache_
std::vector< std::string > GetCollisionRobotLinks() override
Gets the collision robot links.
Eigen::Vector3d contact_pos
void UpdateCollisionObjectTransforms() override
Updates collision object transformations from the kinematic tree.
std::weak_ptr< Scene > scene_
std::vector< CollisionProxy > proxies
static bool CollisionCallbackDistance(fcl::CollisionObjectd *o1, fcl::CollisionObjectd *o2, void *data, double &dist)
bool IsRobotLink(std::shared_ptr< KinematicElement > e)
double Normalize(double eps=epsilon)
Eigen::Vector3d GetTranslation(const std::string &name) override
bool replace_primitive_shapes_with_meshes_
static void CheckCollision(fcl::CollisionObjectd *o1, fcl::CollisionObjectd *o2, CollisionData *data)
fcl::CollisionRequestd request
std::vector< Key > GetKeysFromMap(const std::map< Key, Val > &map)
bool IsCollisionFree(const std::string &o1, const std::string &o2, double safe_distance=0.0) override
std::shared_ptr< Shape > ShapePtr
std::shared_ptr< KinematicElement > e1
std::shared_ptr< fcl::CollisionObjectd > ConstructFclCollisionObject(long i, std::shared_ptr< KinematicElement > element)
std::vector< fcl::CollisionObjectd * > fcl_objects_
std::vector< CollisionProxy > GetCollisionDistance(bool self) override
Computes collision distances.
TFSIMD_FORCE_INLINE Vector3 normalized() const
std::string ToString(const KDL::Frame &s)
fcl::Transform3d transformKDLToFCL(const KDL::Frame &frame)
CollisionSceneFCLLatest * scene
CollisionSceneFCLLatest * scene
bool IsStateValid(bool self=true, double safe_distance=0.0) override
Check if the whole robot is valid (collision only).
#define REGISTER_COLLISION_SCENE_TYPE(TYPE, DERIV)
std::vector< CollisionProxy > GetRobotToWorldCollisionDistance(double check_margin) override
std::vector< CollisionProxy > GetRobotToRobotCollisionDistance(double check_margin) override
ContinuousCollisionProxy ContinuousCollisionCheck(const std::string &o1, const KDL::Frame &tf1_beg, const KDL::Frame &tf1_end, const std::string &o2, const KDL::Frame &tf2_beg, const KDL::Frame &tf2_end) override
Performs a continuous collision check between two objects with a linear interpolation between two giv...
std::shared_ptr< KinematicElement > GetKinematicElementFromMapByName(const std::string &frame_name)
bool needs_update_of_collision_objects_
fcl::DistanceResultd result
std::map< std::string, std::weak_ptr< KinematicElement > > kinematic_elements_map_
bool always_externally_updated_collision_scene_
void transformFCLToKDL(const fcl::Transform3d &tf, KDL::Frame &frame)
std::shared_ptr< fcl::BroadPhaseCollisionManagerd > broad_phase_collision_manager_
Mesh * createMeshFromShape(const Sphere &sphere)
#define HIGHLIGHT_NAMED(name, x)
void UpdateCollisionObjects(const std::map< std::string, std::weak_ptr< KinematicElement >> &objects) override
Creates the collision scene from kinematic elements.
Eigen::Vector3d contact_normal
fcl::DistanceRequestd request
AllowedCollisionMatrix acm_
std::map< std::string, std::vector< fcl::CollisionObjectd * > > fcl_world_objects_map_
static void ComputeDistance(fcl::CollisionObjectd *o1, fcl::CollisionObjectd *o2, DistanceData *data)
std::vector< std::string > GetCollisionWorldLinks() override
Gets the collision world links.
fcl::CollisionResultd result
double world_link_padding_
bool getAllowedCollision(const std::string &name1, const std::string &name2) const
std::shared_ptr< KinematicElement > e2
void AppendVector(std::vector< Val > &orig, const std::vector< Val > &extra)
static bool CollisionCallback(fcl::CollisionObjectd *o1, fcl::CollisionObjectd *o2, void *data)
std::map< std::string, std::vector< fcl::CollisionObjectd * > > fcl_robot_objects_map_
std::vector< std::weak_ptr< KinematicElement > > kinematic_elements_
std::shared_ptr< KinematicElement > e2
double robot_link_padding_
std::shared_ptr< KinematicElement > e1
bool replace_cylinders_with_capsules_
std::map< std::string, std::vector< fcl::CollisionObjectd * > > fcl_objects_map_