From b939677c2da7cf395b860099f8c679bbdae6061e Mon Sep 17 00:00:00 2001 From: paleziart <paleziart@laas.fr> Date: Fri, 18 Dec 2020 17:31:52 +0100 Subject: [PATCH] Implement change of gait with joystick for C++ Planner --- .../quadruped-reactive-walking/Planner.hpp | 6 +- python/gepadd.cpp | 2 +- scripts/Planner.py | 7 +- src/Planner.cpp | 107 +++++++++++++++++- 4 files changed, 116 insertions(+), 6 deletions(-) diff --git a/include/quadruped-reactive-walking/Planner.hpp b/include/quadruped-reactive-walking/Planner.hpp index 70dd1a15..db403bda 100644 --- a/include/quadruped-reactive-walking/Planner.hpp +++ b/include/quadruped-reactive-walking/Planner.hpp @@ -132,8 +132,12 @@ class Planner { int create_walk(); int create_trot(); + int create_pacing(); + int create_bounding(); + int create_static(); int create_gait_f(); int roll(int k); + int handle_joystick(int code, const Eigen::MatrixXd &q); int compute_footsteps(Eigen::MatrixXd q_cur, Eigen::MatrixXd v_cur, Eigen::MatrixXd v_ref); double get_stance_swing_duration(int i, int j, double value); int compute_next_footstep(int i, int j); @@ -141,7 +145,7 @@ class Planner { int update_target_footsteps(); int update_trajectory_generator(int k, double h_estim); int run_planner(int k, const Eigen::MatrixXd &q, const Eigen::MatrixXd &v, const Eigen::MatrixXd &b_vref, - double h_estim, double z_average); + double h_estim, double z_average, int joystick_code); // Accessors (to retrieve C data from Python) Eigen::MatrixXd get_xref(); diff --git a/python/gepadd.cpp b/python/gepadd.cpp index c399c67b..da855671 100644 --- a/python/gepadd.cpp +++ b/python/gepadd.cpp @@ -53,7 +53,7 @@ struct PlannerPythonVisitor : public bp::def_visitor<PlannerPythonVisitor<Planne //.add_property("xref", &Planner::get_xref) // Run Planner from Python - .def("run_planner", &Planner::run_planner, bp::args("k", "q", "v", "b_vref", "h_estim", "z_average"), + .def("run_planner", &Planner::run_planner, bp::args("k", "q", "v", "b_vref", "h_estim", "z_average", "joystick_code"), "Run Planner from Python.\n"); } diff --git a/scripts/Planner.py b/scripts/Planner.py index 53ae9dc2..1c27557a 100644 --- a/scripts/Planner.py +++ b/scripts/Planner.py @@ -571,20 +571,25 @@ class PyPlanner: self.new_desired_gait = self.one_swing_gait() self.is_static = False""" + joystick_code = 0 if joystick is not None: if joystick.northButton: + joystick_code = 1 self.new_desired_gait = self.pacing_gait() self.is_static = False joystick.northButton = False elif joystick.eastButton: + joystick_code = 2 self.new_desired_gait = self.bounding_gait() self.is_static = False joystick.eastButton = False elif joystick.southButton: + joystick_code = 3 self.new_desired_gait = self.trot_gait() self.is_static = False joystick.southButton = False elif joystick.westButton: + joystick_code = 4 self.new_desired_gait = self.static_gait() self.is_static = True self.q_static[0:7, 0:1] = q.copy() @@ -617,7 +622,7 @@ class PyPlanner: # Update desired location of footsteps on the ground # self.update_target_footsteps() - self.Cplanner.run_planner(k, q, v, b_vref, np.double(h_estim), np.double(z_average)) + self.Cplanner.run_planner(k, q, v, b_vref, np.double(h_estim), np.double(z_average), joystick_code) # Update trajectory generator (3D pos, vel, acc) # self.update_trajectory_generator(k, h_estim, q) diff --git a/src/Planner.cpp b/src/Planner.cpp index 365f1c30..e92da2ed 100644 --- a/src/Planner.cpp +++ b/src/Planner.cpp @@ -102,6 +102,69 @@ int Planner::create_trot() { return 0; } +int Planner::create_pacing() { + /* Create a pacing gait with legs on the same side (left or right) moving at the same time */ + + // Number of timesteps in a half period of gait + int N = (int)std::lround(0.5 * T_gait / dt); + + gait_f_des = Eigen::Matrix<double, N0_gait, 5>::Zero(); + gait_f_des.block(0, 0, 2, 1) << N, N; + fsteps.block(0, 0, 2, 1) = gait_f_des.block(0, 0, 2, 1); + + // Set stance and swing phases + // Coefficient (i, j) is equal to 0.0 if the j-th feet is in swing phase during the i-th phase + // Coefficient (i, j) is equal to 1.0 if the j-th feet is in stance phase during the i-th phase + gait_f_des(0, 1) = 1.0; + gait_f_des(0, 3) = 1.0; + gait_f_des(1, 2) = 1.0; + gait_f_des(1, 4) = 1.0; + + return 0; +} + +int Planner::create_bounding() { + /* Create a bounding gait with legs on the same side (front or hind) moving at the same time */ + + // Number of timesteps in a half period of gait + int N = (int)std::lround(0.5 * T_gait / dt); + + gait_f_des = Eigen::Matrix<double, N0_gait, 5>::Zero(); + gait_f_des.block(0, 0, 2, 1) << N, N; + fsteps.block(0, 0, 2, 1) = gait_f_des.block(0, 0, 2, 1); + + // Set stance and swing phases + // Coefficient (i, j) is equal to 0.0 if the j-th feet is in swing phase during the i-th phase + // Coefficient (i, j) is equal to 1.0 if the j-th feet is in stance phase during the i-th phase + gait_f_des(0, 1) = 1.0; + gait_f_des(0, 2) = 1.0; + gait_f_des(1, 3) = 1.0; + gait_f_des(1, 4) = 1.0; + + return 0; +} + +int Planner::create_static() { + /* Create a static gait with all legs in stance phase */ + + // Number of timesteps in a half period of gait + int N = (int)std::lround(T_gait / dt); + + gait_f_des = Eigen::Matrix<double, N0_gait, 5>::Zero(); + gait_f_des(0, 0) = N; + fsteps(0, 0) = gait_f_des(0, 0); + + // Set stance and swing phases + // Coefficient (i, j) is equal to 0.0 if the j-th feet is in swing phase during the i-th phase + // Coefficient (i, j) is equal to 1.0 if the j-th feet is in stance phase during the i-th phase + gait_f_des(0, 1) = 1.0; + gait_f_des(0, 2) = 1.0; + gait_f_des(0, 3) = 1.0; + gait_f_des(0, 4) = 1.0; + + return 0; +} + int Planner::create_gait_f() { /* Initialize content of the gait matrix based on the desired gait, the gait period and the length of the prediciton horizon */ @@ -400,11 +463,13 @@ int Planner::getRefStates(Eigen::MatrixXd q, Eigen::MatrixXd v, Eigen::MatrixXd } if (is_static) { + Eigen::Matrix<double, 3, 1> RPY; + Eigen::Quaterniond quat(q_static(6, 0), q_static(3, 0), q_static(4, 0), q_static(5, 0)); // w, x, y, z + RPY << pinocchio::rpy::matrixToRpy(quat.toRotationMatrix()); for (int i = 0; i < n_steps; i++) { xref.block(0, 1 + i, 3, 1) = q_static.block(0, 0, 3, 1); + xref.block(3, 1 + i, 3, 1) = RPY; } - xref.block(3, 1, 3, n_steps) = Eigen::Matrix<double, 3, Eigen::Dynamic>::Zero( - 3, n_steps); // (utils_mpc.quaternionToRPY(self.q_static[3:7, 0])).reshape((3, 1)) } return 0; @@ -514,7 +579,7 @@ int Planner::update_trajectory_generator(int k, double h_estim) { } int Planner::run_planner(int k, const Eigen::MatrixXd &q, const Eigen::MatrixXd &v, const Eigen::MatrixXd &b_vref_in, - double h_estim, double z_average) { + double h_estim, double z_average, int joystick_code) { /* Run the planner for one iteration of the main control loop Args: @@ -524,6 +589,7 @@ int Planner::run_planner(int k, const Eigen::MatrixXd &q, const Eigen::MatrixXd b_vref_in (6x1 array): desired velocity vector of the flying base in base frame (linear and angular stacked) h_estim (double): estimated height of the base z_average (double): average height of feet currently in stance phase + joystick_code (int): integer to trigger events with the joystick */ // Get the reference velocity in world frame (given in base frame) @@ -536,6 +602,9 @@ int Planner::run_planner(int k, const Eigen::MatrixXd &q, const Eigen::MatrixXd vref_in.block(0, 0, 3, 1) = R_2 * b_vref_in.block(0, 0, 3, 1); vref_in.block(3, 0, 3, 1) = b_vref_in.block(3, 0, 3, 1); + // Handle joystick events + handle_joystick(joystick_code, q); + // Move one step further in the gait if (k % k_mpc == 0) { roll(k); @@ -636,6 +705,38 @@ int Planner::roll(int k) { return 0; } +int Planner::handle_joystick(int code, const Eigen::MatrixXd &q) { + /* Handle the joystick code to trigger events (change of gait for instance) + + Args: + code (int): integer to trigger events with the joystick + q (7x1 array): current position vector of the flying base in world frame (linear and angular stacked) + */ + + if (code == 0) { + return 0; + } + else if (code == 1) { + create_pacing(); + is_static = false; + } + else if (code == 2) { + create_bounding(); + is_static = false; + } + else if (code == 3) { + create_trot(); + is_static = false; + } + else if (code == 4) { + create_static(); + q_static.block(0, 0, 7, 1) = q.block(0, 0, 7, 1); + is_static = true; + } + + return 0; +} + // Trajectory generator functions (output reference pos, vel and acc of feet in swing phase) TrajGen::TrajGen() {} -- GitLab