footstep_state.cpp
Go to the documentation of this file.
00001 // -*- mode: c++ -*-
00002 /*********************************************************************
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2015, JSK Lab
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/o2r other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the JSK Lab nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *********************************************************************/
00035 
00036 #include "jsk_footstep_planner/footstep_state.h"
00037 
00038 #include <eigen_conversions/eigen_msg.h>
00039 
00040 #include <jsk_recognition_utils/pcl_conversion_util.h>
00041 #include <jsk_recognition_utils/geo_util.h>
00042 #include "jsk_footstep_planner/line2d.h"
00043 
00044 namespace jsk_footstep_planner
00045 {
00046 
00047   std::string projectStateToString(unsigned int state)
00048   {
00049     if (state == projection_state::success) {
00050       return "success";
00051     }
00052     else if (state == projection_state::no_pointcloud) {
00053       return "no pointcloud";
00054     }
00055     else if (state == projection_state::no_enough_support) {
00056       return "no enough support";
00057     }
00058     else if (state == projection_state::no_plane) {
00059       return "no plane";
00060     }
00061     else if (state == projection_state::no_enough_inliers) {
00062       return "no enough inliers";
00063     }
00064     else if (state == projection_state::close_to_success) {
00065       return "close to success";
00066     }
00067     else {
00068       return "unknown error";
00069     }
00070   }
00071   
00072   jsk_footstep_msgs::Footstep::Ptr
00073   FootstepState::toROSMsg()
00074   {
00075     jsk_footstep_msgs::Footstep::Ptr ret(new jsk_footstep_msgs::Footstep);
00076     tf::poseEigenToMsg(pose_, ret->pose);
00077     ret->dimensions.x = dimensions_[0];
00078     ret->dimensions.y = dimensions_[1];
00079     ret->dimensions.z = dimensions_[2];
00080     ret->leg = leg_;
00081     return ret;
00082   }
00083 
00084   pcl::PointIndices::Ptr
00085   FootstepState::cropPointCloudExact(pcl::PointCloud<pcl::PointNormal>::Ptr cloud,
00086                                      pcl::PointIndices::Ptr near_indices)
00087   {
00088     // Project vertices into 2d
00089     Eigen::Vector3f z(0, 0, 1);
00090     Eigen::Vector3f a = pose_ * Eigen::Vector3f(dimensions_[0]/2, dimensions_[1]/2, 0);
00091     Eigen::Vector3f b = pose_ * Eigen::Vector3f(-dimensions_[0]/2, dimensions_[1]/2, 0);
00092     Eigen::Vector3f c = pose_ * Eigen::Vector3f(-dimensions_[0]/2, -dimensions_[1]/2, 0);
00093     Eigen::Vector3f d = pose_ * Eigen::Vector3f(dimensions_[0]/2, -dimensions_[1]/2, 0);
00094     Eigen::Vector3f a_2d = a + (- z.dot(a)) * z;
00095     Eigen::Vector3f b_2d = b + (- z.dot(b)) * z;
00096     Eigen::Vector3f c_2d = c + (- z.dot(c)) * z;
00097     Eigen::Vector3f d_2d = d + (- z.dot(d)) * z;
00098 
00099     Eigen::Vector2f a2d(a_2d[0], a_2d[1]);
00100     Eigen::Vector2f b2d(b_2d[0], b_2d[1]);
00101     Eigen::Vector2f c2d(c_2d[0], c_2d[1]);
00102     Eigen::Vector2f d2d(d_2d[0], d_2d[1]);
00103     //std::set<int> set_indices;
00104     pcl::PointIndices::Ptr ret(new pcl::PointIndices);
00105     ret->indices.reserve(near_indices->indices.size());
00106     const std::vector<int> near_indices_indices = near_indices->indices;
00107     for (size_t i = 0; i < near_indices->indices.size(); i++) {
00108       const int index = near_indices_indices[i];
00109       const pcl::PointNormal point = cloud->points[index];
00110       const Eigen::Vector3f ep = point.getVector3fMap();
00111       const Eigen::Vector3f point_2d = ep + (-z.dot(ep)) * z;
00112       const Eigen::Vector2f p2d(point_2d[0], point_2d[1]);
00113       if (cross2d((b2d - a2d), (p2d - a2d)) > 0 &&
00114           cross2d((c2d - b2d), (p2d - b2d)) > 0 &&
00115           cross2d((d2d - c2d), (p2d - c2d)) > 0 &&
00116           cross2d((a2d - d2d), (p2d - d2d)) > 0) {
00117         //set_indices.insert(index);
00118         ret->indices.push_back(index);
00119       }
00120     }
00121 
00122     //ret->indices = std::vector<int>(set_indices.begin(), set_indices.end());
00123     return ret;
00124   }
00125   
00126   pcl::PointIndices::Ptr
00127   FootstepState::cropPointCloud(pcl::PointCloud<pcl::PointNormal>::Ptr cloud,
00128                                 ANNGrid::Ptr grid_search)
00129   {
00130     pcl::PointIndices::Ptr near_indices(new pcl::PointIndices);
00131     Eigen::Vector3f a = pose_ * Eigen::Vector3f(dimensions_[0]/2, dimensions_[1]/2, 0);
00132     Eigen::Vector3f b = pose_ * Eigen::Vector3f(-dimensions_[0]/2, dimensions_[1]/2, 0);
00133     Eigen::Vector3f c = pose_ * Eigen::Vector3f(-dimensions_[0]/2, -dimensions_[1]/2, 0);
00134     Eigen::Vector3f d = pose_ * Eigen::Vector3f(dimensions_[0]/2, -dimensions_[1]/2, 0);
00135     grid_search->approximateSearchInBox(a, b, c, d, *near_indices);
00136     return cropPointCloudExact(cloud, near_indices);
00137   }
00138   
00139   pcl::PointIndices::Ptr
00140   FootstepState::cropPointCloud(pcl::PointCloud<pcl::PointNormal>::Ptr cloud,
00141                                 pcl::search::Octree<pcl::PointNormal>& tree)
00142   {
00143     pcl::PointNormal center;
00144     center.getVector3fMap() = Eigen::Vector3f(pose_.translation());
00145     center.z = 0.0;
00146     float r = 0.2;
00147     pcl::PointIndices::Ptr near_indices(new pcl::PointIndices);
00148     std::vector<float> distances;
00149     tree.radiusSearch(center, r, near_indices->indices, distances);
00150     return cropPointCloudExact(cloud, near_indices);
00151   }
00152 
00153   bool FootstepState::crossCheck(FootstepState::Ptr other)
00154   {
00155     Eigen::Vector3f a0, a1, a2, a3;
00156     Eigen::Vector3f b0, b1, b2, b3;
00157     vertices(a0, a1, a2, a3);
00158     other->vertices(b0, b1, b2, b3);
00159     Line2D a_01(a0, a1), a_12(a1, a2), a_23(a2, a3), a_30(a3, a0);
00160     Line2D b_01(b0, b1), b_12(b1, b2), b_23(b2, b3), b_30(b3, b0);
00161     return !(a_01.isCrossing(b_01) ||
00162              a_01.isCrossing(b_12) ||
00163              a_01.isCrossing(b_23) ||
00164              a_01.isCrossing(b_30) ||
00165              a_12.isCrossing(b_01) ||
00166              a_12.isCrossing(b_12) ||
00167              a_12.isCrossing(b_23) ||
00168              a_12.isCrossing(b_30) ||
00169              a_23.isCrossing(b_01) ||
00170              a_23.isCrossing(b_12) ||
00171              a_23.isCrossing(b_23) ||
00172              a_23.isCrossing(b_30) ||
00173              a_30.isCrossing(b_01) ||
00174              a_30.isCrossing(b_12) ||
00175              a_30.isCrossing(b_23) ||
00176              a_30.isCrossing(b_30));
00177   }
00178   
00179   FootstepState::Ptr
00180   FootstepState::projectToCloud(pcl::KdTreeFLANN<pcl::PointNormal>& tree,
00181                                 pcl::PointCloud<pcl::PointNormal>::Ptr cloud,
00182                                 ANNGrid::Ptr grid_search,
00183                                 pcl::search::Octree<pcl::PointNormal>& tree_2d,
00184                                 pcl::PointCloud<pcl::PointNormal>::Ptr cloud_2d,
00185                                 const Eigen::Vector3f& z,
00186                                 unsigned int& error_state,
00187                                 double outlier_threshold,
00188                                 int max_iterations,
00189                                 int min_inliers,
00190                                 int foot_x_sampling_num,
00191                                 int foot_y_sampling_num,
00192                                 double vertex_threshold,
00193                                 const bool skip_cropping)
00194   {
00195     // TODO: z is ignored
00196     // extract candidate points
00197     //pcl::PointIndices::Ptr indices = cropPointCloud(cloud_2d, tree_2d);
00198     // Before computing, check is it supported or not to omit recognition
00199     pcl::PointIndices::Ptr indices;
00200     FootstepSupportState presupport_state;
00201     if (skip_cropping) {
00202       presupport_state = isSupportedByPointCloudWithoutCropping(
00203         pose_, cloud, tree,
00204         indices, foot_x_sampling_num, foot_y_sampling_num, vertex_threshold);
00205     }
00206     indices = cropPointCloud(cloud, grid_search);
00207     if (indices->indices.size() < min_inliers) {
00208       error_state = projection_state::no_enough_inliers;
00209       return FootstepState::Ptr();
00210     }
00211 
00212     else {
00213       presupport_state = isSupportedByPointCloud(
00214         pose_, cloud, tree,
00215         indices, foot_x_sampling_num, foot_y_sampling_num, vertex_threshold);
00216     }
00217     if (presupport_state == projection_state::success) {
00218       return FootstepState::Ptr(new FootstepState(leg_, pose_, dimensions_,
00219                                                   resolution_,
00220                                                   index_x_,
00221                                                   index_y_,
00222                                                   index_yaw_));
00223     }
00224     // estimate plane with ransac
00225     pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
00226     pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
00227     pcl::SACSegmentation<pcl::PointNormal> seg;
00228     seg.setOptimizeCoefficients (true);
00229     seg.setRadiusLimits(0.3, std::numeric_limits<double>::max ());
00230     seg.setMethodType(pcl::SAC_RANSAC);
00231     seg.setDistanceThreshold(outlier_threshold);
00232     seg.setModelType(pcl::SACMODEL_PLANE);
00233     seg.setInputCloud(cloud);
00234     seg.setIndices(indices);
00235     seg.setMaxIterations(max_iterations);
00236     seg.segment (*inliers, *coefficients);
00237     if (inliers->indices.size() == 0) {
00238       error_state = projection_state::no_plane;
00239       return FootstepState::Ptr();
00240     }
00241     else if (inliers->indices.size() < min_inliers) {
00242       error_state = projection_state::no_enough_inliers;
00243       return FootstepState::Ptr();
00244     }
00245     else {
00246       jsk_recognition_utils::Plane plane(coefficients->values);
00247       if (!plane.isSameDirection(z)) {
00248         plane = plane.flip();
00249       }
00250       Eigen::Vector3f n = plane.getNormal();
00251       Eigen::Vector3f x = pose_.matrix().block<3, 3>(0, 0) * Eigen::Vector3f::UnitX();
00252       if (acos(n.dot(x)) == 0) {
00253         error_state = projection_state::vertical_footstep;
00254         return FootstepState::Ptr();
00255       }
00256       Eigen::Vector3f rotation_axis = n.cross(x);
00257       Eigen::Vector3f new_x = Eigen::AngleAxisf(M_PI / 2.0, rotation_axis) * n;
00258       if (acos(new_x.dot(x)) > M_PI / 2.0) {
00259         new_x = - new_x;
00260       }
00261       Eigen::Vector3f new_y = n.cross(new_x);
00262       Eigen::Matrix3f new_rot_mat;
00263       new_rot_mat << new_x, new_y, n;
00264       Eigen::Quaternionf new_rot(new_rot_mat);
00265       Eigen::Vector3f p(pose_.translation());
00266       double alpha = (- plane.getD() - n.dot(p)) / (n.dot(z));
00267       Eigen::Vector3f q = p + alpha * z;
00268       Eigen::Affine3f new_pose = Eigen::Translation3f(q) * new_rot;
00269       // check is it enough points to support the footstep
00270       FootstepSupportState support_state;
00271       if (skip_cropping) {
00272         support_state = isSupportedByPointCloudWithoutCropping(
00273           new_pose, cloud, tree,
00274           inliers, foot_x_sampling_num, foot_y_sampling_num, vertex_threshold);
00275       }
00276       else {
00277         support_state = isSupportedByPointCloud(
00278           new_pose, cloud, tree,
00279           inliers, foot_x_sampling_num, foot_y_sampling_num, vertex_threshold);
00280       }
00281       if (support_state == NOT_SUPPORTED) {
00282         error_state = projection_state::no_enough_support;
00283         return FootstepState::Ptr();
00284       }
00285       else if (support_state == CLOSE_TO_SUPPORTED) {
00286         error_state = projection_state::close_to_success;
00287         return FootstepState::Ptr();
00288       }
00289       else {
00290         error_state = projection_state::success;
00291         return FootstepState::Ptr(new FootstepState(leg_, new_pose, dimensions_,
00292                                                     resolution_,
00293                                                     index_x_,
00294                                                     index_y_,
00295                                                     index_yaw_));
00296       }
00297     }
00298   }
00299   
00300   FootstepSupportState
00301   FootstepState::isSupportedByPointCloud(const Eigen::Affine3f& pose,
00302                                          pcl::PointCloud<pcl::PointNormal>::Ptr cloud,
00303                                          pcl::KdTreeFLANN<pcl::PointNormal>& tree,
00304                                          pcl::PointIndices::Ptr inliers,
00305                                          const int foot_x_sampling_num,
00306                                          const int foot_y_sampling_num,
00307                                          const double vertex_threshold)
00308   {
00309     const double dx = dimensions_[0] / foot_x_sampling_num;
00310     const double dy = dimensions_[1] / foot_y_sampling_num;
00311     // vertices
00312     const Eigen::Vector3f ux = Eigen::Vector3f::UnitX();
00313     const Eigen::Vector3f uy = Eigen::Vector3f::UnitY();
00314     const Eigen::Affine3f new_origin = pose *
00315       Eigen::Translation3f(- ux * dimensions_[0] / 2.0) *
00316       Eigen::Translation3f(- uy * dimensions_[1] / 2.0);
00317     const Eigen::Affine3f inv_pose = new_origin.inverse();
00318     
00319     bool occupiedp[foot_x_sampling_num][foot_y_sampling_num];
00320     // Initialize by false
00321     for (size_t i = 0; i < foot_x_sampling_num; i++) {
00322       for (size_t j = 0; j < foot_y_sampling_num; j++) {
00323         occupiedp[i][j] = false;
00324       }
00325     }
00326     
00327     for (size_t i = 0; i < inliers->indices.size(); i++) {
00328       pcl::PointNormal pp = cloud->points[inliers->indices[i]];
00329       const Eigen::Vector3f p = pp.getVector3fMap();
00330       const Eigen::Vector3f local_p = inv_pose * p;
00331       const int nx = floor(local_p[0] / dx);
00332       const int ny = floor(local_p[1] / dy);
00333       
00334       if (0 <= nx && nx < foot_x_sampling_num &&
00335           0 <= ny && ny < foot_y_sampling_num) {
00336         occupiedp[nx][ny] = true;
00337       }
00338     }
00339     for (size_t i = 0; i < foot_x_sampling_num; i++) {
00340       for (size_t j = 0; j < foot_y_sampling_num; j++) {
00341         if (!occupiedp[i][j]) {
00342           return NOT_SUPPORTED;
00343         }
00344       }
00345     }
00346 
00347     Eigen::Vector3f a((pose * Eigen::Translation3f(ux * dimensions_[0] / 2 + uy * dimensions_[1] / 2)).translation());
00348     Eigen::Vector3f b((pose * Eigen::Translation3f(- ux * dimensions_[0] / 2 + uy * dimensions_[1] / 2)).translation());
00349     Eigen::Vector3f c((pose * Eigen::Translation3f(- ux * dimensions_[0] / 2 - uy * dimensions_[1] / 2)).translation());
00350     Eigen::Vector3f d((pose * Eigen::Translation3f(ux * dimensions_[0] / 2 - uy * dimensions_[1] / 2)).translation());
00351     pcl::PointNormal pa, pb, pc, pd, p;
00352     pa.getVector3fMap() = a;
00353     pb.getVector3fMap() = b;
00354     pc.getVector3fMap() = c;
00355     pd.getVector3fMap() = d;
00356     p.getVector3fMap() = Eigen::Vector3f(pose.translation());
00357     std::vector<int> kdl_indices;
00358     std::vector<float> kdl_distances;
00359     if (tree.radiusSearch(p, vertex_threshold, kdl_indices, kdl_distances, 1) > 0 &&
00360         tree.radiusSearch(pa, vertex_threshold, kdl_indices, kdl_distances, 1) > 0 &&
00361         tree.radiusSearch(pb, vertex_threshold, kdl_indices, kdl_distances, 1) > 0 &&
00362         tree.radiusSearch(pc, vertex_threshold, kdl_indices, kdl_distances, 1) > 0 &&
00363         tree.radiusSearch(pd, vertex_threshold, kdl_indices, kdl_distances, 1) > 0) {
00364       return SUPPORTED;
00365     }
00366     else {
00367       return CLOSE_TO_SUPPORTED;
00368     }
00369   }
00370   
00371   FootstepSupportState
00372   FootstepState::isSupportedByPointCloudWithoutCropping(
00373     const Eigen::Affine3f& pose,
00374     pcl::PointCloud<pcl::PointNormal>::Ptr cloud,
00375     pcl::KdTreeFLANN<pcl::PointNormal>& tree,
00376     pcl::PointIndices::Ptr inliers,
00377     const int foot_x_sampling_num,
00378     const int foot_y_sampling_num,
00379     const double vertex_threshold)
00380   {
00381     const Eigen::Vector3f ux = Eigen::Vector3f::UnitX();
00382     const Eigen::Vector3f uy = Eigen::Vector3f::UnitY();
00383     Eigen::Vector3f a((pose * Eigen::Translation3f(ux * dimensions_[0] / 2 + uy * dimensions_[1] / 2)).translation());
00384     Eigen::Vector3f b((pose * Eigen::Translation3f(- ux * dimensions_[0] / 2 + uy * dimensions_[1] / 2)).translation());
00385     Eigen::Vector3f c((pose * Eigen::Translation3f(- ux * dimensions_[0] / 2 - uy * dimensions_[1] / 2)).translation());
00386     Eigen::Vector3f d((pose * Eigen::Translation3f(ux * dimensions_[0] / 2 - uy * dimensions_[1] / 2)).translation());
00387     pcl::PointNormal pa, pb, pc, pd, p;
00388     pa.getVector3fMap() = a;
00389     pb.getVector3fMap() = b;
00390     pc.getVector3fMap() = c;
00391     pd.getVector3fMap() = d;
00392     p.getVector3fMap() = Eigen::Vector3f(pose.translation());
00393     std::vector<int> kdl_indices;
00394     std::vector<float> kdl_distances;
00395     size_t success_count = 0;
00396     
00397     if (tree.radiusSearch(p, vertex_threshold, kdl_indices, kdl_distances, 1) > 0) {
00398       ++success_count;
00399     }
00400     if (tree.radiusSearch(pa, vertex_threshold, kdl_indices, kdl_distances, 1) > 0) {
00401       ++success_count;
00402     }
00403     if (tree.radiusSearch(pb, vertex_threshold, kdl_indices, kdl_distances, 1) > 0) {
00404       ++success_count;
00405     }
00406     if (tree.radiusSearch(pc, vertex_threshold, kdl_indices, kdl_distances, 1) > 0) {
00407       ++success_count;
00408     }
00409     if (tree.radiusSearch(pd, vertex_threshold, kdl_indices, kdl_distances, 1) > 0) {
00410       ++success_count;
00411     }
00412     if (success_count == 5) {
00413       return SUPPORTED;
00414     }
00415     else if (success_count > 0) {
00416       return CLOSE_TO_SUPPORTED;
00417     }
00418     else {
00419       return NOT_SUPPORTED;
00420     }
00421   }
00422   
00423 
00424   
00425   FootstepState::Ptr FootstepState::fromROSMsg(const jsk_footstep_msgs::Footstep& f,
00426                                                const Eigen::Vector3f& size,
00427                                                const Eigen::Vector3f& resolution)
00428   {
00429     Eigen::Affine3f pose;
00430     tf::poseMsgToEigen(f.pose, pose);
00431     return FootstepState::Ptr(new FootstepState(
00432                                 f.leg, pose,
00433                                 size, resolution));
00434   }
00435 
00436 }


jsk_footstep_planner
Author(s): Ryohei Ueda
autogenerated on Wed Sep 16 2015 04:37:56