00001 #include <ros/ros.h>
00002 #include <pcl_ros/point_cloud.h>
00003 #include <pcl_ros/transforms.h>
00004 #include <tf/transform_listener.h>
00005 #include <pcl/point_types.h>
00006 #include <pcl/filters/voxel_grid.h>
00007 #include <pcl/filters/passthrough.h>
00008
00013 class PointCloudMapper
00014 {
00015 public:
00016
00017 typedef pcl::PointXYZRGB Point;
00018 typedef pcl::PointCloud<pcl::PointXYZRGB> PointCloud;
00019
00020 PointCloudMapper() :
00021 nh_(), nh_priv_("~")
00022 {
00023 nh_priv_.param("fixed_frame", fixed_frame_, std::string("/map"));
00024
00025 nh_priv_.param("x_filter_min", x_filter_min_, -30.0);
00026 nh_priv_.param("x_filter_max", x_filter_max_, 30.0);
00027 nh_priv_.param("y_filter_min", y_filter_min_, -30.0);
00028 nh_priv_.param("y_filter_max", y_filter_max_, 30.0);
00029 nh_priv_.param("z_filter_min", z_filter_min_, 2.0);
00030 nh_priv_.param("z_filter_max", z_filter_max_, 30.0);
00031 nh_priv_.param("voxel_size", voxel_size_, 0.1);
00032 nh_priv_.param("filter_map", filter_map_, false);
00033
00034 cloud_sub_ = nh_.subscribe<sensor_msgs::PointCloud2>("input", 1, &PointCloudMapper::callback, this);
00035 cloud_pub_ = nh_priv_.advertise<sensor_msgs::PointCloud2>("output", 1, true);
00036
00037 accumulated_cloud_.header.frame_id = fixed_frame_;
00038
00039 ROS_INFO_STREAM("[PointCloudMapper params:\n" <<
00040 "\t* Fixed frame: " << fixed_frame_ << "\n" <<
00041 "\t* Filter map: " << filter_map_ << "\n" <<
00042 "\t* Filter bounds: " << "( " << x_filter_min_ << ", " << y_filter_min_ << ", " << z_filter_min_ << ") and ( " << x_filter_max_ << ", " << y_filter_max_ << ", " << z_filter_max_ << ")" << "\n" <<
00043 "\t* Voxel size: " << voxel_size_);
00044
00045 pub_timer_ = nh_.createWallTimer(ros::WallDuration(3.0), &PointCloudMapper::publishCallback, this);
00046 }
00047
00048 void callback(const sensor_msgs::PointCloud2ConstPtr& cloud_msg)
00049 {
00050 PointCloud cloud;
00051 pcl::fromROSMsg(*cloud_msg, cloud);
00052 ROS_INFO_STREAM("Received cloud with " << cloud.points.size() << " points.");
00053
00054 PointCloud transformed_cloud;
00055 tf::StampedTransform transform;
00056 try {
00057 tf_listener_.waitForTransform(fixed_frame_, cloud_msg->header.frame_id, cloud_msg->header.stamp, ros::Duration(5.0));
00058 tf_listener_.lookupTransform(fixed_frame_, cloud_msg->header.frame_id, cloud_msg->header.stamp, transform);
00059 } catch (tf::TransformException ex){
00060 ROS_ERROR("%s",ex.what());
00061 ros::Duration(1.0).sleep();
00062 }
00063
00064 pcl_ros::transformPointCloud(cloud, transformed_cloud, tf::Transform(transform));
00065 bool success = true;
00066 if (success)
00067 {
00068 accumulated_cloud_ += transformed_cloud;
00069
00070 if(filter_map_)
00071 {
00072 PointCloud::Ptr cloud_downsampled = filter(accumulated_cloud_.makeShared());
00073 accumulated_cloud_ = *cloud_downsampled;
00074 }
00075
00076 ROS_INFO_STREAM("Map has " << accumulated_cloud_.points.size() << " points.");
00077
00078
00079 if (cloud_pub_.getNumSubscribers() > 0)
00080 cloud_pub_.publish(accumulated_cloud_);
00081 last_pub_time_ = ros::WallTime::now();
00082 }
00083 else
00084 {
00085 ROS_ERROR("Could not transform point cloud to %s", fixed_frame_.c_str());
00086 }
00087 }
00088
00089 void publishCallback(const ros::WallTimerEvent&)
00090 {
00091
00092 ros::WallDuration elapsed_time = ros::WallTime::now() - last_pub_time_;
00093 if (cloud_pub_.getNumSubscribers() > 0 && elapsed_time.toSec() > 5.0) {
00094
00095 sensor_msgs::PointCloud2 cloud_msg;
00096 pcl::toROSMsg(accumulated_cloud_, cloud_msg);
00097 cloud_pub_.publish(cloud_msg);
00098 }
00099 }
00100
00101 PointCloud::Ptr filter(PointCloud::Ptr cloud)
00102 {
00103
00104 PointCloud::Ptr cloud_ptr(new PointCloud);
00105
00106
00107 PointCloud::Ptr cloud_filtered_ptr(new PointCloud);
00108 pcl::PassThrough<Point> pass_;
00109
00110
00111 pass_.setFilterFieldName("x");
00112 pass_.setFilterLimits(x_filter_min_, x_filter_max_);
00113 pass_.setInputCloud(cloud);
00114 pass_.filter(*cloud_filtered_ptr);
00115
00116
00117 pass_.setFilterFieldName("y");
00118 pass_.setFilterLimits(y_filter_min_, y_filter_max_);
00119 pass_.setInputCloud(cloud_filtered_ptr);
00120 pass_.filter(*cloud_filtered_ptr);
00121
00122
00123 pass_.setFilterFieldName("z");
00124 pass_.setFilterLimits(z_filter_min_, z_filter_max_);
00125 pass_.setInputCloud(cloud);
00126 pass_.filter(*cloud_filtered_ptr);
00127
00128
00129 pcl::VoxelGrid<Point> grid_;
00130 PointCloud::Ptr cloud_downsampled_ptr(new PointCloud);
00131 double plane_detection_voxel_size_ = voxel_size_;
00132
00133 grid_.setLeafSize(plane_detection_voxel_size_,
00134 plane_detection_voxel_size_,
00135 plane_detection_voxel_size_);
00136 grid_.setDownsampleAllData(true);
00137 grid_.setInputCloud(cloud_filtered_ptr);
00138 grid_.filter(*cloud_downsampled_ptr);
00139
00140 return cloud_downsampled_ptr;
00141 }
00142
00143 private:
00144
00145 double x_filter_min_;
00146 double x_filter_max_;
00147 double y_filter_min_;
00148 double y_filter_max_;
00149 double z_filter_min_;
00150 double z_filter_max_;
00151 double voxel_size_;
00152 bool filter_map_;
00153
00154 ros::NodeHandle nh_;
00155 ros::NodeHandle nh_priv_;
00156
00157 ros::WallTimer pub_timer_;
00158
00159 ros::Subscriber cloud_sub_;
00160 ros::Publisher cloud_pub_;
00161
00162 std::string fixed_frame_;
00163 tf::TransformListener tf_listener_;
00164 PointCloud accumulated_cloud_;
00165 ros::WallTime last_pub_time_;
00166 };
00167
00168 int main(int argc, char **argv)
00169 {
00170 ros::init(argc, argv, "cloud_mapper");
00171 PointCloudMapper mapper;
00172 ros::spin();
00173 return 0;
00174 }
00175