trot but not stable

This commit is contained in:
Huang Zhenbiao 2024-09-18 19:37:01 +08:00
parent da5be83eda
commit f0a5257852
25 changed files with 639 additions and 68 deletions

View File

@ -34,6 +34,7 @@ add_library(${PROJECT_NAME} SHARED
src/FSM/StateSwingTest.cpp
src/FSM/StateFreeStand.cpp
src/FSM/StateBalanceTest.cpp
src/FSM/StateTrotting.cpp
src/robot/QuadrupedRobot.cpp
src/robot/RobotLeg.cpp
@ -46,7 +47,7 @@ add_library(${PROJECT_NAME} SHARED
src/quadProgpp/QuadProg++.cc
src/gait/WaveGenerator.cpp
src/gait/FootEndCtrl.cpp
src/gait/FeetEndCtrl.cpp
src/gait/GaitGenerator.cpp
)

View File

@ -22,9 +22,10 @@ public:
private:
void calcTorque();
Estimator& estimator_;
QuadrupedRobot& robot_model_;
BalanceCtrl& balance_ctrl_;
Estimator &estimator_;
QuadrupedRobot &robot_model_;
BalanceCtrl &balance_ctrl_;
WaveGenerator &wave_generator_;
Vec3 pcd_, pcd_init_;
RotMat Rd_;

View File

@ -0,0 +1,81 @@
//
// Created by tlab-uav on 24-9-18.
//
#ifndef STATETROTTING_H
#define STATETROTTING_H
#include <unitree_guide_controller/gait/GaitGenerator.h>
#include "FSMState.h"
class StateTrotting final : public FSMState {
public:
explicit StateTrotting(CtrlComponent &ctrlComp);
void enter() override;
void run() override;
void exit() override;
FSMStateName checkChange() override;
private:
void getUserCmd();
void calcCmd();
void calcTau();
void calcQQd();
void calcGain() const;
/**
* Check whether the robot should take a step or not
* @return
*/
bool checkStepOrNot();
Estimator &estimator_;
QuadrupedRobot &robot_model_;
BalanceCtrl &balance_ctrl_;
WaveGenerator &wave_generator_;
GaitGenerator gait_generator_;
// Robot State
Vec3 _posBody, _velBody;
double _yaw{}, _dYaw{};
Vec34 _posFeetGlobal, _velFeetGlobal;
Vec34 _posFeet2BGlobal;
RotMat B2G_RotMat, G2B_RotMat;
Vec12 _q;
// Robot command
Vec3 _pcd;
Vec3 _vCmdGlobal, _vCmdBody;
double dt_;
double _yawCmd{}, _dYawCmd{};
double _dYawCmdPast{};
Vec3 _wCmdGlobal;
Vec34 _posFeetGlobalGoal, _velFeetGlobalGoal;
Vec34 _posFeet2BGoal, _velFeet2BGoal;
RotMat Rd;
Vec3 _ddPcd, _dWbd;
Vec34 force_feet_global_, force_feet_body_;
Vec12 _tau;
// Control Parameters
double _gaitHeight;
Vec3 pos_error_, vel_error_;
Mat3 Kpp, Kdp, Kdw;
double _kpw;
Mat3 KpSwing, KdSwing;
Vec2 _vxLim, _vyLim, _wyawLim;
};
#endif //STATETROTTING_H

View File

@ -16,6 +16,7 @@
#include "FSM/StateFreeStand.h"
#include "FSM/StatePassive.h"
#include "FSM/StateSwingTest.h"
#include "FSM/StateTrotting.h"
namespace unitree_guide_controller {
struct FSMStateList {
@ -24,6 +25,7 @@ namespace unitree_guide_controller {
std::shared_ptr<StateFixedDown> fixedDown;
std::shared_ptr<StateFixedStand> fixedStand;
std::shared_ptr<StateFreeStand> freeStand;
std::shared_ptr<StateTrotting> trotting;
std::shared_ptr<StateSwingTest> swingTest;
std::shared_ptr<StateBalanceTest> balanceTest;

View File

@ -61,5 +61,25 @@ inline Vec3 rotMatToExp(const RotMat &rm) {
return exp;
}
template<typename T>
T saturation(const T a, Vec2 limits) {
T lowLim, highLim;
if (limits(0) > limits(1)) {
lowLim = limits(1);
highLim = limits(0);
} else {
lowLim = limits(0);
highLim = limits(1);
}
if (a < lowLim) {
return lowLim;
}
if (a > highLim) {
return highLim;
}
return a;
}
#endif //MATHTOOLS_H

View File

@ -26,14 +26,14 @@ public:
* @return
*/
Vec34 calF(const Vec3 &ddPcd, const Vec3 &dWbd, const RotMat &rot_matrix,
const Vec34 &feet_pos_2_body, const std::vector<int> &contact);
const Vec34 &feet_pos_2_body, const VecInt4 &contact);
private:
void calMatrixA(const Vec34 &feet_pos_2_body, const RotMat &rotM);
void calVectorBd(const Vec3 &ddPcd, const Vec3 &dWbd, const RotMat &rotM);
void calConstraints(const std::vector<int> &contact);
void calConstraints(const VecInt4 &contact);
void solveQP();

View File

@ -44,11 +44,23 @@ public:
return getPosition() + Vec3((rotation_ * foot_poses_[index].p).data);
}
/**
* Get the estimated feet velocity in world frame
* @return feet velocity in world frame
*/
Vec34 getFeetPos() {
Vec34 feetPos;
for (int i(0); i < 4; ++i) {
feetPos.col(i) = getFootPos(i);
}
return feetPos;
}
/**
* Get the estimated foot position in body frame
* @return
*/
Vec34 getFootPos2Body() {
Vec34 getFeetPos2Body() {
Vec34 foot_pos;
const Vec3 body_pos = getPosition();
for (int i = 0; i < 4; i++) {
@ -65,8 +77,18 @@ public:
return gyro_;
}
[[nodiscard]] KDL::Vector getGlobalGyro() const {
return rotation_ * gyro_;
[[nodiscard]] Vec3 getGlobalGyro() const {
return Vec3((rotation_ * gyro_).data);
}
[[nodiscard]] double getYaw() const {
double roll, pitch, yaw;
rotation_.GetRPY(roll, pitch, yaw);
return yaw;
}
[[nodiscard]] double getDYaw() const {
return getGlobalGyro()(2);
}
void update();

View File

@ -0,0 +1,38 @@
//
// Created by biao on 24-9-18.
//
#ifndef FOOTENDCTRL_H
#define FOOTENDCTRL_H
#include <unitree_guide_controller/common/mathTypes.h>
class Estimator;
struct CtrlComponent;
class QuadrupedRobot;
class FeetEndCtrl {
public:
explicit FeetEndCtrl(CtrlComponent &ctrl_component);
void init();
~FeetEndCtrl() = default;
Vec3 calcFootPos(int index, Vec2 vxy_goal_global, double d_yaw_global, double phase);
private:
CtrlComponent &ctrl_component_;
QuadrupedRobot &robot_model_;
Estimator &estimator_;
Vec4 feet_radius_, feet_init_angle_;
double k_x_, k_y_, k_yaw_;
double t_stance_{}, t_swing_{};
};
#endif //FOOTENDCTRL_H

View File

@ -1,24 +0,0 @@
//
// Created by biao on 24-9-18.
//
#ifndef FOOTENDCTRL_H
#define FOOTENDCTRL_H
#include <unitree_guide_controller/common/mathTypes.h>
class FootEndCtrl {
public:
FootEndCtrl();
~FootEndCtrl() = default;
Vec3 calcFootPos(int index, Vec2 vxy_goal_global, double d_yaw_global, double phase);
private:
double k_x_, k_y_, k_yaw_;
};
#endif //FOOTENDCTRL_H

View File

@ -5,10 +5,76 @@
#ifndef GAITGENERATOR_H
#define GAITGENERATOR_H
#include <unitree_guide_controller/common/mathTypes.h>
#include "FeetEndCtrl.h"
class Gaitgenerator {
class Estimator;
class WaveGenerator;
struct CtrlComponent;
class GaitGenerator {
public:
explicit GaitGenerator(CtrlComponent &ctrl_component);
~GaitGenerator() = default;
void setGait(Vec2 vxy_goal_global, double d_yaw_goal, double gait_height);
void run(Vec34 &feet_pos, Vec34 &feet_vel);
void restart();
private:
Vec3 getFootPos(int i);
Vec3 getFootVel(int i);
/**
* Calculate the position of the foot in the XY plane
* @param startXY
* @param endXY
* @param phase
* @return
*/
static double cycloidXYPosition(double startXY, double endXY, double phase);
/**
* Calculate the position of the foot in the Z direction
* @param startZ
* @param height
* @param phase
* @return
*/
static double cycloidZPosition(double startZ, double height, double phase);
/**
* Calculate the velocity of the foot in the XY plane
* @param startXY
* @param endXY
* @param phase
* @return
*/
[[nodiscard]] double cycloidXYVelocity(double startXY, double endXY, double phase) const;
/**
* Calculate the velocity of the foot in the Z direction
* @param height
* @param phase
* @return
*/
[[nodiscard]] double cycloidZVelocity(double height, double phase) const;
WaveGenerator &wave_generator_;
Estimator &estimator_;
FeetEndCtrl feet_end_ctrl_;
double gait_height_{};
Vec2 vxy_goal_;
double d_yaw_goal_{};
Vec34 start_p_, end_p_, ideal_p_, past_p_;
bool first_run_;
};

View File

@ -23,12 +23,16 @@ public:
void init(double period, double st_ratio, const Vec4 &bias);
void calculate(Vec4 &phase_result, VecInt4 &contact_result, WaveStatus status);
void update();
[[nodiscard]] double get_t_stance() const { return period_ * st_ratio_; }
[[nodiscard]] double get_t_swing() const { return period_ * (1 - st_ratio_); }
[[nodiscard]] double get_t() const { return period_; }
Vec4 phase_;
VecInt4 contact_;
WaveStatus status_{};
private:
/**
* Update phase, contact and status based on current time.
@ -43,8 +47,8 @@ private:
Vec4 bias_;
Vec4 normal_t_; // normalize time [0,1)
Vec4 phase_, phase_past_; // foot phase
VecInt4 contact_, contact_past_; // foot contact
Vec4 phase_past_; // foot phase
VecInt4 contact_past_; // foot contact
VecInt4 switch_status_;
WaveStatus status_past_;

View File

@ -30,6 +30,10 @@ public:
*/
[[nodiscard]] std::vector<KDL::JntArray> getQ(const std::vector<KDL::Frame> &pEe_list) const;
[[nodiscard]] Vec12 getQ(const Vec34 &vecP) const;
Vec12 getQd(const std::vector<KDL::Frame> &pos, const Vec34 &vel);
/**
* Calculate the foot end position based on joint positions
* @return vector of foot-end position

View File

@ -10,7 +10,8 @@ StateBalanceTest::StateBalanceTest(CtrlComponent &ctrlComp) : FSMState(FSMStateN
ctrlComp),
estimator_(ctrlComp.estimator_),
robot_model_(ctrlComp.robot_model_),
balance_ctrl_(ctrlComp.balance_ctrl_) {
balance_ctrl_(ctrlComp.balance_ctrl_),
wave_generator_(ctrl_comp_.wave_generator_) {
_xMax = 0.05;
_xMin = -_xMax;
_yMax = 0.05;
@ -31,6 +32,7 @@ void StateBalanceTest::enter() {
pcd_init_ = estimator_.getPosition();
pcd_ = pcd_init_;
init_rotation_ = estimator_.getRotation();
wave_generator_.status_ = WaveStatus::STANCE_ALL;
}
void StateBalanceTest::run() {
@ -74,12 +76,11 @@ void StateBalanceTest::calcTorque() {
// expected body angular acceleration
d_wbd_ = -kp_w_ * rotMatToExp(Rd_ * G2B_Rotation) +
Kd_w_ * Vec3((-estimator_.getGlobalGyro()).data);
Kd_w_ * -estimator_.getGlobalGyro();
// calculate foot force
const std::vector contact(4, 1);
const Vec34 foot_force = G2B_Rotation * balance_ctrl_.calF(dd_pcd_, d_wbd_, B2G_Rotation,
estimator_.getFootPos2Body(), contact);
estimator_.getFeetPos2Body(), wave_generator_.contact_);
std::vector<KDL::JntArray> current_joints = robot_model_.current_joint_pos_;
for (int i = 0; i < 4; i++) {

View File

@ -15,6 +15,7 @@ void StateFixedDown::enter() {
for (int i = 0; i < 12; i++) {
start_pos_[i] = ctrl_comp_.joint_position_state_interface_[i].get().get_value();
}
ctrl_comp_.control_inputs_.get().command = 0;
}
void StateFixedDown::run() {

View File

@ -15,6 +15,7 @@ void StateFixedStand::enter() {
for (int i = 0; i < 12; i++) {
start_pos_[i] = ctrl_comp_.joint_position_state_interface_[i].get().get_value();
}
ctrl_comp_.control_inputs_.get().command = 0;
}
void StateFixedStand::run() {
@ -44,6 +45,8 @@ FSMStateName StateFixedStand::checkChange() {
return FSMStateName::FIXEDDOWN;
case 3:
return FSMStateName::FREESTAND;
case 4:
return FSMStateName::TROTTING;
case 9:
return FSMStateName::SWINGTEST;
case 10:

View File

@ -33,6 +33,7 @@ void StateFreeStand::enter() {
foot_pos.p -= fr_init_pos_.p;
foot_pos.M = KDL::Rotation::RPY(0, 0, 0);
}
ctrl_comp_.control_inputs_.get().command = 0;
}
void StateFreeStand::run() {

View File

@ -27,6 +27,7 @@ void StatePassive::enter() {
for (auto i: ctrl_comp_.joint_kd_command_interface_) {
i.get().set_value(1);
}
ctrl_comp_.control_inputs_.get().command = 0;
}
void StatePassive::run() {

View File

@ -0,0 +1,196 @@
//
// Created by tlab-uav on 24-9-18.
//
#include "unitree_guide_controller/FSM/StateTrotting.h"
#include <unitree_guide_controller/common/mathTools.h>
StateTrotting::StateTrotting(CtrlComponent &ctrlComp) : FSMState(FSMStateName::TROTTING, "trotting", ctrlComp),
estimator_(ctrlComp.estimator_),
robot_model_(ctrlComp.robot_model_),
balance_ctrl_(ctrlComp.balance_ctrl_),
wave_generator_(ctrl_comp_.wave_generator_),
gait_generator_(ctrlComp) {
_gaitHeight = 0.08;
Kpp = Vec3(70, 70, 70).asDiagonal();
Kdp = Vec3(10, 10, 10).asDiagonal();
_kpw = 780;
Kdw = Vec3(70, 70, 70).asDiagonal();
KpSwing = Vec3(400, 400, 400).asDiagonal();
KdSwing = Vec3(10, 10, 10).asDiagonal();
_vxLim << -0.4, 0.4;
_vyLim << -0.3, 0.3;
_wyawLim << -0.5, 0.5;
dt_ = 1.0 / ctrl_comp_.frequency_;
}
void StateTrotting::enter() {
_pcd = estimator_.getPosition();
_vCmdBody.setZero();
_yawCmd = estimator_.getYaw();
Rd = Mat3(KDL::Rotation::RPY(0, 0, _yawCmd).Inverse().data);
_wCmdGlobal.setZero();
ctrl_comp_.control_inputs_.get().command = 0;
gait_generator_.restart();
}
void StateTrotting::run() {
_posBody = estimator_.getPosition();
_velBody = estimator_.getVelocity();
_posFeet2BGlobal = estimator_.getFeetPos2Body();
_posFeetGlobal = estimator_.getFeetPos();
B2G_RotMat = Eigen::Matrix3d(estimator_.getRotation().data);
G2B_RotMat = B2G_RotMat.transpose();
getUserCmd();
calcCmd();
gait_generator_.setGait(_vCmdGlobal.segment(0, 2), _wCmdGlobal(2), _gaitHeight);
gait_generator_.run(_posFeetGlobalGoal, _velFeetGlobalGoal);
calcTau();
calcQQd();
if (checkStepOrNot()) {
wave_generator_.status_ = WaveStatus::WAVE_ALL;
} else {
wave_generator_.status_ = WaveStatus::STANCE_ALL;
}
calcGain();
}
void StateTrotting::exit() {
wave_generator_.status_ = WaveStatus::SWING_ALL;
}
FSMStateName StateTrotting::checkChange() {
switch (ctrl_comp_.control_inputs_.get().command) {
case 1:
return FSMStateName::FIXEDDOWN;
case 2:
return FSMStateName::FIXEDSTAND;
default:
return FSMStateName::TROTTING;
}
}
void StateTrotting::getUserCmd() {
/* Movement */
_vCmdBody(0) = invNormalize(ctrl_comp_.control_inputs_.get().ly, _vxLim(0), _vxLim(1));
_vCmdBody(1) = -invNormalize(ctrl_comp_.control_inputs_.get().lx, _vyLim(0), _vyLim(1));
_vCmdBody(2) = 0;
/* Turning */
_dYawCmd = -invNormalize(ctrl_comp_.control_inputs_.get().rx, _wyawLim(0), _wyawLim(1));
_dYawCmd = 0.9 * _dYawCmdPast + (1 - 0.9) * _dYawCmd;
_dYawCmdPast = _dYawCmd;
}
void StateTrotting::calcCmd() {
/* Movement */
_vCmdGlobal = B2G_RotMat * _vCmdBody;
_vCmdGlobal(0) =
saturation(_vCmdGlobal(0), Vec2(_velBody(0) - 0.2, _velBody(0) + 0.2));
_vCmdGlobal(1) =
saturation(_vCmdGlobal(1), Vec2(_velBody(1) - 0.2, _velBody(1) + 0.2));
_pcd(0) = saturation(_pcd(0) + _vCmdGlobal(0) * dt_,
Vec2(_posBody(0) - 0.05, _posBody(0) + 0.05));
_pcd(1) = saturation(_pcd(1) + _vCmdGlobal(1) * dt_,
Vec2(_posBody(1) - 0.05, _posBody(1) + 0.05));
_vCmdGlobal(2) = 0;
/* Turning */
_yawCmd = _yawCmd + _dYawCmd * dt_;
Rd = Mat3(KDL::Rotation::RPY(0, 0, _yawCmd).Inverse().data);
_wCmdGlobal(2) = _dYawCmd;
}
void StateTrotting::calcTau() {
pos_error_ = _pcd - _posBody;
vel_error_ = _vCmdGlobal - _velBody;
_ddPcd = Kpp * pos_error_ + Kdp * vel_error_;
_dWbd = _kpw * rotMatToExp(Rd * G2B_RotMat) +
Kdw * (_wCmdGlobal - estimator_.getGlobalGyro());
_ddPcd(0) = saturation(_ddPcd(0), Vec2(-3, 3));
_ddPcd(1) = saturation(_ddPcd(1), Vec2(-3, 3));
_ddPcd(2) = saturation(_ddPcd(2), Vec2(-5, 5));
_dWbd(0) = saturation(_dWbd(0), Vec2(-40, 40));
_dWbd(1) = saturation(_dWbd(1), Vec2(-40, 40));
_dWbd(2) = saturation(_dWbd(2), Vec2(-10, 10));
force_feet_global_ =
-balance_ctrl_.calF(_ddPcd, _dWbd, B2G_RotMat, _posFeet2BGlobal, wave_generator_.contact_);
for (int i(0); i < 4; ++i) {
if (wave_generator_.contact_(i) == 0) {
force_feet_global_.col(i) =
KpSwing * (_posFeetGlobalGoal.col(i) - _posFeetGlobal.col(i)) +
KdSwing * (_velFeetGlobalGoal.col(i) - _velFeetGlobal.col(i));
}
}
force_feet_body_ = G2B_RotMat * force_feet_global_;
std::vector<KDL::JntArray> current_joints = robot_model_.current_joint_pos_;
for (int i = 0; i < 4; i++) {
KDL::JntArray torque = robot_model_.getTorque(force_feet_body_.col(i), i);
for (int j = 0; j < 3; j++) {
ctrl_comp_.joint_effort_command_interface_[i * 3 + j].get().set_value(torque(j));
}
}
}
void StateTrotting::calcQQd() {
const std::vector<KDL::Frame> _posFeet2B = robot_model_.getFeet2BPositions();
for (int i(0); i < 4; ++i) {
_posFeet2BGoal.col(i) = G2B_RotMat * (_posFeetGlobalGoal.col(i) - _posBody);
_velFeet2BGoal.col(i) = G2B_RotMat * (_velFeetGlobalGoal.col(i) - _velBody);
// _velFeet2BGoal.col(i) = _G2B_RotMat * (_velFeetGlobalGoal.col(i) -
// _velBody - _B2G_RotMat * (skew(_lowState->getGyro()) * _posFeet2B.col(i))
// ); // c.f formula (6.12)
}
Vec12 q_goal = robot_model_.getQ(_posFeet2BGoal);
Vec12 qd_goal = robot_model_.getQd(_posFeet2B, _velFeet2BGoal);
for (int i = 0; i < 12; i++) {
ctrl_comp_.joint_position_command_interface_[i].get().set_value(q_goal(i));
ctrl_comp_.joint_velocity_command_interface_[i].get().set_value(qd_goal(i));
}
}
void StateTrotting::calcGain() const {
for (int i(0); i < 4; ++i) {
if (wave_generator_.contact_(i) == 0) {
for (int j = 0; j < 3; j++) {
ctrl_comp_.joint_kp_command_interface_[i * 3 + j].get().set_value(3);
ctrl_comp_.joint_kd_command_interface_[i * 3 + j].get().set_value(2);
}
} else {
for (int j = 0; j < 3; j++) {
ctrl_comp_.joint_kp_command_interface_[i * 3 + j].get().set_value(0.8);
ctrl_comp_.joint_kd_command_interface_[i * 3 + j].get().set_value(0.8);
}
}
}
}
bool StateTrotting::checkStepOrNot() {
if (fabs(_vCmdBody(0)) > 0.03 || fabs(_vCmdBody(1)) > 0.03 ||
fabs(pos_error_(0)) > 0.08 || fabs(pos_error_(1)) > 0.08 ||
fabs(vel_error_(0)) > 0.05 || fabs(vel_error_(1)) > 0.05 ||
fabs(_dYawCmd) > 0.20) {
return true;
}
return false;
}

View File

@ -51,6 +51,7 @@ namespace unitree_guide_controller {
ctrl_comp_.robot_model_.update();
ctrl_comp_.wave_generator_.update();
ctrl_comp_.estimator_.update();
if (mode_ == FSMMode::NORMAL) {
@ -114,6 +115,8 @@ namespace unitree_guide_controller {
get_node()->get_parameter("update_rate", ctrl_comp_.frequency_);
RCLCPP_INFO(get_node()->get_logger(), "Controller Manager Update Rate: %d Hz", ctrl_comp_.frequency_);
ctrl_comp_.wave_generator_.init(0.45, 0.5, Vec4(0, 0.5, 0.5, 0));
return CallbackReturn::SUCCESS;
}
@ -142,6 +145,7 @@ namespace unitree_guide_controller {
state_list_.swingTest = std::make_shared<StateSwingTest>(ctrl_comp_);
state_list_.freeStand = std::make_shared<StateFreeStand>(ctrl_comp_);
state_list_.balanceTest = std::make_shared<StateBalanceTest>(ctrl_comp_);
state_list_.trotting = std::make_shared<StateTrotting>(ctrl_comp_);
// Initialize FSM
current_state_ = state_list_.passive;
@ -186,8 +190,8 @@ namespace unitree_guide_controller {
return state_list_.fixedStand;
case FSMStateName::FREESTAND:
return state_list_.freeStand;
// case FSMStateName::TROTTING:
// return state_list_.trotting;
case FSMStateName::TROTTING:
return state_list_.trotting;
case FSMStateName::SWINGTEST:
return state_list_.swingTest;
case FSMStateName::BALANCETEST:

View File

@ -38,7 +38,7 @@ void BalanceCtrl::init(const QuadrupedRobot &robot) {
}
Vec34 BalanceCtrl::calF(const Vec3 &ddPcd, const Vec3 &dWbd, const RotMat &rot_matrix,
const Vec34 &feet_pos_2_body, const std::vector<int> &contact) {
const Vec34 &feet_pos_2_body, const VecInt4 &contact) {
calMatrixA(feet_pos_2_body, rot_matrix);
calVectorBd(ddPcd, dWbd, rot_matrix);
calConstraints(contact);
@ -64,7 +64,7 @@ void BalanceCtrl::calVectorBd(const Vec3 &ddPcd, const Vec3 &dWbd, const RotMat
bd_.tail(3) = rotM * Ib_ * rotM.transpose() * dWbd;
}
void BalanceCtrl::calConstraints(const std::vector<int> &contact) {
void BalanceCtrl::calConstraints(const VecInt4 &contact) {
int contactLegNum = 0;
for (int i(0); i < 4; ++i) {
if (contact[i] == 1) {

View File

@ -0,0 +1,56 @@
//
// Created by biao on 24-9-18.
//
#include "unitree_guide_controller/gait/FeetEndCtrl.h"
#include "unitree_guide_controller/control/CtrlComponent.h"
FeetEndCtrl::FeetEndCtrl(CtrlComponent &ctrl_component) : ctrl_component_(ctrl_component),
robot_model_(ctrl_component.robot_model_),
estimator_(ctrl_component.estimator_) {
k_x_ = 0.005;
k_y_ = 0.005;
k_yaw_ = 0.005;
}
void FeetEndCtrl::init() {
t_stance_ = ctrl_component_.wave_generator_.get_t_stance();
t_swing_ = ctrl_component_.wave_generator_.get_t_swing();
Vec34 feet_pos_body = estimator_.getFeetPos2Body();
for (int i(0); i < 4; ++i) {
feet_radius_(i) =
sqrt(pow(feet_pos_body(0, i), 2) + pow(feet_pos_body(1, i), 2));
feet_init_angle_(i) = atan2(feet_pos_body(1, i), feet_pos_body(0, i));
}
}
Vec3 FeetEndCtrl::calcFootPos(const int index, Vec2 vxy_goal_global, const double d_yaw_global, const double phase) {
Vec3 body_vel_global = estimator_.getVelocity();
Vec3 next_step;
next_step(0) = body_vel_global(0) * (1 - phase) * t_swing_ +
body_vel_global(0) * t_stance_ / 2 +
k_x_ * (body_vel_global(0) - vxy_goal_global(0));
next_step(1) = body_vel_global(1) * (1 - phase) * t_swing_ +
body_vel_global(1) * t_stance_ / 2 +
k_y_ * (body_vel_global(1) - vxy_goal_global(1));
next_step(2) = 0;
const double yaw = estimator_.getYaw();
const double d_yaw = estimator_.getDYaw();
const double next_yaw = d_yaw * (1 - phase) * t_swing_ + d_yaw * t_stance_ / 2 +
k_yaw_ * (d_yaw_global - d_yaw);
next_step(0) +=
feet_radius_(index) * cos(yaw + feet_init_angle_(index) + next_yaw);
next_step(1) +=
feet_radius_(index) * sin(yaw + feet_init_angle_(index) + next_yaw);
Vec3 foot_pos = estimator_.getPosition() + next_step;
foot_pos(2) = 0.0;
return foot_pos;
}

View File

@ -1,14 +0,0 @@
//
// Created by biao on 24-9-18.
//
#include "unitree_guide_controller/gait/FootEndCtrl.h"
FootEndCtrl::FootEndCtrl() {
k_x_ = 0.005;
k_y_ = 0.005;
k_yaw_ = 0.005;
}
Vec3 FootEndCtrl::calcFootPos(int index, Vec2 vxy_goal_global, double d_yaw_global, double phase) {
}

View File

@ -3,3 +3,92 @@
//
#include "unitree_guide_controller/gait/GaitGenerator.h"
#include <utility>
#include "unitree_guide_controller/control/CtrlComponent.h"
GaitGenerator::GaitGenerator(CtrlComponent &ctrl_component) : estimator_(ctrl_component.estimator_),
feet_end_ctrl_(ctrl_component),
wave_generator_(ctrl_component.wave_generator_) {
first_run_ = true;
}
void GaitGenerator::setGait(Vec2 vxy_goal_global, const double d_yaw_goal, const double gait_height) {
vxy_goal_ = std::move(vxy_goal_global);
d_yaw_goal_ = d_yaw_goal;
gait_height_ = gait_height;
}
void GaitGenerator::run(Vec34 &feet_pos, Vec34 &feet_vel) {
if (first_run_) {
start_p_ = estimator_.getFeetPos();
first_run_ = false;
}
for (int i = 0; i < 4; i++) {
if (wave_generator_.contact_(i) == 1) {
// foot contact the ground
if (wave_generator_.phase_(i) < 0.5) {
start_p_.col(i) = estimator_.getFootPos(i);
}
feet_pos.col(i) = start_p_.col(i);
feet_vel.col(i).setZero();
} else {
// foot not contact, swing
end_p_.col(i) = feet_end_ctrl_.calcFootPos(i, vxy_goal_, d_yaw_goal_, wave_generator_.phase_(i));
feet_pos.col(i) = getFootPos(i);
feet_vel.col(i) = getFootVel(i);
}
}
}
void GaitGenerator::restart() {
first_run_ = true;
vxy_goal_.setZero();
feet_end_ctrl_.init();
}
Vec3 GaitGenerator::getFootPos(const int i) {
Vec3 foot_pos;
foot_pos(0) =
cycloidXYPosition(start_p_.col(i)(0), end_p_.col(i)(0), wave_generator_.phase_(i));
foot_pos(1) =
cycloidXYPosition(start_p_.col(i)(1), end_p_.col(i)(1), wave_generator_.phase_(i));
foot_pos(2) = cycloidZPosition(start_p_.col(i)(2), gait_height_, wave_generator_.phase_(i));
return foot_pos;
}
Vec3 GaitGenerator::getFootVel(const int i) {
Vec3 foot_vel;
foot_vel(0) =
cycloidXYVelocity(start_p_.col(i)(0), end_p_.col(i)(0), wave_generator_.phase_(i));
foot_vel(1) =
cycloidXYVelocity(start_p_.col(i)(1), end_p_.col(i)(1), wave_generator_.phase_(i));
foot_vel(2) = cycloidZVelocity(gait_height_, wave_generator_.phase_(i));
return foot_vel;
}
double GaitGenerator::cycloidXYPosition(const double startXY, const double endXY, const double phase) {
const double phase_pi = 2 * M_PI * phase;
return (endXY - startXY) * (phase_pi - sin(phase_pi)) / (2 * M_PI) + startXY;
}
double GaitGenerator::cycloidZPosition(const double startZ, const double height, const double phase) {
const double phase_pi = 2 * M_PI * phase;
return height * (1 - cos(phase_pi)) / 2 + startZ;
}
double GaitGenerator::cycloidXYVelocity(const double startXY, const double endXY, const double phase) const {
const double phase_pi = 2 * M_PI * phase;
return (endXY - startXY) * (1 - cos(phase_pi)) / wave_generator_.get_t_swing();
}
double GaitGenerator::cycloidZVelocity(const double height, const double phase) const {
const double phase_pi = 2 * M_PI * phase;
return height * M_PI * sin(phase_pi) / wave_generator_.get_t_swing();
}

View File

@ -12,6 +12,7 @@ WaveGenerator::WaveGenerator() {
phase_past_ << 0.5, 0.5, 0.5, 0.5;
contact_past_.setZero();
status_past_ = WaveStatus::SWING_ALL;
status_ = WaveStatus::SWING_ALL;
}
void WaveGenerator::init(const double period, const double st_ratio, const Vec4 &bias) {
@ -35,18 +36,18 @@ void WaveGenerator::init(const double period, const double st_ratio, const Vec4
start_t_ = getSystemTime();
}
auto WaveGenerator::calculate(Vec4 &phase_result, VecInt4 &contact_result, const WaveStatus status) -> void {
calcWave(phase_, contact_, status);
auto WaveGenerator::update() -> void {
calcWave(phase_, contact_, status_);
if (status != status_past_) {
if (status_ != status_past_) {
if (switch_status_.sum() == 0) {
switch_status_.setOnes();
}
calcWave(phase_past_, contact_past_, status_past_);
if (status == WaveStatus::STANCE_ALL && status_past_ == WaveStatus::SWING_ALL) {
if (status_ == WaveStatus::STANCE_ALL && status_past_ == WaveStatus::SWING_ALL) {
contact_past_.setOnes();
} else if (status == WaveStatus::SWING_ALL && status_past_ == WaveStatus::STANCE_ALL) {
} else if (status_ == WaveStatus::SWING_ALL && status_past_ == WaveStatus::STANCE_ALL) {
contact_past_.setZero();
}
}
@ -61,12 +62,9 @@ auto WaveGenerator::calculate(Vec4 &phase_result, VecInt4 &contact_result, const
}
}
if (switch_status_.sum() == 0) {
status_past_ = status;
status_past_ = status_;
}
}
phase_result = phase_;
contact_result = contact_;
}
void WaveGenerator::calcWave(Vec4 &phase, VecInt4 &contact, const WaveStatus status) {

View File

@ -42,6 +42,26 @@ std::vector<KDL::JntArray> QuadrupedRobot::getQ(const std::vector<KDL::Frame> &p
return result;
}
Vec12 QuadrupedRobot::getQ(const Vec34 &vecP) const {
Vec12 q;
for (int i(0); i < 4; ++i) {
KDL::Frame frame;
frame.p = KDL::Vector(vecP.col(i)[0], vecP.col(i)[1], vecP.col(i)[2]);
q.segment(3 * i, 3) = robot_legs_[i]->calcQ(frame, current_joint_pos_[i]).data;
}
return q;
}
Vec12 QuadrupedRobot::getQd(const std::vector<KDL::Frame> &pos, const Vec34 &vel) {
Vec12 qd;
std::vector<KDL::JntArray> q = getQ(pos);
for (int i(0); i < 4; ++i) {
Mat3 jacobian = robot_legs_[i]->calcJaco(q[i]).data.topRows(3);
qd.segment(3 * i, 3) = jacobian.inverse() * vel.col(i);
}
return qd;
}
std::vector<KDL::Frame> QuadrupedRobot::getFeet2BPositions() const {
std::vector<KDL::Frame> result;
result.resize(4);