- 3.0.2 rigid body dynamics module.
TermTaskspacePoseCG.hpp
Go to the documentation of this file.
1 /**********************************************************************************************************************
2 This file is part of the Control Toolbox (https://github.com/ethz-adrl/control-toolbox), copyright by ETH Zurich.
3 Authors: Michael Neunert, Markus Giftthaler, Markus Stäuble, Diego Pardo, Farbod Farshidian
4 Licensed under the BSD-2 license (see LICENSE file in main directory)
5 **********************************************************************************************************************/
6 
7 #pragma once
8 
9 #ifdef CPPADCG
10 
11 #include <ct/optcon/optcon.h>
12 
14 #include <ct/rbd/state/RBDState.h>
15 
16 namespace ct {
17 namespace rbd {
18 
36 template <class KINEMATICS, bool FLOATING_BASE, size_t STATE_DIM, size_t CONTROL_DIM>
37 class TermTaskspacePoseCG : public optcon::TermBase<STATE_DIM, CONTROL_DIM, double, double>
38 {
39 public:
40  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
41 
42  /*
43  * The AD parameter vector consists of:
44  * - states (STATE_DIM parameters)
45  * - controls (CONTROL_DIM parameters)
46  * - desired end-effector positions (3 parameters)
47  * - desired end-effector orientation (9 parameters)
48  * - time (1 parameter)
49  */
50  static const size_t AD_PARAMETER_DIM = STATE_DIM + CONTROL_DIM + 3 + 9 + 1;
51 
52  using BASE = optcon::TermBase<STATE_DIM, CONTROL_DIM, double, double>;
53 
54  using DerivativesCppadJIT = core::DerivativesCppadJIT<AD_PARAMETER_DIM, 1>;
55  using CGScalar = typename DerivativesCppadJIT::CG_SCALAR;
56 
58 
59  using state_matrix_t = Eigen::Matrix<double, STATE_DIM, STATE_DIM>;
60  using control_matrix_t = Eigen::Matrix<double, CONTROL_DIM, CONTROL_DIM>;
61  using control_state_matrix_t = Eigen::Matrix<double, CONTROL_DIM, STATE_DIM>;
62 
63 
65  TermTaskspacePoseCG() = default;
66 
68  TermTaskspacePoseCG(size_t eeInd,
69  const Eigen::Matrix3d& Qpos,
70  const double& Qrot,
71  const core::StateVector<3>& w_pos_des,
72  const Eigen::Quaterniond& w_q_des,
73  const std::string& name = "TermTaskSpace",
74  bool evalControlDerivatives = true)
75  : BASE(name), eeInd_(eeInd), Q_pos_(Qpos), Q_rot_(Qrot), evalControlDerivatives_(evalControlDerivatives)
76  {
77  setReferencePosition(w_pos_des);
78  setReferenceOrientation(w_q_des);
79  setup();
80  }
81 
83  TermTaskspacePoseCG(size_t eeInd,
84  const Eigen::Matrix3d& Qpos,
85  const double& Qrot,
86  const ct::rbd::RigidBodyPose& rbdPose,
87  const std::string& name = "TermTaskSpace",
88  bool evalControlDerivatives = true)
89  // delegate constructor
90  : TermTaskspacePoseCG(eeInd,
91  Qpos,
92  Qrot,
93  rbdPose.position().toImplementation(),
94  rbdPose.getRotationQuaternion().toImplementation(),
95  name,
96  evalControlDerivatives)
97  {
98  }
99 
101  TermTaskspacePoseCG(size_t eeInd,
102  const Eigen::Matrix3d& Qpos,
103  const double& Qrot,
104  const core::StateVector<3>& w_pos_des,
105  const Eigen::Matrix3d& eulerXyz,
106  const std::string& name = "TermTaskSpace",
107  bool evalControlDerivatives = true)
108  // delegate constructor
109  : TermTaskspacePoseCG(eeInd,
110  Qpos,
111  Qrot,
112  w_pos_des,
113  Eigen::Quaterniond(Eigen::AngleAxisd(eulerXyz(0), Eigen::Vector3d::UnitX()) *
114  Eigen::AngleAxisd(eulerXyz(1), Eigen::Vector3d::UnitY()) *
115  Eigen::AngleAxisd(eulerXyz(2), Eigen::Vector3d::UnitZ())),
116  name,
117  evalControlDerivatives)
118  {
119  }
120 
122  TermTaskspacePoseCG(size_t eeInd,
123  const Eigen::Matrix3d& Qpos,
124  const double& Qrot,
125  const std::string& name = "TermTaskSpace",
126  bool evalControlDerivatives = false)
127  : BASE(name), eeInd_(eeInd), Q_pos_(Qpos), Q_rot_(Qrot), evalControlDerivatives_(evalControlDerivatives)
128  {
129  // arbitrary dummy values
130  Eigen::Quaterniond w_q_des(0.0, 0.0, 0.0, 1.0);
131  setReferenceOrientation(w_q_des);
132  setReferencePosition(core::StateVector<3>::Zero());
133  setup();
134  }
135 
137  TermTaskspacePoseCG(const std::string& configFile, const std::string& termName, bool verbose = false)
138  {
139  loadConfigFile(configFile, termName, verbose);
140  }
141 
143  TermTaskspacePoseCG(const TermTaskspacePoseCG& arg)
144  : BASE(arg),
145  eeInd_(arg.eeInd_),
146  kinematics_(KINEMATICS()),
147  Q_pos_(arg.Q_pos_),
148  Q_rot_(arg.Q_rot_),
149  costFun_(arg.costFun_),
150  adParameterVector_(arg.adParameterVector_),
151  evalControlDerivatives_(arg.evalControlDerivatives_)
152  {
153  derivativesCppadJIT_ = std::shared_ptr<DerivativesCppadJIT>(arg.derivativesCppadJIT_->clone());
154  }
155 
157  virtual ~TermTaskspacePoseCG() {}
159  virtual TermTaskspacePoseCG<KINEMATICS, FLOATING_BASE, STATE_DIM, CONTROL_DIM>* clone() const override
160  {
161  return new TermTaskspacePoseCG(*this);
162  }
163 
165  void setup()
166  {
167  // map term evaluation function to AD function
168  costFun_ = [&](const Eigen::Matrix<CGScalar, AD_PARAMETER_DIM, 1>& inputParams) {
169  return evalLocal<CGScalar>(inputParams);
170  };
171 
172  // set up derivatives
173  derivativesCppadJIT_ =
174  std::shared_ptr<DerivativesCppadJIT>(new DerivativesCppadJIT(costFun_, AD_PARAMETER_DIM, 1));
175 
177  settings.createForwardZero_ = true;
178  settings.createJacobian_ = true;
179  settings.createHessian_ = true;
180 
181  std::cout << "compiling JIT for TermTaskspacePoseCG" << std::endl;
182  derivativesCppadJIT_->compileJIT(settings, "TermTaskspacePoseCGcosts");
183  }
184 
185 
186  void setCurrentStateAndControl(const Eigen::Matrix<double, STATE_DIM, 1>& x,
187  const Eigen::Matrix<double, CONTROL_DIM, 1>& u,
188  const double& t)
189  {
190  adParameterVector_.template segment<STATE_DIM>(0) = x;
191  adParameterVector_.template segment<CONTROL_DIM>(STATE_DIM) = u;
192  adParameterVector_(AD_PARAMETER_DIM - 1) = t;
193  }
194 
195 
197  virtual double evaluate(const Eigen::Matrix<double, STATE_DIM, 1>& x,
198  const Eigen::Matrix<double, CONTROL_DIM, 1>& u,
199  const double& t) override
200  {
201  setCurrentStateAndControl(x, u, t);
202  return derivativesCppadJIT_->forwardZero(adParameterVector_)(0);
203  }
204 
205 
207  virtual core::StateVector<STATE_DIM> stateDerivative(const core::StateVector<STATE_DIM>& x,
208  const core::ControlVector<CONTROL_DIM>& u,
209  const double& t) override
210  {
211  setCurrentStateAndControl(x, u, t);
212  Eigen::Matrix<double, 1, AD_PARAMETER_DIM> jacTot = derivativesCppadJIT_->jacobian(adParameterVector_);
213  return jacTot.template leftCols<STATE_DIM>().transpose();
214  }
215 
217  virtual core::ControlVector<CONTROL_DIM> controlDerivative(const core::StateVector<STATE_DIM>& x,
218  const core::ControlVector<CONTROL_DIM>& u,
219  const double& t) override
220  {
221  if (evalControlDerivatives_)
222  {
223  setCurrentStateAndControl(x, u, t);
224  Eigen::Matrix<double, 1, AD_PARAMETER_DIM> jacTot = derivativesCppadJIT_->jacobian(adParameterVector_);
225  return jacTot.template block<1, CONTROL_DIM>(0, STATE_DIM).transpose();
226  }
227  else
228  return core::ControlVector<CONTROL_DIM>::Zero();
229  }
230 
232  virtual state_matrix_t stateSecondDerivative(const core::StateVector<STATE_DIM>& x,
233  const core::ControlVector<CONTROL_DIM>& u,
234  const double& t) override
235  {
236  setCurrentStateAndControl(x, u, t);
237  Eigen::Matrix<double, 1, 1> w(1.0);
238  Eigen::MatrixXd hesTot = derivativesCppadJIT_->hessian(adParameterVector_, w);
239  return hesTot.template block<STATE_DIM, STATE_DIM>(0, 0);
240  }
241 
243  virtual control_matrix_t controlSecondDerivative(const core::StateVector<STATE_DIM>& x,
244  const core::ControlVector<CONTROL_DIM>& u,
245  const double& t) override
246  {
247  if (evalControlDerivatives_)
248  {
249  setCurrentStateAndControl(x, u, t);
250  Eigen::Matrix<double, 1, 1> w(1.0);
251  Eigen::MatrixXd hesTot = derivativesCppadJIT_->hessian(adParameterVector_, w);
252  return hesTot.template block<CONTROL_DIM, CONTROL_DIM>(STATE_DIM, STATE_DIM);
253  }
254  else
255  return control_matrix_t::Zero();
256  }
257 
259  virtual control_state_matrix_t stateControlDerivative(const core::StateVector<STATE_DIM>& x,
260  const core::ControlVector<CONTROL_DIM>& u,
261  const double& t) override
262  {
263  if (evalControlDerivatives_)
264  {
265  setCurrentStateAndControl(x, u, t);
266  Eigen::Matrix<double, 1, 1> w(1.0);
267  Eigen::MatrixXd hesTot = derivativesCppadJIT_->hessian(adParameterVector_, w);
268  return hesTot.template block<CONTROL_DIM, STATE_DIM>(STATE_DIM, 0);
269  }
270  else
271  return control_state_matrix_t::Zero();
272  }
273 
274 
276  void loadConfigFile(const std::string& filename, const std::string& termName, bool verbose = false) override
277  {
278  if (verbose)
279  std::cout << "Loading TermTaskspacePoseCG from file " << filename << std::endl;
280 
281  ct::optcon::loadScalarCF(filename, "eeId", eeInd_, termName);
282  ct::optcon::loadScalarCF(filename, "Q_rot", Q_rot_, termName);
283 
284  ct::optcon::loadMatrixCF(filename, "Q_pos", Q_pos_, termName);
285 
286  Eigen::Matrix<double, 3, 1> w_p_ref;
287  ct::optcon::loadMatrixCF(filename, "x_des", w_p_ref, termName);
288  setReferencePosition(w_p_ref);
289 
290  ct::optcon::loadScalarCF(filename, "evalControlDerivatives", evalControlDerivatives_, termName);
291 
292 
293  // try loading euler angles
294  if (verbose)
295  std::cout << "trying to load euler angles" << std::endl;
296  try
297  {
298  Eigen::Vector3d eulerXyz;
299  ct::optcon::loadMatrixCF(filename, "eulerXyz_des", eulerXyz, termName);
300  Eigen::Quaternion<double> quat_des(Eigen::AngleAxisd(eulerXyz(0), Eigen::Vector3d::UnitX()) *
301  Eigen::AngleAxisd(eulerXyz(1), Eigen::Vector3d::UnitY()) *
302  Eigen::AngleAxisd(eulerXyz(2), Eigen::Vector3d::UnitZ()));
303  setReferenceOrientation(quat_des);
304  if (verbose)
305  std::cout << "Read desired Euler Angles Xyz as = \n" << eulerXyz.transpose() << std::endl;
306  } catch (const std::exception& e)
307  {
308  throw std::runtime_error(
309  "Failed to load TermTaskspacePoseCG, could not find a desired end effector orientation in file.");
310  }
311 
312  if (verbose)
313  {
314  std::cout << "Read eeId as eeId = \n" << eeInd_ << std::endl;
315  std::cout << "Read Q_pos as Q_pos = \n" << Q_pos_ << std::endl;
316  std::cout << "Read Q_rot as Q_rot = \n" << Q_rot_ << std::endl;
317  std::cout << "Read x_des as x_des = \n" << getReferencePosition().transpose() << std::endl;
318  std::cout << "Read evalControlDerivatives as evalControlDerivatives = \n"
319  << evalControlDerivatives_ << std::endl;
320  }
321 
322  // new initialization required
323  setup();
324  }
325 
326 
328  const Eigen::Matrix<double, 3, 1> getReferencePosition() const
329  {
330  return adParameterVector_.template segment<3>(STATE_DIM + CONTROL_DIM);
331  }
332 
334  void setReferencePosition(Eigen::Matrix<double, 3, 1> w_p_ref)
335  {
336  adParameterVector_.template segment<3>(STATE_DIM + CONTROL_DIM) = w_p_ref;
337  }
338 
340  const Eigen::Quaterniond getReferenceOrientation() const
341  {
342  return Eigen::Quaterniond(extractReferenceRotationMatrix(adParameterVector_));
343  }
344 
346  void setReferenceOrientation(const Eigen::Matrix<double, 3, 3>& w_R_ref)
347  {
348  // transcribe the rotation matrix into the parameter vector
349  const Eigen::Matrix<double, 9, 1> matVectorized(
350  Eigen::Map<const Eigen::Matrix<double, 9, 1>>(w_R_ref.data(), 9));
351  adParameterVector_.template segment<9>(STATE_DIM + CONTROL_DIM + 3) = matVectorized;
352  }
353 
355  void setReferenceOrientation(const Eigen::Quaterniond& w_q_des)
356  {
357  setReferenceOrientation(w_q_des.normalized().toRotationMatrix());
358  }
359 
361  const ct::rbd::RigidBodyPose getReferencePose() const
362  {
363  return ct::rbd::RigidBodyPose(getReferenceOrientation(), getReferencePosition());
364  }
365 
366 
367 protected:
374  virtual RBDStateTpl setStateFromVector(const Eigen::Matrix<CGScalar, STATE_DIM, 1>& x)
375  {
376  return setStateFromVector_specialized<FLOATING_BASE>(x);
377  }
378 
379 private:
381  template <typename SC>
382  const Eigen::Matrix<SC, 3, 3> extractReferenceRotationMatrix(
383  const Eigen::Matrix<SC, AD_PARAMETER_DIM, 1>& parameterVector) const
384  {
385  Eigen::Matrix<SC, 9, 1> matVectorized = parameterVector.template segment<9>(STATE_DIM + CONTROL_DIM + 3);
386  Eigen::Matrix<SC, 3, 3> w_R_ee(Eigen::Map<Eigen::Matrix<SC, 3, 3>>(matVectorized.data(), 3, 3));
387  return w_R_ee;
388  }
389 
391  template <typename SC>
392  const Eigen::Matrix<SC, STATE_DIM, 1> extractStateVector(
393  const Eigen::Matrix<SC, AD_PARAMETER_DIM, 1>& parameterVector) const
394  {
395  return parameterVector.template segment<STATE_DIM>(0);
396  }
397 
399  template <typename SC>
400  const Eigen::Matrix<SC, 3, 1> extractReferencePosition(
401  const Eigen::Matrix<SC, AD_PARAMETER_DIM, 1>& parameterVector) const
402  {
403  return parameterVector.template segment<3>(STATE_DIM + CONTROL_DIM);
404  }
405 
407  template <bool FB>
408  RBDStateTpl setStateFromVector_specialized(const Eigen::Matrix<CGScalar, -1, 1>& x,
409  typename std::enable_if<FB, bool>::type = true)
410  {
411  RBDStateTpl rbdState;
412  rbdState.fromStateVectorEulerXyz(x);
413  return rbdState;
414  }
415 
417  template <bool FB>
418  RBDStateTpl setStateFromVector_specialized(const Eigen::Matrix<CGScalar, -1, 1>& x,
419  typename std::enable_if<!FB, bool>::type = true)
420  {
421  RBDStateTpl rbdState;
422  rbdState.joints().toImplementation() = x.head(STATE_DIM);
423  return rbdState;
424  }
425 
426 
428  template <typename SC>
429  Eigen::Matrix<SC, 1, 1> evalLocal(const Eigen::Matrix<SC, AD_PARAMETER_DIM, 1>& adParams)
430  {
431  // extract state, plus position and rotation references
432  Eigen::Matrix<SC, STATE_DIM, 1> x = extractStateVector(adParams);
433  Eigen::Matrix<SC, 3, 1> w_p_ref = extractReferencePosition(adParams);
434  Eigen::Matrix<SC, 3, 3> w_R_ref = extractReferenceRotationMatrix<SC>(adParams);
435 
436  // transform the robot state vector into a CT RBDState
437  RBDState<KINEMATICS::NJOINTS, SC> rbdState = setStateFromVector(x);
438 
439  // position difference in world frame
440  Eigen::Matrix<SC, 3, 1> xCurr =
441  kinematics_.getEEPositionInWorld(eeInd_, rbdState.basePose(), rbdState.jointPositions()).toImplementation();
442  Eigen::Matrix<SC, 3, 1> xDiff = xCurr - w_p_ref;
443 
444 
445  // compute the cost from the position error
446  SC pos_cost = (xDiff.transpose() * Q_pos_.template cast<SC>() * xDiff)(0, 0);
447 
448 
449  // get current end-effector rotation in world frame
450  Eigen::Matrix<SC, 3, 3> ee_rot =
451  kinematics_.getEERotInWorld(eeInd_, rbdState.basePose(), rbdState.jointPositions());
452 
453  // compute a measure for the difference between current rotation and desired rotation and compute cost based on the orientation error
454  // for the intuition behind, consider the following posts:
455  // https://math.stackexchange.com/a/87698
456  // https://math.stackexchange.com/a/773635
457  Eigen::Matrix<SC, 3, 3> ee_R_diff = w_R_ref.transpose() * ee_rot;
458 
459  // compute rotation penalty using the Frobenius norm of (R_diff-I)
460  SC rot_cost = (SC)Q_rot_ * (ee_R_diff - Eigen::Matrix<SC, 3, 3>::Identity()).squaredNorm();
461 
462  Eigen::Matrix<SC, 1, 1> result;
463  result(0, 0) = (pos_cost + rot_cost);
464  return result;
465  }
466 
468  size_t eeInd_;
469 
471  KINEMATICS kinematics_;
472 
474  Eigen::Matrix3d Q_pos_;
475 
477  double Q_rot_;
478 
480  std::shared_ptr<DerivativesCppadJIT> derivativesCppadJIT_;
481 
483  typename DerivativesCppadJIT::FUN_TYPE_CG costFun_;
484 
486  Eigen::Matrix<double, AD_PARAMETER_DIM, 1> adParameterVector_;
487 
491  bool evalControlDerivatives_;
492 };
493 
494 
495 } // namespace rbd
496 } // namespace ct
497 
498 #endif
Eigen::Matrix< double, nControls, nControls > control_matrix_t
Cored::Vector3 Vector3d
Definition: rbd.h:137
tpl::RigidBodyPose< double > RigidBodyPose
Definition: RigidBodyPose.h:426
Definition: eigen_traits.h:23
joint states and base states
Definition: RBDState.h:27
bool verbose
Definition: rbdJITtests.h:15
void loadScalarCF(const std::string &filename, const std::string &scalarName, SCALAR &scalar, const std::string &termName="")
double Qrot
Definition: rbdJITtests.h:28
const Eigen::Matrix< double, 3, 3 > Qpos
Definition: rbdJITtests.h:27
Eigen::Matrix< double, nStates, nStates > state_matrix_t
void loadMatrixCF(const std::string &filename, const std::string &matrixName, Eigen::Matrix< SCALAR, ROW, COL > &matrix, const std::string &termName="")