From a22ddc4e135f24b76ed31dd591cdb16972ce9e02 Mon Sep 17 00:00:00 2001
From: t steve <pro@stevetonneau.fr>
Date: Fri, 12 May 2017 14:18:33 +0200
Subject: [PATCH] grasping

---
 .../centroidal_dynamics.hh                    |  14 +-
 include/centroidal-dynamics-lib/util.hh       |   4 +-
 python/centroidal_dynamics_python.cpp         |  27 +++-
 python/test/binding_tests.py                  |  25 +++
 src/centroidal_dynamics.cpp                   | 145 ++++++------------
 src/util.cpp                                  |  42 +++--
 6 files changed, 140 insertions(+), 117 deletions(-)

diff --git a/include/centroidal-dynamics-lib/centroidal_dynamics.hh b/include/centroidal-dynamics-lib/centroidal_dynamics.hh
index 997fd73..cbc5274 100644
--- a/include/centroidal-dynamics-lib/centroidal_dynamics.hh
+++ b/include/centroidal-dynamics-lib/centroidal_dynamics.hh
@@ -66,9 +66,9 @@ private:
   /** Coefficient used for converting the robustness measure in Newtons */
   double m_b0_to_emax_coefficient;
 
-  bool computePolytopeProjection(Cref_matrix6X v);
+  bool computePolytopeProjection(Cref_matrix6X v, const int graspIndex = -1);
   bool computeGenerators(Cref_matrixX3 contactPoints, Cref_matrixX3 contactNormals,
-                         double frictionCoefficient, const bool perturbate = false);
+                         double frictionCoefficient,  const int graspIndex, const double maxGraspForce, const bool perturbate = false);
 
   /**
    * @brief Given the smallest coefficient of the contact force generators it computes
@@ -130,10 +130,13 @@ public:
    * @param contactNormals List of N 3d contact normal directions as an Nx3 matrix.
    * @param frictionCoefficient The contact friction coefficient.
    * @param alg Algorithm to use for testing equilibrium.
+   * @param graspIndex if different than -1, specify starting where the contact points are grasping points
+   * WARNING graspIndexOnly works for PP algorithm
+   * @param maxGraspForce maximum grasping force applicable at each contact point
    * @return True if the operation succeeded, false otherwise.
    */
   bool setNewContacts(const MatrixX3& contactPoints, const MatrixX3& contactNormals,
-                      const double frictionCoefficient, const EquilibriumAlgorithm alg);
+                      const double frictionCoefficient, const EquilibriumAlgorithm alg, const int graspIndex = -1, const double maxGraspForce = 50.);
 
   /**
    * @brief Specify a new set of contacts.
@@ -144,10 +147,13 @@ public:
    * @param contactNormals List of N 3d contact normal directions as an Nx3 matrix.
    * @param frictionCoefficient The contact friction coefficient.
    * @param alg Algorithm to use for testing equilibrium.
+   * @param graspIndex if different than -1, specify starting where the contact points are grasping points
+   * WARNING graspIndexOnly works for PP algorithm
+   * @param maxGraspForce maximum grasping force applicable at each contact point
    * @return True if the operation succeeded, false otherwise.
    */
   bool setNewContacts(const MatrixX3ColMajor& contactPoints, const MatrixX3ColMajor&  contactNormals,
-                      const double frictionCoefficient, const EquilibriumAlgorithm alg);
+                      const double frictionCoefficient, const EquilibriumAlgorithm alg, const int graspIndex = -1, const double maxGraspForce = 50.);
 
   void setG(Cref_matrix6X G){m_G_centr = G;}
 
diff --git a/include/centroidal-dynamics-lib/util.hh b/include/centroidal-dynamics-lib/util.hh
index 66e2231..1c7ba0d 100644
--- a/include/centroidal-dynamics-lib/util.hh
+++ b/include/centroidal-dynamics-lib/util.hh
@@ -115,7 +115,7 @@ namespace centroidal_dynamics
  * @return The mX(n+1) output cdd matrix, which contains an additional column,
  * the first one, with all zeros.
  */
-  dd_MatrixPtr cone_span_eigen_to_cdd(Cref_matrixXX input, const bool canonicalize=false);
+  dd_MatrixPtr cone_span_eigen_to_cdd(Cref_matrixXX input, const bool canonicalize=false, const int graspIndex = -1);
 
   /**
  * Compute the cross-product skew-symmetric matrix associated to the specified vector.
@@ -191,8 +191,6 @@ namespace centroidal_dynamics
         int running_i  = 0;
         int running_j = 0;
         Matrix<typename DerivedU::Scalar,1,Dynamic> running(1,k);
-       /* const std::function<void(int,int)> doCombs =
-        [&running,&N,&doCombs,&running_i,&running_j,&U,&V](int offset, int k)*/;
         doCombs(running, running_i, running_j, U, V,0,k);
     }
 } //namespace centroidal_dynamics
diff --git a/python/centroidal_dynamics_python.cpp b/python/centroidal_dynamics_python.cpp
index 82f1b37..60256c8 100644
--- a/python/centroidal_dynamics_python.cpp
+++ b/python/centroidal_dynamics_python.cpp
@@ -26,6 +26,25 @@ boost::python::tuple wrapComputeEquilibriumRobustness(Equilibrium& self, const V
     return boost::python::make_tuple(status, robustness);
 }
 
+boost::python::tuple wrapCheckRobustEquilibrium(Equilibrium& self, const Vector3& com)
+{
+    bool robustness;
+    LP_status status = self.checkRobustEquilibrium(com, robustness);
+    return boost::python::make_tuple(status, robustness);
+}
+
+bool wrapSetNewContacts(Equilibrium& self, const MatrixX3ColMajor& contactPoints, const MatrixX3ColMajor&  contactNormals,
+                        const double frictionCoefficient, const EquilibriumAlgorithm alg)
+{
+    return self.setNewContacts(contactPoints, contactNormals, frictionCoefficient, alg);
+}
+
+bool wrapSetNewContactsFull(Equilibrium& self, const MatrixX3ColMajor& contactPoints, const MatrixX3ColMajor&  contactNormals,
+                      const double frictionCoefficient, const EquilibriumAlgorithm alg, const int graspIndex, const double maxGraspForce)
+{
+    return self.setNewContacts(contactPoints, contactNormals, frictionCoefficient, alg, graspIndex, maxGraspForce);
+}
+
 boost::python::tuple wrapGetPolytopeInequalities(Equilibrium& self)
 {
     MatrixXX H;
@@ -86,17 +105,19 @@ BOOST_PYTHON_MODULE(centroidal_dynamics)
 
     /** END enum types **/
 
-    bool (Equilibrium::*setNewContacts)
-            (const MatrixX3ColMajor&, const MatrixX3ColMajor&, const double, const EquilibriumAlgorithm) = &Equilibrium::setNewContacts;
+    //bool (Equilibrium::*setNewContacts)
+    //        (const MatrixX3ColMajor&, const MatrixX3ColMajor&, const double, const EquilibriumAlgorithm, const int graspIndex, const double maxGraspForce) = &Equilibrium::setNewContacts;
 
     class_<Equilibrium>("Equilibrium", init<std::string, double, unsigned int, optional <SolverLP, bool, const unsigned int, const bool> >())
             .def("useWarmStart", &Equilibrium::useWarmStart)
             .def("setUseWarmStart", &Equilibrium::setUseWarmStart)
             .def("getName", &Equilibrium::getName)
             .def("getAlgorithm", &Equilibrium::getAlgorithm)
-            .def("setNewContacts", setNewContacts)
+            .def("setNewContacts", wrapSetNewContacts)
+            .def("setNewContacts", wrapSetNewContactsFull)
             .def("computeEquilibriumRobustness", wrapComputeQuasiEquilibriumRobustness)
             .def("computeEquilibriumRobustness", wrapComputeEquilibriumRobustness)
+            .def("checkRobustEquilibrium", wrapCheckRobustEquilibrium)
             .def("getPolytopeInequalities", wrapGetPolytopeInequalities)
     ;
 }
diff --git a/python/test/binding_tests.py b/python/test/binding_tests.py
index 14db32b..1de874d 100644
--- a/python/test/binding_tests.py
+++ b/python/test/binding_tests.py
@@ -45,3 +45,28 @@ assert (robustness < 0), "first test should NOT be in equilibrirum"
 eq.setNewContacts(asmatrix(P),asmatrix(N),0.3,EquilibriumAlgorithm.EQUILIBRIUM_ALGORITHM_PP)
 H,h = eq.getPolytopeInequalities()
 
+
+#now, use polytope projection algorithm with grasping
+eq.setNewContacts(asmatrix(P),asmatrix(N),0.3,EquilibriumAlgorithm.EQUILIBRIUM_ALGORITHM_PP,4,50.)
+H,h = eq.getPolytopeInequalities()
+print P
+c= asmatrix(array([0.,0.,1.]))
+status, stable = eq.checkRobustEquilibrium(c)
+#~ assert (status == LP_STATUS_OPTIMAL), "checkRobustEquilibrium should not fail"
+#~ assert (stable), "lat test should be in equilibrirum"
+
+
+from numpy import array, vstack, zeros, sqrt, cross, matrix, asmatrix
+from numpy.linalg import norm
+import numpy as np
+
+def compute_w(c, ddc, dL=array([0.,0.,0.]), m = 54., g_vec=array([0.,0.,-9.81])):
+	w1 = m * (ddc - g_vec)
+	return array(w1.tolist() + (cross(c, w1) + dL).tolist())
+	
+
+def is_stable(H,c=array([0.,0.,1.]), ddc=array([0.,0.,0.]), dL=array([0.,0.,0.]), m = 54., g_vec=array([0.,0.,-9.81]), robustness = 0.):
+	w = compute_w(c, ddc, dL, m, g_vec)	
+	return (H.dot(-w)<=-robustness).all()
+    
+assert(is_stable(H))
diff --git a/src/centroidal_dynamics.cpp b/src/centroidal_dynamics.cpp
index c8b3b6b..4046c19 100644
--- a/src/centroidal_dynamics.cpp
+++ b/src/centroidal_dynamics.cpp
@@ -55,9 +55,13 @@ Equilibrium::Equilibrium(const string& name, const double mass, const unsigned i
 }
 
 bool Equilibrium::computeGenerators(Cref_matrixX3 contactPoints, Cref_matrixX3 contactNormals,
-                                          double frictionCoefficient, const bool perturbate)
+                                          double frictionCoefficient, const int graspIndex, const double maxGraspForce, const bool perturbate)
 {
-    long int c = contactPoints.rows();
+    if(graspIndex != -1)
+    {
+      assert(graspIndex < contactPoints.rows());
+    }
+    long int c = graspIndex > -1 ? graspIndex : 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);
@@ -118,6 +122,30 @@ bool Equilibrium::computeGenerators(Cref_matrixX3 contactPoints, Cref_matrixX3 c
       // project generators in 6d centroidal space
       m_G_centr.block(0,cg*i,6,cg) = A * G;
     }
+    if(graspIndex > -1)
+    {
+        Matrix3X cube(3, 8);
+        cube.col(0)= Vector3(-maxGraspForce,-maxGraspForce,-maxGraspForce);
+        cube.col(1)= Vector3( maxGraspForce,-maxGraspForce,-maxGraspForce);
+        cube.col(2)= Vector3( maxGraspForce, maxGraspForce,-maxGraspForce);
+        cube.col(3)= Vector3(-maxGraspForce, maxGraspForce,-maxGraspForce);
+        cube.col(4)= Vector3(-maxGraspForce,-maxGraspForce, maxGraspForce);
+        cube.col(5)= Vector3( maxGraspForce,-maxGraspForce, maxGraspForce);
+        cube.col(6)= Vector3( maxGraspForce, maxGraspForce, maxGraspForce);
+        cube.col(7)= Vector3(-maxGraspForce, maxGraspForce, maxGraspForce);
+        //first compute the cube constraining the grasping force.
+        for(long int i=graspIndex; i<contactPoints.rows(); i++)
+        {
+          // compute tangent directions
+          //N = contactNormals.row(i);
+          P = contactPoints.row(i);
+          // compute matrix mapping contact forces to gravito-inertial wrench
+          A.bottomRows<3>() = crossMatrix(-1.0*P);
+          // project generators in 6d centroidal space
+          m_G_centr.block(0,graspIndex*cg + 8*(i-graspIndex),6,8) = A * cube;
+        }
+    }
+
     // Compute the coefficient to convert b0 to e_max
     Vector3 f0 = Vector3::Zero();
     for(int j=0; j<cg; j++)
@@ -138,18 +166,22 @@ void Equilibrium::setAlgorithm(EquilibriumAlgorithm algorithm){
 }
 
 bool Equilibrium::setNewContacts(const MatrixX3ColMajor& contactPoints, const MatrixX3ColMajor& contactNormals,
-                                       const double frictionCoefficient, const EquilibriumAlgorithm alg)
+                                       const double frictionCoefficient, const EquilibriumAlgorithm alg, const int graspIndex, const double maxGraspForce)
 {
     MatrixX3 _contactPoints  = contactPoints;
     MatrixX3 _contactNormals = contactNormals;
-    return setNewContacts(_contactPoints,_contactNormals, frictionCoefficient, alg);
+    return setNewContacts(_contactPoints,_contactNormals, frictionCoefficient, alg, graspIndex, maxGraspForce);
 }
 
 bool Equilibrium::setNewContacts(const MatrixX3& contactPoints, const MatrixX3& contactNormals,
-                                 const double frictionCoefficient, const EquilibriumAlgorithm alg)
+                                 const double frictionCoefficient, const EquilibriumAlgorithm alg, const int graspIndex, const double maxGraspForce)
 {
   assert(contactPoints.rows()==contactNormals.rows());
-
+  if(alg!=EQUILIBRIUM_ALGORITHM_PP && graspIndex != -1)
+  {
+    SEND_ERROR_MSG("GRASPING not implemented yet expect for EQUILIBRIUM_ALGORITHM_PP");
+    return false;
+  }
   if(alg==EQUILIBRIUM_ALGORITHM_IP)
   {
     SEND_ERROR_MSG("Algorithm IP not implemented yet");
@@ -164,9 +196,12 @@ bool Equilibrium::setNewContacts(const MatrixX3& contactPoints, const MatrixX3&
   m_algorithm = alg;
 
   // Lists of contact generators (3 X generatorsPerContact)
-  m_G_centr.resize(6,contactPoints.rows()*m_generatorsPerContact);
+  if(graspIndex == -1)
+    m_G_centr.resize(6,contactPoints.rows()*m_generatorsPerContact);
+  else
+    m_G_centr.resize(6,graspIndex*m_generatorsPerContact+(contactPoints.rows()-graspIndex)*8);
 
-  if (!computeGenerators(contactPoints,contactNormals,frictionCoefficient,false))
+  if (!computeGenerators(contactPoints,contactNormals,frictionCoefficient, graspIndex, maxGraspForce,false))
   {
     return false;
   }
@@ -174,9 +209,9 @@ bool Equilibrium::setNewContacts(const MatrixX3& contactPoints, const MatrixX3&
   if(m_algorithm==EQUILIBRIUM_ALGORITHM_PP)
   {
     unsigned int attempts = max_num_cdd_trials;
-    while(!computePolytopeProjection(m_G_centr) && attempts>0)
+    while(!computePolytopeProjection(m_G_centr, graspIndex) && attempts>0)
     {
-      computeGenerators(contactPoints,contactNormals,frictionCoefficient,true);
+      computeGenerators(contactPoints,contactNormals,frictionCoefficient, graspIndex, maxGraspForce,true);
       attempts--;
     }
     // resetting random because obviously libcdd always resets to 0
@@ -521,55 +556,7 @@ LP_status Equilibrium::findExtremumInDirection(Cref_vector3 direction, Ref_vecto
   SEND_ERROR_MSG("findExtremumInDirection not implemented yet");
   return LP_STATUS_ERROR;
 }
-///
-/// \brief Computes factorial of a number
-///
-int fact(const int n)
-{
-    assert(n>=0);
-    int res = 1;
-    for (int i=2 ; i <= n ; ++i)
-       res *= i;
-    return res;
-}
-
-///
-/// \brief Computes a binomal coefficient
-///
-int choosenk(const int n, const int k)
-{
-    return fact(n) / (fact(k) * fact(n - k));
-}
-
-VectorX computeCombVector(const int order)
-{
-    VectorX res = VectorX::Zero(order);
-    for (int i = 0; i< order; ++i)
-        res[i] = i;
-    return res;
-}
-#include <algorithm>
-#include <set>
-#include <iterator>
-
-std::set<int> vec_to_set(Cref_vectorX A)
-{
-    std::set<int> res;
-    for(int i = 0; i < A.size(); ++i)
-        res.insert(A[i]);
-    return res;
-}
-
-//elements of A not in B
-std::set<int> setDiff(Cref_vectorX A, Cref_vectorX B)
-{
-    std::set<int> s1 = vec_to_set(A), s2 = vec_to_set(B);
-    // Fill in s1 and s2 with values
-    std::set<int> result;
-    std::set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(),
-        std::inserter(result, result.end()));
-}
-bool Equilibrium::computePolytopeProjection(Cref_matrix6X v)
+bool Equilibrium::computePolytopeProjection(Cref_matrix6X v, const int graspIndex)
 {
 
     // todo: for the moment using ad hoc upper bound = 500 N
@@ -580,41 +567,8 @@ bool Equilibrium::computePolytopeProjection(Cref_matrix6X v)
         SEND_ERROR_MSG("V has more lines that columns, this case is not handled!");
         return false;
     }
-    MatrixXX I;
-    VectorX comb = computeCombVector(m);
-    nchoosek(comb,n-1,I);
-    int nbcomb = I.rows();
-    int sizemat = (int)(2*nchoosek(m,n-1));
-    MatrixXX C = MatrixXX::Zero(sizemat,n);
-    VectorX d = VectorX::Zero(sizemat);
-    MatrixXX V = MatrixXX::Zero(n,m);
-    for(int i = 0; i< nbcomb; ++i)
-    {
-        const Eigen::Ref<VectorX>& chosen_comb = I.row(i);
-        for(int j = 0; j < chosen_comb.size(); ++j)
-            V.col(j) = v.col((int)(chosen_comb[j]));
-        Eigen::FullPivLU<MatrixXX> lu(V);
-        MatrixXX c = lu.kernel();
-        std::cout << "c " << c.cols() << std::endl;
-        std::cout << "V " << V.cols() << std::endl;
-        if(c.cols()==1) // The n-1 lines of V are lineraly independent
-        {
-            c.normalize();
-            C.row(2*i-1) = c;
-            C.row(2*i) = c;
-            std::set<int> J = setDiff(comb,chosen_comb);
-            std::set<int>::const_iterator setit = J.begin();
-            MatrixXX VV = MatrixXX::Zero(n,J.size());
-            for(int j = 0; j < chosen_comb.size(); ++j, ++setit)
-                VV.col(j) = v.col(*setit);
-            MatrixXX scalar=VV*c(0,0);
-            std::cout << "scalar " << scalar << std::endl;
-        }
-    }
-
-    //int I = I=nchoosek(1:m,n-1);*/
 //  getProfiler().start("eigen_to_cdd");
- /* dd_MatrixPtr V = cone_span_eigen_to_cdd(v.transpose(),canonicalize_cdd_matrix);
+    dd_MatrixPtr V = cone_span_eigen_to_cdd(v.transpose(),canonicalize_cdd_matrix,graspIndex);
 //  getProfiler().stop("eigen_to_cdd");
 
   dd_ErrorType error = dd_NoError;
@@ -665,7 +619,6 @@ bool Equilibrium::computePolytopeProjection(Cref_matrix6X v)
     m_h(rowsize + i) = -m_h((int)(*cit));
     m_H(rowsize + i) = -m_H((int)(*cit));
   }
-<<<<<<< HEAD
 //  getProfiler().stop("cdd to eigen");
   if(m_h.rows() < n )
     {
@@ -674,10 +627,6 @@ bool Equilibrium::computePolytopeProjection(Cref_matrix6X v)
         return false;
     }
 
-=======
-//  getProfiler().stop("cdd to eigen");*/
->>>>>>> ongoing
-
   return true;
 }
 
diff --git a/src/util.cpp b/src/util.cpp
index a0e1fcd..d714f87 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -12,7 +12,7 @@
 namespace centroidal_dynamics
 {
 
-dd_MatrixPtr cone_span_eigen_to_cdd(Cref_matrixXX input, const bool canonicalize)
+dd_MatrixPtr cone_span_eigen_to_cdd(Cref_matrixXX input, const bool canonicalize, const int graspIndex)
 {
   dd_debug = false;
   dd_MatrixPtr M=NULL;
@@ -28,17 +28,42 @@ dd_MatrixPtr cone_span_eigen_to_cdd(Cref_matrixXX input, const bool canonicalize
   M=dd_CreateMatrix(m_input, d_input);
   M->representation=rep;
   M->numbtype=NT;
-
-  for (i = 0; i < input.rows(); i++)
+  if(graspIndex > 0)
   {
-    dd_set_d(value, 0);
-    dd_set(M->matrix[i][0],value);
-    for (j = 1; j < d_input; j++)
+    for (i = 0; i < input.rows(); i++)
+    {
+        dd_set_d(value, 1);
+        dd_set(M->matrix[i][0],value);
+        for (j = graspIndex+1; j < d_input; j++)
+        {
+              dd_set_d(value, input(i,j-1));
+              dd_set(M->matrix[i][j],value);
+        }
+    }
+    for (i = 0; i < input.rows(); i++)
     {
-      dd_set_d(value, input(i,j-1));
-      dd_set(M->matrix[i][j],value);
+      dd_set_d(value, 0);
+      dd_set(M->matrix[i][0],value);
+      for (j = 1; j < graspIndex+1; j++)
+      {
+        dd_set_d(value, input(i,j-1));
+        dd_set(M->matrix[i][j],value);
+      }
     }
   }
+  else
+  {
+      for (i = 0; i < input.rows(); i++)
+      {
+        dd_set_d(value, 0);
+        dd_set(M->matrix[i][0],value);
+        for (j = 1; j < d_input; j++)
+        {
+          dd_set_d(value, input(i,j-1));
+          dd_set(M->matrix[i][j],value);
+        }
+      }
+  }
   dd_clear(value);
   if(canonicalize)
   {
@@ -50,7 +75,6 @@ dd_MatrixPtr cone_span_eigen_to_cdd(Cref_matrixXX input, const bool canonicalize
     set_free(impl_linset);
     free(newpos);
   }
-
   return M;
 }
 
-- 
GitLab