00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "robot_self_filter/self_mask.h"
00031 #include <urdf/model.h>
00032 #include <resource_retriever/retriever.h>
00033 #include <geometric_shapes/shape_operations.h>
00034 #include <ros/console.h>
00035 #include <algorithm>
00036 #include <sstream>
00037 #include <climits>
00038 #include <assimp/assimp.hpp>
00039 #include <assimp/aiScene.h>
00040 #include <assimp/aiPostProcess.h>
00041
00042 void robot_self_filter::SelfMask::freeMemory (void)
00043 {
00044 for (unsigned int i = 0 ; i < bodies_.size() ; ++i)
00045 {
00046 if (bodies_[i].body)
00047 delete bodies_[i].body;
00048 if (bodies_[i].unscaledBody)
00049 delete bodies_[i].unscaledBody;
00050 }
00051
00052 bodies_.clear ();
00053 }
00054
00055
00056 namespace robot_self_filter
00057 {
00058 static inline btTransform urdfPose2btTransform(const urdf::Pose &pose)
00059 {
00060 return btTransform(btQuaternion(pose.rotation.x, pose.rotation.y, pose.rotation.z, pose.rotation.w), btVector3(pose.position.x, pose.position.y, pose.position.z));
00061 }
00062
00063 static shapes::Shape* constructShape(const urdf::Geometry *geom)
00064 {
00065 ROS_ASSERT(geom);
00066
00067 shapes::Shape *result = NULL;
00068 switch (geom->type)
00069 {
00070 case urdf::Geometry::SPHERE:
00071 {
00072 result = new shapes::Sphere(dynamic_cast<const urdf::Sphere*>(geom)->radius);
00073 break;
00074 }
00075 case urdf::Geometry::BOX:
00076 {
00077 urdf::Vector3 dim = dynamic_cast<const urdf::Box*>(geom)->dim;
00078 result = new shapes::Box(dim.x, dim.y, dim.z);
00079 break;
00080 }
00081 case urdf::Geometry::CYLINDER:
00082 {
00083 result = new shapes::Cylinder(dynamic_cast<const urdf::Cylinder*>(geom)->radius,
00084 dynamic_cast<const urdf::Cylinder*>(geom)->length);
00085 break;
00086 }
00087 case urdf::Geometry::MESH:
00088 {
00089 const urdf::Mesh *mesh = dynamic_cast<const urdf::Mesh*>(geom);
00090 if (!mesh->filename.empty())
00091 {
00092 resource_retriever::Retriever retriever;
00093 resource_retriever::MemoryResource res;
00094 bool ok = true;
00095
00096 try
00097 {
00098 res = retriever.get(mesh->filename);
00099 }
00100 catch (resource_retriever::Exception& e)
00101 {
00102 ROS_ERROR("%s", e.what());
00103 ok = false;
00104 }
00105
00106 if (ok)
00107 {
00108 if (res.size == 0)
00109 ROS_WARN("Retrieved empty mesh for resource '%s'", mesh->filename.c_str());
00110 else
00111 {
00112
00113 Assimp::Importer importer;
00114
00115
00116 std::string hint;
00117 std::size_t pos = mesh->filename.find_last_of(".");
00118 if (pos != std::string::npos)
00119 {
00120 hint = mesh->filename.substr(pos + 1);
00121
00122
00123 if (hint.find("stl") != std::string::npos)
00124 hint = "stl";
00125 }
00126
00127
00128 const aiScene* scene = importer.ReadFileFromMemory(reinterpret_cast<void*>(res.data.get()), res.size,
00129 aiProcess_Triangulate |
00130 aiProcess_JoinIdenticalVertices |
00131 aiProcess_SortByPType, hint.c_str());
00132 btVector3 scale(mesh->scale.x, mesh->scale.y, mesh->scale.z);
00133 if (scene)
00134 {
00135 if (scene->HasMeshes())
00136 {
00137 if (scene->mNumMeshes > 1)
00138 ROS_WARN("More than one mesh specified in resource. Using first one");
00139 result = shapes::createMeshFromAsset(scene->mMeshes[0], scale);
00140 }
00141 else
00142 ROS_ERROR("There is no mesh specified in the indicated resource");
00143 }
00144 else
00145 {
00146 std::string ext;
00147 importer.GetExtensionList(ext);
00148 ROS_ERROR("Failed to import scene containing mesh: %s. Supported extensions are: %s", importer.GetErrorString(), ext.c_str());
00149 }
00150
00151 if (result == NULL)
00152 ROS_ERROR("Failed to load mesh '%s'", mesh->filename.c_str());
00153 else
00154 ROS_DEBUG("Loaded mesh '%s' consisting of %d triangles", mesh->filename.c_str(), static_cast<shapes::Mesh*>(result)->triangleCount);
00155 }
00156 }
00157 }
00158 else
00159 ROS_WARN("Empty mesh filename");
00160 break;
00161 }
00162 default:
00163 {
00164 ROS_ERROR("Unknown geometry type: %d", (int)geom->type);
00165 break;
00166 }
00167 }
00168 return (result);
00169 }
00170 }
00171
00172 bool robot_self_filter::SelfMask::configure(const std::vector<LinkInfo> &links)
00173 {
00174
00175 freeMemory();
00176 sensor_pos_.setValue(0, 0, 0);
00177
00178 std::string content;
00179 boost::shared_ptr<urdf::Model> urdfModel;
00180
00181 if (nh_.getParam("robot_description", content))
00182 {
00183 urdfModel = boost::shared_ptr<urdf::Model>(new urdf::Model());
00184 if (!urdfModel->initString(content))
00185 {
00186 ROS_ERROR("Unable to parse URDF description!");
00187 return false;
00188 }
00189 }
00190 else
00191 {
00192 ROS_ERROR("Robot model not found! Did you remap 'robot_description'?");
00193 return false;
00194 }
00195
00196 std::stringstream missing;
00197
00198
00199
00200
00201 for (unsigned int i = 0 ; i < links.size() ; ++i)
00202 {
00203 const urdf::Link *link = urdfModel->getLink(links[i].name).get();
00204 if (!link)
00205 {
00206 missing << " " << links[i].name;
00207 continue;
00208 }
00209
00210 if (!(link->collision && link->collision->geometry))
00211 {
00212 ROS_WARN("No collision geometry specified for link '%s'", links[i].name.c_str());
00213 continue;
00214 }
00215
00216 shapes::Shape *shape = constructShape(link->collision->geometry.get());
00217
00218 if (!shape)
00219 {
00220 ROS_ERROR("Unable to construct collision shape for link '%s'", links[i].name.c_str());
00221 continue;
00222 }
00223
00224 SeeLink sl;
00225 sl.body = bodies::createBodyFromShape(shape);
00226
00227 if (sl.body)
00228 {
00229 sl.name = links[i].name;
00230
00231
00232
00233 sl.constTransf = urdfPose2btTransform(link->collision->origin);
00234
00235 sl.body->setScale(links[i].scale);
00236 sl.body->setPadding(links[i].padding);
00237 ROS_DEBUG_STREAM("Self see link name " << links[i].name << " padding " << links[i].padding);
00238 sl.volume = sl.body->computeVolume();
00239 sl.unscaledBody = bodies::createBodyFromShape(shape);
00240 bodies_.push_back(sl);
00241 }
00242 else
00243 ROS_WARN("Unable to create point inclusion body for link '%s'", links[i].name.c_str());
00244
00245 delete shape;
00246 }
00247
00248 if (missing.str().size() > 0)
00249 ROS_WARN("Some links were included for self mask but they do not exist in the model:%s", missing.str().c_str());
00250
00251 if (bodies_.empty())
00252 ROS_WARN("No robot links will be checked for self mask");
00253
00254
00255 std::sort(bodies_.begin(), bodies_.end(), SortBodies());
00256
00257 bspheres_.resize(bodies_.size());
00258 bspheresRadius2_.resize(bodies_.size());
00259
00260 for (unsigned int i = 0 ; i < bodies_.size() ; ++i)
00261 ROS_DEBUG("Self mask includes link %s with volume %f", bodies_[i].name.c_str(), bodies_[i].volume);
00262
00263
00264
00265 return true;
00266 }
00267
00268 void robot_self_filter::SelfMask::getLinkNames(std::vector<std::string> &frames) const
00269 {
00270 for (unsigned int i = 0 ; i < bodies_.size() ; ++i)
00271 frames.push_back(bodies_[i].name);
00272 }
00273
00274 void robot_self_filter::SelfMask::maskContainment(const pcl::PointCloud<pcl::PointXYZ>& data_in, std::vector<int> &mask)
00275 {
00276 mask.resize(data_in.points.size());
00277 if (bodies_.empty())
00278 std::fill(mask.begin(), mask.end(), (int)OUTSIDE);
00279 else
00280 {
00281 assumeFrame(data_in.header.frame_id,data_in.header.stamp);
00282 maskAuxContainment(data_in, mask);
00283 }
00284 }
00285
00286 void robot_self_filter::SelfMask::maskIntersection(const pcl::PointCloud<pcl::PointXYZ>& data_in, const std::string &sensor_frame, const double min_sensor_dist,
00287 std::vector<int> &mask, const boost::function<void(const btVector3&)> &callback)
00288 {
00289 mask.resize(data_in.points.size());
00290 if (bodies_.empty()) {
00291 std::fill(mask.begin(), mask.end(), (int)OUTSIDE);
00292 }
00293 else
00294 {
00295 assumeFrame(data_in.header.frame_id, data_in.header.stamp, sensor_frame, min_sensor_dist);
00296 if (sensor_frame.empty())
00297 maskAuxContainment(data_in, mask);
00298 else
00299 maskAuxIntersection(data_in, mask, callback);
00300 }
00301 }
00302
00303 void robot_self_filter::SelfMask::maskIntersection(const pcl::PointCloud<pcl::PointXYZ>& data_in, const btVector3 &sensor_pos, const double min_sensor_dist,
00304 std::vector<int> &mask, const boost::function<void(const btVector3&)> &callback)
00305 {
00306 mask.resize(data_in.points.size());
00307 if (bodies_.empty())
00308 std::fill(mask.begin(), mask.end(), (int)OUTSIDE);
00309 else
00310 {
00311 assumeFrame(data_in.header.frame_id, data_in.header.stamp, sensor_pos, min_sensor_dist);
00312 maskAuxIntersection(data_in, mask, callback);
00313 }
00314 }
00315
00316 void robot_self_filter::SelfMask::computeBoundingSpheres(void)
00317 {
00318 const unsigned int bs = bodies_.size();
00319 for (unsigned int i = 0 ; i < bs ; ++i)
00320 {
00321 bodies_[i].body->computeBoundingSphere(bspheres_[i]);
00322 bspheresRadius2_[i] = bspheres_[i].radius * bspheres_[i].radius;
00323 }
00324 }
00325
00326 void robot_self_filter::SelfMask::assumeFrame(const std::string& frame_id, const ros::Time& stamp, const btVector3 &sensor_pos, double min_sensor_dist)
00327 {
00328 assumeFrame(frame_id,stamp);
00329 sensor_pos_ = sensor_pos;
00330 min_sensor_dist_ = min_sensor_dist;
00331 }
00332
00333 void robot_self_filter::SelfMask::assumeFrame(const std::string& frame_id, const ros::Time& stamp, const std::string &sensor_frame, double min_sensor_dist)
00334 {
00335 assumeFrame(frame_id,stamp);
00336
00337 std::string err;
00338 if(!tf_.waitForTransform(frame_id, sensor_frame, stamp, ros::Duration(.1), ros::Duration(.01), &err)) {
00339 ROS_ERROR("WaitForTransform timed out from %s to %s after 100ms. Error string: %s", sensor_frame.c_str(), frame_id.c_str(), err.c_str());
00340 sensor_pos_.setValue(0, 0, 0);
00341 }
00342
00343
00344
00345 try
00346 {
00347 tf::StampedTransform transf;
00348 tf_.lookupTransform(frame_id, sensor_frame, stamp, transf);
00349 sensor_pos_ = transf.getOrigin();
00350 }
00351 catch(tf::TransformException& ex)
00352 {
00353 sensor_pos_.setValue(0, 0, 0);
00354 ROS_ERROR("Unable to lookup transform from %s to %s. Exception: %s", sensor_frame.c_str(), frame_id.c_str(), ex.what());
00355 }
00356
00357 min_sensor_dist_ = min_sensor_dist;
00358 }
00359
00360 void robot_self_filter::SelfMask::assumeFrame(const std::string &frame_id, const ros::Time &stamp)
00361 {
00362 const unsigned int bs = bodies_.size();
00363
00364
00365 for (unsigned int i = 0 ; i < bs ; ++i)
00366 {
00367 std::string err;
00368 if(!tf_.waitForTransform(frame_id, bodies_[i].name, stamp, ros::Duration(.1), ros::Duration(.01), &err)) {
00369 ROS_ERROR("WaitForTransform timed out from %s to %s after 100ms. Error string: %s", bodies_[i].name.c_str(), frame_id.c_str(), err.c_str());
00370 }
00371
00372
00373 tf::StampedTransform transf;
00374 try
00375 {
00376 tf_.lookupTransform(frame_id, bodies_[i].name, stamp, transf);
00377 }
00378 catch(tf::TransformException& ex)
00379 {
00380 transf.setIdentity();
00381 ROS_ERROR("Unable to lookup transform from %s to %s. Exception: %s", bodies_[i].name.c_str(), frame_id.c_str(), ex.what());
00382 }
00383
00384
00385 bodies_[i].body->setPose(transf * bodies_[i].constTransf);
00386 bodies_[i].unscaledBody->setPose(transf * bodies_[i].constTransf);
00387 }
00388
00389 computeBoundingSpheres();
00390 }
00391
00392 void robot_self_filter::SelfMask::maskAuxContainment(const pcl::PointCloud<pcl::PointXYZ>& data_in, std::vector<int> &mask)
00393 {
00394 const unsigned int bs = bodies_.size();
00395 const unsigned int np = data_in.points.size();
00396
00397
00398 bodies::BoundingSphere bound;
00399 bodies::mergeBoundingSpheres(bspheres_, bound);
00400 btScalar radiusSquared = bound.radius * bound.radius;
00401
00402
00403
00404 for (int i = 0 ; i < (int)np ; ++i)
00405 {
00406 btVector3 pt = btVector3(data_in.points[i].x, data_in.points[i].y, data_in.points[i].z);
00407 int out = OUTSIDE;
00408 if (bound.center.distance2(pt) < radiusSquared)
00409 for (unsigned int j = 0 ; out == OUTSIDE && j < bs ; ++j)
00410 if (bodies_[j].body->containsPoint(pt))
00411 out = INSIDE;
00412
00413 mask[i] = out;
00414 }
00415 }
00416
00417 void robot_self_filter::SelfMask::maskAuxIntersection(const pcl::PointCloud<pcl::PointXYZ>& data_in, std::vector<int> &mask, const boost::function<void(const btVector3&)> &callback)
00418 {
00419 const unsigned int bs = bodies_.size();
00420 const unsigned int np = data_in.points.size();
00421
00422
00423 bodies::BoundingSphere bound;
00424 bodies::mergeBoundingSpheres(bspheres_, bound);
00425 btScalar radiusSquared = bound.radius * bound.radius;
00426
00427
00428
00429
00430
00431 for (int i = 0 ; i < (int)np ; ++i)
00432 {
00433 bool print = false;
00434
00435 btVector3 pt = btVector3(data_in.points[i].x, data_in.points[i].y, data_in.points[i].z);
00436 int out = OUTSIDE;
00437
00438
00439
00440 if (bound.center.distance2(pt) < radiusSquared)
00441 for (unsigned int j = 0 ; out == OUTSIDE && j < bs ; ++j)
00442 if (bodies_[j].unscaledBody->containsPoint(pt))
00443 {
00444 if(print)
00445 std::cout << "Point " << i << " in unscaled body part " << bodies_[j].name << std::endl;
00446 out = INSIDE;
00447 }
00448
00449
00450 if (out == OUTSIDE)
00451 {
00452
00453 btVector3 dir(sensor_pos_ - pt);
00454 btScalar lng = dir.length();
00455 if (lng < min_sensor_dist_)
00456 {
00457 out = INSIDE;
00458
00459 }
00460 else
00461 {
00462 dir /= lng;
00463 std::vector<btVector3> intersections;
00464 for (unsigned int j = 0 ; out == OUTSIDE && j < bs ; ++j)
00465 {
00466 if (bodies_[j].body->intersectsRay(pt, dir, &intersections, 1))
00467 {
00468 if (dir.dot(sensor_pos_ - intersections[0]) >= 0.0)
00469 {
00470 if (callback)
00471 callback(intersections[0]);
00472 out = SHADOW;
00473 if(print) std::cout << "Point " << i << " shadowed by body part " << bodies_[j].name << std::endl;
00474 }
00475 }
00476 }
00477
00478 if (out == OUTSIDE && bound.center.distance2(pt) < radiusSquared)
00479 for (unsigned int j = 0 ; out == OUTSIDE && j < bs ; ++j)
00480 if (bodies_[j].body->containsPoint(pt))
00481 {
00482 if(print)
00483 std::cout << "Point " << i << " in scaled body part " << bodies_[j].name << std::endl;
00484 out = INSIDE;
00485 }
00486 }
00487 }
00488 mask[i] = out;
00489 }
00490 }
00491
00492 int robot_self_filter::SelfMask::getMaskContainment(const btVector3 &pt) const
00493 {
00494 const unsigned int bs = bodies_.size();
00495 int out = OUTSIDE;
00496 for (unsigned int j = 0 ; out == OUTSIDE && j < bs ; ++j)
00497 if (bodies_[j].body->containsPoint(pt))
00498 out = INSIDE;
00499 return out;
00500 }
00501
00502 int robot_self_filter::SelfMask::getMaskContainment(double x, double y, double z) const
00503 {
00504 return getMaskContainment(btVector3(x, y, z));
00505 }
00506
00507 int robot_self_filter::SelfMask::getMaskIntersection(const btVector3 &pt, const boost::function<void(const btVector3&)> &callback) const
00508 {
00509 const unsigned int bs = bodies_.size();
00510
00511
00512
00513 int out = OUTSIDE;
00514 for (unsigned int j = 0 ; out == OUTSIDE && j < bs ; ++j)
00515 if (bodies_[j].unscaledBody->containsPoint(pt))
00516 out = INSIDE;
00517
00518 if (out == OUTSIDE)
00519 {
00520
00521 btVector3 dir(sensor_pos_ - pt);
00522 btScalar lng = dir.length();
00523 if (lng < min_sensor_dist_)
00524 out = INSIDE;
00525 else
00526 {
00527 dir /= lng;
00528
00529 std::vector<btVector3> intersections;
00530 for (unsigned int j = 0 ; out == OUTSIDE && j < bs ; ++j)
00531 if (bodies_[j].body->intersectsRay(pt, dir, &intersections, 1))
00532 {
00533 if (dir.dot(sensor_pos_ - intersections[0]) >= 0.0)
00534 {
00535 if (callback)
00536 callback(intersections[0]);
00537 out = SHADOW;
00538 }
00539 }
00540
00541
00542 for (unsigned int j = 0 ; out == OUTSIDE && j < bs ; ++j)
00543 if (bodies_[j].body->containsPoint(pt))
00544 out = INSIDE;
00545 }
00546 }
00547 return (out);
00548 }
00549
00550 int robot_self_filter::SelfMask::getMaskIntersection(double x, double y, double z, const boost::function<void(const btVector3&)> &callback) const
00551 {
00552 return getMaskIntersection(btVector3(x, y, z), callback);
00553 }