38#include <geometric_shapes/shapes.h>
40#include <rclcpp/logger.hpp>
41#include <rclcpp/logging.hpp>
44#if (MOVEIT_FCL_VERSION >= FCL_VERSION_CHECK(0, 6, 0))
45#include <fcl/geometry/bvh/BVH_model.h>
46#include <fcl/geometry/octree/octree.h>
48#include <fcl/BVH/BVH_model.h>
49#include <fcl/shape/geometric_shapes.h>
50#include <fcl/octree.h>
99 bool always_allow_collision =
false;
109 always_allow_collision =
true;
112 RCLCPP_DEBUG(getLogger(),
113 "Collision between '%s' (type '%s') and '%s' (type '%s') is always allowed. "
114 "No contacts are computed.",
124 RCLCPP_DEBUG(getLogger(),
"Collision between '%s' and '%s' is conditionally allowed", cd1->
getID().c_str(),
125 cd2->
getID().c_str());
135 if (tl.find(cd1->
getID()) != tl.end())
137 always_allow_collision =
true;
140 RCLCPP_DEBUG(getLogger(),
"Robot link '%s' is allowed to touch attached object '%s'. No contacts are computed.",
148 if (tl.find(cd2->
getID()) != tl.end())
150 always_allow_collision =
true;
153 RCLCPP_DEBUG(getLogger(),
"Robot link '%s' is allowed to touch attached object '%s'. No contacts are computed.",
165 always_allow_collision =
true;
171 if (tl1.find(cd2->
getID()) != tl1.end() || tl2.find(cd1->
getID()) != tl2.end())
173 always_allow_collision =
true;
176 if (always_allow_collision && cdata->
req_->
verbose)
178 RCLCPP_DEBUG(getLogger(),
179 "Attached object '%s' is allowed to touch attached object '%s'. No contacts are computed.",
185 if (always_allow_collision)
190 RCLCPP_DEBUG(getLogger(),
"Actually checking collisions between %s and %s", cd1->
getID().c_str(),
191 cd2->
getID().c_str());
195 std::size_t want_contact_count{ 0 };
203 std::pair<std::string, std::string> cp(cd1->
getID(), cd2->
getID());
208 std::pair<std::string, std::string> cp(cd2->
getID(), cd1->
getID());
211 if (have < cdata->req_->max_contacts_per_pair)
222 bool enable_cost = cdata->
req_->
cost;
224 bool enable_contact =
true;
226 int num_contacts = fcl::collide(o1, o2,
228 num_max_cost_sources, enable_cost),
230 if (num_contacts > 0)
234 RCLCPP_INFO(getLogger(),
235 "Found %d contacts between '%s' and '%s'. "
236 "These contacts will be evaluated to check if they are accepted or not",
237 num_contacts, cd1->
getID().c_str(), cd2->
getID().c_str());
240 const std::pair<std::string, std::string>& pc = cd1->
getID() < cd2->
getID() ?
243 for (
int i = 0; i < num_contacts; ++i)
250 if (want_contact_count > 0)
252 --want_contact_count;
257 RCLCPP_INFO(getLogger(),
"Found unacceptable contact between '%s' and '%s'. Contact was stored.",
263 RCLCPP_INFO(getLogger(),
264 "Found unacceptable contact between '%s' (type '%s') and '%s' "
265 "(type '%s'). Contact was stored.",
270 if (want_contact_count == 0)
278 std::vector<fcl::CostSourced> cost_sources;
279 col_result.getCostSources(cost_sources);
282 for (
auto& cost_source : cost_sources)
293 if (want_contact_count > 0)
296 bool enable_cost = cdata->
req_->
cost;
298 bool enable_contact{
true };
305 if (num_contacts > 0)
307 int num_contacts_initial = num_contacts;
310 if (want_contact_count >=
static_cast<std::size_t
>(num_contacts))
312 want_contact_count -= num_contacts;
316 num_contacts = want_contact_count;
317 want_contact_count = 0;
322 RCLCPP_INFO(getLogger(),
323 "Found %d contacts between '%s' (type '%s') and '%s' (type '%s'), "
324 "which constitute a collision. %d contacts will be stored",
329 const std::pair<std::string, std::string>& pc = cd1->
getID() < cd2->
getID() ?
333 for (
int i = 0; i < num_contacts; ++i)
344 std::vector<fcl::CostSourced> cost_sources;
345 col_result.getCostSources(cost_sources);
348 for (
auto& cost_source : cost_sources)
359 bool enable_cost = cdata->
req_->
cost;
361 bool enable_contact =
false;
363 int num_contacts = fcl::collide(
365 if (num_contacts > 0)
370 RCLCPP_INFO(getLogger(),
371 "Found a contact between '%s' (type '%s') and '%s' (type '%s'), "
372 "which constitutes a collision. "
373 "Contact information is not stored.",
381 std::vector<fcl::CostSourced> cost_sources;
382 col_result.getCostSources(cost_sources);
385 for (
auto& cost_source : cost_sources)
404 RCLCPP_INFO(getLogger(),
405 "Collision checking is considered complete (collision was found and %u contacts are stored)",
416 RCLCPP_INFO(getLogger(),
417 "Collision checking is considered complete due to external callback. "
418 "%s was found. %u contacts are stored.",
433 using ShapeMap = std::map<ShapeKey, FCLGeometryConstPtr, std::owner_less<ShapeKey>>;
447 for (
auto it =
map_.begin(); it !=
map_.end();)
451 if (it->first.expired())
503 bool always_allow_collision =
false;
513 always_allow_collision =
true;
516 RCLCPP_DEBUG(getLogger(),
"Collision between '%s' and '%s' is always allowed. No distances are computed.",
527 if (tl.find(cd1->
getID()) != tl.end())
529 always_allow_collision =
true;
532 RCLCPP_DEBUG(getLogger(),
533 "Robot link '%s' is allowed to touch attached object '%s'. No distances are computed.",
541 if (tl.find(cd2->
getID()) != tl.end())
543 always_allow_collision =
true;
546 RCLCPP_DEBUG(getLogger(),
547 "Robot link '%s' is allowed to touch attached object '%s'. No distances are computed.",
553 if (always_allow_collision)
559 RCLCPP_DEBUG(getLogger(),
"Actually checking collisions between %s and %s", cd1->
getID().c_str(),
560 cd2->
getID().c_str());
565 const std::pair<const std::string&, const std::string&> pc =
566 cd1->
getID() < cd2->
getID() ? std::make_pair(std::cref(cd1->
getID()), std::cref(cd2->
getID())) :
567 std::make_pair(std::cref(cd2->
getID()), std::cref(cd1->
getID()));
569 DistanceMap::iterator it = cdata->
res->
distances.find(pc);
572 if (cdata->
req->
type == DistanceRequestType::GLOBAL)
579 if (cdata->
req->
type == DistanceRequestType::LIMITED)
587 else if (cdata->
req->
type == DistanceRequestType::SINGLE)
589 dist_threshold = it->second[0].distance;
594 fcl_result.min_distance = dist_threshold;
596 if ((o1->getObjectType() == fcl::OT_OCTREE &&
597 !std::static_pointer_cast<const fcl::OcTreed>(o1->collisionGeometry())->getRoot()) ||
598 (o2->getObjectType() == fcl::OT_OCTREE &&
599 !std::static_pointer_cast<const fcl::OcTreed>(o2->collisionGeometry())->getRoot()))
608 if (distance < dist_threshold)
613 dist_result.
distance = fcl_result.min_distance;
620#if (MOVEIT_FCL_VERSION >= FCL_VERSION_CHECK(0, 6, 0))
624 dist_result.
nearest_points[0] = Eigen::Map<const Eigen::Vector3d>(fcl_result.nearest_points[0].data.vs);
625 dist_result.
nearest_points[1] = Eigen::Map<const Eigen::Vector3d>(fcl_result.nearest_points[1].data.vs);
636 if (distance <= 0 && cdata->req->enable_signed_distance)
640 dist_result.
normal.setZero();
645 coll_req.enable_contact =
true;
646 coll_req.num_max_contacts = 200;
647 std::size_t contacts = fcl::collide(o1, o2, coll_req, coll_res);
652 for (std::size_t i = 0; i < contacts; ++i)
655 if (contact.penetration_depth > max_dist)
657 max_dist = contact.penetration_depth;
662 const fcl::Contactd& contact = coll_res.getContact(max_index);
663 dist_result.
distance = -contact.penetration_depth;
665#if (MOVEIT_FCL_VERSION >= FCL_VERSION_CHECK(0, 6, 0))
669 dist_result.
nearest_points[0] = Eigen::Map<const Eigen::Vector3d>(contact.pos.data.vs);
670 dist_result.
nearest_points[1] = Eigen::Map<const Eigen::Vector3d>(contact.pos.data.vs);
675#if (MOVEIT_FCL_VERSION >= FCL_VERSION_CHECK(0, 6, 0))
676 Eigen::Vector3d normal(contact.normal);
678 Eigen::Vector3d normal(contact.normal.data.vs);
682 if (contact.o1 == o1->collisionGeometry().get())
684 dist_result.
normal = normal;
688 dist_result.
normal = -normal;
704 if (cdata->
req->
type != DistanceRequestType::GLOBAL)
708 std::vector<DistanceResultsData> data;
710 data.push_back(dist_result);
715 if (cdata->
req->
type == DistanceRequestType::ALL)
717 it->second.push_back(dist_result);
719 else if (cdata->
req->
type == DistanceRequestType::SINGLE)
721 if (dist_result.
distance < it->second[0].distance)
722 it->second[0] = dist_result;
724 else if (cdata->
req->
type == DistanceRequestType::LIMITED)
727 it->second.push_back(dist_result);
744template <
typename BV,
typename T>
765template <
typename BV,
typename T>
768 using ShapeKey = shapes::ShapeConstWeakPtr;
769 using ShapeMap = std::map<ShapeKey, FCLGeometryConstPtr, std::owner_less<ShapeKey>>;
773 shapes::ShapeConstWeakPtr wptr(shape);
775 ShapeMap::const_iterator cache_it = cache.
map_.find(wptr);
776 if (cache_it != cache.
map_.end())
778 if (cache_it->second->collision_geometry_data_->ptr.raw == data)
783 return cache_it->second;
785 else if (cache_it->second.unique())
787 const_cast<FCLGeometry*
>(cache_it->second.get())->updateCollisionGeometryData(data, shape_index,
false);
792 return cache_it->second;
800 if (std::is_same<T, moveit::core::AttachedBody>::value)
803 FCLShapeCache& othercache = getShapeCache<BV, World::Object>();
806 auto cache_it = othercache.
map_.find(wptr);
807 if (cache_it != othercache.
map_.end())
809 if (cache_it->second.unique())
812 FCLGeometryConstPtr obj_cache = cache_it->second;
813 othercache.
map_.erase(cache_it);
815 const_cast<FCLGeometry*
>(obj_cache.get())->updateCollisionGeometryData(data, shape_index,
true);
823 cache.
map_[wptr] = obj_cache;
833 if (std::is_same<T, World::Object>::value)
836 FCLShapeCache& othercache = getShapeCache<BV, moveit::core::AttachedBody>();
839 auto cache_it = othercache.
map_.find(wptr);
840 if (cache_it != othercache.
map_.end())
842 if (cache_it->second.unique())
845 FCLGeometryConstPtr obj_cache = cache_it->second;
846 othercache.
map_.erase(cache_it);
849 const_cast<FCLGeometry*
>(obj_cache.get())->updateCollisionGeometryData(data, shape_index,
true);
858 cache.
map_[wptr] = obj_cache;
871 const shapes::Plane* p =
static_cast<const shapes::Plane*
>(shape.get());
877 const shapes::Sphere* s =
static_cast<const shapes::Sphere*
>(shape.get());
883 const shapes::Box* s =
static_cast<const shapes::Box*
>(shape.get());
884 const double* size = s->size;
885 cg_g =
new fcl::Boxd(size[0], size[1], size[2]);
888 case shapes::CYLINDER:
890 const shapes::Cylinder* s =
static_cast<const shapes::Cylinder*
>(shape.get());
896 const shapes::Cone* s =
static_cast<const shapes::Cone*
>(shape.get());
902 auto g =
new fcl::BVHModel<BV>();
903 const shapes::Mesh* mesh =
static_cast<const shapes::Mesh*
>(shape.get());
904 if (mesh->vertex_count > 0 && mesh->triangle_count > 0)
906 std::vector<fcl::Triangle> tri_indices(mesh->triangle_count);
907 for (
unsigned int i = 0; i < mesh->triangle_count; ++i)
910 fcl::Triangle(mesh->triangles[3 * i], mesh->triangles[3 * i + 1], mesh->triangles[3 * i + 2]);
913 std::vector<fcl::Vector3d> points(mesh->vertex_count);
914 for (
unsigned int i = 0; i < mesh->vertex_count; ++i)
915 points[i] =
fcl::Vector3d(mesh->vertices[3 * i], mesh->vertices[3 * i + 1], mesh->vertices[3 * i + 2]);
918 g->addSubModel(points, tri_indices);
926 const shapes::OcTree* g =
static_cast<const shapes::OcTree*
>(shape.get());
931 RCLCPP_ERROR(getLogger(),
"This shape type (%d) is not supported using FCL yet",
static_cast<int>(shape->type));
937 cg_g->computeLocalAABB();
938 FCLGeometryConstPtr res = std::make_shared<const FCLGeometry>(cg_g, data, shape_index);
939 cache.
map_[wptr] = res;
943 return FCLGeometryConstPtr();
949 return createCollisionGeometry<fcl::OBBRSSd, moveit::core::LinkModel>(shape, link, shape_index);
955 return createCollisionGeometry<fcl::OBBRSSd, moveit::core::AttachedBody>(shape, ab, shape_index);
960 return createCollisionGeometry<fcl::OBBRSSd, World::Object>(shape, obj, 0);
965template <
typename BV,
typename T>
967 const T* data,
int shape_index)
969 if (fabs(scale - 1.0) <= std::numeric_limits<double>::epsilon() &&
970 fabs(padding) <= std::numeric_limits<double>::epsilon())
972 return createCollisionGeometry<BV, T>(shape, data, shape_index);
976 shapes::ShapePtr scaled_shape(shape->clone());
977 scaled_shape->scaleAndPadd(scale, padding);
978 return createCollisionGeometry<BV, T>(scaled_shape, data, shape_index);
985 return createCollisionGeometry<fcl::OBBRSSd, moveit::core::LinkModel>(shape, scale, padding, link, shape_index);
991 return createCollisionGeometry<fcl::OBBRSSd, moveit::core::AttachedBody>(shape, scale, padding, ab, shape_index);
997 return createCollisionGeometry<fcl::OBBRSSd, World::Object>(shape, scale, padding, obj, 0);
1002 FCLShapeCache& cache1 = getShapeCache<fcl::OBBRSSd, World::Object>();
1006 FCLShapeCache& cache2 = getShapeCache<fcl::OBBRSSd, moveit::core::AttachedBody>();
1029 if (!collision_objects.empty())
1030 manager->registerObjects(collision_objects);
1036 manager->unregisterObject(collision_object.get());
bool getAllowedCollision(const std::string &name1, const std::string &name2, DecideContactFn &fn) const
Get the allowed collision predicate between two elements. Return true if a predicate for entry is inc...
Object defining bodies that can be attached to robot links.
const LinkModel * getAttachedLink() const
Get the model of the link this body is attached to.
const std::set< std::string > & getTouchLinks() const
Get the links that the attached body is allowed to touch.
A link from the robot. Contains the constant transform applied to the link and its geometry.
@ CONDITIONAL
The collision is allowed depending on a predicate evaluated on the produced contact....
@ ALWAYS
Collisions between a particular pair of bodies does not imply that the robot configuration is in coll...
@ ROBOT_LINK
A link on the robot.
@ ROBOT_ATTACHED
A body attached to a robot link.
rclcpp::Logger getLogger()
void fcl2contact(const fcl::Contactd &fc, Contact &c)
Transforms an FCL contact into a MoveIt contact point.
FCLGeometryConstPtr createCollisionGeometry(const shapes::ShapeConstPtr &shape, const moveit::core::LinkModel *link, int shape_index)
Create new FCLGeometry object out of robot link model.
FCLShapeCache & getShapeCache()
void cleanCollisionGeometryCache()
Increases the counter of the caches which can trigger the cleaning of expired entries from them.
bool collisionCallback(fcl::CollisionObjectd *o1, fcl::CollisionObjectd *o2, void *data)
Callback function used by the FCLManager used for each pair of collision objects to calculate object ...
std::function< bool(collision_detection::Contact &)> DecideContactFn
Signature of predicate that decides whether a contact is allowed or not (when AllowedCollision::Type ...
void fcl2costsource(const fcl::CostSourced &fcs, CostSource &cs)
Transforms the FCL internal representation to the MoveIt CostSource data structure.
bool distanceCallback(fcl::CollisionObjectd *o1, fcl::CollisionObjectd *o2, void *data, double &min_dist)
Callback function used by the FCLManager used for each pair of collision objects to calculate collisi...
fcl::CollisionObject CollisionObjectd
fcl::DistanceResult DistanceResultd
fcl::BroadPhaseCollisionManager BroadPhaseCollisionManagerd
fcl::DistanceRequest DistanceRequestd
fcl::CollisionGeometry CollisionGeometryd
fcl::CollisionResult CollisionResultd
fcl::CollisionRequest CollisionRequestd
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Data structure which is passed to the collision callback function of the collision manager.
const std::set< const moveit::core::LinkModel * > * active_components_only_
If the collision request includes a group name, this set contains the pointers to the link models tha...
const AllowedCollisionMatrix * acm_
The user-specified collision matrix (may be nullptr).
void enableGroup(const moveit::core::RobotModelConstPtr &robot_model)
Compute active_components_only_ based on the joint group specified in req_.
bool done_
Flag indicating whether collision checking is complete.
CollisionResult * res_
The user-specified response location.
const CollisionRequest * req_
The collision request passed by the user.
Wrapper around world, link and attached objects' geometry data.
const moveit::core::LinkModel * link
bool sameObject(const CollisionGeometryData &other) const
Check if two CollisionGeometryData objects point to the same source object.
const std::string & getID() const
Returns the name which is saved in the member pointed to in ptr.
std::string getTypeString() const
Returns a string of the corresponding type.
const moveit::core::AttachedBody * ab
union collision_detection::CollisionGeometryData::@0 ptr
Points to the type of body which contains the geometry.
BodyType type
Indicates the body type of the object.
std::string group_name
The group name to check collisions for (optional; if empty, assume the complete robot)....
bool verbose
Flag indicating whether information about detected collisions should be reported.
std::size_t max_cost_sources
When costs are computed, this value defines how many of the top cost sources should be returned.
bool contacts
If true, compute contacts. Otherwise only a binary collision yes/no is reported.
bool cost
If true, a collision cost is computed.
std::size_t max_contacts
Overall maximum number of contacts to compute.
std::function< bool(const CollisionResult &)> is_done
Function call that decides whether collision detection should stop.
std::size_t max_contacts_per_pair
Maximum number of contacts to compute per pair of bodies (multiple bodies may be in contact at differ...
std::set< CostSource > cost_sources
These are the individual cost sources when costs are computed.
bool collision
True if collision was found, false otherwise.
std::size_t contact_count
Number of contacts returned.
When collision costs are computed, this structure contains information about the partial cost incurre...
Data structure which is passed to the distance callback function of the collision manager.
DistanceResult * res
Distance query results information.
const DistanceRequest * req
Distance query request information.
bool done
Indicates if distance query is finished.
const std::set< const moveit::core::LinkModel * > * active_components_only
The set of active components to check.
bool verbose
Log debug information.
std::size_t max_contacts_per_body
Maximum number of contacts to store for bodies (multiple bodies may be within distance threshold)
double distance_threshold
bool enable_signed_distance
Indicate if a signed distance should be calculated in a collision.
const AllowedCollisionMatrix * acm
The allowed collision matrix used to filter checks.
bool enable_nearest_points
Indicate if nearest point information should be calculated.
DistanceMap distances
A map of distance data for each link in the req.active_components_only.
bool collision
Indicates if two objects were in collision.
DistanceResultsData minimum_distance
ResultsData for the two objects with the minimum distance.
Generic representation of the distance information for a pair of objects.
BodyType body_types[2]
The object body type.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Eigen::Vector3d nearest_points[2]
The nearest points.
std::string link_names[2]
The object link names.
double distance
The distance between two objects. If two objects are in collision, distance <= 0.
Bundles the CollisionGeometryData and FCL collision geometry representation into a single class.
std::vector< FCLCollisionObjectPtr > collision_objects_
void unregisterFrom(fcl::BroadPhaseCollisionManagerd *manager)
std::vector< FCLGeometryConstPtr > collision_geometry_
Geometry data corresponding to collision_objects_.
void registerTo(fcl::BroadPhaseCollisionManagerd *manager)
Cache for an arbitrary type of shape. It is assigned during the execution of createCollisionGeometry(...
ShapeMap map_
Map of weak pointers to the FCLGeometry.
static const unsigned int MAX_CLEAN_COUNT
void bumpUseCount(bool force=false)
shapes::ShapeConstWeakPtr ShapeKey
unsigned int clean_count_
Counts cache usage and triggers clearing of cache when \m MAX_CLEAN_COUNT is exceeded.
std::map< ShapeKey, FCLGeometryConstPtr, std::owner_less< ShapeKey > > ShapeMap
A representation of an object.