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 "hrl_kinematics/TestStability.h"
00033 #include <pcl/surface/convex_hull.h>
00034 #include <pcl/point_types.h>
00035
00036 using robot_state_publisher::SegmentPair;
00037 using boost::shared_ptr;
00038
00039 namespace hrl_kinematics {
00040
00041 TestStability::TestStability(std::string rfoot_mesh_link_name,
00042 std::string root_link_name, std::string rfoot_link_name, std::string lfoot_link_name,
00043 const boost::shared_ptr<const urdf::ModelInterface>& urdf_model,
00044 double foot_polygon_scale)
00045 : Kinematics(root_link_name, rfoot_link_name, lfoot_link_name, urdf_model)
00046 , rfoot_mesh_link_name_(rfoot_mesh_link_name)
00047 {
00048
00049 initFootPolygon(foot_polygon_scale);
00050 }
00051
00052 TestStability::~TestStability() {
00053
00054 }
00055
00056 bool TestStability::isPoseStable(const std::map<std::string, double>& joint_positions, FootSupport support_mode){
00057 tf::Vector3 normal(0.0, 0.0, 1.0);
00058 return isPoseStable(joint_positions, support_mode, normal);
00059 }
00060
00061 bool TestStability::isPoseStable(const std::map<std::string, double>& joint_positions,
00062 FootSupport support_mode, const tf::Vector3& normal_vector)
00063 {
00064
00065 tf::Vector3 upright_vector(0.0, 0.0, 1.0);
00066 double angle = acos(upright_vector.dot(normal_vector.normalized()));
00067
00068 tf::Quaternion q;
00069 if (std::abs(angle) < FLT_EPSILON)
00070 q=tf::createIdentityQuaternion();
00071 else{
00072 tf::Vector3 axis = upright_vector.cross(normal_vector).normalized();
00073 q = tf::Quaternion(axis, angle);
00074 }
00075 tf::Transform rotate_plane(q, tf::Vector3(0,0,0));
00076
00077 tf::Point com;
00078 double m;
00079
00080
00081 tf::Transform tf_right_foot, tf_left_foot;
00082 computeCOM(joint_positions, com, m, tf_right_foot, tf_left_foot);
00083
00084 tf::Transform tf_to_support;
00085
00086 if (support_mode == SUPPORT_SINGLE_LEFT){
00087 support_polygon_ = foot_support_polygon_left_;
00088 tf_to_support_ = tf_left_foot;
00089 } else {
00090 support_polygon_ = foot_support_polygon_right_;
00091 tf_to_support_ = tf_right_foot;
00092
00093 }
00094
00095
00096 for (unsigned i = 0; i < support_polygon_.size(); ++i){
00097 support_polygon_[i] = rotate_plane * support_polygon_[i];
00098 }
00099
00100
00101 if (support_mode == SUPPORT_DOUBLE){
00102 tf::Transform tf_right_to_left = tf_right_foot.inverseTimes(tf_left_foot);
00103 for (unsigned i = 0; i < foot_support_polygon_left_.size(); ++i){
00104 support_polygon_.push_back(rotate_plane * tf_right_to_left * foot_support_polygon_left_[i]);
00105 }
00106 support_polygon_ = convexHull(support_polygon_);
00107 }
00108 if (support_polygon_.size() <= 2)
00109 return false;
00110
00111
00112 p_com_ = rotate_plane * tf_to_support_.inverse() * com;
00113 p_com_.setZ(0.0);
00114
00115 return pointInConvexHull(p_com_, support_polygon_);
00116 }
00117
00118 geometry_msgs::PolygonStamped TestStability::getSupportPolygon() const{
00119 geometry_msgs::PolygonStamped footprint_poly;
00120 footprint_poly.header.frame_id = root_link_name_;
00121 footprint_poly.header.stamp = ros::Time::now();
00122 for (unsigned i=0; i < support_polygon_.size(); ++i){
00123 geometry_msgs::Point32 p;
00124 tf::Point tfP = tf_to_support_ * support_polygon_[i];
00125 p.x = tfP.x();
00126 p.y = tfP.y();
00127 p.z = tfP.z();
00128 footprint_poly.polygon.points.push_back(p);
00129 }
00130
00131 return footprint_poly;
00132 }
00133
00134 visualization_msgs::Marker TestStability::getCOMMarker() const{
00135
00136 visualization_msgs::Marker com_marker;
00137 com_marker.header.stamp = ros::Time::now();
00138 com_marker.header.frame_id = root_link_name_;
00139 com_marker.action = visualization_msgs::Marker::ADD;
00140 com_marker.type = visualization_msgs::Marker::SPHERE;
00141 tf::pointTFToMsg(tf_to_support_ * p_com_, com_marker.pose.position);
00142 tf::quaternionTFToMsg(tf_to_support_.getRotation(), com_marker.pose.orientation);
00143 com_marker.scale.x = 0.03;
00144 com_marker.scale.y = 0.03;
00145 com_marker.scale.z = 0.005;
00146 com_marker.color.a = 1.0;
00147 com_marker.color.g = 1.0;
00148 com_marker.color.r = 0.0;
00149
00150
00151 return com_marker;
00152 }
00153
00154 std::vector<tf::Point> TestStability::convexHull(const std::vector<tf::Point>& points) const{
00155 std::vector<tf::Point> hull;
00156
00157 pcl::PointCloud<pcl::PointXYZ>::Ptr pcl_points(new pcl::PointCloud<pcl::PointXYZ>);
00158 pcl::PointCloud<pcl::PointXYZ> chull_points;
00159 pcl::ConvexHull<pcl::PointXYZ> chull;
00160
00161 if (points.empty()){
00162 ROS_ERROR("convexHull on empty set of points!");
00163 return hull;
00164 }
00165
00166 for (unsigned i = 0; i < points.size(); ++i){
00167 pcl_points->points.push_back(pcl::PointXYZ(points[i].x(), points[i].y(), 0.0));
00168 }
00169
00170 chull.setDimension(2);
00171 chull.setInputCloud(pcl_points);
00172 std::vector<pcl::Vertices> polygons;
00173 chull.reconstruct(chull_points, polygons);
00174
00175 if (polygons.size() == 0){
00176 ROS_ERROR("Convex hull polygons are empty");
00177 return hull;
00178 } else if (polygons.size() > 1){
00179 ROS_WARN("Convex hull polygons are larger than 1");
00180 }
00181
00182 for (unsigned i = 0; i < polygons[0].vertices.size(); ++i){
00183 int idx = polygons[0].vertices[i];
00184 tf::Point p(chull_points.points[idx].x,
00185 chull_points.points[idx].y,
00186 chull_points.points[idx].z);
00187 hull.push_back(p);
00188 }
00189
00190 return hull;
00191 }
00192
00193 bool TestStability::pointInConvexHull(const tf::Point& point, const std::vector<tf::Point>& polygon) const{
00194 assert(polygon.size() >=3);
00195 int positive_direction = 0;
00196 for (unsigned i = 0; i < polygon.size(); ++i){
00197 int i2 = (i+1)% (polygon.size());
00198 double dx = polygon[i2].getX() - polygon[i].getX();
00199 double dy = polygon[i2].getY() - polygon[i].getY();
00200 if (dx == 0.0 && dy == 0.0){
00201 ROS_DEBUG("Skipping polygon connection [%d-%d] (identical points)", i, i2);
00202 continue;
00203 }
00204 double line_test = (point.y() - polygon[i].getY())*dx - (point.x() - polygon[i].getX())*dy;
00205 if (i == 0)
00206 positive_direction = (line_test > 0.0);
00207 ROS_DEBUG("Line test [%d-%d] from (%f,%f) to (%f,%f): %f", i, i2, polygon[i].getX(), polygon[i].getY(),
00208 polygon[i2].getX(), polygon[i2].getY(), line_test);
00209 if ((line_test > 0.0) != positive_direction)
00210 return false;
00211
00212 }
00213
00214 return true;
00215 }
00216
00217 void TestStability::initFootPolygon(double foot_polygon_scale){
00218
00219
00220 foot_polygon_scale_ = foot_polygon_scale;
00221
00222
00223 if (!loadFootPolygon()){
00224 ROS_WARN("Could not load foot mesh, using default points");
00225
00226 foot_support_polygon_right_.push_back(tf::Point(0.07f, 0.023f, 0.0));
00227 foot_support_polygon_right_.push_back(tf::Point(0.07f, -0.03f, 0.0));
00228 foot_support_polygon_right_.push_back(tf::Point(-0.03f, -0.03f, 0.0));
00229 foot_support_polygon_right_.push_back(tf::Point(-0.03f, 0.02, 0.0));
00230 }
00231
00232
00233 foot_support_polygon_left_ = foot_support_polygon_right_;
00234 for (unsigned i=0; i < foot_support_polygon_left_.size(); ++i){
00235 foot_support_polygon_left_[i] *= tf::Point(1.0, -1.0, 1.0);
00236 }
00237
00238
00239 foot_support_polygon_left_ = convexHull(foot_support_polygon_left_);
00240 }
00241
00242
00243 bool TestStability::loadFootPolygon(){
00244 boost::shared_ptr<const urdf::Link> foot_link = urdf_model_->getLink(rfoot_mesh_link_name_);
00245 assert(foot_link);
00246 boost::shared_ptr<const urdf::Geometry> geom;
00247 urdf::Pose geom_pose;
00248 if (foot_link->collision && foot_link->collision->geometry){
00249 geom = foot_link->collision->geometry;
00250 geom_pose = foot_link->collision->origin;
00251 } else if (foot_link->visual && foot_link->visual->geometry){
00252 geom = foot_link->visual->geometry;
00253 geom_pose = foot_link->visual->origin;
00254 } else{
00255 ROS_ERROR_STREAM("No geometry for link "<< rfoot_mesh_link_name_ << " available");
00256 return false;
00257 }
00258
00259 tf::Pose geom_origin = tf::Pose(tf::Transform(tf::Quaternion(geom_pose.rotation.x, geom_pose.rotation.y, geom_pose.rotation.z, geom_pose.rotation.w),
00260 tf::Vector3(geom_pose.position.x, geom_pose.position.y, geom_pose.position.z)));
00261
00262 if (geom->type != urdf::Geometry::MESH){
00263 ROS_ERROR_STREAM("Geometry for link "<< rfoot_mesh_link_name_ << " is not a mesh");
00264 return false;
00265 } else {
00266 shared_ptr<const urdf::Mesh> mesh = boost::dynamic_pointer_cast<const urdf::Mesh>(geom);
00267
00268 const Eigen::Vector3d scale(mesh->scale.x, mesh->scale.y, mesh->scale.z);
00269 shapes::Mesh* shape_mesh = shapes::createMeshFromResource(mesh->filename, scale);
00270 size_t vertex_count = shape_mesh->vertex_count;
00271
00272
00273 std::vector<tf::Point> foot_SP_right;
00274 for (unsigned int i = 0 ; i < vertex_count ; ++i)
00275 {
00276 unsigned int i3 = i * 3;
00277
00278 tf::Point p(shape_mesh->vertices[i3], shape_mesh->vertices[i3 + 1], shape_mesh->vertices[i3 + 2]);
00279 tf::Point projectedP = geom_origin*p;
00280 projectedP.setZ(0.0);
00281
00282
00283 foot_SP_right.push_back(projectedP);
00284 }
00285
00286
00287 float sum_x_coord = 0.0;
00288 float sum_y_coord = 0.0;
00289 tf::Point r_foot_center;
00290 for (unsigned int i = 0 ; i < foot_SP_right.size(); ++i)
00291 {
00292 sum_x_coord = sum_x_coord + foot_SP_right[i].x();
00293 sum_y_coord = sum_y_coord + foot_SP_right[i].y();
00294 }
00295
00296 r_foot_center.setX(sum_x_coord/foot_SP_right.size());
00297 r_foot_center.setY(sum_y_coord/foot_SP_right.size());
00298
00299
00300 std::vector<tf::Point> foot_SP_right_center;
00301 tf::Point foot_point;
00302 for (unsigned int i = 0 ; i < foot_SP_right.size(); ++i){
00303
00304 foot_point.setX( (foot_SP_right[i].x() - r_foot_center.x()) * foot_polygon_scale_ );
00305 foot_point.setY( (foot_SP_right[i].y() - r_foot_center.y()) * foot_polygon_scale_ );
00306 foot_SP_right_center.push_back(foot_point);
00307 }
00308
00309
00310 std::vector<tf::Point> scaled_SP_right;
00311 for (unsigned int i = 0 ; i < foot_SP_right_center.size() ; ++i){
00312
00313 foot_point.setX( foot_SP_right_center[i].x() + r_foot_center.x() ) ;
00314 foot_point.setY( foot_SP_right_center[i].y() + r_foot_center.y() ) ;
00315 scaled_SP_right.push_back(foot_point);
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 foot_support_polygon_right_ = convexHull(scaled_SP_right);
00327
00328 }
00329
00330 ROS_DEBUG("Foot polygon loaded with %zu points", foot_support_polygon_right_.size());
00331
00332 return true;
00333
00334 }
00335
00336
00337
00338 void TestStability::scaleConvexHull(double scaling_factor)
00339 {
00340
00341 initFootPolygon(scaling_factor);
00342 }
00343
00344
00345
00346 }