Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend Support for Mimic Joint #2441

Open
wants to merge 258 commits into
base: devel
Choose a base branch
from
Open

Conversation

MegMll
Copy link
Collaborator

@MegMll MegMll commented Sep 30, 2024

Overview

This PR enhances support for the mimic joint.
Mimic joint refer to a joint which configuration depends on the configuration of another joint (that we named the primary joint). The relation is $q_{mimic} = \alpha * q_{primary} + \beta$ (where $\alpha, \beta$ are defined by the user)

Key Updates:

URDF Parsing:

The mimic tag can now be parsed from urdf, and add the corresponding mimic joint to the model.
A mimic flag has been added to the parser to enable this feature or not (default to false) in order to preserve backward compatibility.

Robot and Joint Model Modifications:

  • The already existing mimic joint type has been update to allow support in more algorithms.
    • The main change being that instead of being templated on the primary joint type, the mimic joint now holds a variant of joint for the primary.
  • The robot and joint nq and nv (resp. idx_q, idx_v) values have now been extended with a nvExtended (resp idx_vExtended) value, holding the dimension of the extended robot/joint tangeant space. (for all classical joint nv==nvExtened but for mimic nv==0 and nvExtended==primary.nvExtended). The suffix vExtended stand for Jacobian as those values are mainly used for computing jacobians rows and columns.

Features of the joint mimic:

Joint

Not all the joints are able to be mimicked. Please see the following list for the joints that can be mimicked:
- Prismatics
- Revolutes
- Helicoidals
Please also note that the mimic joint must be after its primary (i.e. id_mimicking > id_mimicked) in the kinematic tree for it to be created in pinocchio. If that's not the case, the model will not be created.

Algorithms

The following algorithms support the new joint mimic :
- RNEA
- CRBA
- Forward Kinematics
- Jacobians and Frames
- Centroidal Algorithm (ccrba)
- Reachable Workspace

Testing & Validation:

  • Added unit tests to validate mimic joint support for all the above algorithms.
  • Verified URDF parsing for different robot models that include mimic joints.

Limitations:

  • Algorithms such as ABA, or any derivatives are not supported and should trigger asserts.
  • Currently, the mimic joint should always be after the primary joint (i.e. id_mimicking > id_mimicked) in the kinematic tree. (assert is triggered if not)

Feedback Needed:

The naming of the new member variable and functions is pretty arbitrary, we are eager to change them to better suit pinocchio naming standards.
Non exhaustively, here are a list of the lesser quality one (that should most probably be renamed) :

  • idx_j/nj : representing the dimension and index in the "extended model"
  • jointCols, jointRows, etc method has been split into jointVelCols and jointJacCols (respectively if they refer to idx_v/nv or idx_j/nj)
  • Similarly jointConfigSelector was splitted into jointConfigFromDofSelector and jointConfigFromNqSelector to meet the need for mimic joint to select config either from the parent joint or don't select anything
  • Similarly jointVelocitySelector was splitted into jointVelocityFromDofSelector and jointConfigFromNqSelector to meet the need for mimic joint to select config either from the parent joint or don't select anything

Next

Non linear mimic support

We can add a functor to JointModelMimicTpl constructor argument. This functor will hold the functon to apply to the config and velocity vectors.

This can be added latter as:

  • a new JointModelMimicTpl template argument set with a default value
  • a std::function stored in JointModelMimicTpl

The latter options is less effective.
In both case, this will avoid a call to a visitor, since the configVectorAffineTransform can be solved at the JointModelMimmicTpl construction.

Special Thanks:

A special thank you to @EtienneAr for his guidance and advice throughout this development process.

Current TODO list

Following our IRL meeting, here is the todo list:

  • Refactor the translateJacobian to prevent performance drop (due to nested for loops and visitor call increase)
  • Make sure the API (C++ & Python) is not broken by this PR (i.e. check that the non-mimic test did not change)
  • Add a check "model has mimic" in robot model to factorize code, and use that check in algorithms
  • Double check the necessity of the SE3 static_cast
  • Add specific check for mimic in check.hxx (instead of just skipping with an if) (@MegMll)
  • Revert all changes in unsupported algo
  • Rename nj, idx_j -> nv_extended, idx_v_extended
  • Make sure that jcalc is easily upgradable for non linear mimic (withoput API break)
  • Edit this PR to list more limitations of this feature: Which joints type are mimickable, what are the contraints on the joint ids
  • setIndexes to fix (@jorisv)
  • Old MimicJoint API: see if we can keep the same major @jcarpent
  • getRelativePlacement: ask to @jcarpent if we keep it
  • Use extended instead of full in the documentation (@MegMll)
  • Add ConfigVectorAffineTransform in helical joints (@jorisv)
    • Check in all joint if we need to add or not a ConfigVectorAffineTransform specialization
  • NoAffine transform must assert
  • Don't use mutable in JointDataMimicTpl accessors (@jorisv)
  • Nice JointModelMimicTpl and JointDataMimicTpl cout
  • Improve JointModelMimicTpl doc and comment
  • Store JointModelMimicTpl::m_jmodel_ref nq and nv to avoid visitor call
  • Rename JointModelMimicTpl::m_jmodel_ref into m_jmodel_mimicking
  • Check dIntegrate with @jcarpent
  • We can use nvExtended instead of nv in data.hpp since algorithm that doesn't support nvExtended will raise an exception
    • Update checkData to use the new size
  • Fix serialization issue (@MegMll)
  • Fix cast issue (@MegMll)
  • Fix reduce model issue (@MegMll)
  • Impove changelog
  • Fix setIndexes (@MegMll)
  • Update urdf parsing
  • Check the jointConfig/jointVelocitySelector (maybe some are badly named or missing)
  • Add Workspace as supported algorithm (and use mimic model in workspace unit test)
  • Add TU for double mimic in a model (primary different and same primary)
  • Modify CRBA
  • Modify Jacobian algorithms
  • Modify Serialization of Mimic Data (probably missig some infos)
  • Add vector of joint index to keep track of mimic joints to model (serialize and bind it)
  • Add pairs of common ancestors for mimic joint and its primary joint in model (serialize and bind it)
  • Check buildReducedModel et AppendModel with new model attributes
  • Throw an exception in Python binding if the algorithm doesn't support mimic
    ...

The following point are Nice To Have and should be addressed in separate issues / PRs:

  • Function to go from "Reduced" mimic model to full "extended" model
  • Store extra data in robot model/data to speed up so algo
  • Make proper safe/unsafe function for every algo to check (or not) input parameters, for performance issues and to be able to check for python bindings
  • Function that give the constraint matrix from a "Reduced" mimic model

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👋 Hi,
This is a reminder message to assign an extra build label to this Pull Request if needed.
By default, this PR will be build with minimal build options (URDF support and Python bindings)
The possible extra labels are:

  • build_collision (build Pinocchio with coal support)
  • build_casadi (build Pinocchio with CasADi support)
  • build_autodiff (build Pinocchio with CppAD support)
  • build_codegen (build Pinocchio with CppADCodeGen support)
  • build_extra (build Pinocchio with extra algorithms)
  • build_mpfr (build Pinocchio with Boost.Multiprecision support)
  • build_sdf (build Pinocchio with SDF parser)
  • build_accelerate (build Pinocchio with APPLE Accelerate framework support)
  • build_all (build Pinocchio with ALL the options stated above)

Thanks.
The Pinocchio development team.

Copy link
Contributor

@jcarpent jcarpent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will provide a detailed review later.

@abussy-aldebaran
Copy link
Contributor

Hi,

I started using mimic joints, so I'm following this PR with interest !
I tested this branch with forward and inverse kinematics (with pseudo-inverses of the Jacobians), and it seems to work fine 👍

How/Where can I report any bug I find ?
I'll try to add MREs as unittests. For instance, I found : abussy-aldebaran@5a8f205

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could add typedef for mimic joints ?

typedef JointModelMimicTpl<Scalar, Options, JointCollectionTpl> JointModelMimic;
typedef JointDataMimicTpl<Scalar, Options, JointCollectionTpl> JointDataMimic;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why ? There is no joint typedef in model.hpp

res.setIndexes(id(), idx_q(), idx_v());
m_jmodel_ref.template cast<NewScalar>(), ScalarCast<NewScalar, Scalar>::cast(m_scaling),
ScalarCast<NewScalar, Scalar>::cast(m_offset));
res.setIndexes(id(), idx_q(), idx_v(), idx_j());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't a setMimicIndices missing ?
See abussy-aldebaran@5a8f205
and abussy-aldebaran@afef317

@MegMll MegMll force-pushed the topic/mimic branch 2 times, most recently from bd466b3 to b90f6e0 Compare December 16, 2024 10:39
@MegMll
Copy link
Collaborator Author

MegMll commented Dec 16, 2024

Hi,

I started using mimic joints, so I'm following this PR with interest ! I tested this branch with forward and inverse kinematics (with pseudo-inverses of the Jacobians), and it seems to work fine 👍

How/Where can I report any bug I find ? I'll try to add MREs as unittests. For instance, I found : abussy-aldebaran@5a8f205

Hi,

Thanks a lot for your interest in this PR, ! In order to simplify the PR and the review process, if you want to add new unittests, please do it directly on this branch.

If you don't feel confortable with this solution, we'll find another way.

As for bugs, please add comments here, and we'll take a look at it.

Thanks again !

@abussy-aldebaran
Copy link
Contributor

In order to simplify the PR and the review process, if you want to add new unittests, please do it directly on this branch.

What do you mean ? Opening a PR in your forked repository ?

@MegMll MegMll force-pushed the topic/mimic branch 2 times, most recently from ea956c8 to 083d240 Compare January 10, 2025 10:04
include/pinocchio/algorithm/rnea.hxx Show resolved Hide resolved
include/pinocchio/algorithm/rnea.hxx Show resolved Hide resolved
include/pinocchio/algorithm/rnea.hxx Show resolved Hide resolved
include/pinocchio/algorithm/rnea.hxx Show resolved Hide resolved
include/pinocchio/algorithm/rnea.hxx Show resolved Hide resolved
include/pinocchio/algorithm/rnea.hxx Show resolved Hide resolved
include/pinocchio/algorithm/rnea.hxx Show resolved Hide resolved
include/pinocchio/algorithm/rnea.hxx Show resolved Hide resolved
include/pinocchio/algorithm/rnea.hxx Show resolved Hide resolved
@@ -149,6 +149,7 @@ namespace pinocchio
PINOCCHIO_CHECK_ARGUMENT_SIZE(Jout.rows(), 6);

Matrix6xLikeOut & Jout_ = Jout.const_cast_derived();
Jout_.setZero();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why setZero here ? It should be done in the part that will do a +=.

@@ -324,6 +324,10 @@ namespace pinocchio
/// \brief End index of the Joint motion subspace
std::vector<int> end_idx_v_fromRow;

/// \brief Extended model mapping of the joint rows (idx_v_extended_fromRow[idx_v_extended] =
/// idx_v)
std::vector<int> idx_v_extended_fromRow;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be named idx_v_fromRow.


v_out = v_in;
v_out += v_in;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like for CRBA, the += can hurt performances. So it should be done in a dedicated for loop.

@@ -319,7 +325,7 @@ namespace pinocchio
data.iMf[parent] = data.liMi[i] * data.iMf[i];

Matrix6xLike & J_ = J.const_cast_derived();
jmodel.jointCols(J_) = data.iMf[i].actInv(jdata.S());
jmodel.jointCols(J_) += data.iMf[i].actInv(jdata.S());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, we should add a second step in computeJointJacobian to avoid the +=.

@@ -83,6 +83,22 @@ namespace pinocchio
return bp::make_tuple(ancestor_id, index_ancestor_in_support1, index_ancestor_in_support2);
}

template<typename Scalar, int Options, template<typename, int> class JointCollectionTpl>
ModelTpl<Scalar, Options, JointCollectionTpl> transformJointIntoMimic(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use the same pattern as findCommonAncestor_proxy, this avoid to specify the full signature in the definition.

bp::def(
"transformJointIntoMimic",
(Model(*)(
const Model &, const JointIndex &, const JointIndex &, const double &, const double &))(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use transformJointIntoMimic_proxy to note specify the full signature

bindings/python/parsers/urdf/model.cpp Outdated Show resolved Hide resolved
@@ -193,6 +193,32 @@ namespace pinocchio
PINOCCHIO_EIGEN_CONST_CAST(Matrix6Type, I), update_I));
}

template<typename InputType, typename ReturnType>
struct jointConfigExtendedModelSelectorVisitor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jointConfigExtendedModelSelectorVisitor => JointConfigExtendedModelSelectorVisitor

include/pinocchio/parsers/urdf.hpp Outdated Show resolved Hide resolved
{
return buildModel(filename, rootJoint, "root_joint", model, verbose);
return buildModel(filename, rootJoint, "root_joint", model, mimic, verbose);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return buildModel(filename, rootJoint, "root_joint", model, mimic, verbose);
return buildModel(filename, rootJoint, "root_joint", model, verbose, mimic);

Be careful, this error is in a lot of place

Comment on lines +339 to +340
// ar & make_nvp("base_class",base_object< pinocchio::JointModelBase<JointType>
// >(joint));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this dead code.

@@ -83,6 +83,22 @@ namespace pinocchio
return bp::make_tuple(ancestor_id, index_ancestor_in_support1, index_ancestor_in_support2);
}

template<typename Scalar, int Options, template<typename, int> class JointCollectionTpl>
ModelTpl<Scalar, Options, JointCollectionTpl> transformJointIntoMimic_proxy(
const ModelTpl<Scalar, Options, JointCollectionTpl> & input_model,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can simplify (like findCommonAncestor) by using context::Model.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transform mimic cannot take context, because it's not cppad compatible

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of some equality tests ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not have time to investigate, it just won't compile, and since it's in a file with the PINOCCHIO_SKIP_ALGORITHM define, i just thought it made sense to use double.

If we want it with casadi and autodiff, i can add it to the todo list

@@ -290,7 +291,7 @@ struct TestADOnJoints
void operator()(const pinocchio::JointModelBase<JointModel_> &) const
{
JointModel_ jmodel = init<JointModel_>::run();
jmodel.setIndexes(0, 0, 0);
// jmodel.setIndexes(0, 0, 0, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove dead code

static void test(const pinocchio::JointModelMimic<JointModel_> & /*jmodel*/)
template<typename Scalar, int Options, template<typename, int> class JointCollection>
static void
test(const pinocchio::JointModelMimicTpl<Scalar, Options, JointCollection> & /*jmodel*/)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mimic joint are not working with casadi ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We did the same test as for joint composite

Comment on lines -112 to +130
template<class JointModel>
struct buildModel<JointModelMimic<JointModel>>
{
typedef JointModelMimic<JointModel> JointModel_;
// template<class JointModel>
// struct buildModel<JointModelMimic<JointModel>>
// {
// typedef JointModelMimic<JointModel> JointModel_;

static Model run(const JointModel_ & jmodel)
{
Model model;
model.addJoint(0, jmodel.jmodel(), SE3::Identity(), "joint");
model.addJoint(0, jmodel, SE3::Identity(), "joint_mimic");
// static Model run(const JointModel_ & jmodel)
// {
// Model model;
// model.addJoint(0, jmodel.jmodel(), SE3::Identity(), "joint");
// model.addJoint(0, jmodel, SE3::Identity(), "joint_mimic");

return model;
}
};
// return model;
// }
// };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this code is not used anymore, delete it.

@@ -429,7 +440,7 @@ struct TestJointConstraint
void operator()(const JointModelBase<JointModel> &) const
{
JointModel jmodel = init<JointModel>::run();
jmodel.setIndexes(0, 0, 0);
// jmodel.setIndexes(0, 0, 0, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No dead code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add a test with a mimic joint (like for crba, create the extended model and compare with the mimic one)

}

BOOST_AUTO_TEST_CASE(build_model_sample_manipulator)
{
pinocchio::Model model;
pinocchio::buildModels::manipulator(model);
pinocchio::buildModels::manipulator(model, true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like for humanoid random, keep the test without mimic.

@@ -67,4 +100,71 @@ BOOST_AUTO_TEST_CASE(build_model_sample_humanoid)
* direct geometry with respect to reference values. */
}

BOOST_AUTO_TEST_CASE(compare_mimic)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get the purpose of this test.
It test RNEA, CRBA, nonLinearEffect, forwardKinematics. But these test should already be done in the rnea, crba and kinematics test file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants