Skip to content

Commit 8f3e77f

Browse files
Second order vel-damper support
1 parent dabe8ea commit 8f3e77f

8 files changed

Lines changed: 241 additions & 18 deletions

File tree

include/mc_rbdyn/Collision.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ struct MC_RBDYN_DLLAPI Collision
2828
const std::optional<std::vector<std::string>> & r1Joints = {},
2929
const std::optional<std::vector<std::string>> & r2Joints = {},
3030
bool r1JointsInactive = false,
31-
bool r2JointsInactive = false)
31+
bool r2JointsInactive = false,
32+
double m = 0.0,
33+
double lambda = 0.0)
3234
: body1(b1), body2(b2), iDist(i), sDist(s), damping(d), r1Joints(r1Joints), r2Joints(r2Joints),
33-
r1JointsInactive(r1JointsInactive), r2JointsInactive(r2JointsInactive)
35+
r1JointsInactive(r1JointsInactive), r2JointsInactive(r2JointsInactive), overDamping(m), lambda(lambda)
3436
{
3537
}
3638
std::string body1; /** First body in the constraint */
@@ -50,6 +52,8 @@ struct MC_RBDYN_DLLAPI Collision
5052
r2Joints; /** Active/Inactive joints in the second robot, ignored if r1 == r2 */
5153
bool r1JointsInactive = false; /** When true the selected joints in r1ActiveJoints are considered inactive */
5254
bool r2JointsInactive = false; /** When true the selected joints in r2ActiveJoints are considered inactive */
55+
double overDamping; /** Damping ratio **/
56+
double lambda; /** Lambda parameter **/
5357
inline bool isNone() { return body1 == "NONE" && body2 == "NONE"; }
5458

5559
bool operator==(const Collision & rhs) const;

include/mc_solver/CollisionsConstraint.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ struct MC_SOLVER_DLLAPI CollisionsConstraint : public ConstraintSet
8383
*/
8484
void addCollisions(QPSolver & solver, const std::vector<mc_rbdyn::Collision> & cols);
8585

86+
void editCollisions(QPSolver & solver, const std::vector<mc_rbdyn::Collision> & cols);
87+
88+
void setCollisionsDampers(QPSolver & solver, const std::vector<double> & dampers);
89+
8690
/** Returns true if the given collision is in this constraint */
8791
bool hasCollision(const std::string & c1, const std::string & c2) const noexcept;
8892

@@ -100,6 +104,8 @@ struct MC_SOLVER_DLLAPI CollisionsConstraint : public ConstraintSet
100104
*/
101105
inline void automaticMonitor(bool a) noexcept { autoMonitor_ = a; }
102106

107+
inline void logCollisions(bool a) noexcept { logCollisions_ = a; }
108+
103109
void addToSolverImpl(QPSolver & solver) override;
104110

105111
void update(QPSolver & solver) override;
@@ -132,14 +138,18 @@ struct MC_SOLVER_DLLAPI CollisionsConstraint : public ConstraintSet
132138
std::pair<int, mc_rbdyn::Collision> __popCollId(const std::string & name1, const std::string & name2);
133139
/** Actually adds the collision to the constraint, handles id creation and wildcard support */
134140
void __addCollision(mc_solver::QPSolver & solver, const mc_rbdyn::Collision & col);
141+
void __editCollision(mc_solver::QPSolver & solver, const mc_rbdyn::Collision & col);
135142

136143
/* Internal management for collision display */
137144
bool autoMonitor_ = true;
145+
bool logCollisions_ = true;
138146
std::unordered_set<int> monitored_;
139147
std::shared_ptr<mc_rtc::gui::StateBuilder> gui_;
148+
std::shared_ptr<mc_rtc::Logger> logger_;
140149
std::vector<std::string> category_;
141150
void addMonitorButton(int collId, const mc_rbdyn::Collision & col);
142151
void toggleCollisionMonitor(int collId, const mc_rbdyn::Collision * col = nullptr);
152+
void addLogs(int collId, const mc_rbdyn::Collision & col);
143153
};
144154

145155
} // namespace mc_solver

include/mc_solver/DynamicsConstraint.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,29 @@ struct MC_SOLVER_DLLAPI DynamicsConstraint : public KinematicsConstraint
6161
bool infTorque = false,
6262
bool compensateExtTorques = false);
6363

64+
/** Constructor
65+
* Builds a damped joint limits constraint and a motion constr depending on
66+
* the nature of the robot
67+
* See tasks::qp::MotionConstr for details on the latter one
68+
* \param robots The robots including the robot affected by this constraint
69+
* \param robotIndex The index of the robot affected by this constraint
70+
* \param damperSecond Value of the damper {interaction distance, safety distance,
71+
* offset, damping ratio, lambda}
72+
* \param velocityPercent Maximum joint velocity percentage, 0.5 is advised
73+
* \param infTorque If true, ignore the torque limits set in the robot model
74+
* \param compensateExtTorques If true, compensates external disturbances using a feedworward torque signal. The
75+
* constraint will search for the compensation value in robot by calling `compensationTorques()` method, if not an
76+
* estimation of external torques acting on the robot will be used by calling `externalTorques()` method.
77+
*/
78+
DynamicsConstraint(const mc_rbdyn::Robots & robots,
79+
unsigned int robotIndex,
80+
double timeStep,
81+
const std::array<double, 3> & damper,
82+
const std::array<double, 2> & damperSecond,
83+
double velocityPercent = 1.0,
84+
bool infTorque = false,
85+
bool compensateExternalForces = false);
86+
6487
/** Returns the tasks::qp::MotionConstr
6588
*
6689
* This assumes the backend was Tasks

include/mc_solver/KinematicsConstraint.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,23 @@ struct MC_SOLVER_DLLAPI KinematicsConstraint : public ConstraintSet
4545
const std::array<double, 3> & damper,
4646
double velocityPercent = 0.5);
4747

48+
/** Damped constraint constructor
49+
* Builds a damped joint limits constraint
50+
* See tasks::qp::DamperJointLimitsConstr documentation for detail
51+
* \param robots The robots including the robot affected by this constraint
52+
* \param robotIndex The index of the robot affected by this constraint
53+
* \param timeStep Solver timestep
54+
* \param damper Value of the damper {interaction distance, safety distance, offset}
55+
* \param damperSecond Value of the damper {damping ratio, lambda}
56+
* \param velocityPercent Maximum joint velocity percentage, 0.5 is advised
57+
*/
58+
KinematicsConstraint(const mc_rbdyn::Robots & robots,
59+
unsigned int robotIndex,
60+
double timeStep,
61+
const std::array<double, 3> & damper,
62+
const std::array<double, 2> & damperSecond,
63+
double velocityPercent = 0.5);
64+
4865
protected:
4966
/** Implementation of mc_solver::ConstraintSet::addToSolver */
5067
void addToSolverImpl(mc_solver::QPSolver & solver) override;

src/mc_solver/CollisionsConstraint.cpp

Lines changed: 133 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919

2020
#include <Tasks/QPConstr.h>
2121

22+
#include "mc_rbdyn/Collision.h"
23+
#include "mc_rtc/log/Logger.h"
24+
#include "mc_solver/QPSolver.h"
25+
#include <algorithm>
2226
#include <tvm/task_dynamics/VelocityDamper.h>
2327

2428
#include "utils/jointsToSelector.h"
@@ -113,12 +117,16 @@ struct TVMCollisionConstraint
113117
void addCollision(TVMQPSolver & solver, CollisionData & data)
114118
{
115119
const auto & col = data.collision;
116-
data.task = solver.problem().add(
117-
data.function >= 0.,
118-
tvm::task_dynamics::VelocityDamper(
119-
solver.dt(), {col.iDist, col.sDist, col.damping, mc_solver::CollisionsConstraint::defaultDampingOffset},
120-
tvm::constant::big_number),
121-
{tvm::requirements::PriorityLevel(0)});
120+
mc_rtc::log::info("[CollisionsConstraint] Adding collision constraint with xsi={}, xsioff={}, m={}, lambda={}",
121+
col.damping, mc_solver::CollisionsConstraint::defaultDampingOffset, col.overDamping, col.lambda);
122+
data.task =
123+
solver.problem().add(data.function >= 0.,
124+
tvm::task_dynamics::VelocityDamper(solver.dt(),
125+
{col.iDist, col.sDist, col.damping,
126+
mc_solver::CollisionsConstraint::defaultDampingOffset,
127+
col.overDamping, col.lambda},
128+
tvm::constant::big_number),
129+
{tvm::requirements::PriorityLevel(0)});
122130
}
123131
};
124132

@@ -368,6 +376,54 @@ void CollisionsConstraint::__addCollision(mc_solver::QPSolver & solver, const mc
368376
break;
369377
}
370378
addMonitorButton(collId, col);
379+
if(logCollisions_) addLogs(collId, col);
380+
}
381+
382+
void CollisionsConstraint::__editCollision(mc_solver::QPSolver & solver, const mc_rbdyn::Collision & col)
383+
{
384+
// Check for the correct backend
385+
if(backend_ != QPSolver::Backend::TVM)
386+
{
387+
mc_rtc::log::error("[CollisionsConstraint] Editing collisions is only supported for TVM backend currently.");
388+
return;
389+
}
390+
391+
// Find the collision in the existing set of constraints
392+
auto collIdIt = collIdDict.find(__keyByNames(col.body1, col.body2));
393+
if(collIdIt == collIdDict.end())
394+
{
395+
mc_rtc::log::error("[CollisionsConstraint] Attempting to edit a non-existent collision: {} - {}", col.body1,
396+
col.body2);
397+
return;
398+
}
399+
400+
// Get the current collision data
401+
int collId = collIdIt->second.first;
402+
403+
// Remove from collision vector
404+
// cols.erase(std::find(cols.begin(), cols.end(), p.second));
405+
406+
if(backend_ == QPSolver::Backend::TVM)
407+
{
408+
// Remove the existing collision
409+
tvm_constraint(constraint_)->deleteCollision(tvm_solver(solver), col);
410+
}
411+
else if(backend_ == QPSolver::Backend::Tasks)
412+
{
413+
// Remove the existing collision
414+
auto collConstr = tasks_constraint(constraint_);
415+
auto & qpsolver = tasks_solver(solver);
416+
bool ret = collConstr->rmCollision(collId);
417+
if(ret)
418+
{
419+
collConstr->updateNrVars({}, qpsolver.data());
420+
qpsolver.updateConstrSize();
421+
}
422+
}
423+
424+
addCollision(solver, {col});
425+
426+
mc_rtc::log::info("[CollisionsConstraint] Edited collision: {} - {}", col.body1, col.body2);
371427
}
372428

373429
void CollisionsConstraint::addMonitorButton(int collId, const mc_rbdyn::Collision & col)
@@ -384,6 +440,45 @@ void CollisionsConstraint::addMonitorButton(int collId, const mc_rbdyn::Collisio
384440
}
385441
}
386442

443+
void CollisionsConstraint::addLogs(int collId, const mc_rbdyn::Collision & col)
444+
{
445+
if(logger_ && inSolver_)
446+
{
447+
auto & logger = *logger_;
448+
std::string label = col.body1 + "::" + col.body2;
449+
auto addLogger = [&](auto && distance_callback, auto && di_callback, auto && ds_callback)
450+
{
451+
logger.addLogEntry("CollisionMonitor_" + label + "_distance",
452+
[distance_callback]() { return distance_callback(); });
453+
logger.addLogEntry("CollisionMonitor_" + label + "_di", [di_callback]() { return di_callback(); });
454+
logger.addLogEntry("CollisionMonitor_" + label + "_ds", [ds_callback]() { return ds_callback(); });
455+
};
456+
// Add the monitor
457+
switch(backend_)
458+
{
459+
case QPSolver::Backend::Tasks:
460+
{
461+
auto collConstr = tasks_constraint(constraint_);
462+
addLogger([collConstr, collId]() { return collConstr->getCollisionData(collId).distance; },
463+
[collConstr, collId]() { return collConstr->getCollisionData(collId).di; },
464+
[collConstr, collId]() { return collConstr->getCollisionData(collId).ds; });
465+
break;
466+
}
467+
case QPSolver::Backend::TVM:
468+
{
469+
auto collConstr = tvm_constraint(constraint_);
470+
auto fn = collConstr->getData(collId)->function;
471+
addLogger([fn]() { return fn->distance(); },
472+
[collConstr, collId]() { return collConstr->getData(collId)->collision.iDist; },
473+
[collConstr, collId]() { return collConstr->getData(collId)->collision.sDist; });
474+
break;
475+
}
476+
default:
477+
break;
478+
}
479+
}
480+
}
481+
387482
void CollisionsConstraint::toggleCollisionMonitor(int collId, const mc_rbdyn::Collision * col_p)
388483
{
389484
auto findCollisionById = [this, collId, &col_p]()
@@ -474,9 +569,36 @@ void CollisionsConstraint::addCollisions(QPSolver & solver, const std::vector<mc
474569
}
475570
}
476571

572+
void CollisionsConstraint::editCollisions(QPSolver & solver, const std::vector<mc_rbdyn::Collision> & cols)
573+
{
574+
// Check if the backend is TVM, as editing collisions is only supported for TVM
575+
if(backend_ != QPSolver::Backend::TVM)
576+
{
577+
mc_rtc::log::error("[CollisionsConstraint] Editing collisions is only supported for TVM backend currently.");
578+
return;
579+
}
580+
// Clear the existing collisions
581+
// tvm_constraint(constraint_)->clear();
582+
// Iterate over the list of collisions and call __editCollision for each
583+
for(const auto & col : cols) { __editCollision(solver, col); }
584+
585+
mc_rtc::log::info("[CollisionsConstraint] Successfully edited {} collisions.", cols.size());
586+
}
587+
588+
void CollisionsConstraint::setCollisionsDampers(QPSolver & solver, const std::vector<double> & dampers)
589+
{
590+
for(auto & col : cols)
591+
{
592+
col.overDamping = dampers[0];
593+
col.lambda = dampers[1];
594+
}
595+
editCollisions(solver, cols);
596+
}
597+
477598
void CollisionsConstraint::addToSolverImpl(QPSolver & solver)
478599
{
479600
gui_ = solver.gui();
601+
logger_ = solver.logger();
480602
const mc_rbdyn::Robot & r1 = solver.robots().robot(r1Index);
481603
const mc_rbdyn::Robot & r2 = solver.robots().robot(r2Index);
482604
category_ = {"Collisions", r1.name() + "/" + r2.name()};
@@ -500,7 +622,11 @@ void CollisionsConstraint::addToSolverImpl(QPSolver & solver)
500622
default:
501623
break;
502624
}
503-
for(const auto & cols : collIdDict) { addMonitorButton(cols.second.first, cols.second.second); }
625+
for(const auto & cols : collIdDict)
626+
{
627+
addMonitorButton(cols.second.first, cols.second.second);
628+
if(logCollisions_) { addLogs(cols.second.first, cols.second.second); };
629+
}
504630
}
505631

506632
void CollisionsConstraint::update(QPSolver &)

src/mc_solver/DynamicsConstraint.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,20 @@ DynamicsConstraint::DynamicsConstraint(const mc_rbdyn::Robots & robots,
147147
{
148148
}
149149

150+
DynamicsConstraint::DynamicsConstraint(const mc_rbdyn::Robots & robots,
151+
unsigned int robotIndex,
152+
double timeStep,
153+
const std::array<double, 3> & damper,
154+
const std::array<double, 2> & damperSecond,
155+
double velocityPercent,
156+
bool infTorque,
157+
bool compensateExtTorques)
158+
: KinematicsConstraint(robots, robotIndex, timeStep, damper, damperSecond, velocityPercent),
159+
motion_constr_(initialize(backend_, robots, robotIndex, timeStep, infTorque, compensateExtTorques)),
160+
robotIndex_(robotIndex)
161+
{
162+
}
163+
150164
void DynamicsConstraint::addToSolverImpl(QPSolver & solver)
151165
{
152166
KinematicsConstraint::addToSolverImpl(solver);

0 commit comments

Comments
 (0)