impulse-dynamics-derivatives.cpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2020-2021 CNRS INRIA
3 //
4 
14 
15 #include <iostream>
16 
17 #include <boost/test/unit_test.hpp>
18 #include <boost/utility/binary.hpp>
19 
20 BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE)
21 
22 using namespace Eigen;
23 using namespace pinocchio;
24 
25 BOOST_AUTO_TEST_CASE(test_sparse_impulse_dynamics_derivatives_no_contact)
26 {
27  // result: (dMdq)(dqafter-v) = drnea(q,0,dqafter-v)
28  using namespace Eigen;
29  using namespace pinocchio;
30 
31  Model model;
33  Data data(model), data_ref(model);
34 
35  model.lowerPositionLimit.head<3>().fill(-1.);
36  model.upperPositionLimit.head<3>().fill(1.);
37  VectorXd q = randomConfiguration(model);
38 
39  VectorXd v = VectorXd::Random(model.nv);
40 
41  // Contact models and data
44 
45  const double mu0 = 0.;
46  ProximalSettings prox_settings(1e-12, mu0, 1);
47 
48  const double r_coeff = 0.5;
49 
50  initConstraintDynamics(model, data, empty_contact_models);
52  model, data, q, v, empty_contact_models, empty_contact_data, r_coeff, prox_settings);
53 
54  const Eigen::VectorXd dv = data.dq_after - v;
56  model, data, empty_contact_models, empty_contact_data, r_coeff, prox_settings);
57 
58  Motion gravity_bk = model.gravity;
59  model.gravity.setZero();
60  computeRNEADerivatives(model, data_ref, q, Eigen::VectorXd::Zero(model.nv), dv);
61  // Reference values
62  BOOST_CHECK(data_ref.dtau_dq.isApprox(data.dtau_dq));
63 }
64 
65 BOOST_AUTO_TEST_CASE(test_sparse_impulse_dynamics_derivatives)
66 {
67  using namespace Eigen;
68  using namespace pinocchio;
69  Model model;
71  Data data(model), data_ref(model);
72 
73  model.lowerPositionLimit.head<3>().fill(-1.);
74  model.upperPositionLimit.head<3>().fill(1.);
75  VectorXd q = randomConfiguration(model);
76  VectorXd v = VectorXd::Random(model.nv);
77 
78  const std::string RF = "rleg6_joint";
79  const Model::JointIndex RF_id = model.getJointId(RF);
80  const std::string LF = "lleg6_joint";
81  const Model::JointIndex LF_id = model.getJointId(LF);
82 
83  // Contact models and data
86 
89 
90  contact_models.push_back(ci_LF);
91  contact_data.push_back(RigidConstraintData(ci_LF));
92  contact_models.push_back(ci_RF);
93  contact_data.push_back(RigidConstraintData(ci_RF));
94 
95  Eigen::DenseIndex constraint_dim = 0;
96  for (size_t k = 0; k < contact_models.size(); ++k)
98 
99  const double mu0 = 0.;
100  ProximalSettings prox_settings(1e-12, mu0, 1);
101  const double r_coeff = 0.5;
102 
107 
108  typedef PINOCCHIO_ALIGNED_STD_VECTOR(Force) ForceVector;
109 
110  ForceVector iext((size_t)model.njoints);
111  for (ForceVector::iterator it = iext.begin(); it != iext.end(); ++it)
112  (*it).setZero();
113 
114  iext[model.getJointId(LF)] = contact_data[0].contact_force;
115  iext[model.getJointId(RF)] = contact_data[1].contact_force;
116 
117  Eigen::VectorXd effective_v = (1 + r_coeff) * v + data.ddq;
118 
120  model, data_ref, q, effective_v, Eigen::VectorXd::Zero(model.nv));
121 
122  for (size_t i = 0; i < data.ov.size(); i++)
123  {
124  BOOST_CHECK(((1 + r_coeff) * data.ov[i] + data.oa[i] - data_ref.ov[i]).isZero());
125  }
126 
127  Eigen::MatrixXd Jc(9, model.nv), dv_dq(9, model.nv), Jc_tmp(6, model.nv), dv_dq_tmp(6, model.nv);
128  Jc.setZero();
129  dv_dq.setZero();
130  dv_dq_tmp.setZero();
131  Jc_tmp.setZero();
132 
133  getJointVelocityDerivatives(model, data_ref, LF_id, LOCAL, dv_dq.topRows<6>(), Jc.topRows<6>());
134 
135  getJointVelocityDerivatives(model, data_ref, RF_id, LOCAL, dv_dq_tmp, Jc_tmp);
136 
137  Jc.bottomRows<3>() = Jc_tmp.topRows<3>();
138  dv_dq.bottomRows<3>() = dv_dq_tmp.topRows<3>();
139 
140  BOOST_CHECK(data_ref.J.isApprox(data.J));
141 
142  const Motion gravity_bk = model.gravity;
143  model.gravity.setZero();
144  computeRNEADerivatives(model, data_ref, q, Eigen::VectorXd::Zero(model.nv), data.ddq, iext);
145  model.gravity = gravity_bk;
146 
147  BOOST_CHECK(data.dac_da.isApprox(Jc));
148  // BOOST_CHECK((data.dvc_dq-(dv_dq-Jc*data.Minv*data_ref.dtau_dq)).norm()<=1e-12);
149 
150  BOOST_CHECK((data.dlambda_dv + (1 + r_coeff) * data.osim * Jc).isZero());
151 }
152 
153 BOOST_AUTO_TEST_CASE(test_impulse_dynamics_derivatives_LOCAL_fd)
154 {
155  using namespace Eigen;
156  using namespace pinocchio;
157 
158  Model model;
160  Data data(model), data_fd(model);
161 
162  model.lowerPositionLimit.head<3>().fill(-1.);
163  model.upperPositionLimit.head<3>().fill(1.);
164  VectorXd q = randomConfiguration(model);
165 
166  VectorXd v = VectorXd::Random(model.nv);
167 
168  const std::string RF = "rleg6_joint";
169  const Model::JointIndex RF_id = model.getJointId(RF);
170  const std::string LF = "lleg6_joint";
171  const Model::JointIndex LF_id = model.getJointId(LF);
172 
173  // Contact models and data
176 
177  RigidConstraintModel ci_LF(CONTACT_6D, model, LF_id, SE3::Random(), LOCAL);
178  RigidConstraintModel ci_RF(CONTACT_3D, model, RF_id, SE3::Random(), LOCAL);
179 
180  contact_models.push_back(ci_LF);
181  contact_data.push_back(RigidConstraintData(ci_LF));
182  contact_models.push_back(ci_RF);
183  contact_data.push_back(RigidConstraintData(ci_RF));
184 
185  Eigen::DenseIndex constraint_dim = 0;
186  for (size_t k = 0; k < contact_models.size(); ++k)
188 
189  const double mu0 = 0.;
190  ProximalSettings prox_settings(1e-12, mu0, 1);
191  const double r_coeff = 0.5;
192 
197 
198  // Data_fd
200 
201  MatrixXd dqafter_partial_dq_fd(model.nv, model.nv);
202  dqafter_partial_dq_fd.setZero();
203  MatrixXd dqafter_partial_dv_fd(model.nv, model.nv);
204  dqafter_partial_dv_fd.setZero();
205 
206  MatrixXd impulse_partial_dq_fd(constraint_dim, model.nv);
207  impulse_partial_dq_fd.setZero();
208  MatrixXd impulse_partial_dv_fd(constraint_dim, model.nv);
209  impulse_partial_dv_fd.setZero();
210 
211  const VectorXd dqafter0 =
213  const VectorXd impulse0 = data_fd.impulse_c;
214  VectorXd v_eps(VectorXd::Zero(model.nv));
215  VectorXd q_plus(model.nq);
216  VectorXd dqafter_plus(model.nv);
217 
218  const Eigen::MatrixXd Jc = data.contact_chol.matrix().topRightCorner(constraint_dim, model.nv);
219  const Eigen::VectorXd vel_jump = Jc * (dqafter0 + r_coeff * v);
220 
221  Data data_plus(model);
222  VectorXd impulse_plus(constraint_dim);
223 
224  Eigen::MatrixXd dvc_dq_fd(constraint_dim, model.nv);
225  const double alpha = 1e-8;
226  for (int k = 0; k < model.nv; ++k)
227  {
228  v_eps[k] += alpha;
229  q_plus = integrate(model, q, v_eps);
230  dqafter_plus = impulseDynamics(
231  model, data_fd, q_plus, v, contact_models, contact_data, r_coeff, prox_settings);
232 
233  const Eigen::MatrixXd Jc_plus =
234  data_fd.contact_chol.matrix().topRightCorner(constraint_dim, model.nv);
235  const Eigen::VectorXd vel_jump_plus = Jc_plus * (dqafter0 + r_coeff * v);
236 
237  dqafter_partial_dq_fd.col(k) = (dqafter_plus - dqafter0) / alpha;
238  impulse_partial_dq_fd.col(k) = (data_fd.impulse_c - impulse0) / alpha;
239  dvc_dq_fd.col(k) = (vel_jump_plus - vel_jump) / alpha;
240  v_eps[k] = 0.;
241  }
242 
243  BOOST_CHECK(Jc.isApprox(data.dac_da, sqrt(alpha)));
244  BOOST_CHECK(dqafter_partial_dq_fd.isApprox(data.ddq_dq, sqrt(alpha)));
245  BOOST_CHECK(impulse_partial_dq_fd.isApprox(data.dlambda_dq, sqrt(alpha)));
246 
247  VectorXd v_plus(v);
248  for (int k = 0; k < model.nv; ++k)
249  {
250  v_plus[k] += alpha;
251  dqafter_plus = impulseDynamics(
252  model, data_fd, q, v_plus, contact_models, contact_data, r_coeff, prox_settings);
253 
254  dqafter_partial_dv_fd.col(k) = (dqafter_plus - dqafter0) / alpha;
255  impulse_partial_dv_fd.col(k) = (data_fd.impulse_c - impulse0) / alpha;
256  v_plus[k] -= alpha;
257  }
258 
259  BOOST_CHECK(dqafter_partial_dv_fd.isApprox(
260  Eigen::MatrixXd::Identity(model.nv, model.nv) + data.ddq_dv, sqrt(alpha)));
261  BOOST_CHECK(impulse_partial_dv_fd.isApprox(data.dlambda_dv, sqrt(alpha)));
262 }
263 
264 BOOST_AUTO_TEST_CASE(test_impulse_dynamics_derivatives_LOCAL_WORLD_ALIGNED_fd)
265 {
266  using namespace Eigen;
267  using namespace pinocchio;
268 
269  Model model;
271  Data data(model), data_fd(model);
272 
273  model.lowerPositionLimit.head<3>().fill(-1.);
274  model.upperPositionLimit.head<3>().fill(1.);
275  VectorXd q = randomConfiguration(model);
276 
277  VectorXd v = VectorXd::Random(model.nv);
278 
279  const std::string RF = "rleg6_joint";
280  const Model::JointIndex RF_id = model.getJointId(RF);
281  const std::string LF = "lleg6_joint";
282  const Model::JointIndex LF_id = model.getJointId(LF);
283 
284  // Contact models and data
287 
288  RigidConstraintModel ci_LF(CONTACT_6D, model, LF_id, SE3::Random(), LOCAL_WORLD_ALIGNED);
289  RigidConstraintModel ci_RF(CONTACT_3D, model, RF_id, SE3::Random(), LOCAL_WORLD_ALIGNED);
290 
291  contact_models.push_back(ci_LF);
292  contact_data.push_back(RigidConstraintData(ci_LF));
293  contact_models.push_back(ci_RF);
294  contact_data.push_back(RigidConstraintData(ci_RF));
295 
296  Eigen::DenseIndex constraint_dim = 0;
297  for (size_t k = 0; k < contact_models.size(); ++k)
299 
300  const double mu0 = 0.;
301  ProximalSettings prox_settings(1e-12, mu0, 1);
302  const double r_coeff = 0.5;
303 
308 
309  // Data_fd
311 
312  MatrixXd dqafter_partial_dq_fd(model.nv, model.nv);
313  dqafter_partial_dq_fd.setZero();
314  MatrixXd dqafter_partial_dv_fd(model.nv, model.nv);
315  dqafter_partial_dv_fd.setZero();
316 
317  MatrixXd impulse_partial_dq_fd(constraint_dim, model.nv);
318  impulse_partial_dq_fd.setZero();
319  MatrixXd impulse_partial_dv_fd(constraint_dim, model.nv);
320  impulse_partial_dv_fd.setZero();
321 
322  const VectorXd dqafter0 =
324  const VectorXd impulse0 = data_fd.impulse_c;
325  VectorXd v_eps(VectorXd::Zero(model.nv));
326  VectorXd q_plus(model.nq);
327  VectorXd dqafter_plus(model.nv);
328 
329  VectorXd impulse_plus(constraint_dim);
330  const double alpha = 1e-8;
331  for (int k = 0; k < model.nv; ++k)
332  {
333  v_eps[k] += alpha;
334  q_plus = integrate(model, q, v_eps);
335  dqafter_plus = impulseDynamics(
336  model, data_fd, q_plus, v, contact_models, contact_data, r_coeff, prox_settings);
337  dqafter_partial_dq_fd.col(k) = (dqafter_plus - dqafter0) / alpha;
338  impulse_partial_dq_fd.col(k) = (data_fd.impulse_c - impulse0) / alpha;
339  v_eps[k] = 0.;
340  }
341 
342  BOOST_CHECK(dqafter_partial_dq_fd.isApprox(data.ddq_dq, sqrt(alpha)));
343  BOOST_CHECK(impulse_partial_dq_fd.isApprox(data.dlambda_dq, sqrt(alpha)));
344 
345  VectorXd v_plus(v);
346  for (int k = 0; k < model.nv; ++k)
347  {
348  v_plus[k] += alpha;
349  dqafter_plus = impulseDynamics(
350  model, data_fd, q, v_plus, contact_models, contact_data, r_coeff, prox_settings);
351  dqafter_partial_dv_fd.col(k) = (dqafter_plus - dqafter0) / alpha;
352  impulse_partial_dv_fd.col(k) = (data_fd.impulse_c - impulse0) / alpha;
353  v_plus[k] -= alpha;
354  }
355 
356  BOOST_CHECK(dqafter_partial_dv_fd.isApprox(
357  Eigen::MatrixXd::Identity(model.nv, model.nv) + data.ddq_dv, sqrt(alpha)));
358  BOOST_CHECK(impulse_partial_dv_fd.isApprox(data.dlambda_dv, sqrt(alpha)));
359 }
360 
361 BOOST_AUTO_TEST_SUITE_END()
pinocchio::RigidConstraintData
RigidConstraintDataTpl< context::Scalar, context::Options > RigidConstraintData
Definition: algorithm/fwd.hpp:27
frames.hpp
Eigen
pinocchio::DataTpl
Definition: context/generic.hpp:25
kinematics-derivatives.dv_dq
dv_dq
Definition: kinematics-derivatives.py:29
autodiff-rnea.dv
dv
Definition: autodiff-rnea.py:27
contact-cholesky.contact_data
list contact_data
Definition: contact-cholesky.py:36
inverse-kinematics.i
int i
Definition: inverse-kinematics.py:20
kinematics.hpp
rnea-derivatives.hpp
setup.data
data
Definition: cmake/cython/setup.in.py:48
pinocchio::buildModels::humanoidRandom
void humanoidRandom(ModelTpl< Scalar, Options, JointCollectionTpl > &model, bool usingFF=true)
Create a humanoid kinematic tree with 6-DOF limbs and random joint placements.
pinocchio::python::computeRNEADerivatives
bp::tuple computeRNEADerivatives(const context::Model &model, context::Data &data, const context::VectorXs &q, const context::VectorXs &v, const context::VectorXs &a)
Definition: expose-rnea-derivatives.cpp:38
pinocchio::randomConfiguration
void randomConfiguration(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const Eigen::MatrixBase< ConfigVectorIn1 > &lowerLimits, const Eigen::MatrixBase< ConfigVectorIn2 > &upperLimits, const Eigen::MatrixBase< ReturnType > &qout)
Generate a configuration vector uniformly sampled among provided limits.
Definition: joint-configuration.hpp:325
impulse-dynamics-derivatives.hpp
pinocchio::CONTACT_6D
@ CONTACT_6D
Point contact model.
Definition: algorithm/contact-info.hpp:22
rnea.hpp
bindings_dynamics.r_coeff
float r_coeff
Definition: bindings_dynamics.py:11
anymal-simulation.model
model
Definition: anymal-simulation.py:12
pinocchio::ModelTpl::JointIndex
pinocchio::JointIndex JointIndex
Definition: multibody/model.hpp:68
pinocchio::LOCAL_WORLD_ALIGNED
@ LOCAL_WORLD_ALIGNED
Definition: multibody/fwd.hpp:52
pinocchio::computeForwardKinematicsDerivatives
void computeForwardKinematicsDerivatives(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< ConfigVectorType > &q, const Eigen::MatrixBase< TangentVectorType1 > &v, const Eigen::MatrixBase< TangentVectorType2 > &a)
Computes all the terms required to compute the derivatives of the placement, spatial velocity and acc...
joint-configuration.hpp
reachable-workspace-with-collisions.alpha
float alpha
Definition: reachable-workspace-with-collisions.py:159
pinocchio::ProximalSettingsTpl
Structure containing all the settings paramters for the proximal algorithms.
Definition: algorithm/fwd.hpp:13
pinocchio::DataTpl::dtau_dq
RowMatrixXs dtau_dq
Partial derivative of the joint torque vector with respect to the joint configuration.
Definition: multibody/data.hpp:387
pinocchio::integrate
void integrate(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const Eigen::MatrixBase< ConfigVectorType > &q, const Eigen::MatrixBase< TangentVectorType > &v, const Eigen::MatrixBase< ReturnType > &qout)
Integrate a configuration vector for the specified model for a tangent vector during one unit time.
Definition: joint-configuration.hpp:72
pinocchio::RigidConstraintModelTpl
Definition: algorithm/constraints/fwd.hpp:14
autodiff-rnea.v
v
Definition: autodiff-rnea.py:15
pinocchio::getJointVelocityDerivatives
void getJointVelocityDerivatives(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, const DataTpl< Scalar, Options, JointCollectionTpl > &data, const Model::JointIndex jointId, const ReferenceFrame rf, const Eigen::MatrixBase< Matrix6xOut1 > &v_partial_dq, const Eigen::MatrixBase< Matrix6xOut2 > &v_partial_dv)
Computes the partial derivaties of the spatial velocity of a given with respect to the joint configur...
pinocchio::RigidConstraintDataTpl
Definition: algorithm/constraints/fwd.hpp:16
pinocchio::initConstraintDynamics
void initConstraintDynamics(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, DataTpl< Scalar, Options, JointCollectionTpl > &data, const std::vector< RigidConstraintModelTpl< Scalar, Options >, Allocator > &contact_models)
Init the forward dynamics data according to the contact information contained in contact_models.
pinocchio::computeImpulseDynamicsDerivatives
void computeImpulseDynamicsDerivatives(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, DataTpl< Scalar, Options, JointCollectionTpl > &data, const std::vector< RigidConstraintModelTpl< Scalar, Options >, ConstraintModelAllocator > &contact_models, std::vector< RigidConstraintDataTpl< Scalar, Options >, ConstraintDataAllocator > &contact_data, const Scalar r_coeff, const ProximalSettingsTpl< Scalar > &settings, const Eigen::MatrixBase< MatrixType1 > &dvimpulse_partial_dq, const Eigen::MatrixBase< MatrixType2 > &dvimpulse_partial_dv, const Eigen::MatrixBase< MatrixType3 > &impulse_partial_dq, const Eigen::MatrixBase< MatrixType4 > &impulse_partial_dv)
pinocchio::ForceTpl
Definition: context/casadi.hpp:25
size
FCL_REAL size() const
q
q
PINOCCHIO_STD_VECTOR_WITH_EIGEN_ALLOCATOR
#define PINOCCHIO_STD_VECTOR_WITH_EIGEN_ALLOCATOR(T)
Definition: container/aligned-vector.hpp:13
pinocchio::DataTpl::J
Matrix6x J
Jacobian of joint placements.
Definition: multibody/data.hpp:360
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(test_sparse_impulse_dynamics_derivatives_no_contact)
Definition: impulse-dynamics-derivatives.cpp:25
fill
fill
impulse-dynamics.hpp
pinocchio::impulseDynamics
const PINOCCHIO_DEPRECATED DataTpl< Scalar, Options, JointCollectionTpl >::TangentVectorType & impulseDynamics(const ModelTpl< Scalar, Options, JointCollectionTpl > &model, DataTpl< Scalar, Options, JointCollectionTpl > &data, const Eigen::MatrixBase< ConfigVectorType > &q, const Eigen::MatrixBase< TangentVectorType > &v_before, const Eigen::MatrixBase< ConstraintMatrixType > &J, const Scalar r_coeff=0., const Scalar inv_damping=0.)
Compute the impulse dynamics with contact constraints. Internally, pinocchio::crba is called.
contact-cholesky.contact_models
list contact_models
Definition: contact-cholesky.py:25
PINOCCHIO_ALIGNED_STD_VECTOR
#define PINOCCHIO_ALIGNED_STD_VECTOR(Type)
Definition: container/aligned-vector.hpp:11
anymal-simulation.constraint_dim
constraint_dim
Definition: anymal-simulation.py:67
sample-models.hpp
pinocchio::MotionTpl
Definition: context/casadi.hpp:27
jacobian.hpp
pinocchio::ModelTpl
Definition: context/generic.hpp:20
simulation-closed-kinematic-chains.prox_settings
prox_settings
Definition: simulation-closed-kinematic-chains.py:163
pinocchio::CONTACT_3D
@ CONTACT_3D
Definition: algorithm/contact-info.hpp:21
pinocchio::DataTpl::impulse_c
VectorXs impulse_c
Lagrange Multipliers corresponding to the contact impulses in pinocchio::impulseDynamics.
Definition: multibody/data.hpp:491
pinocchio::DataTpl::contact_chol
ContactCholeskyDecomposition contact_chol
Cholesky decomposition of the KKT contact matrix.
Definition: multibody/data.hpp:532
pinocchio
Main pinocchio namespace.
Definition: timings.cpp:27
BOOST_CHECK
#define BOOST_CHECK(check)
Definition: overview-urdf.cpp:34
pinocchio::LOCAL
@ LOCAL
Definition: multibody/fwd.hpp:50


pinocchio
Author(s):
autogenerated on Sat Jun 22 2024 02:41:47