From 6c0d872530f5c24c81db5ca459b6a2c1f51ccb80 Mon Sep 17 00:00:00 2001 From: Steve Tonneau <stonneau@axle.laas.fr> Date: Tue, 9 Aug 2016 16:04:07 +0200 Subject: [PATCH] added perturbation method to recompute invalid matrix --- .../static_equilibrium.hh | 10 +- src/static_equilibrium.cpp | 146 +++++++++++------- 2 files changed, 101 insertions(+), 55 deletions(-) diff --git a/include/robust-equilibrium-lib/static_equilibrium.hh b/include/robust-equilibrium-lib/static_equilibrium.hh index 4ed0471..04c7629 100644 --- a/include/robust-equilibrium-lib/static_equilibrium.hh +++ b/include/robust-equilibrium-lib/static_equilibrium.hh @@ -46,6 +46,10 @@ private: VectorX m_h; /** False if a numerical instability appeared in the computation H and h*/ bool m_is_cdd_stable; + /** STATIC_EQUILIBRIUM_ALGORITHM_PP: If double description fails, + * indicate the max number of attempts to compute the cone by introducing + * a small pertubation of the system */ + const unsigned max_num_cdd_trials; /** Inequality matrix and vector defining the CoM support polygon HD com + Hd <= h */ MatrixX3 m_HD; @@ -59,6 +63,8 @@ private: double m_b0_to_emax_coefficient; bool computePolytopeProjection(Cref_matrix6X v); + bool computeGenerators(Cref_matrixX3 contactPoints, Cref_matrixX3 contactNormals, + double frictionCoefficient, const bool perturbate = false); /** * @brief Given the smallest coefficient of the contact force generators it computes @@ -81,9 +87,11 @@ public: * @param generatorsPerContact Number of generators used to approximate the friction cone per contact point. * @param solver_type Type of LP solver to use. * @param useWarmStart Whether the LP solver can warm start the resolution. + * @param max_num_cdd_trials indicate the max number of attempts to compute the cone by introducing + * a small pertubation of the system */ StaticEquilibrium(std::string name, double mass, unsigned int generatorsPerContact, - SolverLP solver_type, bool useWarmStart=true); + SolverLP solver_type, bool useWarmStart=true, const unsigned int max_num_cdd_trials=0); /** * @brief Returns the useWarmStart flag. diff --git a/src/static_equilibrium.cpp b/src/static_equilibrium.cpp index 35d6b40..635593b 100644 --- a/src/static_equilibrium.cpp +++ b/src/static_equilibrium.cpp @@ -18,13 +18,16 @@ namespace robust_equilibrium bool StaticEquilibrium::m_is_cdd_initialized = false; StaticEquilibrium::StaticEquilibrium(string name, double mass, unsigned int generatorsPerContact, - SolverLP solver_type, bool useWarmStart) + SolverLP solver_type, bool useWarmStart, + const unsigned int max_num_cdd_trials) : m_is_cdd_stable(true) + , max_num_cdd_trials(max_num_cdd_trials) { if(!m_is_cdd_initialized) { init_cdd_library(); m_is_cdd_initialized = true; + srand ( (unsigned int) (time(NULL)) ); } if(generatorsPerContact<3) @@ -49,6 +52,82 @@ StaticEquilibrium::StaticEquilibrium(string name, double mass, unsigned int gene m_D.block<3,3>(3,0) = crossMatrix(-m_mass*m_gravity); } +bool StaticEquilibrium::computeGenerators(Cref_matrixX3 contactPoints, Cref_matrixX3 contactNormals, + double frictionCoefficient, const bool perturbate) +{ + long int c = contactPoints.rows(); + unsigned int &cg = m_generatorsPerContact; + double theta, delta_theta=2*M_PI/cg; + const value_type pi_4 = value_type(M_PI_4); + // perturbation for libcdd + const value_type epsilon = 2*1e-3; + if(perturbate) + frictionCoefficient = frictionCoefficient +(rand()/ value_type(RAND_MAX))*epsilon; + // Tangent directions + Vector3 T1, T2, N; + // contact point + Vector3 P; + // Matrix mapping a 3d contact force to gravito-inertial wrench (6 X 3) + Matrix63 A; + A.topRows<3>() = -Matrix3::Identity(); + Matrix3X G(3, cg); + for(long int i=0; i<c; i++) + { + // check that contact normals have norm 1 + if(fabs(contactNormals.row(i).norm()-1.0)>1e-6) + { + SEND_ERROR_MSG("Contact normals should have norm 1, this has norm %f"+toString(contactNormals.row(i).norm())); + return false; + } + // compute tangent directions + N = contactNormals.row(i); + P = contactPoints.row(i); + if(perturbate) + { + for(int k =0; k<3; ++k) + { + N(k) +=(rand()/ value_type(RAND_MAX))*epsilon; + P(k) +=(rand()/ value_type(RAND_MAX))*epsilon; + } + N.normalize(); + } + T1 = N.cross(Vector3::UnitY()); + if(T1.norm()<1e-5) + T1 = N.cross(Vector3::UnitX()); + T2 = N.transpose().cross(T1); + T1.normalize(); + T2.normalize(); + + // compute matrix mapping contact forces to gravito-inertial wrench + A.bottomRows<3>() = crossMatrix(-1.0*P); + + // compute generators + theta = pi_4; + for(int j=0; j<cg; j++) + { + G.col(j) = frictionCoefficient*sin(theta)*T1 + + frictionCoefficient*cos(theta)*T2 + + contactNormals.row(i).transpose(); + G.col(j).normalize(); + // SEND_DEBUG_MSG("Contact "+toString(i)+" generator "+toString(j)+" = "+toString(G.col(j).transpose())); + theta += delta_theta; + } + + // project generators in 6d centroidal space + m_G_centr.block(0,cg*i,6,cg) = A * G; + } + // Compute the coefficient to convert b0 to e_max + Vector3 f0 = Vector3::Zero(); + for(int j=0; j<cg; j++) + f0 += G.col(j); // sum of the contact generators + // Compute the distance between the friction cone boundaries and + // the sum of the contact generators, which is e_max when b0=1. + // When b0!=1 we just multiply b0 times this value. + // This value depends only on the number of generators and the friction coefficient + m_b0_to_emax_coefficient = (f0.cross(G.col(0))).norm(); + return true; +} + bool StaticEquilibrium::setNewContacts(Cref_matrixX3 contactPoints, Cref_matrixX3 contactNormals, double frictionCoefficient, StaticEquilibriumAlgorithm alg) { @@ -67,67 +146,26 @@ bool StaticEquilibrium::setNewContacts(Cref_matrixX3 contactPoints, Cref_matrixX m_algorithm = alg; - long int c = contactPoints.rows(); - unsigned int &cg = m_generatorsPerContact; - double theta, delta_theta=2*M_PI/cg; - // Tangent directions - Vector3 T1, T2; - // Matrix mapping a 3d contact force to gravito-inertial wrench (6 X 3) - Matrix63 A; - A.topRows<3>() = -Matrix3::Identity(); // Lists of contact generators (3 X generatorsPerContact) - Matrix3X G(3, cg); - m_G_centr.resize(6,c*cg); + m_G_centr.resize(6,contactPoints.rows()*m_generatorsPerContact); - for(long int i=0; i<c; i++) + if (!computeGenerators(contactPoints,contactNormals,frictionCoefficient,false)) { - // check that contact normals have norm 1 - if(fabs(contactNormals.row(i).norm()-1.0)>1e-6) - { - SEND_ERROR_MSG("Contact normals should have norm 1, this has norm %f"+toString(contactNormals.row(i).norm())); - return false; - } - // compute tangent directions - T1 = contactNormals.row(i).cross(Vector3::UnitY()); - if(T1.norm()<1e-5) - T1 = contactNormals.row(i).cross(Vector3::UnitX()); - T2 = contactNormals.row(i).transpose().cross(T1); - T1.normalize(); - T2.normalize(); - - // compute matrix mapping contact forces to gravito-inertial wrench - A.bottomRows<3>() = crossMatrix(-1.0*contactPoints.row(i).transpose()); - - // compute generators - theta = acos(1/sqrt(2)); - for(int j=0; j<cg; j++) - { - G.col(j) = frictionCoefficient*sin(theta)*T1 - + frictionCoefficient*cos(theta)*T2 - + contactNormals.row(i).transpose(); - G.col(j).normalize(); -// SEND_DEBUG_MSG("Contact "+toString(i)+" generator "+toString(j)+" = "+toString(G.col(j).transpose())); - theta += delta_theta; - } - - // project generators in 6d centroidal space - m_G_centr.block(0,cg*i,6,cg) = A * G; + return false; } - // Compute the coefficient to convert b0 to e_max - Vector3 f0 = Vector3::Zero(); - for(int j=0; j<cg; j++) - f0 += G.col(j); // sum of the contact generators - // Compute the distance between the friction cone boundaries and - // the sum of the contact generators, which is e_max when b0=1. - // When b0!=1 we just multiply b0 times this value. - // This value depends only on the number of generators and the friction coefficient - m_b0_to_emax_coefficient = (f0.cross(G.col(0))).norm(); - if(m_algorithm==STATIC_EQUILIBRIUM_ALGORITHM_PP) { - if(!computePolytopeProjection(m_G_centr)) + unsigned int attempts = max_num_cdd_trials; + while(!computePolytopeProjection(m_G_centr) && attempts>0) + { + computeGenerators(contactPoints,contactNormals,frictionCoefficient,true); + attempts--; + } + if(!m_is_cdd_stable) + { return false; + } m_HD = m_H * m_D; m_Hd = m_H * m_d; } -- GitLab