From bf55149cddfd2ff28eca1404d9a4e34ea7f3aee8 Mon Sep 17 00:00:00 2001 From: Gabriele Buondonno <gbuondon@laas.fr> Date: Thu, 20 Dec 2018 18:38:09 +0100 Subject: [PATCH] DCM controller [second version] --- CMakeLists.txt | 2 + .../sot/talos_balance/dcm-com-controller.hh | 104 ++++++++ .../create_entities_utils.py | 27 ++ .../test/test_dcmComControl.py | 149 ++++++++++++ .../test/test_dcmComZmpControl.py | 130 ++++++++++ src/CMakeLists.txt | 1 + src/dcm-com-controller.cpp | 230 ++++++++++++++++++ 7 files changed, 643 insertions(+) create mode 100644 include/sot/talos_balance/dcm-com-controller.hh create mode 100644 python/sot_talos_balance/test/test_dcmComControl.py create mode 100644 python/sot_talos_balance/test/test_dcmComZmpControl.py create mode 100644 src/dcm-com-controller.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 95a4e11..8a0aa5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,8 @@ IF(BUILD_PYTHON_INTERFACE) IF(BUILD_TEST) INSTALL(FILES python/${SOTTALOSBALANCE_PYNAME}/test/__init__.py python/${SOTTALOSBALANCE_PYNAME}/test/run_test_utils.py + python/${SOTTALOSBALANCE_PYNAME}/test/test_dcmComControl.py + python/${SOTTALOSBALANCE_PYNAME}/test/test_dcmComZmpControl.py python/${SOTTALOSBALANCE_PYNAME}/test/test_dcmZmpControl.py python/${SOTTALOSBALANCE_PYNAME}/test/test_comAdmittance.py python/${SOTTALOSBALANCE_PYNAME}/test/test_admittance_single_joint.py diff --git a/include/sot/talos_balance/dcm-com-controller.hh b/include/sot/talos_balance/dcm-com-controller.hh new file mode 100644 index 0000000..126fbbc --- /dev/null +++ b/include/sot/talos_balance/dcm-com-controller.hh @@ -0,0 +1,104 @@ +/* + * 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/>. + */ + +#ifndef __sot_talos_balance_dcm_com_controller_H__ +#define __sot_talos_balance_dcm_com_controller_H__ + +/* --------------------------------------------------------------------- */ +/* --- API ------------------------------------------------------------- */ +/* --------------------------------------------------------------------- */ + +#if defined (WIN32) +# if defined (dcm_com_controller_EXPORTS) +# define DCMCOMCONTROLLER_EXPORT __declspec(dllexport) +# else +# define DCMCOMCONTROLLER_EXPORT __declspec(dllimport) +# endif +#else +# define DCMCOMCONTROLLER_EXPORT +#endif + + +/* --------------------------------------------------------------------- */ +/* --- INCLUDE --------------------------------------------------------- */ +/* --------------------------------------------------------------------- */ + +#include "utils/signal-helper.hh" +#include "utils/logger.hh" +#include <map> +#include "boost/assign.hpp" + +namespace dynamicgraph { + namespace sot { + namespace talos_balance { + + /* --------------------------------------------------------------------- */ + /* --- CLASS ----------------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + + class DCMCOMCONTROLLER_EXPORT DcmComController + : public ::dynamicgraph::Entity + { + DYNAMIC_GRAPH_ENTITY_DECL(); + + public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + /* --- CONSTRUCTOR ---- */ + DcmComController( const std::string & name ); + + void init(const double & dt); + + void resetDcmIntegralError(); + + /* --- SIGNALS --- */ + DECLARE_SIGNAL_IN(Kp, dynamicgraph::Vector); + DECLARE_SIGNAL_IN(Ki, dynamicgraph::Vector); + DECLARE_SIGNAL_IN(decayFactor, double); + DECLARE_SIGNAL_IN(omega, double); + DECLARE_SIGNAL_IN(mass, double); + DECLARE_SIGNAL_IN(dcm, dynamicgraph::Vector); + DECLARE_SIGNAL_IN(dcmDes, dynamicgraph::Vector); + DECLARE_SIGNAL_IN(comDes, dynamicgraph::Vector); + DECLARE_SIGNAL_IN(ddcomDes, dynamicgraph::Vector); + + DECLARE_SIGNAL_OUT(ddcomRef, dynamicgraph::Vector); + DECLARE_SIGNAL_OUT(zmpRef, dynamicgraph::Vector); + DECLARE_SIGNAL_OUT(wrenchRef, dynamicgraph::Vector); + + /* --- COMMANDS --- */ + /* --- ENTITY INHERITANCE --- */ + virtual void display( std::ostream& os ) const; + + void sendMsg(const std::string& msg, MsgType t=MSG_TYPE_INFO, const char* file="", int line=0) + { + getLogger().sendMsg("[DcmComController-"+name+"] "+msg, t, file, line); + } + + protected: + bool m_initSucceeded; /// true if the entity has been successfully initialized + dynamicgraph::Vector m_dcmIntegralError; // internal state + double m_dt; + + }; // class DcmComController + + } // namespace talos_balance + } // namespace sot +} // namespace dynamicgraph + + + +#endif // #ifndef __sot_talos_balance_dcm_com_controller_H__ diff --git a/python/sot_talos_balance/create_entities_utils.py b/python/sot_talos_balance/create_entities_utils.py index 7bfc6c4..8586203 100644 --- a/python/sot_talos_balance/create_entities_utils.py +++ b/python/sot_talos_balance/create_entities_utils.py @@ -5,6 +5,7 @@ from sot_talos_balance.joint_admittance_controller import JointAdmittanceControl from sot_talos_balance.dummy_dcm_estimator import DummyDcmEstimator from sot_talos_balance.com_admittance_controller import ComAdmittanceController from sot_talos_balance.dcm_controller import DcmController +from sot_talos_balance.dcm_com_controller import DcmComController from time import sleep from dynamic_graph import plug @@ -124,6 +125,32 @@ def create_dcm_controller(Kp,Ki,dt,robot,dcmSignal): controller.init(dt) return controller +def create_dcm_com_controller(Kp,Ki,dt,robot,dcmSignal): + from math import sqrt + controller = DcmComController("dcmComCtrl") + mass = robot.dynamic.data.mass[0] + robot.dynamic.com.recompute(0) + h = robot.dynamic.com.value[2] + g = 9.81 + omega = sqrt(g/h) + + controller.Kp.value = Kp + controller.Ki.value = Ki + controller.decayFactor.value = 0.2 + controller.mass.value = mass + controller.omega.value = omega + + controller.ddcomDes.value = [0.0,0.0,0.0] + + plug(dcmSignal,controller.dcm) + + robot.dynamic.com.recompute(0) + controller.comDes.value = robot.dynamic.com.value + controller.dcmDes.value = (robot.dynamic.com.value[0], robot.dynamic.com.value[1], 0.0) + + controller.init(dt) + return controller + def addTrace(tracer, entity, signalName): signal = '{0}.{1}'.format(entity.name, signalName) filename = '{0}-{1}'.format(entity.name, signalName) diff --git a/python/sot_talos_balance/test/test_dcmComControl.py b/python/sot_talos_balance/test/test_dcmComControl.py new file mode 100644 index 0000000..33d278c --- /dev/null +++ b/python/sot_talos_balance/test/test_dcmComControl.py @@ -0,0 +1,149 @@ +from sot_talos_balance.create_entities_utils import create_com_admittance_controller, create_dummy_dcm_estimator, create_dcm_com_controller +from dynamic_graph.sot.core.meta_tasks_kine import MetaTaskKine6d, MetaTaskKineCom, gotoNd +from dynamic_graph.sot.core.matrix_util import matrixToTuple +from dynamic_graph import plug +from dynamic_graph.sot.core import SOT +from numpy import eye +from time import sleep +import sys +import os + +from dynamic_graph.tracer_real_time import TracerRealTime +from sot_talos_balance.create_entities_utils import addTrace, dump_tracer +import matplotlib.pyplot as plt +import numpy as np + +def main(robot): + dt = robot.timeStep; + + # --- COM + robot.taskCom = MetaTaskKineCom(robot.dynamic) + robot.dynamic.com.recompute(0) + robot.taskCom.featureDes.errorIN.value = robot.dynamic.com.value + robot.taskCom.task.controlGain.value = 600 + + # --- Dummy estimator + robot.estimator = create_dummy_dcm_estimator(robot) + + # --- DCM controller + Kp_dcm = [5.0,5.0,0.0] + Ki_dcm = [0.0,0.0,0.0] + robot.dcm_control = create_dcm_com_controller(Kp_dcm,Ki_dcm,dt,robot,robot.estimator.dcm) + + # --- Admittance controller + Kp_adm = [0.0,0.0,0.0] # must stay zero + robot.com_admittance_control = create_com_admittance_controller(Kp_adm,dt,robot) + + # -- Gains = 0, ddcomDes = ddcomRef --> admittance controller is a double integrator + plug(robot.dcm_control.ddcomRef,robot.com_admittance_control.ddcomDes) + + # --- CONTACTS + #define contactLF and contactRF + robot.contactLF = MetaTaskKine6d('contactLF',robot.dynamic,'LF',robot.OperationalPointsMap['left-ankle']) + robot.contactLF.feature.frame('desired') + robot.contactLF.gain.setConstant(300) + robot.contactLF.keep() + locals()['contactLF'] = robot.contactLF + + robot.contactRF = MetaTaskKine6d('contactRF',robot.dynamic,'RF',robot.OperationalPointsMap['right-ankle']) + robot.contactRF.feature.frame('desired') + robot.contactRF.gain.setConstant(300) + robot.contactRF.keep() + locals()['contactRF'] = robot.contactRF + + robot.sot = SOT('sot') + robot.sot.setSize(robot.dynamic.getDimension()) + plug(robot.sot.control,robot.device.control) + + robot.sot.push(robot.contactRF.task.name) + robot.sot.push(robot.contactLF.task.name) + robot.sot.push(robot.taskCom.task.name) + robot.device.control.recompute(0) + + # --- TRACER + robot.tracer = TracerRealTime("zmp_tracer") + robot.tracer.setBufferSize(80*(2**20)) + robot.tracer.open('/tmp','dg_','.dat') + robot.device.after.addSignal('{0}.triger'.format(robot.tracer.name)) + + addTrace(robot.tracer, robot.dynamic, 'zmp') + addTrace(robot.tracer, robot.dcm_control, 'zmpRef') + addTrace(robot.tracer, robot.estimator, 'dcm') + addTrace(robot.tracer, robot.dynamic, 'com') + addTrace(robot.tracer, robot.com_admittance_control, 'comRef') + + # SIMULATION + + plug(robot.com_admittance_control.comRef,robot.taskCom.featureDes.errorIN) + plug(robot.dcm_control.zmpRef,robot.com_admittance_control.zmpDes) + robot.dcm_control.Ki.value = [1.0,1.0,0.0] + sleep(1.0) + + robot.tracer.start() + + os.system("rosservice call \start_dynamic_graph") + + sleep(5.0) + + dump_tracer(robot.tracer) + + # --- DISPLAY + dcm_data = np.loadtxt('/tmp/dg_'+robot.estimator.name+'-dcm.dat') + zmp_data = np.loadtxt('/tmp/dg_'+robot.dynamic.name+'-zmp.dat') + zmpDes_data = np.loadtxt('/tmp/dg_'+robot.dcm_control.name+'-zmpRef.dat') + com_data = np.loadtxt('/tmp/dg_'+robot.dynamic.name+'-com.dat') + comDes_data = np.loadtxt('/tmp/dg_'+robot.com_admittance_control.name+'-comRef.dat') + + plt.figure() + plt.plot(dcm_data[:,1],'b-') + plt.plot(dcm_data[:,2],'r-') + plt.title('DCM') + plt.legend(['x','y']) + + plt.figure() + plt.plot(com_data[:,1],'b-') + plt.plot(comDes_data[:,1],'b--') + plt.plot(com_data[:,2],'r-') + plt.plot(comDes_data[:,2],'r--') + plt.plot(com_data[:,3],'g-') + plt.plot(comDes_data[:,3],'g--') + plt.title('COM real vs desired') + plt.legend(['Real x','Desired x','Real y','Desired y','Real z','Desired z']) + + plt.figure() + plt.plot(com_data[:,1],'b-') + plt.title('COM real x') + plt.figure() + plt.plot(comDes_data[:,1],'b--') + plt.title('COM desired x') + + plt.figure() + plt.plot(com_data[:,2],'r-') + plt.title('COM real y') + plt.figure() + plt.plot(comDes_data[:,2],'r--') + plt.title('COM desired y') + + plt.figure() + plt.plot(com_data[:,3],'g-') + plt.title('COM real z') + plt.figure() + plt.plot(comDes_data[:,3],'g--') + plt.title('COM desired z') + + plt.figure() + plt.plot(zmp_data[:,1],'b-') + plt.plot(zmpDes_data[:,1],'b--') + plt.plot(zmp_data[:,2],'r-') + plt.plot(zmpDes_data[:,2],'r--') + plt.title('ZMP real vs desired') + plt.legend(['Real x','Desired x','Real y','Desired y']) + + plt.figure() + plt.plot(zmp_data[:,1] - zmpDes_data[:,1],'b-') + plt.plot(zmp_data[:,2] - zmpDes_data[:,2],'r-') + plt.title('ZMP error') + plt.legend(['Error on x','Error on y']) + + plt.show() + diff --git a/python/sot_talos_balance/test/test_dcmComZmpControl.py b/python/sot_talos_balance/test/test_dcmComZmpControl.py new file mode 100644 index 0000000..0ddc168 --- /dev/null +++ b/python/sot_talos_balance/test/test_dcmComZmpControl.py @@ -0,0 +1,130 @@ +from sot_talos_balance.create_entities_utils import create_com_admittance_controller, create_dummy_dcm_estimator, create_dcm_com_controller +from dynamic_graph.sot.core.meta_tasks_kine import MetaTaskKine6d, MetaTaskKineCom, gotoNd +from dynamic_graph.sot.core.matrix_util import matrixToTuple +from dynamic_graph import plug +from dynamic_graph.sot.core import SOT +from numpy import eye +from time import sleep +import sys +import os + +from dynamic_graph.tracer_real_time import TracerRealTime +from sot_talos_balance.create_entities_utils import addTrace, dump_tracer +import matplotlib.pyplot as plt +import numpy as np + +def main(robot): + dt = robot.timeStep; + + # --- COM + robot.taskCom = MetaTaskKineCom(robot.dynamic) + robot.dynamic.com.recompute(0) + robot.taskCom.featureDes.errorIN.value = robot.dynamic.com.value + robot.taskCom.task.controlGain.value = 600 + + # --- Dummy estimator + robot.estimator = create_dummy_dcm_estimator(robot) + + # --- DCM controller + Kp_dcm = [5.0,5.0,5.0] + Ki_dcm = [0.0,0.0,0.0] + robot.dcm_control = create_dcm_com_controller(Kp_dcm,Ki_dcm,dt,robot,robot.estimator.dcm) + + # --- Admittance controller + Kp_adm = [0.0,0.0,0.0] + robot.com_admittance_control = create_com_admittance_controller(Kp_adm,dt,robot) + + # --- CONTACTS + #define contactLF and contactRF + robot.contactLF = MetaTaskKine6d('contactLF',robot.dynamic,'LF',robot.OperationalPointsMap['left-ankle']) + robot.contactLF.feature.frame('desired') + robot.contactLF.gain.setConstant(300) + robot.contactLF.keep() + locals()['contactLF'] = robot.contactLF + + robot.contactRF = MetaTaskKine6d('contactRF',robot.dynamic,'RF',robot.OperationalPointsMap['right-ankle']) + robot.contactRF.feature.frame('desired') + robot.contactRF.gain.setConstant(300) + robot.contactRF.keep() + locals()['contactRF'] = robot.contactRF + + robot.sot = SOT('sot') + robot.sot.setSize(robot.dynamic.getDimension()) + plug(robot.sot.control,robot.device.control) + + robot.sot.push(robot.contactRF.task.name) + robot.sot.push(robot.contactLF.task.name) + robot.sot.push(robot.taskCom.task.name) + robot.device.control.recompute(0) + + # --- TRACER + robot.tracer = TracerRealTime("zmp_tracer") + robot.tracer.setBufferSize(80*(2**20)) + robot.tracer.open('/tmp','dg_','.dat') + robot.device.after.addSignal('{0}.triger'.format(robot.tracer.name)) + + addTrace(robot.tracer, robot.dynamic, 'zmp') + addTrace(robot.tracer, robot.dcm_control, 'zmpRef') + addTrace(robot.tracer, robot.estimator, 'dcm') + addTrace(robot.tracer, robot.dynamic, 'com') + addTrace(robot.tracer, robot.com_admittance_control, 'comRef') + + # SIMULATION + + plug(robot.com_admittance_control.comRef,robot.taskCom.featureDes.errorIN) + sleep(1.0) + os.system("rosservice call \start_dynamic_graph") + sleep(2.0) + + plug(robot.dcm_control.zmpRef,robot.com_admittance_control.zmpDes) + + robot.com_admittance_control.setState(robot.dynamic.com.value,[0.0,0.0,0.0]) + robot.com_admittance_control.Kp.value = [10.0,10.0,0.0] + robot.dcm_control.resetDcmIntegralError() + robot.dcm_control.Ki.value = [1.0,1.0,0.0] + + robot.tracer.start() + + sleep(5.0) + + dump_tracer(robot.tracer) + + # --- DISPLAY + dcm_data = np.loadtxt('/tmp/dg_'+robot.estimator.name+'-dcm.dat') + zmp_data = np.loadtxt('/tmp/dg_'+robot.dynamic.name+'-zmp.dat') + zmpDes_data = np.loadtxt('/tmp/dg_'+robot.dcm_control.name+'-zmpRef.dat') + com_data = np.loadtxt('/tmp/dg_'+robot.dynamic.name+'-com.dat') + comDes_data = np.loadtxt('/tmp/dg_'+robot.com_admittance_control.name+'-comRef.dat') + + plt.figure() + plt.plot(dcm_data[:,1],'b-') + plt.plot(dcm_data[:,2],'r-') + plt.title('DCM') + plt.legend(['x','y']) + + plt.figure() + plt.plot(com_data[:,1],'b-') + plt.plot(comDes_data[:,1],'b--') + plt.plot(com_data[:,2],'r-') + plt.plot(comDes_data[:,2],'r--') + plt.plot(com_data[:,3],'g-') + plt.plot(comDes_data[:,3],'g--') + plt.title('COM real vs desired') + plt.legend(['Real x','Desired x','Real y','Desired y','Real z','Desired z']) + + plt.figure() + plt.plot(zmp_data[:,1],'b-') + plt.plot(zmpDes_data[:,1],'b--') + plt.plot(zmp_data[:,2],'r-') + plt.plot(zmpDes_data[:,2],'r--') + plt.title('ZMP real vs desired') + plt.legend(['Real x','Desired x','Real y','Desired y']) + + plt.figure() + plt.plot(zmp_data[:,1] - zmpDes_data[:,1],'b-') + plt.plot(zmp_data[:,2] - zmpDes_data[:,2],'r-') + plt.title('ZMP error') + plt.legend(['Error on x','Error on y']) + + plt.show() + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 26271ae..a4c9caf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,6 +36,7 @@ ENDIF(UNIX) #This project will create many plugins as shared libraries, listed here SET(plugins example + dcm-com-controller dcm-controller dummy-dcm-estimator com-admittance-controller diff --git a/src/dcm-com-controller.cpp b/src/dcm-com-controller.cpp new file mode 100644 index 0000000..99f546b --- /dev/null +++ b/src/dcm-com-controller.cpp @@ -0,0 +1,230 @@ +/* + * 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 + -- GitLab