diff --git a/include/qrw/FootTrajectoryGenerator.hpp b/include/qrw/FootTrajectoryGenerator.hpp
index 21bb3db5be6fff60acfeff05b3b2eeab8d1064b5..536ef25a0e72fab96d1b0a0809f9fa6b30e9759b 100644
--- a/include/qrw/FootTrajectoryGenerator.hpp
+++ b/include/qrw/FootTrajectoryGenerator.hpp
@@ -63,6 +63,10 @@ public:
     ////////////////////////////////////////////////////////////////////////////////////////////////
     void update(int k, MatrixN const& targetFootstep);
 
+    Eigen::MatrixXd getFootPositionBaseFrame(const Eigen::Matrix<double, 3, 3> &R, const Eigen::Matrix<double, 3, 1> &T);
+    Eigen::MatrixXd getFootVelocityBaseFrame(const Eigen::Matrix<double, 3, 3> &R, const Eigen::Matrix<double, 3, 1> &v_ref, const Eigen::Matrix<double, 3, 1> &w_ref);
+    Eigen::MatrixXd getFootAccelerationBaseFrame(const Eigen::Matrix<double, 3, 3> &R, const Eigen::Matrix<double, 3, 1> &w_ref);
+
     MatrixN getTargetPosition() { return targetFootstep_; }  ///< Get the foot goal position
     MatrixN getFootPosition() { return position_; }          ///< Get the next foot position
     MatrixN getFootVelocity() { return velocity_; }          ///< Get the next foot velocity
@@ -70,10 +74,11 @@ public:
 
 private:
     Gait* gait_;        ///< Target lock before the touchdown
-    double dt_tsid;     ///<
+    double dt_wbc;      ///<
     int k_mpc;          ///<
     double maxHeight_;  ///< Apex height of the swinging trajectory
     double lockTime_;   ///< Target lock before the touchdown
+    double vertTime_;   ///< Duration during which feet move only along Z when taking off and landing
 
     std::vector<int> feet;
     Vector4 t0s;
@@ -87,5 +92,9 @@ private:
     Matrix34 position_;      // position computed in updateFootPosition
     Matrix34 velocity_;      // velocity computed in updateFootPosition
     Matrix34 acceleration_;  // acceleration computed in updateFootPosition
+
+    Matrix34 position_base_;      // position computed in updateFootPosition in base frame
+    Matrix34 velocity_base_;      // velocity computed in updateFootPosition in base frame
+    Matrix34 acceleration_base_;  // acceleration computed in updateFootPosition in base frame
 };
 #endif  // TRAJGEN_H_INCLUDED
diff --git a/include/qrw/Params.hpp b/include/qrw/Params.hpp
index b7ec78a09e9ee7eb0641c5c1c57bfffa7a83c338..f35667cd9bec05a4706be3db595d98540f926935 100644
--- a/include/qrw/Params.hpp
+++ b/include/qrw/Params.hpp
@@ -65,6 +65,7 @@ public:
 
     double max_height;
     double lock_time;
+    double vert_time;
 
     std::vector<double> osqp_w_states;
     std::vector<double> osqp_w_forces;
diff --git a/python/gepadd.cpp b/python/gepadd.cpp
index ae0478e9a8a7a1bd9a542fa8055c2acc67a861e0..018c537858a1bf0c1a82269d18ef43f89d0677ba 100644
--- a/python/gepadd.cpp
+++ b/python/gepadd.cpp
@@ -151,6 +151,13 @@ struct FootTrajectoryGeneratorPythonVisitor : public bp::def_visitor<FootTraject
     {
         cl.def(bp::init<>(bp::arg(""), "Default constructor."))
 
+            .def("getFootPositionBaseFrame", &FootTrajectoryGenerator::getFootPositionBaseFrame,
+                 bp::args("R", "T"), "Get position_ matrix in base frame.\n")
+            .def("getFootVelocityBaseFrame", &FootTrajectoryGenerator::getFootVelocityBaseFrame,
+                 bp::args("R", "v_ref", "w_ref"), "Get velocity_ matrix in base frame.\n")
+            .def("getFootAccelerationBaseFrame", &FootTrajectoryGenerator::getFootAccelerationBaseFrame,
+                 bp::args("R", "w_ref"), "Get acceleration_ matrix in base frame.\n")
+
             .def("getFootPosition", &FootTrajectoryGenerator::getFootPosition, "Get position_ matrix.\n")
             .def("getFootVelocity", &FootTrajectoryGenerator::getFootVelocity, "Get velocity_ matrix.\n")
             .def("getFootAcceleration", &FootTrajectoryGenerator::getFootAcceleration, "Get acceleration_ matrix.\n")
diff --git a/scripts/Controller.py b/scripts/Controller.py
index 15d2c0a3dc72f1ded19de04fa94fec12fbbe7ae1..0bc45948497b679cf0a5d08efb41e6256d654bee 100644
--- a/scripts/Controller.py
+++ b/scripts/Controller.py
@@ -293,18 +293,10 @@ class Controller:
             self.b_v[:6, 0] = self.v_ref[:6, 0]  # Base at reference velocity (TODO: add hRb once v_ref is considered in base frame)
             self.b_v[6:, 0] = self.myController.vdes[6:, 0]  # with reference angular velocities of previous loop
 
-            # Feet command acceleration in base frame
-            self.feet_a_cmd = oRh.transpose() @ self.footTrajectoryGenerator.getFootAcceleration() \
-                - self.cross12(self.v_ref[3:6, 0:1], self.cross12(self.v_ref[3:6, 0:1], self.feet_p_cmd)) \
-                - 2 * self.cross12(self.v_ref[3:6, 0:1], self.feet_v_cmd)
-
-            # Feet command velocity in base frame
-            self.feet_v_cmd = oRh.transpose() @ self.footTrajectoryGenerator.getFootVelocity()
-            self.feet_v_cmd = self.feet_v_cmd - self.v_ref[0:3, 0:1] - self.cross12(self.v_ref[3:6, 0:1], self.feet_p_cmd)
-
-            # Feet command position in base frame
-            self.feet_p_cmd = oRh.transpose() @ (self.footTrajectoryGenerator.getFootPosition()
-                                                 - np.array([[0.0], [0.0], [self.h_ref]]) - oTh)
+            # Feet command position, velocity and acceleration in base frame
+            self.feet_a_cmd = self.footTrajectoryGenerator.getFootAccelerationBaseFrame(oRh.transpose(), self.v_ref[3:6, 0:1])
+            self.feet_v_cmd = self.footTrajectoryGenerator.getFootVelocityBaseFrame(oRh.transpose(), self.v_ref[0:3, 0:1], self.v_ref[3:6, 0:1])
+            self.feet_p_cmd = self.footTrajectoryGenerator.getFootPositionBaseFrame(oRh.transpose(), np.array([[0.0], [0.0], [self.h_ref]]) + oTh)
 
             # Run InvKin + WBC QP
             self.myController.compute(self.q_wbc, self.b_v,
@@ -413,15 +405,16 @@ class Controller:
             self.q[2, 0] = self.estimator.q_filt[2, 0]
 
             # Mix perfect yaw with pitch and roll measurements
-            self.yaw_estim += self.v_ref[5, 0:1] * self.myController.dt
-            self.q[3:7, 0] = self.estimator.EulerToQuaternion([self.estimator.RPY[0], self.estimator.RPY[1], self.yaw_estim])
+            self.yaw_estim += self.v_ref[5, 0] * self.myController.dt
+            self.q[3:7, 0] = pin.Quaternion(pin.rpy.rpyToMatrix(self.estimator.RPY[0], self.estimator.RPY[1], self.yaw_estim)).coeffs()
 
             # Actuators measurements
             self.q[7:, 0] = self.estimator.q_filt[7:, 0]
 
             # Velocities are the one estimated by the estimator
             self.v = self.estimator.v_filt.copy()
-            hRb = utils_mpc.EulerToRotation(self.estimator.RPY[0], self.estimator.RPY[1], 0.0)
+            hRb = pin.rpy.rpyToMatrix(self.estimator.RPY[0], self.estimator.RPY[1], 0.0)
+
             self.h_v[0:3, 0:1] = hRb @ self.v[0:3, 0:1]
             self.h_v[3:6, 0:1] = hRb @ self.v[3:6, 0:1]
 
@@ -440,17 +433,3 @@ class Controller:
         oTh = np.array([[self.q[0, 0]], [self.q[1, 0]], [0.0]])
 
         return oRh, oTh
-
-    def cross12(self, left, right):
-        """Numpy is inefficient for this
-
-        Args:
-            left (3x1 array): left term of the cross product
-            right (3x4 array): right term of the cross product
-        """
-        res = np.zeros((3, 4))
-        for i in range(4):
-            res[:, i] = np.array([left[1, 0] * right[2, i] - left[2, 0] * right[1, i],
-                                  left[2, 0] * right[0, i] - left[0, 0] * right[2, i],
-                                  left[0, 0] * right[1, i] - left[1, 0] * right[0, i]])
-        return res
diff --git a/scripts/Estimator.py b/scripts/Estimator.py
index 0f3831021c076e8d0482e9c3d5c2a97c97360441..c3241c4bd58e02ced9c30776758f9d95de20a0e3 100644
--- a/scripts/Estimator.py
+++ b/scripts/Estimator.py
@@ -358,15 +358,15 @@ class Estimator:
         self.IMU_ang_vel[:] = device.baseAngularVelocity
 
         # Angular position of the trunk (local frame)
-        self.RPY = self.quaternionToRPY(device.baseOrientation)
+        self.RPY = pin.rpy.matrixToRpy(pin.Quaternion(device.baseOrientation).toRotationMatrix())
 
         if (self.k_log <= 1):
-            self.offset_yaw_IMU = self.RPY[2, 0]
+            self.offset_yaw_IMU = self.RPY[2]
         self.RPY[2] -= self.offset_yaw_IMU  # Remove initial offset of IMU
 
-        self.IMU_ang_pos[:] = self.EulerToQuaternion([self.RPY[0],
-                                                      self.RPY[1],
-                                                      self.RPY[2]])
+        self.IMU_ang_pos[:] = pin.Quaternion(pin.rpy.rpyToMatrix(self.RPY[0],
+                                                                 self.RPY[1],
+                                                                 self.RPY[2])).coeffs()
         # Above could be commented since IMU_ang_pos yaw is not used anywhere and instead
         # replace by: self.IMU_ang_pos[:] = device.baseOrientation
 
diff --git a/src/FootTrajectoryGenerator.cpp b/src/FootTrajectoryGenerator.cpp
index 6a01193a211e821669110184236cd17e47da6d57..33fb3528e0ad01e7671e1d787bb88260b6a6f02a 100644
--- a/src/FootTrajectoryGenerator.cpp
+++ b/src/FootTrajectoryGenerator.cpp
@@ -4,7 +4,7 @@
 
 FootTrajectoryGenerator::FootTrajectoryGenerator()
     : gait_(NULL)
-    , dt_tsid(0.0)
+    , dt_wbc(0.0)
     , k_mpc(0)
     , maxHeight_(0.0)
     , lockTime_(0.0)
@@ -17,17 +17,22 @@ FootTrajectoryGenerator::FootTrajectoryGenerator()
     , position_(Matrix34::Zero())
     , velocity_(Matrix34::Zero())
     , acceleration_(Matrix34::Zero())
+    , position_base_(Matrix34::Zero())
+    , velocity_base_(Matrix34::Zero())
+    , acceleration_base_(Matrix34::Zero())
 {
 }
 
 void FootTrajectoryGenerator::initialize(Params& params, Gait& gaitIn)
 {
-    dt_tsid = params.dt_wbc;
+    dt_wbc = params.dt_wbc;
     k_mpc = (int)std::round(params.dt_mpc / params.dt_wbc);
     maxHeight_ = params.max_height;
     lockTime_ = params.lock_time;
+    vertTime_ = params.vert_time;
     targetFootstep_ << Eigen::Map<Eigen::VectorXd, Eigen::Unaligned>(params.footsteps_init.data(), params.footsteps_init.size());
     position_ = targetFootstep_;
+    position_base_ = targetFootstep_;
     gait_ = &gaitIn;
 }
 
@@ -41,9 +46,9 @@ void FootTrajectoryGenerator::updateFootPosition(int const j, Vector3 const& tar
     double x0 = position_(0, j);
     double y0 = position_(1, j);
 
-    double t = t0s[j];
-    double d = t_swing[j];
-    double dt = dt_tsid;
+    double t = t0s[j] - vertTime_;
+    double d = t_swing[j] - 2 * vertTime_;
+    double dt = dt_wbc;
 
     if (t < d - lockTime_)
     {
@@ -67,14 +72,16 @@ void FootTrajectoryGenerator::updateFootPosition(int const j, Vector3 const& tar
     }
 
     // Coefficients for z (deterministic)
+    double Tz = t_swing[j];
     Vector4 Az;
-    Az(0, j) = -maxHeight_ / (std::pow((d / 2), 3) * std::pow((d - d / 2), 3));
-    Az(1, j) = (3 * d * maxHeight_) / (std::pow((d / 2), 3) * std::pow((d - d / 2), 3));
-    Az(2, j) = -(3 * std::pow(d, 2) * maxHeight_) / (std::pow((d / 2), 3) * std::pow((d - d / 2), 3));
-    Az(3, j) = (std::pow(d, 3) * maxHeight_) / (std::pow((d / 2), 3) * std::pow((d - d / 2), 3));
+    Az(0, j) = -maxHeight_ / (std::pow((Tz / 2), 3) * std::pow((Tz - Tz / 2), 3));
+    Az(1, j) = (3 * Tz * maxHeight_) / (std::pow((Tz / 2), 3) * std::pow((Tz - Tz / 2), 3));
+    Az(2, j) = -(3 * std::pow(Tz, 2) * maxHeight_) / (std::pow((Tz / 2), 3) * std::pow((Tz - Tz / 2), 3));
+    Az(3, j) = (std::pow(Tz, 3) * maxHeight_) / (std::pow((Tz / 2), 3) * std::pow((Tz - Tz / 2), 3));
 
     // Get the next point
     double ev = t + dt;
+    double evz = t0s[j] + dt;
 
     if (t < 0.0 || t > d)  // Just vertical motion
     {
@@ -94,9 +101,9 @@ void FootTrajectoryGenerator::updateFootPosition(int const j, Vector3 const& tar
         acceleration_(0, j) = 2 * Ax(3, j) + 3 * 2 * Ax(2, j) * ev + 4 * 3 * Ax(1, j) * std::pow(ev, 2) + 5 * 4 * Ax(0, j) * std::pow(ev, 3);
         acceleration_(1, j) = 2 * Ay(3, j) + 3 * 2 * Ay(2, j) * ev + 4 * 3 * Ay(1, j) * std::pow(ev, 2) + 5 * 4 * Ay(0, j) * std::pow(ev, 3);
     }
-    velocity_(2, j) = 3 * Az(3, j) * std::pow(ev, 2) + 4 * Az(2, j) * std::pow(ev, 3) + 5 * Az(1, j) * std::pow(ev, 4) + 6 * Az(0, j) * std::pow(ev, 5);
-    acceleration_(2, j) = 2 * 3 * Az(3, j) * ev + 3 * 4 * Az(2, j) * std::pow(ev, 2) + 4 * 5 * Az(1, j) * std::pow(ev, 3) + 5 * 6 * Az(0, j) * std::pow(ev, 4);
-    position_(2, j) = Az(3, j) * std::pow(ev, 3) + Az(2, j) * std::pow(ev, 4) + Az(1, j) * std::pow(ev, 5) + Az(0, j) * std::pow(ev, 6);
+    velocity_(2, j) = 3 * Az(3, j) * std::pow(evz, 2) + 4 * Az(2, j) * std::pow(evz, 3) + 5 * Az(1, j) * std::pow(evz, 4) + 6 * Az(0, j) * std::pow(evz, 5);
+    acceleration_(2, j) = 2 * 3 * Az(3, j) * evz + 3 * 4 * Az(2, j) * std::pow(evz, 2) + 4 * 5 * Az(1, j) * std::pow(evz, 3) + 5 * 6 * Az(0, j) * std::pow(evz, 4);
+    position_(2, j) = Az(3, j) * std::pow(evz, 3) + Az(2, j) * std::pow(evz, 4) + Az(1, j) * std::pow(evz, 5) + Az(0, j) * std::pow(evz, 6);
 }
 
 void FootTrajectoryGenerator::update(int k, MatrixN const& targetFootstep)
@@ -119,7 +126,7 @@ void FootTrajectoryGenerator::update(int k, MatrixN const& targetFootstep)
         {
             int i = feet[j];
             t_swing[i] = gait_->getPhaseDuration(0, feet[j], 0.0);  // 0.0 for swing phase
-            double value = t_swing[i] - (gait_->getRemainingTime() * k_mpc - ((k + 1) % k_mpc)) * dt_tsid - dt_tsid;
+            double value = t_swing[i] - (gait_->getRemainingTime() * k_mpc - ((k + 1) % k_mpc)) * dt_wbc - dt_wbc;
             t0s[i] = std::max(0.0, value);
         }
     }
@@ -132,7 +139,7 @@ void FootTrajectoryGenerator::update(int k, MatrixN const& targetFootstep)
         // Increment of one time step for feet in swing phase
         for (int i = 0; i < (int)feet.size(); i++)
         {
-            double value = t0s[feet[i]] + dt_tsid;
+            double value = t0s[feet[i]] + dt_wbc;
             t0s[feet[i]] = std::max(0.0, value);
         }
     }
@@ -143,3 +150,21 @@ void FootTrajectoryGenerator::update(int k, MatrixN const& targetFootstep)
     }
     return;
 }
+
+Eigen::MatrixXd FootTrajectoryGenerator::getFootPositionBaseFrame(const Eigen::Matrix<double, 3, 3> &R, const Eigen::Matrix<double, 3, 1> &T) {
+
+    position_base_ = R * (position_ - T.replicate<1, 4>());  // Value saved because it is used to get velocity and acceleration
+    return position_base_;
+}
+
+Eigen::MatrixXd FootTrajectoryGenerator::getFootVelocityBaseFrame(const Eigen::Matrix<double, 3, 3> &R, const Eigen::Matrix<double, 3, 1> &v_ref,
+                                                                  const Eigen::Matrix<double, 3, 1> &w_ref) {
+
+    velocity_base_ = R * velocity_ - v_ref.replicate<1, 4>() + position_base_.colwise().cross(w_ref);  // Value saved because it is used to get acceleration
+    return velocity_base_;
+}
+
+Eigen::MatrixXd FootTrajectoryGenerator::getFootAccelerationBaseFrame(const Eigen::Matrix<double, 3, 3> &R, const Eigen::Matrix<double, 3, 1> &w_ref) {
+
+    return R * acceleration_ - (position_base_.colwise().cross(w_ref)).colwise().cross(w_ref) + 2 * velocity_base_.colwise().cross(w_ref);
+}
diff --git a/src/Params.cpp b/src/Params.cpp
index 5b50a8eaca3376eee0991a06e85d319721c6cc15..e142d59c64f7b40e7ba9b96f50b90a6363ec95fa 100644
--- a/src/Params.cpp
+++ b/src/Params.cpp
@@ -29,6 +29,7 @@ Params::Params()
 
     , max_height(0.0)
     , lock_time(0.0)
+    , vert_time(0.0)
 
     , osqp_w_states(12, 0.0) // Fill with zeros, will be filled with values later
     , osqp_w_forces(3, 0.0) // Fill with zeros, will be filled with values later
diff --git a/src/config_solo12.yaml b/src/config_solo12.yaml
index 054251a1ab231e90f76f79b4526ce4873a9827f2..3b540d97992a613d9631eab5e244257de84b2aed 100644
--- a/src/config_solo12.yaml
+++ b/src/config_solo12.yaml
@@ -29,7 +29,8 @@ robot:
 
     # Parameters of FootTrajectoryGenerator
     max_height: 0.05  # Apex height of the swinging trajectory [m]
-    lock_time: 0.07  # Target lock before the touchdown [s]
+    lock_time: 0.04  # Target lock before the touchdown [s]
+    vert_time: 0.02  # Duration during which feet move only along Z when taking off and landing
 
     # Parameters of MPC with OSQP
     osqp_w_states: [2.0, 2.0, 20.0, 0.25, 0.25, 10.0, 0.2, 0.2, 0.2, 0.0, 0.0, 0.3]  # Weights for state tracking error
@@ -43,5 +44,5 @@ robot:
     # Parameters of WBC QP problem
     Q1: 0.1  # Weights for the "delta articular accelerations" optimization variables
     Q2: 5.0  # Weights for the "delta contact forces" optimization variables
-    Fz_max: 25.0  # Maximum vertical contact force [N]
+    Fz_max: 35.0  # Maximum vertical contact force [N]
     Fz_min: 0.0  # Minimal vertical contact force [N]
\ No newline at end of file