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