GCC Code Coverage Report


Directory: ./
File: include/pinocchio/algorithm/delassus.hxx
Date: 2025-02-12 21:03:38
Exec Total Coverage
Lines: 0 308 0.0%
Branches: 0 974 0.0%

Line Branch Exec Source
1 //
2 // Copyright (c) 2020-2024 INRIA CNRS
3 // Copyright (c) 2023 KU Leuven
4 //
5
6 #ifndef __pinocchio_algorithm_contact_delassus_hxx__
7 #define __pinocchio_algorithm_contact_delassus_hxx__
8
9 #include "pinocchio/algorithm/check.hpp"
10 #include "pinocchio/algorithm/contact-info.hpp"
11 #include "pinocchio/algorithm/model.hpp"
12 #include "pinocchio/multibody/fwd.hpp"
13
14 namespace pinocchio
15 {
16
17 template<
18 typename Scalar,
19 int Options,
20 template<typename, int> class JointCollectionTpl,
21 typename ConfigVectorType>
22 struct ComputeOSIMForwardStep
23 : public fusion::JointUnaryVisitorBase<
24 ComputeOSIMForwardStep<Scalar, Options, JointCollectionTpl, ConfigVectorType>>
25 {
26 typedef ModelTpl<Scalar, Options, JointCollectionTpl> Model;
27 typedef DataTpl<Scalar, Options, JointCollectionTpl> Data;
28
29 typedef boost::fusion::vector<const Model &, Data &, const ConfigVectorType &> ArgsType;
30
31 template<typename JointModel>
32 ✗ static void algo(
33 const pinocchio::JointModelBase<JointModel> & jmodel,
34 pinocchio::JointDataBase<typename JointModel::JointDataDerived> & jdata,
35 const Model & model,
36 Data & data,
37 const Eigen::MatrixBase<ConfigVectorType> & q)
38 {
39 typedef typename Model::JointIndex JointIndex;
40
41 ✗ const JointIndex i = jmodel.id();
42 ✗ jmodel.calc(jdata.derived(), q.derived());
43
44 ✗ const JointIndex parent = model.parents[i];
45 ✗ data.liMi[i] = model.jointPlacements[i] * jdata.M();
46 ✗ if (parent > 0)
47 ✗ data.oMi[i] = data.oMi[parent] * data.liMi[i];
48 else
49 ✗ data.oMi[i] = data.liMi[i];
50
51 ✗ jmodel.jointCols(data.J) = data.oMi[i].act(jdata.S());
52 ✗ data.oYcrb[i] = data.oMi[i].act(model.inertias[i]);
53 ✗ data.oYaba[i] = data.oYcrb[i].matrix();
54 }
55 };
56
57 template<typename Scalar, int Options, template<typename, int> class JointCollectionTpl>
58 struct ComputeOSIMBackwardStep
59 : public fusion::JointUnaryVisitorBase<
60 ComputeOSIMBackwardStep<Scalar, Options, JointCollectionTpl>>
61 {
62 typedef ModelTpl<Scalar, Options, JointCollectionTpl> Model;
63 typedef DataTpl<Scalar, Options, JointCollectionTpl> Data;
64
65 typedef boost::fusion::vector<const Model &, Data &> ArgsType;
66
67 template<typename JointModel>
68 ✗ static void algo(
69 const JointModelBase<JointModel> & jmodel,
70 JointDataBase<typename JointModel::JointDataDerived> & jdata,
71 const Model & model,
72 Data & data)
73 {
74 typedef typename Model::JointIndex JointIndex;
75 typedef typename Data::Inertia Inertia;
76 typedef typename Data::Matrix6 Matrix6;
77 typedef typename Data::Matrix6x Matrix6x;
78
79 ✗ const JointIndex i = jmodel.id();
80 ✗ const JointIndex parent = model.parents[i];
81 ✗ typename Inertia::Matrix6 & Ia = data.oYaba[i];
82
83 typedef typename SizeDepType<JointModel::NV>::template ColsReturn<Matrix6x>::Type ColBlock;
84 ✗ ColBlock Jcols = jmodel.jointCols(data.J);
85
86 ✗ jdata.U().noalias() = Ia * Jcols;
87 ✗ jdata.StU().noalias() = Jcols.transpose() * jdata.U();
88
89 // Account for the rotor inertia contribution
90 ✗ jdata.StU().diagonal() += jmodel.jointVelocitySelector(model.armature);
91
92 ✗ internal::PerformStYSInversion<Scalar>::run(jdata.StU(), jdata.Dinv());
93
94 ✗ jdata.UDinv().noalias() =
95 Jcols
96 ✗ * jdata.Dinv().transpose(); //@justin can we remove the transpose since Dinv() is symmetric?
97 ✗ data.oK[i].noalias() = jdata.UDinv() * Jcols.transpose();
98 ✗ data.oL[i].noalias() = -jdata.UDinv() * jdata.U().transpose();
99 ✗ data.oL[i] += Matrix6::Identity();
100
101 ✗ if (parent > 0)
102 {
103 ✗ jdata.UDinv().noalias() = jdata.U() * jdata.Dinv();
104 ✗ data.oYaba[parent] += Ia;
105 ✗ data.oYaba[parent].noalias() -= jdata.UDinv() * jdata.U().transpose();
106 }
107 }
108 };
109
110 template<
111 typename Scalar,
112 int Options,
113 template<typename, int> class JointCollectionTpl,
114 typename ConfigVectorType,
115 class ModelAllocator,
116 class DataAllocator,
117 typename MatrixType>
118 ✗ void computeDelassusMatrix(
119 const ModelTpl<Scalar, Options, JointCollectionTpl> & model,
120 DataTpl<Scalar, Options, JointCollectionTpl> & data,
121 const Eigen::MatrixBase<ConfigVectorType> & q,
122 const std::vector<RigidConstraintModelTpl<Scalar, Options>, ModelAllocator> & contact_models,
123 std::vector<RigidConstraintDataTpl<Scalar, Options>, DataAllocator> & contact_data,
124 const Eigen::MatrixBase<MatrixType> & delassus_,
125 const Scalar mu)
126 {
127 ✗ assert(model.check(data) && "data is not consistent with model.");
128 ✗ PINOCCHIO_CHECK_ARGUMENT_SIZE(
129 q.size(), model.nq, "The joint configuration vector is not of right size");
130 ✗ PINOCCHIO_CHECK_INPUT_ARGUMENT(
131 check_expression_if_real<Scalar>(mu >= Scalar(0)), "mu has to be positive");
132 ✗ PINOCCHIO_CHECK_ARGUMENT_SIZE(
133 contact_models.size(), contact_data.size(), "contact models and data size are not the same");
134
135 ✗ MatrixType & delassus = delassus_.const_cast_derived();
136 ✗ const size_t constraint_total_size = getTotalConstraintSize(contact_models);
137 ✗ PINOCCHIO_CHECK_ARGUMENT_SIZE(delassus_.rows(), (Eigen::DenseIndex)constraint_total_size);
138 ✗ PINOCCHIO_CHECK_ARGUMENT_SIZE(delassus_.cols(), (Eigen::DenseIndex)constraint_total_size);
139
140 typedef ModelTpl<Scalar, Options, JointCollectionTpl> Model;
141 typedef DataTpl<Scalar, Options, JointCollectionTpl> Data;
142
143 typedef typename Model::JointIndex JointIndex;
144 typedef typename Model::SE3 SE3;
145 typedef typename Model::IndexVector IndexVector;
146 typedef RigidConstraintModelTpl<Scalar, Options> RigidConstraintModel;
147 typedef RigidConstraintDataTpl<Scalar, Options> RigidConstraintData;
148
149 typedef ComputeOSIMForwardStep<Scalar, Options, JointCollectionTpl, ConfigVectorType> Pass1;
150 ✗ for (JointIndex i = 1; i < (JointIndex)model.njoints; ++i)
151 {
152 ✗ Pass1::run(
153 ✗ model.joints[i], data.joints[i], typename Pass1::ArgsType(model, data, q.derived()));
154 }
155
156 ✗ for (size_t k = 0; k < contact_models.size(); ++k)
157 {
158 ✗ const RigidConstraintModel & cmodel = contact_models[k];
159 ✗ RigidConstraintData & cdata = contact_data[k];
160
161 ✗ const JointIndex joint1_id = cmodel.joint1_id;
162
163 // Compute relative placement between the joint and the contact frame
164 ✗ SE3 & oMc = cdata.oMc1;
165 ✗ oMc = data.oMi[joint1_id] * cmodel.joint1_placement; // contact placement
166
167 typedef typename Data::Inertia Inertia;
168 typedef typename Inertia::Symmetric3 Symmetric3;
169
170 // Add contact inertia to the joint articulated inertia
171 ✗ Symmetric3 S(Symmetric3::Zero());
172 ✗ if (cmodel.type == CONTACT_6D)
173 ✗ S.setDiagonal(Symmetric3::Vector3::Constant(mu));
174
175 ✗ const Inertia contact_inertia(mu, oMc.translation(), S);
176 ✗ data.oYaba[joint1_id] += contact_inertia.matrix();
177 }
178
179 typedef ComputeOSIMBackwardStep<Scalar, Options, JointCollectionTpl> Pass2;
180 ✗ for (JointIndex i = (JointIndex)model.njoints - 1; i > 0; --i)
181 {
182 ✗ Pass2::run(model.joints[i], data.joints[i], typename Pass2::ArgsType(model, data));
183 }
184
185 ✗ Eigen::DenseIndex current_row_id = 0;
186 ✗ for (size_t k = 0; k < contact_models.size(); ++k)
187 {
188 typedef typename RigidConstraintData::VectorOfMatrix6 VectorOfMatrix6;
189 ✗ const RigidConstraintModel & cmodel = contact_models[k];
190 ✗ RigidConstraintData & cdata = contact_data[k];
191
192 ✗ const JointIndex joint1_id = cmodel.joint1_id;
193 ✗ const SE3 & oMc1 = cdata.oMc1;
194 ✗ const IndexVector & support1 = model.supports[joint1_id];
195
196 {
197 ✗ VectorOfMatrix6 & propagators = cdata.extended_motion_propagators_joint1;
198 ✗ VectorOfMatrix6 & lambdas = cdata.lambdas_joint1;
199 ✗ switch (cmodel.type)
200 {
201 ✗ case CONTACT_3D: {
202 ✗ oMc1.toActionMatrixInverse(propagators.back());
203 ✗ propagators.back().template bottomRows<3>().setZero();
204 ✗ for (size_t j = support1.size() - 1; j > 1; --j)
205 {
206 ✗ lambdas[j].template leftCols<3>().noalias() =
207 ✗ data.oK[(size_t)support1[j]] * propagators[j].template topRows<3>().transpose();
208 ✗ propagators[j - 1].template topRows<3>().noalias() =
209 ✗ propagators[j].template topRows<3>() * data.oL[(size_t)support1[j]];
210 }
211 ✗ lambdas[1].template leftCols<3>().noalias() =
212 ✗ data.oK[(size_t)support1[1]] * propagators[1].template topRows<3>().transpose();
213
214 ✗ for (size_t j = 2; j < support1.size(); ++j)
215 {
216 ✗ lambdas[j].template leftCols<3>().noalias() +=
217 ✗ data.oL[(size_t)support1[j]] * lambdas[j - 1].template leftCols<3>();
218 }
219 ✗ break;
220 }
221 ✗ case CONTACT_6D: {
222 ✗ oMc1.toActionMatrixInverse(propagators.back());
223 ✗ for (size_t j = support1.size() - 1; j > 1; --j)
224 {
225 ✗ lambdas[j].noalias() = data.oK[(size_t)support1[j]] * propagators[j].transpose();
226 ✗ propagators[j - 1].noalias() = propagators[j] * data.oL[(size_t)support1[j]];
227 }
228 ✗ lambdas[1].noalias() = data.oK[(size_t)support1[1]] * propagators[1].transpose();
229
230 ✗ for (size_t j = 2; j < support1.size(); ++j)
231 {
232 ✗ lambdas[j].noalias() += data.oL[(size_t)support1[j]] * lambdas[j - 1];
233 }
234 ✗ break;
235 }
236 ✗ default: {
237 ✗ assert(false && "must never happened");
238 break;
239 }
240 }
241 }
242
243 // Fill the delassus matrix block-wise
244 {
245 ✗ const int size = cmodel.size();
246
247 ✗ const VectorOfMatrix6 & propagators = cdata.extended_motion_propagators_joint1;
248 ✗ const VectorOfMatrix6 & lambdas = cdata.lambdas_joint1;
249
250 ✗ Eigen::DenseIndex current_row_id_other = 0;
251 ✗ for (size_t i = 0; i < k; ++i)
252 {
253 ✗ const RigidConstraintModel & cmodel_other = contact_models[i];
254 ✗ const RigidConstraintData & cdata_other = contact_data[i];
255 ✗ const int size_other = cmodel_other.size();
256 ✗ const IndexVector & support1_other = model.supports[cmodel_other.joint1_id];
257
258 ✗ const VectorOfMatrix6 & propagators_other =
259 cdata_other.extended_motion_propagators_joint1;
260
261 size_t id_in_support1, id_in_support1_other;
262 ✗ findCommonAncestor(
263 ✗ model, joint1_id, cmodel_other.joint1_id, id_in_support1, id_in_support1_other);
264
265 ✗ delassus.block(current_row_id_other, current_row_id, size_other, size).noalias() =
266 ✗ propagators_other[id_in_support1_other].topRows(size_other)
267 ✗ * lambdas[id_in_support1].leftCols(size);
268
269 ✗ current_row_id_other += size_other;
270 }
271
272 ✗ assert(current_row_id_other == current_row_id && "current row indexes do not match.");
273 ✗ delassus.block(current_row_id, current_row_id, size, size).noalias() =
274 ✗ propagators.back().topRows(size) * lambdas.back().leftCols(size);
275 ✗ current_row_id += size;
276 }
277 }
278 ✗ assert(
279 current_row_id == delassus.rows()
280 && "current row indexes do not the number of rows in the Delassus matrix.");
281 }
282
283 template<
284 typename Scalar,
285 int Options,
286 template<typename, int> class JointCollectionTpl,
287 class Allocator>
288 inline void initPvDelassus(
289 const ModelTpl<Scalar, Options, JointCollectionTpl> & model,
290 DataTpl<Scalar, Options, JointCollectionTpl> & data,
291 const std::vector<RigidConstraintModelTpl<Scalar, Options>, Allocator> & contact_models)
292 {
293 std::fill(data.constraints_supported_dim.begin(), data.constraints_supported_dim.end(), 0);
294 for (std::size_t i = 0; i < contact_models.size(); ++i)
295 {
296 const RigidConstraintModelTpl<Scalar, Options> & contact_model = contact_models[i];
297 const JointIndex & joint_id = contact_model.joint1_id;
298 switch (contact_model.reference_frame)
299 {
300 case LOCAL:
301 if (contact_model.type == CONTACT_6D)
302 data.constraints_supported_dim[joint_id] += 6;
303 else if (contact_model.type == CONTACT_3D)
304 data.constraints_supported_dim[joint_id] += 3;
305 else
306 assert(false && "Must never happen");
307 break;
308 case WORLD:
309 assert(false && "WORLD not implemented");
310 break;
311 case LOCAL_WORLD_ALIGNED:
312 assert(false && "LOCAL_WORLD_ALIGNED not implemented");
313 break;
314 default:
315 assert(false && "Must never happen");
316 break;
317 }
318 data.accumulation_descendant[joint_id] = joint_id;
319
320 data.constraints_on_joint[joint_id].push_back(i);
321 }
322
323 // Running backprop to get the count of constraints
324 for (JointIndex i = (JointIndex)model.njoints - 1; i > 0; --i)
325 {
326 const JointIndex & parent = model.parents[i];
327 data.constraints_supported_dim[parent] += data.constraints_supported_dim[i];
328 for (std::size_t constraint : data.constraints_on_joint[i])
329 data.constraints_supported[i].insert(constraint);
330 for (std::size_t constraint : data.constraints_supported[i])
331 data.constraints_supported[parent].insert(
332 constraint); // For loops, will need to use a set data-structure
333 }
334 // Assign accumulation descendants for branching nodes
335 for (JointIndex i = (JointIndex)model.njoints - 1; i > 0; --i)
336 {
337 const JointIndex & parent = model.parents[i];
338 if (data.constraints_supported_dim[i] > 0)
339 {
340 data.joints_supporting_constraints.push_back(i);
341 data.accumulation_descendant[parent] = data.accumulation_descendant[i];
342 if (data.constraints_supported_dim[parent] > data.constraints_supported_dim[i])
343 {
344 data.accumulation_descendant[parent] = parent;
345 }
346 }
347 }
348
349 for (JointIndex i = 1; i < (JointIndex)model.njoints; i++)
350 {
351 if (data.accumulation_descendant[i] == i)
352 data.accumulation_joints.push_back(i);
353 }
354 // Assign accumulation ancestors
355 for (JointIndex i = (JointIndex)model.njoints - 1; i > 0; --i)
356 {
357 const JointIndex & parent = model.parents[i];
358 if (data.accumulation_descendant[parent] == parent)
359 {
360 if (data.accumulation_descendant[i] != 0)
361 data.accumulation_ancestor[data.accumulation_descendant[i]] = parent;
362 }
363 }
364 }
365
366 template<typename Scalar, int Options, template<typename, int> class JointCollectionTpl>
367 ✗ JointIndex findGreatestCommonAncestor(
368 const ModelTpl<Scalar, Options, JointCollectionTpl> & model,
369 const DataTpl<Scalar, Options, JointCollectionTpl> & data,
370 JointIndex joint1_id,
371 JointIndex joint2_id,
372 size_t & index_ancestor_in_support1,
373 size_t & index_ancestor_in_support2)
374 {
375 ✗ PINOCCHIO_CHECK_INPUT_ARGUMENT(
376 joint1_id < (JointIndex)model.njoints, "joint1_id is not valid.");
377 ✗ PINOCCHIO_CHECK_INPUT_ARGUMENT(
378 joint2_id < (JointIndex)model.njoints, "joint2_id is not valid.");
379
380 ✗ if (joint1_id == 0 || joint2_id == 0)
381 {
382 ✗ index_ancestor_in_support1 = index_ancestor_in_support2 = 0;
383 ✗ return 0;
384 }
385
386 ✗ index_ancestor_in_support1 = 0;
387 ✗ index_ancestor_in_support2 = 0;
388
389 ✗ if (data.constraints_supported[joint1_id].size() > 1)
390 ✗ index_ancestor_in_support1++;
391 ✗ if (data.constraints_supported[joint2_id].size() > 1)
392 ✗ index_ancestor_in_support2++;
393
394 ✗ while (joint1_id != joint2_id)
395 {
396 ✗ if (joint1_id > joint2_id)
397 {
398 ✗ joint1_id = data.accumulation_ancestor[joint1_id];
399 ✗ index_ancestor_in_support1++;
400 }
401 else
402 {
403 ✗ joint2_id = data.accumulation_ancestor[joint2_id];
404 ✗ index_ancestor_in_support2++;
405 }
406 }
407
408 ✗ index_ancestor_in_support1--;
409 ✗ index_ancestor_in_support2--;
410
411 ✗ return joint1_id;
412 }
413
414 template<typename Scalar, int Options, template<typename, int> class JointCollectionTpl>
415 struct ComputePvDelassusBackwardStep
416 : public fusion::JointUnaryVisitorBase<
417 ComputeOSIMBackwardStep<Scalar, Options, JointCollectionTpl>>
418 {
419 typedef ModelTpl<Scalar, Options, JointCollectionTpl> Model;
420 typedef DataTpl<Scalar, Options, JointCollectionTpl> Data;
421
422 typedef boost::fusion::vector<const Model &, Data &> ArgsType;
423
424 template<typename JointModel>
425 static void algo(
426 const JointModelBase<JointModel> & jmodel,
427 JointDataBase<typename JointModel::JointDataDerived> & jdata,
428 const Model & model,
429 Data & data)
430 {
431 typedef typename Model::JointIndex JointIndex;
432 typedef typename Data::Inertia Inertia;
433 typedef typename Data::Matrix6x Matrix6x;
434
435 const JointIndex i = jmodel.id();
436 const JointIndex parent = model.parents[i];
437 typename Inertia::Matrix6 & Ia = data.oYaba[i];
438
439 typedef typename SizeDepType<JointModel::NV>::template ColsReturn<Matrix6x>::Type ColBlock;
440 ColBlock Jcols = jmodel.jointCols(data.J);
441
442 jdata.U().noalias() = Ia * Jcols;
443 jdata.StU().noalias() = Jcols.transpose() * jdata.U();
444
445 // Account for the rotor inertia contribution
446 jdata.StU().diagonal() += jmodel.jointVelocitySelector(model.armature);
447
448 internal::PerformStYSInversion<Scalar>::run(jdata.StU(), jdata.Dinv());
449
450 jdata.UDinv().noalias() = Jcols * jdata.Dinv().transpose();
451 data.oL[i].setIdentity();
452 data.oL[i].noalias() -= jdata.UDinv() * jdata.U().transpose();
453
454 if (parent > 0)
455 {
456 data.oYaba[parent].noalias() = Ia - jdata.UDinv() * jdata.U().transpose();
457 }
458 }
459 };
460
461 template<
462 typename Scalar,
463 int Options,
464 template<typename, int> class JointCollectionTpl,
465 typename ConfigVectorType,
466 class ModelAllocator,
467 class DataAllocator,
468 typename MatrixType>
469 ✗ void computePvDelassusMatrix(
470 const ModelTpl<Scalar, Options, JointCollectionTpl> & model,
471 DataTpl<Scalar, Options, JointCollectionTpl> & data,
472 const Eigen::MatrixBase<ConfigVectorType> & q,
473 const std::vector<RigidConstraintModelTpl<Scalar, Options>, ModelAllocator> & contact_models,
474 std::vector<RigidConstraintDataTpl<Scalar, Options>, DataAllocator> & contact_data,
475 const Eigen::MatrixBase<MatrixType> & delassus_,
476 const Scalar mu)
477 {
478 ✗ assert(model.check(data) && "data is not consistent with model.");
479 ✗ PINOCCHIO_CHECK_ARGUMENT_SIZE(
480 q.size(), model.nq, "The joint configuration vector is not of right size");
481 ✗ PINOCCHIO_CHECK_INPUT_ARGUMENT(
482 check_expression_if_real<Scalar>(mu >= Scalar(0)), "mu has to be positive");
483 ✗ PINOCCHIO_CHECK_ARGUMENT_SIZE(
484 contact_models.size(), contact_data.size(), "contact models and data size are not the same");
485
486 ✗ MatrixType & delassus = delassus_.const_cast_derived();
487 ✗ const size_t constraint_total_size = getTotalConstraintSize(contact_models);
488 ✗ PINOCCHIO_CHECK_ARGUMENT_SIZE(delassus_.rows(), (Eigen::DenseIndex)constraint_total_size);
489 ✗ PINOCCHIO_CHECK_ARGUMENT_SIZE(delassus_.cols(), (Eigen::DenseIndex)constraint_total_size);
490
491 typedef DataTpl<Scalar, Options, JointCollectionTpl> Data;
492
493 ✗ typename Data::Vector6 scratch_pad_vector = Data::Vector6::Zero();
494 ✗ typename Data::Vector6 scratch_pad_vector2 = Data::Vector6::Zero();
495
496 ✗ typename Data::Matrix6 scratch_pad1;
497 ✗ typename Data::Matrix6 scratch_pad2;
498
499 typedef ModelTpl<Scalar, Options, JointCollectionTpl> Model;
500
501 typedef typename Model::JointIndex JointIndex;
502 typedef typename Model::SE3 SE3;
503 typedef RigidConstraintModelTpl<Scalar, Options> RigidConstraintModel;
504 typedef RigidConstraintDataTpl<Scalar, Options> RigidConstraintData;
505
506 typedef ComputeOSIMForwardStep<Scalar, Options, JointCollectionTpl, ConfigVectorType> Pass1;
507 ✗ for (JointIndex i = 1; i < (JointIndex)model.njoints; ++i)
508 {
509 ✗ Pass1::run(
510 ✗ model.joints[i], data.joints[i], typename Pass1::ArgsType(model, data, q.derived()));
511 }
512
513 ✗ for (size_t k = 0; k < contact_models.size(); ++k)
514 {
515 ✗ const RigidConstraintModel & cmodel = contact_models[k];
516 ✗ RigidConstraintData & cdata = contact_data[k];
517
518 ✗ const JointIndex joint1_id = cmodel.joint1_id;
519
520 // Compute relative placement between the joint and the contact frame
521 ✗ SE3 & oMc = cdata.oMc1;
522 ✗ oMc = data.oMi[joint1_id] * cmodel.joint1_placement; // contact placement
523
524 typedef typename Data::Inertia Inertia;
525 typedef typename Inertia::Symmetric3 Symmetric3;
526
527 // Add contact inertia to the joint articulated inertia
528 ✗ Symmetric3 S(Symmetric3::Zero());
529 ✗ if (cmodel.type == CONTACT_6D)
530 ✗ S.setDiagonal(Symmetric3::Vector3::Constant(mu));
531
532 ✗ const Inertia contact_inertia(mu, oMc.translation(), S);
533 ✗ data.oYaba[joint1_id] += contact_inertia.matrix();
534
535 typedef typename RigidConstraintData::VectorOfMatrix6 VectorOfMatrix6;
536
537 ✗ VectorOfMatrix6 & propagators = cdata.extended_motion_propagators_joint1;
538 ✗ switch (cmodel.type)
539 {
540 ✗ case CONTACT_3D: {
541 ✗ oMc.toActionMatrixInverse(propagators[0]);
542 ✗ propagators[0].template bottomRows<3>().setZero();
543 ✗ break;
544 }
545 ✗ case CONTACT_6D: {
546 ✗ oMc.toActionMatrixInverse(propagators[0]);
547 ✗ break;
548 }
549
550 ✗ default: {
551 ✗ assert(false && "must never happen");
552 break;
553 }
554 }
555 }
556
557 // Initialize motion propagator and spatial_inv_inertia at all the accumulation joints
558 ✗ for (JointIndex i : data.accumulation_joints)
559 {
560
561 ✗ if (data.constraints_supported[i].size() == 1)
562 {
563 ✗ size_t constraint = data.constraints_on_joint[i][0];
564 ✗ data.extended_motion_propagator[i] =
565 ✗ contact_data[constraint].extended_motion_propagators_joint1[0];
566 }
567 else
568 {
569 ✗ data.extended_motion_propagator[i].setIdentity();
570 }
571 ✗ data.spatial_inv_inertia[i].setZero();
572 }
573
574 typedef ComputePvDelassusBackwardStep<Scalar, Options, JointCollectionTpl> Pass2;
575 ✗ for (JointIndex i = (JointIndex)model.njoints - 1; i > 0; --i)
576 {
577 ✗ Pass2::run(model.joints[i], data.joints[i], typename Pass2::ArgsType(model, data));
578
579 ✗ if (data.constraints_supported_dim[i] > 0)
580 {
581 ✗ size_t ad_i = data.accumulation_descendant[i];
582 ✗ int nv = model.joints[i].nv();
583 // propagate the spatial inverse inertia
584 ✗ if (nv == 1)
585 {
586 // Optimization for single DoF joints
587 ✗ if (data.constraints_supported_dim[ad_i] != 3)
588 {
589 // When propagating 6D constraints
590 ✗ scratch_pad_vector.noalias() =
591 ✗ data.extended_motion_propagator[i] * model.joints[i].jointCols(data.J);
592 ✗ scratch_pad_vector2.noalias() = scratch_pad_vector * data.joints[i].Dinv().coeff(0, 0);
593 ✗ data.spatial_inv_inertia[ad_i].noalias() +=
594 ✗ scratch_pad_vector2 * scratch_pad_vector.transpose();
595 }
596 else
597 {
598 // Propagating 3D constraints
599 ✗ scratch_pad_vector.template topRows<3>().noalias() =
600 ✗ data.extended_motion_propagator[i].template topRows<3>()
601 ✗ * model.joints[i].jointCols(data.J);
602 ✗ scratch_pad_vector2.template topRows<3>().noalias() =
603 ✗ scratch_pad_vector.template topRows<3>() * data.joints[i].Dinv().coeff(0, 0);
604 ✗ data.spatial_inv_inertia[ad_i].template topLeftCorner<3, 3>().noalias() +=
605 ✗ scratch_pad_vector2.template topRows<3>()
606 ✗ * scratch_pad_vector.template topRows<3>().transpose();
607 }
608 }
609 ✗ else if (nv == 6)
610 {
611 ✗ scratch_pad1.noalias() =
612 ✗ data.extended_motion_propagator[i] * model.joints[i].jointCols(data.J);
613 ✗ scratch_pad2.noalias() = scratch_pad1 * data.joints[i].Dinv();
614 ✗ data.spatial_inv_inertia[ad_i].noalias() += scratch_pad2 * scratch_pad1.transpose();
615 }
616 ✗ else if (nv > 1)
617 {
618 // Joints with more than 1 DoF
619 ✗ scratch_pad1.leftCols(nv).noalias() =
620 ✗ data.extended_motion_propagator[i] * model.joints[i].jointCols(data.J);
621 ✗ scratch_pad2.leftCols(nv).noalias() = scratch_pad1.leftCols(nv) * data.joints[i].Dinv();
622 ✗ data.spatial_inv_inertia[ad_i].noalias() +=
623 ✗ scratch_pad2.leftCols(nv) * scratch_pad1.leftCols(nv).transpose();
624 }
625 else
626 {
627 ✗ assert(false && "must never happen");
628 }
629 // propagate the EMP
630 ✗ const JointIndex parent = model.parents[i];
631 ✗ size_t par_ad_i = data.accumulation_descendant[parent];
632 ✗ if (parent > 0 && par_ad_i == ad_i)
633 {
634
635 ✗ if (data.constraints_supported_dim[ad_i] != 3)
636 {
637 ✗ data.extended_motion_propagator[parent].noalias() =
638 ✗ data.extended_motion_propagator[i] * data.oL[i];
639 }
640 else
641 {
642 ✗ data.extended_motion_propagator[parent].template topRows<3>().noalias() =
643 ✗ data.extended_motion_propagator[i].template topRows<3>() * data.oL[i];
644 }
645 }
646 ✗ else if (par_ad_i != ad_i) // TODO: optimize for 3D constraints
647 {
648 ✗ data.extended_motion_propagator2[ad_i].noalias() =
649 ✗ data.extended_motion_propagator[i] * data.oL[i];
650 }
651 }
652 }
653
654 ✗ for (JointIndex i : data.accumulation_joints)
655 {
656
657 ✗ size_t an_i = data.accumulation_ancestor[i];
658 ✗ if (an_i != 0) // TODO: optimize for 3D constraints. Not very important here.
659 {
660 ✗ scratch_pad1.noalias() =
661 ✗ data.extended_motion_propagator2[i] * data.spatial_inv_inertia[an_i];
662 ✗ data.spatial_inv_inertia[i].noalias() +=
663 ✗ scratch_pad1 * data.extended_motion_propagator2[i].transpose();
664 }
665 }
666
667 typedef typename RigidConstraintData::VectorOfMatrix6 VectorOfMatrix6;
668 // compute EMP in the reverse direction
669 ✗ for (size_t k = 0; k < contact_models.size(); ++k)
670 {
671 ✗ VectorOfMatrix6 & cemp = contact_data[k].extended_motion_propagators_joint1;
672 ✗ JointIndex curr_joint = contact_models[k].joint1_id;
673
674 JointIndex an_i;
675
676 ✗ if (data.constraints_supported[curr_joint].size() == 1)
677 {
678 ✗ cemp[0] = data.extended_motion_propagator2[curr_joint];
679 ✗ an_i = data.accumulation_ancestor[curr_joint];
680 }
681 else
682 {
683 ✗ an_i = curr_joint;
684 }
685
686 ✗ size_t counter = 1;
687 ✗ while (an_i > 1)
688 {
689 ✗ if (contact_models[k].size() != 3)
690 ✗ cemp[counter].noalias() = cemp[counter - 1] * data.extended_motion_propagator2[an_i];
691 else
692 ✗ cemp[counter].template topRows<3>().noalias() =
693 ✗ cemp[counter - 1].template topRows<3>() * data.extended_motion_propagator2[an_i];
694 ✗ curr_joint = an_i;
695 ✗ an_i = data.accumulation_ancestor[curr_joint];
696 ✗ counter++;
697 }
698 }
699
700 ✗ Eigen::DenseIndex current_row_id = 0;
701 ✗ for (size_t k = 0; k < contact_models.size(); ++k)
702 {
703 ✗ const RigidConstraintModel & cmodel = contact_models[k];
704 ✗ RigidConstraintData & cdata = contact_data[k];
705 ✗ const VectorOfMatrix6 & cemp = cdata.extended_motion_propagators_joint1;
706
707 ✗ const JointIndex joint1_id = cmodel.joint1_id;
708
709 // Fill the delassus matrix block-wise
710 {
711 ✗ const int size = cmodel.size();
712
713 ✗ Eigen::DenseIndex current_row_id_other = 0;
714 ✗ for (size_t i = 0; i < k; ++i)
715 {
716 ✗ RigidConstraintData & cdata_other = contact_data[i];
717 ✗ const RigidConstraintModel & cmodel_other = contact_models[i];
718 ✗ const int size_other = cmodel_other.size();
719 ✗ const JointIndex joint1_id_other = cmodel_other.joint1_id;
720
721 ✗ const VectorOfMatrix6 & cemp_other = cdata_other.extended_motion_propagators_joint1;
722
723 size_t id_in_support1, id_in_support1_other, gca;
724 ✗ gca = findGreatestCommonAncestor(
725 model, data, joint1_id, joint1_id_other, id_in_support1, id_in_support1_other);
726
727 ✗ scratch_pad1.noalias() = cemp_other[id_in_support1_other] * data.spatial_inv_inertia[gca];
728 ✗ if (size == 6)
729 {
730 ✗ if (size_other == 6)
731 ✗ delassus.template block<6, 6>(current_row_id_other, current_row_id).noalias() =
732 ✗ scratch_pad1 * cemp[id_in_support1].transpose();
733 ✗ else if (size_other == 3)
734 ✗ delassus.template block<3, 6>(current_row_id_other, current_row_id).noalias() =
735 ✗ scratch_pad1.template topRows<3>()
736 ✗ * cemp[id_in_support1].template topRows<6>().transpose();
737 }
738 ✗ else if (size == 3)
739 {
740 ✗ if (size_other == 6)
741 ✗ delassus.template block<6, 3>(current_row_id_other, current_row_id).noalias() =
742 ✗ scratch_pad1.template topRows<6>()
743 ✗ * cemp[id_in_support1].template topRows<3>().transpose();
744 ✗ else if (size_other == 3)
745 ✗ delassus.template block<3, 3>(current_row_id_other, current_row_id).noalias() =
746 ✗ scratch_pad1.template topRows<3>()
747 ✗ * cemp[id_in_support1].template topRows<3>().transpose();
748 }
749 else
750 {
751 ✗ delassus.block(current_row_id_other, current_row_id, size_other, size).noalias() =
752 ✗ scratch_pad1.topRows(size_other) * cemp[id_in_support1].topRows(size).transpose();
753 }
754 ✗ current_row_id_other += size_other;
755 }
756
757 ✗ assert(current_row_id_other == current_row_id && "current row indexes do not match.");
758 ✗ if (
759 ✗ data.constraints_supported_dim[joint1_id] > 6
760 ✗ || data.constraints_supported[joint1_id].size() > 1)
761 {
762 ✗ scratch_pad1.noalias() = cemp[0] * data.spatial_inv_inertia[joint1_id];
763 ✗ delassus.block(current_row_id, current_row_id, size, size).noalias() =
764 ✗ scratch_pad1.topRows(size) * cemp[0].topRows(size).transpose();
765 }
766 else
767 {
768 ✗ if (size == 6)
769 ✗ delassus.template block<6, 6>(current_row_id, current_row_id) =
770 ✗ data.spatial_inv_inertia[joint1_id];
771 ✗ else if (size == 3)
772 ✗ delassus.template block<3, 3>(current_row_id, current_row_id) =
773 ✗ data.spatial_inv_inertia[joint1_id].template topLeftCorner<3, 3>();
774 else
775 ✗ delassus.block(current_row_id, current_row_id, size, size) =
776 ✗ data.spatial_inv_inertia[joint1_id].topLeftCorner(size, size);
777 }
778 ✗ current_row_id += size;
779 }
780 }
781 ✗ assert(
782 current_row_id == delassus.rows()
783 && "current row indexes do not the number of rows in the Delassus matrix.");
784 }
785
786 template<
787 typename Scalar,
788 int Options,
789 template<typename, int> class JointCollectionTpl,
790 typename ConfigVectorType,
791 class ModelAllocator,
792 class DataAllocator,
793 typename MatrixType>
794 ✗ void computeDampedDelassusMatrixInverse(
795 const ModelTpl<Scalar, Options, JointCollectionTpl> & model,
796 DataTpl<Scalar, Options, JointCollectionTpl> & data,
797 const Eigen::MatrixBase<ConfigVectorType> & q,
798 const std::vector<RigidConstraintModelTpl<Scalar, Options>, ModelAllocator> & contact_models,
799 std::vector<RigidConstraintDataTpl<Scalar, Options>, DataAllocator> & contact_data,
800 const Eigen::MatrixBase<MatrixType> & damped_delassus_inverse_,
801 const Scalar mu,
802 const bool scaled,
803 const bool Pv)
804 {
805 ✗ PINOCCHIO_CHECK_INPUT_ARGUMENT(
806 check_expression_if_real<Scalar>(mu >= Eigen::NumTraits<Scalar>::dummy_precision()),
807 "mu is too small.");
808
809 ✗ const Scalar mu_inv = Scalar(1) / mu;
810 ✗ MatrixType & damped_delassus_inverse = damped_delassus_inverse_.const_cast_derived();
811
812 ✗ const Scalar mu_inv_square = mu_inv * mu_inv;
813 ✗ assert(
814 check_expression_if_real<Scalar>(mu_inv_square != std::numeric_limits<Scalar>::infinity())
815 && "mu_inv**2 is equal to infinity.");
816
817 ✗ if (Pv)
818 ✗ computePvDelassusMatrix(
819 model, data, q, contact_models, contact_data, damped_delassus_inverse, mu_inv);
820 else
821 ✗ computeDelassusMatrix(
822 model, data, q, contact_models, contact_data, damped_delassus_inverse, mu_inv);
823
824 ✗ damped_delassus_inverse *= -mu_inv;
825 ✗ damped_delassus_inverse.diagonal().array() += Scalar(1);
826 ✗ if (!scaled)
827 ✗ damped_delassus_inverse *= mu_inv;
828 }
829
830 } // namespace pinocchio
831
832 #endif // ifndef __pinocchio_algorithm_contact_delassus_hxx__
833