Line |
Branch |
Exec |
Source |
1 |
|
|
// |
2 |
|
|
// Copyright (c) 2016 CNRS |
3 |
|
|
// |
4 |
|
|
|
5 |
|
|
#include "pinocchio/multibody/joint/joint-composite.hpp" |
6 |
|
|
#include "pinocchio/algorithm/joint-configuration.hpp" |
7 |
|
|
#include "pinocchio/algorithm/kinematics.hpp" |
8 |
|
|
|
9 |
|
|
#include <iostream> |
10 |
|
|
#include <boost/test/unit_test.hpp> |
11 |
|
|
#include <boost/utility/binary.hpp> |
12 |
|
|
|
13 |
|
|
using namespace pinocchio; |
14 |
|
|
using namespace Eigen; |
15 |
|
|
|
16 |
|
|
template<typename JointModel> |
17 |
|
|
void test_joint_methods( |
18 |
|
|
const JointModelBase<JointModel> & jmodel, JointModelComposite & jmodel_composite); |
19 |
|
|
|
20 |
|
|
template<typename JointModel> |
21 |
|
✗ |
void test_joint_methods(const JointModelBase<JointModel> & jmodel) |
22 |
|
|
{ |
23 |
|
✗ |
JointModelComposite jmodel_composite(jmodel); |
24 |
|
✗ |
test_joint_methods(jmodel, jmodel_composite); |
25 |
|
|
} |
26 |
|
|
|
27 |
|
|
template<typename JointModel> |
28 |
|
✗ |
void test_joint_methods( |
29 |
|
|
const JointModelBase<JointModel> & jmodel, JointModelComposite & jmodel_composite) |
30 |
|
|
{ |
31 |
|
|
typedef typename JointModelBase<JointModel>::JointDataDerived JointData; |
32 |
|
|
|
33 |
|
✗ |
JointData jdata = jmodel.createData(); |
34 |
|
✗ |
JointDataComposite jdata_composite = jmodel_composite.createData(); |
35 |
|
|
|
36 |
|
✗ |
jmodel_composite.setIndexes(jmodel.id(), jmodel.idx_q(), jmodel.idx_v()); |
37 |
|
|
|
38 |
|
|
typedef typename JointModel::ConfigVector_t ConfigVector_t; |
39 |
|
|
typedef typename JointModel::TangentVector_t TangentVector_t; |
40 |
|
|
typedef typename LieGroup<JointModel>::type LieGroupType; |
41 |
|
|
|
42 |
|
|
typedef Eigen::Matrix<typename ConfigVector_t::Scalar, Eigen::Dynamic, 1, ConfigVector_t::Options> |
43 |
|
|
DynConfigVectorType; |
44 |
|
|
typedef DynConfigVectorType DynTangentVectorType; |
45 |
|
|
|
46 |
|
✗ |
ConfigVector_t ql(ConfigVector_t::Constant(jmodel.nq(), -M_PI)); |
47 |
|
✗ |
ConfigVector_t qu(ConfigVector_t::Constant(jmodel.nq(), M_PI)); |
48 |
|
✗ |
DynConfigVectorType q = LieGroupType().randomConfiguration(ql, qu); |
49 |
|
|
|
50 |
|
✗ |
BOOST_CHECK(jmodel.nv() == jmodel_composite.nv()); |
51 |
|
✗ |
BOOST_CHECK(jmodel.nq() == jmodel_composite.nq()); |
52 |
|
|
|
53 |
|
✗ |
jmodel.calc(jdata, q); |
54 |
|
✗ |
jmodel_composite.calc(jdata_composite, q); |
55 |
|
|
|
56 |
|
✗ |
BOOST_CHECK(jdata_composite.M.isApprox((SE3)jdata.M)); |
57 |
|
✗ |
BOOST_CHECK(jdata_composite.S.matrix().isApprox(jdata.S.matrix())); |
58 |
|
|
|
59 |
|
✗ |
q = LieGroupType().randomConfiguration(ql, qu); |
60 |
|
✗ |
DynTangentVectorType v = TangentVector_t::Random(jmodel.nv()); |
61 |
|
✗ |
jmodel.calc(jdata, q, v); |
62 |
|
✗ |
jmodel_composite.calc(jdata_composite, q, v); |
63 |
|
|
|
64 |
|
✗ |
BOOST_CHECK(jdata_composite.M.isApprox((SE3)jdata.M)); |
65 |
|
✗ |
BOOST_CHECK(jdata_composite.S.matrix().isApprox(jdata.S.matrix())); |
66 |
|
✗ |
BOOST_CHECK(jdata_composite.v.isApprox((Motion)jdata.v)); |
67 |
|
✗ |
BOOST_CHECK(jdata_composite.c.isApprox((Motion)jdata.c)); |
68 |
|
|
|
69 |
|
|
// TODO: Not yet checked |
70 |
|
|
// { |
71 |
|
|
// VectorXd q1(jmodel.random()); |
72 |
|
|
// jmodel.normalize(q1); |
73 |
|
|
// VectorXd q2(jmodel.random()); |
74 |
|
|
// jmodel.normalize(q2); |
75 |
|
|
// VectorXd v(VectorXd::Random(jmodel.nv())); |
76 |
|
|
// |
77 |
|
|
// BOOST_CHECK(jmodel_composite.integrate(q1,v).isApprox(jmodel.integrate(q1,v))); |
78 |
|
|
// |
79 |
|
|
// TangentVector_t v1 = jmodel_composite.difference(q1,q2); |
80 |
|
|
// TangentVector_t v2 = jmodel.difference(q1,q2); |
81 |
|
|
// |
82 |
|
|
// BOOST_CHECK(v1.isApprox(v2)); |
83 |
|
|
// |
84 |
|
|
// const double alpha = 0.2; |
85 |
|
|
// BOOST_CHECK(jmodel_composite.interpolate(q1,q2,alpha).isApprox(jmodel.interpolate(q1,q2,alpha))); |
86 |
|
|
// BOOST_CHECK(math::fabs(jmodel_composite.distance(q1,q2)-jmodel.distance(q1,q2))<= |
87 |
|
|
// NumTraits<double>::dummy_precision()); |
88 |
|
|
// } |
89 |
|
|
|
90 |
|
✗ |
Inertia::Matrix6 I0(Inertia::Random().matrix()); |
91 |
|
|
|
92 |
|
✗ |
Inertia::Matrix6 I1 = I0; |
93 |
|
✗ |
Inertia::Matrix6 I2 = I0; |
94 |
|
|
|
95 |
|
✗ |
const Eigen::VectorXd armature = |
96 |
|
✗ |
Eigen::VectorXd::Random(jmodel.nv()) + Eigen::VectorXd::Ones(jmodel.nv()); |
97 |
|
✗ |
jmodel.calc_aba(jdata, armature, I1, true); |
98 |
|
✗ |
jmodel_composite.calc_aba(jdata_composite, armature, I2, true); |
99 |
|
|
|
100 |
|
✗ |
double prec = 1e-10; // higher tolerance to errors due to possible numerical imprecisions |
101 |
|
|
|
102 |
|
✗ |
BOOST_CHECK(jdata.U.isApprox(jdata_composite.U, prec)); |
103 |
|
✗ |
BOOST_CHECK(jdata.Dinv.isApprox(jdata_composite.Dinv, prec)); |
104 |
|
✗ |
BOOST_CHECK(jdata.UDinv.isApprox(jdata_composite.UDinv, prec)); |
105 |
|
|
|
106 |
|
|
// Checking the inertia was correctly updated |
107 |
|
|
// We use isApprox as usual, except for the freeflyer, |
108 |
|
|
// where the correct result is exacly zero and isApprox would fail. |
109 |
|
|
// Only for this single case, we use the infinity norm of the difference |
110 |
|
✗ |
if (jmodel.shortname() == "JointModelFreeFlyer") |
111 |
|
✗ |
BOOST_CHECK((I1 - I2).lpNorm<Eigen::Infinity>() < prec); |
112 |
|
|
else |
113 |
|
✗ |
BOOST_CHECK(I1.isApprox(I2, prec)); |
114 |
|
|
|
115 |
|
|
// Test operator= |
116 |
|
✗ |
JointModelComposite jmodel_composite2 = jmodel_composite; |
117 |
|
✗ |
JointDataComposite jdata_composite2 = jmodel_composite2.createData(); |
118 |
|
|
|
119 |
|
✗ |
jmodel_composite2.calc(jdata_composite2, q, v); |
120 |
|
|
|
121 |
|
✗ |
Inertia::Matrix6 I3 = I0; |
122 |
|
✗ |
jmodel_composite2.calc_aba(jdata_composite2, armature, I3, true); |
123 |
|
|
|
124 |
|
✗ |
if (jmodel.shortname() == "JointModelFreeFlyer") |
125 |
|
✗ |
BOOST_CHECK((I3 - I2).lpNorm<Eigen::Infinity>() < prec); |
126 |
|
|
else |
127 |
|
✗ |
BOOST_CHECK(I3.isApprox(I2, prec)); |
128 |
|
|
|
129 |
|
✗ |
BOOST_CHECK(jmodel_composite2 == jmodel_composite); |
130 |
|
|
|
131 |
|
✗ |
BOOST_CHECK(jdata_composite2.U.isApprox(jdata_composite.U, prec)); |
132 |
|
✗ |
BOOST_CHECK(jdata_composite2.Dinv.isApprox(jdata_composite.Dinv, prec)); |
133 |
|
✗ |
BOOST_CHECK(jdata_composite2.UDinv.isApprox(jdata_composite.UDinv, prec)); |
134 |
|
|
|
135 |
|
|
// Test operator << |
136 |
|
✗ |
std::cout << "JointModelComposite operator<<:\n" << jmodel_composite << std::endl; |
137 |
|
|
|
138 |
|
|
// Test block operators |
139 |
|
✗ |
const int m = 100; |
140 |
|
✗ |
Data::Matrix6x mat(Data::Matrix6x::Ones(6, m)); |
141 |
|
✗ |
const Data::Matrix6x mat_const(Data::Matrix6x::Ones(6, m)); |
142 |
|
✗ |
Model::ConfigVectorType vec(Model::ConfigVectorType::Ones(m)); |
143 |
|
✗ |
const Model::ConfigVectorType vec_const(Model::ConfigVectorType::Ones(m)); |
144 |
|
|
|
145 |
|
✗ |
BOOST_CHECK(jmodel.jointConfigSelector(vec) == jmodel_composite.jointConfigSelector(vec)); |
146 |
|
✗ |
BOOST_CHECK( |
147 |
|
|
jmodel.jointConfigSelector(vec_const) == jmodel_composite.jointConfigSelector(vec_const)); |
148 |
|
|
|
149 |
|
✗ |
BOOST_CHECK(jmodel.jointVelocitySelector(vec) == jmodel_composite.jointVelocitySelector(vec)); |
150 |
|
✗ |
BOOST_CHECK( |
151 |
|
|
jmodel.jointVelocitySelector(vec_const) == jmodel_composite.jointVelocitySelector(vec_const)); |
152 |
|
|
|
153 |
|
✗ |
BOOST_CHECK(jmodel.jointCols(mat) == jmodel_composite.jointCols(mat)); |
154 |
|
✗ |
BOOST_CHECK(jmodel.jointCols(mat_const) == jmodel_composite.jointCols(mat_const)); |
155 |
|
|
} |
156 |
|
|
|
157 |
|
|
struct TestJointComposite |
158 |
|
|
{ |
159 |
|
|
|
160 |
|
|
template<typename JointModel> |
161 |
|
✗ |
void operator()(const JointModelBase<JointModel> &) const |
162 |
|
|
{ |
163 |
|
✗ |
JointModel jmodel; |
164 |
|
✗ |
jmodel.setIndexes(0, 0, 0); |
165 |
|
|
|
166 |
|
✗ |
test_joint_methods(jmodel); |
167 |
|
|
} |
168 |
|
|
|
169 |
|
|
// void operator()(const JointModelBase<JointModelComposite> &) const |
170 |
|
|
// { |
171 |
|
|
// JointModelComposite jmodel_composite; |
172 |
|
|
// jmodel_composite.addJoint(pinocchio::JointModelRX()); |
173 |
|
|
// jmodel_composite.addJoint(pinocchio::JointModelRY()); |
174 |
|
|
// jmodel_composite.setIndexes(0,0,0); |
175 |
|
|
// |
176 |
|
|
// test_joint_methods(jmodel_composite); |
177 |
|
|
// } |
178 |
|
|
|
179 |
|
✗ |
void operator()(const JointModelBase<JointModelRevoluteUnaligned> &) const |
180 |
|
|
{ |
181 |
|
✗ |
JointModelRevoluteUnaligned jmodel(1.5, 1., 0.); |
182 |
|
✗ |
jmodel.setIndexes(0, 0, 0); |
183 |
|
|
|
184 |
|
✗ |
test_joint_methods(jmodel); |
185 |
|
|
} |
186 |
|
|
|
187 |
|
✗ |
void operator()(const JointModelBase<JointModelPrismaticUnaligned> &) const |
188 |
|
|
{ |
189 |
|
✗ |
JointModelPrismaticUnaligned jmodel(1.5, 1., 0.); |
190 |
|
✗ |
jmodel.setIndexes(0, 0, 0); |
191 |
|
✗ |
test_joint_methods(jmodel); |
192 |
|
|
} |
193 |
|
|
}; |
194 |
|
|
|
195 |
|
|
BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE) |
196 |
|
|
|
197 |
|
✗ |
BOOST_AUTO_TEST_CASE(test_basic) |
198 |
|
|
{ |
199 |
|
|
typedef boost::variant< |
200 |
|
|
JointModelRX, JointModelRY, JointModelRZ, JointModelRevoluteUnaligned, JointModelSpherical, |
201 |
|
|
JointModelSphericalZYX, JointModelPX, JointModelPY, JointModelPZ, JointModelPrismaticUnaligned, |
202 |
|
|
JointModelFreeFlyer, JointModelPlanar, JointModelTranslation, JointModelRUBX, JointModelRUBY, |
203 |
|
|
JointModelRUBZ> |
204 |
|
|
Variant; |
205 |
|
|
|
206 |
|
✗ |
boost::mpl::for_each<Variant::types>(TestJointComposite()); |
207 |
|
|
} |
208 |
|
|
|
209 |
|
✗ |
BOOST_AUTO_TEST_CASE(chain) |
210 |
|
|
{ |
211 |
|
✗ |
JointModelComposite jmodel_composite; |
212 |
|
✗ |
jmodel_composite.addJoint(JointModelRZ()) |
213 |
|
✗ |
.addJoint(JointModelRY(), SE3::Random()) |
214 |
|
✗ |
.addJoint(JointModelRX()); |
215 |
|
✗ |
BOOST_CHECK_MESSAGE(jmodel_composite.nq() == 3, "Chain did not work"); |
216 |
|
✗ |
BOOST_CHECK_MESSAGE(jmodel_composite.nv() == 3, "Chain did not work"); |
217 |
|
✗ |
BOOST_CHECK_MESSAGE(jmodel_composite.njoints == 3, "Chain did not work"); |
218 |
|
|
} |
219 |
|
|
|
220 |
|
✗ |
BOOST_AUTO_TEST_CASE(vsZYX) |
221 |
|
|
{ |
222 |
|
✗ |
JointModelSphericalZYX jmodel_spherical; |
223 |
|
✗ |
jmodel_spherical.setIndexes(0, 0, 0); |
224 |
|
|
|
225 |
|
✗ |
JointModelComposite jmodel_composite((JointModelRZ())); |
226 |
|
✗ |
jmodel_composite.addJoint(JointModelRY()); |
227 |
|
✗ |
jmodel_composite.addJoint(JointModelRX()); |
228 |
|
|
|
229 |
|
✗ |
test_joint_methods(jmodel_spherical, jmodel_composite); |
230 |
|
|
} |
231 |
|
|
|
232 |
|
✗ |
BOOST_AUTO_TEST_CASE(vsTranslation) |
233 |
|
|
{ |
234 |
|
✗ |
JointModelTranslation jmodel_translation; |
235 |
|
✗ |
jmodel_translation.setIndexes(0, 0, 0); |
236 |
|
|
|
237 |
|
✗ |
JointModelComposite jmodel_composite((JointModelPX())); |
238 |
|
✗ |
jmodel_composite.addJoint(JointModelPY()); |
239 |
|
✗ |
jmodel_composite.addJoint(JointModelPZ()); |
240 |
|
|
|
241 |
|
✗ |
test_joint_methods(jmodel_translation, jmodel_composite); |
242 |
|
|
} |
243 |
|
|
|
244 |
|
✗ |
BOOST_AUTO_TEST_CASE(test_recursive_variant) |
245 |
|
|
{ |
246 |
|
|
/// Create joint composite with two joints, |
247 |
|
✗ |
JointModelComposite jmodel_composite_two_rx((JointModelRX())); |
248 |
|
✗ |
jmodel_composite_two_rx.addJoint(JointModelRY()); |
249 |
|
|
|
250 |
|
|
/// Create Joint composite with three joints, and add a composite in it, to test the |
251 |
|
|
/// recursive_wrapper |
252 |
|
✗ |
JointModelComposite jmodel_composite_recursive((JointModelFreeFlyer())); |
253 |
|
✗ |
jmodel_composite_recursive.addJoint(JointModelPlanar()); |
254 |
|
✗ |
jmodel_composite_recursive.addJoint(jmodel_composite_two_rx); |
255 |
|
|
} |
256 |
|
|
|
257 |
|
✗ |
BOOST_AUTO_TEST_CASE(test_copy) |
258 |
|
|
{ |
259 |
|
✗ |
JointModelComposite jmodel_composite_planar((JointModelPX())); |
260 |
|
✗ |
jmodel_composite_planar.addJoint(JointModelPY()); |
261 |
|
✗ |
jmodel_composite_planar.addJoint(JointModelRZ()); |
262 |
|
✗ |
jmodel_composite_planar.setIndexes(0, 0, 0); |
263 |
|
|
|
264 |
|
✗ |
JointDataComposite jdata_composite_planar = jmodel_composite_planar.createData(); |
265 |
|
|
|
266 |
|
✗ |
VectorXd q1(VectorXd::Random(3)); |
267 |
|
✗ |
VectorXd q1_dot(VectorXd::Random(3)); |
268 |
|
|
|
269 |
|
✗ |
JointModelComposite model_copy = jmodel_composite_planar; |
270 |
|
✗ |
JointDataComposite data_copy = model_copy.createData(); |
271 |
|
|
|
272 |
|
✗ |
BOOST_CHECK_MESSAGE( |
273 |
|
|
model_copy.nq() == jmodel_composite_planar.nq(), "Test Copy Composite, nq are differents"); |
274 |
|
✗ |
BOOST_CHECK_MESSAGE( |
275 |
|
|
model_copy.nv() == jmodel_composite_planar.nv(), "Test Copy Composite, nv are differents"); |
276 |
|
|
|
277 |
|
✗ |
jmodel_composite_planar.calc(jdata_composite_planar, q1, q1_dot); |
278 |
|
✗ |
model_copy.calc(data_copy, q1, q1_dot); |
279 |
|
|
} |
280 |
|
|
|
281 |
|
✗ |
BOOST_AUTO_TEST_CASE(test_kinematics) |
282 |
|
|
{ |
283 |
|
✗ |
Model model; |
284 |
|
✗ |
JointModelComposite jmodel_composite; |
285 |
|
|
|
286 |
|
✗ |
SE3 config = SE3::Random(); |
287 |
|
✗ |
JointIndex parent = 0; |
288 |
|
|
|
289 |
|
✗ |
for (int i = 0; i < 10; i++) |
290 |
|
|
{ |
291 |
|
✗ |
parent = model.addJoint(parent, JointModelRX(), config, "joint"); |
292 |
|
✗ |
jmodel_composite.addJoint(JointModelRX(), config); |
293 |
|
|
|
294 |
|
✗ |
config.setRandom(); |
295 |
|
|
} |
296 |
|
|
|
297 |
|
✗ |
Data data(model); |
298 |
|
|
|
299 |
|
✗ |
Model model_c; |
300 |
|
✗ |
model_c.addJoint(0, jmodel_composite, SE3::Identity(), "joint"); |
301 |
|
|
|
302 |
|
✗ |
Data data_c(model_c); |
303 |
|
|
|
304 |
|
✗ |
BOOST_CHECK(model.nv == model_c.nv); |
305 |
|
✗ |
BOOST_CHECK(model.nq == model_c.nq); |
306 |
|
|
|
307 |
|
✗ |
VectorXd q(VectorXd::Random(model.nv)); |
308 |
|
✗ |
forwardKinematics(model, data, q); |
309 |
|
✗ |
forwardKinematics(model_c, data_c, q); |
310 |
|
|
|
311 |
|
✗ |
BOOST_CHECK(data.oMi.back().isApprox(data_c.oMi.back())); |
312 |
|
|
|
313 |
|
✗ |
q.setRandom(model.nq); |
314 |
|
✗ |
VectorXd v(VectorXd::Random(model.nv)); |
315 |
|
✗ |
forwardKinematics(model, data, q, v); |
316 |
|
✗ |
forwardKinematics(model_c, data_c, q, v); |
317 |
|
|
|
318 |
|
✗ |
BOOST_CHECK(data.oMi.back().isApprox(data_c.oMi.back())); |
319 |
|
✗ |
BOOST_CHECK(data.v.back().isApprox(data_c.v.back())); |
320 |
|
|
|
321 |
|
✗ |
q.setRandom(model.nq); |
322 |
|
✗ |
v.setRandom(model.nv); |
323 |
|
✗ |
VectorXd a(VectorXd::Random(model.nv)); |
324 |
|
✗ |
forwardKinematics(model, data, q, v, a); |
325 |
|
✗ |
forwardKinematics(model_c, data_c, q, v, a); |
326 |
|
|
|
327 |
|
✗ |
BOOST_CHECK(data.oMi.back().isApprox(data_c.oMi.back())); |
328 |
|
✗ |
BOOST_CHECK(data.v.back().isApprox(data_c.v.back())); |
329 |
|
✗ |
BOOST_CHECK(data.a.back().isApprox(data_c.a.back())); |
330 |
|
|
} |
331 |
|
|
|
332 |
|
|
BOOST_AUTO_TEST_SUITE_END() |
333 |
|
|
|