sot-talos-balance  2.0.5
Collection of dynamic-graph entities aimed at implementing balance control on talos.
simple-distribute-wrench.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2018, Gepetto team, LAAS-CNRS
3  *
4  * This file is part of sot-talos-balance.
5  * sot-talos-balance is free software: you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License
7  * as published by the Free Software Foundation, either version 3 of
8  * the License, or (at your option) any later version.
9  * sot-talos-balance is distributed in the hope that it will be
10  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
11  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details. You should
13  * have received a copy of the GNU Lesser General Public License along
14  * with sot-talos-balance. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
18 
19 #include <dynamic-graph/all-commands.h>
20 #include <dynamic-graph/factory.h>
21 
22 #include <iostream>
23 #include <pinocchio/algorithm/frames.hpp>
24 #include <pinocchio/algorithm/kinematics.hpp>
25 #include <pinocchio/parsers/urdf.hpp>
26 #include <sot/core/debug.hh>
27 #include <sot/core/stop-watch.hh>
28 
29 namespace dynamicgraph {
30 namespace sot {
31 namespace talos_balance {
32 namespace dg = ::dynamicgraph;
33 using namespace dg;
34 using namespace dg::command;
35 
36 // Size to be aligned "-------------------------------------------------------"
37 #define PROFILE_SIMPLE_DISTRIBUTE_WRENCH_KINEMATICS_COMPUTATIONS \
38  "SimpleDistributeWrench: kinematics computations "
39 #define PROFILE_SIMPLE_DISTRIBUTE_WRENCH_WRENCHES_COMPUTATIONS \
40  "SimpleDistributeWrench: wrenches computations "
41 
42 #define INPUT_SIGNALS m_wrenchDesSIN << m_qSIN << m_rhoSIN << m_phaseSIN
43 
44 #define INNER_SIGNALS m_kinematics_computations << m_wrenches
45 
46 #define OUTPUT_SIGNALS \
47  m_wrenchLeftSOUT << m_ankleWrenchLeftSOUT << m_surfaceWrenchLeftSOUT \
48  << m_copLeftSOUT << m_wrenchRightSOUT \
49  << m_ankleWrenchRightSOUT << m_surfaceWrenchRightSOUT \
50  << m_copRightSOUT << m_wrenchRefSOUT << m_zmpRefSOUT \
51  << m_emergencyStopSOUT
52 
55 typedef SimpleDistributeWrench EntityClassName;
56 
57 /* --- DG FACTORY ---------------------------------------------------- */
59  "SimpleDistributeWrench");
60 
61 /* ------------------------------------------------------------------- */
62 /* --- CONSTRUCTION -------------------------------------------------- */
63 /* ------------------------------------------------------------------- */
65  : Entity(name),
66  CONSTRUCT_SIGNAL_IN(wrenchDes, dynamicgraph::Vector),
67  CONSTRUCT_SIGNAL_IN(q, dynamicgraph::Vector),
68  CONSTRUCT_SIGNAL_IN(rho, double),
69  CONSTRUCT_SIGNAL_IN(phase, int),
70  CONSTRUCT_SIGNAL_INNER(kinematics_computations, int, m_qSIN),
71  CONSTRUCT_SIGNAL_INNER(wrenches, int,
72  m_wrenchDesSIN << m_rhoSIN << m_phaseSIN
73  << m_kinematics_computationsSINNER),
74  CONSTRUCT_SIGNAL_OUT(wrenchLeft, dynamicgraph::Vector, m_wrenchesSINNER),
75  CONSTRUCT_SIGNAL_OUT(ankleWrenchLeft, dynamicgraph::Vector,
76  m_wrenchLeftSOUT),
77  CONSTRUCT_SIGNAL_OUT(surfaceWrenchLeft, dynamicgraph::Vector,
78  m_wrenchLeftSOUT),
79  CONSTRUCT_SIGNAL_OUT(copLeft, dynamicgraph::Vector, m_wrenchLeftSOUT),
80  CONSTRUCT_SIGNAL_OUT(wrenchRight, dynamicgraph::Vector, m_wrenchesSINNER),
81  CONSTRUCT_SIGNAL_OUT(ankleWrenchRight, dynamicgraph::Vector,
82  m_wrenchRightSOUT),
83  CONSTRUCT_SIGNAL_OUT(surfaceWrenchRight, dynamicgraph::Vector,
84  m_wrenchRightSOUT),
85  CONSTRUCT_SIGNAL_OUT(copRight, dynamicgraph::Vector, m_wrenchRightSOUT),
86  CONSTRUCT_SIGNAL_OUT(wrenchRef, dynamicgraph::Vector,
87  m_wrenchLeftSOUT << m_wrenchRightSOUT),
88  CONSTRUCT_SIGNAL_OUT(zmpRef, dynamicgraph::Vector, m_wrenchRefSOUT),
89  CONSTRUCT_SIGNAL_OUT(emergencyStop, bool, m_zmpRefSOUT),
90  m_initSucceeded(false),
91  m_model(),
92  m_data(pinocchio::Model()) {
93  Entity::signalRegistration(INPUT_SIGNALS << OUTPUT_SIGNALS);
94 
95  /* Commands. */
96  addCommand("init", makeCommandVoid1(*this, &SimpleDistributeWrench::init,
97  docCommandVoid1("Initialize the entity.",
98  "Robot name")));
99 }
100 
101 void SimpleDistributeWrench::init(const std::string& robotName) {
102  if (!m_wrenchDesSIN.isPlugged())
103  return SEND_MSG("Init failed: signal wrenchDes is not plugged",
104  MSG_TYPE_ERROR);
105  if (!m_qSIN.isPlugged())
106  return SEND_MSG("Init failed: signal q is not plugged", MSG_TYPE_ERROR);
107 
108  try {
109  /* Retrieve m_robot_util informations */
110  std::string localName(robotName);
111  if (isNameInRobotUtil(localName)) {
112  m_robot_util = getRobotUtil(localName);
113  // std::cerr << "m_robot_util:" << m_robot_util << std::endl;
114  } else {
115  SEND_MSG("You should have a robotUtil pointer initialized before",
116  MSG_TYPE_ERROR);
117  return;
118  }
119 
120  pinocchio::urdf::buildModel(m_robot_util->m_urdf_filename,
121  pinocchio::JointModelFreeFlyer(), m_model);
122  m_data = pinocchio::Data(m_model);
123  } catch (const std::exception& e) {
124  std::cout << e.what();
125  SEND_MSG("Init failed: Could load URDF :" + m_robot_util->m_urdf_filename,
126  MSG_TYPE_ERROR);
127  return;
128  }
129 
130  assert(m_model.existFrame(m_robot_util->m_foot_util.m_Left_Foot_Frame_Name));
131  assert(m_model.existFrame(m_robot_util->m_foot_util.m_Right_Foot_Frame_Name));
133  m_model.getFrameId(m_robot_util->m_foot_util.m_Left_Foot_Frame_Name);
135  m_model.getFrameId(m_robot_util->m_foot_util.m_Right_Foot_Frame_Name);
136 
137  // m_ankle_M_ftSens = pinocchio::SE3(Eigen::Matrix3d::Identity(),
138  // m_robot_util->m_foot_util.m_Right_Foot_Force_Sensor_XYZ.head<3>());
140  pinocchio::SE3(Eigen::Matrix3d::Identity(),
141  m_robot_util->m_foot_util.m_Right_Foot_Sole_XYZ.head<3>());
142 
143  m_initSucceeded = true;
144 }
145 
147  const dg::Vector& wrenchGlobal, const pinocchio::SE3& pose) const {
149  pose.actInv(pinocchio::Force(wrenchGlobal)).toVector();
150 
151  const double h = pose.translation()[2];
152 
153  const double fx = wrench[0];
154  const double fy = wrench[1];
155  const double fz = wrench[2];
156  const double tx = wrench[3];
157  const double ty = wrench[4];
158 
159  double m_eps = 0.1; // temporary
160 
161  double px, py;
162 
163  if (fz >= m_eps / 2) {
164  px = (-ty - fx * h) / fz;
165  py = (tx - fy * h) / fz;
166  } else {
167  px = 0.0;
168  py = 0.0;
169  }
170  const double pz = 0.0;
171 
172  Eigen::Vector3d cop;
173  cop[0] = px;
174  cop[1] = py;
175  cop[2] = pz;
176 
177  return cop;
178 }
179 
180 /* ------------------------------------------------------------------- */
181 /* --- SIGNALS ------------------------------------------------------- */
182 /* ------------------------------------------------------------------- */
183 
184 DEFINE_SIGNAL_INNER_FUNCTION(kinematics_computations, int) {
185  if (!m_initSucceeded) {
186  SEND_WARNING_STREAM_MSG(
187  "Cannot compute signal kinematics_computations before initialization!");
188  return s;
189  }
190 
191  const Eigen::VectorXd& q = m_qSIN(iter);
192  assert(q.size() == m_model.nq && "Unexpected size of signal q");
193 
195 
196  pinocchio::forwardKinematics(m_model, m_data, q);
197  pinocchio::updateFramePlacement(m_model, m_data, m_left_foot_id);
198  pinocchio::updateFramePlacement(m_model, m_data, m_right_foot_id);
199 
200  m_contactLeft = m_data.oMf[m_left_foot_id] * m_ankle_M_sole;
201  m_contactRight = m_data.oMf[m_right_foot_id] * m_ankle_M_sole;
202 
204 
205  return s;
206 }
207 
208 void SimpleDistributeWrench::distributeWrench(const Eigen::VectorXd& wrenchDes,
209  const double rho) {
210  Eigen::Vector3d forceLeft = wrenchDes.head<3>() / 2;
211  Eigen::Vector3d forceRight = forceLeft;
212  forceLeft[2] = rho * wrenchDes[2];
213  forceRight[2] = (1 - rho) * wrenchDes[2];
214 
215  Eigen::Vector3d tauLeft = m_contactLeft.translation().cross(forceLeft);
216  Eigen::Vector3d tauRight = m_contactRight.translation().cross(forceRight);
217 
218  Eigen::Vector3d tauResidual = (wrenchDes.tail<3>() - tauLeft - tauRight) / 2;
219  tauLeft += tauResidual;
220  tauRight += tauResidual;
221 
222  m_wrenchLeft << forceLeft, tauLeft;
223  m_wrenchRight << forceRight, tauRight;
224 
225  const bool success = true;
226 
227  m_emergency_stop_triggered = !success;
228 }
229 
230 void SimpleDistributeWrench::saturateWrench(const Eigen::VectorXd& wrenchDes,
231  const int phase) {
232  const bool success = true;
233 
234  m_emergency_stop_triggered = !success;
235 
236  const Eigen::VectorXd& result = wrenchDes;
237 
238  if (phase > 0) {
239  m_wrenchLeft = result;
240  m_wrenchRight.setZero(6);
241  } else if (phase < 0) {
242  m_wrenchRight = result;
243  m_wrenchLeft.setZero(6);
244  }
245 }
246 
248  if (!m_initSucceeded) {
249  SEND_WARNING_STREAM_MSG(
250  "Cannot compute signal wrenches before initialization!");
251  return s;
252  }
253 
254  const Eigen::VectorXd& wrenchDes = m_wrenchDesSIN(iter);
255  const int& dummy = m_kinematics_computationsSINNER(iter);
256  (void)dummy;
257  const int& phase = m_phaseSIN(iter);
258 
259  assert(wrenchDes.size() == 6 && "Unexpected size of signal wrenchDes");
260 
262 
263  if (phase == 0) {
264  const double& rho = m_rhoSIN(iter);
265 
266  distributeWrench(wrenchDes, rho);
267  } else {
268  saturateWrench(wrenchDes, phase);
269  }
270 
272 
273  if (m_emergency_stop_triggered) {
274  SEND_WARNING_STREAM_MSG("Error in wrench distribution!");
275  return s;
276  }
277 
278  return s;
279 }
280 
282  if (!m_initSucceeded) {
283  SEND_WARNING_STREAM_MSG(
284  "Cannot compute signal wrenchLeft before initialization!");
285  return s;
286  }
287  if (s.size() != 6) s.resize(6);
288 
289  const int& dummy = m_wrenchesSINNER(iter);
290  (void)dummy;
291  s = m_wrenchLeft;
292  return s;
293 }
294 
296  if (!m_initSucceeded) {
297  SEND_WARNING_STREAM_MSG(
298  "Cannot compute signal wrenchRight before initialization!");
299  return s;
300  }
301  if (s.size() != 6) s.resize(6);
302 
303  const int& dummy = m_wrenchesSINNER(iter);
304  (void)dummy;
305  s = m_wrenchRight;
306  return s;
307 }
308 
310  if (!m_initSucceeded) {
311  SEND_WARNING_STREAM_MSG(
312  "Cannot compute signal ankleWrenchLeft before initialization!");
313  return s;
314  }
315  if (s.size() != 6) s.resize(6);
316 
317  const Eigen::VectorXd& wrenchLeft = m_wrenchLeftSOUT(iter);
318 
319  s = m_data.oMf[m_left_foot_id]
320  .actInv(pinocchio::Force(wrenchLeft))
321  .toVector();
322 
323  return s;
324 }
325 
327  if (!m_initSucceeded) {
328  SEND_WARNING_STREAM_MSG(
329  "Cannot compute signal ankleWrenchRight before initialization!");
330  return s;
331  }
332  if (s.size() != 6) s.resize(6);
333 
334  const Eigen::VectorXd& wrenchRight = m_wrenchRightSOUT(iter);
335 
336  s = m_data.oMf[m_right_foot_id]
337  .actInv(pinocchio::Force(wrenchRight))
338  .toVector();
339 
340  return s;
341 }
342 
344  if (!m_initSucceeded) {
345  SEND_WARNING_STREAM_MSG(
346  "Cannot compute signal surfaceWrenchLeft before initialization!");
347  return s;
348  }
349  if (s.size() != 6) s.resize(6);
350 
351  const Eigen::VectorXd& wrenchLeft = m_wrenchLeftSOUT(iter);
352 
353  s = m_contactLeft.actInv(pinocchio::Force(wrenchLeft)).toVector();
354 
355  return s;
356 }
357 
359  if (!m_initSucceeded) {
360  SEND_WARNING_STREAM_MSG(
361  "Cannot compute signal surfaceWrenchRight before initialization!");
362  return s;
363  }
364  if (s.size() != 6) s.resize(6);
365 
366  const Eigen::VectorXd& wrenchRight = m_wrenchRightSOUT(iter);
367 
368  s = m_contactRight.actInv(pinocchio::Force(wrenchRight)).toVector();
369 
370  return s;
371 }
372 
374  if (!m_initSucceeded) {
375  SEND_WARNING_STREAM_MSG(
376  "Cannot compute signal copLeft before initialization!");
377  return s;
378  }
379  if (s.size() != 3) s.resize(3);
380 
381  const Eigen::VectorXd& wrenchLeft = m_wrenchLeftSOUT(iter);
382 
383  if (m_emergency_stop_triggered) {
384  s.setZero(3);
385  return s;
386  }
387 
388  s = computeCoP(wrenchLeft, m_contactLeft);
389 
390  return s;
391 }
392 
394  if (!m_initSucceeded) {
395  SEND_WARNING_STREAM_MSG(
396  "Cannot compute signal copRight before initialization!");
397  return s;
398  }
399  if (s.size() != 3) s.resize(3);
400 
401  const Eigen::VectorXd& wrenchRight = m_wrenchRightSOUT(iter);
402 
403  if (m_emergency_stop_triggered) {
404  s.setZero(3);
405  return s;
406  }
407 
408  s = computeCoP(wrenchRight, m_contactRight);
409 
410  return s;
411 }
412 
414  if (!m_initSucceeded) {
415  SEND_WARNING_STREAM_MSG(
416  "Cannot compute signal wrenchRef before initialization!");
417  return s;
418  }
419  if (s.size() != 6) s.resize(6);
420 
421  const Eigen::VectorXd& wrenchLeft = m_wrenchLeftSOUT(iter);
422  const Eigen::VectorXd& wrenchRight = m_wrenchRightSOUT(iter);
423 
424  s = wrenchLeft + wrenchRight;
425 
426  return s;
427 }
428 
430  if (!m_initSucceeded) {
431  SEND_WARNING_STREAM_MSG(
432  "Cannot compute signal zmpRef before initialization!");
433  return s;
434  }
435  if (s.size() != 3) s.resize(3);
436 
437  const Eigen::VectorXd& wrenchRef = m_wrenchRefSOUT(iter);
438 
439  if (m_emergency_stop_triggered) {
440  s.setZero(3);
441  return s;
442  }
443 
444  // const double fx = wrenchRef[0];
445  // const double fy = wrenchRef[1];
446  const double fz = wrenchRef[2];
447  const double tx = wrenchRef[3];
448  const double ty = wrenchRef[4];
449 
450  double m_eps = 0.1; // temporary
451 
452  double px, py;
453  if (fz >= m_eps / 2) {
454  px = -ty / fz;
455  py = tx / fz;
456  } else {
457  px = 0.0;
458  py = 0.0;
459  }
460  const double pz = 0.0;
461 
462  Eigen::Vector3d zmp(3);
463  zmp[0] = px;
464  zmp[1] = py;
465  zmp[2] = pz;
466 
467  s = zmp;
468 
469  return s;
470 }
471 
472 DEFINE_SIGNAL_OUT_FUNCTION(emergencyStop, bool) {
473  const dynamicgraph::Vector& zmp =
474  m_zmpRefSOUT(iter); // dummy to trigger zmp computation
475  (void)zmp; // disable unused variable warning
476  s = m_emergency_stop_triggered;
477  return s;
478 }
479 
480 /* --- COMMANDS ---------------------------------------------------------- */
481 
482 /* ------------------------------------------------------------------- */
483 /* --- ENTITY -------------------------------------------------------- */
484 /* ------------------------------------------------------------------- */
485 
486 void SimpleDistributeWrench::display(std::ostream& os) const {
487  os << "SimpleDistributeWrench " << getName();
488  try {
489  getProfiler().report_all(3, os);
490  } catch (ExceptionSignal e) {
491  }
492 }
493 
494 } // namespace talos_balance
495 } // namespace sot
496 } // namespace dynamicgraph
pinocchio::FrameIndex m_left_foot_id
ankle to sole transformation
Eigen::Vector3d computeCoP(const dynamicgraph::Vector &wrench, const pinocchio::SE3 &pose) const
pinocchio::Model m_model
true if the entity has been successfully initialized
void distributeWrench(const Eigen::VectorXd &wrenchDes, const double rho)
EIGEN_MAKE_ALIGNED_OPERATOR_NEW SimpleDistributeWrench(const std::string &name)
void saturateWrench(const Eigen::VectorXd &wrenchDes, const int phase)
Eigen::Matrix< Scalar, 6, 1 > Vector6
Definition: fwd.hh:42
Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > Vector
Definition: fwd.hh:36
DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(AdmittanceControllerEndEffector, "AdmittanceControllerEndEffector")
DEFINE_SIGNAL_INNER_FUNCTION(w_force, dynamicgraph::Vector)
#define PROFILE_SIMPLE_DISTRIBUTE_WRENCH_WRENCHES_COMPUTATIONS
#define INPUT_SIGNALS
#define PROFILE_SIMPLE_DISTRIBUTE_WRENCH_KINEMATICS_COMPUTATIONS
#define OUTPUT_SIGNALS