00001 #include "door_cloud_alg_node.h"
00002
00003 DoorCloudAlgNode::DoorCloudAlgNode(void) :
00004 algorithm_base::IriBaseAlgorithm<DoorCloudAlgorithm>()
00005 {
00006
00007
00008
00009
00010 this->open_door_cloud_publisher_ = this->public_node_handle_.advertise<sensor_msgs::PointCloud2>("open_door_cloud", 1);
00011 this->open_door_marker_publisher_ = this->public_node_handle_.advertise<visualization_msgs::Marker>("open_door_marker", 1);
00012 this->door_centroid_publisher_ = this->public_node_handle_.advertise<geometry_msgs::PoseStamped>("door_centroid", 1);
00013
00014 this->closed_door_cloud_publisher_ = this->public_node_handle_.advertise<sensor_msgs::PointCloud2>("closed_door_cloud", 1);
00015 this->closed_door_marker_publisher_ = this->public_node_handle_.advertise<visualization_msgs::Marker>("closed_door_marker", 1);
00016 this->door_handle_publisher_ = this->public_node_handle_.advertise<geometry_msgs::PoseStamped>("door_handle", 1);
00017
00018
00019 if (!no_simulator)
00020 this->door_action_start_subscriber_ = this->public_node_handle_.subscribe("/iri_door_detector/door_detector_actions/door_action_start", 1, &DoorCloudAlgNode::door_action_start_callback, this);
00021
00022 if (no_simulator)
00023 {
00024 this->points_subscriber_ = this->public_node_handle_.subscribe("/camera/depth/points", 1, &DoorCloudAlgNode::points_callback, this);
00025 this->door_centroid_subscriber_ = this->public_node_handle_.subscribe("/iri_door_detector/open_door_detector/door_centroid", 1, &DoorCloudAlgNode::door_centroid_callback, this);
00026 this->handle_location_subscriber_ = this->public_node_handle_.subscribe("/iri_door_detector/closed_door_detector/door_handle", 1, &DoorCloudAlgNode::handle_location_callback, this);
00027 }
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 captured_open = 0;
00039 captured_closed = 0;
00040 start = 0;
00041 tf_original_frame = "/kinect_depth_optical_frame";
00042 }
00043
00044 DoorCloudAlgNode::~DoorCloudAlgNode(void)
00045 {
00046
00047 }
00048
00049 void DoorCloudAlgNode::mainNodeThread(void)
00050 {
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 }
00065
00066
00067 void DoorCloudAlgNode::door_action_start_callback(const std_msgs::Int8::ConstPtr& action_start)
00068 {
00069
00070
00071
00072
00073 this->door_action_start_mutex_.enter();
00074
00075 start=action_start->data;
00076
00077 if (start==0)
00078 {
00079 points_subscriber_.shutdown();
00080 door_centroid_subscriber_.shutdown();
00081 handle_location_subscriber_.shutdown();
00082 }
00083 if (start==1)
00084 {
00085 this->points_subscriber_ = this->public_node_handle_.subscribe("/camera/depth/points", 1, &DoorCloudAlgNode::points_callback, this);
00086 this->door_centroid_subscriber_ = this->public_node_handle_.subscribe("/iri_door_detector/open_door_detector/door_centroid", 1, &DoorCloudAlgNode::door_centroid_callback, this);
00087 this->handle_location_subscriber_ = this->public_node_handle_.subscribe("/iri_door_detector/closed_door_detector/door_handle", 1, &DoorCloudAlgNode::handle_location_callback, this);
00088 }
00089
00090
00091
00092 this->door_action_start_mutex_.exit();
00093 }
00094 void DoorCloudAlgNode::door_centroid_callback(const geometry_msgs::PoseStamped::ConstPtr& door_centroid)
00095 {
00096
00097
00098 this->door_centroid_mutex_.enter();
00099
00100 if (captured_open==0)
00101 {
00102 y_open=door_centroid->pose.position.y;
00103 z_open=door_centroid->pose.position.z;
00104 w_open=door_centroid->pose.orientation.w;
00105
00106 x_left = door_centroid->pose.position.x;
00107 x_right = door_centroid->pose.orientation.x;
00108 y_top = door_centroid->pose.orientation.y;
00109
00110 x_open=(x_left+x_right)/2;
00111
00112
00113 captured_open=1;
00114 }
00115
00116
00117
00118 this->door_centroid_mutex_.exit();
00119 }
00120 void DoorCloudAlgNode::handle_location_callback(const geometry_msgs::PoseStamped::ConstPtr& handle_location)
00121 {
00122
00123
00124 this->handle_location_mutex_.enter();
00125
00126
00127
00128 if (captured_closed==0)
00129 {
00130
00131 x_closed=handle_location->pose.position.x;
00132 y_closed=handle_location->pose.position.y;
00133 z_closed=handle_location->pose.position.z;
00134 w_closed=handle_location->pose.orientation.w;
00135
00136 captured_closed=1;
00137 }
00138
00139
00140
00141 this->handle_location_mutex_.exit();
00142 }
00143
00144 void DoorCloudAlgNode::points_callback(const sensor_msgs::PointCloud2::ConstPtr& input_cloud)
00145 {
00146
00147
00148 this->points_mutex_.enter();
00149
00150 if(captured_open==1 || captured_closed==1)
00151 {
00152
00153 pcl::fromROSMsg (*input_cloud,cloud);
00154 pcl::ModelCoefficients::Ptr cloud_coeffs (new pcl::ModelCoefficients ());
00155 pcl::PointIndices::Ptr cloud_inliers (new pcl::PointIndices);
00156
00157 pcl::VoxelGrid<pcl::PointXYZ> sor;
00158 sor.setInputCloud (cloud.makeShared());
00159 sor.setLeafSize (0.01f, 0.01f, 0.01f);
00160 sor.filter (cloud);
00161
00162 if(captured_open==1)
00163 {
00164
00165
00166 cloud_filtered.clear();
00167 cloud_filtered_left.clear();
00168 cloud_filtered_right.clear();
00169 cloud_filtered_top.clear();
00170
00171 cloud_filtered.header=cloud.header;
00172
00173
00174
00175
00176
00177 lower_x = x_left-0.3;
00178 upper_x = x_left;
00179 lower_y = y_open-5.0;
00180 upper_y = y_open;
00181 lower_z = z_open-0.25;
00182 upper_z = z_open+0.25;
00183
00184
00185 cloud_filtered_left=filterCloud(cloud, lower_x, upper_x, lower_y, upper_y, lower_z, upper_z, false);
00186 cloud_filtered_left.header=cloud.header;
00187 cloud_filtered+=cloud_filtered_left;
00188
00189
00190 lower_x = x_right;
00191 upper_x = x_right+0.3;
00192
00193
00194 cloud_filtered_right=filterCloud(cloud, lower_x, upper_x, lower_y, upper_y, lower_z, upper_z, false);
00195 cloud_filtered_right.header=cloud.header;
00196 cloud_filtered+=cloud_filtered_right;
00197
00198
00199 lower_x = x_left-0.3;
00200 upper_x = x_right+0.3;
00201 lower_y = y_open-5.0;
00202 upper_y = y_top;
00203
00204
00205 cloud_filtered_top=filterCloud(cloud, lower_x, upper_x, lower_y, upper_y, lower_z, upper_z, false);
00206 cloud_filtered_top.header.frame_id=input_cloud->header.frame_id;
00207
00208
00209
00210 door_plane = planeFit(cloud_filtered);
00211
00212 cloud_plane= boost::tuples::get<0>(door_plane);
00213 cloud_inliers= boost::tuples::get<1>(door_plane);
00214 cloud_coeffs= boost::tuples::get<2>(door_plane);
00215
00216 if (cloud_inliers->indices.size () == 0)
00217 {
00218 ROS_WARN("Open Door Detector: Could not compute plane! maybe there are too few points");
00219 }
00220
00221
00222 if (cloud_inliers->indices.size () > 0)
00223 {
00224
00225 if(cloud_coeffs->values[2]<0)
00226 {
00227 cloud_coeffs->values[0]= -cloud_coeffs->values[0];
00228 cloud_coeffs->values[1]= -cloud_coeffs->values[1];
00229 cloud_coeffs->values[2]= -cloud_coeffs->values[2];
00230 cloud_coeffs->values[3]= -cloud_coeffs->values[3];
00231 }
00232
00233
00234
00235
00236 poses.header.frame_id=input_cloud->header.frame_id;
00237 poses.header.stamp=input_cloud->header.stamp;
00238
00239 poses.pose.position.x = x_open;
00240 poses.pose.position.y = y_open;
00241 poses.pose.position.z = z_open;
00242
00243 poses.pose.orientation.x = cloud_coeffs->values[0];
00244 poses.pose.orientation.y = cloud_coeffs->values[1];
00245 poses.pose.orientation.z = cloud_coeffs->values[2];
00246 poses.pose.orientation.w = w_open;
00247
00248 door_centroid_publisher_.publish(poses);
00249
00250 tf::Vector3 initial_position = tf::Vector3(1.0,0.0,0.0);
00251 tf::Vector3 plane_norm = tf::Vector3(poses.pose.orientation.x,
00252 poses.pose.orientation.y,
00253 poses.pose.orientation.z);
00254
00255 orient=quaternionFromVectors(initial_position, plane_norm);
00256 poses.pose.orientation=orient;
00257
00258 pcl::toROSMsg(cloud_plane, open_door_cloud);
00259 open_door_cloud.header.frame_id=input_cloud->header.frame_id;
00260 open_door_cloud.header.stamp=input_cloud->header.stamp;
00261 open_door_cloud_publisher_.publish(open_door_cloud);
00262
00263 cloud_plane.points.clear();
00264 cloud_plane.width=1;
00265 cloud_plane.height=1;
00266 cloud_plane.points.resize (1);
00267 pcl::toROSMsg(cloud_plane, closed_door_cloud);
00268 closed_door_cloud.header=input_cloud->header;
00269 closed_door_cloud_publisher_.publish(closed_door_cloud);
00270
00271 marker = ArrowMarker(input_cloud->header, poses.pose, 1, 2, "door_centroid_vector");
00272 open_door_marker_publisher_.publish(marker);
00273
00274 marker.ns = "door_handle_vector";
00275 marker.color.a = 0.0;
00276 closed_door_marker_publisher_.publish(marker);
00277 }
00278 }
00279
00280 if(captured_closed==1)
00281 {
00282
00283
00284
00285 lower_x = x_closed-0.4;
00286 upper_x = x_closed+0.4;
00287 lower_y = y_closed-5.0;
00288 upper_y = y_closed;
00289 lower_z = z_closed-0.3;
00290 upper_z = z_closed+0.3;
00291
00292 if(w_closed==-1)
00293 {
00294 lower_x = x_closed-0.1;
00295 upper_x = x_closed+0.6;
00296 }
00297 if(w_closed==1)
00298 {
00299 lower_x = x_closed-0.6;
00300 upper_x = x_closed+0.1;
00301 }
00302
00303
00304 cloud_filtered=filterCloud(cloud, lower_x, upper_x, lower_y, upper_y, lower_z, upper_z, false);
00305
00306
00307 door_plane = planeFit(cloud_filtered);
00308 cloud_plane= boost::tuples::get<0>(door_plane);
00309 cloud_inliers= boost::tuples::get<1>(door_plane);
00310 cloud_coeffs= boost::tuples::get<2>(door_plane);
00311
00312 if (cloud_inliers->indices.size () == 0)
00313 {
00314 ROS_WARN("Closed Door Detector: Could not compute plane! maybe there are too few points");
00315
00316 }
00317
00318
00319 if (cloud_inliers->indices.size () > 0)
00320 {
00321
00322 if(cloud_coeffs->values[2]<0)
00323 {
00324 cloud_coeffs->values[3]=cloud_coeffs->values[3]-0.04;
00325 }
00326 if(cloud_coeffs->values[2]>0)
00327 {
00328 cloud_coeffs->values[3]=cloud_coeffs->values[3]+0.04;
00329 }
00330
00331
00332
00333 if(cloud_coeffs->values[2]<0)
00334 {
00335 cloud_coeffs->values[0]= -cloud_coeffs->values[0];
00336 cloud_coeffs->values[1]= -cloud_coeffs->values[1];
00337 cloud_coeffs->values[2]= -cloud_coeffs->values[2];
00338 cloud_coeffs->values[3]= -cloud_coeffs->values[3];
00339 }
00340
00341
00342
00343 poses.header.frame_id=input_cloud->header.frame_id;
00344 poses.header.stamp=input_cloud->header.stamp;
00345
00346 poses.pose.position.x = x_closed;
00347 poses.pose.position.y = y_closed;
00348 poses.pose.position.z = z_closed;
00349
00350 poses.pose.orientation.x=cloud_coeffs->values[0];
00351 poses.pose.orientation.y=cloud_coeffs->values[1];
00352 poses.pose.orientation.z=cloud_coeffs->values[2];
00353 poses.pose.orientation.w = w_closed;
00354
00355 door_handle_publisher_.publish(poses);
00356
00357 tf::Vector3 initial_position = tf::Vector3(-1.0,0.0,0.0);
00358 tf::Vector3 plane_norm = tf::Vector3(poses.pose.orientation.x,
00359 poses.pose.orientation.y,
00360 poses.pose.orientation.z);
00361
00362 orient=quaternionFromVectors(initial_position, plane_norm);
00363 poses.pose.orientation=orient;
00364
00365 pcl::toROSMsg(cloud_plane, closed_door_cloud);
00366 closed_door_cloud.header.frame_id=input_cloud->header.frame_id;
00367 closed_door_cloud.header.stamp=input_cloud->header.stamp;
00368
00369 closed_door_cloud_publisher_.publish(closed_door_cloud);
00370
00371 cloud_plane.points.clear();
00372 cloud_plane.width=1;
00373 cloud_plane.height=1;
00374 cloud_plane.points.resize (1);
00375 pcl::toROSMsg(cloud_plane, open_door_cloud);
00376 open_door_cloud.header=input_cloud->header;
00377 open_door_cloud_publisher_.publish(open_door_cloud);
00378
00379 marker = ArrowMarker(input_cloud->header, poses.pose, 1, 2, "door_handle_vector");
00380 closed_door_marker_publisher_.publish(marker);
00381
00382 marker.ns = "door_centroid_vector";
00383 marker.color.a = 0.0;
00384 open_door_marker_publisher_.publish(marker);
00385 }
00386 }
00387
00388 captured_open=0;
00389 captured_closed=0;
00390 }
00391
00392
00393
00394 this->points_mutex_.exit();
00395 }
00396
00397
00398
00399
00400
00401
00402
00403 void DoorCloudAlgNode::node_config_update(Config &config, uint32_t level)
00404 {
00405 this->alg_.lock();
00406
00407 this->no_simulator = config.no_simulator;
00408
00409 this->alg_.unlock();
00410 }
00411
00412 void DoorCloudAlgNode::addNodeDiagnostics(void)
00413 {
00414 }
00415
00416
00417 int main(int argc,char *argv[])
00418 {
00419 return algorithm_base::main<DoorCloudAlgNode>(argc, argv, "door_cloud_alg_node");
00420 }
00421
00422
00423 pcl::PointCloud<pcl::PointXYZ> DoorCloudAlgNode::filterCloud (pcl::PointCloud<pcl::PointXYZ> raw_cloud, float Lowx, float Uppx, float Lowy, float Uppy, float Lowz, float Uppz, bool negative_limits)
00424 {
00425
00426 pcl::PointCloud<pcl::PointXYZ> cloud_filtered_x;
00427 pcl::PointCloud<pcl::PointXYZ> cloud_filtered_z;
00428 pcl::PointCloud<pcl::PointXYZ> cloud_filtered_y;
00429
00430 pcl::PassThrough<pcl::PointXYZ> pass;
00431 pass.setInputCloud (raw_cloud.makeShared());
00432 pass.setFilterFieldName ("x");
00433 pass.setFilterLimits (Lowx, Uppx);
00434 pass.setFilterLimitsNegative (negative_limits);
00435 pass.filter (cloud_filtered_x);
00436
00437 if (cloud_filtered_x.points.size()>0)
00438 {
00439 pcl::PassThrough<pcl::PointXYZ> pass2;
00440 pass2.setInputCloud (cloud_filtered_x.makeShared());
00441 pass2.setFilterFieldName ("y");
00442 pass2.setFilterLimits (Lowy, Uppy);
00443 pass2.filter (cloud_filtered_y);
00444
00445 if (cloud_filtered_y.points.size()>0)
00446 {
00447 pcl::PassThrough<pcl::PointXYZ> pass3;
00448 pass3.setInputCloud (cloud_filtered_y.makeShared());
00449 pass3.setFilterFieldName ("z");
00450 pass3.setFilterLimits (Lowz, Uppz);
00451 pass3.filter (cloud_filtered_z);
00452 }
00453 }
00454
00455 return cloud_filtered_z;
00456 }
00457
00458 boost::tuple<pcl::PointCloud<pcl::PointXYZ>, pcl::PointIndices::Ptr,pcl::ModelCoefficients::Ptr> DoorCloudAlgNode::planeFit (pcl::PointCloud<pcl::PointXYZ> raw_cloud)
00459 {
00460
00461 pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients ());
00462 pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
00463 pcl::PointCloud<pcl::PointXYZ> planecloud;
00464
00465
00466 pcl::SACSegmentation<pcl::PointXYZ> seg;
00467
00468 seg.setOptimizeCoefficients (true);
00469
00470 seg.setModelType (pcl::SACMODEL_PLANE);
00471 seg.setMethodType (pcl::SAC_RANSAC);
00472 seg.setDistanceThreshold (0.05);
00473
00474 if (raw_cloud.points.size()>0)
00475 {
00476 seg.setInputCloud (raw_cloud.makeShared ());
00477 seg.segment (*inliers, *coefficients);
00478
00479 pcl::ExtractIndices<pcl::PointXYZ> extract;
00480 extract.setInputCloud(raw_cloud.makeShared ());
00481 extract.setIndices (inliers);
00482 extract.setNegative(false);
00483 extract.filter(planecloud);
00484 }
00485
00486 boost::tuple<pcl::PointCloud<pcl::PointXYZ>, pcl::PointIndices::Ptr, pcl::ModelCoefficients::Ptr> planeFit (planecloud, inliers, coefficients);
00487
00488 return planeFit;
00489 }
00490
00491 geometry_msgs::Quaternion DoorCloudAlgNode::quaternionFromVectors (tf::Vector3 vector_1, tf::Vector3 vector_2)
00492 {
00493
00494 vector_1 = vector_1.normalize();
00495 vector_2 = vector_2.normalize();
00496 float rot_ang = acos(vector_1.dot(vector_2));
00497 tf::Vector3 rot_axis = vector_1.cross(vector_2);
00498 tf::Quaternion q = tf::Quaternion(rot_axis,rot_ang);
00499 q.normalize();
00500 tf::quaternionTFToMsg(q, orient);
00501
00502
00503
00504 return orient;
00505 }
00506
00507 visualization_msgs::Marker DoorCloudAlgNode::ArrowMarker(std_msgs::Header header, geometry_msgs::Pose pose, int alpha, int color, const char arrow_tag[])
00508 {
00509
00510 marker.header = header;
00511 marker.ns = arrow_tag;
00512 marker.id = 0;
00513 marker.type = visualization_msgs::Marker::ARROW;
00514 marker.action = visualization_msgs::Marker::ADD;
00515 marker.pose = pose;
00516
00517
00518 marker.scale.x = 0.7;
00519 marker.scale.y = 0.7;
00520 marker.scale.z = 0.7;
00521
00522
00523 marker.color.a = alpha;
00524 marker.color.r = 0.0;
00525 marker.color.g = 0.0;
00526 marker.color.b = 0.0;
00527
00528 if(color==1)
00529 marker.color.r = 1.0;
00530 if(color==2)
00531 marker.color.g = 1.0;
00532 if(color==3)
00533 marker.color.b = 1.0;
00534
00535 return marker;
00536 }