Go to the documentation of this file.00001 
00068 
00069 
00070 
00071 
00072 
00073 #include <sstream>
00074 #include <fstream>
00075 
00076 
00077 
00078 #include <ros/ros.h>
00079 #include <ros/console.h>
00080 
00081 #include <pluginlib/class_list_macros.h>
00082 #include <dynamic_reconfigure/server.h>
00083 #include <cob_3d_mapping_point_map/point_map_nodeletConfig.h>
00084 
00085 
00086 #include <pcl/io/pcd_io.h>
00087 #include <pcl/point_types.h>
00088 #include <pcl/filters/voxel_grid.h>
00089 #include <pcl_ros/point_cloud.h>
00090 #include <nodelet/nodelet.h>
00091 
00092 
00093 
00094 
00095 #include <cob_3d_mapping_msgs/SetPointMap.h>
00096 #include <cob_3d_mapping_msgs/GetPointMap.h>
00097 #include <cob_srvs/Trigger.h>
00098 
00099 
00100 
00101 
00102 class PointMapNodelet : public nodelet::Nodelet
00103 {
00104   typedef pcl::PointXYZRGB Point;
00105 
00106 public:
00107   
00108   PointMapNodelet()
00109   : ctr_(0),
00110     is_running_(false),
00111     map_frame_id_("/map")
00112     {
00113 
00114     map_.header.frame_id = map_frame_id_;
00115     }
00116 
00117 
00118   
00119   ~PointMapNodelet()
00120   {
00121     
00122   }
00123 
00131   void
00132   dynReconfCallback(cob_3d_mapping_point_map::point_map_nodeletConfig &config, uint32_t level)
00133   {
00134     file_path_ = config.file_path;
00135     save_ = config.save;
00136     voxel_leafsize_ = config.voxel_leafsize;
00137     map_frame_id_ = config.map_frame_id;
00138     map_.header.frame_id = map_frame_id_;
00139   }
00140 
00141 
00149   void
00150   onInit()
00151   {
00152     n_ = getNodeHandle();
00153 
00154     config_server_ = boost::shared_ptr<dynamic_reconfigure::Server<cob_3d_mapping_point_map::point_map_nodeletConfig> >(new dynamic_reconfigure::Server<cob_3d_mapping_point_map::point_map_nodeletConfig>(getPrivateNodeHandle()));
00155     config_server_->setCallback(boost::bind(&PointMapNodelet::dynReconfCallback, this, _1, _2));
00156 
00157     point_cloud_sub_ = n_.subscribe("point_cloud2", 1, &PointMapNodelet::updateCallback, this);
00158     map_pub_ = n_.advertise<pcl::PointCloud<Point> >("map",1);
00159     clear_map_server_ = n_.advertiseService("clear_map", &PointMapNodelet::clearMap, this);
00160     get_map_server_ = n_.advertiseService("get_map", &PointMapNodelet::getMap, this);
00161     set_map_server_ = n_.advertiseService("set_map", &PointMapNodelet::setMap, this);
00162 
00163     
00164     
00165     
00166   }
00167 
00182   void
00183   updateCallback(const pcl::PointCloud<Point>::Ptr& pc)
00184   {
00185     ROS_DEBUG("PointCloudSubCallback");
00186     if (pc->size() < 1)
00187     {
00188       ROS_WARN("[point_map] Incoming point cloud is empty, skipping map update.");
00189       return;
00190     }
00191     if(pc->header.frame_id != map_frame_id_)
00192     {
00193       ROS_ERROR("[point_map] Frame ID of incoming point cloud (%s) does not match map frame ID (%s), aborting...", pc->header.frame_id.c_str(), map_frame_id_.c_str());
00194       return;
00195     }
00196 
00197     updateMap(pc);
00198     map_pub_.publish(map_);
00199 
00200     ROS_DEBUG("[point_map] Updated map has %d points", map_.size());
00201 
00202     if(save_)
00203     {
00204       std::stringstream ss;
00205       ss << file_path_ << "/map_" << ctr_ << ".pcd";
00206       pcl::io::savePCDFileASCII (ss.str(), map_);
00207     }
00208     ctr_++;
00209     return;
00210   }
00211 
00212   void
00213   updateMap(const pcl::PointCloud<Point>::Ptr& pc)
00214   {
00215     map_ += *pc;
00216     downsampleMap();
00217   }
00218 
00219 
00229   
00230 
00231 
00232 
00233 
00234 
00235 
00236 
00237 
00238 
00239 
00240 
00241 
00242 
00243 
00244 
00245 
00246 
00247 
00248 
00249 
00250 
00251 
00252 
00253 
00264   bool
00265   clearMap(cob_srvs::Trigger::Request &req,
00266            cob_srvs::Trigger::Response &res)
00267   {
00268     
00269     ROS_INFO("Clearing point map...");
00270     map_.clear();
00271     Point p;
00272     map_.points.push_back(p);
00273     map_pub_.publish(map_);
00274     return true;
00275   }
00276 
00287   bool
00288   getMap(cob_3d_mapping_msgs::GetPointMap::Request &req,
00289          cob_3d_mapping_msgs::GetPointMap::Response &res)
00290   {
00291     pcl::toROSMsg(map_, res.map);
00292     return true;
00293   }
00294 
00306   bool
00307   setMap(cob_3d_mapping_msgs::SetPointMap::Request &req,
00308                   cob_3d_mapping_msgs::SetPointMap::Response &res)
00309   {
00310     pcl::fromROSMsg(req.map, map_);
00311     downsampleMap();
00312     map_pub_.publish(map_);
00313     
00314     return true;
00315   }
00316 
00317 
00325   void
00326   downsampleMap()
00327   {
00328     pcl::VoxelGrid<Point> vox_filter;
00329     vox_filter.setInputCloud(map_.makeShared());
00330     vox_filter.setLeafSize(voxel_leafsize_,voxel_leafsize_,voxel_leafsize_);
00331     vox_filter.filter(map_);
00332   }
00333 
00334 
00335   ros::NodeHandle n_;
00336 
00337 
00338 protected:
00339   ros::Subscriber point_cloud_sub_;     
00340   ros::Publisher map_pub_;              
00341   ros::ServiceServer clear_map_server_;
00342   ros::ServiceServer get_map_server_;
00343   ros::ServiceServer set_map_server_;
00344 
00345   boost::shared_ptr<dynamic_reconfigure::Server<cob_3d_mapping_point_map::point_map_nodeletConfig> > config_server_;
00346 
00347   unsigned int ctr_;
00348   bool is_running_;
00349 
00350   
00351   std::string file_path_;
00352   bool save_;
00353   std::string map_frame_id_;
00354   double voxel_leafsize_;
00355 
00356   pcl::PointCloud<Point> map_;
00357 
00358 };
00359 
00360 PLUGINLIB_DECLARE_CLASS(cob_3d_mapping_point_map, PointMapNodelet, PointMapNodelet, nodelet::Nodelet)
00361