Skip to content

Commit

Permalink
generalized enum + added unittest + updated force computation + corre…
Browse files Browse the repository at this point in the history
…cted mistakes in contact1d calcdiff transformations
  • Loading branch information
skleff1994 committed Mar 31, 2022
1 parent fd58261 commit 1fecfb4
Show file tree
Hide file tree
Showing 8 changed files with 503 additions and 32 deletions.
12 changes: 6 additions & 6 deletions bindings/python/crocoddyl/multibody/contacts/contact-1d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ namespace python {
void exposeContact1D() {
bp::register_ptr_to_python<boost::shared_ptr<ContactModel1D> >();

bp::enum_<Contact1DMaskType>("Contact1DMaskType")
.value("X_MASK", X_MASK)
.value("Y_MASK", Y_MASK)
.value("Z_MASK", Z_MASK)
bp::enum_<Vector3MaskType>("Vector3MaskType")
.value("x", x)
.value("y", y)
.value("z", z)
.export_values();

bp::class_<ContactModel1D, bp::bases<ContactModelAbstract> >(
Expand All @@ -29,15 +29,15 @@ void exposeContact1D() {
"The calc and calcDiff functions compute the contact Jacobian and drift (holonomic constraint) or\n"
"the derivatives of the holonomic constraint, respectively.",
bp::init<boost::shared_ptr<StateMultibody>, pinocchio::FrameIndex, double, std::size_t,
bp::optional<Eigen::Vector2d, Contact1DMaskType, pinocchio::ReferenceFrame> >(
bp::optional<Eigen::Vector2d, Vector3MaskType, pinocchio::ReferenceFrame> >(
bp::args("self", "state", "id", "xref", "nu", "gains", "mask", "type"),
"Initialize the contact model.\n\n"
":param state: state of the multibody system\n"
":param id: reference frame id of the contact\n"
":param xref: contact position used for the Baumgarte stabilization\n"
":param nu: dimension of control vector\n"
":param gains: gains of the contact model (default np.matrix([0.,0.]))\n"
":param mask: axis of the contact constraint (0=x, 1=y or 2=z)\n"
":param mask: axis of the contact constraint (default z)\n"
":param type: reference type of contact"))
.def(bp::init<boost::shared_ptr<StateMultibody>, pinocchio::FrameIndex, double,
bp::optional<Eigen::Vector2d, pinocchio::ReferenceFrame> >(
Expand Down
26 changes: 18 additions & 8 deletions include/crocoddyl/multibody/contacts/contact-1d.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

namespace crocoddyl {

enum Contact1DMaskType { X_MASK = 0, Y_MASK = 1, Z_MASK = 2 };
enum Vector3MaskType { x = 0, y = 1, z = 2 };

template <typename _Scalar>
class ContactModel1DTpl : public ContactModelAbstractTpl<_Scalar> {
Expand All @@ -39,7 +39,7 @@ class ContactModel1DTpl : public ContactModelAbstractTpl<_Scalar> {
typedef typename MathBase::Vector3s Vector3s;
typedef typename MathBase::VectorXs VectorXs;
typedef typename MathBase::Matrix3s Matrix3s;

typedef typename MathBase::Matrix6s Matrix6s;
/**
* @brief Initialize the 1d contact model
*
Expand All @@ -48,12 +48,12 @@ class ContactModel1DTpl : public ContactModelAbstractTpl<_Scalar> {
* @param[in] xref Contact position used for the Baumgarte stabilization
* @param[in] nu Dimension of the control vector
* @param[in] gains Baumgarte stabilization gains
* @param[in] mask Constraint 1D axis
* @param[in] mask Constraint 1D axis (default z)
* @param[in] ref Reference type of contact
*/
ContactModel1DTpl(boost::shared_ptr<StateMultibody> state, const pinocchio::FrameIndex id, const Scalar xref,
const std::size_t nu, const Vector2s& gains = Vector2s::Zero(),
const Contact1DMaskType& mask = Z_MASK, const pinocchio::ReferenceFrame ref = pinocchio::LOCAL);
const Vector3MaskType& mask = Vector3MaskType::z, const pinocchio::ReferenceFrame ref = pinocchio::LOCAL);

/**
* @brief Initialize the 1d contact model
Expand Down Expand Up @@ -130,12 +130,12 @@ class ContactModel1DTpl : public ContactModelAbstractTpl<_Scalar> {
/**
* @brief Modify contact 1D mask
*/
void set_mask(const Contact1DMaskType mask);
void set_mask(const Vector3MaskType mask);

/**
* @brief Get contact 1D mask
*/
const Contact1DMaskType get_mask() const;
const Vector3MaskType get_mask() const;

/**
* @brief Print relevant information of the 1d contact model
Expand All @@ -153,7 +153,7 @@ class ContactModel1DTpl : public ContactModelAbstractTpl<_Scalar> {
private:
Scalar xref_; //!< Contact position used for the Baumgarte stabilization
Vector2s gains_; //!< Baumgarte stabilization gains
Contact1DMaskType mask_; //!< Axis of the 1D contact in (x,y,z)
Vector3MaskType mask_; //!< Axis of the 1D contact in (x,y,z)
pinocchio::ReferenceFrame type_; //!< Reference type of contact
};

Expand Down Expand Up @@ -182,7 +182,7 @@ struct ContactData1DTpl : public ContactDataAbstractTpl<_Scalar> {
fXjda_dv(6, model->get_state()->get_nv()) {
frame = model->get_id();
jMf = model->get_state()->get_pinocchio()->frames[frame].placement;
fXj = jMf.inverse().toActionMatrix();
fXj = pinocchio::SE3::Identity().toActionMatrix(); //jMf.inverse().toActionMatrix();
fJf.setZero();
v_partial_dq.setZero();
a_partial_dq.setZero();
Expand All @@ -196,6 +196,11 @@ struct ContactData1DTpl : public ContactDataAbstractTpl<_Scalar> {
vv_skew.setZero();
vw_skew.setZero();
oRf.setZero();
type = model->get_type();
mask = model->get_mask();
jMc_ = pinocchio::SE3::Identity();
wMlwa_ = pinocchio::SE3::Identity();
lwaMj_ = pinocchio::SE3::Identity();
}

using Base::a0;
Expand Down Expand Up @@ -224,6 +229,11 @@ struct ContactData1DTpl : public ContactDataAbstractTpl<_Scalar> {
Matrix3s vv_skew;
Matrix3s vw_skew;
Matrix2s oRf;
pinocchio::ReferenceFrame type;
Vector3MaskType mask;
pinocchio::SE3 jMc_;
pinocchio::SE3 wMlwa_;
pinocchio::SE3 lwaMj_;
};

} // namespace crocoddyl
Expand Down
37 changes: 21 additions & 16 deletions include/crocoddyl/multibody/contacts/contact-1d.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,17 @@ namespace crocoddyl {
template <typename Scalar>
ContactModel1DTpl<Scalar>::ContactModel1DTpl(boost::shared_ptr<StateMultibody> state, const pinocchio::FrameIndex id,
const Scalar xref, const std::size_t nu, const Vector2s& gains,
const Contact1DMaskType& mask, const pinocchio::ReferenceFrame type)
const Vector3MaskType& mask, const pinocchio::ReferenceFrame type)
: Base(state, 1, nu), xref_(xref), gains_(gains), mask_(mask), type_(type) {
id_ = id;
if (mask_ < 0 || mask_ > 2) {
throw_pretty("Invalid argument: "
<< "Contact1D mask must be in {0,1,2} for {x,y,z}");
}
}

template <typename Scalar>
ContactModel1DTpl<Scalar>::ContactModel1DTpl(boost::shared_ptr<StateMultibody> state, const pinocchio::FrameIndex id,
const Scalar xref, const Vector2s& gains,
const pinocchio::ReferenceFrame type)
: Base(state, 1), xref_(xref), gains_(gains), type_(type) {
: Base(state, 1), xref_(xref), gains_(gains), type_(type), mask_(Vector3MaskType::z) {
id_ = id;
// Default mask is z
mask_ = Z_MASK;
}

template <typename Scalar>
Expand Down Expand Up @@ -69,6 +63,17 @@ void ContactModel1DTpl<Scalar>::calcDiff(const boost::shared_ptr<ContactDataAbst
const std::size_t nv = state_->get_nv();
pinocchio::skew(d->vv, d->vv_skew);
pinocchio::skew(d->vw, d->vw_skew);
// Matrix6s fXj;
if (type_ == pinocchio::LOCAL){
d->fXj = d->jMf.inverse().toActionMatrix();
}
else if (type_ == pinocchio::WORLD) {
d->fXj = d->fXj;
}
else if (type_ == pinocchio::LOCAL_WORLD_ALIGNED) {
d->lwaMj_.translation(d->jMf.inverse().translation());
d->fXj = d->lwaMj_.toActionMatrix();
}
d->fXjdv_dq.noalias() = d->fXj * d->v_partial_dq;
d->fXjda_dq.noalias() = d->fXj * d->a_partial_dq;
d->fXjda_dv.noalias() = d->fXj * d->a_partial_dv;
Expand Down Expand Up @@ -100,23 +105,23 @@ void ContactModel1DTpl<Scalar>::updateForce(const boost::shared_ptr<ContactDataA
<< "lambda has wrong dimension (it should be 1)");
}
Data* d = static_cast<Data*>(data.get());
pinocchio::SE3 jMc;
switch (type_) {
case pinocchio::LOCAL: {
jMc = d->jMf;
d->jMc_ = d->jMf;
break;
}
case pinocchio::WORLD: {
jMc = d->jMf.act(d->pinocchio->oMf[id_].inverse());
d->jMc_ = d->jMf.act(d->pinocchio->oMf[id_].inverse());
break;
}
case pinocchio::LOCAL_WORLD_ALIGNED: {
jMc = pinocchio::SE3(Matrix3s::Identity(), d->jMf.translation());
d->wMlwa_.translation(d->pinocchio->oMf[id_].translation());
d->jMc_ = d->jMf.act(d->pinocchio->oMf[id_].actInv(d->wMlwa_));
break;
}
}
data->f.linear() = jMc.rotation().col(mask_) * force[0];
data->f.angular() = jMc.translation().cross(data->f.linear());
data->f.linear() = d->jMc_.rotation().col(mask_) * force[0];
data->f.angular() = d->jMc_.translation().cross(data->f.linear());
}

template <typename Scalar>
Expand Down Expand Up @@ -156,12 +161,12 @@ const pinocchio::ReferenceFrame ContactModel1DTpl<Scalar>::get_type() const {
}

template <typename Scalar>
void ContactModel1DTpl<Scalar>::set_mask(const Contact1DMaskType mask) {
void ContactModel1DTpl<Scalar>::set_mask(const Vector3MaskType mask) {
mask_ = mask;
}

template <typename Scalar>
const Contact1DMaskType ContactModel1DTpl<Scalar>::get_mask() const {
const Vector3MaskType ContactModel1DTpl<Scalar>::get_mask() const {
return mask_;
}

Expand Down
15 changes: 13 additions & 2 deletions include/crocoddyl/multibody/residuals/contact-force.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,20 @@ void ResidualModelContactForceTpl<Scalar>::calc(const boost::shared_ptr<Residual

// We transform the force to the contact frame
switch (d->contact_type) {
case Contact1D:
data->r = ((d->contact->jMf.actInv(d->contact->f) - fref_).linear()).row(2);
case Contact1D:{
ContactData1DTpl<Scalar>* d1d = static_cast<ContactData1DTpl<Scalar>*>(d->contact.get());
if(d1d->type == pinocchio::LOCAL){
data->r = ((d->contact->jMf.actInv(d->contact->f) - fref_).linear()).row(d1d->mask);
}
else if(d1d->type == pinocchio::WORLD) {
data->r = ((d->contact->pinocchio->oMf[id_].act(d->contact->jMf.actInv(d->contact->f)) - fref_).linear()).row(d1d->mask);
}
else if(d1d->type == pinocchio::LOCAL_WORLD_ALIGNED) {
d1d->wMlwa_.translation_impl(d->contact->pinocchio->oMf[id_].translation());
data->r = (( d1d->wMlwa_.actInv( d->contact->pinocchio->oMf[id_].act(d->contact->jMf.inverse()) ).act(d->contact->f) - fref_).linear()).row(d1d->mask);
}
break;
}
case Contact3D:
data->r = (d->contact->jMf.actInv(d->contact->f) - fref_).linear();
break;
Expand Down
1 change: 1 addition & 0 deletions unittest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ SET(${PROJECT_NAME}_CPP_TESTS
test_costs_collision
test_cost_sum
test_contacts
test_contact1d
test_controls
test_impulses
test_multiple_contacts
Expand Down
141 changes: 141 additions & 0 deletions unittest/factory/contact1d.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
///////////////////////////////////////////////////////////////////////////////
// BSD 3-Clause License
//
// Copyright (C) 2019-2021, University of Edinburgh
// Copyright note valid unless otherwise stated in individual files.
// All rights reserved.
///////////////////////////////////////////////////////////////////////////////

#include "contact1d.hpp"
#include "crocoddyl/multibody/contacts/contact-1d.hpp"
#include "crocoddyl/core/utils/exception.hpp"

namespace crocoddyl {
namespace unittest {

const std::vector<ContactModelMaskTypes::Type> ContactModelMaskTypes::all(ContactModelMaskTypes::init_all());

const std::vector<PinocchioReferenceTypes::Type> PinocchioReferenceTypes::all(PinocchioReferenceTypes::init_all());

std::ostream& operator<<(std::ostream& os, const ContactModelMaskTypes::Type& type) {
switch (type) {
case ContactModelMaskTypes::X:
os << "X";
break;
case ContactModelMaskTypes::Y:
os << "Y";
break;
case ContactModelMaskTypes::Z:
os << "Z";
break;
case ContactModelMaskTypes::NbMaskTypes:
os << "NbMaskTypes";
break;
default:
os << "Unknown type";
break;
}
return os;
}

std::ostream& operator<<(std::ostream& os, const PinocchioReferenceTypes::Type& type) {
switch (type) {
case PinocchioReferenceTypes::LOCAL:
os << "LOCAL";
break;
case PinocchioReferenceTypes::WORLD:
os << "WORLD";
break;
case PinocchioReferenceTypes::LOCAL_WORLD_ALIGNED:
os << "LOCAL_WORLD_ALIGNED";
break;
case PinocchioReferenceTypes::NbPinRefTypes:
os << "NbPinRefTypes";
break;
default:
os << "Unknown type";
break;
}
return os;
}

ContactModel1DFactory::ContactModel1DFactory() {}
ContactModel1DFactory::~ContactModel1DFactory() {}

boost::shared_ptr<crocoddyl::ContactModelAbstract> ContactModel1DFactory::create(ContactModelMaskTypes::Type mask_type,
PinocchioModelTypes::Type model_type,
PinocchioReferenceTypes::Type reference_type,
const std::string frame_name,
std::size_t nu) const {
PinocchioModelFactory model_factory(model_type);
boost::shared_ptr<crocoddyl::StateMultibody> state =
boost::make_shared<crocoddyl::StateMultibody>(model_factory.create());
boost::shared_ptr<crocoddyl::ContactModelAbstract> contact;
std::size_t frame_id = 0;
if (frame_name == "") {
frame_id = model_factory.get_frame_id();
} else {
frame_id = state->get_pinocchio()->getFrameId(frame_name);
}
if (nu == std::numeric_limits<std::size_t>::max()) {
nu = state->get_nv();
}

Eigen::Vector2d gains = Eigen::Vector2d::Zero();
switch (mask_type) {
case ContactModelMaskTypes::X: {
if(reference_type == PinocchioReferenceTypes::LOCAL){
contact = boost::make_shared<crocoddyl::ContactModel1D>(state, frame_id, 0., nu, gains, Vector3MaskType::x, pinocchio::LOCAL);
} else if(reference_type == PinocchioReferenceTypes::WORLD){
contact = boost::make_shared<crocoddyl::ContactModel1D>(state, frame_id, 0., nu, gains, Vector3MaskType::x, pinocchio::WORLD);
} else if(reference_type == PinocchioReferenceTypes::LOCAL_WORLD_ALIGNED){
contact = boost::make_shared<crocoddyl::ContactModel1D>(state, frame_id, 0., nu, gains, Vector3MaskType::x, pinocchio::LOCAL_WORLD_ALIGNED);
}
break;
}
case ContactModelMaskTypes::Y: {
if(reference_type == PinocchioReferenceTypes::LOCAL){
contact = boost::make_shared<crocoddyl::ContactModel1D>(state, frame_id, 0., nu, gains, Vector3MaskType::y, pinocchio::LOCAL);
} else if(reference_type == PinocchioReferenceTypes::WORLD){
contact = boost::make_shared<crocoddyl::ContactModel1D>(state, frame_id, 0., nu, gains, Vector3MaskType::y, pinocchio::WORLD);
} else if(reference_type == PinocchioReferenceTypes::LOCAL_WORLD_ALIGNED){
contact = boost::make_shared<crocoddyl::ContactModel1D>(state, frame_id, 0., nu, gains, Vector3MaskType::y, pinocchio::LOCAL_WORLD_ALIGNED);
}
break;
}
case ContactModelMaskTypes::Z:
if(reference_type == PinocchioReferenceTypes::LOCAL){
contact = boost::make_shared<crocoddyl::ContactModel1D>(state, frame_id, 0., nu, gains, Vector3MaskType::z, pinocchio::LOCAL);
} else if(reference_type == PinocchioReferenceTypes::WORLD){
contact = boost::make_shared<crocoddyl::ContactModel1D>(state, frame_id, 0., nu, gains, Vector3MaskType::z, pinocchio::WORLD);
} else if(reference_type == PinocchioReferenceTypes::LOCAL_WORLD_ALIGNED){
contact = boost::make_shared<crocoddyl::ContactModel1D>(state, frame_id, 0., nu, gains, Vector3MaskType::z, pinocchio::LOCAL_WORLD_ALIGNED);
}
break;
default:
throw_pretty(__FILE__ ": Wrong ContactModelMaskTypes::Type given");
break;
}
return contact;
}

boost::shared_ptr<crocoddyl::ContactModelAbstract> create_random_contact1d() {
static bool once = true;
if (once) {
srand((unsigned)time(NULL));
once = false;
}
boost::shared_ptr<crocoddyl::ContactModelAbstract> contact;
ContactModel1DFactory factory;
if (rand() % 3 == 0) {
contact = factory.create(ContactModelMaskTypes::X, PinocchioModelTypes::RandomHumanoid, PinocchioReferenceTypes::LOCAL);
} else if (rand() % 3 == 1) {
contact = factory.create(ContactModelMaskTypes::Y, PinocchioModelTypes::RandomHumanoid, PinocchioReferenceTypes::LOCAL);
} else {
contact = factory.create(ContactModelMaskTypes::Z, PinocchioModelTypes::RandomHumanoid, PinocchioReferenceTypes::LOCAL);
}
return contact;
}

} // namespace unittest
} // namespace crocoddyl
Loading

0 comments on commit 1fecfb4

Please sign in to comment.