1 |
|
|
// |
2 |
|
|
// Copyright (c) 2014 CNRS |
3 |
|
|
// Authors: Steve Tonneau (steve.tonneau@laas.fr) |
4 |
|
|
// |
5 |
|
|
// This file is part of hpp-rbprm. |
6 |
|
|
// hpp-rbprm is free software: you can redistribute it |
7 |
|
|
// and/or modify it under the terms of the GNU Lesser General Public |
8 |
|
|
// License as published by the Free Software Foundation, either version |
9 |
|
|
// 3 of the License, or (at your option) any later version. |
10 |
|
|
// |
11 |
|
|
// hpp-rbprm is distributed in the hope that it will be |
12 |
|
|
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
13 |
|
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 |
|
|
// General Lesser Public License for more details. You should have |
15 |
|
|
// received a copy of the GNU Lesser General Public License along with |
16 |
|
|
// hpp-core If not, see |
17 |
|
|
// <http://www.gnu.org/licenses/>. |
18 |
|
|
|
19 |
|
|
#ifndef HPP_RBPRM_TIME_CONSTRAINT_HELPER_UTILS_HH |
20 |
|
|
#define HPP_RBPRM_TIME_CONSTRAINT_HELPER_UTILS_HH |
21 |
|
|
|
22 |
|
|
#include <hpp/constraints/generic-transformation.hh> |
23 |
|
|
#include <hpp/core/bi-rrt-planner.hh> |
24 |
|
|
#include <hpp/core/constraint-set.hh> |
25 |
|
|
#include <hpp/core/path-optimization/partial-shortcut.hh> |
26 |
|
|
#include <hpp/core/path-optimization/random-shortcut.hh> |
27 |
|
|
#include <hpp/core/problem-target/goal-configurations.hh> |
28 |
|
|
#include <hpp/core/roadmap.hh> |
29 |
|
|
#include <hpp/core/steering-method/straight.hh> |
30 |
|
|
#include <hpp/rbprm/interpolation/limb-rrt-shooter.hh> |
31 |
|
|
#include <hpp/rbprm/interpolation/time-constraint-path-validation.hh> |
32 |
|
|
#include <hpp/rbprm/interpolation/time-constraint-utils.hh> |
33 |
|
|
#include <hpp/rbprm/interpolation/time-dependant.hh> |
34 |
|
|
// #include <hpp/constraints/position.hh> |
35 |
|
|
// #include <hpp/constraints/orientation.hh> |
36 |
|
|
#include <hpp/constraints/locked-joint.hh> |
37 |
|
|
#include <hpp/core/config-projector.hh> |
38 |
|
|
#include <hpp/core/path-vector.hh> |
39 |
|
|
#include <hpp/core/subchain-path.hh> |
40 |
|
|
#include <hpp/pinocchio/joint.hh> |
41 |
|
|
// #include <hpp/pinocchio/object-factory.hh> |
42 |
|
|
#include <hpp/constraints/relative-com.hh> |
43 |
|
|
#include <hpp/constraints/symbolic-calculus.hh> |
44 |
|
|
#include <hpp/constraints/symbolic-function.hh> |
45 |
|
|
#include <hpp/pinocchio/configuration.hh> |
46 |
|
|
#include <hpp/rbprm/tools.hh> |
47 |
|
|
#include <vector> |
48 |
|
|
namespace hpp { |
49 |
|
|
using namespace core; |
50 |
|
|
namespace rbprm { |
51 |
|
|
namespace interpolation { |
52 |
|
|
|
53 |
|
|
namespace { |
54 |
|
|
inline std::vector<bool> setMaintainRotationConstraints() { |
55 |
|
|
std::vector<bool> res; |
56 |
|
|
for (std::size_t i = 0; i < 3; ++i) res.push_back(true); |
57 |
|
|
return res; |
58 |
|
|
} |
59 |
|
|
} // namespace |
60 |
|
|
|
61 |
|
|
template <class Path_T, class ShooterFactory_T, typename ConstraintFactory_T> |
62 |
|
|
void TimeConstraintHelper<Path_T, ShooterFactory_T, |
63 |
|
|
ConstraintFactory_T>::InitConstraints() { |
64 |
|
|
core::ConstraintSetPtr_t cSet = |
65 |
|
|
core::ConstraintSet::create(rootProblem_->robot(), ""); |
66 |
|
|
cSet->addConstraint(proj_); |
67 |
|
|
rootProblem_->constraints(cSet); |
68 |
|
|
} |
69 |
|
|
|
70 |
|
|
template <class Path_T, class ShooterFactory_T, typename ConstraintFactory_T> |
71 |
|
|
void TimeConstraintHelper<Path_T, ShooterFactory_T, ConstraintFactory_T>:: |
72 |
|
|
SetConfigShooter(const hpp::rbprm::State& from, |
73 |
|
|
const hpp::rbprm::State& to) { |
74 |
|
|
rootProblem_->configurationShooter( |
75 |
|
|
shooterFactory_(fullbody_, refPath_, fullBodyDevice_->configSize() - 1, |
76 |
|
|
from, to, steeringMethod_->tds_, proj_)); |
77 |
|
|
} |
78 |
|
|
|
79 |
|
|
namespace { |
80 |
|
|
inline std::vector<std::string> extractEffectorsName( |
81 |
|
|
const rbprm::T_Limb& limbs) { |
82 |
|
|
std::vector<std::string> res; |
83 |
|
|
for (rbprm::T_Limb::const_iterator cit = limbs.begin(); cit != limbs.end(); |
84 |
|
|
++cit) { |
85 |
|
|
res.push_back(cit->first); |
86 |
|
|
} |
87 |
|
|
return res; |
88 |
|
|
} |
89 |
|
|
|
90 |
|
|
inline void DisableUnNecessaryCollisions(core::Problem& problem, |
91 |
|
|
rbprm::RbPrmLimbPtr_t limb) { |
92 |
|
|
// TODO should we really disable collisions for other bodies ? |
93 |
|
|
tools::RemoveNonLimbCollisionRec<core::Problem>( |
94 |
|
|
problem.robot()->rootJoint(), |
95 |
|
|
//"all", |
96 |
|
|
limb->limb_->name(), problem.collisionObstacles(), problem); |
97 |
|
|
|
98 |
|
|
if (limb->disableEndEffectorCollision_) { |
99 |
|
|
hpp::tools::RemoveEffectorCollision<core::Problem>( |
100 |
|
|
problem, problem.robot()->getJointByName(limb->effector_.name()), |
101 |
|
|
problem.collisionObstacles()); |
102 |
|
|
} |
103 |
|
|
} |
104 |
|
|
|
105 |
|
|
inline void DisableUnNecessaryCollisions( |
106 |
|
|
core::Problem& problem, const std::vector<std::string>& variations, |
107 |
|
|
const rbprm::T_Limb& limbs) { |
108 |
|
|
std::vector<std::string> jointNamesVariations; |
109 |
|
|
for (std::vector<std::string>::const_iterator cit = variations.begin(); |
110 |
|
|
cit != variations.end(); ++cit) { |
111 |
|
|
rbprm::RbPrmLimbPtr_t limb = limbs.at(*cit); |
112 |
|
|
jointNamesVariations.push_back(limb->limb_->name()); |
113 |
|
|
if (limb->disableEndEffectorCollision_) { |
114 |
|
|
hpp::tools::RemoveEffectorCollision<core::Problem>( |
115 |
|
|
problem, problem.robot()->getJointByName(limb->effector_.name()), |
116 |
|
|
problem.collisionObstacles()); |
117 |
|
|
} |
118 |
|
|
} |
119 |
|
|
// TODO should we really disable collisions for other bodies ? |
120 |
|
|
tools::RemoveNonLimbCollisionRec<core::Problem>( |
121 |
|
|
problem.robot()->rootJoint(), jointNamesVariations, |
122 |
|
|
problem.collisionObstacles(), problem); |
123 |
|
|
} |
124 |
|
|
|
125 |
|
|
inline core::PathPtr_t generateRootPath(const core::Problem& problem, |
126 |
|
|
const State& from, const State& to) { |
127 |
|
|
core::Configuration_t startRootConf(from.configuration_); |
128 |
|
|
core::Configuration_t endRootConf(to.configuration_); |
129 |
|
|
return (*(problem.steeringMethod()))(startRootConf, endRootConf); |
130 |
|
|
} |
131 |
|
|
} // namespace |
132 |
|
|
|
133 |
|
|
template <class Path_T, class Shooter_T, typename ConstraintFactory_T> |
134 |
|
|
PathVectorPtr_t |
135 |
|
|
TimeConstraintHelper<Path_T, Shooter_T, ConstraintFactory_T>::Run( |
136 |
|
|
const State& from, const State& to, const size_t maxIterations) { |
137 |
|
|
PathVectorPtr_t res; |
138 |
|
|
SetPathValidation(*this); |
139 |
|
|
const rbprm::T_Limb& limbs = fullbody_->GetLimbs(); |
140 |
|
|
// get limbs that moved |
141 |
|
|
std::vector<std::string> variations = |
142 |
|
|
to.allVariations(from, extractEffectorsName(limbs)); |
143 |
|
|
if (!variations.empty()) { |
144 |
|
|
DisableUnNecessaryCollisions(*rootProblem_, variations, limbs); |
145 |
|
|
} |
146 |
|
|
// TODO IS THIS REDUNDANT ? |
147 |
|
|
/*for(rbprm::CIT_Limb lit = limbs.begin(); lit != limbs.end(); ++lit) |
148 |
|
|
{ |
149 |
|
|
if(lit->second->disableEndEffectorCollision_ && |
150 |
|
|
std::find(variations.begin(), variations.end(), lit->second->limb_->name()) == |
151 |
|
|
variations.end()) |
152 |
|
|
{ |
153 |
|
|
hpp::tools::RemoveEffectorCollision<core::Problem>(rootProblem_, |
154 |
|
|
rootProblem_->robot()->getJointByName(lit->second->effector_->name()), |
155 |
|
|
rootProblem_->collisionObstacles()); |
156 |
|
|
} |
157 |
|
|
}*/ |
158 |
|
|
SetConfigShooter(from, to); |
159 |
|
|
|
160 |
|
|
ConfigurationPtr_t start = TimeConfigFromDevice(*this, from, 0.); |
161 |
|
|
ConfigurationPtr_t end = TimeConfigFromDevice(*this, to, 1.); |
162 |
|
|
hppDout(notice, "Run : start config = r([" << pinocchio::displayConfig(*start) |
163 |
|
|
<< "])"); |
164 |
|
|
hppDout(notice, |
165 |
|
|
"Run : end config = r([" << pinocchio::displayConfig(*end) << "])"); |
166 |
|
|
|
167 |
|
|
rootProblem_->initConfig(start); |
168 |
|
|
BiRRTPlannerPtr_t planner = BiRRTPlanner::create(rootProblem_); |
169 |
|
|
// ProblemTargetPtr_t target = problemTarget::GoalConfigurations::create |
170 |
|
|
// (planner); |
171 |
|
|
ProblemTargetPtr_t target = |
172 |
|
|
problemTarget::GoalConfigurations::create(rootProblem_); |
173 |
|
|
rootProblem_->target(target); |
174 |
|
|
rootProblem_->addGoalConfig(end); |
175 |
|
|
InitConstraints(); |
176 |
|
|
if (maxIterations > 0) planner->maxIterations(maxIterations); |
177 |
|
|
hppDout(notice, "Max iterations : " << maxIterations); |
178 |
|
|
boost::posix_time::ptime timeStart( |
179 |
|
|
boost::posix_time::microsec_clock::universal_time()); |
180 |
|
|
try { |
181 |
|
|
res = planner->solve(); |
182 |
|
|
hppDout(notice, |
183 |
|
|
"TimeConstraintHelper : solved in " |
184 |
|
|
<< ((boost::posix_time::microsec_clock::universal_time() - |
185 |
|
|
timeStart) |
186 |
|
|
.total_milliseconds()) |
187 |
|
|
<< " ms"); |
188 |
|
|
hppDout(notice, "With a roadmap of " << planner->roadmap()->nodes().size() |
189 |
|
|
<< " nodes"); |
190 |
|
|
} catch (std::runtime_error e) { |
191 |
|
|
hppDout(notice, |
192 |
|
|
"TimeConstraintHelper : planner returned an error : " << e.what()); |
193 |
|
|
res = PathVectorPtr_t(); |
194 |
|
|
} catch (core::projection_error e) { |
195 |
|
|
hppDout(notice, "TimeConstraintHelper : Projection error : " << e.what()); |
196 |
|
|
res = PathVectorPtr_t(); |
197 |
|
|
} |
198 |
|
|
|
199 |
|
|
rootProblem_->resetGoalConfigs(); |
200 |
|
|
return res; |
201 |
|
|
} |
202 |
|
|
|
203 |
|
|
namespace { |
204 |
|
|
template <class Helper_T> |
205 |
|
|
PathVectorPtr_t optimize(Helper_T& helper, PathVectorPtr_t partialPath, |
206 |
|
|
const std::size_t numOptimizations) { |
207 |
|
|
core::pathOptimization::RandomShortcutPtr_t rs = |
208 |
|
|
core::pathOptimization::RandomShortcut::create(helper.rootProblem_); |
209 |
|
|
for (std::size_t j = 0; j < numOptimizations; ++j) { |
210 |
|
|
hppDout(notice, "Optimize random shortucut, iter : " << j); |
211 |
|
|
partialPath = rs->optimize(partialPath); |
212 |
|
|
} |
213 |
|
|
core::pathOptimization::PartialShortcutPtr_t rs2 = |
214 |
|
|
core::pathOptimization::PartialShortcut::create(helper.rootProblem_); |
215 |
|
|
for (std::size_t j = 0; j < numOptimizations; ++j) { |
216 |
|
|
hppDout(notice, "Optimize partial shortcut, iter : " << j); |
217 |
|
|
partialPath = rs2->optimize(partialPath); |
218 |
|
|
} |
219 |
|
|
return partialPath; |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
inline std::size_t checkPath(const std::size_t& distance, bool valid[]) { |
223 |
|
|
std::size_t numValid(distance); |
224 |
|
|
for (std::size_t i = 0; i < distance; ++i) { |
225 |
|
|
if (!valid[i]) { |
226 |
|
|
numValid = i; |
227 |
|
|
break; |
228 |
|
|
} |
229 |
|
|
} |
230 |
|
|
// if (numValid==0) |
231 |
|
|
// throw std::runtime_error("No path found at state 0"); |
232 |
|
|
/*else */ if (numValid != distance) { |
233 |
|
|
std::cout << "No path found at state " << numValid << std::endl; |
234 |
|
|
} |
235 |
|
|
return numValid; |
236 |
|
|
} |
237 |
|
|
|
238 |
|
|
inline PathPtr_t ConcatenateAndResizePath(PathVectorPtr_t res[], |
239 |
|
|
std::size_t numValid, |
240 |
|
|
const bool keepExtraDof, |
241 |
|
|
hpp::pinocchio::DevicePtr_t device) { |
242 |
|
|
PathVectorPtr_t completePath = res[0]; |
243 |
|
|
for (std::size_t i = 1; i < numValid; ++i) { |
244 |
|
|
completePath->concatenate(res[i]); |
245 |
|
|
} |
246 |
|
|
PathVectorPtr_t flat = core::PathVector::create( |
247 |
|
|
completePath->outputSize(), completePath->outputDerivativeSize()); |
248 |
|
|
completePath->flatten( |
249 |
|
|
flat); // assure that there is no pathVector inside a pathVector |
250 |
|
|
hppDout(notice, |
251 |
|
|
"end of interpolateStatesFromPath, number of paths in pathVector : " |
252 |
|
|
<< flat->numberPaths()); |
253 |
|
|
if (keepExtraDof) { |
254 |
|
|
return flat; |
255 |
|
|
} else { |
256 |
|
|
// reducing path (remove last value of the configuration) |
257 |
|
|
core::segment_t interval(0, flat->initial().rows() - 1); |
258 |
|
|
core::segments_t intervals; |
259 |
|
|
intervals.push_back(interval); |
260 |
|
|
core::segments_t velIntervals(1, |
261 |
|
|
core::segment_t(0, device->numberDof() - 1)); |
262 |
|
|
PathVectorPtr_t reducedPV = core::PathVector::create( |
263 |
|
|
flat->outputSize() - 1, flat->outputDerivativeSize() - 1); |
264 |
|
|
for (std::size_t pid = 0; pid < flat->numberPaths(); ++pid) { |
265 |
|
|
reducedPV->appendPath(core::SubchainPath::create( |
266 |
|
|
flat->pathAtRank(pid), intervals, velIntervals)); |
267 |
|
|
} |
268 |
|
|
return reducedPV; |
269 |
|
|
} |
270 |
|
|
} |
271 |
|
|
} // namespace |
272 |
|
|
|
273 |
|
|
struct GenPath { |
274 |
|
|
GenPath(const core::Problem& problem) : problem_(problem) {} |
275 |
|
|
~GenPath() {} |
276 |
|
|
PathPtr_t operator()(const CIT_State& from, const CIT_State& to) const { |
277 |
|
|
return interpolation::generateRootPath(problem_, *from, *to); |
278 |
|
|
} |
279 |
|
|
const core::Problem& problem_; |
280 |
|
|
}; |
281 |
|
|
|
282 |
|
|
struct ExtractPath { |
283 |
|
|
ExtractPath(PathPtr_t refPath) : refPath_(refPath) {} |
284 |
|
|
~ExtractPath() {} |
285 |
|
|
PathPtr_t operator()(const CIT_StateFrame& from, CIT_StateFrame& to) const { |
286 |
|
|
return refPath_->extract(core::interval_t(from->first, to->first)); |
287 |
|
|
} |
288 |
|
|
PathPtr_t refPath_; |
289 |
|
|
}; |
290 |
|
|
|
291 |
|
|
inline const State& get(const CIT_StateFrame& from) { return from->second; } |
292 |
|
|
|
293 |
|
|
inline const State& get(const CIT_State& from) { return *from; } |
294 |
|
|
|
295 |
|
|
template <class Helper_T, class StateIterator_T, class ShooterFactory_T, |
296 |
|
|
typename ConstraintFactory_T, class PathGetter_T> |
297 |
|
|
PathPtr_t interpolateStatesFromPathGetter( |
298 |
|
|
RbPrmFullBodyPtr_t fullbody, core::ProblemPtr_t referenceProblem, |
299 |
|
|
const ShooterFactory_T& shooterFactory, |
300 |
|
|
const ConstraintFactory_T& constraintFactory, |
301 |
|
|
const PathGetter_T& pathGetter, const StateIterator_T& startState, |
302 |
|
|
const StateIterator_T& endState, const std::size_t numOptimizations, |
303 |
|
|
const bool keepExtraDof = false, |
304 |
|
|
const pinocchio::value_type error_treshold = 0.001, |
305 |
|
|
const size_t maxIterations = 0) { |
306 |
|
|
hppDout(notice, "Begin interpolateStatesFromPathGetter :"); |
307 |
|
|
pinocchio::Computation_t flag = fullbody->device_->computationFlag(); |
308 |
|
|
pinocchio::Computation_t newflag = static_cast<pinocchio::Computation_t>( |
309 |
|
|
pinocchio::JOINT_POSITION | pinocchio::JACOBIAN | pinocchio::COM); |
310 |
|
|
fullbody->device_->controlComputation(newflag); |
311 |
|
|
PathVectorPtr_t res[100]; |
312 |
|
|
bool valid[100]; |
313 |
|
|
std::size_t distance = std::distance(startState, endState); |
314 |
|
|
assert(distance < 100); |
315 |
|
|
// treat each interpolation between two states separatly |
316 |
|
|
// in a different thread |
317 |
|
|
hppDout(notice, "InterpolateStates from path : distance = " << distance); |
318 |
|
|
std::size_t numValid; |
319 |
|
|
do { |
320 |
|
|
#pragma omp parallel for |
321 |
|
|
for (std::size_t i = 0; i < distance; ++i) { |
322 |
|
|
StateIterator_T a, b; |
323 |
|
|
a = (startState + i); |
324 |
|
|
b = (startState + i + 1); |
325 |
|
|
Helper_T helper(fullbody, shooterFactory, constraintFactory, |
326 |
|
|
referenceProblem, pathGetter(a, b), |
327 |
|
|
error_treshold); // 0.1 : error |
328 |
|
|
helper.SetConstraints(get(a), get(b)); |
329 |
|
|
hppDout(notice, "Start helper.run :"); |
330 |
|
|
PathVectorPtr_t partialPath = helper.Run(get(a), get(b), maxIterations); |
331 |
|
|
hppDout(notice, "helper.run done."); |
332 |
|
|
if (partialPath) { |
333 |
|
|
res[i] = optimize(helper, partialPath, numOptimizations); |
334 |
|
|
valid[i] = true; |
335 |
|
|
} else { |
336 |
|
|
hppDout(notice, |
337 |
|
|
"InterpolateStates : helper.run returned an empty path"); |
338 |
|
|
valid[i] = false; |
339 |
|
|
} |
340 |
|
|
} |
341 |
|
|
numValid = checkPath(distance, valid); |
342 |
|
|
} while (numValid < distance); |
343 |
|
|
|
344 |
|
|
fullbody->device_->controlComputation(flag); |
345 |
|
|
return ConcatenateAndResizePath(res, numValid, keepExtraDof, |
346 |
|
|
fullbody->device_); |
347 |
|
|
} |
348 |
|
|
|
349 |
|
|
template <class Helper_T, class ShooterFactory_T, typename ConstraintFactory_T> |
350 |
|
|
PathPtr_t interpolateStatesFromPath( |
351 |
|
|
RbPrmFullBodyPtr_t fullbody, core::ProblemPtr_t referenceProblem, |
352 |
|
|
const ShooterFactory_T& shooterFactory, |
353 |
|
|
const ConstraintFactory_T& constraintFactory, const PathPtr_t refPath, |
354 |
|
|
const CIT_StateFrame& startState, const CIT_StateFrame& endState, |
355 |
|
|
const std::size_t numOptimizations, const bool keepExtraDof, |
356 |
|
|
const value_type error_treshold, const size_t maxIterations) { |
357 |
|
|
ExtractPath extractPath(refPath); |
358 |
|
|
return interpolateStatesFromPathGetter<Helper_T, CIT_StateFrame, |
359 |
|
|
ShooterFactory_T, ConstraintFactory_T, |
360 |
|
|
ExtractPath>( |
361 |
|
|
fullbody, referenceProblem, shooterFactory, constraintFactory, |
362 |
|
|
extractPath, startState, endState, numOptimizations, keepExtraDof, |
363 |
|
|
error_treshold, maxIterations); |
364 |
|
|
} |
365 |
|
|
|
366 |
|
|
template <class Helper_T, class ShooterFactory_T, typename ConstraintFactory_T, |
367 |
|
|
typename StateConstIterator> |
368 |
|
|
PathPtr_t interpolateStates( |
369 |
|
|
RbPrmFullBodyPtr_t fullbody, core::ProblemPtr_t referenceProblem, |
370 |
|
|
const ShooterFactory_T& shooterFactory, |
371 |
|
|
const ConstraintFactory_T& constraintFactory, |
372 |
|
|
const StateConstIterator& startState, const StateConstIterator& endState, |
373 |
|
|
const std::size_t numOptimizations, const bool keepExtraDof, |
374 |
|
|
const value_type error_treshold, const size_t maxIterations) { |
375 |
|
|
GenPath genPath(*referenceProblem); |
376 |
|
|
return interpolateStatesFromPathGetter<Helper_T, StateConstIterator, |
377 |
|
|
ShooterFactory_T, ConstraintFactory_T, |
378 |
|
|
GenPath>( |
379 |
|
|
fullbody, referenceProblem, shooterFactory, constraintFactory, genPath, |
380 |
|
|
startState, endState, numOptimizations, keepExtraDof, error_treshold, |
381 |
|
|
maxIterations); |
382 |
|
|
} |
383 |
|
|
|
384 |
|
|
} // namespace interpolation |
385 |
|
|
} // namespace rbprm |
386 |
|
|
} // namespace hpp |
387 |
|
|
|
388 |
|
|
#endif // HPP_RBPRM_TIME_CONSTRAINT_HELPER_UTILS_HH |