GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: unittest/frames.cpp Lines: 416 416 100.0 %
Date: 2024-01-23 21:41:47 Branches: 1539 3116 49.4 %

Line Branch Exec Source
1
//
2
// Copyright (c) 2016-2020 CNRS INRIA
3
//
4
5
#include "pinocchio/multibody/model.hpp"
6
#include "pinocchio/multibody/data.hpp"
7
#include "pinocchio/algorithm/model.hpp"
8
#include "pinocchio/algorithm/jacobian.hpp"
9
#include "pinocchio/algorithm/frames.hpp"
10
#include "pinocchio/algorithm/rnea.hpp"
11
#include "pinocchio/algorithm/crba.hpp"
12
#include "pinocchio/spatial/act-on-set.hpp"
13
#include "pinocchio/parsers/sample-models.hpp"
14
#include "pinocchio/utils/timer.hpp"
15
#include "pinocchio/algorithm/joint-configuration.hpp"
16
17
#include <iostream>
18
19
#include <boost/test/unit_test.hpp>
20
#include <boost/utility/binary.hpp>
21
22
template<typename Derived>
23
1
inline bool isFinite(const Eigen::MatrixBase<Derived> & x)
24
{
25


1
  return ((x - x).array() == (x - x).array()).all();
26
}
27
28
29
BOOST_AUTO_TEST_SUITE ( BOOST_TEST_MODULE )
30
31
















4
BOOST_AUTO_TEST_CASE(frame_basic)
32
{
33
  using namespace pinocchio;
34
4
  Model model;
35
2
  buildModels::humanoidRandom(model);
36
37



2
  BOOST_CHECK(model.frames.size() >= size_t(model.njoints));
38
112
  for(Model::FrameVector::const_iterator it = model.frames.begin();
39
222
      it != model.frames.end(); ++it)
40
  {
41
110
    const Frame & frame = *it;
42



110
    BOOST_CHECK(frame == frame);
43
220
    Frame frame_copy(frame);
44



110
    BOOST_CHECK(frame_copy == frame);
45
  }
46
47
4
  std::ostringstream os;
48



2
  os << Frame("toto",0,0,SE3::Random(),OP_FRAME) << std::endl;
49



2
  BOOST_CHECK(!os.str().empty());
50
2
}
51
52
















4
BOOST_AUTO_TEST_CASE(cast)
53
{
54
  using namespace pinocchio;
55


6
  Frame frame("toto",0,0,SE3::Random(),OP_FRAME);
56
57




2
  BOOST_CHECK(frame.cast<double>() == frame);
58





2
  BOOST_CHECK(frame.cast<double>().cast<long double>() == frame.cast<long double>());
59
2
}
60
61
















4
BOOST_AUTO_TEST_CASE ( test_kinematics )
62
{
63
  using namespace Eigen;
64
  using namespace pinocchio;
65
66
4
  pinocchio::Model model;
67
2
  pinocchio::buildModels::humanoidRandom(model);
68




2
  Model::Index parent_idx = model.existJointName("rarm2_joint")?model.getJointId("rarm2_joint"):(Model::Index)(model.njoints-1);
69
4
  const std::string & frame_name = std::string( model.names[parent_idx]+ "_frame");
70
2
  const SE3 & framePlacement = SE3::Random();
71

2
  model.addFrame(Frame (frame_name, parent_idx, 0, framePlacement, OP_FRAME));
72
4
  pinocchio::Data data(model);
73
74

4
  VectorXd q = VectorXd::Ones(model.nq);
75

2
  q.middleRows<4> (3).normalize();
76
2
  framesForwardKinematics(model, data, q);
77
78




2
  BOOST_CHECK(data.oMf[model.getFrameId(frame_name)].isApprox(data.oMi[parent_idx]*framePlacement));
79
80
2
}
81
82
















4
BOOST_AUTO_TEST_CASE ( test_update_placements )
83
{
84
  using namespace Eigen;
85
  using namespace pinocchio;
86
87
4
  pinocchio::Model model;
88
2
  pinocchio::buildModels::humanoidRandom(model);
89




2
  Model::Index parent_idx = model.existJointName("rarm2_joint")?model.getJointId("rarm2_joint"):(Model::Index)(model.njoints-1);
90
4
  const std::string & frame_name = std::string( model.names[parent_idx]+ "_frame");
91
2
  const SE3 & framePlacement = SE3::Random();
92

2
  Model::FrameIndex frame_idx = model.addFrame(Frame (frame_name, parent_idx, 0, framePlacement, OP_FRAME));
93
4
  pinocchio::Data data(model);
94
4
  pinocchio::Data data_ref(model);
95
96

4
  VectorXd q = VectorXd::Ones(model.nq);
97

2
  q.middleRows<4> (3).normalize();
98
99
2
  forwardKinematics(model, data, q);
100
2
  updateFramePlacements(model, data);
101
102
2
  framesForwardKinematics(model, data_ref, q);
103
104



2
  BOOST_CHECK(data.oMf[frame_idx].isApprox(data_ref.oMf[frame_idx]));
105
2
}
106
107
















4
BOOST_AUTO_TEST_CASE ( test_update_single_placement )
108
{
109
  using namespace Eigen;
110
  using namespace pinocchio;
111
112
4
  pinocchio::Model model;
113
2
  pinocchio::buildModels::humanoidRandom(model);
114




2
  Model::Index parent_idx = model.existJointName("rarm2_joint")?model.getJointId("rarm2_joint"):(Model::Index)(model.njoints-1);
115
4
  const std::string & frame_name = std::string( model.names[parent_idx]+ "_frame");
116
2
  const SE3 & framePlacement = SE3::Random();
117

2
  Model::FrameIndex frame_idx = model.addFrame(Frame (frame_name, parent_idx, 0, framePlacement, OP_FRAME));
118
4
  pinocchio::Data data(model);
119
4
  pinocchio::Data data_ref(model);
120
121

4
  VectorXd q = VectorXd::Ones(model.nq);
122

2
  q.middleRows<4> (3).normalize();
123
124
2
  forwardKinematics(model, data, q);
125
2
  updateFramePlacement(model, data, frame_idx);
126
127
2
  framesForwardKinematics(model, data_ref, q);
128
129



2
  BOOST_CHECK(data.oMf[frame_idx].isApprox(data_ref.oMf[frame_idx]));
130
2
}
131
132
















4
BOOST_AUTO_TEST_CASE ( test_velocity )
133
{
134
  using namespace Eigen;
135
  using namespace pinocchio;
136
137
4
  pinocchio::Model model;
138
2
  pinocchio::buildModels::humanoidRandom(model);
139




2
  Model::Index parent_idx = model.existJointName("rarm2_joint")?model.getJointId("rarm2_joint"):(Model::Index)(model.njoints-1);
140
4
  const std::string & frame_name = std::string( model.names[parent_idx]+ "_frame");
141
2
  const SE3 & framePlacement = SE3::Random();
142

2
  Model::FrameIndex frame_idx = model.addFrame(Frame (frame_name, parent_idx, 0, framePlacement, OP_FRAME));
143
4
  pinocchio::Data data(model);
144
145

4
  VectorXd q = VectorXd::Ones(model.nq);
146

2
  q.middleRows<4> (3).normalize();
147

4
  VectorXd v = VectorXd::Ones(model.nv);
148
2
  forwardKinematics(model, data, q, v);
149
150
2
  Motion vf = getFrameVelocity(model, data, frame_idx);
151
152




2
  BOOST_CHECK(vf.isApprox(framePlacement.actInv(data.v[parent_idx])));
153
154
4
  pinocchio::Data data_ref(model);
155
2
  forwardKinematics(model, data_ref, q, v);
156
2
  updateFramePlacements(model, data_ref);
157
2
  Motion v_ref = getFrameVelocity(model, data_ref, frame_idx);
158
159




2
  BOOST_CHECK(v_ref.isApprox(getFrameVelocity(model,data,frame_idx)));
160




2
  BOOST_CHECK(v_ref.isApprox(getFrameVelocity(model,data,frame_idx,LOCAL)));
161




2
  BOOST_CHECK(data_ref.oMf[frame_idx].act(v_ref).isApprox(getFrameVelocity(model,data,frame_idx,WORLD)));
162






2
  BOOST_CHECK(SE3(data_ref.oMf[frame_idx].rotation(), Eigen::Vector3d::Zero()).act(v_ref).isApprox(getFrameVelocity(model,data,frame_idx,LOCAL_WORLD_ALIGNED)));
163
2
}
164
165
















4
BOOST_AUTO_TEST_CASE ( test_acceleration )
166
{
167
  using namespace Eigen;
168
  using namespace pinocchio;
169
170
4
  pinocchio::Model model;
171
2
  pinocchio::buildModels::humanoidRandom(model);
172




2
  Model::Index parent_idx = model.existJointName("rarm2_joint")?model.getJointId("rarm2_joint"):(Model::Index)(model.njoints-1);
173
4
  const std::string & frame_name = std::string( model.names[parent_idx]+ "_frame");
174
2
  const SE3 & framePlacement = SE3::Random();
175

2
  Model::FrameIndex frame_idx = model.addFrame(Frame (frame_name, parent_idx, 0, framePlacement, OP_FRAME));
176
4
  pinocchio::Data data(model);
177
178

4
  VectorXd q = VectorXd::Ones(model.nq);
179

2
  q.middleRows<4> (3).normalize();
180

4
  VectorXd v = VectorXd::Ones(model.nv);
181

4
  VectorXd a = VectorXd::Ones(model.nv);
182
2
  forwardKinematics(model, data, q, v, a);
183
184
2
  Motion af = getFrameAcceleration(model, data, frame_idx);
185
186




2
  BOOST_CHECK(af.isApprox(framePlacement.actInv(data.a[parent_idx])));
187
188
4
  pinocchio::Data data_ref(model);
189
2
  forwardKinematics(model, data_ref, q, v, a);
190
2
  updateFramePlacements(model, data_ref);
191
2
  Motion a_ref = getFrameAcceleration(model, data_ref, frame_idx);
192
193




2
  BOOST_CHECK(a_ref.isApprox(getFrameAcceleration(model,data,frame_idx)));
194




2
  BOOST_CHECK(a_ref.isApprox(getFrameAcceleration(model,data,frame_idx,LOCAL)));
195




2
  BOOST_CHECK(data_ref.oMf[frame_idx].act(a_ref).isApprox(getFrameAcceleration(model,data,frame_idx,WORLD)));
196






2
  BOOST_CHECK(SE3(data_ref.oMf[frame_idx].rotation(), Eigen::Vector3d::Zero()).act(a_ref).isApprox(getFrameAcceleration(model,data,frame_idx,LOCAL_WORLD_ALIGNED)));
197
2
}
198
199
















4
BOOST_AUTO_TEST_CASE ( test_classic_acceleration )
200
{
201
  using namespace Eigen;
202
  using namespace pinocchio;
203
204
4
  pinocchio::Model model;
205
2
  pinocchio::buildModels::humanoidRandom(model);
206




2
  Model::Index parent_idx = model.existJointName("rarm2_joint")?model.getJointId("rarm2_joint"):(Model::Index)(model.njoints-1);
207
4
  const std::string & frame_name = std::string( model.names[parent_idx]+ "_frame");
208
2
  const SE3 & framePlacement = SE3::Random();
209

2
  Model::FrameIndex frame_idx = model.addFrame(Frame (frame_name, parent_idx, 0, framePlacement, OP_FRAME));
210
4
  pinocchio::Data data(model);
211
212

4
  VectorXd q = VectorXd::Ones(model.nq);
213

2
  q.middleRows<4> (3).normalize();
214

4
  VectorXd v = VectorXd::Ones(model.nv);
215

4
  VectorXd a = VectorXd::Ones(model.nv);
216
2
  forwardKinematics(model, data, q, v, a);
217
218
2
  Motion vel = framePlacement.actInv(data.v[parent_idx]);
219
2
  Motion acc = framePlacement.actInv(data.a[parent_idx]);
220
2
  Vector3d linear;
221
222
2
  Motion acc_classical_local = acc;
223



2
  linear = acc.linear() + vel.angular().cross(vel.linear());
224

2
  acc_classical_local.linear() = linear;
225
226
2
  Motion af = getFrameClassicalAcceleration(model, data, frame_idx);
227
228



2
  BOOST_CHECK(af.isApprox(acc_classical_local));
229
230
4
  pinocchio::Data data_ref(model);
231
2
  forwardKinematics(model, data_ref, q, v, a);
232
2
  updateFramePlacements(model, data_ref);
233
234
2
  SE3 T_ref = data_ref.oMf[frame_idx];
235
2
  Motion v_ref = getFrameVelocity(model, data_ref, frame_idx);
236
2
  Motion a_ref = getFrameAcceleration(model, data_ref, frame_idx);
237
238
2
  Motion acc_classical_local_ref = a_ref;
239



2
  linear = a_ref.linear() + v_ref.angular().cross(v_ref.linear());
240

2
  acc_classical_local_ref.linear() = linear;
241
242




2
  BOOST_CHECK(acc_classical_local_ref.isApprox(getFrameClassicalAcceleration(model,data,frame_idx)));
243




2
  BOOST_CHECK(acc_classical_local_ref.isApprox(getFrameClassicalAcceleration(model,data,frame_idx,LOCAL)));
244
245
2
  Motion vel_world_ref = T_ref.act(v_ref);
246
2
  Motion acc_classical_world_ref = T_ref.act(a_ref);
247



2
  linear = acc_classical_world_ref.linear() + vel_world_ref.angular().cross(vel_world_ref.linear());
248

2
  acc_classical_world_ref.linear() = linear;
249
250




2
  BOOST_CHECK(acc_classical_world_ref.isApprox(getFrameClassicalAcceleration(model,data,frame_idx,WORLD)));
251
252


2
  Motion vel_aligned_ref = SE3(T_ref.rotation(), Eigen::Vector3d::Zero()).act(v_ref);
253


2
  Motion acc_classical_aligned_ref = SE3(T_ref.rotation(), Eigen::Vector3d::Zero()).act(a_ref);
254



2
  linear = acc_classical_aligned_ref.linear() + vel_aligned_ref.angular().cross(vel_aligned_ref.linear());
255

2
  acc_classical_aligned_ref.linear() = linear;
256
257




2
  BOOST_CHECK(acc_classical_aligned_ref.isApprox(getFrameClassicalAcceleration(model,data,frame_idx,LOCAL_WORLD_ALIGNED)));
258
2
}
259
260
















4
BOOST_AUTO_TEST_CASE(test_frame_getters)
261
{
262
  using namespace Eigen;
263
  using namespace pinocchio;
264
265
  // Build a simple 1R planar model
266
4
  Model model;
267


2
  JointIndex parentId = model.addJoint(0, JointModelRZ(), SE3::Identity(), "Joint1");
268



2
  FrameIndex frameId = model.addFrame(Frame("Frame1", parentId, 0, SE3(Matrix3d::Identity(), Vector3d(1.0, 0.0, 0.0)), OP_FRAME));
269
270
4
  Data data(model);
271
272
  // Predetermined configuration values
273
4
  VectorXd q(model.nq);
274
2
  q << M_PI/2;
275
276
4
  VectorXd v(model.nv);
277
2
  v << 1.0;
278
279
4
  VectorXd a(model.nv);
280
2
  a << 0.0;
281
282
  // Expected velocity
283
2
  Motion v_local;
284

2
  v_local.linear() = Vector3d(0.0, 1.0, 0.0);
285

2
  v_local.angular() = Vector3d(0.0, 0.0, 1.0);
286
287
2
  Motion v_world;
288

2
  v_world.linear() = Vector3d::Zero();
289

2
  v_world.angular() = Vector3d(0.0, 0.0, 1.0);
290
291
2
  Motion v_align;
292

2
  v_align.linear() = Vector3d(-1.0, 0.0, 0.0);
293

2
  v_align.angular() = Vector3d(0.0, 0.0, 1.0);
294
295
  // Expected classical acceleration
296
2
  Motion ac_local;
297

2
  ac_local.linear() = Vector3d(-1.0, 0.0, 0.0);
298

2
  ac_local.angular() = Vector3d::Zero();
299
300
2
  Motion ac_world = Motion::Zero();
301
302
2
  Motion ac_align;
303

2
  ac_align.linear() = Vector3d(0.0, -1.0, 0.0);
304

2
  ac_align.angular() = Vector3d::Zero();
305
306
  // Perform kinematics
307
2
  forwardKinematics(model,data,q,v,a);
308
309
  // Check output velocity
310




2
  BOOST_CHECK(v_local.isApprox(getFrameVelocity(model,data,frameId)));
311




2
  BOOST_CHECK(v_local.isApprox(getFrameVelocity(model,data,frameId,LOCAL)));
312




2
  BOOST_CHECK(v_world.isApprox(getFrameVelocity(model,data,frameId,WORLD)));
313




2
  BOOST_CHECK(v_align.isApprox(getFrameVelocity(model,data,frameId,LOCAL_WORLD_ALIGNED)));
314
315
  // Check output acceleration (all zero)
316




2
  BOOST_CHECK(getFrameAcceleration(model,data,frameId).isZero());
317




2
  BOOST_CHECK(getFrameAcceleration(model,data,frameId,LOCAL).isZero());
318




2
  BOOST_CHECK(getFrameAcceleration(model,data,frameId,WORLD).isZero());
319




2
  BOOST_CHECK(getFrameAcceleration(model,data,frameId,LOCAL_WORLD_ALIGNED).isZero());
320
321
  // Check output classical acceleration
322




2
  BOOST_CHECK(ac_local.isApprox(getFrameClassicalAcceleration(model,data,frameId)));
323




2
  BOOST_CHECK(ac_local.isApprox(getFrameClassicalAcceleration(model,data,frameId,LOCAL)));
324




2
  BOOST_CHECK(ac_world.isApprox(getFrameClassicalAcceleration(model,data,frameId,WORLD)));
325




2
  BOOST_CHECK(ac_align.isApprox(getFrameClassicalAcceleration(model,data,frameId,LOCAL_WORLD_ALIGNED)));
326
2
}
327
328
















4
BOOST_AUTO_TEST_CASE ( test_get_frame_jacobian )
329
{
330
  using namespace Eigen;
331
  using namespace pinocchio;
332
333
4
  Model model;
334
2
  buildModels::humanoidRandom(model);
335




2
  Model::Index parent_idx = model.existJointName("rarm2_joint")?model.getJointId("rarm2_joint"):(Model::Index)(model.njoints-1);
336
4
  const std::string & frame_name = std::string( model.names[parent_idx]+ "_frame");
337
2
  const SE3 & framePlacement = SE3::Random();
338

2
  model.addFrame(Frame (frame_name, parent_idx, 0, framePlacement, OP_FRAME));
339



2
  BOOST_CHECK(model.existFrame(frame_name));
340
341
4
  pinocchio::Data data(model);
342
4
  pinocchio::Data data_ref(model);
343
344

2
  model.lowerPositionLimit.head<7>().fill(-1.);
345

2
  model.upperPositionLimit.head<7>().fill( 1.);
346
4
  VectorXd q = randomConfiguration(model);
347

4
  VectorXd v = VectorXd::Ones(model.nv);
348
349
  /// In local frame
350
2
  Model::Index idx = model.getFrameId(frame_name);
351
2
  const Frame & frame = model.frames[idx];
352



2
  BOOST_CHECK(frame.placement.isApprox_impl(framePlacement));
353

4
  Data::Matrix6x Jjj(6,model.nv); Jjj.fill(0);
354

4
  Data::Matrix6x Jff(6,model.nv); Jff.fill(0);
355

4
  Data::Matrix6x Jff2(6,model.nv); Jff2.fill(0);
356
357
2
  computeJointJacobians(model,data,q);
358
2
  updateFramePlacement(model, data, idx);
359
2
  getFrameJacobian(model,     data,        idx, LOCAL, Jff);
360
2
  computeJointJacobians(model,data_ref,q);
361
2
  getJointJacobian(model, data_ref, parent_idx, LOCAL, Jjj);
362
363

2
  Motion nu_frame = Motion(Jff*v);
364

2
  Motion nu_joint = Motion(Jjj*v);
365
366
2
  const SE3::ActionMatrixType jXf = frame.placement.toActionMatrix();
367

4
  Data::Matrix6x Jjj_from_frame(jXf * Jff);
368



2
  BOOST_CHECK(Jjj_from_frame.isApprox(Jjj));
369
370




2
  BOOST_CHECK(nu_frame.isApprox(frame.placement.actInv(nu_joint), 1e-12));
371
372
  // In world frame
373
2
  getFrameJacobian(model,data,idx,WORLD,Jff);
374
2
  getJointJacobian(model, data_ref, parent_idx,WORLD, Jjj);
375



2
  BOOST_CHECK(Jff.isApprox(Jjj));
376
377
2
  computeFrameJacobian(model,data,q,idx,WORLD,Jff2);
378
379



2
  BOOST_CHECK(Jff2.isApprox(Jjj));
380
2
}
381
382
















4
BOOST_AUTO_TEST_CASE ( test_frame_jacobian )
383
{
384
  using namespace Eigen;
385
  using namespace pinocchio;
386
387
4
  Model model;
388
2
  buildModels::humanoidRandom(model);
389




2
  Model::Index parent_idx = model.existJointName("rarm2_joint")?model.getJointId("rarm2_joint"):(Model::Index)(model.njoints-1);
390
4
  const std::string & frame_name = std::string( model.names[parent_idx]+ "_frame");
391
2
  const SE3 & framePlacement = SE3::Random();
392

2
  model.addFrame(Frame (frame_name, parent_idx, 0, framePlacement, OP_FRAME));
393



2
  BOOST_CHECK(model.existFrame(frame_name));
394
395
4
  pinocchio::Data data(model);
396
4
  pinocchio::Data data_ref(model);
397
398

2
  model.lowerPositionLimit.head<7>().fill(-1.);
399

2
  model.upperPositionLimit.head<7>().fill( 1.);
400
4
  VectorXd q = randomConfiguration(model);
401

4
  VectorXd v = VectorXd::Ones(model.nv);
402
403
2
  Model::Index idx = model.getFrameId(frame_name);
404
2
  const Frame & frame = model.frames[idx];
405



2
  BOOST_CHECK(frame.placement.isApprox_impl(framePlacement));
406

4
  Data::Matrix6x Jf(6,model.nv); Jf.fill(0);
407

4
  Data::Matrix6x Jf2(6,model.nv); Jf2.fill(0);
408

4
  Data::Matrix6x Jf_ref(6,model.nv); Jf_ref.fill(0);
409
410
2
  computeFrameJacobian(model, data_ref, q, idx, Jf);
411
412
2
  computeJointJacobians(model, data_ref, q);
413
2
  updateFramePlacement(model,  data_ref, idx);
414
2
  getFrameJacobian(model,      data_ref, idx, LOCAL, Jf_ref);
415
416



2
  BOOST_CHECK(Jf.isApprox(Jf_ref));
417
418
2
  computeFrameJacobian(model,data,q,idx,LOCAL,Jf2);
419
420



2
  BOOST_CHECK(Jf2.isApprox(Jf_ref));
421
2
}
422
423
















4
BOOST_AUTO_TEST_CASE ( test_frame_jacobian_local_world_oriented )
424
{
425
  using namespace Eigen;
426
  using namespace pinocchio;
427
428
4
  Model model;
429
2
  buildModels::humanoidRandom(model);
430




2
  Model::Index parent_idx = model.existJointName("rarm2_joint")?model.getJointId("rarm2_joint"):(Model::Index)(model.njoints-1);
431
4
  const std::string & frame_name = std::string( model.names[parent_idx]+ "_frame");
432
2
  const SE3 & framePlacement = SE3::Random();
433

2
  model.addFrame(Frame (frame_name, parent_idx, 0, framePlacement, OP_FRAME));
434



2
  BOOST_CHECK(model.existFrame(frame_name));
435
436
4
  pinocchio::Data data(model);
437
438

2
  model.lowerPositionLimit.head<7>().fill(-1.);
439

2
  model.upperPositionLimit.head<7>().fill( 1.);
440
4
  VectorXd q = randomConfiguration(model);
441

4
  VectorXd v = VectorXd::Ones(model.nv);
442
443

2
  Model::Index idx = model.getFrameId(frame_name);
444

4
  Data::Matrix6x Jf(6,model.nv); Jf.fill(0);
445

4
  Data::Matrix6x Jf2(6,model.nv); Jf2.fill(0);
446

4
  Data::Matrix6x Jf_ref(6,model.nv); Jf_ref.fill(0);
447
448
2
  computeJointJacobians(model, data, q);
449
2
  updateFramePlacement(model,  data, idx);
450
2
  getFrameJacobian(model,      data, idx, LOCAL, Jf_ref);
451
452
  // Compute the jacobians.
453



2
  Jf_ref = SE3(data.oMf[idx].rotation(), Eigen::Vector3d::Zero()).toActionMatrix() * Jf_ref;
454
2
  getFrameJacobian(model,      data, idx, LOCAL_WORLD_ALIGNED, Jf);
455
456



2
  BOOST_CHECK(Jf.isApprox(Jf_ref));
457
458
2
  computeFrameJacobian(model,data,q,idx,LOCAL_WORLD_ALIGNED,Jf2);
459
460



2
  BOOST_CHECK(Jf2.isApprox(Jf_ref));
461
2
}
462
463
















4
BOOST_AUTO_TEST_CASE ( test_frame_jacobian_time_variation )
464
{
465
  using namespace Eigen;
466
  using namespace pinocchio;
467
468
4
  pinocchio::Model model;
469
2
  pinocchio::buildModels::humanoidRandom(model);
470




2
  Model::Index parent_idx = model.existJointName("rarm2_joint")?model.getJointId("rarm2_joint"):(Model::Index)(model.njoints-1);
471
4
  const std::string & frame_name = std::string( model.names[parent_idx]+ "_frame");
472
2
  const SE3 & framePlacement = SE3::Random();
473

2
  model.addFrame(Frame (frame_name, parent_idx, 0, framePlacement, OP_FRAME));
474
4
  pinocchio::Data data(model);
475
4
  pinocchio::Data data_ref(model);
476
477


4
  VectorXd q = randomConfiguration(model, -1 * Eigen::VectorXd::Ones(model.nq), Eigen::VectorXd::Ones(model.nq) );
478

4
  VectorXd v = VectorXd::Random(model.nv);
479

4
  VectorXd a = VectorXd::Random(model.nv);
480
481
2
  computeJointJacobiansTimeVariation(model,data,q,v);
482
2
  updateFramePlacements(model,data);
483
484
2
  forwardKinematics(model,data_ref,q,v,a);
485
2
  updateFramePlacements(model,data_ref);
486
487



2
  BOOST_CHECK(isFinite(data.dJ));
488
489
2
  Model::Index idx = model.getFrameId(frame_name);
490
2
  const Frame & frame = model.frames[idx];
491



2
  BOOST_CHECK(frame.placement.isApprox_impl(framePlacement));
492
493

4
  Data::Matrix6x J(6,model.nv); J.fill(0.);
494

4
  Data::Matrix6x dJ(6,model.nv); dJ.fill(0.);
495
496
  // Regarding to the WORLD origin
497
2
  getFrameJacobian(model,data,idx,WORLD,J);
498
2
  getFrameJacobianTimeVariation(model,data,idx,WORLD,dJ);
499
500

2
  Motion v_idx(J*v);
501
2
  const Motion & v_ref_local = frame.placement.actInv(data_ref.v[parent_idx]);
502
2
  const Motion & v_ref = data_ref.oMf[idx].act(v_ref_local);
503
504

2
  const SE3 & wMf = SE3(data_ref.oMf[idx].rotation(),SE3::Vector3::Zero());
505
2
  const Motion & v_ref_local_world_aligned = wMf.act(v_ref_local);
506



2
  BOOST_CHECK(v_idx.isApprox(v_ref));
507
508


2
  Motion a_idx(J*a + dJ*v);
509
2
  const Motion & a_ref_local = frame.placement.actInv(data_ref.a[parent_idx]);
510
2
  const Motion & a_ref = data_ref.oMf[idx].act(a_ref_local);
511
2
  const Motion & a_ref_local_world_aligned = wMf.act(a_ref_local);
512



2
  BOOST_CHECK(a_idx.isApprox(a_ref));
513
514

2
  J.fill(0.);  dJ.fill(0.);
515
  // Regarding to the LOCAL frame
516
2
  getFrameJacobian(model,data,idx,LOCAL,J);
517
2
  getFrameJacobianTimeVariation(model,data,idx,LOCAL,dJ);
518
519

2
  v_idx = (Motion::Vector6)(J*v);
520



2
  BOOST_CHECK(v_idx.isApprox(v_ref_local));
521
522


2
  a_idx = (Motion::Vector6)(J*a + dJ*v);
523



2
  BOOST_CHECK(a_idx.isApprox(a_ref_local));
524
525
  // Regarding to the LOCAL_WORLD_ALIGNED frame
526
2
  getFrameJacobian(model,data,idx,LOCAL_WORLD_ALIGNED,J);
527
2
  getFrameJacobianTimeVariation(model,data,idx,LOCAL_WORLD_ALIGNED,dJ);
528
529

2
  v_idx = (Motion::Vector6)(J*v);
530



2
  BOOST_CHECK(v_idx.isApprox(v_ref_local_world_aligned));
531
532


2
  a_idx = (Motion::Vector6)(J*a + dJ*v);
533



2
  BOOST_CHECK(a_idx.isApprox(a_ref_local_world_aligned));
534
535
  // compare to finite differencies
536
  {
537

4
    Data data_ref(model), data_ref_plus(model);
538
539
2
    const double alpha = 1e-8;
540
4
    Eigen::VectorXd q_plus(model.nq);
541

2
    q_plus = integrate(model,q,alpha*v);
542
543
    //data_ref
544

4
    Data::Matrix6x J_ref_world(6,model.nv), J_ref_local(6,model.nv), J_ref_local_world_aligned(6,model.nv);
545

2
    J_ref_world.fill(0.); J_ref_local.fill(0.); J_ref_local_world_aligned.fill(0.);
546
2
    computeJointJacobians(model,data_ref,q);
547
2
    updateFramePlacements(model,data_ref);
548
2
    const SE3 & oMf_q = data_ref.oMf[idx];
549
2
    getFrameJacobian(model,data_ref,idx,WORLD,J_ref_world);
550
2
    getFrameJacobian(model,data_ref,idx,LOCAL,J_ref_local);
551
2
    getFrameJacobian(model,data_ref,idx,LOCAL_WORLD_ALIGNED,J_ref_local_world_aligned);
552
553
    //data_ref_plus
554

4
    Data::Matrix6x J_ref_plus_world(6,model.nv), J_ref_plus_local(6,model.nv), J_ref_plus_local_world_aligned(6,model.nv);
555

2
    J_ref_plus_world.fill(0.); J_ref_plus_local.fill(0.); J_ref_plus_local_world_aligned.fill(0.);
556
2
    computeJointJacobians(model,data_ref_plus,q_plus);
557
2
    updateFramePlacements(model,data_ref_plus);
558
2
    const SE3 & oMf_q_plus = data_ref_plus.oMf[idx];
559
2
    getFrameJacobian(model,data_ref_plus,idx,WORLD,J_ref_plus_world);
560
2
    getFrameJacobian(model,data_ref_plus,idx,LOCAL,J_ref_plus_local);
561
2
    getFrameJacobian(model,data_ref_plus,idx,LOCAL_WORLD_ALIGNED,J_ref_plus_local_world_aligned);
562
563
    //Move J_ref_plus_local to reference frame
564


2
    J_ref_plus_local = (oMf_q.inverse()*oMf_q_plus).toActionMatrix()*(J_ref_plus_local);
565
566
    //Move J_ref_plus_local_world_aligned to reference frame
567
2
    SE3 oMf_translation = SE3::Identity();
568


2
    oMf_translation.translation() = oMf_q_plus.translation() - oMf_q.translation();
569

2
    J_ref_plus_local_world_aligned = oMf_translation.toActionMatrix()*(J_ref_plus_local_world_aligned);
570
571

4
    Data::Matrix6x dJ_ref_world(6,model.nv), dJ_ref_local(6,model.nv), dJ_ref_local_world_aligned(6,model.nv);
572

2
    dJ_ref_world.fill(0.); dJ_ref_local.fill(0.); dJ_ref_local_world_aligned.fill(0.);
573

2
    dJ_ref_world = (J_ref_plus_world - J_ref_world)/alpha;
574

2
    dJ_ref_local = (J_ref_plus_local - J_ref_local)/alpha;
575

2
    dJ_ref_local_world_aligned = (J_ref_plus_local_world_aligned - J_ref_local_world_aligned)/alpha;
576
577
    //data
578
2
    computeJointJacobiansTimeVariation(model,data,q,v);
579
2
    forwardKinematics(model,data,q,v);
580
2
    updateFramePlacements(model,data);
581

4
    Data::Matrix6x dJ_world(6,model.nv), dJ_local(6,model.nv), dJ_local_world_aligned(6,model.nv);
582

2
    dJ_world.fill(0.); dJ_local.fill(0.); dJ_local_world_aligned.fill(0.);
583
2
    getFrameJacobianTimeVariation(model,data,idx,WORLD,dJ_world);
584
2
    getFrameJacobianTimeVariation(model,data,idx,LOCAL,dJ_local);
585
2
    getFrameJacobianTimeVariation(model,data,idx,LOCAL_WORLD_ALIGNED,dJ_local_world_aligned);
586
587



2
    BOOST_CHECK(dJ_world.isApprox(dJ_ref_world,sqrt(alpha)));
588



2
    BOOST_CHECK(dJ_local.isApprox(dJ_ref_local,sqrt(alpha)));
589



2
    BOOST_CHECK(dJ_local_world_aligned.isApprox(dJ_ref_local_world_aligned,sqrt(alpha)));
590
  }
591
2
}
592
593
















4
BOOST_AUTO_TEST_CASE(test_supported_inertia_and_force)
594
{
595
  using namespace Eigen;
596
  using namespace pinocchio;
597
598
  // Create a humanoid robot
599
4
  Model model_free;
600
2
  pinocchio::buildModels::humanoid(model_free, true);
601
4
  Data data_free(model_free);
602
603
  // Set freeflyer limits to allow for randomConfiguration
604

2
  model_free.lowerPositionLimit.segment(0, 3) << Vector3d::Constant(-1);
605

2
  model_free.upperPositionLimit.segment(0, 3) << Vector3d::Constant( 1);
606
607
  // Joint of interest (that will be converted to frame)
608
4
  const std::string joint_name = "chest2_joint";
609
2
  const JointIndex joint_id = model_free.getJointId(joint_name);
610
611
  // Duplicate of the model with the joint of interest fixed (to make a frame)
612

6
  pinocchio::Model model_fix = buildReducedModel(model_free, {joint_id}, neutral(model_free));
613
4
  Data data_fix(model_fix);
614
2
  const FrameIndex frame_id = model_fix.getFrameId(joint_name);
615
616
  // Const variable to help convert q, v, a from one model to another
617
2
  const int joint_idx_q(model_free.joints[joint_id].idx_q());
618
2
  const int joint_idx_v(model_free.joints[joint_id].idx_v());
619
620
  // Pick random q, v, a
621
4
  VectorXd q_free = randomConfiguration(model_free);
622

4
  VectorXd v_free(VectorXd::Random(model_free.nv));
623

4
  VectorXd a_free(VectorXd::Random(model_free.nv));
624
625
  // Set joint of interest to q, v, a = 0 to mimic the fixed joint
626
2
  q_free[joint_idx_q] =  0;
627
2
  v_free[joint_idx_v] =  0;
628
2
  a_free[joint_idx_v] =  0;
629
630
  // Adapt configuration for fixed joint model
631
4
  VectorXd q_fix(model_fix.nq);
632


2
  q_fix << q_free.head(joint_idx_q), q_free.tail(model_free.nq - joint_idx_q - 1);
633
4
  VectorXd v_fix(model_fix.nv);
634


2
  v_fix << v_free.head(joint_idx_v), v_free.tail(model_free.nv - joint_idx_v - 1);
635
4
  VectorXd a_fix(model_fix.nv);
636


2
  a_fix << a_free.head(joint_idx_v), a_free.tail(model_free.nv - joint_idx_v - 1);
637
638
  // Compute inertia/force for both models differently
639
2
  forwardKinematics(model_fix, data_fix, q_fix, v_fix, a_fix);
640
2
  crba(model_free, data_free, q_free);
641
642
2
  Inertia inertia_fix = computeSupportedInertiaByFrame(model_fix, data_fix, frame_id, false);
643
2
  Inertia inertia_free(model_free.inertias[joint_id]);
644



2
  BOOST_CHECK(inertia_fix.isApprox(inertia_free));
645
646

2
  inertia_fix = computeSupportedInertiaByFrame(model_fix, data_fix, frame_id, true);
647
2
  inertia_free = data_free.Ycrb[joint_id];
648



2
  BOOST_CHECK(inertia_fix.isApprox(inertia_free));
649
650
2
  rnea(model_fix, data_fix, q_fix, v_fix, a_fix);
651
2
  rnea(model_free,  data_free,  q_free,  v_free,  a_free);
652
653
2
  Force force_fix = computeSupportedForceByFrame(model_fix, data_fix, frame_id);
654
2
  Force force_free(data_free.f[joint_id]);
655



2
  BOOST_CHECK(force_fix.isApprox(force_free));
656
2
}
657
BOOST_AUTO_TEST_SUITE_END ()