tried to add balance test

This commit is contained in:
Huang Zhenbiao 2024-09-16 21:15:34 +08:00
parent 028b7b52b1
commit 5eaf8e1e17
19 changed files with 732 additions and 104 deletions

View File

@ -5,6 +5,7 @@ if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic) add_compile_options(-Wall -Wextra -Wpedantic)
endif () endif ()
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CONTROLLER_INCLUDE_DEPENDS set(CONTROLLER_INCLUDE_DEPENDS
@ -32,12 +33,14 @@ add_library(${PROJECT_NAME} SHARED
src/FSM/StateFixedStand.cpp src/FSM/StateFixedStand.cpp
src/FSM/StateSwingTest.cpp src/FSM/StateSwingTest.cpp
src/FSM/StateFreeStand.cpp src/FSM/StateFreeStand.cpp
src/FSM/StateBalanceTest.cpp
src/robot/QuadrupedRobot.cpp src/robot/QuadrupedRobot.cpp
src/robot/RobotLeg.cpp src/robot/RobotLeg.cpp
src/control/Estimator.cpp src/control/Estimator.cpp
src/control/LowPassFilter.cpp src/control/LowPassFilter.cpp
src/control/BalanceCtrl.cpp
src/quadProgpp/Array.cc src/quadProgpp/Array.cc
src/quadProgpp/QuadProg++.cc src/quadProgpp/QuadProg++.cc

View File

@ -0,0 +1,43 @@
//
// Created by tlab-uav on 24-9-16.
//
#ifndef STATEBALANCETEST_H
#define STATEBALANCETEST_H
#include "FSMState.h"
class StateBalanceTest final : public FSMState {
public:
explicit StateBalanceTest(CtrlComponent ctrlComp);
void enter() override;
void run() override;
void exit() override;
FSMStateName checkChange() override;
private:
void calcTorque();
KDL::Vector pcd_;
KDL::Vector pcdInit_;
KDL::Rotation Rd_;
KDL::Rotation RdInit_;
KDL::Vector pose_body_, vel_body_;
double kp_w_;
Mat3 Kp_p_, Kd_p_, Kd_w_;
Vec3 _ddPcd, _dWbd;
float _xMax, _xMin;
float _yMax, _yMin;
float _zMax, _zMin;
float _yawMax, _yawMin;
};
#endif //STATEBALANCETEST_H

View File

@ -10,6 +10,7 @@
#include <unitree_guide_controller/FSM/FSMState.h> #include <unitree_guide_controller/FSM/FSMState.h>
#include <unitree_guide_controller/common/enumClass.h> #include <unitree_guide_controller/common/enumClass.h>
#include "FSM/StateBalanceTest.h"
#include "FSM/StateFixedDown.h" #include "FSM/StateFixedDown.h"
#include "FSM/StateFixedStand.h" #include "FSM/StateFixedStand.h"
#include "FSM/StateFreeStand.h" #include "FSM/StateFreeStand.h"
@ -25,6 +26,7 @@ namespace unitree_guide_controller {
std::shared_ptr<StateFreeStand> freeStand; std::shared_ptr<StateFreeStand> freeStand;
std::shared_ptr<StateSwingTest> swingTest; std::shared_ptr<StateSwingTest> swingTest;
std::shared_ptr<StateBalanceTest> balanceTest;
}; };
class UnitreeGuideController final : public controller_interface::ControllerInterface { class UnitreeGuideController final : public controller_interface::ControllerInterface {

View File

@ -33,5 +33,37 @@ T windowFunc(const T x, const T windowRatio, const T xRange = 1.0,
return yRange; return yRange;
} }
inline Eigen::Matrix3d skew(const KDL::Vector &vec) {
Eigen::Matrix3d skewMat;
skewMat << 0, -vec.z(), vec.y(),
vec.z(), 0, -vec.x(),
-vec.y(), vec.x(), 0;
return skewMat;
}
inline Vec3 rotationToExp(const KDL::Rotation &rotation) {
auto rm = Eigen::Matrix3d(rotation.data);
double cosValue = rm.trace() / 2.0 - 1 / 2.0;
if (cosValue > 1.0f) {
cosValue = 1.0f;
} else if (cosValue < -1.0f) {
cosValue = -1.0f;
}
double angle = acos(cosValue);
Vec3 exp;
if (fabs(angle) < 1e-5) {
exp = Vec3(0, 0, 0);
} else if (fabs(angle - M_PI) < 1e-5) {
exp = angle * Vec3(rm(0, 0) + 1, rm(0, 1), rm(0, 2)) /
sqrt(2 * (1 + rm(0, 0)));
} else {
exp = angle / (2.0f * sin(angle)) *
Vec3(rm(2, 1) - rm(1, 2), rm(0, 2) - rm(2, 0), rm(1, 0) - rm(0, 1));
}
return exp;
}
#endif //MATHTOOLS_H #endif //MATHTOOLS_H

View File

@ -10,58 +10,58 @@
/******** Vector ********/ /******** Vector ********/
/************************/ /************************/
// 2x1 Vector // 2x1 Vector
using Vec2 = typename Eigen::Matrix<double, 2, 1>; using Vec2 = Eigen::Matrix<double, 2, 1>;
// 3x1 Vector // 3x1 Vector
using Vec3 = typename Eigen::Matrix<double, 3, 1>; using Vec3 = Eigen::Matrix<double, 3, 1>;
// 4x1 Vector // 4x1 Vector
using Vec4 = typename Eigen::Matrix<double, 4, 1>; using Vec4 = Eigen::Matrix<double, 4, 1>;
// 6x1 Vector // 6x1 Vector
using Vec6 = typename Eigen::Matrix<double, 6, 1>; using Vec6 = Eigen::Matrix<double, 6, 1>;
// Quaternion // Quaternion
using Quat = typename Eigen::Matrix<double, 4, 1>; using Quat = Eigen::Matrix<double, 4, 1>;
// 4x1 Integer Vector // 4x1 Integer Vector
using VecInt4 = typename Eigen::Matrix<int, 4, 1>; using VecInt4 = Eigen::Matrix<int, 4, 1>;
// 12x1 Vector // 12x1 Vector
using Vec12 = typename Eigen::Matrix<double, 12, 1>; using Vec12 = Eigen::Matrix<double, 12, 1>;
// 18x1 Vector // 18x1 Vector
using Vec18 = typename Eigen::Matrix<double, 18, 1>; using Vec18 = Eigen::Matrix<double, 18, 1>;
// Dynamic Length Vector // Dynamic Length Vector
using VecX = typename Eigen::Matrix<double, Eigen::Dynamic, 1>; using VecX = Eigen::Matrix<double, Eigen::Dynamic, 1>;
/************************/ /************************/
/******** Matrix ********/ /******** Matrix ********/
/************************/ /************************/
// Rotation Matrix // Rotation Matrix
using RotMat = typename Eigen::Matrix<double, 3, 3>; using RotMat = Eigen::Matrix<double, 3, 3>;
// Homogenous Matrix // Homogenous Matrix
using HomoMat = typename Eigen::Matrix<double, 4, 4>; using HomoMat = Eigen::Matrix<double, 4, 4>;
// 2x2 Matrix // 2x2 Matrix
using Mat2 = typename Eigen::Matrix<double, 2, 2>; using Mat2 = Eigen::Matrix<double, 2, 2>;
// 3x3 Matrix // 3x3 Matrix
using Mat3 = typename Eigen::Matrix<double, 3, 3>; using Mat3 = Eigen::Matrix<double, 3, 3>;
// 3x3 Identity Matrix // 3x3 Identity Matrix
#define I3 Eigen::MatrixXd::Identity(3, 3) #define I3 Eigen::MatrixXd::Identity(3, 3)
// 3x4 Matrix, each column is a 3x1 vector // 3x4 Matrix, each column is a 3x1 vector
using Vec34 = typename Eigen::Matrix<double, 3, 4>; using Vec34 = Eigen::Matrix<double, 3, 4>;
// 6x6 Matrix // 6x6 Matrix
using Mat6 = typename Eigen::Matrix<double, 6, 6>; using Mat6 = Eigen::Matrix<double, 6, 6>;
// 12x12 Matrix // 12x12 Matrix
using Mat12 = typename Eigen::Matrix<double, 12, 12>; using Mat12 = Eigen::Matrix<double, 12, 12>;
// 12x12 Identity Matrix // 12x12 Identity Matrix
#define I12 Eigen::MatrixXd::Identity(12, 12) #define I12 Eigen::MatrixXd::Identity(12, 12)
@ -70,7 +70,7 @@ using Mat12 = typename Eigen::Matrix<double, 12, 12>;
#define I18 Eigen::MatrixXd::Identity(18, 18) #define I18 Eigen::MatrixXd::Identity(18, 18)
// Dynamic Size Matrix // Dynamic Size Matrix
using MatX = typename Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>; using MatX = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;
/************************/ /************************/
/****** Functions *******/ /****** Functions *******/

View File

@ -0,0 +1,48 @@
//
// Created by tlab-uav on 24-9-16.
//
#ifndef BALANCECTRL_H
#define BALANCECTRL_H
#include <kdl/frames.hpp>
#include "unitree_guide_controller/common/mathTypes.h"
class QuadrupedRobot;
class BalanceCtrl {
public:
explicit BalanceCtrl();
~BalanceCtrl() = default;
void init(const QuadrupedRobot &robot);
std::vector<KDL::Vector> calF(const Vec3 &ddPcd, const Vec3 &dWbd, const KDL::Rotation &rotM,
const std::vector<KDL::Vector> &feetPos2B, const std::vector<int> &contact);
private:
void calMatrixA(const std::vector<KDL::Vector> &feetPos2B, const KDL::Rotation &rotM);
void calVectorBd(const Vec3 &ddPcd, const Vec3 &dWbd, const KDL::Rotation &rotM);
void calConstraints(const std::vector<int> &contact);
void solveQP();
Mat12 _G, _W, _U;
Mat6 _S;
Mat3 _Ib;
Vec6 _bd;
KDL::Vector _pcb;
Vec3 _g;
Vec12 _F, _Fprev, _g0T;
double _mass, _alpha, _beta, _fricRatio;
Eigen::MatrixXd _CE, _CI;
Eigen::VectorXd _ce0, _ci0;
Eigen::Matrix<double, 6, 12> _A;
Eigen::Matrix<double, 5, 3> _fricMat;
};
#endif //BALANCECTRL_H

View File

@ -11,6 +11,9 @@
#include <control_input_msgs/msg/inputs.hpp> #include <control_input_msgs/msg/inputs.hpp>
#include <unitree_guide_controller/robot/QuadrupedRobot.h> #include <unitree_guide_controller/robot/QuadrupedRobot.h>
#include "BalanceCtrl.h"
#include "Estimator.h"
struct CtrlComponent { struct CtrlComponent {
std::vector<std::reference_wrapper<hardware_interface::LoanedCommandInterface> > std::vector<std::reference_wrapper<hardware_interface::LoanedCommandInterface> >
joint_effort_command_interface_; joint_effort_command_interface_;
@ -41,7 +44,14 @@ struct CtrlComponent {
QuadrupedRobot default_robot_model_; QuadrupedRobot default_robot_model_;
std::reference_wrapper<QuadrupedRobot> robot_model_; std::reference_wrapper<QuadrupedRobot> robot_model_;
CtrlComponent() : control_inputs_(default_inputs_), robot_model_(default_robot_model_) { Estimator default_estimator_;
std::reference_wrapper<Estimator> estimator_;
BalanceCtrl default_balance_ctrl_;
std::reference_wrapper<BalanceCtrl> balance_ctrl_;
CtrlComponent() : control_inputs_(default_inputs_), robot_model_(default_robot_model_),
estimator_(default_estimator_), balance_ctrl_(default_balance_ctrl_) {
} }
void clear() { void clear() {

View File

@ -4,9 +4,12 @@
#ifndef ESTIMATOR_H #ifndef ESTIMATOR_H
#define ESTIMATOR_H #define ESTIMATOR_H
#include <memory>
#include <eigen3/Eigen/Dense> #include <eigen3/Eigen/Dense>
#include <kdl/frames.hpp> #include <kdl/frames.hpp>
#include "LowPassFilter.h"
struct CtrlComponent; struct CtrlComponent;
class Estimator { class Estimator {
@ -19,49 +22,89 @@ public:
* Get the estimated robot central position * Get the estimated robot central position
* @return robot central position * @return robot central position
*/ */
Eigen::Matrix<double, 3, 1> getPosition() { KDL::Vector getPosition() {
return _xhat.segment(0, 3); return {_xhat(0), _xhat(1), _xhat(2)};
} }
/** /**
* Get the estimated robot central velocity * Get the estimated robot central velocity
* @return robot central velocity * @return robot central velocity
*/ */
Eigen::Matrix<double, 3, 1> getVelocity() { KDL::Vector getVelocity() {
return _xhat.segment(3, 3); return {_xhat(3), _xhat(4), _xhat(5)};
} }
void run( /**
const CtrlComponent &ctrlComp, * Get the estimated foot position in world frame
std::vector<KDL::Frame> feet_poses_, * @param index leg index
std::vector<KDL::Vector> feet_vels_, * @return foot position in world frame
const std::vector<int> &contact, */
const std::vector<double> &phase KDL::Vector getFootPos(const int index) {
); return getPosition() + rotation_ * foot_poses_[index].p;
}
/**
* Get all estimated foot positions in world frame
* @return all foot positions in world frame
*/
std::vector<KDL::Vector> getFootPos() {
std::vector<KDL::Vector> foot_pos;
foot_pos.resize(4);
for (int i = 0; i < 4; i++) {
foot_pos[i] = getFootPos(i);
}
return foot_pos;
}
/**
* Get the estimated foot position in body frame
* @return
*/
std::vector<KDL::Vector> getFootPos2Body() {
std::vector<KDL::Vector> foot_pos;
foot_pos.resize(4);
const KDL::Vector body_pos = getPosition();
for (int i = 0; i < 4; i++) {
foot_pos[i] = getFootPos(i) - body_pos;
}
return foot_pos;
}
KDL::Rotation getRotation() {
return rotation_;
}
KDL::Vector getGyro() {
return gyro_;
}
[[nodiscard]] KDL::Vector getGlobalGyro() const {
return rotation_ * gyro_;
}
void update(const CtrlComponent &ctrlComp);
private: private:
void init();
Eigen::Matrix<double, 18, 1> _xhat; // The state of estimator, position(3)+velocity(3)+feet position(3x4) Eigen::Matrix<double, 18, 1> _xhat; // The state of estimator, position(3)+velocity(3)+feet position(3x4)
Eigen::Matrix<double, 3, 1> _u; // The input of estimator Eigen::Matrix<double, 3, 1> _u; // The input of estimator
Eigen::Matrix<double, 28, 1> _y; // The measurement value of output y Eigen::Matrix<double, 28, 1> _y; // The measurement value of output y
Eigen::Matrix<double, 28, 1> _yhat; // The prediction of output y Eigen::Matrix<double, 28, 1> _yhat; // The prediction of output y
Eigen::Matrix<double, 18, 18> _A; // The transtion matrix of estimator Eigen::Matrix<double, 18, 18> A; // The transtion matrix of estimator
Eigen::Matrix<double, 18, 3> _B; // The input matrix Eigen::Matrix<double, 18, 3> B; // The input matrix
Eigen::Matrix<double, 28, 18> _C; // The output matrix Eigen::Matrix<double, 28, 18> C; // The output matrix
// Covariance Matrix // Covariance Matrix
Eigen::Matrix<double, 18, 18> _P; // Prediction covariance Eigen::Matrix<double, 18, 18> P; // Prediction covariance
Eigen::Matrix<double, 18, 18> _Ppriori; // Priori prediction covariance Eigen::Matrix<double, 18, 18> Ppriori; // Priori prediction covariance
Eigen::Matrix<double, 18, 18> _Q; // Dynamic simulation covariance Eigen::Matrix<double, 18, 18> Q; // Dynamic simulation covariance
Eigen::Matrix<double, 28, 28> _R; // Measurement covariance Eigen::Matrix<double, 28, 28> R; // Measurement covariance
Eigen::Matrix<double, 18, 18> Eigen::Matrix<double, 18, 18>
_QInit; // Initial value of Dynamic simulation covariance QInit; // Initial value of Dynamic simulation covariance
Eigen::Matrix<double, 28, 28> Eigen::Matrix<double, 28, 28>
_RInit; // Initial value of Measurement covariance RInit; // Initial value of Measurement covariance
Eigen::Matrix<double, 18, 1> _Qdig; // adjustable process noise covariance Eigen::Matrix<double, 18, 1> Qdig; // adjustable process noise covariance
Eigen::Matrix<double, 3, 3> _Cu; // The covariance of system input u Eigen::Matrix<double, 3, 3> Cu; // The covariance of system input u
// Output Measurement // Output Measurement
Eigen::Matrix<double, 12, 1> Eigen::Matrix<double, 12, 1>
_feetPos2Body; // The feet positions to body, in the global coordinate _feetPos2Body; // The feet positions to body, in the global coordinate
@ -69,20 +112,25 @@ private:
_feetVel2Body; // The feet velocity to body, in the global coordinate _feetVel2Body; // The feet velocity to body, in the global coordinate
Eigen::Matrix<double, 4, 1> Eigen::Matrix<double, 4, 1>
_feetH; // The Height of each foot, in the global coordinate _feetH; // The Height of each foot, in the global coordinate
Eigen::Matrix<double, 28, 28> _S; // _S = C*P*C.T + R Eigen::Matrix<double, 28, 28> S; // _S = C*P*C.T + R
Eigen::PartialPivLU<Eigen::Matrix<double, 28, 28> > _Slu; // _S.lu() Eigen::PartialPivLU<Eigen::Matrix<double, 28, 28> > Slu; // _S.lu()
Eigen::Matrix<double, 28, 1> _Sy; // _Sy = _S.inv() * (y - yhat) Eigen::Matrix<double, 28, 1> Sy; // _Sy = _S.inv() * (y - yhat)
Eigen::Matrix<double, 28, 18> _Sc; // _Sc = _S.inv() * C Eigen::Matrix<double, 28, 18> Sc; // _Sc = _S.inv() * C
Eigen::Matrix<double, 28, 28> _SR; // _SR = _S.inv() * R Eigen::Matrix<double, 28, 28> SR; // _SR = _S.inv() * R
Eigen::Matrix<double, 28, 18> _STC; // _STC = (_S.transpose()).inv() * C Eigen::Matrix<double, 28, 18> STC; // _STC = (_S.transpose()).inv() * C
Eigen::Matrix<double, 18, 18> _IKC; // _IKC = I - KC Eigen::Matrix<double, 18, 18> IKC; // _IKC = I - KC
KDL::Vector g_; KDL::Vector g_;
double _dt;
std::vector<KDL::Frame> feet_poses_; KDL::Rotation rotation_;
std::vector<KDL::Vector> feet_vels_; KDL::Vector acceleration_;
KDL::Vector gyro_;
std::vector<KDL::Frame> foot_poses_;
std::vector<KDL::Vector> foot_vels_;
std::vector<std::shared_ptr<LowPassFilter> > low_pass_filters_;
double _trust;
double _largeVariance; double _largeVariance;
}; };

View File

@ -30,10 +30,9 @@ public:
/** /**
* Calculate the foot end position based on joint positions * Calculate the foot end position based on joint positions
* @param joint_positions vector of joint positions
* @return vector of foot-end position * @return vector of foot-end position
*/ */
[[nodiscard]] std::vector<KDL::Frame> getFeet2BPositions(const std::vector<KDL::JntArray> &joint_positions) const; [[nodiscard]] std::vector<KDL::Frame> getFeet2BPositions() const;
/** /**
* Calculate the foot end position based on joint positions * Calculate the foot end position based on joint positions
@ -63,22 +62,21 @@ public:
* @param index leg index * @param index leg index
* @return velocity vector * @return velocity vector
*/ */
[[nodiscard]] KDL::Vector getFeet2BVelocities (int index) const; [[nodiscard]] KDL::Vector getFeet2BVelocities(int index) const;
/** /**
* Calculate all foot end velocity * Calculate all foot end velocity
* @return list of foot end velocity * @return list of foot end velocity
*/ */
[[nodiscard]] std::vector<KDL::Vector> getFeet2BVelocities () const; [[nodiscard]] std::vector<KDL::Vector> getFeet2BVelocities() const;
double mass_ = 0;
std::vector<KDL::JntArray> current_joint_pos_; std::vector<KDL::JntArray> current_joint_pos_;
std::vector<KDL::JntArray> current_joint_vel_; std::vector<KDL::JntArray> current_joint_vel_;
void update(const CtrlComponent &ctrlComp); void update(const CtrlComponent &ctrlComp);
private: private:
double mass_ = 0;
std::vector<std::shared_ptr<RobotLeg> > robot_legs_; std::vector<std::shared_ptr<RobotLeg> > robot_legs_;
KDL::Chain fr_chain_; KDL::Chain fr_chain_;

View File

@ -1,6 +1,6 @@
# Unitree Guide Controller # Unitree Guide Controller
This is a ros2-control controller based on unitree guide. This is a ros2-control controller based on unitree guide. The original unitree guide project could be found [here](https://github.com/unitreerobotics/unitree_guide)
```bash ```bash
cd ~/ros2_ws cd ~/ros2_ws

View File

@ -0,0 +1,97 @@
//
// Created by tlab-uav on 24-9-16.
//
#include "unitree_guide_controller/FSM/StateBalanceTest.h"
#include <unitree_guide_controller/common/mathTools.h>
StateBalanceTest::StateBalanceTest(CtrlComponent ctrlComp) : FSMState(FSMStateName::BALANCETEST, "balance test",
std::move(ctrlComp)) {
_xMax = 0.05;
_xMin = -_xMax;
_yMax = 0.05;
_yMin = -_yMax;
_zMax = 0.04;
_zMin = -_zMax;
_yawMax = 20 * M_PI / 180;
_yawMin = -_yawMax;
Kp_p_ = Vec3(150, 150, 150).asDiagonal();
Kd_p_ = Vec3(25, 25, 25).asDiagonal();
kp_w_ = 200;
Kd_w_ = Vec3(30, 30, 30).asDiagonal();
}
void StateBalanceTest::enter() {
pcd_ = ctrlComp_.estimator_.get().getPosition();
pcdInit_ = pcd_;
RdInit_ = ctrlComp_.estimator_.get().getRotation();
}
void StateBalanceTest::run() {
pcd_(0) = pcdInit_(0) + invNormalize(ctrlComp_.control_inputs_.get().ly, _xMin, _xMax);
pcd_(1) = pcdInit_(1) - invNormalize(ctrlComp_.control_inputs_.get().lx, _yMin, _yMax);
pcd_(2) = pcdInit_(2) + invNormalize(ctrlComp_.control_inputs_.get().ry, _zMin, _zMax);
const float yaw = invNormalize(ctrlComp_.control_inputs_.get().rx, _yawMin, _yawMax);
Rd_ = KDL::Rotation::RPY(0, 0, yaw) * RdInit_;
pose_body_ = ctrlComp_.estimator_.get().getPosition();
vel_body_ = ctrlComp_.estimator_.get().getVelocity();
calcTorque();
for (int i = 0; i < 12; i++) {
ctrlComp_.joint_kp_command_interface_[i].get().set_value(0.8);
ctrlComp_.joint_kd_command_interface_[i].get().set_value(0.8);
}
}
void StateBalanceTest::exit() {
}
FSMStateName StateBalanceTest::checkChange() {
switch (ctrlComp_.control_inputs_.get().command) {
case 1:
return FSMStateName::FIXEDDOWN;
case 2:
return FSMStateName::FIXEDSTAND;
default:
return FSMStateName::BALANCETEST;
}
}
void StateBalanceTest::calcTorque() {
// expected body acceleration
_ddPcd = Kp_p_ * Vec3((pcd_ - pose_body_).data) + Kd_p_ * Vec3(
(KDL::Vector(0, 0, 0) - vel_body_).data);
std::cout << "ddPcd: " << Vec3(vel_body_.data) << std::endl;
// expected body angular acceleration
const KDL::Rotation B2G_RotMat = ctrlComp_.estimator_.get().getRotation();
const KDL::Rotation G2B_RotMat = B2G_RotMat.Inverse();
_dWbd = kp_w_ * rotationToExp(Rd_ * G2B_RotMat) +
Kd_w_ * (Vec3(0, 0, 0) - Vec3(ctrlComp_.estimator_.get().getGlobalGyro().data));
// calculate foot force
const std::vector contact(4, 1);
const std::vector<KDL::Vector> foot_force = ctrlComp_.balance_ctrl_.get().calF(_ddPcd, _dWbd, B2G_RotMat,
ctrlComp_.estimator_.get().
getFootPos2Body(), contact);
std::vector<KDL::JntArray> current_joints = ctrlComp_.robot_model_.get().current_joint_pos_;
for (int i = 0; i < 4; i++) {
const auto &foot = foot_force[i];
std::cout << "foot_force: " << foot.x() << "," << foot.y() << "," << foot.z() << std::endl;
const KDL::Wrench wrench0(G2B_RotMat * foot, KDL::Vector::Zero());
const KDL::Wrenches wrenches(1, wrench0); // 创建一个包含 wrench0 的容器
KDL::JntArray torque0 = ctrlComp_.robot_model_.get().getTorque(wrenches, i);
for (int j = 0; j < 3; j++) {
ctrlComp_.joint_effort_command_interface_[i * 3 + j].get().set_value(torque0(j));
ctrlComp_.joint_position_command_interface_[i * 3 + j].get().set_value(current_joints[i](j));
}
}
}

View File

@ -46,6 +46,8 @@ FSMStateName StateFixedStand::checkChange() {
return FSMStateName::FREESTAND; return FSMStateName::FREESTAND;
case 9: case 9:
return FSMStateName::SWINGTEST; return FSMStateName::SWINGTEST;
case 10:
return FSMStateName::BALANCETEST;
default: default:
return FSMStateName::FIXEDSTAND; return FSMStateName::FIXEDSTAND;
} }

View File

@ -22,10 +22,9 @@ void StateFreeStand::enter() {
ctrlComp_.joint_kp_command_interface_[i].get().set_value(180); ctrlComp_.joint_kp_command_interface_[i].get().set_value(180);
ctrlComp_.joint_kd_command_interface_[i].get().set_value(5); ctrlComp_.joint_kd_command_interface_[i].get().set_value(5);
} }
ctrlComp_.robot_model_.get().update(ctrlComp_);
init_joint_pos_ = ctrlComp_.robot_model_.get().current_joint_pos_; init_joint_pos_ = ctrlComp_.robot_model_.get().current_joint_pos_;
init_foot_pos_ = ctrlComp_.robot_model_.get().getFeet2BPositions(init_joint_pos_); init_foot_pos_ = ctrlComp_.robot_model_.get().getFeet2BPositions();
fr_init_pos_ = init_foot_pos_[0]; fr_init_pos_ = init_foot_pos_[0];

View File

@ -29,10 +29,9 @@ void StateSwingTest::enter() {
Kp = KDL::Vector(20, 20, 50); Kp = KDL::Vector(20, 20, 50);
Kd = KDL::Vector(5, 5, 20); Kd = KDL::Vector(5, 5, 20);
ctrlComp_.robot_model_.get().update(ctrlComp_);
init_joint_pos_ = ctrlComp_.robot_model_.get().current_joint_pos_; init_joint_pos_ = ctrlComp_.robot_model_.get().current_joint_pos_;
init_foot_pos_ = ctrlComp_.robot_model_.get().getFeet2BPositions();
init_foot_pos_ = ctrlComp_.robot_model_.get().getFeet2BPositions(init_joint_pos_);
target_foot_pos_ = init_foot_pos_; target_foot_pos_ = init_foot_pos_;
fr_init_pos_ = init_foot_pos_[0]; fr_init_pos_ = init_foot_pos_[0];
fr_goal_pos_ = fr_init_pos_; fr_goal_pos_ = fr_init_pos_;

View File

@ -41,6 +41,19 @@ namespace unitree_guide_controller {
controller_interface::return_type UnitreeGuideController:: controller_interface::return_type UnitreeGuideController::
update(const rclcpp::Time &time, const rclcpp::Duration &period) { update(const rclcpp::Time &time, const rclcpp::Duration &period) {
// auto now = std::chrono::steady_clock::now();
// std::chrono::duration<double> time_diff = now - last_update_time_;
// last_update_time_ = now;
//
// // Calculate the frequency
// update_frequency_ = 1.0 / time_diff.count();
// RCLCPP_INFO(get_node()->get_logger(), "Update frequency: %f Hz", update_frequency_);
ctrl_comp_.robot_model_.get().update(ctrl_comp_);
ctrl_comp_.estimator_.get().update(ctrl_comp_);
if (mode_ == FSMMode::NORMAL) { if (mode_ == FSMMode::NORMAL) {
current_state_->run(); current_state_->run();
next_state_name_ = current_state_->checkChange(); next_state_name_ = current_state_->checkChange();
@ -72,7 +85,6 @@ namespace unitree_guide_controller {
// imu sensor // imu sensor
imu_name_ = auto_declare<std::string>("imu_name", imu_name_); imu_name_ = auto_declare<std::string>("imu_name", imu_name_);
imu_interface_types_ = auto_declare<std::vector<std::string> >("imu_interfaces", state_interface_types_); imu_interface_types_ = auto_declare<std::vector<std::string> >("imu_interfaces", state_interface_types_);
} catch (const std::exception &e) { } catch (const std::exception &e) {
fprintf(stderr, "Exception thrown during init stage with message: %s \n", e.what()); fprintf(stderr, "Exception thrown during init stage with message: %s \n", e.what());
return controller_interface::CallbackReturn::ERROR; return controller_interface::CallbackReturn::ERROR;
@ -96,8 +108,8 @@ namespace unitree_guide_controller {
robot_description_subscription_ = get_node()->create_subscription<std_msgs::msg::String>( robot_description_subscription_ = get_node()->create_subscription<std_msgs::msg::String>(
"~/robot_description", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local(), "~/robot_description", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local(),
[this](const std_msgs::msg::String::SharedPtr msg) { [this](const std_msgs::msg::String::SharedPtr msg) {
// Handle message
ctrl_comp_.robot_model_.get().init(msg->data); ctrl_comp_.robot_model_.get().init(msg->data);
ctrl_comp_.balance_ctrl_.get().init(ctrl_comp_.robot_model_.get());
}); });
get_node()->get_parameter("update_rate", ctrl_comp_.frequency_); get_node()->get_parameter("update_rate", ctrl_comp_.frequency_);
@ -130,6 +142,7 @@ namespace unitree_guide_controller {
state_list_.fixedStand = std::make_shared<StateFixedStand>(ctrl_comp_); state_list_.fixedStand = std::make_shared<StateFixedStand>(ctrl_comp_);
state_list_.swingTest = std::make_shared<StateSwingTest>(ctrl_comp_); state_list_.swingTest = std::make_shared<StateSwingTest>(ctrl_comp_);
state_list_.freeStand = std::make_shared<StateFreeStand>(ctrl_comp_); state_list_.freeStand = std::make_shared<StateFreeStand>(ctrl_comp_);
state_list_.balanceTest = std::make_shared<StateBalanceTest>(ctrl_comp_);
// Initialize FSM // Initialize FSM
current_state_ = state_list_.passive; current_state_ = state_list_.passive;
@ -178,8 +191,8 @@ namespace unitree_guide_controller {
// return state_list_.trotting; // return state_list_.trotting;
case FSMStateName::SWINGTEST: case FSMStateName::SWINGTEST:
return state_list_.swingTest; return state_list_.swingTest;
// case FSMStateName::BALANCETEST: case FSMStateName::BALANCETEST:
// return state_list_.balanceTest; return state_list_.balanceTest;
default: default:
return state_list_.invalid; return state_list_.invalid;
} }

View File

@ -0,0 +1,153 @@
//
// Created by tlab-uav on 24-9-16.
//
#include "unitree_guide_controller/control/BalanceCtrl.h"
#include <unitree_guide_controller/common/mathTools.h>
#include <unitree_guide_controller/quadProgpp/QuadProg++.hh>
#include <unitree_guide_controller/robot/QuadrupedRobot.h>
BalanceCtrl::BalanceCtrl() {
_mass = 15;
_alpha = 0.001;
_beta = 0.1;
_fricRatio = 0.4;
_g << 0, 0, -9.81;
}
void BalanceCtrl::init(const QuadrupedRobot &robot) {
_mass = robot.mass_;
_pcb = KDL::Vector(0.0, 0.0, 0.0);
_Ib = Vec3(0.0792, 0.2085, 0.2265).asDiagonal();
Vec6 s;
Vec12 w, u;
w << 10, 10, 4, 10, 10, 4, 10, 10, 4, 10, 10, 4;
u << 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3;
s << 20, 20, 50, 450, 450, 450;
_S = s.asDiagonal();
_W = w.asDiagonal();
_U = u.asDiagonal();
_Fprev.setZero();
_fricMat << 1, 0, _fricRatio, -1, 0, _fricRatio, 0, 1, _fricRatio, 0, -1,
_fricRatio, 0, 0, 1;
}
std::vector<KDL::Vector> BalanceCtrl::calF(const Vec3 &ddPcd, const Vec3 &dWbd, const KDL::Rotation &rotM,
const std::vector<KDL::Vector> &feetPos2B, const std::vector<int> &contact) {
calMatrixA(feetPos2B, rotM);
calVectorBd(ddPcd, dWbd, rotM);
calConstraints(contact);
_G = _A.transpose() * _S * _A + _alpha * _W + _beta * _U;
_g0T = -_bd.transpose() * _S * _A - _beta * _Fprev.transpose() * _U;
solveQP();
_Fprev = _F;
std::vector<KDL::Vector> res;
res.resize(4);
for (int i = 0; i < 4; ++i) {
res[i] = KDL::Vector(_F(i * 3), _F(i * 3 + 1), _F(i * 3 + 2));
}
return res;
}
void BalanceCtrl::calMatrixA(const std::vector<KDL::Vector> &feetPos2B, const KDL::Rotation &rotM) {
for (int i = 0; i < 4; ++i) {
_A.block(0, 3 * i, 3, 3) = I3;
KDL::Vector tempVec = feetPos2B[i] - rotM * _pcb;
_A.block(3, 3 * i, 3, 3) = skew(tempVec);
}
}
void BalanceCtrl::calVectorBd(const Vec3 &ddPcd, const Vec3 &dWbd, const KDL::Rotation &rotM) {
_bd.head(3) = _mass * (ddPcd - _g);
_bd.tail(3) = Eigen::Matrix3d(rotM.data) * _Ib * Eigen::Matrix3d(rotM.data).transpose() *
dWbd;
}
void BalanceCtrl::calConstraints(const std::vector<int> &contact) {
int contactLegNum = 0;
for (int i(0); i < 4; ++i) {
if (contact[i] == 1) {
contactLegNum += 1;
}
}
_CI.resize(5 * contactLegNum, 12);
_ci0.resize(5 * contactLegNum);
_CE.resize(3 * (4 - contactLegNum), 12);
_ce0.resize(3 * (4 - contactLegNum));
_CI.setZero();
_ci0.setZero();
_CE.setZero();
_ce0.setZero();
int ceID = 0;
int ciID = 0;
for (int i(0); i < 4; ++i) {
if (contact[i] == 1) {
_CI.block(5 * ciID, 3 * i, 5, 3) = _fricMat;
++ciID;
} else {
_CE.block(3 * ceID, 3 * i, 3, 3) = I3;
++ceID;
}
}
}
void BalanceCtrl::solveQP() {
const int n = _F.size();
const int m = _ce0.size();
const int p = _ci0.size();
quadprogpp::Matrix<double> G, CE, CI;
quadprogpp::Vector<double> g0, ce0, ci0, x;
G.resize(n, n);
CE.resize(n, m);
CI.resize(n, p);
g0.resize(n);
ce0.resize(m);
ci0.resize(p);
x.resize(n);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
G[i][j] = _G(i, j);
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
CE[i][j] = (_CE.transpose())(i, j);
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < p; ++j) {
CI[i][j] = (_CI.transpose())(i, j);
}
}
for (int i = 0; i < n; ++i) {
g0[i] = _g0T[i];
}
for (int i = 0; i < m; ++i) {
ce0[i] = _ce0[i];
}
for (int i = 0; i < p; ++i) {
ci0[i] = _ci0[i];
}
solve_quadprog(G, g0, CE, ce0, CI, ci0, x);
for (int i = 0; i < n; ++i) {
_F[i] = x[i];
}
}

View File

@ -4,48 +4,228 @@
#include "unitree_guide_controller/control/Estimator.h" #include "unitree_guide_controller/control/Estimator.h"
#include "unitree_guide_controller/control/CtrlComponent.h" #include "unitree_guide_controller/control/CtrlComponent.h"
#include <unitree_guide_controller/common/mathTools.h> #include "unitree_guide_controller/common/mathTools.h"
#define I3 Eigen::MatrixXd::Identity(3, 3)
// 12x12 Identity Matrix
#define I12 Eigen::MatrixXd::Identity(12, 12)
// 18x18 Identity Matrix
#define I18 Eigen::MatrixXd::Identity(18, 18)
Estimator::Estimator() { Estimator::Estimator() {
g_ = KDL::Vector(0, 0, -9.81); g_ = KDL::Vector(0, 0, -9.81);
_dt = 0.002;
_largeVariance = 100;
_xhat.setZero();
_u.setZero();
A.setZero();
A.block(0, 0, 3, 3) = I3;
A.block(0, 3, 3, 3) = I3 * _dt;
A.block(3, 3, 3, 3) = I3;
A.block(6, 6, 12, 12) = I12;
B.setZero();
B.block(3, 0, 3, 3) = I3 * _dt;
C.setZero();
C.block(0, 0, 3, 3) = -I3;
C.block(3, 0, 3, 3) = -I3;
C.block(6, 0, 3, 3) = -I3;
C.block(9, 0, 3, 3) = -I3;
C.block(12, 3, 3, 3) = -I3;
C.block(15, 3, 3, 3) = -I3;
C.block(18, 3, 3, 3) = -I3;
C.block(21, 3, 3, 3) = -I3;
C.block(0, 6, 12, 12) = I12;
C(24, 8) = 1;
C(25, 11) = 1;
C(26, 14) = 1;
C(27, 17) = 1;
P.setIdentity();
P = _largeVariance * P;
RInit << 0.008, 0.012, -0.000, -0.009, 0.012, 0.000, 0.009, -0.009, -0.000,
-0.009, -0.009, 0.000, -0.000, 0.000, -0.000, 0.000, -0.000, -0.001,
-0.002, 0.000, -0.000, -0.003, -0.000, -0.001, 0.000, 0.000, 0.000, 0.000,
0.012, 0.019, -0.001, -0.014, 0.018, -0.000, 0.014, -0.013, -0.000,
-0.014, -0.014, 0.001, -0.001, 0.001, -0.001, 0.000, 0.000, -0.001,
-0.003, 0.000, -0.001, -0.004, -0.000, -0.001, 0.000, 0.000, 0.000, 0.000,
-0.000, -0.001, 0.001, 0.001, -0.001, 0.000, -0.000, 0.000, -0.000, 0.001,
0.000, -0.000, 0.000, -0.000, 0.000, 0.000, -0.000, -0.000, 0.000, -0.000,
-0.000, -0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, -0.009, -0.014,
0.001, 0.010, -0.013, 0.000, -0.010, 0.010, 0.000, 0.010, 0.010, -0.000,
0.001, 0.000, 0.000, 0.001, -0.000, 0.001, 0.002, -0.000, 0.000, 0.003,
0.000, 0.001, 0.000, 0.000, 0.000, 0.000, 0.012, 0.018, -0.001, -0.013,
0.018, -0.000, 0.013, -0.013, -0.000, -0.013, -0.013, 0.001, -0.001,
0.000, -0.001, 0.000, 0.001, -0.001, -0.003, 0.000, -0.001, -0.004,
-0.000, -0.001, 0.000, 0.000, 0.000, 0.000, 0.000, -0.000, 0.000, 0.000,
-0.000, 0.001, 0.000, 0.000, -0.000, 0.000, 0.000, -0.000, -0.000, 0.000,
-0.000, 0.000, 0.000, 0.000, -0.000, -0.000, -0.000, -0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 0.000, 0.009, 0.014, -0.000, -0.010, 0.013, 0.000,
0.010, -0.010, -0.000, -0.010, -0.010, 0.000, -0.001, 0.000, -0.001,
0.000, -0.000, -0.001, -0.001, 0.000, -0.000, -0.003, -0.000, -0.001,
0.000, 0.000, 0.000, 0.000, -0.009, -0.013, 0.000, 0.010, -0.013, 0.000,
-0.010, 0.009, 0.000, 0.010, 0.010, -0.000, 0.001, -0.000, 0.000, -0.000,
0.000, 0.001, 0.002, 0.000, 0.000, 0.003, 0.000, 0.001, 0.000, 0.000,
0.000, 0.000, -0.000, -0.000, -0.000, 0.000, -0.000, -0.000, -0.000,
0.000, 0.001, 0.000, 0.000, 0.000, 0.000, -0.000, 0.000, -0.000, 0.000,
-0.000, 0.000, -0.000, 0.000, 0.000, -0.000, -0.000, 0.000, 0.000, 0.000,
0.000, -0.009, -0.014, 0.001, 0.010, -0.013, 0.000, -0.010, 0.010, 0.000,
0.010, 0.010, -0.000, 0.001, 0.000, 0.000, -0.000, -0.000, 0.001, 0.002,
-0.000, 0.000, 0.003, 0.000, 0.001, 0.000, 0.000, 0.000, 0.000, -0.009,
-0.014, 0.000, 0.010, -0.013, 0.000, -0.010, 0.010, 0.000, 0.010, 0.010,
-0.000, 0.001, -0.000, 0.000, -0.000, 0.000, 0.001, 0.002, -0.000, 0.000,
0.003, 0.001, 0.001, 0.000, 0.000, 0.000, 0.000, 0.000, 0.001, -0.000,
-0.000, 0.001, -0.000, 0.000, -0.000, 0.000, -0.000, -0.000, 0.001, 0.000,
-0.000, -0.000, -0.000, 0.000, 0.000, -0.000, 0.000, 0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 0.000, 0.000, -0.000, -0.001, 0.000, 0.001, -0.001,
-0.000, -0.001, 0.001, 0.000, 0.001, 0.001, 0.000, 1.708, 0.048, 0.784,
0.062, 0.042, 0.053, 0.077, 0.001, -0.061, 0.046, -0.019, -0.029, 0.000,
0.000, 0.000, 0.000, 0.000, 0.001, -0.000, 0.000, 0.000, 0.000, 0.000,
-0.000, -0.000, 0.000, -0.000, -0.000, 0.048, 5.001, -1.631, -0.036,
0.144, 0.040, 0.036, 0.016, -0.051, -0.067, -0.024, -0.005, 0.000, 0.000,
0.000, 0.000, -0.000, -0.001, 0.000, 0.000, -0.001, -0.000, -0.001, 0.000,
0.000, 0.000, 0.000, -0.000, 0.784, -1.631, 1.242, 0.057, -0.037, 0.018,
0.034, -0.017, -0.015, 0.058, -0.021, -0.029, 0.000, 0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 0.001, 0.000, 0.000, 0.000, -0.000, -0.000, -0.000,
-0.000, -0.000, 0.062, -0.036, 0.057, 6.228, -0.014, 0.932, 0.059, 0.053,
-0.069, 0.148, 0.015, -0.031, 0.000, 0.000, 0.000, 0.000, -0.000, 0.000,
-0.000, -0.000, 0.001, 0.000, -0.000, 0.000, 0.000, -0.000, 0.000, 0.000,
0.042, 0.144, -0.037, -0.014, 3.011, 0.986, 0.076, 0.030, -0.052, -0.027,
0.057, 0.051, 0.000, 0.000, 0.000, 0.000, -0.001, -0.001, -0.000, 0.001,
-0.001, 0.000, -0.001, 0.001, -0.000, 0.001, 0.001, 0.000, 0.053, 0.040,
0.018, 0.932, 0.986, 0.885, 0.090, 0.044, -0.055, 0.057, 0.051, -0.003,
0.000, 0.000, 0.000, 0.000, -0.002, -0.003, 0.000, 0.002, -0.003, -0.000,
-0.001, 0.002, 0.000, 0.002, 0.002, -0.000, 0.077, 0.036, 0.034, 0.059,
0.076, 0.090, 6.230, 0.139, 0.763, 0.013, -0.019, -0.024, 0.000, 0.000,
0.000, 0.000, 0.000, 0.000, -0.000, -0.000, 0.000, -0.000, 0.000, 0.000,
-0.000, -0.000, -0.000, 0.000, 0.001, 0.016, -0.017, 0.053, 0.030, 0.044,
0.139, 3.130, -1.128, -0.010, 0.131, 0.018, 0.000, 0.000, 0.000, 0.000,
-0.000, -0.001, -0.000, 0.000, -0.001, -0.000, -0.000, 0.000, 0.000,
0.000, 0.000, 0.000, -0.061, -0.051, -0.015, -0.069, -0.052, -0.055,
0.763, -1.128, 0.866, -0.022, -0.053, 0.007, 0.000, 0.000, 0.000, 0.000,
-0.003, -0.004, -0.000, 0.003, -0.004, -0.000, -0.003, 0.003, 0.000,
0.003, 0.003, 0.000, 0.046, -0.067, 0.058, 0.148, -0.027, 0.057, 0.013,
-0.010, -0.022, 2.437, -0.102, 0.938, 0.000, 0.000, 0.000, 0.000, -0.000,
-0.000, 0.000, 0.000, -0.000, 0.000, -0.000, 0.000, -0.000, 0.000, 0.001,
0.000, -0.019, -0.024, -0.021, 0.015, 0.057, 0.051, -0.019, 0.131, -0.053,
-0.102, 4.944, 1.724, 0.000, 0.000, 0.000, 0.000, -0.001, -0.001, 0.000,
0.001, -0.001, 0.000, -0.001, 0.001, -0.000, 0.001, 0.001, 0.000, -0.029,
-0.005, -0.029, -0.031, 0.051, -0.003, -0.024, 0.018, 0.007, 0.938, 1.724,
1.569, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 1.0, 0.000,
0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 1.0, 0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 0.000, 0.000, 1.0, 0.000, 0.000, 0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000,
0.000, 0.000, 0.000, 1.0;
Cu << 268.573, -43.819, -147.211, -43.819, 92.949, 58.082, -147.211, 58.082,
302.120;
QInit = Qdig.asDiagonal();
QInit += B * Cu * B.transpose();
low_pass_filters_.resize(3);
low_pass_filters_[0] = std::make_shared<LowPassFilter>(0.02, 3.0);
low_pass_filters_[1] = std::make_shared<LowPassFilter>(0.02, 3.0);
low_pass_filters_[2] = std::make_shared<LowPassFilter>(0.02, 3.0);
} }
void Estimator::run(const CtrlComponent &ctrlComp, std::vector<KDL::Frame> feet_poses_, void Estimator::update(const CtrlComponent &ctrlComp) {
std::vector<KDL::Vector> feet_vels_, if (ctrlComp.robot_model_.get().mass_ == 0) return;
const std::vector<int> &contact, const std::vector<double> &phase) {
_Q = _QInit; Q = QInit;
_R = _RInit; R = RInit;
foot_poses_ = ctrlComp.robot_model_.get().getFeet2BPositions();
foot_vels_ = ctrlComp.robot_model_.get().getFeet2BVelocities();
_feetH.setZero();
const std::vector contact(4, 1);
const std::vector phase(4, 0.5);
// Adjust the covariance based on foot contact and phase. // Adjust the covariance based on foot contact and phase.
for (int i(0); i < 4; ++i) { for (int i(0); i < 4; ++i) {
if (contact[i] == 0) { if (contact[i] == 0) {
_Q.block(6 + 3 * i, 6 + 3 * i, 3, 3) = _largeVariance * Eigen::MatrixXd::Identity(3, 3); // foot not contact
_R.block(12 + 3 * i, 12 + 3 * i, 3, 3) = _largeVariance * Eigen::MatrixXd::Identity(3, 3); Q.block(6 + 3 * i, 6 + 3 * i, 3, 3) = _largeVariance * Eigen::MatrixXd::Identity(3, 3);
_R(24 + i, 24 + i) = _largeVariance; R.block(12 + 3 * i, 12 + 3 * i, 3, 3) = _largeVariance * Eigen::MatrixXd::Identity(3, 3);
R(24 + i, 24 + i) = _largeVariance;
} else { } else {
_trust = windowFunc(phase[i], 0.2); // foot contact
_Q.block(6 + 3 * i, 6 + 3 * i, 3, 3) = const double trust = windowFunc(phase[i], 0.2);
(1 + (1 - _trust) * _largeVariance) * Q.block(6 + 3 * i, 6 + 3 * i, 3, 3) =
_QInit.block(6 + 3 * i, 6 + 3 * i, 3, 3); (1 + (1 - trust) * _largeVariance) *
_R.block(12 + 3 * i, 12 + 3 * i, 3, 3) = QInit.block(6 + 3 * i, 6 + 3 * i, 3, 3);
(1 + (1 - _trust) * _largeVariance) * R.block(12 + 3 * i, 12 + 3 * i, 3, 3) =
_RInit.block(12 + 3 * i, 12 + 3 * i, 3, 3); (1 + (1 - trust) * _largeVariance) *
_R(24 + i, 24 + i) = RInit.block(12 + 3 * i, 12 + 3 * i, 3, 3);
(1 + (1 - _trust) * _largeVariance) * _RInit(24 + i, 24 + i); R(24 + i, 24 + i) =
(1 + (1 - trust) * _largeVariance) * RInit(24 + i, 24 + i);
} }
_feetPos2Body.segment(3 * i, 3) = Eigen::Map<Eigen::Vector3d>(feet_poses_[i].p.data); _feetPos2Body.segment(3 * i, 3) = Eigen::Map<Eigen::Vector3d>(foot_poses_[i].p.data);
_feetVel2Body.segment(3 * i, 3) = Eigen::Map<Eigen::Vector3d>(feet_vels_[i].data); _feetVel2Body.segment(3 * i, 3) = Eigen::Map<Eigen::Vector3d>(foot_vels_[i].data);
} }
// Acceleration from imu as system input // Acceleration from imu as system input
const KDL::Rotation rotation = KDL::Rotation::Quaternion(ctrlComp.imu_state_interface_[7].get().get_value(), rotation_ = KDL::Rotation::Quaternion(ctrlComp.imu_state_interface_[0].get().get_value(),
ctrlComp.imu_state_interface_[8].get().get_value(), ctrlComp.imu_state_interface_[1].get().get_value(),
ctrlComp.imu_state_interface_[9].get().get_value(), ctrlComp.imu_state_interface_[2].get().get_value(),
ctrlComp.imu_state_interface_[6].get().get_value()); ctrlComp.imu_state_interface_[3].get().get_value());
const KDL::Vector acc(ctrlComp.imu_state_interface_[3].get().get_value(),
ctrlComp.imu_state_interface_[4].get().get_value(), gyro_ = KDL::Vector(ctrlComp.imu_state_interface_[4].get().get_value(),
ctrlComp.imu_state_interface_[5].get().get_value()); ctrlComp.imu_state_interface_[5].get().get_value(),
_u = Eigen::Map<Eigen::Vector3d>((rotation * acc + g_).data); ctrlComp.imu_state_interface_[6].get().get_value());
_xhat = _A * _xhat + _B * _u;
_yhat = _C * _xhat; acceleration_ = KDL::Vector(ctrlComp.imu_state_interface_[7].get().get_value(),
ctrlComp.imu_state_interface_[8].get().get_value(),
ctrlComp.imu_state_interface_[9].get().get_value());
_u = Vec3((rotation_ * acceleration_ + g_).data);
const double *rot_mat = rotation_.data;
std::cout << "Rotation Matrix: " << std::endl;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
std::cout << rot_mat[i * 3 + j] << " ";
}
std::cout << std::endl;
}
_xhat = A * _xhat + B * _u;
_yhat = C * _xhat;
// Update the measurement value
_y << _feetPos2Body, _feetVel2Body, _feetH;
// Update the covariance matrix
Ppriori = A * P * A.transpose() + Q;
S = R + C * Ppriori * C.transpose();
Slu = S.lu();
Sy = Slu.solve(_y - _yhat);
Sc = Slu.solve(C);
SR = Slu.solve(R);
STC = S.transpose().lu().solve(C);
IKC = Eigen::MatrixXd::Identity(18, 18) - Ppriori * C.transpose() * Sc;
// Update the state and covariance matrix
_xhat += Ppriori * C.transpose() * Sy;
P = IKC * Ppriori * IKC.transpose() +
Ppriori * C.transpose() * SR * STC * Ppriori.transpose();
// Using low pass filter to smooth the velocity
low_pass_filters_[0]->addValue(_xhat(3));
low_pass_filters_[1]->addValue(_xhat(4));
low_pass_filters_[2]->addValue(_xhat(5));
_xhat(3) = low_pass_filters_[0]->getValue();
_xhat(4) = low_pass_filters_[1]->getValue();
_xhat(5) = low_pass_filters_[2]->getValue();
} }

View File

@ -42,11 +42,11 @@ std::vector<KDL::JntArray> QuadrupedRobot::getQ(const std::vector<KDL::Frame> &p
return result; return result;
} }
std::vector<KDL::Frame> QuadrupedRobot::getFeet2BPositions(const std::vector<KDL::JntArray> &joint_positions) const { std::vector<KDL::Frame> QuadrupedRobot::getFeet2BPositions() const {
std::vector<KDL::Frame> result; std::vector<KDL::Frame> result;
result.resize(4); result.resize(4);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
result[i] = robot_legs_[i]->calcPEe2B(joint_positions[i]); result[i] = robot_legs_[i]->calcPEe2B(current_joint_pos_[i]);
} }
return result; return result;
} }
@ -80,6 +80,7 @@ std::vector<KDL::Vector> QuadrupedRobot::getFeet2BVelocities() const {
} }
void QuadrupedRobot::update(const CtrlComponent &ctrlComp) { void QuadrupedRobot::update(const CtrlComponent &ctrlComp) {
if (mass_ == 0) return;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
KDL::JntArray pos_array(3); KDL::JntArray pos_array(3);
pos_array(0) = ctrlComp.joint_position_state_interface_[i * 3].get().get_value(); pos_array(0) = ctrlComp.joint_position_state_interface_[i * 3].get().get_value();

View File

@ -50,13 +50,13 @@ unitree_guide_controller:
imu_name: "imu_sensor" imu_name: "imu_sensor"
imu_interfaces: imu_interfaces:
- orientation.x
- orientation.y
- orientation.z
- orientation.w
- angular_velocity.x - angular_velocity.x
- angular_velocity.y - angular_velocity.y
- angular_velocity.z - angular_velocity.z
- linear_acceleration.x - linear_acceleration.x
- linear_acceleration.y - linear_acceleration.y
- linear_acceleration.z - linear_acceleration.z
- orientation.w
- orientation.x
- orientation.y
- orientation.z