From c0d85d5c688c30221871af24c3b31ac7c33eaaa0 Mon Sep 17 00:00:00 2001
From: thomascbrs <thomas.corberes@laposte.net>
Date: Mon, 25 Oct 2021 13:59:46 +0100
Subject: [PATCH] Estimation of the feet by FK in Bezier planner, in cpp,
 removed from controller

---
 include/qrw/FootTrajectoryGeneratorBezier.hpp | 36 +++++++--
 scripts/Controller.py                         | 81 ++-----------------
 src/FootTrajectoryGeneratorBezier.cpp         | 46 ++++++++++-
 3 files changed, 81 insertions(+), 82 deletions(-)

diff --git a/include/qrw/FootTrajectoryGeneratorBezier.hpp b/include/qrw/FootTrajectoryGeneratorBezier.hpp
index ad5b1a9b..aa9a8781 100644
--- a/include/qrw/FootTrajectoryGeneratorBezier.hpp
+++ b/include/qrw/FootTrajectoryGeneratorBezier.hpp
@@ -15,6 +15,13 @@
 #include "qrw/Types.h"
 #include "qrw/Params.hpp"
 
+#include "pinocchio/math/rpy.hpp"
+#include "pinocchio/multibody/model.hpp"
+#include "pinocchio/multibody/data.hpp"
+#include "pinocchio/parsers/urdf.hpp"
+#include "pinocchio/algorithm/compute-all-terms.hpp"
+#include "pinocchio/algorithm/frames.hpp"
+
 #include "ndcurves/fwd.h"
 #include "ndcurves/bezier_curve.h"
 #include "ndcurves/optimization/details.h"
@@ -60,8 +67,9 @@ class FootTrajectoryGeneratorBezier {
   ///
   /// \brief updates the nex foot position, velocity and acceleration, and the foot goal position
   ///
-  /// \param[in] j foot id
-  /// \param[in] targetFootstep desired target location at the end of the swing phase
+  /// \param[in] k (int): number of time steps since the start of the simulation
+  /// \param[in] j (int): index of the foot
+  /// \param[in] targetFootstep (Vector3): desired target location at the end of the swing phase
   ///
   ////////////////////////////////////////////////////////////////////////////////////////////////
   void updateFootPosition(int const& k, int const& i_foot, Vector3 const& targetFootstep);
@@ -72,10 +80,21 @@ class FootTrajectoryGeneratorBezier {
   ///        to the desired position on the ground (computed by the footstep planner)
   ///
   /// \param[in] k (int): number of time steps since the start of the simulation
+  /// \param[in] surfacesSelected (SurfaceVector): Vector of contact surfaces for each foot
+  /// \param[in] targetFootstep (Matrix34): desired target location at the end of the swing phase
+  /// \param[in] q (Vector18): State of the robot, (RPY formulation, size 18)
+  ///
+  ////////////////////////////////////////////////////////////////////////////////////////////////
+  void update(int k, MatrixN const& targetFootstep, SurfaceVector const& surfacesSelected, VectorN const& q);
+
+  ////////////////////////////////////////////////////////////////////////////////////////////////
+  ///
+  /// \brief Update the 3D position of the feet in world frame by forward kinematic, matrix position_FK_
+  ///
+  /// \param[in] q (Vector18): State of the robot, (RPY formulation, size 18)
   ///
   ////////////////////////////////////////////////////////////////////////////////////////////////
-  void update(int k, MatrixN const& targetFootstep, SurfaceVector const& surfacesSelected,
-              MatrixN const& currentPosition);
+  void update_position_FK(VectorN const& q);
 
   void updatePolyCoeff_XY(int const& i_foot, Vector3 const& x_init, Vector3 const& v_init, Vector3 const& a_init,
                           Vector3 const& x_target, double const& t0, double const& t1);
@@ -120,6 +139,7 @@ class FootTrajectoryGeneratorBezier {
   Matrix74 Az;  ///< Coefficients for the Z component
 
   Matrix34 position_;      // position computed in updateFootPosition
+  Matrix34 position_FK_;   // position computed by Forward dynamics
   Matrix34 velocity_;      // velocity computed in updateFootPosition
   Matrix34 acceleration_;  // acceleration computed in updateFootPosition
   Matrix34 jerk_;          // Jerk computed in updateFootPosition
@@ -176,9 +196,15 @@ class FootTrajectoryGeneratorBezier {
   // QP solver
   EiquadprogFast_status expected = EIQUADPROG_FAST_OPTIMAL;
   EiquadprogFast_status status;
-
   EiquadprogFast qp;
 
+  // Pinocchio model for foot estimation
+  pinocchio::Model model_;          // Pinocchio model for forward kinematics
+  pinocchio::Data data_;            // Pinocchio datas for forward kinematics
+  int foot_ids_[4] = {0, 0, 0, 0};  // Indexes of feet frames
+  Matrix34 pos_feet_;               // Estimated feet positions based on measurements
+  Vector19 q_FK_;                   // Estimated state of the base (height, roll, pitch, joints)
+
   // Methods to compute intersection point
   bool doIntersect_segment(Vector2 const& p1, Vector2 const& q1, Vector2 const& p2, Vector2 const& q2);
   bool onSegment(Vector2 const& p, Vector2 const& q, Vector2 const& r);
diff --git a/scripts/Controller.py b/scripts/Controller.py
index fa207be2..64a2f07c 100644
--- a/scripts/Controller.py
+++ b/scripts/Controller.py
@@ -15,6 +15,8 @@ from solopython.utils.viewerClient import viewerClient, NonBlockingViewerFromRob
 import libquadruped_reactive_walking as lqrw
 from example_robot_data.robots_loader import Solo12Loader
 
+from solo3D.tools.utils import quaternionToRPY
+
 class Result:
     """Object to store the result of the control loop
     It contains what is sent to the robot (gains, desired positions and velocities,
@@ -143,8 +145,6 @@ class Controller:
         if params.solo3D:
             from solo3D.SurfacePlannerWrapper import SurfacePlanner_Wrapper
             from solo3D.tools.pyb_environment_3D import PybEnvironment3D
-            from solo3D.tools.utils import quaternionToRPY
-            from example_robot_data import load
 
         self.enable_multiprocessing_mip = params.enable_multiprocessing_mip
         self.offset_perfect_estimator = 0.
@@ -168,12 +168,6 @@ class Controller:
             N_sample_ineq = 10  # Number of sample while browsing the curve
             degree = 7  # Degree of the Bezier curve
 
-            # pinocchio model and data, CoM and Inertia estimation for MPC
-            robot = load('solo12')
-            self.data = robot.data.copy()  # for velocity estimation (forward kinematics)
-            self.model = robot.model.copy()  # for velocity estimation (forward kinematics)
-            self.q_neutral = pin.neutral(self.model).reshape((19, 1))  # column vector
-
             self.footTrajectoryGenerator = lqrw.FootTrajectoryGeneratorBezier()
             self.footTrajectoryGenerator.initialize(params, self.gait, self.surfacePlanner.floor_surface,
                                                     x_margin_max_, t_margin_, z_margin_, N_sample, N_sample_ineq,
@@ -453,10 +447,9 @@ class Controller:
                     self.o_targetFootstep[:2, foot] = self.x_f_mpc[24 + 2*foot:24+2*foot+2, id+1]
 
         # Update pos, vel and acc references for feet
-        if self.solo3D:  # Bezier curves, needs estimated position of the feet
-            currentPosition = self.computeFootPositionFeedback(self.k, device, self.q_filt_3d, self.v_filt_3d)
+        if self.solo3D:  # Bezier curves
             self.footTrajectoryGenerator.update(self.k, self.o_targetFootstep, self.surfacePlanner.selected_surfaces,
-                                                currentPosition)
+                                                self.q_filt_3d)
         else:
             self.footTrajectoryGenerator.update(self.k, self.o_targetFootstep)
         # Whole Body Control
@@ -523,7 +516,7 @@ class Controller:
                 self.h_ref += self.vref_filt_mpc[2, 0] * self.dt_wbc
                 self.h_ref = np.clip(self.h_ref, 0.19, 0.26)
                 self.xgoals[3:5, 0] = np.clip(self.xgoals[3:5, 0], [-0.25, -0.17], [0.25, 0.17])"""
-            
+
 
             self.xgoals[6:, 0] = self.vref_filt_mpc[:, 0]  # Velocities (in horizontal frame!)
 
@@ -576,7 +569,7 @@ class Controller:
 
         """if self.k == 1:
             quit()"""
-        
+
         """np.set_printoptions(precision=3, linewidth=300)
         print("---- ", self.k)
         print(self.x_f_mpc[12:24, 0])
@@ -727,65 +720,3 @@ class Controller:
         self.t_mpc = t_mpc - t_planner
         self.t_wbc = t_wbc - t_mpc
         self.t_loop = time.time() - tic
-
-    def computeFootPositionFeedback(self, k, device, q_filt, v_filt):
-        ''' Return the position of the foot using Pybullet feedback, Pybullet feedback with forward dynamics 
-        or Estimator feedback with forward dynamics
-        Args :
-        - k (int) : step indice
-        - q_filt (Arrayx18) : q estimated (only for estimator feedback)
-        - v_vilt (arrayx18) : v estimated (only for estimator feedback)
-        Returns :
-        - currentPosition (Array 3x4)
-        '''
-        currentPosition = np.zeros((3, 4))
-        q_filt_ = np.zeros((19, 1))
-        q_filt_[:3] = q_filt[:3]
-        q_filt_[3:7] = pin.Quaternion(pin.rpy.rpyToMatrix(q_filt[3:6, 0])).coeffs().reshape((4, 1))
-        q_filt_[7:] = q_filt[6:]
-
-        # Current position : Pybullet feedback, directly
-        ##########################
-
-        # linkId = [3, 7 ,11 ,15]
-        # if k != 0 :
-        #     links = pyb.getLinkStates(device.pyb_sim.robotId, linkId , computeForwardKinematics=True , computeLinkVelocity=True )
-
-        #     for j in range(4) :
-        #         self.goals[:,j] = np.array(links[j][4])[:]   # pos frame world for feet
-        #         self.goals[2,j] -= 0.016988                  #  Z offset due to position of frame in object
-        #         self.vgoals[:,j] = np.array(links[j][6])     # vel frame world for feet
-
-        # Current position : Pybullet feedback, with forward dynamics
-        ##########################
-
-        # if k > 0:    # Dummy device for k == 0
-        #     qmes = np.zeros((19, 1))
-        #     revoluteJointIndices = [0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14]
-        #     jointStates = pyb.getJointStates(device.pyb_sim.robotId, revoluteJointIndices)
-        #     baseState = pyb.getBasePositionAndOrientation(device.pyb_sim.robotId)
-        #     qmes[:3, 0] = baseState[0]
-        #     qmes[3:7, 0] = baseState[1]
-        #     qmes[7:, 0] = [state[0] for state in jointStates]
-        #     pin.forwardKinematics(self.model, self.data, qmes, v_filt)
-        # else:
-        #     pin.forwardKinematics(self.model, self.data, q_filt_, v_filt)
-
-        # Current position : Estimator feedback, with forward dynamics
-        ##########################
-
-        pin.forwardKinematics(self.model, self.data, q_filt_, v_filt)
-
-        contactFrameId = [10, 18, 26, 34]  # = [ FL , FR , HL , HR]
-
-        for j in range(4):
-            framePlacement = pin.updateFramePlacement(self.model, self.data,
-                                                      contactFrameId[j])  # = solo.data.oMf[18].translation
-            frameVelocity = pin.getFrameVelocity(self.model, self.data, contactFrameId[j], pin.ReferenceFrame.LOCAL)
-
-            currentPosition[:, j] = framePlacement.translation[:]
-            # if k > 0:
-            #     currentPosition[2, j] -= 0.016988                     # Pybullet offset on Z
-            # self.vgoals[:,j] = frameVelocity.linear       # velocity feedback not working
-
-        return currentPosition
diff --git a/src/FootTrajectoryGeneratorBezier.cpp b/src/FootTrajectoryGeneratorBezier.cpp
index 05c155a4..e9032d24 100644
--- a/src/FootTrajectoryGeneratorBezier.cpp
+++ b/src/FootTrajectoryGeneratorBezier.cpp
@@ -79,6 +79,27 @@ void FootTrajectoryGeneratorBezier::initialize(Params& params, Gait& gaitIn, Sur
   x_margin_max_ = x_margin_max_in;
   t_margin_ = t_margin_in;  // 1 % of the curve after critical point
   z_margin_ = z_margin_in;
+
+  // Path to the robot URDF (TODO: Automatic path)
+  const std::string filename =
+      std::string("/opt/openrobots/share/example-robot-data/robots/solo_description/robots/solo12.urdf");
+
+  // Build model from urdf (base is not free flyer)
+  pinocchio::urdf::buildModel(filename, pinocchio::JointModelFreeFlyer(), model_, false);
+
+  // Construct data from model
+  data_ = pinocchio::Data(model_);
+
+  // Update all the quantities of the model
+  VectorN q_tmp = VectorN::Zero(model_.nq);
+  q_tmp(6, 0) = 1.0;  // Quaternion (0, 0, 0, 1)
+  pinocchio::computeAllTerms(model_, data_, q_tmp, VectorN::Zero(model_.nv));
+
+  // Get feet frame IDs
+  foot_ids_[0] = static_cast<int>(model_.getFrameId("FL_FOOT"));  // from long uint to int
+  foot_ids_[1] = static_cast<int>(model_.getFrameId("FR_FOOT"));
+  foot_ids_[2] = static_cast<int>(model_.getFrameId("HL_FOOT"));
+  foot_ids_[3] = static_cast<int>(model_.getFrameId("HR_FOOT"));
 }
 
 void FootTrajectoryGeneratorBezier::updatePolyCoeff_XY(int const& i_foot, Vector3 const& x_init, Vector3 const& v_init,
@@ -488,7 +509,7 @@ void FootTrajectoryGeneratorBezier::updateFootPosition(int const& k, int const&
 }
 
 void FootTrajectoryGeneratorBezier::update(int k, MatrixN const& targetFootstep, SurfaceVector const& surfacesSelected,
-                                           MatrixN const& currentPosition) {
+                                           VectorN const& q) {
   if ((k % k_mpc) == 0) {
     // Indexes of feet in swing phase
     feet.clear();
@@ -525,13 +546,34 @@ void FootTrajectoryGeneratorBezier::update(int k, MatrixN const& targetFootstep,
     }
   }
 
+  // Update feet position using estimated state, by FK
+  update_position_FK(q);
+
+  // Update desired position, velocities and accelerations for flying feet
   for (int i = 0; i < (int)feet.size(); i++) {
-    position_.col(feet[i]) = currentPosition.col(feet[i]);
+    position_.col(feet[i]) = position_FK_.col(feet[i]);
     updateFootPosition(k, feet[i], targetFootstep.col(feet[i]));
   }
   return;
 }
 
+void FootTrajectoryGeneratorBezier::update_position_FK(VectorN const& q) {
+  // Get position of the feet in world frame, using estimated state q
+  q_FK_.head(3) = q.head(3);
+  q_FK_.block(3, 0, 4, 1) =
+      pinocchio::SE3::Quaternion(pinocchio::rpy::rpyToMatrix(q(3, 0), q(4, 0), q(5, 0))).coeffs();
+  q_FK_.tail(12) = q.tail(12);
+
+  // Update model and data of the robot
+  pinocchio::forwardKinematics(model_, data_, q_FK_);
+  pinocchio::updateFramePlacements(model_, data_);
+
+  // Get data required by IK with Pinocchio
+  for (int i = 0; i < 4; i++) {
+    position_FK_.col(i) = data_.oMf[foot_ids_[i]].translation();
+  }
+}
+
 bool FootTrajectoryGeneratorBezier::doIntersect_segment(Vector2 const& p1, Vector2 const& q1, Vector2 const& p2,
                                                         Vector2 const& q2) {
   //  Find the 4 orientations required for
-- 
GitLab