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 #include <ros/ros.h>
00033 #include <sensor_msgs/PointCloud2.h>
00034 #include <actionlib/server/simple_action_server.h>
00035 #include <turtlebot_block_manipulation/BlockDetectionAction.h>
00036
00037 #include <tf/transform_listener.h>
00038
00039 #include <pcl/ros/conversions.h>
00040 #include <pcl/point_cloud.h>
00041 #include <pcl/point_types.h>
00042 #include <pcl/filters/passthrough.h>
00043 #include <pcl/segmentation/extract_clusters.h>
00044 #include <pcl/filters/extract_indices.h>
00045 #include <pcl/kdtree/kdtree_flann.h>
00046 #include <pcl/sample_consensus/method_types.h>
00047 #include <pcl/sample_consensus/model_types.h>
00048 #include <pcl/segmentation/sac_segmentation.h>
00049 #include <pcl/segmentation/extract_clusters.h>
00050
00051
00052 #include <pcl_ros/point_cloud.h>
00053 #include <pcl_ros/transforms.h>
00054
00055 #include <cmath>
00056 #include <algorithm>
00057
00058 namespace turtlebot_block_manipulation
00059 {
00060
00061 class BlockDetectionServer
00062 {
00063 private:
00064
00065 ros::NodeHandle nh_;
00066 actionlib::SimpleActionServer<turtlebot_block_manipulation::BlockDetectionAction> as_;
00067 std::string action_name_;
00068 turtlebot_block_manipulation::BlockDetectionFeedback feedback_;
00069 turtlebot_block_manipulation::BlockDetectionResult result_;
00070 turtlebot_block_manipulation::BlockDetectionGoalConstPtr goal_;
00071 ros::Subscriber sub_;
00072 ros::Publisher pub_;
00073
00074 tf::TransformListener tf_listener_;
00075
00076
00077 std::string arm_link;
00078 double block_size;
00079 double table_height;
00080
00081 ros::Publisher block_pub_;
00082
00083
00084
00085 public:
00086 BlockDetectionServer(const std::string name) :
00087 nh_("~"), as_(name, false), action_name_(name)
00088 {
00089
00090
00091
00092
00093
00094 as_.registerGoalCallback(boost::bind(&BlockDetectionServer::goalCB, this));
00095 as_.registerPreemptCallback(boost::bind(&BlockDetectionServer::preemptCB, this));
00096
00097 as_.start();
00098
00099
00100 sub_ = nh_.subscribe("/camera/depth_registered/points", 1, &BlockDetectionServer::cloudCb, this);
00101 pub_ = nh_.advertise< pcl::PointCloud<pcl::PointXYZRGB> >("block_output", 1);
00102
00103 block_pub_ = nh_.advertise< geometry_msgs::PoseArray >("/turtlebot_blocks", 1, true);
00104 }
00105
00106 void goalCB()
00107 {
00108 ROS_INFO("[block detection] Received goal!");
00109
00110 result_.blocks.poses.clear();
00111
00112 goal_ = as_.acceptNewGoal();
00113
00114 block_size = goal_->block_size;
00115 table_height = goal_->table_height;
00116 arm_link = goal_->frame;
00117
00118 result_.blocks.header.frame_id = arm_link;
00119 }
00120
00121 void preemptCB()
00122 {
00123 ROS_INFO("%s: Preempted", action_name_.c_str());
00124
00125 as_.setPreempted();
00126 }
00127
00128 void cloudCb ( const sensor_msgs::PointCloud2ConstPtr& msg )
00129 {
00130
00131 if (!as_.isActive()) return;
00132
00133 result_.blocks.header.stamp = msg->header.stamp;
00134
00135
00136 pcl::PointCloud<pcl::PointXYZRGB> cloud;
00137 pcl::fromROSMsg (*msg, cloud);
00138
00139
00140 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_transformed (new pcl::PointCloud<pcl::PointXYZRGB>);
00141
00142 tf_listener_.waitForTransform(std::string(arm_link), cloud.header.frame_id, cloud.header.stamp, ros::Duration(1.0));
00143 if (!pcl_ros::transformPointCloud (std::string(arm_link), cloud, *cloud_transformed, tf_listener_))
00144 {
00145 ROS_ERROR ("Error converting to desired frame");
00146 return;
00147 }
00148
00149
00150 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZRGB>);
00151 pcl::SACSegmentation<pcl::PointXYZRGB> seg;
00152 pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
00153 pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
00154 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_plane (new pcl::PointCloud<pcl::PointXYZRGB> ());
00155 seg.setOptimizeCoefficients (true);
00156 seg.setModelType (pcl::SACMODEL_PLANE);
00157 seg.setMethodType (pcl::SAC_RANSAC);
00158 seg.setMaxIterations (200);
00159 seg.setDistanceThreshold (0.005);
00160
00161
00162 pcl::PassThrough<pcl::PointXYZRGB> pass;
00163 pass.setInputCloud(cloud_transformed);
00164 pass.setFilterFieldName("z");
00165
00166 pass.setFilterLimits(table_height - 0.05, table_height + block_size + 0.05);
00167 pass.filter(*cloud_filtered);
00168 if( cloud_filtered->points.size() == 0 ){
00169 ROS_ERROR("0 points left");
00170 return;
00171 }else
00172 ROS_INFO("Filtered, %d points left", (int) cloud_filtered->points.size());
00173
00174 int nr_points = cloud_filtered->points.size ();
00175 while (cloud_filtered->points.size () > 0.3 * nr_points)
00176 {
00177
00178 seg.setInputCloud(cloud_filtered);
00179 seg.segment (*inliers, *coefficients);
00180 if (inliers->indices.size () == 0)
00181 {
00182 std::cout << "Could not estimate a planar model for the given dataset." << std::endl;
00183 return;
00184 }
00185
00186 std::cout << "Inliers: " << (inliers->indices.size ()) << std::endl;
00187
00188
00189 pcl::ExtractIndices<pcl::PointXYZRGB> extract;
00190 extract.setInputCloud (cloud_filtered);
00191 extract.setIndices (inliers);
00192 extract.setNegative (false);
00193
00194
00195 extract.filter (*cloud_plane);
00196 std::cout << "PointCloud representing the planar component: " << cloud_plane->points.size () << " data points." << std::endl;
00197
00198
00199 extract.setNegative (true);
00200 extract.filter (*cloud_filtered);
00201 }
00202
00203
00204 pcl::KdTree<pcl::PointXYZRGB>::Ptr tree (new pcl::KdTreeFLANN<pcl::PointXYZRGB>);
00205 tree->setInputCloud (cloud_filtered);
00206
00207 std::vector<pcl::PointIndices> cluster_indices;
00208 pcl::EuclideanClusterExtraction<pcl::PointXYZRGB> ec;
00209 ec.setClusterTolerance (0.005);
00210 ec.setMinClusterSize (100);
00211 ec.setMaxClusterSize (25000);
00212 ec.setSearchMethod (tree);
00213 ec.setInputCloud( cloud_filtered);
00214 ec.extract (cluster_indices);
00215
00216 pub_.publish(cloud_filtered);
00217
00218
00219 for (size_t c = 0; c < cluster_indices.size (); ++c)
00220 {
00221
00222 float xmin = 0; float xmax = 0; float ymin = 0; float ymax = 0;
00223 float zmin = 0; float zmax = 0;
00224 for (size_t i = 0; i < cluster_indices[c].indices.size(); i++)
00225 {
00226 int j = cluster_indices[c].indices[i];
00227 float x = cloud_filtered->points[j].x;
00228 float y = cloud_filtered->points[j].y;
00229 float z = cloud_filtered->points[j].z;
00230 if (i == 0)
00231 {
00232 xmin = xmax = x;
00233 ymin = ymax = y;
00234 zmin = zmax = z;
00235 }
00236 else
00237 {
00238 xmin = std::min(xmin, x);
00239 xmax = std::max(xmax, x);
00240 ymin = std::min(ymin, y);
00241 ymax = std::max(ymax, y);
00242 zmin = std::min(zmin, z);
00243 zmax = std::max(zmax, z);
00244 }
00245 }
00246
00247
00248 float xside = xmax-xmin;
00249 float yside = ymax-ymin;
00250 float zside = zmax-zmin;
00251
00252 const float tol = 0.01;
00253
00254
00255
00256 if (xside > block_size-tol && xside < block_size*sqrt(2)+tol &&
00257 yside > block_size-tol && yside < block_size*sqrt(2)+tol &&
00258 zside > tol && zside < block_size+tol)
00259 {
00260
00261 float angle = atan(block_size/((xside+yside)/2));
00262
00263 if (yside < block_size)
00264 angle = 0.0;
00265
00266 ROS_INFO_STREAM("xside: " << xside << " yside: " << yside << " zside " << zside << " angle: " << angle);
00267
00268 ROS_INFO("Adding a new block!");
00269 addBlock( xmin+(xside)/2.0, ymin+(yside)/2.0, zmax - block_size/2.0, angle);
00270 }
00271 }
00272
00273 if (result_.blocks.poses.size() > 0)
00274 {
00275 as_.setSucceeded(result_);
00276 block_pub_.publish(result_.blocks);
00277 ROS_INFO("[block detection] Set as succeeded!");
00278 }
00279 else
00280 ROS_INFO("[block detection] Couldn't find any blocks this iteration!");
00281
00282 }
00283
00284 void addBlock(float x, float y, float z, float angle)
00285 {
00286 geometry_msgs::Pose block_pose;
00287 block_pose.position.x = x;
00288 block_pose.position.y = y;
00289 block_pose.position.z = z;
00290
00291 Eigen::Quaternionf quat(Eigen::AngleAxis<float>(angle, Eigen::Vector3f(0,0,1)));
00292
00293 block_pose.orientation.x = quat.x();
00294 block_pose.orientation.y = quat.y();
00295 block_pose.orientation.z = quat.z();
00296 block_pose.orientation.w = quat.w();
00297
00298 result_.blocks.poses.push_back(block_pose);
00299 }
00300
00301 };
00302
00303 };
00304
00305 int main(int argc, char** argv)
00306 {
00307 ros::init(argc, argv, "block_detection_action_server");
00308
00309 turtlebot_block_manipulation::BlockDetectionServer server("block_detection");
00310 ros::spin();
00311
00312 return 0;
00313 }
00314