GCC Code Coverage Report


Directory: ./
File: src/formulations/inverse-dynamics-formulation-acc-force.cpp
Date: 2025-05-10 01:12:46
Exec Total Coverage
Lines: 0 346 0.0%
Branches: 0 948 0.0%

Line Branch Exec Source
1 //
2 // Copyright (c) 2017 CNRS, NYU, MPI Tübingen
3 //
4 // This file is part of tsid
5 // tsid is free software: you can redistribute it
6 // and/or modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation, either version
8 // 3 of the License, or (at your option) any later version.
9 // tsid is distributed in the hope that it will be
10 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
11 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Lesser Public License for more details. You should have
13 // received a copy of the GNU Lesser General Public License along with
14 // tsid If not, see
15 // <http://www.gnu.org/licenses/>.
16 //
17
18 #include "tsid/formulations/inverse-dynamics-formulation-acc-force.hpp"
19
20 #include "tsid/math/constraint-bound.hpp"
21 #include "tsid/math/constraint-inequality.hpp"
22
23 using namespace tsid;
24 using namespace math;
25 using namespace tasks;
26 using namespace contacts;
27 using namespace solvers;
28 using namespace std;
29
30 typedef pinocchio::Data Data;
31
32 ✗ InverseDynamicsFormulationAccForce::InverseDynamicsFormulationAccForce(
33 ✗ const std::string &name, RobotWrapper &robot, bool verbose)
34 : InverseDynamicsFormulationBase(name, robot, verbose),
35 ✗ m_data(robot.model()),
36 ✗ m_baseDynamics(new math::ConstraintEquality(
37 ✗ "base-dynamics", robot.nv() - robot.na(), robot.nv())),
38 ✗ m_solutionDecoded(false) {
39 ✗ m_t = 0.0;
40 ✗ m_v = robot.nv();
41 ✗ m_u = robot.nv() - robot.na();
42 ✗ m_k = 0;
43 ✗ m_eq = m_u;
44 ✗ m_in = 0;
45 ✗ m_hqpData.resize(2);
46 ✗ m_Jc.setZero(m_k, m_v);
47 ✗ h_fext.setZero(m_v);
48 ✗ m_hqpData[0].push_back(
49 ✗ solvers::make_pair<double, std::shared_ptr<ConstraintBase> >(
50 ✗ 1.0, m_baseDynamics));
51 }
52
53 ✗ Data &InverseDynamicsFormulationAccForce::data() { return m_data; }
54
55 ✗ unsigned int InverseDynamicsFormulationAccForce::nVar() const {
56 ✗ return m_v + m_k;
57 }
58
59 ✗ unsigned int InverseDynamicsFormulationAccForce::nEq() const { return m_eq; }
60
61 ✗ unsigned int InverseDynamicsFormulationAccForce::nIn() const { return m_in; }
62
63 ✗ void InverseDynamicsFormulationAccForce::resizeHqpData() {
64 ✗ m_Jc.setZero(m_k, m_v);
65 ✗ m_baseDynamics->resize(m_u, m_v + m_k);
66 ✗ for (HQPData::iterator it = m_hqpData.begin(); it != m_hqpData.end(); it++) {
67 ✗ for (ConstraintLevel::iterator itt = it->begin(); itt != it->end(); itt++) {
68 ✗ itt->second->resize(itt->second->rows(), m_v + m_k);
69 }
70 }
71 }
72
73 template <class TaskLevelPointer>
74 ✗ void InverseDynamicsFormulationAccForce::addTask(TaskLevelPointer tl,
75 double weight,
76 unsigned int priorityLevel) {
77 ✗ if (priorityLevel > m_hqpData.size()) m_hqpData.resize(priorityLevel);
78 ✗ const ConstraintBase &c = tl->task.getConstraint();
79 ✗ if (c.isEquality()) {
80 ✗ tl->constraint =
81 ✗ std::make_shared<ConstraintEquality>(c.name(), c.rows(), m_v + m_k);
82 ✗ if (priorityLevel == 0) m_eq += c.rows();
83 } else // if(c.isInequality())
84 {
85 ✗ tl->constraint =
86 ✗ std::make_shared<ConstraintInequality>(c.name(), c.rows(), m_v + m_k);
87 ✗ if (priorityLevel == 0) m_in += c.rows();
88 }
89 // don't use bounds for now because EiQuadProg doesn't exploit them anyway
90 // else
91 // tl->constraint = new ConstraintBound(c.name(), m_v+m_k);
92 ✗ m_hqpData[priorityLevel].push_back(
93 make_pair<double, std::shared_ptr<ConstraintBase> >(weight,
94 ✗ tl->constraint));
95 }
96
97 ✗ bool InverseDynamicsFormulationAccForce::addMotionTask(
98 TaskMotion &task, double weight, unsigned int priorityLevel,
99 double transition_duration) {
100 ✗ PINOCCHIO_CHECK_INPUT_ARGUMENT(
101 weight >= 0.0, "The weight needs to be positive or equal to 0");
102 ✗ PINOCCHIO_CHECK_INPUT_ARGUMENT(
103 transition_duration >= 0.0,
104 "The transition duration needs to be greater than or equal to 0");
105
106 ✗ auto tl = std::make_shared<TaskLevel>(task, priorityLevel);
107 ✗ m_taskMotions.push_back(tl);
108 ✗ addTask(tl, weight, priorityLevel);
109
110 ✗ return true;
111 }
112
113 ✗ bool InverseDynamicsFormulationAccForce::addForceTask(
114 TaskContactForce &task, double weight, unsigned int priorityLevel,
115 double transition_duration) {
116 ✗ PINOCCHIO_CHECK_INPUT_ARGUMENT(
117 weight >= 0.0, "The weight needs to be positive or equal to 0");
118 ✗ PINOCCHIO_CHECK_INPUT_ARGUMENT(
119 transition_duration >= 0.0,
120 "The transition duration needs to be greater than or equal to 0");
121
122 ✗ auto tl = std::make_shared<TaskLevelForce>(task, priorityLevel);
123 ✗ m_taskContactForces.push_back(tl);
124 ✗ addTask(tl, weight, priorityLevel);
125 ✗ return true;
126 }
127
128 ✗ bool InverseDynamicsFormulationAccForce::addActuationTask(
129 TaskActuation &task, double weight, unsigned int priorityLevel,
130 double transition_duration) {
131 ✗ PINOCCHIO_CHECK_INPUT_ARGUMENT(
132 weight >= 0.0, "The weight needs to be positive or equal to 0");
133 ✗ PINOCCHIO_CHECK_INPUT_ARGUMENT(
134 transition_duration >= 0.0,
135 "The transition duration needs to be greater than or equal to 0");
136
137 ✗ auto tl = std::make_shared<TaskLevel>(task, priorityLevel);
138 ✗ m_taskActuations.push_back(tl);
139
140 ✗ if (priorityLevel > m_hqpData.size()) m_hqpData.resize(priorityLevel);
141
142 ✗ const ConstraintBase &c = tl->task.getConstraint();
143 ✗ if (c.isEquality()) {
144 ✗ tl->constraint =
145 ✗ std::make_shared<ConstraintEquality>(c.name(), c.rows(), m_v + m_k);
146 ✗ if (priorityLevel == 0) m_eq += c.rows();
147 } else // an actuator bound becomes an inequality because actuator forces are
148 // not in the problem variables
149 {
150 ✗ tl->constraint =
151 ✗ std::make_shared<ConstraintInequality>(c.name(), c.rows(), m_v + m_k);
152 ✗ if (priorityLevel == 0) m_in += c.rows();
153 }
154
155 ✗ m_hqpData[priorityLevel].push_back(
156 ✗ make_pair<double, std::shared_ptr<ConstraintBase> >(weight,
157 ✗ tl->constraint));
158
159 ✗ return true;
160 }
161
162 ✗ bool InverseDynamicsFormulationAccForce::updateTaskWeight(
163 const std::string &task_name, double weight) {
164 ✗ ConstraintLevel::iterator it;
165 // do not look into first priority level because weights do not matter there
166 ✗ for (unsigned int i = 1; i < m_hqpData.size(); i++) {
167 ✗ for (it = m_hqpData[i].begin(); it != m_hqpData[i].end(); it++) {
168 ✗ if (it->second->name() == task_name) {
169 ✗ it->first = weight;
170 ✗ return true;
171 }
172 }
173 }
174 ✗ return false;
175 }
176
177 ✗ bool InverseDynamicsFormulationAccForce::addRigidContact(
178 ContactBase &contact, double force_regularization_weight,
179 double motion_weight, unsigned int motionPriorityLevel) {
180 ✗ auto cl = std::make_shared<ContactLevel>(contact);
181 ✗ cl->index = m_k;
182 ✗ m_k += contact.n_force();
183 ✗ m_contacts.push_back(cl);
184 ✗ resizeHqpData();
185
186 ✗ const ConstraintBase &motionConstr = contact.getMotionConstraint();
187 ✗ cl->motionConstraint = std::make_shared<ConstraintEquality>(
188 ✗ contact.name() + "_motion_task", motionConstr.rows(), m_v + m_k);
189 ✗ m_hqpData[motionPriorityLevel].push_back(
190 ✗ solvers::make_pair<double, std::shared_ptr<ConstraintBase> >(
191 ✗ motion_weight, cl->motionConstraint));
192
193 ✗ const ConstraintInequality &forceConstr = contact.getForceConstraint();
194 ✗ cl->forceConstraint = std::make_shared<ConstraintInequality>(
195 ✗ contact.name() + "_force_constraint", forceConstr.rows(), m_v + m_k);
196 ✗ m_hqpData[0].push_back(
197 ✗ solvers::make_pair<double, std::shared_ptr<ConstraintBase> >(
198 ✗ 1.0, cl->forceConstraint));
199
200 const ConstraintEquality &forceRegConstr =
201 ✗ contact.getForceRegularizationTask();
202 ✗ cl->forceRegTask = std::make_shared<ConstraintEquality>(
203 ✗ contact.name() + "_force_reg_task", forceRegConstr.rows(), m_v + m_k);
204 ✗ m_hqpData[1].push_back(
205 ✗ solvers::make_pair<double, std::shared_ptr<ConstraintBase> >(
206 ✗ force_regularization_weight, cl->forceRegTask));
207
208 ✗ if (motionPriorityLevel == 0) m_eq += motionConstr.rows();
209 ✗ m_in += forceConstr.rows();
210
211 ✗ return true;
212 }
213
214 ✗ bool InverseDynamicsFormulationAccForce::addRigidContact(ContactBase &contact) {
215 std::cout << "[InverseDynamicsFormulationAccForce] Method "
216 "addRigidContact(ContactBase) is deprecated. You should use "
217 ✗ "addRigidContact(ContactBase, double) instead.\n";
218 ✗ return addRigidContact(contact, 1e-5);
219 }
220
221 ✗ bool InverseDynamicsFormulationAccForce::updateRigidContactWeights(
222 const std::string &contact_name, double force_regularization_weight,
223 double motion_weight) {
224 // update weight of force regularization task
225 ✗ ConstraintLevel::iterator itt;
226 ✗ bool force_reg_task_found = false;
227 ✗ bool motion_task_found = false;
228 ✗ for (unsigned int i = 1; i < m_hqpData.size(); i++) {
229 ✗ for (itt = m_hqpData[i].begin(); itt != m_hqpData[i].end(); itt++) {
230 ✗ if (itt->second->name() == contact_name + "_force_reg_task") {
231 ✗ if (force_regularization_weight >= 0.0)
232 ✗ itt->first = force_regularization_weight;
233 ✗ if (motion_task_found || motion_weight < 0.0)
234 ✗ return true; // If motion_weight is negative, the motion_task will
235 // not be modified. The method can return here
236 ✗ force_reg_task_found = true;
237 ✗ } else if (itt->second->name() == contact_name + "_motion_task") {
238 ✗ if (motion_weight >= 0.0) itt->first = motion_weight;
239 ✗ if (force_reg_task_found) return true;
240 ✗ motion_task_found = true;
241 }
242 }
243 }
244 ✗ return false;
245 }
246
247 ✗ bool InverseDynamicsFormulationAccForce::addMeasuredForce(
248 MeasuredForceBase &measuredForce) {
249 ✗ auto tl = std::make_shared<MeasuredForceLevel>(measuredForce);
250 ✗ m_measuredForces.push_back(tl);
251
252 ✗ return true;
253 }
254
255 ✗ const HQPData &InverseDynamicsFormulationAccForce::computeProblemData(
256 double time, ConstRefVector q, ConstRefVector v) {
257 ✗ m_t = time;
258
259 ✗ for (auto it_ct = m_contactTransitions.begin();
260 ✗ it_ct != m_contactTransitions.end(); it_ct++) {
261 ✗ auto c = *it_ct;
262 ✗ assert(c->time_start <= m_t);
263 ✗ if (m_t <= c->time_end) {
264 const double alpha =
265 ✗ (m_t - c->time_start) / (c->time_end - c->time_start);
266 ✗ const double fMax = c->fMax_start + alpha * (c->fMax_end - c->fMax_start);
267 ✗ c->contactLevel->contact.setMaxNormalForce(fMax);
268 } else {
269 // std::cout<<"[InverseDynamicsFormulationAccForce] Remove contact "<<
270 // c->contactLevel->contact.name()<<" at time
271 // "<<time<<std::endl;
272 ✗ removeRigidContact(c->contactLevel->contact.name());
273 // FIXME: this won't work if multiple contact transitions occur at the
274 // same time because after erasing an element the iterator is invalid
275 ✗ m_contactTransitions.erase(it_ct);
276 ✗ break;
277 }
278 }
279
280 ✗ m_robot.computeAllTerms(m_data, q, v);
281
282 ✗ for (auto cl : m_contacts) {
283 ✗ unsigned int m = cl->contact.n_force();
284
285 const ConstraintBase &mc =
286 ✗ cl->contact.computeMotionTask(time, q, v, m_data);
287 ✗ cl->motionConstraint->matrix().leftCols(m_v) = mc.matrix();
288 ✗ cl->motionConstraint->vector() = mc.vector();
289
290 const Matrix &T =
291 ✗ cl->contact.getForceGeneratorMatrix(); // e.g., 6x12 for a 6d contact
292 ✗ m_Jc.middleRows(cl->index, m).noalias() = T.transpose() * mc.matrix();
293
294 const ConstraintInequality &fc =
295 ✗ cl->contact.computeForceTask(time, q, v, m_data);
296 ✗ cl->forceConstraint->matrix().middleCols(m_v + cl->index, m) = fc.matrix();
297 ✗ cl->forceConstraint->lowerBound() = fc.lowerBound();
298 ✗ cl->forceConstraint->upperBound() = fc.upperBound();
299
300 const ConstraintEquality &fr =
301 ✗ cl->contact.computeForceRegularizationTask(time, q, v, m_data);
302 ✗ cl->forceRegTask->matrix().middleCols(m_v + cl->index, m) = fr.matrix();
303 ✗ cl->forceRegTask->vector() = fr.vector();
304 }
305
306 // Add all measured external forces to dynamic model
307 ✗ h_fext.setZero(m_v);
308 ✗ for (auto it : m_measuredForces) {
309 ✗ h_fext += it->measuredForce.computeJointTorques(m_data);
310 }
311
312 ✗ const Matrix &M_a = m_robot.mass(m_data).bottomRows(m_v - m_u);
313 const Vector &h_a =
314 ✗ m_robot.nonLinearEffects(m_data).tail(m_v - m_u) - h_fext.tail(m_v - m_u);
315 ✗ const Matrix &J_a = m_Jc.rightCols(m_v - m_u);
316 ✗ const Matrix &M_u = m_robot.mass(m_data).topRows(m_u);
317 const Vector &h_u =
318 ✗ m_robot.nonLinearEffects(m_data).head(m_u) - h_fext.head(m_u);
319 ✗ const Matrix &J_u = m_Jc.leftCols(m_u);
320
321 ✗ m_baseDynamics->matrix().leftCols(m_v) = M_u;
322 ✗ m_baseDynamics->matrix().rightCols(m_k) = -J_u.transpose();
323 ✗ m_baseDynamics->vector() = -h_u;
324
325 // std::vector<TaskLevel*>::iterator it;
326 // for(it=m_taskMotions.begin(); it!=m_taskMotions.end(); it++)
327 ✗ for (auto &it : m_taskMotions) {
328 ✗ const ConstraintBase &c = it->task.compute(time, q, v, m_data);
329 ✗ if (c.isEquality()) {
330 ✗ it->constraint->matrix().leftCols(m_v) = c.matrix();
331 ✗ it->constraint->vector() = c.vector();
332 ✗ } else if (c.isInequality()) {
333 ✗ it->constraint->matrix().leftCols(m_v) = c.matrix();
334 ✗ it->constraint->lowerBound() = c.lowerBound();
335 ✗ it->constraint->upperBound() = c.upperBound();
336 } else {
337 ✗ it->constraint->matrix().leftCols(m_v) = Matrix::Identity(m_v, m_v);
338 ✗ it->constraint->lowerBound() = c.lowerBound();
339 ✗ it->constraint->upperBound() = c.upperBound();
340 }
341 }
342
343 ✗ for (auto &it : m_taskContactForces) {
344 // cout<<"Task "<<it->task.name()<<endl;
345 // by default the task is associated to all contact forces
346 ✗ int i0 = m_v;
347 ✗ int c_size = m_k;
348
349 // if the task is associated to a specific contact
350 // cout<<"Associated contact name:
351 // "<<it->task.getAssociatedContactName()<<endl;
352 ✗ if (it->task.getAssociatedContactName() != "") {
353 // look for the associated contact
354 ✗ for (auto cl : m_contacts) {
355 ✗ if (it->task.getAssociatedContactName() == cl->contact.name()) {
356 ✗ i0 += cl->index;
357 ✗ c_size = cl->contact.n_force();
358 ✗ break;
359 }
360 }
361 }
362
363 ✗ const ConstraintBase &c = it->task.compute(time, q, v, m_data, &m_contacts);
364 // cout<<"matrix"<<endl<<c.matrix()<<endl;
365 // cout<<"vector"<<endl<<c.vector().transpose()<<endl;
366 // cout<<"i0 "<<i0<<" c_size "<<c_size<<endl;
367 // cout<<"constraint matrix size: "<<it->constraint->matrix().rows()<<" x
368 // "<<it->constraint->matrix().cols()<<endl;
369
370 ✗ if (c.isEquality()) {
371 ✗ it->constraint->matrix().middleCols(i0, c_size) = c.matrix();
372 ✗ it->constraint->vector() = c.vector();
373 ✗ } else if (c.isInequality()) {
374 ✗ it->constraint->matrix().middleCols(i0, c_size) = c.matrix();
375 ✗ it->constraint->lowerBound() = c.lowerBound();
376 ✗ it->constraint->upperBound() = c.upperBound();
377 } else {
378 ✗ it->constraint->matrix().middleCols(i0, c_size) =
379 ✗ Matrix::Identity(c_size, c_size);
380 ✗ it->constraint->lowerBound() = c.lowerBound();
381 ✗ it->constraint->upperBound() = c.upperBound();
382 }
383 }
384
385 ✗ for (auto &it : m_taskActuations) {
386 ✗ const ConstraintBase &c = it->task.compute(time, q, v, m_data);
387 ✗ if (c.isEquality()) {
388 ✗ it->constraint->matrix().leftCols(m_v).noalias() = c.matrix() * M_a;
389 ✗ it->constraint->matrix().rightCols(m_k).noalias() =
390 ✗ -c.matrix() * J_a.transpose();
391 ✗ it->constraint->vector() = c.vector();
392 ✗ it->constraint->vector().noalias() -= c.matrix() * h_a;
393 ✗ } else if (c.isInequality()) {
394 ✗ it->constraint->matrix().leftCols(m_v).noalias() = c.matrix() * M_a;
395 ✗ it->constraint->matrix().rightCols(m_k).noalias() =
396 ✗ -c.matrix() * J_a.transpose();
397 ✗ it->constraint->lowerBound() = c.lowerBound();
398 ✗ it->constraint->lowerBound().noalias() -= c.matrix() * h_a;
399 ✗ it->constraint->upperBound() = c.upperBound();
400 ✗ it->constraint->upperBound().noalias() -= c.matrix() * h_a;
401 } else {
402 // NB: An actuator bound becomes an inequality
403 ✗ it->constraint->matrix().leftCols(m_v) = M_a;
404 ✗ it->constraint->matrix().rightCols(m_k) = -J_a.transpose();
405 ✗ it->constraint->lowerBound() = c.lowerBound() - h_a;
406 ✗ it->constraint->upperBound() = c.upperBound() - h_a;
407 }
408 }
409
410 ✗ m_solutionDecoded = false;
411
412 ✗ return m_hqpData;
413 }
414
415 ✗ bool InverseDynamicsFormulationAccForce::decodeSolution(const HQPOutput &sol) {
416 ✗ if (m_solutionDecoded) return true;
417
418 ✗ const Matrix &M_a = m_robot.mass(m_data).bottomRows(m_v - m_u);
419 const Vector &h_a =
420 ✗ m_robot.nonLinearEffects(m_data).tail(m_v - m_u) - h_fext.tail(m_v - m_u);
421 ✗ const Matrix &J_a = m_Jc.rightCols(m_v - m_u);
422 ✗ m_dv = sol.x.head(m_v);
423 ✗ m_f = sol.x.tail(m_k);
424 ✗ m_tau = h_a;
425 ✗ m_tau.noalias() += M_a * m_dv;
426 ✗ m_tau.noalias() -= J_a.transpose() * m_f;
427 ✗ m_solutionDecoded = true;
428 ✗ return true;
429 }
430
431 ✗ const Vector &InverseDynamicsFormulationAccForce::getActuatorForces(
432 const HQPOutput &sol) {
433 ✗ decodeSolution(sol);
434 ✗ return m_tau;
435 }
436
437 ✗ const Vector &InverseDynamicsFormulationAccForce::getAccelerations(
438 const HQPOutput &sol) {
439 ✗ decodeSolution(sol);
440 ✗ return m_dv;
441 }
442
443 ✗ const Vector &InverseDynamicsFormulationAccForce::getContactForces(
444 const HQPOutput &sol) {
445 ✗ decodeSolution(sol);
446 ✗ return m_f;
447 }
448
449 ✗ Vector InverseDynamicsFormulationAccForce::getContactForces(
450 const std::string &name, const HQPOutput &sol) {
451 ✗ decodeSolution(sol);
452 // for(std::vector<ContactLevel*>::iterator it=m_contacts.begin();
453 // it!=m_contacts.end(); it++)
454 ✗ for (auto &it : m_contacts) {
455 ✗ if (it->contact.name() == name) {
456 ✗ const int k = it->contact.n_force();
457 ✗ return m_f.segment(it->index, k);
458 }
459 }
460 ✗ return Vector::Zero(0);
461 }
462
463 ✗ bool InverseDynamicsFormulationAccForce::getContactForces(
464 const std::string &name, const HQPOutput &sol, RefVector f) {
465 ✗ decodeSolution(sol);
466 ✗ for (auto &it : m_contacts) {
467 ✗ if (it->contact.name() == name) {
468 ✗ const int k = it->contact.n_force();
469 ✗ assert(f.size() == k);
470 ✗ f = m_f.segment(it->index, k);
471 ✗ return true;
472 }
473 }
474 ✗ return false;
475 }
476
477 ✗ bool InverseDynamicsFormulationAccForce::removeTask(const std::string &taskName,
478 double) {
479 #ifndef NDEBUG
480 ✗ bool taskFound = removeFromHqpData(taskName);
481 ✗ assert(taskFound);
482 #else
483 removeFromHqpData(taskName);
484 #endif
485
486 ✗ for (auto it = m_taskMotions.begin(); it != m_taskMotions.end(); it++) {
487 ✗ if ((*it)->task.name() == taskName) {
488 ✗ if ((*it)->priority == 0) {
489 ✗ if ((*it)->constraint->isEquality())
490 ✗ m_eq -= (*it)->constraint->rows();
491 ✗ else if ((*it)->constraint->isInequality())
492 ✗ m_in -= (*it)->constraint->rows();
493 }
494 ✗ m_taskMotions.erase(it);
495 ✗ return true;
496 }
497 }
498 ✗ for (auto it = m_taskContactForces.begin(); it != m_taskContactForces.end();
499 ✗ it++) {
500 ✗ if ((*it)->task.name() == taskName) {
501 ✗ m_taskContactForces.erase(it);
502 ✗ return true;
503 }
504 }
505 ✗ for (auto it = m_taskActuations.begin(); it != m_taskActuations.end(); it++) {
506 ✗ if ((*it)->task.name() == taskName) {
507 ✗ if ((*it)->priority == 0) {
508 ✗ if ((*it)->constraint->isEquality())
509 ✗ m_eq -= (*it)->constraint->rows();
510 else
511 ✗ m_in -= (*it)->constraint->rows();
512 }
513 ✗ m_taskActuations.erase(it);
514 ✗ return true;
515 }
516 }
517 ✗ return false;
518 }
519
520 ✗ bool InverseDynamicsFormulationAccForce::removeRigidContact(
521 const std::string &contactName, double transition_duration) {
522 ✗ if (transition_duration > 0.0) {
523 ✗ for (auto &it : m_contacts) {
524 ✗ if (it->contact.name() == contactName) {
525 ✗ auto transitionInfo = std::make_shared<ContactTransitionInfo>();
526 ✗ transitionInfo->contactLevel = it;
527 ✗ transitionInfo->time_start = m_t;
528 ✗ transitionInfo->time_end = m_t + transition_duration;
529 ✗ const int k = it->contact.n_force();
530 ✗ if (m_f.size() >= it->index + k) {
531 ✗ const Vector f = m_f.segment(it->index, k);
532 ✗ transitionInfo->fMax_start = it->contact.getNormalForce(f);
533 ✗ } else {
534 ✗ transitionInfo->fMax_start = it->contact.getMaxNormalForce();
535 }
536 ✗ transitionInfo->fMax_end = it->contact.getMinNormalForce() + 1e-3;
537 ✗ m_contactTransitions.push_back(transitionInfo);
538 ✗ return true;
539 }
540 }
541 ✗ return false;
542 }
543
544 ✗ bool first_constraint_found = removeFromHqpData(contactName + "_motion_task");
545 ✗ assert(first_constraint_found);
546
547 bool second_constraint_found =
548 ✗ removeFromHqpData(contactName + "_force_constraint");
549 ✗ assert(second_constraint_found);
550
551 bool third_constraint_found =
552 ✗ removeFromHqpData(contactName + "_force_reg_task");
553 ✗ assert(third_constraint_found);
554
555 ✗ bool contact_found = false;
556 ✗ for (auto it = m_contacts.begin(); it != m_contacts.end(); it++) {
557 ✗ if ((*it)->contact.name() == contactName) {
558 ✗ m_k -= (*it)->contact.n_force();
559 ✗ m_eq -= (*it)->motionConstraint->rows();
560 ✗ m_in -= (*it)->forceConstraint->rows();
561 ✗ m_contacts.erase(it);
562 ✗ resizeHqpData();
563 ✗ contact_found = true;
564 ✗ break;
565 }
566 }
567
568 ✗ int k = 0;
569 ✗ for (auto &it : m_contacts) {
570 ✗ it->index = k;
571 ✗ k += it->contact.n_force();
572 }
573 ✗ return contact_found && first_constraint_found && second_constraint_found &&
574 ✗ third_constraint_found;
575 }
576
577 ✗ bool InverseDynamicsFormulationAccForce::removeMeasuredForce(
578 const std::string &measuredForceName) {
579 ✗ for (auto it = m_measuredForces.begin(); it != m_measuredForces.end(); it++) {
580 ✗ if ((*it)->measuredForce.name() == measuredForceName) {
581 ✗ m_measuredForces.erase(it);
582 ✗ return true;
583 }
584 }
585 ✗ return false;
586 }
587
588 ✗ bool InverseDynamicsFormulationAccForce::removeFromHqpData(
589 const std::string &name) {
590 ✗ bool found = false;
591 ✗ for (HQPData::iterator it = m_hqpData.begin();
592 ✗ !found && it != m_hqpData.end(); it++) {
593 ✗ for (ConstraintLevel::iterator itt = it->begin();
594 ✗ !found && itt != it->end(); itt++) {
595 ✗ if (itt->second->name() == name) {
596 ✗ it->erase(itt);
597 ✗ return true;
598 }
599 }
600 }
601 ✗ return false;
602 }
603