move_floor_detect.cpp
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             // pick a random point on the image
00102             cv::Point2d img_pt(randomInt(res.width), randomInt(res.height));
00103 
00104             // project the point onto the floor
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             // p = p0 + t * v, pz = 0
00115             double t = - cam_trans.getOrigin().z() / img_vec_trans.vector.z;
00116 
00117             // find the cost of this position on the floor
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             // throw out unmoveable positions
00125             if(foot_cost < 0 || foot_cost > min_cost)
00126                 continue;
00127 
00128             // Add point to point cloud of move positions
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         // Cluster into distinct surfaces
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             // find concave hull of surface
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             // create polygon of floor surface
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         //check if the footprint is legal
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 


hrl_move_floor_detect
Author(s): kelsey
autogenerated on Wed Nov 27 2013 11:39:34