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

WIP: fix asymptotically infinite loop with Dichotomy #334

Draft
wants to merge 6 commits into
base: devel
Choose a base branch
from
Draft
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
9 changes: 9 additions & 0 deletions include/hpp/core/continuous-validation.hh
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ class HPP_CORE_DLLAPI ContinuousValidation : public PathValidation,
/// \sa value_type breakDistance() const
void breakDistance(value_type distance);

/// TODO
value_type distanceLowerBoundThreshold() const {
return distanceLowerBoundThr_;
}

/// TODO
void distanceLowerBoundThreshold(value_type distance);

DevicePtr_t robot() const { return robot_; }
/// Iteratively call method doExecute of delegate classes Initialize
/// \sa ContinuousValidation::add, ContinuousValidation::Initialize.
Expand Down Expand Up @@ -300,6 +308,7 @@ class HPP_CORE_DLLAPI ContinuousValidation : public PathValidation,
DevicePtr_t robot_;
value_type tolerance_;
value_type breakDistance_;
value_type distanceLowerBoundThr_;

/// Store weak pointer to itself.
void init(ContinuousValidationWkPtr_t weak);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ class BodyPairCollision : public IntervalValidation {
void securityMargin(const value_type& securityMargin) {
for (auto& request : m_->requests) request.security_margin = securityMargin;
}

/// TODO
void distanceLowerBoundThreshold(value_type distance);
/// \}
protected:
/// Constructor of body pair collision
Expand All @@ -126,7 +129,8 @@ class BodyPairCollision : public IntervalValidation {
BodyPairCollision(const BodyPairCollision& other)
: IntervalValidation(other),
m_(other.m_),
maximalVelocity_(other.maximalVelocity_) {}
maximalVelocity_(other.maximalVelocity_),
distanceLowerBoundThr_(other.distanceLowerBoundThr_) {}

virtual void setReport(ValidationReportPtr_t& report,
fcl::CollisionResult result,
Expand All @@ -146,6 +150,7 @@ class BodyPairCollision : public IntervalValidation {

mutable vector_t Vb_;
value_type maximalVelocity_;
value_type distanceLowerBoundThr_;

/// Compute maximal velocity for a given velocity bound
/// \param Vb velocity
Expand Down
4 changes: 3 additions & 1 deletion include/hpp/core/path-optimization/quadratic-program.hh
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,13 @@ struct QuadraticProgram {
/// Compute solution using quadprog
/// \param ce equality constraints
/// \param ci inequality constraints: \f$ ci.J * x \ge ci.b \f$
/// \param[out] ok is set to true if a solution has been found.
/// \return the cost of the solution.
///
/// \note \ref computeLLT must have been called before.
/// \note if the problem is ill-conditioned, member xStar is left unchanged.
double solve(const LinearConstraint& ce, const LinearConstraint& ci);
double solve(const LinearConstraint& ce, const LinearConstraint& ci,
bool& ok);

/// \}

Expand Down
25 changes: 25 additions & 0 deletions src/continuous-validation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ void ContinuousValidation::Initialize::doExecute() const {
continuousValidation::SolidSolidCollisionPtr_t ss(
SolidSolidCollision::create(joint2, joint1, owner().tolerance_));
ss->breakDistance(owner().breakDistance());
ss->distanceLowerBoundThreshold(owner().distanceLowerBoundThreshold());
owner().addIntervalValidation(ss);
bodyPairMap[jp] = ss;
}
Expand All @@ -112,6 +113,7 @@ void ContinuousValidation::AddObstacle::doExecute(
continuousValidation::SolidSolidCollisionPtr_t ss(
SolidSolidCollision::create(joint, objects, owner().tolerance()));
ss->breakDistance(owner().breakDistance());
ss->distanceLowerBoundThreshold(owner().distanceLowerBoundThreshold());
owner().addIntervalValidation(ss);
}
}
Expand Down Expand Up @@ -253,6 +255,11 @@ void ContinuousValidation::removeObstacleFromJoint(

void ContinuousValidation::breakDistance(value_type distance) {
assert(distance >= 0);
if (distance <= distanceLowerBoundThr_) {
throw std::invalid_argument(
"Break distance must be strictly greater than "
"the distance lower bound threshold.");
}
breakDistance_ = distance;

bodyPairCollisionPool_.clear();
Expand All @@ -263,6 +270,23 @@ void ContinuousValidation::breakDistance(value_type distance) {
}
}

void ContinuousValidation::distanceLowerBoundThreshold(value_type distance) {
assert(distance >= 0);
if (distance >= breakDistance_) {
throw std::invalid_argument(
"Distance lower bound threshold must be "
"strictly smaller than the break distance.");
}
distanceLowerBoundThr_ = distance;

bodyPairCollisionPool_.clear();
for (IntervalValidationPtr_t &val : intervalValidations_) {
continuousValidation::BodyPairCollisionPtr_t bp(
HPP_DYNAMIC_PTR_CAST(continuousValidation::BodyPairCollision, val));
if (bp) bp->distanceLowerBoundThreshold(distance);
}
}

void ContinuousValidation::filterCollisionPairs(
const RelativeMotion::matrix_type &relMotion) {
// Loop over collision pairs and remove disabled ones.
Expand Down Expand Up @@ -409,6 +433,7 @@ ContinuousValidation::ContinuousValidation(const DevicePtr_t &robot,
: robot_(robot),
tolerance_(tolerance),
breakDistance_(1e-2),
distanceLowerBoundThr_(0.0),
intervalValidations_(),
weak_() {
if (tolerance < 0) {
Expand Down
21 changes: 21 additions & 0 deletions src/continuous-validation/body-pair-collision.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ namespace core {
namespace continuousValidation {
using ::pinocchio::toFclTransform3f;

void BodyPairCollision::distanceLowerBoundThreshold(value_type distance) {
distanceLowerBoundThr_ = distance;
}

bool BodyPairCollision::validateConfiguration(
const value_type& t, interval_t& interval, ValidationReportPtr_t& report,
const pinocchio::DeviceData& data) {
Expand Down Expand Up @@ -194,6 +198,7 @@ bool BodyPairCollision::computeDistanceLowerBound(
const CollisionPairs_t& prs(pairs());
CollisionRequests_t& rqsts(requests());
assert(rqsts.size() == prs.size());
std::size_t iSmallest = prs.size();
for (std::size_t i = 0; i < prs.size(); ++i) {
assert(rqsts[i].enable_distance_lower_bound == true);
fcl::CollisionResult result;
Expand All @@ -204,10 +209,26 @@ bool BodyPairCollision::computeDistanceLowerBound(
return false;
}
if (result.distance_lower_bound < distanceLowerBound) {
iSmallest = i;
distanceLowerBound = result.distance_lower_bound;
assert(distanceLowerBound > 0);
}
}
if (distanceLowerBound < distanceLowerBoundThr_) {
hppDout(info, "Trigerring a fake collision because distance lower bound is "
<< distanceLowerBound);
fcl::CollisionRequest req(rqsts[iSmallest]);
req.security_margin += distanceLowerBoundThr_;
fcl::CollisionResult result;
prs[iSmallest].collide(data, req, result);
if (!result.isCollision()) {
hppDout(warning,
"No collision detected while distance lower bound is small.");
return true;
}
setReport(report, result, prs[iSmallest]);
return false;
}
return true;
}
} // namespace continuousValidation
Expand Down
9 changes: 5 additions & 4 deletions src/continuous-validation/dichotomy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ bool Dichotomy::validateStraightPath(IntervalValidations_t& bodyPairCollisions,
} else {
validPart = path;
}
std::cout << niters << '\n';
HPP_STOP_AND_DISPLAY_TIMECOUNTER(CV_Dichotomy_validateStraightPath);
if (niters > 1000) {
hppDout(notice,
Expand All @@ -137,14 +138,14 @@ void Dichotomy::init(const DichotomyWkPtr_t weak) {
}

Dichotomy::Dichotomy(const DevicePtr_t& robot, const value_type& tolerance)
: ContinuousValidation(robot, tolerance), weak_() {
: ContinuousValidation(robot, 0.0), weak_() {
// Tolerance should be equal to 0, otherwise end of valid
// sub-path might be in collision.
if (tolerance != 0) {
if (tolerance > 0) {
throw std::runtime_error(
"Dichotomy path validation method does not"
"support penetration.");
"Tolerance should be negative for continuous validation by dichotomy.");
}
distanceLowerBoundThreshold(-tolerance);
}
} // namespace continuousValidation
} // namespace core
Expand Down
8 changes: 7 additions & 1 deletion src/path-optimization/quadratic-program.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void QuadraticProgram::computeLLT() {
}

double QuadraticProgram::solve(const LinearConstraint& ce,
const LinearConstraint& ci) {
const LinearConstraint& ci, bool& ok) {
if (ce.J.rows() > ce.J.cols())
throw std::runtime_error(
"The QP is over-constrained. QuadProg cannot handle it.");
Expand All @@ -82,11 +82,15 @@ double QuadraticProgram::solve(const LinearConstraint& ce,
switch (status) {
case Eigen::UNBOUNDED:
hppDout(warning, "Quadratic problem is not bounded");
ok = false;
break;
case Eigen::CONVERGED:
ok = true;
break;
case Eigen::CONSTRAINT_LINEARLY_DEPENDENT:
hppDout(error,
"Constraint of quadratic problem are linearly dependent.");
ok = false;
break;
}
return cost;
Expand All @@ -110,8 +114,10 @@ double QuadraticProgram::solve(const LinearConstraint& ce,
value_type res(0);
Eigen::IOFormat fullPrecision(Eigen::FullPrecision, Eigen::DontAlignCols,
", ", ", ", "", "", " << ", ";");
ok = false;
switch (qp.results.info.status) {
case QPSolverOutput::PROXQP_SOLVED:
ok = true;
xStar = qp.results.x;
res += (.5 * xStar.transpose() * H * xStar)(0, 0);
res += (b.transpose() * xStar)(0);
Expand Down
18 changes: 15 additions & 3 deletions src/path-optimization/spline-gradient-based.cc
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,9 @@ PathVectorPtr_t SplineGradientBased<_PB, _SO>::optimize(
// There are no variables left for optimization.
return this->buildPathVector(splines);
QPc.computeLLT();
QPc.solve(collisionReduced, boundConstraintReduced);
bool qpSolved;
QPc.solve(collisionReduced, boundConstraintReduced, qpSolved);
if (!qpSolved) return this->buildPathVector(splines);

while (!(noCollision && minimumReached) && !this->shouldStop()) {
// 6.1
Expand Down Expand Up @@ -537,7 +539,10 @@ PathVectorPtr_t SplineGradientBased<_PB, _SO>::optimize(
if (linearizeAtEachStep) {
collisionFunctions.linearize(splines, solvers, collision);
constraint.reduceConstraint(collision, collisionReduced);
QPc.solve(collisionReduced, boundConstraintReduced);
QPc.solve(collisionReduced, boundConstraintReduced, qpSolved);
if (!qpSolved) {
hppDout(error, "could not solve qp problem");
}
hppDout(info, "linearized");
computeOptimum = true;
}
Expand Down Expand Up @@ -571,6 +576,13 @@ PathVectorPtr_t SplineGradientBased<_PB, _SO>::optimize(
collisionFunctions.functions.size() - 1,
splines[reports[i].second], solvers[reports[i].second]);
if (!ok) break;
QPc.solve(collisionReduced, boundConstraintReduced, ok);
if (!ok) {
hppDout(info, "could not solve QP. Removing constraint");
collisionFunctions.removeLastConstraint(1, collision);
constraint.reduceConstraint(collision, collisionReduced);
break;
}
if (QPc.H.rows() <= collisionReduced.rank) break;
}

Expand All @@ -587,7 +599,7 @@ PathVectorPtr_t SplineGradientBased<_PB, _SO>::optimize(

computeInterpolatedSpline = true;
} else {
QPc.solve(collisionReduced, boundConstraintReduced);
QPc.solve(collisionReduced, boundConstraintReduced, qpSolved);
hppDout(info, "Added " << reports.size()
<< " constraints. "
"Constraints size "
Expand Down
14 changes: 10 additions & 4 deletions src/path/spline.cc
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,11 @@ void Spline<_SplineType, _Order>::impl_derivative(vectorOut_t res,
// at a higher order. At the d2+/dv2 is not available for SE(n) and SO(n).
assert(order == 1 || robot_->configSpace()->isVectorSpace());
BasisFunctionVector_t basisFunc;
const value_type u =
(length() == 0 ? 0 : (s - paramRange().first) / paramLength());
value_type u = (length() == 0 ? 0 : (s - paramRange().first) / paramLength());
// Due to numerical errors, u might be outside range [0, 1]
assert(u >= -1e-12);
assert(u - 1 <= 1e-12);
u = std::min(1.0, std::max(u, 0.0));
basisFunctionDerivative(order, u, basisFunc);
res.noalias() = parameters_.transpose() * basisFunc;

Expand All @@ -399,8 +402,11 @@ template <int _SplineType, int _Order>
void Spline<_SplineType, _Order>::impl_paramDerivative(
vectorOut_t res, const value_type& s) const {
BasisFunctionVector_t basisFunc;
const value_type u =
(length() == 0 ? 0 : (s - paramRange().first) / paramLength());
value_type u = (length() == 0 ? 0 : (s - paramRange().first) / paramLength());
// Due to numerical errors, u might be outside range [0, 1]
assert(u >= -1e-12);
assert(u - 1 <= 1e-12);
u = std::min(1.0, std::max(u, 0.0));
basisFunctionDerivative(0, u, basisFunc);
res = basisFunc;

Expand Down
Loading