Go to the documentation of this file.00001 #include <numeric>
00002 #include <ros/ros.h>
00003 #include <algorithm>
00004 #include <boost/random/mersenne_twister.hpp>
00005 #include <boost/random/uniform_int.hpp>
00006 #include <boost/random/variate_generator.hpp>
00007 #include <boost/make_shared.hpp>
00008
00009 #include <pcl/kdtree/kdtree_flann.h>
00010 #include <pcl/point_types.h>
00011 #include <pcl_ros/point_cloud.h>
00012 #include <pcl/point_cloud.h>
00013 #include <pcl/segmentation/extract_clusters.h>
00014 #include <pcl/surface/concave_hull.h>
00015 #include <tf/transform_listener.h>
00016 #include <opencv/cv.h>
00017 #include <image_transport/image_transport.h>
00018 #include <geometry_msgs/Point.h>
00019 #include <visualization_msgs/Marker.h>
00020 #include <std_srvs/Empty.h>
00021 #include <costmap_2d/costmap_2d_ros.h>
00022 #include <costmap_2d/costmap_2d.h>
00023 #include <base_local_planner/world_model.h>
00024 #include <base_local_planner/costmap_model.h>
00025 #include <image_geometry/pinhole_camera_model.h>
00026 #include <sensor_msgs/image_encodings.h>
00027
00028 #include <hrl_move_floor_detect/SegmentFloor.h>
00029
00030 using namespace sensor_msgs;
00031 using namespace std;
00032 namespace enc = sensor_msgs::image_encodings;
00033 namespace hrl_move_floor_detect {
00034
00035 class MoveFloorDetect {
00036 public:
00037 ros::NodeHandle nh;
00038 tf::TransformListener tf_listener;
00039 ros::Publisher pc_pub, hull_pub;
00040 image_transport::ImageTransport img_trans;
00041 image_transport::CameraSubscriber camera_sub;
00042 image_geometry::PinholeCameraModel cam_model;
00043 ros::ServiceServer seg_floor_srv;
00044 costmap_2d::Costmap2D costmap;
00045 costmap_2d::Costmap2DROS* costmap_ros;
00046 boost::mt19937 rand_gen;
00047 vector<geometry_msgs::Point> footprint_model;
00048 base_local_planner::CostmapModel* world_model;
00049
00050 MoveFloorDetect();
00051 void onInit();
00052 int randomInt(int a, int b=-1);
00053 bool segFloorCallback(SegmentFloor::Request& req, SegmentFloor::Response& resp);
00054 void cameraCallback(const sensor_msgs::ImageConstPtr& img_msg,
00055 const sensor_msgs::CameraInfoConstPtr& info_msg);
00056 double footprintCost(const Eigen::Vector3f& pos, double scale);
00057 };
00058
00059 MoveFloorDetect::MoveFloorDetect() : img_trans(nh) {
00060 onInit();
00061 }
00062
00063 void MoveFloorDetect::onInit() {
00064 costmap_ros = new costmap_2d::Costmap2DROS("table_costmap", tf_listener);
00065 footprint_model = costmap_ros->getRobotFootprint();
00066
00067 camera_sub = img_trans.subscribeCamera<MoveFloorDetect>
00068 ("/kinect_head/rgb/image_color", 1,
00069 &MoveFloorDetect::cameraCallback, this);
00070 seg_floor_srv = nh.advertiseService("move_floor_detect", &MoveFloorDetect::segFloorCallback, this);
00071
00072 pc_pub = nh.advertise<pcl::PointCloud<pcl::PointXYZI> >("move_floor_pc", 1);
00073 hull_pub = nh.advertise<visualization_msgs::Marker>("floor_hull", 1);
00074 ros::Duration(1.0).sleep();
00075 ROS_INFO("[move_floor_detect] move_floor_detect loaded.");
00076 }
00077
00078 void MoveFloorDetect::cameraCallback(const sensor_msgs::ImageConstPtr& img_msg,
00079 const sensor_msgs::CameraInfoConstPtr& info_msg) {
00080 cam_model.fromCameraInfo(info_msg);
00081 }
00082
00083 int MoveFloorDetect::randomInt(int a, int b) {
00084 if(b == -1) { b = a; a = 0; }
00085 boost::uniform_int<> dist(a, b-1);
00086 boost::variate_generator<boost::mt19937&, boost::uniform_int<> > vgen(rand_gen, dist);
00087 return vgen();
00088 }
00089
00090 bool MoveFloorDetect::segFloorCallback(SegmentFloor::Request& req, SegmentFloor::Response& resp) {
00091 int min_cost = 250;
00092 double surf_clust_dist = 0.10, surf_clust_min_size = 30;
00093
00094 costmap_ros->getCostmapCopy(costmap);
00095 world_model = new base_local_planner::CostmapModel(costmap);
00096
00097 pcl::PointCloud<pcl::PointXYZI>::Ptr move_floor_pc (new pcl::PointCloud<pcl::PointXYZI>);
00098 cv::Size res = cam_model.fullResolution();
00099 double start_time = ros::Time::now().toSec();
00100 while(ros::Time::now().toSec() - start_time < 1.0 && ros::ok()) {
00101
00102 cv::Point2d img_pt(randomInt(res.width), randomInt(res.height));
00103
00104
00105 cv::Point3d img_ray = cam_model.projectPixelTo3dRay(img_pt);
00106 geometry_msgs::Vector3Stamped img_vec, img_vec_trans;
00107 img_vec.header.frame_id = cam_model.tfFrame();
00108 img_vec.header.stamp = ros::Time(0);
00109 img_vec.vector.x = img_ray.x; img_vec.vector.y = img_ray.y; img_vec.vector.z = img_ray.z;
00110 tf_listener.transformVector("/odom_combined", img_vec, img_vec_trans);
00111 tf::StampedTransform cam_trans;
00112 tf_listener.lookupTransform("/odom_combined", cam_model.tfFrame(), ros::Time(0),
00113 cam_trans);
00114
00115 double t = - cam_trans.getOrigin().z() / img_vec_trans.vector.z;
00116
00117
00118 double floor_pos_x = cam_trans.getOrigin().x()+t*img_vec_trans.vector.x;
00119 double floor_pos_y = cam_trans.getOrigin().y()+t*img_vec_trans.vector.y;
00120 Eigen::Vector3f floor_pos(floor_pos_x,
00121 floor_pos_y,
00122 std::atan2(floor_pos_y, floor_pos_x));
00123 double foot_cost = footprintCost(floor_pos, 0.5);
00124
00125 if(foot_cost < 0 || foot_cost > min_cost)
00126 continue;
00127
00128
00129 pcl::PointXYZI pc_pt;
00130 pc_pt.x = floor_pos_x; pc_pt.y = floor_pos_y; pc_pt.z = 0;
00131 pc_pt.intensity = (256 - foot_cost)/256;
00132 move_floor_pc->points.push_back(pc_pt);
00133 }
00134 if(move_floor_pc->points.empty())
00135 return false;
00136 move_floor_pc->header.frame_id = "/odom_combined";
00137 move_floor_pc->header.stamp = ros::Time::now();
00138 pc_pub.publish(move_floor_pc);
00139
00140
00141 pcl::EuclideanClusterExtraction<pcl::PointXYZI> surf_clust;
00142 pcl::KdTree<pcl::PointXYZI>::Ptr clust_tree (new pcl::KdTreeFLANN<pcl::PointXYZI> ());
00143 surf_clust.setClusterTolerance(surf_clust_dist);
00144 surf_clust.setMinClusterSize(surf_clust_min_size);
00145 surf_clust.setInputCloud(move_floor_pc);
00146 surf_clust.setSearchMethod(clust_tree);
00147 std::vector<pcl::PointIndices> surf_clust_list;
00148 surf_clust.extract(surf_clust_list);
00149
00150 for(uint32_t i =0;i<surf_clust_list.size();i++) {
00151
00152 pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_hull (new pcl::PointCloud<pcl::PointXYZI>);
00153 pcl::PointCloud<pcl::PointXYZI>::Ptr voronoi_centers (new pcl::PointCloud<pcl::PointXYZI>);
00154 std::vector<pcl::Vertices> hull_verts;
00155 pcl::ConcaveHull<pcl::PointXYZI> concave_hull;
00156 concave_hull.setInputCloud(move_floor_pc);
00157 concave_hull.setIndices(boost::make_shared<pcl::PointIndices>(surf_clust_list[i]));
00158 concave_hull.setAlpha(0.1);
00159 concave_hull.setVoronoiCenters(voronoi_centers);
00160 concave_hull.reconstruct(*cloud_hull, hull_verts);
00161
00162
00163 visualization_msgs::Marker hull_poly;
00164 hull_poly.type = visualization_msgs::Marker::LINE_STRIP;
00165 hull_poly.action = visualization_msgs::Marker::ADD;
00166 hull_poly.ns = "floor_hull";
00167 hull_poly.header.frame_id = "/odom_combined";
00168 hull_poly.header.stamp = ros::Time::now();
00169 hull_poly.id = i;
00170 hull_poly.pose.orientation.w = 1;
00171 hull_poly.scale.x = 0.01; hull_poly.scale.y = 0.01; hull_poly.scale.z = 0.01;
00172 hull_poly.color.r = 1; hull_poly.color.a = 1;
00173 for(uint32_t j=0;j<cloud_hull->points.size();j++) {
00174 geometry_msgs::Point n_pt;
00175 n_pt.x = cloud_hull->points[j].x;
00176 n_pt.y = cloud_hull->points[j].y;
00177 n_pt.z = cloud_hull->points[j].z;
00178 hull_poly.points.push_back(n_pt);
00179 }
00180 if(!hull_poly.points.empty()) {
00181 hull_poly.points.push_back(hull_poly.points[0]);
00182 resp.surfaces.push_back(hull_poly);
00183 hull_pub.publish(hull_poly);
00184 }
00185 }
00186 ROS_INFO("[move_floor_detect] Number of floor surfaces: %d", (int) resp.surfaces.size());
00187
00188 delete world_model;
00189 return true;
00190 }
00191
00192 double MoveFloorDetect::footprintCost(const Eigen::Vector3f& pos, double scale){
00193 double cos_th = cos(pos[2]);
00194 double sin_th = sin(pos[2]);
00195
00196 std::vector<geometry_msgs::Point> scaled_oriented_footprint;
00197 for(unsigned int i = 0; i < footprint_model.size(); ++i){
00198 geometry_msgs::Point new_pt;
00199 new_pt.x = pos[0] + (scale * footprint_model[i].x * cos_th - scale * footprint_model[i].y * sin_th);
00200 new_pt.y = pos[1] + (scale * footprint_model[i].x * sin_th + scale * footprint_model[i].y * cos_th);
00201 scaled_oriented_footprint.push_back(new_pt);
00202 }
00203
00204 geometry_msgs::Point robot_position;
00205 robot_position.x = pos[0];
00206 robot_position.y = pos[1];
00207
00208
00209 double footprint_cost = world_model->footprintCost(robot_position, scaled_oriented_footprint, costmap.getInscribedRadius(), costmap.getCircumscribedRadius());
00210
00211 return footprint_cost;
00212 }
00213 };
00214
00215 using namespace hrl_move_floor_detect;
00216
00217 int main(int argc, char **argv)
00218 {
00219 ros::init(argc, argv, "move_floor_detect");
00220 MoveFloorDetect mfd;
00221 ros::spin();
00222 return 0;
00223 }
00224
00225
00226