Skip to content

Commit ac9a540

Browse files
Cfatherjcarpent
authored andcommitted
add passivity rnea algorithm and the tests
1 parent ca07368 commit ac9a540

File tree

8 files changed

+299
-1
lines changed

8 files changed

+299
-1
lines changed

include/pinocchio/algorithm/rnea.hpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,43 @@ namespace pinocchio
8080
const Eigen::MatrixBase<TangentVectorType2> & a,
8181
const container::aligned_vector<ForceDerived> & fext);
8282

83+
///
84+
/// \brief The passivity-based Recursive Newton-Euler algorithm. It computes a modified inverse dynamics, aka the joint
85+
/// torques according to the current state of the system and the auxiliary joint velocities and accelerations.
86+
/// To be more specific, it computes H(q) * a_r + C(q, v) * v_r + g(q)
87+
///
88+
/// \tparam JointCollection Collection of Joint types.
89+
/// \tparam ConfigVectorType Type of the joint configuration vector.
90+
/// \tparam TangentVectorType1 Type of the joint velocity vector.
91+
/// \tparam TangentVectorType2 Type of the auxiliary joint velocity vector.
92+
/// \tparam TangentVectorType3 Type of the auxiliary joint acceleration vector.
93+
///
94+
/// \param[in] model The model structure of the rigid body system.
95+
/// \param[in] data The data structure of the rigid body system.
96+
/// \param[in] q The joint configuration vector (dim model.nq).
97+
/// \param[in] v The joint velocity vector (dim model.nv).
98+
/// \param[in] v_r The auxiliary joint velocity vector (dim model.nv).
99+
/// \param[in] a_r The auxiliary joint acceleration vector (dim model.nv).
100+
///
101+
/// \return The desired joint torques stored in data.tau.
102+
///
103+
template<
104+
typename Scalar,
105+
int Options,
106+
template<typename, int>
107+
class JointCollectionTpl,
108+
typename ConfigVectorType,
109+
typename TangentVectorType1,
110+
typename TangentVectorType2,
111+
typename TangentVectorType3>
112+
const typename DataTpl<Scalar, Options, JointCollectionTpl>::TangentVectorType & passivityRNEA(
113+
const ModelTpl<Scalar, Options, JointCollectionTpl> & model,
114+
DataTpl<Scalar, Options, JointCollectionTpl> & data,
115+
const Eigen::MatrixBase<ConfigVectorType> & q,
116+
const Eigen::MatrixBase<TangentVectorType1> & v,
117+
const Eigen::MatrixBase<TangentVectorType2> & v_r,
118+
const Eigen::MatrixBase<TangentVectorType3> & a_r);
119+
83120
///
84121
/// \brief Computes the non-linear effects (Corriolis, centrifual and gravitationnal effects),
85122
/// also called the bias terms \f$ b(q,\dot{q}) \f$ of the Lagrangian dynamics: <CENTER> \f$

include/pinocchio/algorithm/rnea.hxx

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,159 @@ namespace pinocchio
215215
return data.tau;
216216
}
217217

218+
template<
219+
typename Scalar,
220+
int Options,
221+
template<typename, int>
222+
class JointCollectionTpl,
223+
typename ConfigVectorType,
224+
typename TangentVectorType1,
225+
typename TangentVectorType2,
226+
typename TangentVectorType3>
227+
struct PassivityRneaForwardStep
228+
: public fusion::JointUnaryVisitorBase<PassivityRneaForwardStep<
229+
Scalar,
230+
Options,
231+
JointCollectionTpl,
232+
ConfigVectorType,
233+
TangentVectorType1,
234+
TangentVectorType2,
235+
TangentVectorType3>>
236+
{
237+
typedef ModelTpl<Scalar, Options, JointCollectionTpl> Model;
238+
typedef DataTpl<Scalar, Options, JointCollectionTpl> Data;
239+
typedef ForceTpl<Scalar, Options> Force;
240+
241+
typedef boost::fusion::vector<
242+
const Model &,
243+
Data &,
244+
const ConfigVectorType &,
245+
const TangentVectorType1 &,
246+
const TangentVectorType2 &,
247+
const TangentVectorType3 &>
248+
ArgsType;
249+
250+
template<typename JointModel>
251+
static void algo(
252+
const JointModelBase<JointModel> & jmodel,
253+
JointDataBase<typename JointModel::JointDataDerived> & jdata,
254+
const Model & model,
255+
Data & data,
256+
const Eigen::MatrixBase<ConfigVectorType> & q,
257+
const Eigen::MatrixBase<TangentVectorType1> & v,
258+
const Eigen::MatrixBase<TangentVectorType2> & v_r,
259+
const Eigen::MatrixBase<TangentVectorType3> & a_r)
260+
{
261+
typedef typename Model::JointIndex JointIndex;
262+
263+
const JointIndex i = jmodel.id();
264+
const JointIndex parent = model.parents[i];
265+
266+
jmodel.calc(jdata.derived(), q.derived(), v.derived());
267+
data.v[i] = jdata.v();
268+
269+
jmodel.calc(jdata.derived(), q.derived(), v_r.derived());
270+
data.v_r[i] = jdata.v();
271+
272+
data.liMi[i] = model.jointPlacements[i] * jdata.M();
273+
274+
if (parent > 0) {
275+
data.v[i] += data.liMi[i].actInv(data.v[parent]);
276+
data.v_r[i] += data.liMi[i].actInv(data.v_r[parent]);
277+
}
278+
279+
data.a_gf[i] = jdata.c() + (data.v[i] ^ jdata.v());
280+
data.a_gf[i] += jdata.S() * jmodel.jointVelocitySelector(a_r);
281+
data.a_gf[i] += data.liMi[i].actInv(data.a_gf[parent]);
282+
//
283+
// data.f[i] = model.inertias[i]*data.a_gf[i];// + model.inertias[i].vxiv(data.v[i]);
284+
// // -f_ext data.h[i] = model.inertias[i]*data.v[i];
285+
286+
// model.inertias[i].__mult__(data.v_r[i], data.h[i]); // option 1
287+
data.B[i] = model.inertias[i].variation(Scalar(0.5) * data.v[i]);
288+
model.inertias[i].__mult__(data.v[i], data.h[i]);
289+
addForceCrossMatrix(Scalar(0.5) * data.h[i], data.B[i]); // option 3 (Christoffel-consistent factorization)
290+
291+
model.inertias[i].__mult__(data.a_gf[i], data.f[i]);
292+
// data.f[i] += data.v[i].cross(data.h[i]); // option 1
293+
data.f[i] += Force(data.B[i] * data.v_r[i].toVector()); // option 3 (Christoffel-consistent factorization)
294+
295+
// data.h[i].motionAction(data.v[i],data.f[i]);
296+
// data.f[i] = model.inertias[i].vxiv(data.v[i]);
297+
// data.f[i].setZero();
298+
}
299+
300+
template<typename ForceDerived, typename M6>
301+
static void
302+
addForceCrossMatrix(const ForceDense<ForceDerived> & f, const Eigen::MatrixBase<M6> & mout)
303+
{
304+
M6 & mout_ = PINOCCHIO_EIGEN_CONST_CAST(M6, mout);
305+
addSkew(
306+
-f.linear(), mout_.template block<3, 3>(ForceDerived::LINEAR, ForceDerived::ANGULAR));
307+
addSkew(
308+
-f.linear(), mout_.template block<3, 3>(ForceDerived::ANGULAR, ForceDerived::LINEAR));
309+
addSkew(
310+
-f.angular(), mout_.template block<3, 3>(ForceDerived::ANGULAR, ForceDerived::ANGULAR));
311+
}
312+
};
313+
314+
template<
315+
typename Scalar,
316+
int Options,
317+
template<typename, int>
318+
class JointCollectionTpl,
319+
typename ConfigVectorType,
320+
typename TangentVectorType1,
321+
typename TangentVectorType2,
322+
typename TangentVectorType3>
323+
const typename DataTpl<Scalar, Options, JointCollectionTpl>::TangentVectorType & passivityRNEA(
324+
const ModelTpl<Scalar, Options, JointCollectionTpl> & model,
325+
DataTpl<Scalar, Options, JointCollectionTpl> & data,
326+
const Eigen::MatrixBase<ConfigVectorType> & q,
327+
const Eigen::MatrixBase<TangentVectorType1> & v,
328+
const Eigen::MatrixBase<TangentVectorType2> & v_r,
329+
const Eigen::MatrixBase<TangentVectorType3> & a_r)
330+
{
331+
assert(model.check(data) && "data is not consistent with model.");
332+
PINOCCHIO_CHECK_ARGUMENT_SIZE(
333+
q.size(), model.nq, "The configuration vector is not of right size");
334+
PINOCCHIO_CHECK_ARGUMENT_SIZE(
335+
v.size(), model.nv, "The velocity vector is not of right size");
336+
PINOCCHIO_CHECK_ARGUMENT_SIZE(
337+
v_r.size(), model.nv, "The auxiliary velocity vector is not of right size");
338+
PINOCCHIO_CHECK_ARGUMENT_SIZE(
339+
a_r.size(), model.nv, "The auxiliary acceleration vector is not of right size");
340+
341+
typedef ModelTpl<Scalar, Options, JointCollectionTpl> Model;
342+
typedef typename Model::JointIndex JointIndex;
343+
344+
data.v[0].setZero();
345+
data.v_r[0].setZero();
346+
data.a_gf[0] = -model.gravity;
347+
348+
typedef PassivityRneaForwardStep<
349+
Scalar, Options, JointCollectionTpl, ConfigVectorType, TangentVectorType1,
350+
TangentVectorType2, TangentVectorType3>
351+
Pass1;
352+
typename Pass1::ArgsType arg1(model, data, q.derived(), v.derived(), v_r.derived(), a_r.derived());
353+
for (JointIndex i = 1; i < (JointIndex)model.njoints; ++i)
354+
{
355+
Pass1::run(model.joints[i], data.joints[i], arg1);
356+
}
357+
358+
typedef RneaBackwardStep<Scalar, Options, JointCollectionTpl> Pass2;
359+
typename Pass2::ArgsType arg2(model, data);
360+
for (JointIndex i = (JointIndex)model.njoints - 1; i > 0; --i)
361+
{
362+
Pass2::run(model.joints[i], data.joints[i], arg2);
363+
}
364+
365+
// Add rotorinertia contribution
366+
data.tau.array() += model.armature.array() * a_r.array(); // Check if there is memory allocation
367+
368+
return data.tau;
369+
}
370+
218371
template<
219372
typename Scalar,
220373
int Options,
@@ -786,6 +939,26 @@ namespace pinocchio
786939
return impl::rnea(model, data, make_const_ref(q), make_const_ref(v), make_const_ref(a), fext);
787940
}
788941

942+
template<
943+
typename Scalar,
944+
int Options,
945+
template<typename, int>
946+
class JointCollectionTpl,
947+
typename ConfigVectorType,
948+
typename TangentVectorType1,
949+
typename TangentVectorType2,
950+
typename TangentVectorType3>
951+
const typename DataTpl<Scalar, Options, JointCollectionTpl>::TangentVectorType & passivityRNEA(
952+
const ModelTpl<Scalar, Options, JointCollectionTpl> & model,
953+
DataTpl<Scalar, Options, JointCollectionTpl> & data,
954+
const Eigen::MatrixBase<ConfigVectorType> & q,
955+
const Eigen::MatrixBase<TangentVectorType1> & v,
956+
const Eigen::MatrixBase<TangentVectorType2> & v_r,
957+
const Eigen::MatrixBase<TangentVectorType3> & a_r)
958+
{
959+
return impl::passivityRNEA(model, data, make_const_ref(q), make_const_ref(v), make_const_ref(v_r), make_const_ref(a_r));
960+
}
961+
789962
template<
790963
typename Scalar,
791964
int Options,

include/pinocchio/algorithm/rnea.txx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,21 @@ namespace pinocchio
3939
const Eigen::MatrixBase<Eigen::Ref<const context::VectorXs>> &,
4040
const container::aligned_vector<context::Force> &);
4141

42+
extern template PINOCCHIO_EXPLICIT_INSTANTIATION_DECLARATION_DLLAPI const context::VectorXs &
43+
passivityRNEA<
44+
context::Scalar,
45+
context::Options,
46+
JointCollectionDefaultTpl,
47+
Eigen::Ref<const context::VectorXs>,
48+
Eigen::Ref<const context::VectorXs>,
49+
Eigen::Ref<const context::VectorXs>>(
50+
const context::Model &,
51+
context::Data &,
52+
const Eigen::MatrixBase<Eigen::Ref<const context::VectorXs>> &,
53+
const Eigen::MatrixBase<Eigen::Ref<const context::VectorXs>> &,
54+
const Eigen::MatrixBase<Eigen::Ref<const context::VectorXs>> &,
55+
const Eigen::MatrixBase<Eigen::Ref<const context::VectorXs>> &);
56+
4257
extern template PINOCCHIO_EXPLICIT_INSTANTIATION_DECLARATION_DLLAPI const context::VectorXs &
4358
nonLinearEffects<
4459
context::Scalar,

include/pinocchio/multibody/data.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ namespace pinocchio
138138
/// \brief Vector of joint velocities expressed in the local frame of the joint.
139139
PINOCCHIO_ALIGNED_STD_VECTOR(Motion) v;
140140

141+
/// \brief Vector of auxiliary joint velocities expressed in the local frame of the joint.
142+
PINOCCHIO_ALIGNED_STD_VECTOR(Motion) v_r;
143+
141144
/// \brief Vector of joint velocities expressed at the origin of the world.
142145
PINOCCHIO_ALIGNED_STD_VECTOR(Motion) ov;
143146

include/pinocchio/multibody/data.hxx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace pinocchio
2626
, a_gf((std::size_t)model.njoints, Motion::Zero())
2727
, oa_gf((std::size_t)model.njoints, Motion::Zero())
2828
, v((std::size_t)model.njoints, Motion::Zero())
29+
, v_r((std::size_t)model.njoints, Motion::Zero())
2930
, ov((std::size_t)model.njoints, Motion::Zero())
3031
, f((std::size_t)model.njoints, Force::Zero())
3132
, of((std::size_t)model.njoints, Force::Zero())
@@ -276,7 +277,7 @@ namespace pinocchio
276277
bool value =
277278
data1.joints == data2.joints && data1.a == data2.a && data1.oa == data2.oa
278279
&& data1.oa_drift == data2.oa_drift && data1.oa_augmented == data2.oa_augmented
279-
&& data1.a_gf == data2.a_gf && data1.oa_gf == data2.oa_gf && data1.v == data2.v
280+
&& data1.a_gf == data2.a_gf && data1.oa_gf == data2.oa_gf && data1.v == data2.v && data1.v_r == data2.v_r
280281
&& data1.ov == data2.ov && data1.f == data2.f && data1.of == data2.of
281282
&& data1.of_augmented == data2.of_augmented && data1.h == data2.h && data1.oh == data2.oh
282283
&& data1.oMi == data2.oMi && data1.liMi == data2.liMi && data1.tau == data2.tau

include/pinocchio/serialization/data.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ namespace boost
3939
PINOCCHIO_MAKE_DATA_NVP(ar, data, a_gf);
4040
PINOCCHIO_MAKE_DATA_NVP(ar, data, oa_gf);
4141
PINOCCHIO_MAKE_DATA_NVP(ar, data, v);
42+
PINOCCHIO_MAKE_DATA_NVP(ar, data, v_r);
4243
PINOCCHIO_MAKE_DATA_NVP(ar, data, ov);
4344
PINOCCHIO_MAKE_DATA_NVP(ar, data, f);
4445
PINOCCHIO_MAKE_DATA_NVP(ar, data, of);

src/algorithm/rnea.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,21 @@ namespace pinocchio
3636
const Eigen::MatrixBase<Eigen::Ref<const context::VectorXs>> &,
3737
const container::aligned_vector<context::Force> &);
3838

39+
template PINOCCHIO_EXPLICIT_INSTANTIATION_DEFINITION_DLLAPI const context::VectorXs & passivityRNEA<
40+
context::Scalar,
41+
context::Options,
42+
JointCollectionDefaultTpl,
43+
Eigen::Ref<const context::VectorXs>,
44+
Eigen::Ref<const context::VectorXs>,
45+
Eigen::Ref<const context::VectorXs>,
46+
Eigen::Ref<const context::VectorXs>>(
47+
const context::Model &,
48+
context::Data &,
49+
const Eigen::MatrixBase<Eigen::Ref<const context::VectorXs>> &,
50+
const Eigen::MatrixBase<Eigen::Ref<const context::VectorXs>> &,
51+
const Eigen::MatrixBase<Eigen::Ref<const context::VectorXs>> &,
52+
const Eigen::MatrixBase<Eigen::Ref<const context::VectorXs>> &);
53+
3954
template PINOCCHIO_EXPLICIT_INSTANTIATION_DEFINITION_DLLAPI const context::VectorXs &
4055
nonLinearEffects<
4156
context::Scalar,

unittest/rnea.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,4 +344,57 @@ BOOST_AUTO_TEST_CASE(test_compute_coriolis)
344344
}
345345
}
346346

347+
BOOST_AUTO_TEST_CASE(test_passivityrnea_vs_rnea)
348+
{
349+
using namespace Eigen;
350+
using namespace pinocchio;
351+
352+
pinocchio::Model model;
353+
buildModels::humanoidRandom(model);
354+
355+
model.lowerPositionLimit.head<3>().fill(-1.);
356+
model.upperPositionLimit.head<3>().fill(1.);
357+
358+
pinocchio::Data data_passivityrnea(model);
359+
pinocchio::Data data_rnea(model);
360+
361+
VectorXd q = randomConfiguration(model);
362+
VectorXd v = VectorXd::Random(model.nv);
363+
VectorXd a = VectorXd::Random(model.nv);
364+
365+
VectorXd tau_passivityrnea = passivityRNEA(model, data_passivityrnea, q, v, v, a);
366+
VectorXd tau_rnea = rnea(model, data_rnea, q, v, a);
367+
368+
BOOST_CHECK(tau_passivityrnea.isApprox(tau_rnea, 1e-12));
369+
}
370+
371+
BOOST_AUTO_TEST_CASE(test_passivityrnea_compute_coriolis)
372+
{
373+
using namespace Eigen;
374+
using namespace pinocchio;
375+
376+
const double prec = Eigen::NumTraits<double>::dummy_precision();
377+
378+
Model model;
379+
buildModels::humanoidRandom(model);
380+
381+
model.lowerPositionLimit.head<3>().fill(-1.);
382+
model.upperPositionLimit.head<3>().fill(1.);
383+
model.gravity.setZero();
384+
385+
Data data_ref(model);
386+
Data data(model);
387+
388+
VectorXd q = randomConfiguration(model);
389+
390+
VectorXd v(VectorXd::Random(model.nv));
391+
computeCoriolisMatrix(model, data, q, v);
392+
393+
VectorXd v_r(VectorXd::Random(model.nv));
394+
passivityRNEA(model, data_ref, q, v, v_r, VectorXd::Zero(model.nv));
395+
396+
VectorXd tau = data.C * v_r;
397+
BOOST_CHECK(tau.isApprox(data_ref.tau, prec));
398+
}
399+
347400
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)