Mini Cheetah 代码分析(四)学习编写自己的控制器

一、简单介绍

二、实战,添加控制器流程介绍

一、简单介绍

要添加自己的机器人控制器,在“Cheetah Software/user”下添加一个文件夹,然后在user文件夹中的“CmakeLists.txt”中,将该文件夹目录添加进去。“JPos_Controller”是一个非常简单的控制器示例,以此为模板即可完成自己的控制器编写,其功能是直接控制腿部各个关节的位置。

下边主要对\user\JPos_Controller文件夹下的几个文件进行分析。

CMakeLists.txt
JPosUserParameters.h
JPos_Controller.cpp
JPos_Controller.hpp
main.cpp

1.main.cpp

int main(int argc, char** argv) {
  main_helper(argc, argv, new JPos_Controller());
  return 0;
}

将自己编写的控制器的类JPos_Controller,new一个放在main_helper的参数列表即可,main函数的写法是统一的。

2.JPos_Controller.hpp 控制器主要看JPos_Controller这个类的写法。

JPos_Controller继承于RobotController类,class JPos_Controller:public RobotController

并定义了几个包括初始化的几个函数

    virtual void initializeController(){}

    virtual void runController();

    virtual void updateVisualization(){}

和几个用于加载用户参数的userParameters的功能。

2.JPos_Controller.cpp 实现控制器主要内容

JPos_Controller继承于JPos_Controller::runController()

控制器的“runController”函数将以1 kHz的频率自动调用,从该类中基本可以访问所有数据。

runController定义在\robot\include\RobotController.h中。JPos_Controller类的具体实现如下:

定义3*3矩阵kpMat和kdMat。以common文件夹中Eigen::Matrix<T, 3, 3>为类模板

  Mat3<float> kpMat;
  Mat3<float> kdMat;
  //kpMat << 20, 0, 0, 0, 20, 0, 0, 0, 20;
  //kdMat << 2.1, 0, 0, 0, 2.1, 0, 0, 0, 2.1;

如果使用了用户配置参数,则将用户配置参数赋值给kpMat和kdMat矩阵,按照行顺序依次赋值,userParameters.kp不是矩阵,是个变量。

  kpMat << userParameters.kp, 0, 0, 0,  userParameters.kp, 0, 0, 0,  userParameters.kp;
  kdMat <<  userParameters.kd, 0, 0, 0, userParameters.kd, 0, 0, 0, userParameters.kd;

定义一个计数的迭代器static int iter(0);  ++iter;将每一条腿leg的每一个关节jidx的位置q赋值给_jpos_ini矩阵,采样10次。leg的定义位置

  if(iter < 10){
    for(int leg(0); leg<4; ++leg){
      for(int jidx(0); jidx<3; ++jidx){
        _jpos_ini[3*leg+jidx] = _legController->datas[leg].q[jidx];
      }
    }
  }

设定腿部控制器最大扭矩值为150,并使能腿部驱动。

  _legController->_maxTorque = 150;
  _legController->_legsEnabled = true;

以下部分解释以注释的形式给出。_calibrateEncoders和_zeroEncoders的作用

 if(userParameters.calibrate > 0.4) {//如果calibrate> 0.4,则将值赋给编码器校准
    _legController->_calibrateEncoders = userParameters.calibrate;
  } else {
    if(userParameters.zero > 0.5) {//如果calibrate< 0.4且zero > 0.5,_zeroEncoders为true
      _legController->_zeroEncoders = true;
    } else {//如果calibrate< 0.4且zero < 0.5,_zeroEncoders为false,并开始发送腿部位置指令
      _legController->_zeroEncoders = false;

      for(int leg(0); leg<4; ++leg){
        for(int jidx(0); jidx<3; ++jidx){
          float pos = std::sin(.001f * iter);//pos以sin函数赋值,函数运行频率为1k,sin函数变化周期为2*pi
          _legController->commands[leg].qDes[jidx] = pos;//将pos的值赋给各个关节
          _legController->commands[leg].qdDes[jidx] = 0.;//各个关节角速度为0
          _legController->commands[leg].tauFeedForward[jidx] = userParameters.tau_ff;//各个关节前馈力矩的大小,关节扭矩tau与足端力关系tau=J^T * f,足端力f = inv(J^T) * tau。前馈用于补偿一分部关节力用于计算足端力,实现方法在LegController.cpp中。
        }
        _legController->commands[leg].kpJoint = kpMat;//将设定的pd参数赋给控制器
        _legController->commands[leg].kdJoint = kdMat;
      }
    }
  }

腿部控制器的算法和主要实现方法在LegController.cpp中,是重点内容。

其中加载的userParameters文件和参数对应于仿真最右的面板,即user Control Parameters这些参数。

依据CMakeLists.txt中的编译设定 add_executable(jpos_ctrl main.cpp JPos_Controller.cpp)

(在终端中运行./user/JPos_Controller/jpos_ctrl代替./user/MIT_Controller/mit_ctrl m s,应该就可以运行该控制器,尚未验证,可能需要加上 m s的参数。)——发现并不是这样,直接运行报错,提示如下:

Simulation Error

Control code  has error: Control parameter Kd_body wasn't found in parameter collection user-parameters.

应该是缺少config/×××.yaml文件的对应配置,尝试后未发现匹配的文件。能跑通的同学可以在下面评论,我会更新到正文中。

解决办法在robot/src/HardwareBridge.cpp中,定位到这一句

_userControlParameters->initializeFromYamlFile(THIS_COM "config/mc-mit-ctrl-user-parameters.yaml");

将config/mc-mit-ctrl-user-parameters.yaml更改为c3-jpos-user-parameters.yaml即可。

同时,还有Example_Leg_InvDyn文件夹和MiniCheetahSpi_Controller文件中的控制器例子,可以作为编写自己控制器的模板,也可以选择其中一个进行改动。 

二、实战,添加控制器流程介绍

1.在CMakeLists.txt文件中,添加自己控制器的编译程序

add_executable(mycontroller ${SOURCES})

2.在与CMakeLists.txt文件同级目录下

复制包含main_helper(robot_controller);的文件,并将文件名称命名为mycontroller.cpp,这样编译后就会在同级目录下生成一个mycontroller的可执行文件。

找到新建控制器的一行,点进去MIT_Controller()跳转到MIT_Controller.cpp文件中

RobotController *robot_controller = new MIT_Controller();

在void MIT_Controller::runController() {}函数中找到

_controlFSM->runFSM();

点进去跳转到ControlFSM.cpp文件中,进入到状态机切换管理的函数中,在elseif中添加新的控制器模式,比如

        else if(rc_mode ==RC_mode::MYLOCOMOTION)
        {
            data.controlParameters->control_mode=K_MYLOCOMOTION;

添加是,在SateLists中也进行添加,对应的地方进行debug。

比如在ControFSM.cpp文件中

    statesList.MY_locomotion = new FSM_State_MY_Locomotion<T>(&data);

状态列表里添加一个新的控制器

在FSM_States文件夹下,复制出一组新的controller文件,例如FSM_State_MY_Locomotion.cpp和FSM_State_MY_Locomotion.h,在其中新建一个控制器的类。

class FSM_State_VMWBC_Locomotion : public FSM_State<T> {

public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    FSM_State_VMWBC_Locomotion(ControlFSMData<T>* _controlFSMData);

    // Behavior to be carried out when entering a state
    void onEnter();

    // Run the normal behavior for the state
    void run();

    // Checks for any transition triggers
    FSM_StateName checkTransition();

    // Manages state specific transitions
    TransitionData<T> transition();

    // Behavior to be carried out when exiting a state
    void onExit();
.
.
.
.

}

在FSM_State_MY_Locomotion.cpp中,定义run()函数

template <typename T>
void FSM_State_MY_Locomotion<T>::run() {
    Timer t1;
    LocomotionControlStep();
//    printf("VM_WBC Solve time %f ms\n", t1.getMs());
}

定义LocomotionControlStep();函数,并跑起来控制器的run()函数

void FSM_State_VMWBC_Locomotion<T>::LocomotionControlStep() {
    cVM_WBC->run<T>(*this->_data);
    Vec3<T> pDes_backup[2];
    Vec3<T> vDes_backup[2];
    Mat3<T> Kp_backup[2];
    Mat3<T> Kd_backup[2];

。
。
。
}

最后在run()中编写自己的控制器函数。

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值