Skip to content

Fix removeRigidContact #273

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

Merged
merged 4 commits into from
Jul 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- Fix value of nEq when removeRigidContact for contact with priority > 0

## [1.8.0] - 2025-03-29

- Fix missing `const` specifier in python bindings for methods `RobotInertia.set_rotor_inertia()`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class InverseDynamicsFormulationAccForce
Vector getContactForces(const std::string& name, const HQPOutput& sol);
bool getContactForces(const std::string& name, const HQPOutput& sol,
RefVector f) override;
unsigned int getTaskPriority(const std::string& name) override;

public:
template <class TaskLevelPointer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ class InverseDynamicsFormulationBase {
virtual bool getContactForces(const std::string& name, const HQPOutput& sol,
RefVector f) = 0;

virtual unsigned int getTaskPriority(const std::string& name) = 0;

protected:
std::string m_name;
RobotWrapper m_robot;
Expand Down
19 changes: 18 additions & 1 deletion src/formulations/inverse-dynamics-formulation-acc-force.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,9 @@ bool InverseDynamicsFormulationAccForce::removeRigidContact(
return false;
}

// Find motion task priority
bool is_motion_contraint =
(getTaskPriority(contactName + "_motion_task") == 0);
bool first_constraint_found = removeFromHqpData(contactName + "_motion_task");
assert(first_constraint_found);

Expand All @@ -556,7 +559,7 @@ bool InverseDynamicsFormulationAccForce::removeRigidContact(
for (auto it = m_contacts.begin(); it != m_contacts.end(); it++) {
if ((*it)->contact.name() == contactName) {
m_k -= (*it)->contact.n_force();
m_eq -= (*it)->motionConstraint->rows();
if (is_motion_contraint) m_eq -= (*it)->motionConstraint->rows();
m_in -= (*it)->forceConstraint->rows();
m_contacts.erase(it);
resizeHqpData();
Expand Down Expand Up @@ -600,3 +603,17 @@ bool InverseDynamicsFormulationAccForce::removeFromHqpData(
}
return false;
}

unsigned int InverseDynamicsFormulationAccForce::getTaskPriority(
const std::string &name) {
for (std::size_t i = 0; i < m_hqpData.size(); i++) {
const bool found = std::any_of(
m_hqpData[i].begin(), m_hqpData[i].end(),
[&name](const auto &c) { return c.second->name() == name; });
if (found) {
return i;
}
}
assert(false); // Task name not found in formulation data
return -1;
}
18 changes: 18 additions & 0 deletions tests/tsid-formulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,15 @@ BOOST_AUTO_TEST_CASE(test_invdyn_formulation_acc_force_remove_contact) {
CHECK_LESS_THAN(v.norm(), 1e6);
}

// Removing contact constraint should decrease nb of equality by 6
int nEq = tsid->nEq();
tsid->removeRigidContact("contact_rfoot");
nEq -= 6;
BOOST_CHECK_EQUAL(nEq, tsid->nEq());
tsid->removeRigidContact("contact_lfoot");
nEq -= 6;
BOOST_CHECK_EQUAL(nEq, tsid->nEq());

delete solver;
cout << "\n### TEST FINISHED ###\n";
PRINT_VECTOR(v);
Expand Down Expand Up @@ -573,6 +582,7 @@ BOOST_AUTO_TEST_CASE(test_contact_point_invdyn_formulation_acc_force) {
Vector3 contactNormal = Vector3::UnitZ();
std::vector<std::shared_ptr<ContactPoint>> contacts(4);

int nEq = tsid->nEq();
for (int i = 0; i < 4; i++) {
auto cp = std::make_shared<ContactPoint>("contact_" + contactFrames[i],
robot, contactFrames[i],
Expand All @@ -584,6 +594,9 @@ BOOST_AUTO_TEST_CASE(test_contact_point_invdyn_formulation_acc_force) {
cp->useLocalFrame(false);
tsid->addRigidContact(*cp, w_forceReg, 1.0, 1);

// Adding rigid contact as cost should not change nb of equalities
BOOST_CHECK_EQUAL(nEq, tsid->nEq());

contacts[i] = cp;
}

Expand Down Expand Up @@ -650,10 +663,15 @@ BOOST_AUTO_TEST_CASE(test_contact_point_invdyn_formulation_acc_force) {
CHECK_LESS_THAN(v.norm(), 1e6);
}

nEq = tsid->nEq();
for (int i = 0; i < 4; i++) {
Eigen::Matrix<double, 3, 1> f;
tsid->getContactForces(contacts[i]->name(), *sol, f);
cout << contacts[i]->name() << " force:" << f.transpose() << endl;

// Removing rigid contact (added as cost) should not change nb of equalities
tsid->removeRigidContact(contacts[i]->name());
BOOST_CHECK_EQUAL(nEq, tsid->nEq());
}

delete solver;
Expand Down
Loading