Go to the documentation of this file.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
00035
00036
00037
00038
00039
00040
00041 #include <ros/ros.h>
00042 #include <sensor_msgs/PointCloud2.h>
00043 #include <stereo_wall_detection/DetectWall.h>
00044 #include <pcl/ModelCoefficients.h>
00045 #include <pcl/io/pcd_io.h>
00046 #include <pcl/point_types.h>
00047 #include <pcl/sample_consensus/method_types.h>
00048 #include <pcl/sample_consensus/model_types.h>
00049 #include <pcl/segmentation/sac_segmentation.h>
00050 #include <pcl/ros/conversions.h>
00051 #include <pcl/io/io.h>
00052 #include <pcl/features/feature.h>
00053 #include <pcl/point_types.h>
00054 #include <boost/thread/mutex.hpp>
00055 #include <boost/thread/condition.hpp>
00056 #include <boost/bind.hpp>
00057
00058 #include <visualization_msgs/Marker.h>
00059
00060 class PlanarFit
00061 {
00062 public:
00063 PlanarFit () : nh_ ("~")
00064 {
00065 serv_ = nh_.advertiseService ("detect_wall", &PlanarFit::detect_wall, this);
00066
00067
00068
00069 cloud_sub_ = nh_.subscribe("points2", 10, &PlanarFit::cloudCb, this);
00070
00071
00072 plane_points_ = nh_.advertise<sensor_msgs::PointCloud2>("wall_points", 10);
00073 plane_marker_ = nh_.advertise<visualization_msgs::Marker>("wall_marker", 10);
00074 }
00075
00076 virtual ~PlanarFit () { }
00077
00078
00079
00080
00081 void cloudCb(const boost::shared_ptr<const sensor_msgs::PointCloud2>& cloud)
00082 {
00083 boost::mutex::scoped_lock lock(cloud_mutex_);
00084 cloud_msg_ = cloud;
00085 cloud_condition_.notify_all();
00086 }
00087
00088
00089
00090 bool detect_wall (stereo_wall_detection::DetectWall::Request &req, stereo_wall_detection::DetectWall::Response &resp)
00091 {
00092 ros::Time start_time = ros::Time::now();
00093
00094
00095 boost::mutex::scoped_lock lock(cloud_mutex_);
00096 cloud_condition_.wait(lock);
00097 bool cloud_found = false;
00098 while (ros::ok() && !cloud_found){
00099
00100 if (ros::Time::now() > start_time + ros::Duration(10.0)){
00101 ROS_ERROR("Did not receive a pointcloud in 10 seconds");
00102 return false;
00103 }
00104
00105
00106 if (cloud_msg_->header.stamp > start_time){
00107 unsigned count = 0;
00108 for (unsigned i=0; i<cloud_msg_->height * cloud_msg_->width; i++){
00109 if (!std::isnan(cloud_msg_->data[i])){
00110 count++;
00111 }
00112 }
00113 if (count > 30000)
00114 cloud_found = true;
00115 else
00116 ROS_INFO("Received a cloud, but it only had %d points", count);
00117 }
00118 else
00119 ROS_INFO("Received a cloud, but the cloud is still %f seconds before start time", (start_time - cloud_msg_->header.stamp).toSec());
00120
00121
00122 if (!cloud_found)
00123 cloud_condition_.wait(lock);
00124 }
00125 ROS_INFO("point cloud received");
00126
00127
00128 double threshold;
00129 nh_.param<double>("distance_threshold", threshold, 0.01);
00130
00131 int tmp_points;
00132
00133
00134 nh_.param<int>("minimum_points", tmp_points, 20000);
00135 size_t min_points = tmp_points;
00136
00137
00138 pcl::PointCloud<pcl::PointXYZ> cloud;
00139 pcl::fromROSMsg(*cloud_msg_, cloud);
00140 pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
00141 pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
00142 pcl::SACSegmentation<pcl::PointXYZ> seg;
00143 seg.setOptimizeCoefficients (true);
00144 seg.setModelType (pcl::SACMODEL_PLANE);
00145 seg.setMethodType (pcl::SAC_RANSAC);
00146 seg.setDistanceThreshold (threshold);
00147 seg.setInputCloud (cloud.makeShared ());
00148 seg.segment (*inliers, *coefficients);
00149 if (inliers->indices.size () == 0) {
00150 ROS_ERROR ("Could not estimate a planar model for the given dataset.");
00151 return false;
00152 }
00153
00154
00155
00156 if( inliers->indices.size() < min_points ) {
00157 ROS_ERROR("Too few inliers in deteted plane: %zd", inliers->indices.size());
00158 return false;
00159 }
00160
00161 pcl::copyPointCloud(cloud, *inliers, cloud);
00162 Eigen::Vector4f centroid;
00163 pcl::compute3DCentroid(cloud, centroid);
00164
00165
00166 if( plane_points_.getNumSubscribers() > 0 ) {
00167 sensor_msgs::PointCloud2 plane_msg;
00168 pcl::toROSMsg(cloud, plane_msg);
00169 plane_points_.publish(plane_msg);
00170 }
00171
00172 geometry_msgs::Vector3 normal;
00173 normal.x = coefficients->values[0];
00174 normal.y = coefficients->values[1];
00175 normal.z = coefficients->values[2];
00176
00177 if( normal.z < 0 ) {
00178
00179 ROS_WARN("Wall Normal points towards camera frame: %s",
00180 cloud_msg_->header.frame_id.c_str());
00181 normal.x = -normal.x;
00182 normal.y = -normal.y;
00183 normal.z = -normal.z;
00184 } else {
00185 ROS_WARN("Wall normal points away from camera frame: %s",
00186 cloud_msg_->header.frame_id.c_str());
00187 }
00188
00189 resp.wall_norm.header = cloud_msg_->header;
00190 resp.wall_norm.vector = normal;
00191
00192 resp.wall_point.header = cloud_msg_->header;
00193 resp.wall_point.point.x = centroid[0];
00194 resp.wall_point.point.y = centroid[1];
00195 resp.wall_point.point.z = centroid[2];
00196
00197
00198
00199 if( plane_marker_.getNumSubscribers() > 0 ) {
00200 visualization_msgs::Marker marker;
00201
00202
00203 marker.header = cloud_msg_->header;
00204 marker.id = 0;
00205 marker.type = visualization_msgs::Marker::ARROW;
00206 marker.action = visualization_msgs::Marker::ADD;
00207
00208
00209 marker.color.a = 1.0;
00210 marker.color.r = 1.0;
00211 marker.color.g = 0.0;
00212 marker.color.b = 0.0;
00213
00214 geometry_msgs::Point end;
00215 end.x = resp.wall_point.point.x + resp.wall_norm.vector.x;
00216 end.y = resp.wall_point.point.y + resp.wall_norm.vector.y;
00217 end.z = resp.wall_point.point.z + resp.wall_norm.vector.z;
00218
00219 marker.points.push_back(resp.wall_point.point);
00220 marker.points.push_back(end);
00221
00222 marker.scale.x = 0.05;
00223 marker.scale.y = 0.1;
00224
00225
00226 plane_marker_.publish(marker);
00227 }
00228
00229 ROS_INFO("Found wall at %f %f %f with normal: %f %f %f in frame %s",
00230 resp.wall_point.point.x, resp.wall_point.point.y, resp.wall_point.point.z,
00231 resp.wall_norm.vector.x, resp.wall_norm.vector.y, resp.wall_norm.vector.z,
00232 cloud_msg_->header.frame_id.c_str());
00233
00234 return true;
00235 }
00236
00237 private:
00238 ros::NodeHandle nh_;
00239 ros::ServiceServer serv_;
00240 ros::Publisher plane_points_;
00241 ros::Publisher plane_marker_;
00242 ros::Subscriber cloud_sub_;
00243
00244 sensor_msgs::PointCloud2ConstPtr cloud_msg_;
00245 boost::condition cloud_condition_;
00246 boost::mutex cloud_mutex_;
00247 };
00248
00249
00250
00251 int main (int argc, char** argv)
00252 {
00253 ros::init (argc, argv, "wall_extractor");
00254
00255 PlanarFit p;
00256 ros::MultiThreadedSpinner spinner(2);
00257 spinner.spin();
00258
00259 return (0);
00260 }
00261