6 #include <dynamic-graph/factory.h> 
    8 #include <sot/core/debug.hh> 
   11 #include <tsid/utils/stop-watch.hpp> 
   16 namespace dg = ::dynamicgraph;
 
   18 using namespace dg::command;
 
   20 using namespace Eigen;
 
   22 using namespace tsid::math;
 
   23 using namespace tsid::tasks;
 
   24 using namespace dg::sot;
 
   26 #define PROFILE_DQ_DES_COMPUTATION "Admittance control computation" 
   28 #define REF_FORCE_SIGNALS m_fRightFootRefSIN << m_fLeftFootRefSIN 
   30 #define FORCE_SIGNALS                                          \ 
   31   m_fRightFootSIN << m_fLeftFootSIN << m_fRightFootFilteredSIN \ 
   32                   << m_fLeftFootFilteredSIN 
   34 #define GAIN_SIGNALS                                           \ 
   35   m_kp_forceSIN << m_ki_forceSIN << m_kp_velSIN << m_ki_velSIN \ 
   36                 << m_force_integral_saturationSIN              \ 
   37                 << m_force_integral_deadzoneSIN 
   38 #define STATE_SIGNALS m_encodersSIN << m_jointsVelocitiesSIN 
   40 #define INPUT_SIGNALS                                                 \ 
   41   STATE_SIGNALS << REF_FORCE_SIGNALS << FORCE_SIGNALS << GAIN_SIGNALS \ 
   42                 << m_controlledJointsSIN << m_dampingSIN 
   44 #define DES_VEL_SIGNALS \ 
   45   m_vDesRightFootSOUT << m_vDesLeftFootSOUT   
   47 #define OUTPUT_SIGNALS m_uSOUT << m_dqDesSOUT << DES_VEL_SIGNALS 
   53 typedef Eigen::Matrix<double, 3, 1> 
Vector3;
 
   54 typedef Eigen::Matrix<double, 6, 1> 
Vector6;
 
   57                                    "AdmittanceController");
 
   65       CONSTRUCT_SIGNAL_IN(jointsVelocities, 
dynamicgraph::Vector),
 
   70       CONSTRUCT_SIGNAL_IN(force_integral_saturation, 
dynamicgraph::Vector),
 
   71       CONSTRUCT_SIGNAL_IN(force_integral_deadzone, 
dynamicgraph::Vector),
 
   72       CONSTRUCT_SIGNAL_IN(fRightFootRef, 
dynamicgraph::Vector),
 
   76       CONSTRUCT_SIGNAL_IN(fRightFootFiltered, 
dynamicgraph::Vector),
 
   77       CONSTRUCT_SIGNAL_IN(fLeftFootFiltered, 
dynamicgraph::Vector),
 
   78       CONSTRUCT_SIGNAL_IN(controlledJoints, 
dynamicgraph::Vector),
 
   89       CONSTRUCT_SIGNAL_OUT(vDesRightFoot, 
dynamicgraph::Vector,
 
   90                            m_fRightFootSIN << m_fRightFootFilteredSIN
 
   94                            m_fLeftFootSIN << m_fLeftFootFilteredSIN
 
  104       m_initSucceeded(false),
 
  105       m_useJacobianTranspose(true) {
 
  113       "getUseJacobianTranspose",
 
  115                        docDirectGetter(
"If true it uses the Jacobian " 
  116                                        "transpose, otherwise the pseudoinverse",
 
  119       "setUseJacobianTranspose",
 
  121                        docDirectSetter(
"If true it uses the Jacobian " 
  122                                        "transpose, otherwise the pseudoinverse",
 
  126                               docCommandVoid2(
"Initialize the entity.",
 
  127                                               "Time period in seconds (double)",
 
  128                                               "Robot name (string)")));
 
  132   if (dt <= 0.0) 
return SEND_MSG(
"Timestep must be positive", MSG_TYPE_ERROR);
 
  133   if (!m_encodersSIN.isPlugged())
 
  134     return SEND_MSG(
"Init failed: signal encoders is not plugged",
 
  136   if (!m_jointsVelocitiesSIN.isPlugged())
 
  137     return SEND_MSG(
"Init failed: signal jointsVelocities is not plugged",
 
  139   if (!m_controlledJointsSIN.isPlugged())
 
  140     return SEND_MSG(
"Init failed: signal controlledJoints is not plugged",
 
  147   std::string localName(robotRef);
 
  148   if (isNameInRobotUtil(localName))
 
  152         "You should have an entity controller manager initialized before",
 
  156     vector<string> package_dirs;
 
  158         new robots::RobotWrapper(
m_robot_util->m_urdf_filename, package_dirs,
 
  159                                  pinocchio::JointModelFreeFlyer());
 
  181   } 
catch (
const std::exception& e) {
 
  182     std::cout << e.what();
 
  184         "Init failed: Could load URDF :" + 
m_robot_util->m_urdf_filename,
 
  194   if (!m_initSucceeded) {
 
  195     SEND_WARNING_STREAM_MSG(
"Cannot compute signal u before initialization!");
 
  199   const Vector& dqDes = m_dqDesSOUT(iter);         
 
  200   const Vector& q = m_encodersSIN(iter);           
 
  201   const Vector& dq = m_jointsVelocitiesSIN(iter);  
 
  202   const Vector& kp = m_kp_velSIN(iter);
 
  203   const Vector& ki = m_ki_velSIN(iter);
 
  211   m_dq_fd = (q - m_qPrev) / m_dt;
 
  214   m_dqErrIntegral += m_dt * ki.cwiseProduct(dqDes - m_dq_fd);
 
  215   s = kp.cwiseProduct(dqDes - dq) + m_dqErrIntegral;
 
  221   if (!m_initSucceeded) {
 
  222     SEND_WARNING_STREAM_MSG(
 
  223         "Cannot compute signal dqDes before initialization!");
 
  229     const dg::sot::Vector6d v_des_LF = m_vDesLeftFootSOUT(iter);
 
  230     const dg::sot::Vector6d v_des_RF = m_vDesRightFootSOUT(iter);
 
  231     const Vector& q_sot = m_encodersSIN(iter);  
 
  237     assert(q_sot.size() == m_nj && 
"Unexpected size of signal encoder");
 
  240     m_robot_util->joints_sot_to_urdf(q_sot, m_q_urdf.tail(m_nj));
 
  241     m_robot->computeAllTerms(*m_data, m_q_urdf, m_v_urdf);
 
  242     m_robot->frameJacobianLocal(*m_data, m_frame_id_rf, m_J_RF);
 
  243     m_robot->frameJacobianLocal(*m_data, m_frame_id_lf, m_J_LF);
 
  253     if (m_useJacobianTranspose) {
 
  254       m_dq_des_urdf = m_J_RF.rightCols(m_nj).transpose() * v_des_RF;
 
  255       m_dq_des_urdf += m_J_LF.rightCols(m_nj).transpose() * v_des_LF;
 
  257       m_J_RF_QR.compute(m_J_RF.rightCols(m_nj));
 
  258       m_J_LF_QR.compute(m_J_LF.rightCols(m_nj));
 
  260       m_dq_des_urdf = m_J_RF_QR.solve(v_des_RF);
 
  261       m_dq_des_urdf += m_J_LF_QR.solve(v_des_LF);
 
  264     if (s.size() != m_nj) s.resize(m_nj);
 
  266     m_robot_util->joints_urdf_to_sot(m_dq_des_urdf, s);
 
  274   if (!m_initSucceeded) {
 
  275     SEND_MSG(
"Cannot compute signal vDesRightFoot before initialization!",
 
  276              MSG_TYPE_WARNING_STREAM);
 
  279   const Vector6& f = m_fRightFootSIN(iter);
 
  280   const Vector6& f_filt = m_fRightFootFilteredSIN(iter);
 
  281   const Vector6& fRef = m_fRightFootRefSIN(iter);
 
  282   const Vector6d& kp = m_kp_forceSIN(iter);
 
  283   const Vector6d& ki = m_ki_forceSIN(iter);
 
  284   const Vector6d& f_sat = m_force_integral_saturationSIN(iter);
 
  285   const Vector6d& dz = m_force_integral_deadzoneSIN(iter);
 
  287   dg::sot::Vector6d err = fRef - f;
 
  288   dg::sot::Vector6d err_filt = fRef - f_filt;
 
  289   dg::sot::Vector6d v_des = -kp.cwiseProduct(err_filt);
 
  291   for (
int i = 0; i < 6; i++) {
 
  293       m_v_RF_int(i) -= m_dt * ki(i) * (err(i) - dz(i));
 
  294     else if (err(i) < -dz(i))
 
  295       m_v_RF_int(i) -= m_dt * ki(i) * (err(i) + dz(i));
 
  299   bool saturating = 
false;
 
  300   for (
int i = 0; i < 6; i++) {
 
  301     if (m_v_RF_int(i) > f_sat(i)) {
 
  303       m_v_RF_int(i) = f_sat(i);
 
  304     } 
else if (m_v_RF_int(i) < -f_sat(i)) {
 
  306       m_v_RF_int(i) = -f_sat(i);
 
  310     SEND_INFO_STREAM_MSG(
"Saturate m_v_RF_int integral: " +
 
  311                          toString(m_v_RF_int.transpose()));
 
  312   s = v_des + m_v_RF_int;
 
  317   if (!m_initSucceeded) {
 
  318     SEND_MSG(
"Cannot compute signal vDesLeftFoot before initialization!",
 
  319              MSG_TYPE_WARNING_STREAM);
 
  322   const Vector6& f = m_fLeftFootSIN(iter);
 
  323   const Vector6& f_filt = m_fLeftFootFilteredSIN(iter);
 
  324   const Vector6& fRef = m_fLeftFootRefSIN(iter);
 
  325   const Vector6d& kp = m_kp_forceSIN(iter);
 
  326   const Vector6d& ki = m_ki_forceSIN(iter);
 
  327   const Vector6d& f_sat = m_force_integral_saturationSIN(iter);
 
  328   const Vector6d& dz = m_force_integral_deadzoneSIN(iter);
 
  330   dg::sot::Vector6d err = fRef - f;
 
  331   dg::sot::Vector6d err_filt = fRef - f_filt;
 
  332   dg::sot::Vector6d v_des = -kp.cwiseProduct(err_filt);
 
  334   for (
int i = 0; i < 6; i++) {
 
  336       m_v_LF_int(i) -= m_dt * ki(i) * (err(i) - dz(i));
 
  337     else if (err(i) < -dz(i))
 
  338       m_v_LF_int(i) -= m_dt * ki(i) * (err(i) + dz(i));
 
  342   bool saturating = 
false;
 
  343   for (
int i = 0; i < 6; i++) {
 
  344     if (m_v_LF_int(i) > f_sat(i)) {
 
  346       m_v_LF_int(i) = f_sat(i);
 
  347     } 
else if (m_v_LF_int(i) < -f_sat(i)) {
 
  349       m_v_LF_int(i) = -f_sat(i);
 
  353     SEND_INFO_STREAM_MSG(
"Saturate m_v_LF_int integral: " +
 
  354                          toString(m_v_LF_int.transpose()));
 
  355   s = v_des + m_v_LF_int;
 
  411   os << 
"AdmittanceController " << getName();
 
  413     getProfiler().report_all(3, os);
 
  414   } 
catch (ExceptionSignal e) {
 
  421   eigen_assert(A.computeU() && A.computeV() &&
 
  422                "svdSolveWithDamping() requires both unitaries U and V to be " 
  423                "computed (thin unitaries suffice).");
 
  424   assert(A.rows() == b.size());
 
  427   VectorXd tmp(A.cols());
 
  428   int nzsv = 
static_cast<int>(A.nonzeroSingularValues());
 
  429   tmp.noalias() = A.matrixU().leftCols(nzsv).adjoint() * b;
 
  431   double sv, d2 = damping * damping;
 
  432   for (
int i = 0; i < nzsv; i++) {
 
  433     sv = A.singularValues()(i);
 
  434     tmp(i) *= sv / (sv * sv + d2);
 
  437   VectorXd res = A.matrixV().leftCols(nzsv) * tmp;
 
#define PROFILE_DQ_DES_COMPUTATION
 
RobotUtilShrPtr m_robot_util
 
bool m_useJacobianTranspose
true if the entity has been successfully initialized
 
tsid::math::Vector m_dqErrIntegral
 
EIGEN_MAKE_ALIGNED_OPERATOR_NEW AdmittanceController(const std::string &name)
 
tsid::math::Vector m_v_urdf
 
int m_frame_id_lf
frame id of right foot
 
tsid::robots::RobotWrapper * m_robot
frame id of left foot
 
virtual void display(std::ostream &os) const
 
tsid::math::Vector m_q_urdf
desired 6d wrench left foot
 
tsid::math::Vector6 m_v_RF_int
 
tsid::math::Vector6 m_v_LF_int
 
int m_nj
control loop time period
 
tsid::math::Vector m_dq_des_urdf
 
void init(const double &dt, const std::string &robotRef)
 
int m_frame_id_rf
robot geometric/inertial data
 
DEFINE_SIGNAL_OUT_FUNCTION(u, dynamicgraph::Vector)
 
AdmittanceController EntityClassName
 
Eigen::Matrix< double, 3, 1 > Vector3
 
Eigen::Matrix< double, 6, 1 > Vector6
 
VectorXd svdSolveWithDamping(const JacobiSVD< MatrixXd > &A, const VectorXd &b, double damping)
 
DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(AdmittanceController, "AdmittanceController")