精华内容
下载资源
问答
  • 四足机器人步态规划
    2021-12-20 19:04:41

    系列文章目录

    提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
    TODO:写完再整理


    前言

    认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长!

    本文先对步态规划做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章


    提示:以下是本篇文章正文内容

    一、步态规划

    1.步态规划与相位控制的一个总类

    /**
     * 列举步态类型。预先计划的步态已定义。
     * 枚举类型15种
     */
    enum class GaitType
    {
      STAND,              //(1)站立STAND
      STAND_CYCLE,        //(2)站立周期STAND_CYCLE
      STATIC_WALK,        //(3)静态行走STATIC_WALK
      AMBLE,              //(4)慢跑AMBLE
      TROT_WALK,          //(5)快步走TROT_WALK
      TROT,               //(6)对角小跑TROT
      TROT_RUN,           //(7)快跑TROT_RUN
      PACE,               //(8)散步PACE
      BOUND,              //(9)跳步BOUND
      ROTARY_GALLOP,      //(10)旋转跑ROTARY_GALLOP
      TRAVERSE_GALLOP,    //(11)打横跑TRAVERSE_GALLOP
      PRONK,              //(12)俯卧PRONK
      THREE_FOOT,         //(13)三条腿THREE_FOOT
      CUSTOM,             //(14)自定义CUSTOM
      TRANSITION_TO_STAND //(15)过渡到站立TRANSITION_TO_STAND
    };
    
    /**
     * 功能:步态时间信息
     */
    template <typename T>
    struct GaitData
    {
      EIGEN_MAKE_ALIGNED_OPERATOR_NEW
      GaitData() { zero(); }
      void zero();            // 把所有的数据归零
      GaitType _currentGait;  // 当前GaitType
      GaitType _nextGait;     // 下一步GaitType过渡到
      std::string gaitName;   // 步态的名字字符串
    
      //  步态描述符
      T periodTimeNominal;     // 总周期时间
      T initialPhase;          // 初始偏移相位
      T switchingPhaseNominal; // 标称相位切换点
      int overrideable;        // 允许步态参数被覆写
    
      //  启用每只脚的标记
      Eigen::Vector4i gaitEnabled; //  启动步态控制腿
    
      // 基于时间的描述符
      Vec4<T> periodTime;          // 整个步态时间
      Vec4<T> timeStance;          // 总站立时间
      Vec4<T> timeSwing;           // 总摆动时间
      Vec4<T> timeStanceRemaining; // 剩余站立时间
      Vec4<T> timeSwingRemaining;  // 剩余摆动时间
    
      //  阶段基于描述符
      Vec4<T> switchingPhase; // 相切换到swing
      Vec4<T> phaseVariable;  // 每只脚的整体步态阶段
      Vec4<T> phaseOffset;    // 步态相位偏移
      Vec4<T> phaseScale;     // 相对于变量的相位刻度
      Vec4<T> phaseStance;    // 支撑相中相位
      Vec4<T> phaseSwing;     // 摆动相中相位
    
      //  预定的接触状态
      Eigen::Vector4i contactStateScheduled; //  脚的接触状态
      Eigen::Vector4i contactStatePrev;      //  脚的先前接触状态
      Eigen::Vector4i touchdownScheduled;    //  预定的触地事件标志
      Eigen::Vector4i liftoffScheduled;      //  预定离地事件标值
    };
    
    /**
     * 功能:处理步态数据和计划的步伐和摆动。
     */
    template <typename T>
    class GaitScheduler
    {
    public:
      GaitScheduler(MIT_UserParameters *_userParameters, float _dt);   //GaitScheduler的构造函数
      ~GaitScheduler(){};                                              //GaitScheduler的析构函数
    
      void initialize();         //初始化步态调度程序
    
      void step();               //调度程序逻辑的迭代步骤
    
      // 从预定义库创建新步态
      void modifyGait();             //修改步态
      void createGait();             //创建步态
      void calcAuxiliaryGaitData();  //计算辅助步态数据
      void printGaitInfo();          //打印特征信息和当前状态
      GaitData<T> gaitData;          //储存所有步态相关数据
    
      // 自然步态参数
      T period_time_natural = 0.5;         //周期时间
      T switching_phase_natural = 0.5;     //摆动向接触切换点
      T swing_time_natural = 0.25;          //摆动时间
    
    private:
    
      // Quadruped<T>& _quadruped;         //四足动物模型
      MIT_UserParameters *userParameters;  //用户参数
      T dt;                                //控制回路时间步长变化
      T dphase;                            //每一步的相变
      int printNum = 5;                    //选择每隔N次迭代打印信息的频率 N*(0.001s) in simulation time
      int printIter = 0;                   // 跟踪自上次信息打印以来的迭代次数
    };
    
    

    .
    .

    2.步态数据清零(初始化)

    template <typename T>
    void GaitData<T>::zero() 
    {
      // 停止任何步态转换
      _nextGait = _currentGait;
    
      //一般步态描述
      periodTimeNominal = 0.0;      // 总周期
      initialPhase = 0.0;           // 初始相位为0
      switchingPhaseNominal = 0.0;  // 转换触点的法相位
    
      //步态使能
      gaitEnabled = Eigen::Vector4i::Zero();  // 启用增益控制腿
    
      //每只脚启用标志
      periodTime = Vec4<T>::Zero();           // 整体步态周期时间
      timeStance = Vec4<T>::Zero();           // 总站姿时间
      timeSwing = Vec4<T>::Zero();            // 总摆动时间
      timeStanceRemaining = Vec4<T>::Zero();  // 站姿剩余时间
      timeSwingRemaining = Vec4<T>::Zero();   // 剩余摆动时间
    
      //基于相位的描述符
      switchingPhase = Vec4<T>::Zero();  // 切换至摆动的相位
      phaseVariable = Vec4<T>::Zero();   // 每只脚的整体步态阶段
      phaseOffset = Vec4<T>::Zero();     // 发步态相位设置为0
      phaseScale = Vec4<T>::Zero();      // 相对于变量的相位标度
      phaseStance = Vec4<T>::Zero();     // 站姿亚相
      phaseSwing = Vec4<T>::Zero();      // 摆动副相
    
      //计划联系状态
      contactStateScheduled = Eigen::Vector4i::Zero();  //脚的接触状态
      contactStatePrev =
          Eigen::Vector4i::Zero();                      //脚以前的接触状态
      touchdownScheduled = Eigen::Vector4i::Zero();     //预定着陆标志
      liftoffScheduled = Eigen::Vector4i::Zero();       //预定升空标志
    
      //在事件中脚在世界范围内的位置
      posFootTouchdownWorld =
          Mat34<T>::Zero();  //预定起飞时的脚部位置
      posFootLiftoffWorld =
          Mat34<T>::Zero();  // 按计划着陆时的脚部位置
    }
    
    template struct GaitData<double>;
    template struct GaitData<float>;
    
    

    3.步态规划器初始化

    /**
     * 功能:构造函数,设置基本站立步态
     */
    template <typename T>
    GaitScheduler<T>::GaitScheduler() 
    {
      initialize();
    }
    
    /**
     * 功能:初始化步态数据函数
     * 默认创建站立的步态
     */
    template <typename T>
    void GaitScheduler<T>::initialize() 
    {
      std::cout << "[GAIT] Initialize Gait Scheduler" << std::endl;
    
      //(1)开始步态类型设置为站立状态,因为我们用这个最多
      gaitData._currentGait = GaitType::STAND;
    
      //(2)将所有步态数据归零
      gaitData.zero();
    
      //(3)从标称初始值创建步态
      createGait();
      period_time_natural = gaitData.periodTimeNominal;
      switching_phase_natural = gaitData.switchingPhaseNominal;
    }
    

    4.创建一个新的步态【重要】

    功能

    根据仿生的步态参数,设计一个新的四足机器人步态
    【防盗标记–盒子君hzj】

    自己先设计好步态参数,填充进去就能创建一个新的步态

    原理

    (1)根据步态类型的初始化参数预先定义多种步态数据
    步态数据如下:

    (1)步态名称
    (2)步态使能
    (3)步态周期
    (4)初始相位【防盗标记–盒子君hzj】
    (5)切换相位
    (6)相位偏移
    (7)相位范围
    

    步态类型如下

    1)站立步态类型
    2)周期站立步态类型
    3)静态行走步态类型
    4)慢跑步态类型
    5)快走步态类型
    6)小跑步态类型
    7)快跑步态类型
    8)溜步步态类型【防盗标记–盒子君hzj】
    9)跳跃步态类型
    10)自身旋转步态类型
    11)快跑步态类型
    12)冲刺步态类型
    13)三腿运动步态类型
    14)过渡到站立步态类型
    

    (2)根据上面的7个步态类型参数为每只脚设置步态参数
    若步态使能了

    (1)计算每英尺的缩放周期时间
    【每英尺的缩放周期时间=步态周期 /腿的相位范围】
    
    (2)将脚从站姿切换到摆动的阶段
    
    (3)计算偏移量初始化相位变量
    【偏移量初始化相位变量=腿的初始相位+相位偏移】
    
    (4)计算整个步态周期的总站姿时间
    【整个步态周期的总站姿时间=步态周期*站立在步态周期的比例】
    
    (5)计算整个步态周期的总摆动时间
    【整个步态周期的总摆动时间=步态周期*(1-站立在步态周期的比例)】
    

    若步态没有使能

    (1)设置每英尺的缩放周期时间为0
    
    (2)设置将脚从站姿切换到摆动的阶段为0
    
    (3)设置根据偏移量初始化相位变量为0
    
    (4)设置脚的站立时间为0【防盗标记–盒子君hzj】
    
    (5)设置脚的摆动时间很大
    

    .
    .

    代码

    /**
     *功能:根据每个步态的类型和参数创建步态结构函数
     *要创建标准步态,只需定义以下内容:
     *   gaitData.periodTimeNominal
     *   gaitData.switchingPhaseNominal
     *   gaitData.phaseOffset
     * 其余设置为:
     *   gaitData.gaitEnabled << 1, 1, 1, 1;
     *   gaitData.initialPhase = 0.0;
     *   gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
     *
     *这些增加了灵活性,用于非常不规则的步态和过渡。
     */
    template <typename T>
    void GaitScheduler<T>::createGait() 
    {
      // (1)根据步态类型的初始化参数预先定义多种步态数据(1)步态名称、(2)步态使能、(3)步态周期、(4)初始相位、(5)转换相位、(6)相位偏移、(7)相位范围
      switch (gaitData._nextGait) 
      {
        //1)站立步态类型
        case GaitType::STAND:                         //gaitData是一个类,后面的参数都是类内成员
          gaitData.gaitName = "STAND";                //创建步态名称
          gaitData.gaitEnabled << 1, 1, 1, 1;         //步态使能
          gaitData.periodTimeNominal = 10.0;          //步态周期                                      【这个必填】
          gaitData.initialPhase = 0.0;                //腿的初始相位,就是该种步态默认的刚开始的相位
          gaitData.switchingPhaseNominal = 1.0;       //转换相位,腾空相或者支撑相                      【这个必填】
          gaitData.phaseOffset << 0.5, 0.5, 0.5, 0.5; //相位偏移,即人为摆动这条腿的,使该退相位偏移的量  【这个必填】
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;  //相位范围,即腿摆动相位的范围
          break;
    
        //2)周期站立步态类型
        case GaitType::STAND_CYCLE:
          gaitData.gaitName = "STAND_CYCLE";
          gaitData.gaitEnabled << 1, 1, 1, 1;
          gaitData.periodTimeNominal = 1.0;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal = 1.0;
          gaitData.phaseOffset << 0.5, 0.5, 0.5, 0.5;
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
          break;
    
        //3)静态行走步态类型
        case GaitType::STATIC_WALK:
          gaitData.gaitName = "STATIC_WALK";
          gaitData.gaitEnabled << 1, 1, 1, 1;
          gaitData.periodTimeNominal = 1.25;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal = 0.8;
          gaitData.phaseOffset << 0.25, 0.0, 0.75, 0.5;
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
          break;
    
        //4)慢跑步态类型
        case GaitType::AMBLE:
          gaitData.gaitName = "AMBLE";
          gaitData.gaitEnabled << 1, 1, 1, 1;
          gaitData.periodTimeNominal = 1.0;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal = 0.8;
          gaitData.phaseOffset << 0.0, 0.5, 0.25, 0.75;
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
          break;
    
        //5)快走步态类型
        case GaitType::TROT_WALK:
          gaitData.gaitName = "TROT_WALK";
          gaitData.gaitEnabled << 1, 1, 1, 1;
          gaitData.periodTimeNominal = 0.5;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal = 0.6;
          gaitData.phaseOffset << 0.0, 0.5, 0.5, 0.0;
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
          break;
    
        //6)小跑步态类型
        case GaitType::TROT:
          gaitData.gaitName = "TROT";
          gaitData.gaitEnabled << 1, 1, 1, 1;
          gaitData.periodTimeNominal = 0.5;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal = 0.5;
          gaitData.phaseOffset << 0.0, 0.5, 0.5, 0.0;
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
          break;
    
        //7)快跑步态类型
        case GaitType::TROT_RUN:
          gaitData.gaitName = "TROT_RUN";
          gaitData.gaitEnabled << 1, 1, 1, 1;
          gaitData.periodTimeNominal = 0.5;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal = 0.4;
          gaitData.phaseOffset << 0.0, 0.5, 0.5, 0.0;
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
          break;
    
        //8)溜步步态类型
        case GaitType::PACE:
          gaitData.gaitName = "PACE";
          gaitData.gaitEnabled << 1, 1, 1, 1;
          gaitData.periodTimeNominal = 0.5;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal = 0.5;
          gaitData.phaseOffset << 0.0, 0.5, 0.0, 0.5;
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
          break;
    
        //9)跳跃步态类型
        case GaitType::BOUND:
          gaitData.gaitName = "BOUND";
          gaitData.gaitEnabled << 1, 1, 1, 1;
          gaitData.periodTimeNominal = 0.5;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal = 0.5;
          gaitData.phaseOffset << 0.0, 0.0, 0.5, 0.5;
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
          break;
    
        //10)自身旋转步态类型
        case GaitType::ROTARY_GALLOP:
          gaitData.gaitName = "ROTARY_GALLOP";
          gaitData.gaitEnabled << 1, 1, 1, 1;
          gaitData.periodTimeNominal = 0.4;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal = 0.2;
          gaitData.phaseOffset << 0.0, 0.8571, 0.3571, 0.5;
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
          break;
    
        //11)快跑步态类型
        case GaitType::TRAVERSE_GALLOP:
          // TODO: find the right sequence, should be easy
          gaitData.gaitName = "TRAVERSE_GALLOP";
          gaitData.gaitEnabled << 1, 1, 1, 1;
          gaitData.periodTimeNominal = 0.5;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal = 0.2;
          gaitData.phaseOffset << 0.0, 0.8571, 0.3571, 0.5;
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
          break;
    
        //12)冲刺步态类型
        case GaitType::PRONK:
          gaitData.gaitName = "PRONK";
          gaitData.gaitEnabled << 1, 1, 1, 1;
          gaitData.periodTimeNominal = 0.5;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal = 0.5;
          gaitData.phaseOffset << 0.0, 0.0, 0.0, 0.0;
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
          break;
    
        //13)三腿运动步态类型
        case GaitType::THREE_FOOT:
          gaitData.gaitName = "THREE_FOOT";
          gaitData.gaitEnabled << 0, 1, 1, 1;
          gaitData.periodTimeNominal = 0.5;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal = 0.5;
          gaitData.phaseOffset << 0.0, 0.666, 0.0, 0.333;
          gaitData.phaseScale << 0.0, 1.0, 1.0, 1.0;
          break;
    
        case GaitType::CUSTOM:
          gaitData.gaitName = "CUSTOM";
          // TODO: get custom gait parameters from operator GUI
          break;
    
        //14)过渡到站立步态类型
        case GaitType::TRANSITION_TO_STAND:
          gaitData.gaitName = "TRANSITION_TO_STAND";
          gaitData.gaitEnabled << 1, 1, 1, 1;
          T oldGaitPeriodTimeNominal = gaitData.periodTimeNominal;
          gaitData.periodTimeNominal = 3 * gaitData.periodTimeNominal;
          gaitData.initialPhase = 0.0;
          gaitData.switchingPhaseNominal =
              (gaitData.periodTimeNominal +
               oldGaitPeriodTimeNominal * (gaitData.switchingPhaseNominal - 1)) /
              gaitData.periodTimeNominal;
          gaitData.phaseOffset << (gaitData.periodTimeNominal +
                                   oldGaitPeriodTimeNominal *
                                       (gaitData.phaseVariable(0) - 1)) /
                                      gaitData.periodTimeNominal,
              (gaitData.periodTimeNominal +
               oldGaitPeriodTimeNominal * (gaitData.phaseVariable(1) - 1)) /
                  gaitData.periodTimeNominal,
              (gaitData.periodTimeNominal +
               oldGaitPeriodTimeNominal * (gaitData.phaseVariable(2) - 1)) /
                  gaitData.periodTimeNominal,
              (gaitData.periodTimeNominal +
               oldGaitPeriodTimeNominal * (gaitData.phaseVariable(3) - 1)) /
                  gaitData.periodTimeNominal;
          gaitData.phaseScale << 1.0, 1.0, 1.0, 1.0;
    
          break;
      }
    
      // (2)根据上面的7个步态类型参数为每只脚设置步态参数
      for (int foot = 0; foot < 4; foot++) 
      {
        if (gaitData.gaitEnabled(foot) == 1) //若步态使能了
        {
          //(1)计算每英尺的缩放周期时间,每英尺的缩放周期时间=步态周期 /腿的相位范围
          gaitData.periodTime(foot) =
              gaitData.periodTimeNominal / gaitData.phaseScale(foot);
    
          //(2)将脚从站姿切换到摆动的阶段
          gaitData.switchingPhase(foot) = gaitData.switchingPhaseNominal;
    
          //(3)计算偏移量初始化相位变量,偏移量初始化相位变量=腿的初始相位+相位偏移
          gaitData.phaseVariable(foot) =
              gaitData.initialPhase + gaitData.phaseOffset(foot);
    
          //(4)计算整个步态周期的总站姿时间,整个步态周期的总站姿时间=步态周期*站立在步态周期的比例
          gaitData.timeStance(foot) =
              gaitData.periodTime(foot) * gaitData.switchingPhase(foot);
    
          //(5)计算整个步态周期的总摆动时间,整个步态周期的总摆动时间=步态周期*(1-站立在步态周期的比例)
          gaitData.timeSwing(foot) =
              gaitData.periodTime(foot) * (1.0 - gaitData.switchingPhase(foot));
    
        } 
        else                                //若步态没有使能
        {
          //(1)设置每英尺的缩放周期时间为0
          gaitData.periodTime(foot) = 0.0;
    
          //(2)设置将脚从站姿切换到摆动的阶段为0
          gaitData.switchingPhase(foot) = 0.0;
    
          //(3)设置根据偏移量初始化相位变量为0
          gaitData.phaseVariable(foot) = 0.0;
    
          //(4)设置脚的站立时间为0
          gaitData.timeStance(foot) = 0.0;
    
          //(5)设置脚的摆动时间很大
          gaitData.timeSwing(foot) = 1.0 / gaitData.periodTime(foot);
        }
      }
    }
    

    5.修改步态函数

    /**
     * 功能:修改步态函数
     * 代码没有调用过
     */
    template <typename T>
    void GaitScheduler<T>::modifyGait()
    {
      switch ((int)userParameters->gait_override)  // 选择步态和参数
      {
      case 0:    // (1)使用来自控制代码的默认设置
        if (gaitData._currentGait != gaitData._nextGait)
        {
          createGait();
        }
        break;
    
      case 1:    //(2)使用用户设定步态
        if (gaitData._currentGait != GaitType(userParameters->gait_type))
        {
          gaitData._nextGait = GaitType(userParameters->gait_type);
          createGait();
        }
        break;
    
      case 2:    // (3)使用这里设置的特定步态及其参数来修改步态
        if (gaitData._currentGait != GaitType(userParameters->gait_type))
        {
          gaitData._nextGait = GaitType(userParameters->gait_type);
          createGait();
        }
    
        //调整步态参数 当前步态周期或摆动切换点和设定步态的不同
        if (fabs(gaitData.periodTimeNominal - (T)userParameters->gait_period_time) > 0.0001 ||
            fabs(gaitData.switchingPhaseNominal - (T)userParameters->gait_switching_phase) > 0.0001)
        {
          // 如果参数当前可覆盖 修改步态参数
          if (gaitData.overrideable == 1)
          {
            gaitData.periodTimeNominal = userParameters->gait_period_time;
            gaitData.switchingPhaseNominal = userParameters->gait_switching_phase;
            calcAuxiliaryGaitData();
          }
        }
        break;
    
      case 3:// (4)使用fsm来的设定
        if (gaitData._currentGait != gaitData._nextGait)
        {
          createGait();
        }
        break;
    
      case 4:   //使用fsm来的设定
        if (gaitData._currentGait != gaitData._nextGait)
        {
          createGait();
          period_time_natural = gaitData.periodTimeNominal;
          switching_phase_natural = gaitData.switchingPhaseNominal;
        }
        else
        {
          gaitData.periodTimeNominal = period_time_natural;
          gaitData.switchingPhaseNominal = switching_phase_natural;
          calcAuxiliaryGaitData();
        }
        break;
      }
    }
    
    /**
     * 功能:计算辅助步态数据函数
     * 没有调用到的
     */
    template <typename T>
    void GaitScheduler<T>::calcAuxiliaryGaitData()
    {
      if (gaitData.overrideable == 1)
      {
        if (userParameters->gait_override == 2)
        {
          // gaitData.periodTimeNominal = userParameters->gait_period_time;
          // gaitData.switchingPhaseNominal = userParameters->gait_switching_phase;
        }
        else if (userParameters->gait_override == 4)
        {
          //gaitData.periodTimeNominal = userParameters->gait_period_time;
          //gaitData.switchingPhaseNominal = userParameters->gait_switching_phase;
        }
      }
    
      for (int foot = 0; foot < 4; foot++)  //为每只脚设置步态参数 
      {
        if (gaitData.gaitEnabled(foot) == 1)//支撑相时
        {
          // 每只脚的缩放周期时间
          gaitData.periodTime(foot) =
              gaitData.periodTimeNominal / gaitData.phaseScale(foot);
    
         //将脚从站姿转换成摇摆姿势的相位
          gaitData.switchingPhase(foot) = gaitData.switchingPhaseNominal;
    
          //根据偏移量初始化相位变量
          gaitData.phaseVariable(foot) =
              gaitData.initialPhase + gaitData.phaseOffset(foot);
    
          //整个步态周期的总站立时间
          gaitData.timeStance(foot) =
              gaitData.periodTime(foot) * gaitData.switchingPhase(foot);
    
          // 整个步态周期的摆动时间
          gaitData.timeSwing(foot) =
              gaitData.periodTime(foot) * (1.0 - gaitData.switchingPhase(foot));
        }
        else                                //腾空相时
        {
          // 每只脚的缩放周期时间
          gaitData.periodTime(foot) = 0.0;
    
          //将脚从站姿转换成摇摆姿势的相位
          gaitData.switchingPhase(foot) = 0.0;
    
          //根据偏移量初始化相位变量
          gaitData.phaseVariable(foot) = 0.0;
    
          //脚一直在摆动,故站立设置为0
          gaitData.timeStance(foot) = 0.0;
    
          //脚一直在摆动,故摆动设置为1
          gaitData.timeSwing(foot) = 1.0 / gaitData.periodTime(foot);
        }
      }
    }
    
    

    .
    .

    5.打印有关步态和当前步态状态的信息函数

    
    /**
     * 功能:打印有关步态和当前步态状态的信息函数
     */
    template <typename T>
    void GaitScheduler<T>::printGaitInfo() 
    {
      //
      printIter++;
    
      // 增量打印迭代
      if (printIter == printNum) {
        std::cout << "[GAIT SCHEDULER] Printing Gait Info...\n";
        std::cout << "Gait Type: " << gaitData.gaitName << "\n";
        std::cout << "---------------------------------------------------------\n";
        std::cout << "Enabled: " << gaitData.gaitEnabled(0) << " | "
                  << gaitData.gaitEnabled(1) << " | " << gaitData.gaitEnabled(2)
                  << " | " << gaitData.gaitEnabled(3) << "\n";
        std::cout << "Period Time: " << gaitData.periodTime(0) << "s | "
                  << gaitData.periodTime(1) << "s | " << gaitData.periodTime(2)
                  << "s | " << gaitData.periodTime(3) << "s\n";
        std::cout << "---------------------------------------------------------\n";
        std::cout << "Contact State: " << gaitData.contactStateScheduled(0) << " | "
                  << gaitData.contactStateScheduled(1) << " | "
                  << gaitData.contactStateScheduled(2) << " | "
                  << gaitData.contactStateScheduled(3) << "\n";
        std::cout << "Phase Variable: " << gaitData.phaseVariable(0) << " | "
                  << gaitData.phaseVariable(1) << " | " << gaitData.phaseVariable(2)
                  << " | " << gaitData.phaseVariable(3) << "\n";
        std::cout << "Stance Time Remaining: " << gaitData.timeStanceRemaining(0)
                  << "s | " << gaitData.timeStanceRemaining(1) << "s | "
                  << gaitData.timeStanceRemaining(2) << "s | "
                  << gaitData.timeStanceRemaining(3) << "s\n";
        std::cout << "Swing Time Remaining: " << gaitData.timeSwingRemaining(0)
                  << "s | " << gaitData.timeSwingRemaining(1) << "s | "
                  << gaitData.timeSwingRemaining(2) << "s | "
                  << gaitData.timeSwingRemaining(3) << "s\n";
        std::cout << std::endl;
    
        //重置迭代计数器
        printIter = 0;
      }
    }
    
    template class GaitScheduler<double>;
    template class GaitScheduler<float>;
    

    .
    .

    二、相位控制

    1.功能

    周期运行的相位控制器【选择步态】+【支撑相或腾空相步态调度相位增量迭代、切换】函数

    2.原理

    (1)判断是否请求新步态(步态类型规划)
    【若是就创建一个新的步态】

    (2)判断四条腿上是否开启了步态调度器(步态相位规划)
    如果开启相位控制器,则进行支撑腿、摆动腿的相位迭代计算与切换,如果腿未启用相位控制器,设置相位为0、接触状态为0

    (3)若开启了相位控制

    1)相位随着系统时间自增【防盗标记–盒子君hzj】

    在待机模式下不要增加相位,STAND就是站立不动视为待机
    在非待机(工作)模式, 基于单调时间的相位增量
    	公式:该腿的相位=该腿的相位刻度*(迭代周期/总周期时间)
    

    (2)找到每只脚的当前相位

    公式:每只脚的当前相位=上一次相位+本次的相位增量
    

    (3)计算支撑/摆动腿状态相关参数【防盗标记–盒子君hzj】

    1)若处于支撑相阶段

    (1)设置足部接触状态:支撑相=1
    
    (2)判断支撑相位切换状态
    		方法:支撑相状态=每只脚的当前相位【0~1】/相切换到swing的相位【1】,若为1就可以切换到支撑相,反之
    
    (3)计算摆动相位:摆动阶段尚未开始,因为脚处于站姿
    
    (4)计算站姿剩余时间
    		公式:站姿剩余的时间=步态总时间*(摆动相位-现在的相位)
    
    (5)计算摆动剩余时间
     		支撑相没有摆动时间
    
    (6)判断是不是第一次接触,设置接触标志位,处理从站立到其他步态刚开始逻辑用的
    

    2)若处于摆动相阶段

    (1)设置足部接触状态:摆动相=0
    
    (2)判断支撑相位
    		脚处于摆动状态,站立状态位0
    
    (3)计算摆动相位
    		公式:摆动相相位=(当前的相位-摆动相默认相位)/(1-摆动相默认相位)
    
    (4)计算站姿剩余时间
    		脚在摆动,没有站立时间,故站立剩余时间为0
    
    (5)计算摆动剩余时间
    		公式:挥杆剩余时间=步态总时间*(1-当前相位值)【防盗标记–盒子君hzj】
    
    (6)判断是不是第一次摆动,设置摆动标志位,处理从站立到其他步态刚开始逻辑用的
    

    .
    .

    3.代码

    /**
     * 功能:周期运行的相位控制器【选择步态】+【支撑相或腾空相步态调度相位增量迭代】函数
     */
    template <typename T>
    void GaitScheduler<T>::step() 
    {
      ///*(A)判断是否请求新步态*/
      if (gaitData._currentGait != gaitData._nextGait) //如果当前步态类型和下一个步态类型不一致
      {
        std::cout << "[GAIT] Transitioning gait from " << gaitData.gaitName
                  << " to ";
        createGait();                                         //(1)重新建立一个新步态
        std::cout << gaitData.gaitName << "\n" << std::endl;
        gaitData._currentGait = gaitData._nextGait;           //(2)进行步态迭代,即把下个步态类型传给当前步态类型
      }
    
      ///*(B)判断四条腿上是否开启了步态调度器*///
      for (int foot = 0; foot < 4; foot++)    
      {
        /*如果有开启步态调度器*/
        if (gaitData.gaitEnabled(foot) == 1) 
        {
          //(1)相位随着时间自增
          if (gaitData._currentGait == GaitType::STAND) // 在待机模式下不要增加相位,STAND就是站立不动视为待机
          {
            dphase = 0.0;  
          }
          else                                          //在非待机(工作)模式, 基于单调时间的相位增量
          {
            //这条是基于周期相位变化
            //公式:该腿的相位=该腿的相位刻度*(迭代周期/总周期时间)
            dphase = gaitData.phaseScale(foot) * (dt / gaitData.periodTimeNominal);
          }
    
          //(2)找到每只脚的当前相位
          //公式:每只脚的当前相位=上一次相位+本次的相位增量
          gaitData.phaseVariable(foot) =
              fmod((gaitData.phaseVariable(foot) + dphase), 1);
    
          //(3)计算支撑/摆动腿状态相关参数
    
          /*若处于支撑相阶段,计算支撑向步态相关参数*/
          if (gaitData.phaseVariable(foot) <= gaitData.switchingPhase(foot))   //腿现在的相位<摆动腿的相位,即处于支撑相阶段
          {
            //(1)设置足部接触状态:支撑相=1,摆动相=0
            gaitData.contactStateScheduled(foot) = 1;
    
            //(2)判断支撑相位状态
            //     方法:支撑相状态=每只脚的当前相位【0~1】/相切换到swing的相位【1】,若为1就可以切换到支撑相,反之
            gaitData.phaseStance(foot) =
                gaitData.phaseVariable(foot) / gaitData.switchingPhase(foot);
    
            //(3)计算摆动相位,摆动阶段尚未开始,因为脚处于站姿
            gaitData.phaseSwing(foot) = 0.0;
    
            //(4)计算站姿剩余时间  
            //     公式:站姿剩余的时间=步态总时间*(摆动相位-现在的相位)
            gaitData.timeStanceRemaining(foot) =
                gaitData.periodTime(foot) *
                (gaitData.switchingPhase(foot) - gaitData.phaseVariable(foot));
    
            //(5)计算摆动剩余时间,支撑相没有摆动时间
            gaitData.timeSwingRemaining(foot) = 0.0;
    
            //(6)判断是不是第一次接触,处理从站立到其他步态刚开始逻辑用的
            if (gaitData.contactStatePrev(foot) == 0)  //第一次接触表示预定着陆
            {
              //将触地标志设为1
              gaitData.touchdownScheduled(foot) = 1;
            } 
            else                                       //第二次接触
            {
              // 将触地标志设置为0
              gaitData.touchdownScheduled(foot) = 0;
            }
    
          } 
          
          /*若处于摆动相阶段,计算支撑向步态相关参数*/
          else                                                                 //腿现在的相位<摆动腿的相位,即处于摆动相阶段
          {
            //(1)设置足部接触状态:支撑相=1,摆动相=0,摆动相足部没有接触
            gaitData.contactStateScheduled(foot) = 0;
    
            //(2)判断支撑相位,脚处于摆动状态,站立状态位0,摆动状态位1
            gaitData.phaseStance(foot) = 1.0;
    
            //(3)计算摆动相位         
            //    公式:摆动相相位=(当前的相位-摆动相默认相位)/(1-摆动相默认相位)
            gaitData.phaseSwing(foot) =
                (gaitData.phaseVariable(foot) - gaitData.switchingPhase(foot)) /
                (1.0 - gaitData.switchingPhase(foot));
    
            //(4)计算站姿剩余时间:脚在摆动,没有站立时间,故站立剩余时间为0
            gaitData.timeStanceRemaining(foot) = 0.0;
    
            //(5)计算摆动剩余时间    
            //     公式:挥杆剩余时间=步态总时间*(1-当前相位值)
            gaitData.timeSwingRemaining(foot) =
                gaitData.periodTime(foot) * (1 - gaitData.phaseVariable(foot));
    
            //(6)判断是不是第一次摆动,设置摆动标志位,处理从站立到其他步态刚开始逻辑用的
            if (gaitData.contactStatePrev(foot) == 1) //第一次接触表示预定着陆
            {
              //将升空标志设置为1
              gaitData.liftoffScheduled(foot) = 1;
              //记住接地时脚的位置
              // posFootLiftoffWorld = ;
            } 
            else                                      //第二次接触
            {
              // 将升空标志设置为0
              gaitData.liftoffScheduled(foot) = 0;
            }
          }
        } 
        
        /*如果腿未启用步态调度器*/
        else                                 
        {
          gaitData.phaseVariable(foot) = 0.0;       //(1)设置相位为0
          gaitData.contactStateScheduled(foot) = 0; //(2)设置接触状态为0
        }
    
        /*(C)迭代,用该次接触状态赋值上一个时间步*///
        gaitData.contactStatePrev(foot) = gaitData.contactStateScheduled(foot);
      }
    }
    
    

    总结

    理论部分我硕士毕业查重过了在发布上来~
    【防盗标记–盒子君hzj】

    更多相关内容
  • #资源达人分享计划#
  • 入门教材,适合广泛应用,对于初学者可以进行体系建立,了解当前时代更新知识。紧跟时代变化知识体系。快来看一看。
  • 有并联脊柱的四足机器人步态规划.pdf
  • #资源达人分享计划#
  • #资源达人分享计划#
  • 在Wilson-Cowan神经振荡器基础上,提出了一种新的CPG控制器,用于四足机器人的节律运动控制,每个Wilson-Cowan神经振荡器分别对应机器人的一个步行腿,对机器人的腿进行协调运动控制。通过调整振荡器之间的步态连接...
  • 四足机器人步态控制完整版代码 :里面共有两个工程,分别是步态控制程序和遥控控制程序 Keil5完整版代码(遥控程序+控制程序) 主控用的是Stm32F103ZGT6 C语言写的,是在 matlab下生成步态算法后移植的,亲测已用...
  • 四足机器人——步态规划

    千次阅读 2021-11-20 20:35:00
    二、四足机器人步态 足式运动的步态是指腿的摆动和支撑运动以及这些运动之间的相对时间关系。不同的步态规则决定了不同的足式运动方式,从而形成了不同的步态形式。 目前对步态的研究主要是为了实现机器人的稳定...

    一、步态的概念

    步态就是描述动物走路的一种周期性现象。(描述动物是怎样走的)

    二、四足机器人的步态

    足式运动的步态是指腿的摆动和支撑运动以及这些运动之间的相对时间关系。不同的步态规则决定了不同的足式运动方式,从而形成了不同的步态形式。
    目前对步态的研究主要是为了实现机器人的稳定周期运动。研究的重点是具体的步态规划方法。传统步态规划内容包括足端轨迹规划,以及协调腿和腿之间运动的相对时间关系,也就是步态时序。其中,足端运动轨迹还包括摆线相轨迹和支撑相轨迹,两者决定了单个腿的运动特征;而规划不同的步态时序就对应了机器人整体的不同步态形式。
    按照平衡方式来分,四足机器人的步态可以分为静态步态,动态步态和准静态步态三种。

    1、行走:

    Walk步态是一种静态步态,即在运动过程中始终有三条腿处于支撑相,至多只有一条腿处于摆动相,四足动物在walk步态中四条腿最常见的轮换顺序为1→3→4→2→1。

     

     

     

    2、缓行:

    3、踱步

    4、小跑(支撑相和摆动相成对角)

    Trot步态是一种动态步态,适用于中低速跑动,并且具有比较大的运动速度范围,另一个重要特征是在中等速度下的Trot步态具有最高的能量效率。这些优点使得Trot步态成为最常用的四足步态。

    Trot步态的特征是以对角的两条腿成对运动,即腿1和腿3运动一致,腿2和腿4运动一致,理想情况下对角腿同时抬起并同时着地。
    在一个运动周期内,四条腿的抬起时刻为φ1=0,φ2=0.5,φ3=0,φ4=0.5,1-p为处于摆动相的时间,但是1-p一定要小于φ,因为只有这样,Trot步态才成立。

     

    5、奔跑

     

    6、慢跑

    三、相位差

    展开全文
  • 所有对四足机器人步态算法研究的爱好者,懂matlab基本语法的都能看懂,hopf数学模型,足间步态逻辑关系,组内协调逻辑关系,此代码里统统涵盖。是为所有对四足机器人步态算法研究爱好者指引的一条通路。可将此算法...
  • #资源达人分享计划#
  • 针对足机器人的越障自由步态规划问题,提出了一种改进的离散化四足机器人步态规划模型,该模型可通过设置相关参数准确模拟实际物理模型,并且可以根据障碍物的分布密集程度改变候选落足点数以提高机器人对地形的适应...
  • 四足机器人】 足端轨迹规划步态规划一、足端轨迹规划1.摆线二、步态规划 近期,博主在古月居学习关于四足机器人的相关部分知识,从阳炼老师的四足机器人控制与仿真课程中学习到了很多内容,故在这里对四足机器人...

    【四足机器人】学习笔记 足端轨迹规划和步态规划

    近期,博主在古月居学习关于四足机器人的相关部分知识,从阳炼老师的四足机器人控制与仿真课程中学习到了很多内容,故在这里对四足机器人的四足运动控制部分进行相应的梳理。
    博主在这篇文章中,对四足机器人的足端轨迹规划和步态规划进行了详细的介绍。

    一、足端轨迹规划(摆线)

    在了解四足机器人的足端轨迹规划前,我们要先了解关于摆线的相关知识,博主这里研究的四足机器人的足端轨迹规划与摆线有很大关联,通过研究摆线的轨迹,可以探究四足机器人足端的运动轨迹,并实验在不同参数下,不同的足端运动轨迹之间的优劣。

    摆线,又称旋轮线、圆滚线,在数学中,摆线(Cycloid)被定义为,一个圆沿一条直线运动时圆便捷上一定点所形成的的轨迹,数学公式表示如下:
    在这里插入图片描述

    x=r*(t-sin(t))
    y=r*(1-cos(t))
    

    x对应于横向长度,y对应于纵向长度,t对应于累计弧度,范围为[0,2π],对这个式子做相应的变换,得到下列关系式

    //xs为起始位置,xf为终点位置
    xt=(xf-xs)*(σ-sin(σ))/2Π+xs
    //h为最高位置,zs为起始高度
    zt=h*(1-cos(σ))+zs
    σ=2Πt/(λTs)0<t<λTs
    

    通过式子的变换,可以通过给定的参数,可以在matlab中观察摆线轨迹,从而研究足端的运动控制。

    二、步态规划

    足式运动的步态是指腿的摆动和支撑运动以及这些运动之间的相对时间关系。不同的步态规则决定了不同的足式运动方式,从而形成了不同的步态形式。
    目前对步态的研究主要是为了实现机器人的稳定周期运动。研究的重点是具体的步态规划方法。传统步态规划内容包括足端轨迹规划,以及协调腿和腿之间运动的相对时间关系,也就是步态时序。其中,足端运动轨迹还包括摆线相轨迹和支撑相轨迹,两者决定了单个腿的运动特征;而规划不同的步态时序就对应了机器人整体的不同步态形式。
    按照平衡方式来分,四足机器人的步态可以分为静态步态,动态步态和准静态步态三种。博主在这里,主要介绍Walk步态和Trot步态。

    1.Walk步态

    Walk步态是一种静态步态,即在运动过程中始终有三条腿处于支撑相,至多只有一条腿处于摆动相,四足动物在walk步态中四条腿最常见的轮换顺序为1→3→4→2→1。
    在这里插入图片描述
    在一个运动周期内,四条腿的抬起时刻为φ1=0,φ2=φ+0.5,φ3=φ,φ4=0.5,1-p为处于摆动相的时间,但是1-p一定要小于φ,因为只有这样,walk步态才成立。
    在这里插入图片描述

    在这里插入图片描述

    2.Trot步态

    Trot步态是一种动态步态,适用于中低速跑动,并且具有比较大的运动速度范围,另一个重要特征是在中等速度下的Trot步态具有最高的能量效率。这些优点使得Trot步态成为最常用的四足步态。
    在这里插入图片描述
    Trot步态的特征是以对角的两条腿成对运动,即腿1和腿3运动一致,腿2和腿4运动一致,理想情况下对角腿同时抬起并同时着地。
    在一个运动周期内,四条腿的抬起时刻为φ1=0,φ2=0.5,φ3=0,φ4=0.5,1-p为处于摆动相的时间,但是1-p一定要小于φ,因为只有这样,Trot步态才成立。在这里插入图片描述
    Trot步态的一种临界状态是当p=φ=0.5,任意时刻都只有两条腿处于摆动相和支撑相,是Trot步态中最为理想的状态。
    以上就是关于四足机器人足端轨迹规划和步态规划的全部知识了。

    展开全文
  • #资源达人分享计划#
  • 首先对液压四足机器人的运动特性进行了研究,选取CPG算法作为控制算法并建立了数学模型,用Matlab实现软件上的仿真,观察各髋关节的输出信号;然后借助Matlab工具HDL Coder将Simulink模型转换为Verilog硬件语言,并...
  • 四足机器人 2.建模和步态规划

    万次阅读 多人点赞 2019-08-09 11:24:45
    四足机器人在运动过程中,与所处环境进行交互作用,为提高机器人运动的稳定性和适应性,需要整体考虑四足机器人的动力学模型、足-地接触模型和步态生成与变换模型。 ​ 运动学建模:D-H方法、李代数方法、螺旋理论 ...

    1.建模

    四足机器人建模: 运动学建模和动力学建模

    四足机器人在运动过程中,与所处环境进行交互作用,为提高机器人运动的稳定性和适应性,需要整体考虑四足机器人的动力学模型、足-地接触模型和步态生成与变换模型。

    运动学建模:D-H方法、李代数方法、螺旋理论

    动力学建模:拉格朗日方法、牛顿-欧拉方法和汉密尔顿法

    运动学建模 D-H参数
    连杆序号杆件长度关节扭角关节距离关节转角(+限位情况)

    正运动学解,算出各腿末端空间坐标值

    逆运动学解,由各腿末端空间坐标值(机器人需到达目标姿态)算目标D-H参数值,进而控制电机调整。

    动力学建模

    知道各部分关节受力情况

    2.步态规划

    四足机器人步态:静步态和动步态

    静步态:任何时刻至少有3条腿着地的步态 ,占空比(duty factor) β \beta β > 0.5。 β \beta β ≥ \geq 0.75为爬行步态(crawl / creep), β \beta β<0.75为慢走步态(amble)。

    动步态:任何时刻最多2条腿着地的步态,占空比(duty factor) β \beta β ≤ \leq 0.5。 β \beta β < 0.5为存在4条腿同时离地的、具有腾空阶段的飞奔(galllop)步态,当 β \beta β = 0.5时,相应动步态可分为对角小跑(trot)、单侧小跑(pace)和双足跳跃(bound)步态。

    这里腿i的占空比 β i \beta_i βi是该腿处于支撑相的时间与步态周期的比。

    连续静步态规划

    a.迈步顺序

    四足机器人共有6种非奇异静步态迈步顺序,4-2-3-1(下图)为稳定裕度最优的迈步顺序。
    在这里插入图片描述
    在机器人进行摆动足运动过程中,其躯干匀速向前运动,此时机器人的ZMP点与重心的投影点重合。因而使用静态稳定裕度即可准确地衡量机器人稳定性。
    b.四足机器人重心轨迹规划
    重心轨迹方程 -> 四足支撑阶段躯干轨迹方程 -> 四足运动方程
    c.摆动足轨迹规划
    四足机器人的摆动足应沿规划的足底运动轨迹准确摆动至期望的落足点,并在其运动过程中避免与地形中的障碍物发生碰撞。
    足底运动轨迹 -> 运动学逆解得机器人各关节的运动角度

    3.总结

    四足机器人运动轨迹方程->重心轨迹方程(质点运动轨迹+躯干姿态调整)->四足运动方程->退一步,获取各足运动序列及下个状态->执行命令(各足切换至下个状态),调用封装好的足端轨迹,输入:1.序列号2.足端目标空间值,插补出足端空间轨迹曲线。

    1质心轨迹(+姿态)
    2步态选择 固定周期步态/自由步态
    3执行机构(行走+姿态)

    确定世界坐标系目的点->调整方向->前进(1.选择运动腿2.确定腿端运动轨迹)

    吐槽一下,​我的编辑器怎么这么卡啊,真难受,我要用txt写了 ?

    展开全文
  • #资源达人分享计划#
  • gai_arduino_四足机器人_

    2021-10-02 04:21:15
    arduino简单 的四足机器人动作组,行走,简单动作
  • #资源达人分享计划#
  • 本文将对四足机器人的足端轨迹进行规划。将数学中的复合摆线和多项式曲线引入到足端轨迹的规划中,根据零冲击原则[2],规划出 3 条满足要求的足端轨迹,包括: 复合摆线轨迹 八次多项式轨迹 分段五次多项式轨迹 本篇...
  • 步态 规划 根据 步态 中各腿 间的相位关 系,借助 四足机器人运动学模 型进行逆运动学解算 ,求 出各腿 的关 节角度 函数 ,利用机 构的几何关系得到各液压缸伸缩量控 制函数,对试验样机各腿进 行伺服驱动控制 ,从而 ...
  • 足及六足机器人相比,双足机器人足部与地面的接触支撑面积较小,使其具有更高的灵活性和环境适应性,但这也是双足机器人容易跌倒的主要原因之一。本文以液压双足机器人步态规划及柔顺控制为目标,进行以下研究。...
  • #资源达人分享计划#
  • 四足机器人(二)---运动学逆解和步态规划

    千次阅读 多人点赞 2020-08-20 18:48:19
    四足机器人(二)---运动学逆解和步态规划运动学逆解步态规划MATLAB仿真 运动学逆解 其实运动学分为运动学正解和运动学逆解,二者有什么区别呢?因为在四足机器人中用的是12个舵机,所以运动学正解是已经知道运动...
  • 足机器人步态规划及其静态稳定性研究,张春阳,江先志,以一种新型六足机器人样机为研究对象,研究机器人直线行走步态及其在步态下的稳定性。本文分别规划了六足机器人纵向与横向直线行
  • 仿蟹机器人步态规划方法.pdf
  • #资源达人分享计划#
  • 基于3-D步行序列的双足机器人步态规划及实验研究.pdf
  • 液压四足机器人单腿竖直跳跃步态规划.pdf,针对机器人跳跃运动落地时冲击力大的问题,面向竖直跳跃运动,以液压四足机器人单腿为研究对象,建立液压驱动四足机器人单腿运动学模型,并分别对机器人单腿处于起跳相、...
  • 然而由于机器人步行的环境并不总是平路而是高低起伏的,机器人为了适应环境就必须在步态规划和控制上适应不同坡度的路况,这需要针对机器人的斜坡步态进行合理规划,进行参数化建模研究,从而解决在不同步行环境中...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 973
精华内容 389
关键字:

四足机器人步态规划