collider.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2010, Willow Garage, Inc.
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/or other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the Willow Garage nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  *  \author Adam Harmat, Gil E. Jones, Kai M. Wurm, Armin Hornung
00036  *********************************************************************/
00037 
00038 #include "collider/collider.h"
00039 #include <planning_environment/monitors/monitor_utils.h>
00040 #include <octomap_msgs/conversions.h>
00041 
00042 Collider::Collider(): root_handle_(""), pruning_counter_(0), transparent_freespace_(false) {
00043    
00044   ros::NodeHandle priv("~");
00045 
00046   cm_ = new planning_environment::CollisionModels("robot_description");
00047   fixed_frame_ = cm_->getWorldFrameId();
00048 
00049   attached_color_.a = 0.5;
00050   attached_color_.r = 0.6;
00051   attached_color_.g = 0.4;
00052   attached_color_.b = 0.3;
00053   
00054   priv.param<double>("resolution", resolution_, 0.1);
00055   priv.param<double>("max_range", max_range_, -1.0); // default: full beam length
00056   priv.param<int>("pruning_period", pruning_period_, 5);
00057 
00058   priv.param<bool>("publish_static_over_dynamic_map", publish_over_dynamic_map_, false);
00059 
00060   // bounds of collision map in fixed frame
00061   priv.param<double>("dimension_x", workspace_box_.dimensionX, 0.0);
00062   priv.param<double>("dimension_y", workspace_box_.dimensionY, 0.0);
00063   priv.param<double>("dimension_z", workspace_box_.dimensionZ, 0.0);
00064 
00065   // origin of collision map in the fixed frame
00066   priv.param<double>("origin_x", workspace_box_.originX, 0.0);
00067   priv.param<double>("origin_y", workspace_box_.originY, 0.0);
00068   priv.param<double>("origin_z", workspace_box_.originZ, 0.0);
00069 
00070   // compute some useful values
00071   workspace_box_.real_minX = -workspace_box_.dimensionX + workspace_box_.originX;
00072   workspace_box_.real_maxX =  workspace_box_.dimensionX + workspace_box_.originX;
00073   workspace_box_.real_minY = -workspace_box_.dimensionY + workspace_box_.originY;
00074   workspace_box_.real_maxY =  workspace_box_.dimensionY + workspace_box_.originY;
00075   workspace_box_.real_minZ = -workspace_box_.dimensionZ + workspace_box_.originZ;
00076   workspace_box_.real_maxZ =  workspace_box_.dimensionZ + workspace_box_.originZ;
00077 
00078   // stereo cam params for sensor cone:
00079   priv.param<int>("camera_stereo_offset_left", camera_stereo_offset_left_, 128);
00080   priv.param<int>("camera_stereo_offset_right", camera_stereo_offset_right_, 0);
00081 
00082 
00083   collision_octree_ = new OcTreeType(resolution_);
00084   double probHit = 0.7;
00085   double probMiss = 0.4;
00086   double thresMin = 0.12;
00087   double thresMax = 0.97;
00088   priv.param("sensor_model_hit", probHit, probHit);
00089   priv.param("sensor_model_miss", probMiss, probMiss);
00090   priv.param("sensor_model_min", thresMin, thresMin);
00091   priv.param("sensor_model_max", thresMax, thresMax);
00092   collision_octree_->setProbHit(probHit);
00093   collision_octree_->setProbMiss(probMiss);
00094   collision_octree_->setClampingThresMin(thresMin);
00095   collision_octree_->setClampingThresMax(thresMax);
00096 
00097   marker_pub_ = root_handle_.advertise<visualization_msgs::Marker>("visualization_marker", 10);
00098   octomap_visualization_pub_ = root_handle_.advertise<visualization_msgs::Marker>("occupied_cells", 10);
00099   octomap_visualization_free_pub_ = root_handle_.advertise<visualization_msgs::Marker>("free_cells", 10);
00100   octomap_visualization_attached_pub_ = root_handle_.advertise<visualization_msgs::Marker>("attached_objects", 10);
00101   octomap_visualization_attached_array_pub_ = root_handle_.advertise<visualization_msgs::MarkerArray>("attached_objects_array", 10);
00102   cmap_publisher_ = root_handle_.advertise<arm_navigation_msgs::CollisionMap>("collision_map_out", 1, true);
00103   static_map_publisher_ = root_handle_.advertise<arm_navigation_msgs::CollisionMap>("collision_map_occ_static", 1);
00104   pointcloud_publisher_ = root_handle_.advertise<sensor_msgs::PointCloud2>("point_cloud_out", 1, true);
00105   
00106   color_occupied_.r = 0;
00107   color_occupied_.g = 0;
00108   color_occupied_.b = 1.0;
00109   color_occupied_.a = 0.5;
00110 
00111   color_free_.r = 0;
00112   color_free_.g = 1.0;
00113   color_free_.b = 0.0;
00114   color_free_.a = 0.5;
00115 
00116   // create a self mask with links: (see self_see_filter.h)
00117   double default_padding, default_scale;
00118   priv.param<double> ("self_see_default_padding", default_padding, .01);
00119   priv.param<double> ("self_see_default_scale", default_scale, 1.0);
00120   priv.param<double> ("min_sensor_dist", self_filter_min_dist_, 0.05);
00121 
00122   std::vector<robot_self_filter::LinkInfo> links;
00123   if (!priv.hasParam ("self_see_links"))
00124   {
00125     ROS_WARN ("No links specified for self filtering.");
00126   }
00127   else
00128   {
00129     XmlRpc::XmlRpcValue ssl_vals;;
00130 
00131     priv.getParam ("self_see_links", ssl_vals);
00132     if (ssl_vals.getType () != XmlRpc::XmlRpcValue::TypeArray)
00133     {
00134       ROS_WARN ("Self see links need to be an array");
00135     }
00136     else
00137     {
00138       if (ssl_vals.size () == 0)
00139       {
00140         ROS_WARN ("No values in self see links array");
00141       }
00142       else
00143       {
00144         for (int i = 0; i < ssl_vals.size (); ++i)
00145         {
00146           robot_self_filter::LinkInfo li;
00147 
00148           if (ssl_vals[i].getType() != XmlRpc::XmlRpcValue::TypeStruct)
00149           {
00150             ROS_WARN ("Self see links entry %d is not a structure.  Stopping processing of self see links", i);
00151             break;
00152           }
00153           if (!ssl_vals[i].hasMember ("name"))
00154           {
00155             ROS_WARN ("Self see links entry %d has no name.  Stopping processing of self see links", i);
00156             break;
00157           }
00158           li.name = std::string (ssl_vals[i]["name"]);
00159           if (!ssl_vals[i].hasMember ("padding"))
00160           {
00161             ROS_DEBUG ("Self see links entry %d has no padding.  Assuming default padding of %g", i, default_padding);
00162             li.padding = default_padding;
00163           }
00164           else
00165           {
00166             li.padding = ssl_vals[i]["padding"];
00167           }
00168           if (!ssl_vals[i].hasMember ("scale"))
00169           {
00170             ROS_DEBUG ("Self see links entry %d has no scale.  Assuming default scale of %g", i, default_scale);
00171             li.scale = default_scale;
00172           }
00173           else
00174           {
00175             li.scale = ssl_vals[i]["scale"];
00176           }
00177           links.push_back (li);
00178         }
00179       }
00180     }
00181   }
00182 
00183 
00184   robot_mask_right_ = new robot_self_filter::SelfMask(tf_, links);
00185   robot_mask_left_ = new robot_self_filter::SelfMask(tf_, links);
00186   ROS_INFO_STREAM("Robot self mask initialized with " << links.size() << " links");
00187 
00188 
00189 
00190   cam_model_initialized_ = false;
00191   camera_info_subscriber_ = new ros::Subscriber;
00192   std::string camera_info_topic;
00193   priv.getParam("camera_info_topic", camera_info_topic);
00194   (*camera_info_subscriber_) = root_handle_.subscribe( camera_info_topic , 10,
00195                                                        &Collider::cameraInfoCallback, this);
00196 
00197 
00198 
00199   if(!priv.hasParam("cloud_sources")) {
00200     //ROS_WARN("No sensor sources specified, please set config correctly (e.g., config/sources.yaml)");
00201     //return;
00202   } 
00203   else 
00204   {
00205     XmlRpc::XmlRpcValue cloud_sources;
00206     priv.getParam("cloud_sources", cloud_sources);
00207 
00208     if(cloud_sources.getType() != XmlRpc::XmlRpcValue::TypeArray) {
00209       ROS_WARN("Cloud sources needs to be an array");
00210     } 
00211     else 
00212     {
00213       for(int i = 0; i < cloud_sources.size(); ++i)
00214       {
00215         CloudInfo cinfo;
00216         if(cloud_sources[i].getType() != XmlRpc::XmlRpcValue::TypeStruct) 
00217         {
00218           ROS_WARN("Cloud source entry %d is not a structure.  Stopping processing of cloud sources",i);
00219           break;
00220         }
00221 
00222         if(!cloud_sources[i].hasMember("name")) 
00223         {
00224           ROS_WARN("Cloud sources entry %d has no name.  Stopping processing of cloud sources",i);
00225           break;
00226         } 
00227 
00228         if(cloud_sources[i].hasMember("raw_name"))
00229         {
00230           cinfo.raw_cloud_name_ = std::string(cloud_sources[i]["raw_name"]);
00231 
00232           if (!cloud_sources[i].hasMember("sensor_stereo_other_frame")){
00233             ROS_WARN("Cloud sources entry %d has a raw_name but no sensor_stereo_other_frame.  Stopping processing of cloud sources",i);
00234             break;
00235           } else{
00236             cinfo.sensor_stereo_other_frame_ = std::string(cloud_sources[i]["sensor_stereo_other_frame"]);
00237           }
00238 
00239         }
00240 
00241         if(!cloud_sources[i].hasMember("sensor_frame")) 
00242         {
00243           ROS_WARN("Cloud sources entry %d has no sensor_frame.  Stopping processing of cloud sources",i);
00244           break;
00245         } 
00246 
00247         cinfo.cloud_name_ = std::string(cloud_sources[i]["name"]);
00248         cinfo.sensor_frame_ = std::string(cloud_sources[i]["sensor_frame"]);
00249 
00250         if(!cloud_sources[i].hasMember("frame_subsample")) 
00251         {
00252           ROS_DEBUG("Cloud sources entry %d has no frame subsample.  Assuming default subsample of %g",i,1.0);
00253           cinfo.frame_subsample_ = 1.0;;
00254         } 
00255         else 
00256         {
00257           cinfo.frame_subsample_ = cloud_sources[i]["frame_subsample"];
00258         }
00259 
00260         if(!cloud_sources[i].hasMember("point_subsample")) 
00261         {
00262           ROS_DEBUG("Cloud sources entry %d has no point subsample.  Assuming default subsample of %g",i,1.0);
00263           cinfo.point_subsample_ = 1.0;;
00264         } 
00265         else 
00266         {
00267           cinfo.point_subsample_ = cloud_sources[i]["point_subsample"];
00268         }
00269 
00270         if(cloud_sources[i].hasMember("dynamic_buffer_size"))
00271           cinfo.dynamic_buffer_size_ = static_cast<unsigned int>(int(cloud_sources[i]["dynamic_buffer_size"]));
00272         
00273         if(cloud_sources[i].hasMember("static_buffer_size"))
00274           cinfo.static_buffer_size_ = static_cast<unsigned int>(int(cloud_sources[i]["static_buffer_size"]));
00275         
00276         if(cloud_sources[i].hasMember("dynamic_buffer_duration"))
00277           cinfo.dynamic_buffer_duration_ = ros::Duration(int(cloud_sources[i]["dynamic_buffer_duration"]));
00278         
00279         if(cloud_sources[i].hasMember("static_buffer_duration"))
00280           cinfo.static_buffer_duration_ = ros::Duration(int(cloud_sources[i]["static_buffer_duration"]));
00281         
00282         if(cloud_sources[i].hasMember("dynamic_publish"))
00283           cinfo.dynamic_publish_ = cloud_sources[i]["dynamic_publish"];
00284         
00285         if(cloud_sources[i].hasMember("static_publish"))
00286           cinfo.static_publish_ = cloud_sources[i]["static_publish"];
00287         
00288         if(cloud_sources[i].hasMember("dynamic_until_static_publish")) {
00289           cinfo.dynamic_until_static_publish_ = cloud_sources[i]["dynamic_until_static_publish"];
00290         }
00291 
00292         if(cloud_sources_.find(cinfo.cloud_name_) != cloud_sources_.end()) 
00293         {
00294           ROS_WARN_STREAM("Already have a cloud defined with name " << cinfo.cloud_name_ << ", using prior values");
00295         } 
00296         else 
00297         {
00298           message_filters::Subscriber<sensor_msgs::PointCloud2>* sub = new message_filters::Subscriber<sensor_msgs::PointCloud2>();
00299           sub->subscribe(root_handle_, cinfo.cloud_name_, 3);
00300           sub_filtered_clouds_.push_back(sub);
00301           if(cinfo.raw_cloud_name_ != "") {
00302             message_filters::Subscriber<sensor_msgs::PointCloud2>* sub_raw = new message_filters::Subscriber<sensor_msgs::PointCloud2>();
00303             sub_raw->subscribe(root_handle_,cinfo.raw_cloud_name_, 3);
00304             message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<sensor_msgs::PointCloud2, sensor_msgs::PointCloud2> >* sync =
00305               new message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<sensor_msgs::PointCloud2, sensor_msgs::PointCloud2> >(3);
00306             sub_raw_clouds_.push_back(sub_raw);            
00307             sync->connectInput (*sub, *sub_raw);
00308             sync->registerCallback(bind (&Collider::cloudCombinedCallback, this, _1, _2, cinfo.cloud_name_));
00309             sync_vector_.push_back(sync);
00310             ROS_INFO_STREAM("Adding synced callback for cloud " << cinfo.cloud_name_ << " raw " << cinfo.raw_cloud_name_);
00311           } else {
00312             sub->registerCallback(boost::bind(&Collider::cloudCallback, this, _1, cinfo.cloud_name_));
00313             ROS_INFO_STREAM("Adding callback for " << cinfo.cloud_name_);
00314           }
00315           cloud_sources_[cinfo.cloud_name_] = cinfo;
00316         }
00317       }
00318     }
00319   }
00320 
00321   attached_collision_object_subscriber_ = new message_filters::Subscriber<arm_navigation_msgs::AttachedCollisionObject>(root_handle_, "attached_collision_object", 1024);       
00322   attached_collision_object_subscriber_->registerCallback(boost::bind(&Collider::attachedObjectCallback, this, _1));    
00323 
00324   collision_object_subscriber_ = new message_filters::Subscriber<arm_navigation_msgs::CollisionObject>(root_handle_, "collision_object", 1024); 
00325   collision_object_subscriber_->registerCallback(boost::bind(&Collider::objectCallback, this, _1));    
00326 
00327   reset_service_ = priv.advertiseService("reset", &Collider::reset, this);
00328   dummy_reset_service_ = priv.advertiseService("dummy_reset", &Collider::dummyReset, this);
00329 
00330   action_server_.reset( new actionlib::SimpleActionServer<arm_navigation_msgs::MakeStaticCollisionMapAction>(root_handle_, "make_static_collision_map", boost::bind(&Collider::makeStaticCollisionMap, this, _1), false));
00331   action_server_->start();
00332 
00333   // queries on the map:
00334   get_octomap_service_ = root_handle_.advertiseService("octomap_binary", &Collider::octomapSrv, this);
00335   occupancy_point_service_ = root_handle_.advertiseService("occupancy_point", &Collider::occupancyPointSrv, this);
00336   occupancy_bbx_service_ = root_handle_.advertiseService("occupancy_in_bbx", &Collider::occupancyBBXSrv, this);
00337   occupancy_bbx_size_service_ = root_handle_.advertiseService("occupancy_in_bbx_size", &Collider::occupancyBBXSizeSrv, this);
00338 
00339 }
00340 
00341 
00342 Collider::~Collider() {
00343 
00344   delete collision_octree_;
00345   delete robot_mask_right_;
00346   delete robot_mask_left_;
00347   delete attached_collision_object_subscriber_;
00348   delete collision_object_subscriber_;
00349   
00350   for(unsigned int i = 0; i < sub_filtered_clouds_.size(); ++i){
00351     delete sub_filtered_clouds_[i];
00352   }
00353   for(unsigned int i = 0; i < sub_raw_clouds_.size(); ++i) {
00354     delete sub_raw_clouds_[i];
00355   }
00356   for(unsigned int i = 0; i < sync_vector_.size(); ++i) {
00357     delete sync_vector_[i];
00358   }
00359 }
00360 
00361 void Collider::attachedObjectCallback(const arm_navigation_msgs::AttachedCollisionObjectConstPtr& attached_object) {
00362   planning_environment::processAttachedCollisionObjectMsg(attached_object, tf_, cm_);
00363 }
00364 
00365 void Collider::objectCallback(const arm_navigation_msgs::CollisionObjectConstPtr& object) {
00366   planning_environment::processCollisionObjectMsg(object, tf_, cm_);
00367 }
00368 
00369 void Collider::cameraInfoCallback(const sensor_msgs::CameraInfo::ConstPtr &cam_info){
00370   ROS_DEBUG("Got camera info: %d x %d\n", cam_info->height, cam_info->width);
00371   cam_model_.fromCameraInfo(*cam_info);
00372   cam_size_ = cam_model_.fullResolution();
00373   cam_model_initialized_ = true;
00374   delete camera_info_subscriber_;
00375 }
00376 
00377 void Collider::cloudCombinedCallback(const sensor_msgs::PointCloud2::ConstPtr &cloud, 
00378                             const sensor_msgs::PointCloud2::ConstPtr &cloud_raw,
00379                             const std::string topic_name) {  
00380 
00381   CloudInfo settings =  cloud_sources_[topic_name];
00382 
00383   ros::WallTime begin_cb = ros::WallTime::now();
00384 
00385   if (!cam_model_initialized_) {
00386     ROS_INFO ("ERROR: camera model not initialized.");
00387     return;
00388   }
00389 
00390   // Use old callback with cloud (filtered)
00391   //  cloudCallback (cloud, "full_cloud_filtered");
00392   // For clearing use cloud_raw to check projections
00393   // (cloud_raw.{width,height})
00394 
00395   // transform pointcloud from sensor frame to fixed_frame_
00396   if (!tf_.waitForTransform(fixed_frame_, cloud_raw->header.frame_id, cloud->header.stamp, ros::Duration(1.0))) {
00397     ROS_WARN_STREAM( "Timed out waiting for transform from " << cloud_raw->header.frame_id
00398                      << " to " << fixed_frame_ << ", quitting callback");
00399     return;
00400   }
00401 
00402   // transform pointcloud from sensor frame to fixed_frame_
00403   if (!tf_.waitForTransform(fixed_frame_, cloud->header.frame_id, cloud->header.stamp, ros::Duration(1.0))) {
00404     ROS_WARN_STREAM( "Timed out waiting for transform from " << cloud->header.frame_id
00405                      << " to " << fixed_frame_ << ", quitting callback");
00406     return;
00407   }
00408 
00409 
00410   tf::StampedTransform trans;
00411   tf_.lookupTransform (fixed_frame_, cloud->header.frame_id, cloud->header.stamp, trans);
00412   tf::Transform to_world = trans;
00413 
00414   ros::WallTime begin_transform = ros::WallTime::now();
00415   Eigen::Matrix4f eigen_transform;
00416   sensor_msgs::PointCloud2 transformed_cloud;
00417   // //  cturtle:
00418 //   pcl::transformAsMatrix (to_world, eigen_transform);
00419 //   pcl::transformPointCloud (eigen_transform, *cloud, transformed_cloud);
00420   // //  dturtle:
00421   pcl_ros::transformAsMatrix (to_world, eigen_transform);
00422   pcl_ros::transformPointCloud (eigen_transform, *cloud, transformed_cloud);
00423 
00424   pcl::PointCloud<pcl::PointXYZ> pcl_cloud;
00425   pcl::fromROSMsg (transformed_cloud, pcl_cloud);
00426   
00427   pcl_cloud.header.frame_id = cm_->getWorldFrameId();
00428   pcl_cloud.header.stamp = cloud->header.stamp;
00429 
00430   std::vector<int> inside_mask;
00431   //filtering out attached object inside points
00432   if(planning_environment::computeAttachedObjectPointCloudMask(pcl_cloud,
00433                                                                cm_->getWorldFrameId(),
00434                                                                cm_,
00435                                                                tf_,
00436                                                                inside_mask)) {
00437     pcl::PointCloud<pcl::PointXYZ>::iterator it = pcl_cloud.points.begin();
00438     unsigned int i = 0;
00439     unsigned int count = 0;
00440     while(it != pcl_cloud.points.end()) {
00441       if(inside_mask[i++] == robot_self_filter::INSIDE) {
00442         it = pcl_cloud.points.erase(it);
00443         count++;
00444       } else {
00445         it++;
00446       }
00447     }
00448     ROS_DEBUG_STREAM("Filtering " << count << " points");
00449   }
00450 
00451   {
00452     planning_models::KinematicState state(cm_->getKinematicModel());
00453     state.setKinematicStateToDefault();
00454     
00455     planning_environment::updateAttachedObjectBodyPoses(cm_,
00456                                                         state,
00457                                                         tf_);
00458     
00459     visualization_msgs::MarkerArray arr;
00460     cm_->getAttachedCollisionObjectMarkers(state,
00461                                            arr,
00462                                            "filter_attached",
00463                                            attached_color_,
00464                                            ros::Duration(.2));
00465     
00466     octomap_visualization_attached_array_pub_.publish(arr);
00467   }
00468   
00469   std_msgs::Header global_header = cloud->header;
00470   global_header.frame_id = fixed_frame_;
00471 
00472   // pcl::transformPointCloud (fixed_frame_, *cloud, transformed_cloud, tf_);
00473   // pcl::PointCloud<pcl::PointXYZ> pcl_cloud;
00474   // pcl::fromROSMsg (transformed_cloud, pcl_cloud);
00475 
00476 
00477   pcl::PointCloud<pcl::PointXYZ> pcl_cloud_raw;
00478   pcl::fromROSMsg (*cloud_raw, pcl_cloud_raw);
00479 
00480   // copy data to octomap pointcloud
00481   octomap::Pointcloud octo_pointcloud;
00482   octomap::pointcloudPCLToOctomap(pcl_cloud, octo_pointcloud);
00483   double elapsed_transform = (ros::WallTime::now() - begin_transform).toSec();
00484 
00485 
00486   octomap::point3d sensor_origin = getSensorOrigin(cloud->header);
00487   tf::Point sensor_origin_tf = octomap::pointOctomapToTf(sensor_origin);
00488 
00489   // integrate pointcloud into map
00490   ros::WallTime begin_insert = ros::WallTime::now();
00491 
00492   // make use of lazy update
00493   collision_octree_->insertScan(octo_pointcloud, sensor_origin, max_range_, false, true);
00494   collision_octree_->updateInnerOccupancy();
00495 
00496   double elapsed_insert = (ros::WallTime::now() - begin_insert).toSec();
00497 
00498 
00499   // remove outdated occupied nodes -----
00500   ros::WallTime begin_degrade = ros::WallTime::now();
00501   degradeOutdatedRaw(cloud->header, sensor_origin_tf, settings.sensor_stereo_other_frame_, pcl_cloud_raw);
00502   double elapsed_degrade = (ros::WallTime::now() - begin_degrade).toSec();
00503 
00504 
00505   // get all occupied nodes from map
00506   octomap::point3d_list node_centers;
00507   ros::WallTime begin_get_occupied = ros::WallTime::now();
00508 
00509   std::vector<geometry_msgs::Point> pointlist;
00510   getOccupiedPoints(pointlist);
00511 
00512   //collision_octree_->getOccupied(node_centers);
00513   double elapsed_get_occupied = (ros::WallTime::now() - begin_get_occupied).toSec();
00514 
00515 
00516   // publish occupied cells
00517   ros::WallTime begin_send = ros::WallTime::now();
00518   if (settings.dynamic_publish_ && cmap_publisher_.getNumSubscribers() > 0) {
00519     publishCollisionMap(pointlist, global_header, cmap_publisher_);
00520   }
00521   if (pointcloud_publisher_.getNumSubscribers() > 0) {
00522     publishPointCloud(pointlist, global_header, pointcloud_publisher_);
00523   }
00524   if (octomap_visualization_pub_.getNumSubscribers() > 0){
00525     publishMarkerArray(pointlist, global_header, color_occupied_, octomap_visualization_pub_);
00526   }
00527   if (octomap_visualization_free_pub_.getNumSubscribers() > 0){
00528           std::vector<geometry_msgs::Point> freelist;
00529           getFreePoints(freelist);
00530           publishMarkerArray(freelist, global_header, color_free_, octomap_visualization_free_pub_);
00531   }
00532   double elapsed_send = (ros::WallTime::now() - begin_send).toSec();
00533 
00534   double total_elapsed = (ros::WallTime::now() - begin_cb).toSec();
00535   ROS_DEBUG("Total cloudCombinedCB %d pts: %f (transf: %f, update: %f, clear: %f, get occ: %f, send map: %f)",
00536                   int(pcl_cloud.size()), total_elapsed, elapsed_transform, elapsed_insert, elapsed_degrade, elapsed_get_occupied, elapsed_send);
00537 
00538 }
00539 
00540 
00541 void Collider::cloudCallback(const sensor_msgs::PointCloud2::ConstPtr &cloud, const std::string topic_name) {
00542 
00543   ros::WallTime begin_cb = ros::WallTime::now();
00544   CloudInfo settings =  cloud_sources_[topic_name];
00545   
00546   // transform pointcloud from sensor frame to fixed_frame_
00547   if (!tf_.waitForTransform(fixed_frame_, cloud->header.frame_id, cloud->header.stamp, ros::Duration(1.0))) {
00548     ROS_WARN_STREAM( "Timed out waiting for transform from " << cloud->header.frame_id
00549                      << " to " << fixed_frame_ << ", quitting callback");
00550     return;
00551   }
00552 
00553   // sensor_msgs::PointCloud2 transformed_cloud;
00554   // pcl::transformPointCloud (fixed_frame_, *cloud, transformed_cloud, tf_);
00555   // // tf::StampedTransform transform;
00556   // // tf_.lookupTransform (fixed_frame_, cloud->header.frame_id, cloud->header.stamp, transform);
00557   // // pcl::transformPointCloud (*cloud, transformed_cloud, transform);
00558   // pcl::PointCloud<pcl::PointXYZ> pcl_cloud;
00559   // pcl::fromROSMsg (transformed_cloud, pcl_cloud);
00560 
00561 
00562 
00563   tf::StampedTransform trans;
00564   tf_.lookupTransform (fixed_frame_, cloud->header.frame_id,  cloud->header.stamp, trans);
00565   tf::Transform to_world = trans;
00566   Eigen::Matrix4f eigen_transform;
00567   sensor_msgs::PointCloud2 transformed_cloud;
00568   // //  cturtle:
00569 //   pcl::transformAsMatrix (to_world, eigen_transform);
00570 //   pcl::transformPointCloud (eigen_transform, *cloud, transformed_cloud);
00571   // //  dturtle:
00572   pcl_ros::transformAsMatrix (to_world, eigen_transform);
00573   pcl_ros::transformPointCloud (eigen_transform, *cloud, transformed_cloud);
00574 
00575   pcl::PointCloud<pcl::PointXYZ> pcl_cloud;
00576   pcl::fromROSMsg (transformed_cloud, pcl_cloud);
00577   transformed_cloud.header.frame_id = fixed_frame_;
00578 
00579   std::vector<int> inside_mask;
00580   //filtering out attached object inside points
00581   if(planning_environment::computeAttachedObjectPointCloudMask(pcl_cloud,
00582                                                                cm_->getWorldFrameId(),
00583                                                                cm_,
00584                                                                tf_,
00585                                                                inside_mask)) {
00586     pcl::PointCloud<pcl::PointXYZ>::iterator it = pcl_cloud.points.begin();
00587     unsigned int i = 0;
00588     while(it != pcl_cloud.end()) {
00589       if(inside_mask[i++] == robot_self_filter::INSIDE) {
00590         it = pcl_cloud.points.erase(it);
00591       } else {
00592         it++;
00593       }
00594     }
00595   }
00596 
00597   {
00598     planning_models::KinematicState state(cm_->getKinematicModel());
00599     state.setKinematicStateToDefault();
00600     
00601     planning_environment::updateAttachedObjectBodyPoses(cm_,
00602                                                         state,
00603                                                         tf_);
00604     
00605     visualization_msgs::MarkerArray arr;
00606     cm_->getAttachedCollisionObjectMarkers(state,
00607                                            arr,
00608                                            "filter_attached",
00609                                            attached_color_,
00610                                            ros::Duration(.2));
00611     
00612     octomap_visualization_attached_array_pub_.publish(arr);
00613   }
00614 
00615   // copy data to octomap pointcloud
00616   octomap::Pointcloud octo_pointcloud;
00617   octomap::pointcloudPCLToOctomap(pcl_cloud, octo_pointcloud);
00618 
00619 
00620   // // retrieve sensor pose from tf
00621   // tf::StampedTransform trans;
00622   // tf_.lookupTransform (fixed_frame_, settings.sensor_frame_, cloud->header.stamp, trans);
00623   // tf::Vector3 orig = trans.getOrigin();
00624   // octomap::pose6d  sensor_pose(orig.x(), orig.y(), orig.z(), 0, 0, 0);
00625   // octomap::point3d sensor_origin(orig.x(), orig.y(), orig.z());
00626 
00627   octomap::point3d sensor_origin = getSensorOrigin(cloud->header);
00628   octomap::pose6d  sensor_pose(sensor_origin.x(), sensor_origin.y(), sensor_origin.z(), 0, 0, 0);
00629 /* 
00630  fprintf(stderr, "sensor origin: %.2f , %.2f , %.2f\n (frame: %s)", 
00631         sensor_origin.x(), sensor_origin.y(), sensor_origin.z(),
00632         cloud->header.frame_id.c_str());
00633 */
00634   // integrate pointcloud into map
00635   ros::WallTime begin_insert = ros::WallTime::now();
00636   collision_octree_->insertScan(octo_pointcloud, sensor_origin, max_range_, false);
00637 
00638   double elapsed_insert = (ros::WallTime::now() - begin_insert).toSec();
00639 
00640 
00641   ros::WallTime begin_degrade = ros::WallTime::now();
00642   // remove outdated occupied nodes
00643   //degradeOutdatedRaycasting(cloud->header, sensor_origin, *collision_octree_);
00644 
00645   // remove single voxels with no neighbors (probably noise)
00646   degradeSingleSpeckles();
00647   double elapsed_degrade = (ros::WallTime::now() - begin_degrade).toSec();
00648 
00649 
00650   // get all occupied nodes from map
00651   octomap::point3d_list node_centers;
00652   ros::WallTime begin_get_occupied = ros::WallTime::now();
00653   std::vector<geometry_msgs::Point> pointlist;
00654   getOccupiedPoints(pointlist);
00655   double elapsed_get_occupied = (ros::WallTime::now() - begin_get_occupied).toSec();
00656 
00657 
00658   // publish occupied cells
00659   ros::WallTime begin_send = ros::WallTime::now();
00660   if (settings.dynamic_publish_ && cmap_publisher_.getNumSubscribers() > 0) {
00661     publishCollisionMap(pointlist, transformed_cloud.header, cmap_publisher_);
00662   }
00663   if (pointcloud_publisher_.getNumSubscribers() > 0) {
00664     publishPointCloud(pointlist, transformed_cloud.header, pointcloud_publisher_);
00665   }
00666   if (octomap_visualization_pub_.getNumSubscribers() > 0){
00667     publishMarkerArray(pointlist, transformed_cloud.header, color_occupied_, octomap_visualization_pub_);
00668   }
00669 
00670   double elapsed_send = (ros::WallTime::now() - begin_send).toSec();
00671 
00672   double total_elapsed = (ros::WallTime::now() - begin_cb).toSec();
00673   ROS_DEBUG("Total cloudCB: %f (Update %d pnts: %f, clearing: %f, get occupied: %f, send map: %f)",
00674             total_elapsed, int(pcl_cloud.size()), elapsed_insert, elapsed_degrade, elapsed_get_occupied, elapsed_send);
00675 
00676 }
00677 
00678 
00679 void Collider::degradeOutdatedRaw(const std_msgs::Header& sensor_header, const tf::Point& sensor_origin,
00680                                   const std::string& other_stereo_frame, const pcl::PointCloud<pcl::PointXYZ>& pcl_cloud_raw) {
00681 
00682   tf::StampedTransform trans;
00683   // tf_.lookupTransform (fixed_frame_, sensor_header.frame_id, sensor_header.stamp, trans);
00684   // tf::Transform to_world = trans;
00685   tf_.lookupTransform (sensor_header.frame_id, fixed_frame_, sensor_header.stamp, trans);
00686   tf::Transform to_sensor = trans;
00687 
00688   robot_mask_right_->assumeFrame(fixed_frame_, sensor_header.stamp, sensor_header.frame_id, self_filter_min_dist_);
00689   robot_mask_left_->assumeFrame(fixed_frame_, sensor_header.stamp, other_stereo_frame, self_filter_min_dist_);
00690 
00691   tf::Vector3 sensor_pos_right, sensor_pos_left;
00692   planning_models::KinematicState state(cm_->getKinematicModel());
00693   planning_environment::configureForAttachedBodyMask(state, 
00694                                                      cm_,
00695                                                      tf_, 
00696                                                      sensor_header.frame_id,
00697                                                      sensor_header.stamp,
00698                                                      sensor_pos_right);
00699 
00700   planning_environment::configureForAttachedBodyMask(state, 
00701                                                      cm_,
00702                                                      tf_, 
00703                                                      other_stereo_frame,
00704                                                      sensor_header.stamp,
00705                                                      sensor_pos_left);
00706   
00707   octomap::point3d min;
00708   octomap::point3d max;
00709   computeBBX(sensor_header, min, max);
00710   unsigned query_time = time(NULL);
00711   unsigned max_update_time = 3;
00712   for(OcTreeType::leaf_bbx_iterator it = collision_octree_->begin_leafs_bbx(min,max),
00713       end=collision_octree_->end_leafs_bbx(); it!= end; ++it)
00714   {
00715     if (collision_octree_->isNodeOccupied(*it) &&
00716         ((query_time - it->getTimestamp()) > max_update_time))
00717     {
00718       tf::Point pos(it.getX(), it.getY(), it.getZ());
00719       tf::Point posRel = to_sensor(pos);
00720       cv::Point2d uv = cam_model_.project3dToPixel(cv::Point3d(posRel.x(), posRel.y(), posRel.z()));
00721 
00722       // ignore point if not in sensor cone
00723       if (!inSensorCone(uv))
00724         continue;
00725 
00726       // ignore point if it is occluded in the map
00727       if (isOccludedRaw(uv, pos.distance(sensor_origin), pcl_cloud_raw))
00728         continue;
00729 
00730       // ignore point if it is in the shadow of the robot or attached object
00731       if (robot_mask_right_->getMaskIntersection(pos) == robot_self_filter::SHADOW
00732           || robot_mask_left_->getMaskIntersection(pos) == robot_self_filter::SHADOW
00733           || planning_environment::computeAttachedObjectPointMask(cm_, pos, sensor_pos_right) == robot_self_filter::SHADOW
00734           || planning_environment::computeAttachedObjectPointMask(cm_, pos, sensor_pos_left) == robot_self_filter::SHADOW)
00735       {
00736         continue;
00737       }
00738 
00739       // otherwise: degrade node
00740       collision_octree_->integrateMissNoTime(&*it);
00741 
00742     }
00743   }
00744 
00745 //  // query map for occupied leafs within a given BBX and time frame
00746 //  std::list<std::pair<octomap::point3d, octomap::OcTreeNodeStamped*> > nodes;
00747 //  tree.getOccupiedNodesUpdateTimeBBX(nodes, 3, time(NULL), min, max);
00748 //
00749 //
00750 //
00751 //  std::list<std::pair<octomap::point3d, octomap::OcTreeNodeStamped*> >::iterator it = nodes.begin();
00752 //  for ( ; it != nodes.end(); ++it) {
00753 //
00754 //
00755 //    // ignore point if not in sensor cone
00756 //    if (!inSensorCone(to_sensor, it->first))
00757 //      continue;
00758 //
00759 //    // ignore point if it is occluded in the map
00760 //    if (isOccludedRaw(to_sensor, sensor_origin, it->first, pcl_cloud_raw))
00761 //        continue;
00762 //
00763 //    // ignore point if it is in the shadow of the robot:
00764 //    if (robot_mask_right_->getMaskIntersection(octomap::pointOctomapToTf(it->first)) == robot_self_filter::SHADOW
00765 //        || robot_mask_left_->getMaskIntersection(octomap::pointOctomapToTf(it->first)) == robot_self_filter::SHADOW
00766 //        || planning_environment::computeAttachedObjectPointMask(cm_, octomap::pointOctomapToTf(it->first), sensor_pos_right) == robot_self_filter::SHADOW
00767 //        || planning_environment::computeAttachedObjectPointMask(cm_, octomap::pointOctomapToTf(it->first), sensor_pos_left) == robot_self_filter::SHADOW)
00768 //    {
00769 //      continue;
00770 //    }
00771 //
00772 //    // degrade node
00773 //    collision_octree_->integrateMissNoTime(it->second);
00774 //  }
00775 /*  std_msgs::Header marker_header = sensor_header;
00776   marker_header.frame_id = fixed_frame_;
00777   publishMarkerArray(shadow_voxels, marker_header, octomap_debug_pub_);*/
00778 
00779 }
00780 
00781 
00782 
00783 void Collider::degradeOutdatedRaycasting(const std_msgs::Header& sensor_header, const octomap::point3d& sensor_origin,
00784                                          octomap::OcTreeStamped& tree) {
00785   tf::StampedTransform trans;
00786   tf_.lookupTransform (sensor_header.frame_id, fixed_frame_, sensor_header.stamp, trans);
00787   tf::Transform to_sensor = trans;
00788 
00789   // compute bbx from sensor cone
00790   octomap::point3d min;
00791   octomap::point3d max;
00792   computeBBX(sensor_header, min, max);
00793 
00794   unsigned query_time = time(NULL);
00795   unsigned max_update_time = 1;
00796   for(OcTreeType::leaf_bbx_iterator it = collision_octree_->begin_leafs_bbx(min,max),
00797       end=collision_octree_->end_leafs_bbx(); it!= end; ++it)
00798   {
00799     if (collision_octree_->isNodeOccupied(*it) &&
00800         ((query_time - it->getTimestamp()) > max_update_time))
00801     {
00802       tf::Point pos(it.getX(), it.getY(), it.getZ());
00803       tf::Point posRel = to_sensor(pos);
00804       cv::Point2d uv = cam_model_.project3dToPixel(cv::Point3d(posRel.x(), posRel.y(), posRel.z()));
00805 
00806       // ignore point if not in sensor cone
00807       if (!inSensorCone(uv))
00808         continue;
00809 
00810       // ignore point if it is occluded in the map
00811       if (isOccludedMap(sensor_origin, it.getCoordinate()))
00812         continue;
00813 
00814       // otherwise: degrade node
00815       collision_octree_->integrateMissNoTime(&*it);
00816 
00817     }
00818   }
00819 }
00820 
00821 void Collider::degradeSingleSpeckles(){
00822   for(OcTreeType::leaf_iterator it = collision_octree_->begin_leafs(),
00823       end=collision_octree_->end_leafs(); it!= end; ++it)
00824   {
00825     if (collision_octree_->isNodeOccupied(*it)){
00826       octomap::OcTreeKey nKey = it.getKey();
00827       octomap::OcTreeKey key;
00828       bool neighborFound = false;
00829       for (key[2] = nKey[2] - 1; !neighborFound && key[2] <= nKey[2] + 1; ++key[2]){
00830         for (key[1] = nKey[1] - 1; !neighborFound && key[1] <= nKey[1] + 1; ++key[1]){
00831           for (key[0] = nKey[0] - 1; !neighborFound && key[0] <= nKey[0] + 1; ++key[0]){
00832             if (key != nKey){
00833               OcTreeType::NodeType* node = collision_octree_->search(key);
00834               if (node && collision_octree_->isNodeOccupied(node)){
00835                 // we have a neighbor => break!
00836                 neighborFound = true;
00837               }
00838             }
00839           }
00840         }
00841       }
00842       // done with search, see if found and degrade otherwise:
00843       if (!neighborFound){
00844         ROS_DEBUG("Degrading single speckle at (%f,%f,%f)", it.getX(), it.getY(), it.getZ());
00845         collision_octree_->integrateMissNoTime(&*it);
00846       }
00847 
00848     }
00849   }
00850 }
00851 
00852 
00853 octomap::point3d Collider::getSensorOrigin(const std_msgs::Header& sensor_header) {
00854 
00855   geometry_msgs::PointStamped stamped_in;
00856   geometry_msgs::PointStamped stamped_out;
00857   stamped_in.header = sensor_header;
00858 
00859 // HACK: laser origin
00860   if (sensor_header.frame_id == "base_footprint") {
00861    stamped_in.header.frame_id = "laser_tilt_link"; 
00862   }
00863 
00864   geometry_msgs::Point p;
00865   p.x=p.y=p.z=0;
00866   try {
00867     tf_.transformPoint(fixed_frame_, stamped_in, stamped_out);
00868   } catch(tf::TransformException& ex) {
00869     ros::Time t;
00870     std::string err_string;
00871     ROS_INFO_STREAM("Transforming sensor origin using latest common time because there's a tf problem");
00872     if (tf_.getLatestCommonTime(fixed_frame_, stamped_in.header.frame_id, stamped_in.header.stamp, &err_string) == tf::NO_ERROR) {
00873       try {
00874         tf_.transformPoint(fixed_frame_, stamped_in, stamped_out);
00875       } catch(...) {
00876         ROS_WARN_STREAM("Still can't transform sensor origin between " << fixed_frame_ << " and " << stamped_in.header.frame_id);
00877       }
00878     } else {
00879       ROS_WARN_STREAM("No common time between " << fixed_frame_ << " and " << stamped_in.header.frame_id);
00880     }
00881   }
00882   octomap::point3d retval (stamped_out.point.x, stamped_out.point.y, stamped_out.point.z);
00883 
00884   return retval;
00885 }
00886 
00887 
00888 void Collider::computeBBX(const std_msgs::Header& sensor_header, octomap::point3d& bbx_min, octomap::point3d& bbx_max) {
00889 
00890   std::string sensor_frame = sensor_header.frame_id;
00891 
00892   //  transform sensor FOV 
00893   geometry_msgs::PointStamped stamped_in;
00894   geometry_msgs::PointStamped stamped_out;
00895   stamped_in.header = sensor_header;
00896   stamped_in.header.frame_id = sensor_frame;
00897 
00898   // get max 3d points from camera at 0.5m and 5m.
00899   geometry_msgs::Point p[8];
00900 
00901   // define min/max 2d points
00902   cv::Point2d uv [4];
00903   uv[0].x = camera_stereo_offset_left_;
00904   uv[0].y = 0;
00905   uv[1].x = cam_size_.width + camera_stereo_offset_right_;
00906   uv[1].y = 0;
00907   uv[2].x = cam_size_.width + camera_stereo_offset_right_;
00908   uv[2].y = cam_size_.height;
00909   uv[3].x = camera_stereo_offset_left_;
00910   uv[3].y = cam_size_.height;
00911 
00912   // transform to 3d space
00913   cv::Point3d xyz [4];
00914   for (int i=0;i<4;i++) {
00915         xyz[i] = cam_model_.projectPixelTo3dRay(uv[i]);
00916     cv::Point3d xyz_05 = xyz[i] * 0.5;
00917     xyz[i] *= 5.; // 5meters
00918     p[i].x = xyz[i].x;
00919     p[i].y = xyz[i].y;
00920     p[i].z = xyz[i].z;
00921     p[i+4].x = xyz_05.x;
00922     p[i+4].y = xyz_05.y;
00923     p[i+4].z = xyz_05.z;
00924   }
00925 
00926   // transform to world coodinates and find axis-aligned bbx
00927   bbx_min.x() = bbx_min.y() = bbx_min.z() = 1e6;
00928   bbx_max.x() = bbx_max.y() = bbx_max.z() = -1e6;
00929   for (int i=0; i<8; i++) {
00930     stamped_in.point = p[i];
00931     tf_.transformPoint(fixed_frame_, stamped_in, stamped_out);
00932     p[i].x = stamped_out.point.x;
00933     p[i].y = stamped_out.point.y;
00934     p[i].z = stamped_out.point.z;
00935     if (p[i].x < bbx_min.x()) bbx_min.x() = p[i].x;
00936     if (p[i].y < bbx_min.y()) bbx_min.y() = p[i].y;
00937     if (p[i].z < bbx_min.z()) bbx_min.z() = p[i].z;
00938     if (p[i].x > bbx_max.x()) bbx_max.x() = p[i].x;
00939     if (p[i].y > bbx_max.y()) bbx_max.y() = p[i].y;
00940     if (p[i].z > bbx_max.z()) bbx_max.z() = p[i].z;
00941   }
00942 
00943 
00944   // // visualize axis-aligned querying bbx
00945   visualization_msgs::Marker bbx;
00946   bbx.header.frame_id = fixed_frame_;
00947   bbx.header.stamp = ros::Time::now();
00948   bbx.ns = "collider";
00949   bbx.id = 1;
00950   bbx.action = visualization_msgs::Marker::ADD;
00951   bbx.type = visualization_msgs::Marker::CUBE;
00952   bbx.pose.orientation.w = 1.0;
00953   bbx.pose.position.x = (bbx_min.x() + bbx_max.x()) / 2.;
00954   bbx.pose.position.y = (bbx_min.y() + bbx_max.y()) / 2.;
00955   bbx.pose.position.z = (bbx_min.z() + bbx_max.z()) / 2.;
00956   bbx.scale.x = bbx_max.x()-bbx_min.x();
00957   bbx.scale.y = bbx_max.y()-bbx_min.y();
00958   bbx.scale.z = bbx_max.z()-bbx_min.z();
00959   bbx.color.g = 1;
00960   bbx.color.a = 0.3;
00961   marker_pub_.publish(bbx);
00962 
00963 
00964   // visualize sensor cone
00965   visualization_msgs::Marker bbx_points;
00966   bbx_points.header.frame_id = fixed_frame_; 
00967   bbx_points.header.stamp = ros::Time::now();  
00968   bbx_points.ns = "collider";
00969   bbx_points.id = 2;
00970   bbx_points.action = visualization_msgs::Marker::ADD;
00971   bbx_points.type = visualization_msgs::Marker::LINE_STRIP;
00972   bbx_points.pose.orientation.w = 1.0;
00973   bbx_points.scale.x = 0.02;
00974   bbx_points.scale.y = 0.02;
00975   bbx_points.color.g = 1;
00976   bbx_points.color.a = 0.3;
00977   bbx_points.points.push_back(p[0]);
00978   bbx_points.points.push_back(p[1]);
00979   bbx_points.points.push_back(p[2]);
00980   bbx_points.points.push_back(p[3]);
00981   bbx_points.points.push_back(p[0]);
00982   bbx_points.points.push_back(p[4]);
00983   bbx_points.points.push_back(p[5]);
00984   bbx_points.points.push_back(p[6]);
00985   bbx_points.points.push_back(p[7]);
00986   bbx_points.points.push_back(p[4]);
00987   bbx_points.points.push_back(p[7]);
00988   bbx_points.points.push_back(p[3]);
00989   bbx_points.points.push_back(p[2]);
00990   bbx_points.points.push_back(p[6]);
00991   bbx_points.points.push_back(p[5]);
00992   bbx_points.points.push_back(p[1]);
00993   marker_pub_.publish(bbx_points);
00994 }
00995 
00996 
00997 bool Collider::inSensorCone(const cv::Point2d& uv) const {
00998   // Check if projected 2D coordinate in pixel range.
00999   // This check is a little more restrictive than it should be by using
01000   // 1 pixel less to account for rounding / discretization errors.
01001   // Otherwise points on the corner are accounted to be in the sensor cone.
01002   return ( (uv.x > camera_stereo_offset_left_+1)
01003            && (uv.x < cam_size_.width + camera_stereo_offset_right_ - 2)
01004            && (uv.y > 1)
01005            && (uv.y < cam_size_.height-2) );
01006 }
01007 
01008 
01009 
01010 bool Collider::isOccludedRaw(const cv::Point2d& uv, double range, const pcl::PointCloud<pcl::PointXYZ>& pcl_cloud_raw) {
01011 
01012   // out of image range?
01013   if ((uv.x < 0) || (uv.y < 0) || (uv.x > cam_size_.width) || (uv.y > cam_size_.height))
01014           return false;
01015   
01016   double sensor_range = pcl_cloud_raw(uv.x, uv.y).z;
01017 
01018   return (sensor_range < range);
01019 }
01020 
01021 
01022 bool Collider::isOccludedMap(const octomap::point3d& sensor_origin, const octomap::point3d& p) const {
01023 
01024   octomap::point3d direction (p-sensor_origin);
01025   octomap::point3d obstacle;
01026   double range = direction.norm() - resolution_;
01027 
01028   if (collision_octree_->castRay(sensor_origin, direction, obstacle, true, range)) {
01029     // fprintf(stderr, "<%.2f , %.2f , %.2f> -> <%.2f , %.2f , %.2f> // obs at: <%.2f , %.2f , %.2f>, range: %.2f\n", 
01030     //         sensor_origin.x(), sensor_origin.y(), sensor_origin.z(),
01031     //         p.x(), p.y(), p.z(), 
01032     //         obstacle.x(), obstacle.y(), obstacle.z(), (obstacle-p).norm());
01033     return true;
01034   }
01035   return false;
01036 }
01037 
01038 
01039 
01040 // publish map  ----------------------------------------------------------------------
01041 
01042 void Collider::publishCollisionMap(const std::vector<geometry_msgs::Point>& pointlist,
01043                                    const std_msgs::Header &header, ros::Publisher &pub) {
01044   if(pointlist.size() <= 1)
01045     return;
01046   
01047   arm_navigation_msgs::CollisionMap cmap;
01048   cmap.header = header;
01049 
01050   arm_navigation_msgs::OrientedBoundingBox box;
01051   box.extents.x = box.extents.y = box.extents.z = collision_octree_->getResolution();
01052   box.axis.x = box.axis.y = 0.0; box.axis.z = 1.0;
01053   box.angle = 0.0;
01054   cmap.boxes.reserve(pointlist.size());
01055 
01056   for (std::vector<geometry_msgs::Point>::const_iterator it = pointlist.begin(); it != pointlist.end(); ++it) {
01057     box.center.x = it->x;
01058     box.center.y = it->y;
01059     box.center.z = it->z;
01060     cmap.boxes.push_back(box);
01061   }
01062   pub.publish(cmap);
01063 }
01064 
01065 
01066 void Collider::publishPointCloud(const std::vector<geometry_msgs::Point>& pointlist,
01067                                  const std_msgs::Header &header, ros::Publisher &pub) {
01068 
01069   if(pointlist.size() <= 1)
01070     return;
01071 
01072   pcl::PointCloud<pcl::PointXYZ> pcl_cloud;
01073   pcl_cloud.points.reserve (pointlist.size ());
01074 
01075   for (std::vector<geometry_msgs::Point>::const_iterator it = pointlist.begin(); it != pointlist.end(); ++it) {
01076     pcl::PointXYZ point;
01077     point.x = it->x;
01078     point.y = it->y;
01079     point.z = it->z;
01080     pcl_cloud.points.push_back (point);
01081   } 
01082 
01083   sensor_msgs::PointCloud2 cloud;
01084   pcl::toROSMsg (pcl_cloud, cloud);
01085   cloud.header = header;
01086   pub.publish (cloud);    
01087 
01088 }
01089 
01090 void Collider::publishMarkerArray(const std::vector<geometry_msgs::Point>& pointlist,
01091                                  const std_msgs::Header &header, const std_msgs::ColorRGBA& color,
01092                                  ros::Publisher &pub) {
01093 
01094   if(pointlist.size() <= 1)
01095     return;
01096 
01097   visualization_msgs::Marker occupiedCellsVis;
01098   occupiedCellsVis.header = header;
01099   occupiedCellsVis.ns = "map";
01100   occupiedCellsVis.id = 0;
01101   occupiedCellsVis.type = visualization_msgs::Marker::CUBE_LIST;
01102   occupiedCellsVis.scale.x = collision_octree_->getResolution();
01103   occupiedCellsVis.scale.y = collision_octree_->getResolution();
01104   occupiedCellsVis.scale.z = collision_octree_->getResolution();
01105   occupiedCellsVis.color = color;
01106 
01107 
01108   occupiedCellsVis.points = pointlist;
01109 
01110   pub.publish (occupiedCellsVis);
01111 
01112 }
01113 
01114 
01115 
01116 // action server  --------------------------------------------------------------------
01117 
01118 bool Collider::reset(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res) {
01119   delete collision_octree_;
01120   collision_octree_ = new OcTreeType(resolution_);
01121   return true;
01122 }
01123 
01124 
01125 bool Collider::dummyReset(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res) {
01126   // Dummy function that doesn't actually reset anything. Needed because some
01127   // parts of the grasping pipeline want to reset the collision map
01128   // on occasion, but with the octomap we don't want other nodes resetting the map sporadically.
01129   return true;
01130 }
01131 
01132 
01133 void Collider::makeStaticCollisionMap(const arm_navigation_msgs::MakeStaticCollisionMapGoalConstPtr& goal) {
01134 
01135   std_msgs::Header head;
01136   head.stamp = ros::Time::now();
01137   head.frame_id = fixed_frame_;
01138 
01139   ROS_INFO("Making static collision map");
01140 
01141   //we first publish whatever we got
01142   std::vector<geometry_msgs::Point> pointlist;
01143   getOccupiedPoints(pointlist);
01144   if (pointcloud_publisher_.getNumSubscribers() > 0) {
01145     publishPointCloud(pointlist, head, pointcloud_publisher_);
01146   }
01147   
01148   if(publish_over_dynamic_map_)
01149   {
01150     if (cmap_publisher_.getNumSubscribers() > 0) {
01151       publishCollisionMap(pointlist, head, cmap_publisher_);
01152     }
01153     // loop through cloud_source_map, set dynamic publish to false on all sources to preserve behavior of older collision_map_self_occ
01154     for(std::map<std::string,CloudInfo>::iterator it = cloud_sources_.begin(); 
01155         it != cloud_sources_.end();
01156         it++) 
01157     {
01158       it->second.dynamic_publish_ = false;      
01159     }   
01160     ROS_INFO("Should stop publishing dynamic map");
01161   } else {
01162     publishCollisionMap(pointlist, head, static_map_publisher_);
01163   }
01164   action_server_->setSucceeded();
01165 }
01166 
01167 bool Collider::octomapSrv(octomap_msgs::GetOctomap::Request  &req, octomap_msgs::GetOctomap::Response &res){
01168         ROS_DEBUG("Sending map data on service request");
01169 
01170         res.map.header.frame_id = fixed_frame_;
01171         res.map.header.stamp = ros::Time::now();
01172         octomap::octomapMapToMsg(*collision_octree_, res.map);
01173 
01174         return true;
01175 }
01176 
01177 bool Collider::occupancyPointSrv(collider::OccupancyPointQuery::Request &req,
01178                                  collider::OccupancyPointQuery::Response &res){
01179 
01180   octomap::OcTreeNodeStamped* node = collision_octree_->search(req.point.x, req.point.y, req.point.z);
01181   if (node){
01182     if (collision_octree_->isNodeOccupied(node))
01183       res.occupancy=collider::OccupancyPointQueryResponse::OCCUPIED;
01184     else
01185       res.occupancy=collider::OccupancyPointQueryResponse::FREE;
01186   } else{
01187     res.occupancy = collider::OccupancyPointQueryResponse::UNKNOWN;
01188   }
01189 
01190         return true;
01191 }
01192 
01193 bool Collider::occupancyBBXSrv(collider::OccupancyBBXQuery::Request &req,
01194                                 collider::OccupancyBBXQuery::Response &res){
01195 
01196   OcTreeType::leaf_bbx_iterator it = collision_octree_->begin_leafs_bbx(octomap::pointMsgToOctomap(req.min),
01197                                                                     octomap::pointMsgToOctomap(req.max));
01198   OcTreeType::leaf_bbx_iterator end = collision_octree_->end_leafs_bbx();
01199 
01200   geometry_msgs::Point pt;
01201   for(; it!= end; ++it){
01202     pt.x = it.getX();
01203     pt.y = it.getY();
01204     pt.z = it.getZ();
01205 
01206     if (collision_octree_->isNodeOccupied(*it)){
01207       res.occupied.push_back(pt);
01208     } else {
01209       res.free.push_back(pt);
01210     }
01211   }
01212   res.resolution = collision_octree_->getResolution();
01213 
01214   return true;
01215 }
01216 
01217 bool Collider::occupancyBBXSizeSrv(collider::OccupancyBBXSizeQuery::Request &req,
01218                                    collider::OccupancyBBXSizeQuery::Response &res){
01219 
01220   octomap::point3d center = octomap::pointMsgToOctomap(req.center);
01221   octomap::point3d size = octomap::pointMsgToOctomap(req.size);
01222   OcTreeType::leaf_bbx_iterator it = collision_octree_->begin_leafs_bbx(center - (size*0.5), center + (size*0.5));
01223   OcTreeType::leaf_bbx_iterator end = collision_octree_->end_leafs_bbx();
01224 
01225   geometry_msgs::Point pt;
01226   for(; it!= end; ++it){
01227     pt.x = it.getX();
01228     pt.y = it.getY();
01229     pt.z = it.getZ();
01230 
01231     if (collision_octree_->isNodeOccupied(*it)){
01232       res.occupied.push_back(pt);
01233     } else {
01234       res.free.push_back(pt);
01235     }
01236   }
01237   res.resolution = collision_octree_->getResolution();
01238 
01239   return true;
01240 }
01241 


collider
Author(s): Adam Harmat, Gil E. Jones, Kai M. Wurm, Armin Hornung. Maintained by Gil E. Jones
autogenerated on Thu Dec 12 2013 11:07:38