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
00031
00032
00033
00034
00044 #include <ros/ros.h>
00045 #include "planning_environment/monitors/collision_space_monitor.h"
00046 #include "planning_environment/util/construct_object.h"
00047
00048 #include <geometric_shapes/bodies.h>
00049 #include <tf/message_filter.h>
00050 #include <message_filters/subscriber.h>
00051 #include <sensor_msgs/PointCloud.h>
00052 #include <geometry_msgs/PoseStamped.h>
00053 #include <mapping_msgs/AttachedCollisionObject.h>
00054 #include <mapping_msgs/CollisionObject.h>
00055
00056 class ClearKnownObjects
00057 {
00058 public:
00059
00060 ClearKnownObjects(void): nh_("~")
00061 {
00062 rm_ = new planning_environment::CollisionModels("robot_description");
00063 ROS_INFO("Starting");
00064 if (rm_->loadedModels())
00065 {
00066 kmsm_ = new planning_environment::CollisionSpaceMonitor(rm_, &tf_);
00067 nh_.param<std::string>("fixed_frame", fixed_frame_, kmsm_->getWorldFrameId());
00068 nh_.param<double>("object_scale", scale_, 1.0);
00069 nh_.param<double>("object_padd", padd_, 0.02);
00070 nh_.param<std::string>("sensor_frame", sensor_frame_, std::string());
00071 nh_.param<bool>("filter_static_objects", filter_static_objects_, false);
00072
00073 kmsm_->startEnvironmentMonitor();
00074
00075 ROS_INFO("Clearing points on known objects using '%s' as fixed frame, %f padding and %f scaling", fixed_frame_.c_str(), padd_, scale_);
00076
00077 cloudPublisher_ = root_handle_.advertise<sensor_msgs::PointCloud>("cloud_out", 1);
00078 kmsm_->setOnAfterAttachCollisionObjectCallback(boost::bind(&ClearKnownObjects::attachObjectEvent, this, _1));
00079 if(filter_static_objects_) {
00080 kmsm_->setOnAfterCollisionObjectCallback(boost::bind(&ClearKnownObjects::objectUpdateEvent, this, _1));
00081 }
00082
00083 cloudSubscriber_ = new message_filters::Subscriber<sensor_msgs::PointCloud>(root_handle_, "cloud_in", 1);
00084 cloudFilter_ = new tf::MessageFilter<sensor_msgs::PointCloud>(*cloudSubscriber_, tf_, fixed_frame_, 1);
00085 cloudFilter_->registerCallback(boost::bind(&ClearKnownObjects::cloudCallback, this, _1));
00086 }
00087 else
00088 {
00089 kmsm_ = NULL;
00090 cloudFilter_ = NULL;
00091 cloudSubscriber_ = NULL;
00092 }
00093 }
00094
00095 ~ClearKnownObjects(void)
00096 {
00097 ROS_INFO("Destructor getting called");
00098 if (cloudFilter_)
00099 delete cloudFilter_;
00100 if (cloudSubscriber_)
00101 delete cloudSubscriber_;
00102 if (kmsm_)
00103 delete kmsm_;
00104 if (rm_)
00105 delete rm_;
00106 for (std::map<std::string, KnownObject*>::iterator it = attached_objects_.begin(); it != attached_objects_.end(); it++) {
00107 delete it->second;
00108 }
00109 for (std::map<std::string, KnownObject*>::iterator it = collisionObjects_.begin() ; it != collisionObjects_.end() ; ++it)
00110 delete it->second;
00111 }
00112
00113 void run(void)
00114 {
00115 if (rm_->loadedModels())
00116 {
00117 kmsm_->waitForState();
00118 }
00119 }
00120
00121 private:
00122
00123 struct KnownObject
00124 {
00125 KnownObject(void)
00126 {
00127 }
00128
00129 ~KnownObject(void) {
00130 deleteBodies();
00131 }
00132
00133 void deleteBodies() {
00134 for(unsigned int i = 0; i < bodies.size(); i++) {
00135 delete bodies[i];
00136 }
00137 bodies.clear();
00138 }
00139
00140 void addBodyWithPose(bodies::Body* body, const btTransform &pose) {
00141 body->setPose(pose);
00142 bodies::BoundingSphere bsphere;
00143 body->computeBoundingSphere(bsphere);
00144 bodies.push_back(body);
00145 double rsquare = bsphere.radius * bsphere.radius;
00146 bspheres.push_back(bsphere);
00147 rsquares.push_back(rsquare);
00148 }
00149
00150 void usePose(const unsigned int i, const btTransform &pose) {
00151 if(i >= bodies.size()) {
00152 ROS_WARN("Not enough bodies");
00153 return;
00154 }
00155 bodies[i]->setPose(pose);
00156 bodies[i]->computeBoundingSphere(bspheres[i]);
00157 rsquares[i] = bspheres[i].radius*bspheres[i].radius;
00158 }
00159
00160 std::vector<bodies::Body*> bodies;
00161 std::vector<bodies::BoundingSphere> bspheres;
00162 std::vector<double> rsquares;
00163 };
00164
00165 void computeMask(const sensor_msgs::PointCloud &cloud, std::vector<int> &mask)
00166 {
00167 planning_models::KinematicState state(kmsm_->getKinematicModel());
00168
00169 kmsm_->setKinematicStateToTime(cloud.header.stamp, state);
00170
00171 updateObjects_.lock();
00172
00173
00174 if (attached_.size() > 0) {
00175
00176 if (fixed_frame_ != kmsm_->getWorldFrameId()) {
00177 std::string errStr;
00178 ros::Time tm;
00179 if (!tf_.getLatestCommonTime(kmsm_->getWorldFrameId(), fixed_frame_, tm, &errStr) == tf::NO_ERROR) {
00180 ROS_ERROR("Unable to transform attached body from frame '%s' to frame '%s'", kmsm_->getWorldFrameId().c_str(), fixed_frame_.c_str());
00181 if (!errStr.empty())
00182 ROS_ERROR("TF said: %s", errStr.c_str());
00183 } else {
00184 bool error = false;
00185 for (unsigned int i = 0 ; i < attached_.size() ; ++i) {
00186 const planning_models::KinematicState::AttachedBodyState* att_state = state.getAttachedBodyState(attached_[i]->getName());
00187 for(unsigned int j = 0; j < att_state->getGlobalCollisionBodyTransforms().size(); j++) {
00188 tf::Stamped<tf::Pose> pose(att_state->getGlobalCollisionBodyTransforms()[j], tm, kmsm_->getWorldFrameId());
00189 tf::Stamped<tf::Pose> poseOut;
00190 try {
00191 tf_.transformPose(fixed_frame_, pose, poseOut);
00192 attached_objects_[attached_[i]->getName()]->usePose(j,poseOut);
00193 } catch(...) {
00194 error = true;
00195 }
00196 }
00197 if (error)
00198 ROS_ERROR("Errors encountered when transforming attached bodies from frame '%s' to frame '%s'", kmsm_->getWorldFrameId().c_str(), fixed_frame_.c_str());
00199 }
00200 }
00201 } else {
00202 for (unsigned int i = 0 ; i < attached_.size() ; ++i) {
00203 const planning_models::KinematicState::AttachedBodyState* att_state = state.getAttachedBodyState(attached_[i]->getName());
00204 for(unsigned int j = 0; j < att_state->getGlobalCollisionBodyTransforms().size(); j++) {
00205 attached_objects_[attached_[i]->getName()]->usePose(j,att_state->getGlobalCollisionBodyTransforms()[j]);
00206 }
00207 }
00208 }
00209 }
00210
00211
00212 sensor_msgs::PointCloud temp;
00213 const sensor_msgs::PointCloud *cloudTransf = &cloud;
00214 if (fixed_frame_ != cloud.header.frame_id) {
00215 tf_.transformPointCloud(fixed_frame_, cloud, temp);
00216 cloudTransf = &temp;
00217 }
00218
00219 btVector3 sensor_pos(0, 0, 0);
00220
00221
00222 if (!sensor_frame_.empty()) {
00223 ros::Time tm;
00224 std::string err;
00225 if (tf_.getLatestCommonTime(sensor_frame_.c_str(), fixed_frame_.c_str(), tm, &err) == tf::NO_ERROR) {
00226 try {
00227 tf::StampedTransform transf;
00228 tf_.lookupTransform(fixed_frame_, sensor_frame_, tm, transf);
00229 sensor_pos = transf.getOrigin();
00230 } catch(tf::TransformException& ex) {
00231 ROS_ERROR("Unable to lookup transform from %s to %s. Exception: %s", sensor_frame_.c_str(), fixed_frame_.c_str(), ex.what());
00232 sensor_pos.setValue(0, 0, 0);
00233 }
00234 } else {
00235 ROS_WARN("No common time between %s and %s", sensor_frame_.c_str(), fixed_frame_.c_str());
00236 sensor_pos.setValue(0, 0, 0);
00237 }
00238 }
00239
00240
00241 int n = cloud.points.size();
00242 mask.resize(n);
00243
00244
00245 for (int i = 0 ; i < n ; ++i) {
00246 btVector3 pt = btVector3(cloudTransf->points[i].x, cloudTransf->points[i].y, cloudTransf->points[i].z);
00247 btVector3 dir(sensor_pos - pt);
00248 dir.normalize();
00249 int out = 1;
00250
00251 for(std::map<std::string, KnownObject*>::iterator it = attached_objects_.begin();
00252 out && it != attached_objects_.end();
00253 it++) {
00254 for(unsigned int k = 0; out && k < it->second->bodies.size(); k++) {
00255 if (it->second->bspheres[k].center.distance2(pt) < it->second->rsquares[k]) {
00256 if (it->second->bodies[k]->containsPoint(pt) || it->second->bodies[k]->intersectsRay(pt, dir)) {
00257 out = 0;
00258 }
00259 }
00260 }
00261 }
00262 for (std::map<std::string, KnownObject*>::iterator it = collisionObjects_.begin() ; out && it != collisionObjects_.end() ; ++it) {
00263 ROS_INFO("Have known objects");
00264 KnownObject* ko = it->second;
00265 for (unsigned int j = 0 ; out && j < ko->bodies.size(); ++j) {
00266 if(ko->bodies.size() != ko->bspheres.size() ||
00267 ko->bodies.size() != ko->rsquares.size()) {
00268 ROS_ERROR_STREAM("Bad sizes " << ko->bodies.size() << " " << ko->bspheres.size()
00269 << " " << ko->rsquares.size());
00270 continue;
00271 }
00272 if (ko->bspheres[j].center.distance2(pt) < ko->rsquares[j]) {
00273 if(ko->bodies[j]->containsPoint(pt)) {
00274 out = 0;
00275 }
00276 if (ko->bodies[j]->intersectsRay(pt, dir)) {
00277 out = 0;
00278 }
00279 }
00280 }
00281 }
00282 mask[i] = out;
00283 }
00284 }
00285
00286 void cloudCallback(const sensor_msgs::PointCloudConstPtr &cloud)
00287 {
00288 ROS_DEBUG("Got pointcloud that is %f seconds old", (ros::Time::now() - cloud->header.stamp).toSec());
00289
00290 std::vector<int> mask;
00291 bool filter = false;
00292
00293 if (attached_objects_.size() > 0 || collisionObjects_.size() > 0)
00294 {
00295 computeMask(*cloud, mask);
00296 filter = true;
00297 }
00298
00299 if (filter)
00300 {
00301
00302 const unsigned int np = cloud->points.size();
00303 sensor_msgs::PointCloud data_out;
00304
00305
00306 data_out.header = cloud->header;
00307
00308 data_out.points.resize(0);
00309 data_out.points.reserve(np);
00310
00311 data_out.channels.resize(cloud->channels.size());
00312 for (unsigned int i = 0 ; i < data_out.channels.size() ; ++i)
00313 {
00314 ROS_ASSERT(cloud->channels[i].values.size() == cloud->points.size());
00315 data_out.channels[i].name = cloud->channels[i].name;
00316 data_out.channels[i].values.reserve(cloud->channels[i].values.size());
00317 }
00318
00319 for (unsigned int i = 0 ; i < np ; ++i)
00320 if (mask[i])
00321 {
00322 data_out.points.push_back(cloud->points[i]);
00323 for (unsigned int j = 0 ; j < data_out.channels.size() ; ++j)
00324 data_out.channels[j].values.push_back(cloud->channels[j].values[i]);
00325 }
00326
00327 ROS_DEBUG("Published filtered cloud (%d points out of %d)", (int)data_out.points.size(), (int)cloud->points.size());
00328 cloudPublisher_.publish(data_out);
00329 }
00330 else
00331 {
00332 cloudPublisher_.publish(*cloud);
00333 ROS_DEBUG("Republished unchanged cloud");
00334 }
00335 updateObjects_.unlock();
00336 }
00337
00338 void objectUpdateEvent(const mapping_msgs::CollisionObjectConstPtr &collisionObject) {
00339 updateObjects_.lock();
00340 if (collisionObject->operation.operation == mapping_msgs::CollisionObjectOperation::ADD) {
00341 KnownObject* kb = new KnownObject();
00342 for(unsigned int i = 0; i < collisionObject->shapes.size(); i++) {
00343
00344 shapes::Shape *shape = planning_environment::constructObject(collisionObject->shapes[i]);
00345 if (shape) {
00346 bool err = false;
00347 geometry_msgs::PoseStamped psi;
00348 geometry_msgs::PoseStamped pso;
00349 psi.pose = collisionObject->poses[i];
00350 psi.header = collisionObject->header;
00351 try {
00352 tf_.transformPose(fixed_frame_, psi, pso);
00353 } catch(tf::TransformException& ex) {
00354 ROS_ERROR("Unable to transform object '%s' in frame '%s' to frame '%s' Exception: %s", collisionObject->id.c_str(), collisionObject->header.frame_id.c_str(), fixed_frame_.c_str(), ex.what());
00355 err = true;
00356 }
00357
00358 if (!err) {
00359 btTransform pose;
00360 tf::poseMsgToTF(pso.pose, pose);
00361 bodies::Body* body = bodies::createBodyFromShape(shape);
00362 body->setScale(scale_);
00363 body->setPadding(padd_);
00364 kb->addBodyWithPose(body, pose);
00365 }
00366 delete shape;
00367 }
00368 }
00369
00370 if(collisionObjects_.find(collisionObject->id) != collisionObjects_.end()) {
00371 delete collisionObjects_[collisionObject->id];
00372 collisionObjects_.erase(collisionObject->id);
00373 }
00374 collisionObjects_[collisionObject->id] = kb;
00375 ROS_INFO("Added object '%s' with to list of known objects", collisionObject->id.c_str());
00376 } else {
00377 if(collisionObject->id == "all") {
00378 for(std::map<std::string, KnownObject*>::iterator it = collisionObjects_.begin();
00379 it != collisionObjects_.end();
00380 it++) {
00381 delete it->second;
00382 }
00383 collisionObjects_.clear();
00384 } else if (collisionObjects_.find(collisionObject->id) != collisionObjects_.end()) {
00385 delete collisionObjects_[collisionObject->id];
00386 collisionObjects_.erase(collisionObject->id);
00387 } else
00388 ROS_WARN("Object '%s' is not in list of known objects", collisionObject->id.c_str());
00389 }
00390 updateObjects_.unlock();
00391 }
00392
00393 void attachObjectEvent(const mapping_msgs::AttachedCollisionObjectConstPtr& attachedObject) {
00394 ROS_INFO_STREAM("Calling attach object for object " << attachedObject->object.id << " operation " << attachedObject->object.operation.operation);
00395 updateObjects_.lock();
00396 if(attachedObject->object.operation.operation != mapping_msgs::CollisionObjectOperation::REMOVE) {
00397
00398 if(attachedObject->object.operation.operation == mapping_msgs::CollisionObjectOperation::DETACH_AND_ADD_AS_OBJECT) {
00399 if(attached_objects_.find(attachedObject->object.id) == attached_objects_.end()) {
00400 ROS_WARN_STREAM("No attached body " << attachedObject->object.id << " to detach");
00401 } else {
00402 if(filter_static_objects_) {
00403 if(collisionObjects_.find(attachedObject->object.id) != collisionObjects_.end()) {
00404 ROS_WARN("Already have object in objects in map");
00405 delete collisionObjects_[attachedObject->object.id];
00406 }
00407 collisionObjects_[attachedObject->object.id] = attached_objects_[attachedObject->object.id];
00408 }
00409 attached_objects_.erase(attachedObject->object.id);
00410 ROS_INFO_STREAM("Clear objects adding attached object " << attachedObject->object.id << " back to objects");
00411 }
00412 } else if(attachedObject->object.operation.operation == mapping_msgs::CollisionObjectOperation::ATTACH_AND_REMOVE_AS_OBJECT) {
00413 if(filter_static_objects_) {
00414 if(collisionObjects_.find(attachedObject->object.id) == collisionObjects_.end()) {
00415 ROS_WARN_STREAM("No object " << attachedObject->object.id << " to attach");
00416 } else {
00417 ROS_INFO_STREAM("Adding object " << attachedObject->object.id << " to attached objects");
00418 delete collisionObjects_[attachedObject->object.id];
00419 collisionObjects_.erase(attachedObject->object.id);
00420 }
00421 }
00422
00423 }
00424 }
00425
00426 attached_.clear();
00427 const std::vector<planning_models::KinematicModel::LinkModel*>& links = kmsm_->getKinematicModel()->getLinkModels();
00428 for (unsigned int i = 0 ; i < links.size() ; ++i) {
00429 for (unsigned int j = 0 ; j < links[i]->getAttachedBodyModels().size() ; ++j) {
00430 attached_.push_back(links[i]->getAttachedBodyModels()[j]);
00431 }
00432 }
00433 for(std::map<std::string, KnownObject*>::iterator it = attached_objects_.begin();
00434 it != attached_objects_.end();
00435 it++) {
00436 delete it->second;
00437 }
00438 attached_objects_.clear();
00439 for (unsigned int i = 0; i < attached_.size(); ++i) {
00440 KnownObject* kb = new KnownObject();
00441 for(unsigned int j = 0; j < attached_[i]->getShapes().size(); j++) {
00442 bodies::Body* body = bodies::createBodyFromShape(attached_[i]->getShapes()[j]);
00443 body->setScale(scale_);
00444 body->setPadding(padd_);
00445 btTransform ident;
00446 ident.setIdentity();
00447 kb->addBodyWithPose(body, ident);
00448 }
00449 attached_objects_[attached_[i]->getName()] = kb;
00450 }
00451 updateObjects_.unlock();
00452 }
00453
00454 ros::NodeHandle nh_;
00455 ros::NodeHandle root_handle_;
00456 tf::TransformListener tf_;
00457 planning_environment::CollisionModels *rm_;
00458 planning_environment::CollisionSpaceMonitor *kmsm_;
00459
00460 message_filters::Subscriber<sensor_msgs::PointCloud> *cloudSubscriber_;
00461 tf::MessageFilter<sensor_msgs::PointCloud> *cloudFilter_;
00462
00463 std::string fixed_frame_;
00464 boost::mutex updateObjects_;
00465 ros::Publisher cloudPublisher_;
00466
00467 std::string sensor_frame_;
00468 double scale_;
00469 double padd_;
00470 std::vector<const planning_models::KinematicModel::AttachedBodyModel*> attached_;
00471 std::map<std::string, KnownObject*> attached_objects_;
00472 std::map<std::string, KnownObject*> collisionObjects_;
00473 bool filter_static_objects_;
00474 };
00475
00476
00477 int main(int argc, char **argv)
00478 {
00479 ros::init(argc, argv, "clear_known_objects");
00480
00481 ros::AsyncSpinner spinner(2);
00482 spinner.start();
00483
00484 ClearKnownObjects cko;
00485 cko.run();
00486
00487 ros::waitForShutdown();
00488
00489 return 0;
00490 }