Skip to content
Snippets Groups Projects
Forked from loco-3d / sot-talos-balance
685 commits behind the upstream repository.
dcm-com-controller.cpp 9.17 KiB
/*
 * Copyright 2018, Gepetto team, LAAS-CNRS
 *
 * This file is part of sot-talos-balance.
 * sot-talos-balance is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * sot-talos-balance is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.  You should
 * have received a copy of the GNU Lesser General Public License along
 * with sot-talos-balance.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "sot/talos_balance/dcm-com-controller.hh"

#include <sot/core/debug.hh>
#include <dynamic-graph/factory.h>
#include <dynamic-graph/command-bind.h>

#include "sot/talos_balance/utils/commands-helper.hh"
#include "sot/talos_balance/utils/stop-watch.hh"

namespace dynamicgraph
{
  namespace sot
  {
    namespace talos_balance
    {
      namespace dg = ::dynamicgraph;
      using namespace dg;
      using namespace dg::command;

//Size to be aligned                                   "-------------------------------------------------------"
#define PROFILE_DCMCOMCONTROLLER_DDCOMREF_COMPUTATION  "DcmComController: ddcomRef computation                 "
#define PROFILE_DCMCOMCONTROLLER_ZMPREF_COMPUTATION    "DcmComController: zmpRef computation                   "
#define PROFILE_DCMCOMCONTROLLER_WRENCHREF_COMPUTATION "DcmComController: wrenchRef computation                "

#define INPUT_SIGNALS m_KpSIN << m_KiSIN << m_decayFactorSIN << m_omegaSIN << m_massSIN << m_dcmSIN << m_dcmDesSIN << m_comDesSIN << m_ddcomDesSIN

#define OUTPUT_SIGNALS m_ddcomRefSOUT << m_zmpRefSOUT << m_wrenchRefSOUT

      /// Define EntityClassName here rather than in the header file
      /// so that it can be used by the macros DEFINE_SIGNAL_**_FUNCTION.
      typedef DcmComController EntityClassName;

      /* --- DG FACTORY ---------------------------------------------------- */
      DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(DcmComController,
                                         "DcmComController");

      /* ------------------------------------------------------------------- */
      /* --- CONSTRUCTION -------------------------------------------------- */
      /* ------------------------------------------------------------------- */
      DcmComController::DcmComController(const std::string& name)
                      : Entity(name)
                      , CONSTRUCT_SIGNAL_IN(Kp, dynamicgraph::Vector)
                      , CONSTRUCT_SIGNAL_IN(Ki, dynamicgraph::Vector)
                      , CONSTRUCT_SIGNAL_IN(decayFactor, double)
                      , CONSTRUCT_SIGNAL_IN(omega, double)
                      , CONSTRUCT_SIGNAL_IN(mass, double)
                      , CONSTRUCT_SIGNAL_IN(dcm, dynamicgraph::Vector)
                      , CONSTRUCT_SIGNAL_IN(dcmDes, dynamicgraph::Vector)
                      , CONSTRUCT_SIGNAL_IN(comDes, dynamicgraph::Vector)
                      , CONSTRUCT_SIGNAL_IN(ddcomDes, dynamicgraph::Vector)
                      , CONSTRUCT_SIGNAL_OUT(ddcomRef, dynamicgraph::Vector, INPUT_SIGNALS)
                      , CONSTRUCT_SIGNAL_OUT(zmpRef, dynamicgraph::Vector,    m_ddcomRefSOUT << m_comDesSIN << m_omegaSIN )
                      , CONSTRUCT_SIGNAL_OUT(wrenchRef, dynamicgraph::Vector, m_ddcomRefSOUT << m_comDesSIN << m_massSIN )
                      , m_initSucceeded(false)
      {
        Entity::signalRegistration( INPUT_SIGNALS << OUTPUT_SIGNALS );

        /* Commands. */
        addCommand("init", makeCommandVoid1(*this, &DcmComController::init, docCommandVoid1("Initialize the entity.","time step")));
        addCommand("resetDcmIntegralError", makeCommandVoid0(*this, &DcmComController::resetDcmIntegralError, docCommandVoid0("Set dcm integral error to zero.")));
      }

      void DcmComController::init(const double & dt)
      {
        if(!m_KpSIN.isPlugged())
          return SEND_MSG("Init failed: signal Kp is not plugged", MSG_TYPE_ERROR);
        if(!m_KiSIN.isPlugged())
          return SEND_MSG("Init failed: signal Ki is not plugged", MSG_TYPE_ERROR);
        if(!m_decayFactorSIN.isPlugged())
          return SEND_MSG("Init failed: signal decayFactor is not plugged", MSG_TYPE_ERROR);
        if(!m_omegaSIN.isPlugged())
          return SEND_MSG("Init failed: signal omega is not plugged", MSG_TYPE_ERROR);
        if(!m_massSIN.isPlugged())
          return SEND_MSG("Init failed: signal mass is not plugged", MSG_TYPE_ERROR);
        if(!m_dcmSIN.isPlugged())
          return SEND_MSG("Init failed: signal dcm is not plugged", MSG_TYPE_ERROR);
        if(!m_dcmDesSIN.isPlugged())
          return SEND_MSG("Init failed: signal dcmDes is not plugged", MSG_TYPE_ERROR);
        if(!m_comDesSIN.isPlugged())
          return SEND_MSG("Init failed: signal comDes is not plugged", MSG_TYPE_ERROR);
        if(!m_ddcomDesSIN.isPlugged())
          return SEND_MSG("Init failed: signal ddcomDes is not plugged", MSG_TYPE_ERROR);

        m_dt = dt;
        resetDcmIntegralError();
        m_initSucceeded = true;
      }

      void DcmComController::resetDcmIntegralError()
      {
        m_dcmIntegralError.setZero(3);
      }

      /* ------------------------------------------------------------------- */
      /* --- SIGNALS ------------------------------------------------------- */
      /* ------------------------------------------------------------------- */

      DEFINE_SIGNAL_OUT_FUNCTION(ddcomRef, dynamicgraph::Vector)
      {
        if(!m_initSucceeded)
        {
          SEND_WARNING_STREAM_MSG("Cannot compute signal ddcomRef before initialization!");
          return s;
        }

        getProfiler().start(PROFILE_DCMCOMCONTROLLER_DDCOMREF_COMPUTATION);

        
        const Vector & Kp = m_KpSIN(iter);
        const Vector & Ki = m_KiSIN(iter);
        const double & decayFactor = m_decayFactorSIN(iter);
        const double & omega = m_omegaSIN(iter);
        const Vector & dcm = m_dcmSIN(iter);
        const Vector & dcmDes = m_dcmDesSIN(iter);
        const Vector & ddcomDes = m_ddcomDesSIN(iter);

        assert(Kp.size()==3       && "Unexpected size of signal Kp");
        assert(Ki.size()==3       && "Unexpected size of signal Ki");
        assert(dcm.size()==3      && "Unexpected size of signal dcm");
        assert(dcmDes.size()==3   && "Unexpected size of signal dcmDes");
        assert(ddcomDes.size()==3 && "Unexpected size of signal ddcomDes");

        Vector dcmError = dcmDes - dcm;
        m_dcmIntegralError += ( dcmError - decayFactor*m_dcmIntegralError ) * m_dt;

        Vector ddcomRef = ddcomDes + omega * Kp.cwiseProduct(dcmError) + omega * Ki.cwiseProduct(m_dcmIntegralError);

        s = ddcomRef;

        getProfiler().stop(PROFILE_DCMCOMCONTROLLER_DDCOMREF_COMPUTATION);

        return s;
      }

      DEFINE_SIGNAL_OUT_FUNCTION(zmpRef, dynamicgraph::Vector)
      {
        if(!m_initSucceeded)
        {
          SEND_WARNING_STREAM_MSG("Cannot compute signal zmpRef before initialization!");
          return s;
        }

        getProfiler().start(PROFILE_DCMCOMCONTROLLER_ZMPREF_COMPUTATION);

        const double & omega = m_omegaSIN(iter);
        const Vector & comDes = m_comDesSIN(iter);

        const Vector & ddcomRef = m_ddcomRefSOUT(iter);

        assert(comDes.size()==3 && "Unexpected size of signal comDes");

        Vector zmpRef = comDes - ddcomRef/(omega*omega);

        s = zmpRef;

        getProfiler().stop(PROFILE_DCMCOMCONTROLLER_ZMPREF_COMPUTATION);

        return s;
      }

      DEFINE_SIGNAL_OUT_FUNCTION(wrenchRef, dynamicgraph::Vector)
      {
        if(!m_initSucceeded)
        {
          SEND_WARNING_STREAM_MSG("Cannot compute signal wrenchRef before initialization!");
          return s;
        }

        getProfiler().start(PROFILE_DCMCOMCONTROLLER_WRENCHREF_COMPUTATION);

        const double & mass   = m_massSIN(iter);
        const Vector & comDes = m_comDesSIN(iter);

        const Vector & ddcomRef = m_ddcomRefSOUT(iter);

        assert(comDes.size()==3 && "Unexpected size of signal comDes");

        Vector gravity(3);
        gravity << 0.0, 0.0, -9.81;

        Vector forceRef = mass * ( ddcomRef - gravity );

        Vector wrenchRef(6);
        wrenchRef.head<3>() = forceRef;
        Eigen::Vector3d comDes3 = comDes;
        wrenchRef.tail<3>() = comDes3.cross(wrenchRef.head<3>());

        s = wrenchRef;

        getProfiler().stop(PROFILE_DCMCOMCONTROLLER_WRENCHREF_COMPUTATION);

        return s;
      }

      /* --- COMMANDS ---------------------------------------------------------- */

      /* ------------------------------------------------------------------- */
      /* --- ENTITY -------------------------------------------------------- */
      /* ------------------------------------------------------------------- */

      void DcmComController::display(std::ostream& os) const
      {
        os << "DcmComController " << getName();
        try
        {
          getProfiler().report_all(3, os);
        }
        catch (ExceptionSignal e) {}
      }
    } // namespace talos_balance
  } // namespace sot
} // namespace dynamicgraph