GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
// |
||
2 |
// Copyright (c) 2017 CNRS |
||
3 |
// Authors: Pierre Fernbach |
||
4 |
// |
||
5 |
// This file is part of hpp-rbprm |
||
6 |
// hpp-core 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-core 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 |
#include <cstdlib> |
||
20 |
#include <deque> |
||
21 |
#include <hpp/core/config-validations.hh> |
||
22 |
#include <hpp/core/distance.hh> |
||
23 |
#include <hpp/core/kinodynamic-oriented-path.hh> |
||
24 |
#include <hpp/core/path-projector.hh> |
||
25 |
#include <hpp/core/path-validation.hh> |
||
26 |
#include <hpp/core/path-vector.hh> |
||
27 |
#include <hpp/core/problem.hh> |
||
28 |
#include <hpp/rbprm/planner/random-shortcut-dynamic.hh> |
||
29 |
#include <hpp/rbprm/planner/rbprm-node.hh> |
||
30 |
#include <hpp/util/assertion.hh> |
||
31 |
#include <hpp/util/debug.hh> |
||
32 |
#include <hpp/util/timer.hh> |
||
33 |
#include <limits> |
||
34 |
|||
35 |
namespace hpp { |
||
36 |
namespace rbprm { |
||
37 |
using core::Configuration_t; |
||
38 |
using core::ConfigurationIn_t; |
||
39 |
using core::ConfigurationPtr_t; |
||
40 |
using core::DistancePtr_t; |
||
41 |
using core::KinodynamicOrientedPath; |
||
42 |
using core::KinodynamicOrientedPathPtr_t; |
||
43 |
using core::KinodynamicPath; |
||
44 |
using core::KinodynamicPathPtr_t; |
||
45 |
using core::PathPtr_t; |
||
46 |
using core::PathVector; |
||
47 |
using core::PathVectorPtr_t; |
||
48 |
using core::Problem; |
||
49 |
using pinocchio::value_type; |
||
50 |
|||
51 |
69 |
RandomShortcutDynamicPtr_t RandomShortcutDynamic::create( |
|
52 |
core::ProblemConstPtr_t problem) { |
||
53 |
✓✗✓✗ |
69 |
RandomShortcutDynamic* ptr = new RandomShortcutDynamic(problem); |
54 |
69 |
return RandomShortcutDynamicPtr_t(ptr); |
|
55 |
} |
||
56 |
|||
57 |
69 |
RandomShortcutDynamic::RandomShortcutDynamic(core::ProblemConstPtr_t problem) |
|
58 |
: RandomShortcut(problem), |
||
59 |
sm_(dynamic_pointer_cast<SteeringMethodKinodynamic>( |
||
60 |
138 |
problem->steeringMethod())), |
|
61 |
rbprmPathValidation_(dynamic_pointer_cast<RbPrmPathValidation>( |
||
62 |
207 |
problem->pathValidation())) { |
|
63 |
✓✗ | 69 |
assert(sm_ && |
64 |
"Random-shortcut-dynamic must use a kinodynamic-steering-method"); |
||
65 |
✓✗ | 69 |
assert( |
66 |
rbprmPathValidation_ && |
||
67 |
"Path validation should be a RbPrmPathValidation class for this solver"); |
||
68 |
|||
69 |
// retrieve parameters from problem : |
||
70 |
✓✗✓✗ |
138 |
sizeFootX_ = problem->getParameter(std::string("DynamicPlanner/sizeFootX")) |
71 |
✓✗ | 69 |
.floatValue() / |
72 |
2.; |
||
73 |
✓✗✓✗ |
138 |
sizeFootY_ = problem->getParameter(std::string("DynamicPlanner/sizeFootY")) |
74 |
✓✗ | 69 |
.floatValue() / |
75 |
2.; |
||
76 |
✓✗✓✗ |
69 |
if (sizeFootX_ > 0. && sizeFootY_ > 0.) |
77 |
69 |
rectangularContact_ = 1; |
|
78 |
else |
||
79 |
rectangularContact_ = 0; |
||
80 |
69 |
tryJump_ = |
|
81 |
✓✗✓✗ ✓✗ |
69 |
problem->getParameter(std::string("DynamicPlanner/tryJump")).boolValue(); |
82 |
hppDout(notice, "tryJump in steering method = " << tryJump_); |
||
83 |
✓✗✓✗ |
138 |
mu_ = problem->getParameter(std::string("DynamicPlanner/friction")) |
84 |
✓✗ | 69 |
.floatValue(); |
85 |
hppDout(notice, "mu define in python : " << mu_); |
||
86 |
69 |
} |
|
87 |
|||
88 |
// Compute the length of a vector of paths assuming that each element |
||
89 |
// is optimal for the given distance. |
||
90 |
template <bool reEstimateLength = false> |
||
91 |
struct PathLength { |
||
92 |
34728 |
static inline value_type run(const PathVectorPtr_t& path, |
|
93 |
const DistancePtr_t& /*distance*/) { |
||
94 |
if (reEstimateLength) |
||
95 |
25942 |
return path->length(); |
|
96 |
else { |
||
97 |
8786 |
value_type result = 0; |
|
98 |
✓✓ | 102874 |
for (std::size_t i = 0; i < path->numberPaths(); ++i) { |
99 |
✓✗ | 94088 |
const PathPtr_t& element(path->pathAtRank(i)); |
100 |
✓✗ | 94088 |
result += element->length(); |
101 |
} |
||
102 |
8786 |
return result; |
|
103 |
} |
||
104 |
} |
||
105 |
}; |
||
106 |
|||
107 |
69 |
PathVectorPtr_t RandomShortcutDynamic::optimize(const PathVectorPtr_t& path) { |
|
108 |
hppDout(notice, "!! Start optimize()"); |
||
109 |
hppStartBenchmark(RANDOM_SHORTCUT); |
||
110 |
using std::make_pair; |
||
111 |
using std::numeric_limits; |
||
112 |
69 |
bool finished = false; |
|
113 |
value_type t[4]; |
||
114 |
✓✓✓✗ ✓✓✗✗ |
690 |
Configuration_t q[4]; |
115 |
✓✗ | 69 |
q[0] = path->initial(); |
116 |
✓✗ | 69 |
q[3] = path->end(); |
117 |
138 |
PathVectorPtr_t tmpPath = path; |
|
118 |
|||
119 |
// Maximal number of iterations without improvements |
||
120 |
std::size_t n = |
||
121 |
69 |
problem() |
|
122 |
✓✗✓✗ |
138 |
->getParameter("PathOptimization/RandomShortcut/NumberOfLoops") |
123 |
✓✗ | 69 |
.intValue(); |
124 |
69 |
std::size_t projectionError = n; |
|
125 |
✓✗ | 138 |
std::deque<value_type> length(n - 1, numeric_limits<value_type>::infinity()); |
126 |
✓✗✓✗ |
69 |
length.push_back(PathLength<>::run(tmpPath, problem()->distance())); |
127 |
69 |
PathVectorPtr_t result; |
|
128 |
✓✗✓✗ |
138 |
Configuration_t q1(path->outputSize()), q2(path->outputSize()); |
129 |
|||
130 |
✓✗ | 69 |
q[1] = q1; |
131 |
✓✗ | 69 |
q[2] = q2; |
132 |
✓✗ | 69 |
double minBetweenPoint = std::min(1., tmpPath->length() * 0.2); |
133 |
hppDout(notice, "minBetweenPoints = " << minBetweenPoint); |
||
134 |
✓✓✓✓ |
4393 |
while (!finished && projectionError != 0) { |
135 |
4324 |
t[0] = tmpPath->timeRange().first; |
|
136 |
4324 |
t[3] = tmpPath->timeRange().second; |
|
137 |
869 |
do { // avoid to sample point too close of eachother, FIXME : remove |
|
138 |
// hardcoded value of 1 and find a way to compute it (a percentage of |
||
139 |
// total time ?) |
||
140 |
5193 |
value_type u2 = t[0] + minBetweenPoint + |
|
141 |
5193 |
(t[3] - t[0] - 2 * minBetweenPoint) * rand() / RAND_MAX; |
|
142 |
5193 |
value_type u1 = t[0] + minBetweenPoint + |
|
143 |
5193 |
(t[3] - t[0] - 2 * minBetweenPoint) * rand() / RAND_MAX; |
|
144 |
✓✓ | 5193 |
if (u1 < u2) { |
145 |
2582 |
t[1] = u1; |
|
146 |
2582 |
t[2] = u2; |
|
147 |
} else { |
||
148 |
2611 |
t[1] = u2; |
|
149 |
2611 |
t[2] = u1; |
|
150 |
} |
||
151 |
10386 |
} while (((t[1] - t[0]) < minBetweenPoint) || |
|
152 |
✓✗✓✗ |
5193 |
((t[3] - t[2]) < minBetweenPoint) || |
153 |
✓✓ | 5193 |
t[2] - t[1] < minBetweenPoint); |
154 |
✓✗✓✗ ✗✓ |
4324 |
if (!(*tmpPath)(q[1], t[1])) { |
155 |
hppDout(error, "Configuration at param " << t[1] |
||
156 |
<< " could not be " |
||
157 |
"projected"); |
||
158 |
projectionError--; |
||
159 |
continue; |
||
160 |
} |
||
161 |
✓✗✓✗ ✗✓ |
4324 |
if (!(*tmpPath)(q[2], t[2])) { |
162 |
hppDout(error, "Configuration at param " << t[2] |
||
163 |
<< " could not be " |
||
164 |
"projected"); |
||
165 |
projectionError--; |
||
166 |
continue; |
||
167 |
} |
||
168 |
// Validate sub parts |
||
169 |
bool valid[3]; |
||
170 |
✓✓✗✗ |
17296 |
PathPtr_t straight[3]; |
171 |
4324 |
core::PathValidationReportPtr_t report; |
|
172 |
4324 |
PathPtr_t validPart; |
|
173 |
|||
174 |
✓✓ | 17296 |
for (unsigned i = 0; i < 3; ++i) { |
175 |
✓✗✓✗ ✓✗ |
12972 |
straight[i] = steer(q[i], q[i + 1]); |
176 |
✓✓ | 12972 |
if (!straight[i]) |
177 |
1 |
valid[i] = false; |
|
178 |
else { // with kinodynamic path, we are not assured that a 'straight |
||
179 |
// line' is shorter than the previously found path |
||
180 |
12971 |
valid[i] = |
|
181 |
✓✗ | 12971 |
(straight[i]->length() < |
182 |
✓✗ | 25942 |
PathLength<true>::run( |
183 |
✓✗✓✗ ✓✗ |
25942 |
tmpPath->extract(make_pair(t[i], t[i + 1]))->as<PathVector>(), |
184 |
25942 |
problem()->distance())); |
|
185 |
✓✓ | 12971 |
if (valid[i]) |
186 |
8234 |
valid[i] = problem()->pathValidation()->validate(straight[i], false, |
|
187 |
✓✗ | 4117 |
validPart, report); |
188 |
} |
||
189 |
} |
||
190 |
hppDout(notice, "t0 = " << t[0] << " ; t1 = " << t[1] << " ; t2 = " << t[2] |
||
191 |
<< " ; t3 = " << t[3]); |
||
192 |
hppDout(notice, "first segment : valid : " << valid[0]); |
||
193 |
hppDout(notice, "mid segment : valid : " << valid[1]); |
||
194 |
hppDout(notice, "last segment : valid : " << valid[2]); |
||
195 |
|||
196 |
// Replace valid parts |
||
197 |
result = |
||
198 |
✓✗ | 4324 |
PathVector::create(path->outputSize(), path->outputDerivativeSize()); |
199 |
|||
200 |
✓✓ | 17296 |
for (unsigned i = 0; i < 3; ++i) { |
201 |
try { |
||
202 |
✓✓ | 12972 |
if (valid[i]) |
203 |
✓✗ | 1714 |
result->appendPath(straight[i]); |
204 |
else |
||
205 |
✓✗ | 22516 |
result->concatenate( |
206 |
✓✗✓✗ ✓✗ |
22516 |
tmpPath->extract(make_pair(t[i], t[i + 1]))->as<PathVector>()); |
207 |
} catch (const core::projection_error& e) { |
||
208 |
hppDout(error, "Caught exception at with time " |
||
209 |
<< t[i] << " and " << t[i + 1] << ": " << e.what()); |
||
210 |
projectionError--; |
||
211 |
result = tmpPath; |
||
212 |
continue; |
||
213 |
} |
||
214 |
} |
||
215 |
core::value_type newLength = |
||
216 |
✓✗ | 4324 |
PathLength<>::run(result, problem()->distance()); |
217 |
4324 |
if ((length[n - 1] - newLength) <= |
|
218 |
✓✓ | 4324 |
10. * std::numeric_limits<core::value_type>::epsilon()) { |
219 |
hppDout(info, "the length would increase:" << length[n - 1] << " " |
||
220 |
<< newLength); |
||
221 |
3927 |
result = tmpPath; |
|
222 |
3927 |
projectionError--; |
|
223 |
} else { |
||
224 |
✓✗ | 397 |
length.push_back(newLength); |
225 |
397 |
length.pop_front(); |
|
226 |
397 |
finished = (length[0] - length[n - 1]) <= 1e-4 * length[n - 1]; |
|
227 |
hppDout(info, "length = " << length[n - 1]); |
||
228 |
397 |
tmpPath = result; |
|
229 |
397 |
projectionError = n; |
|
230 |
} |
||
231 |
} |
||
232 |
✓✓ | 484 |
for (std::size_t i = 0; i < result->numberPaths(); ++i) { |
233 |
✓✗ | 415 |
if (result->pathAtRank(i)->constraints()) |
234 |
hppDout(info, "At rank " << i << ", constraints are " |
||
235 |
<< *result->pathAtRank(i)->constraints()); |
||
236 |
else |
||
237 |
hppDout(info, "At rank " << i << ", no constraints"); |
||
238 |
} |
||
239 |
hppStopBenchmark(RANDOM_SHORTCUT); |
||
240 |
hppDisplayBenchmark(RANDOM_SHORTCUT); |
||
241 |
138 |
return result; |
|
242 |
} // optimize |
||
243 |
|||
244 |
12972 |
PathPtr_t RandomShortcutDynamic::steer(ConfigurationIn_t q1, |
|
245 |
ConfigurationIn_t q2) const { |
||
246 |
// according to optimize() method : the path is always in the direction q1 -> |
||
247 |
// q2 first : create a node and fill all informations about contacts for the |
||
248 |
// initial state (q1): |
||
249 |
core::RbprmNodePtr_t x1( |
||
250 |
✓✗✓✗ ✓✗✓✗ ✓✗ |
12972 |
new core::RbprmNode(ConfigurationPtr_t(new Configuration_t(q1)))); |
251 |
12972 |
core::ValidationReportPtr_t report; |
|
252 |
✓✗ | 12972 |
rbprmPathValidation_->getValidator()->computeAllContacts(true); |
253 |
✓✗✓✗ |
12972 |
problem()->configValidations()->validate(q1, report); |
254 |
✓✗ | 12972 |
rbprmPathValidation_->getValidator()->computeAllContacts(false); |
255 |
hppDout(notice, "Random shortucut, fillNodeMatrices : "); |
||
256 |
✓✗ | 12972 |
x1->fillNodeMatrices( |
257 |
12972 |
report, rectangularContact_, sizeFootX_, sizeFootY_, |
|
258 |
✓✗ | 25944 |
problem()->robot()->mass(), mu_, |
259 |
25944 |
dynamic_pointer_cast<pinocchio::RbPrmDevice>(problem()->robot())); |
|
260 |
// call steering method kinodynamic with the newly created node |
||
261 |
hppDout(notice, "Random shortucut, steering method : "); |
||
262 |
✓✗✓✗ |
25944 |
PathPtr_t dp = (*sm_)(x1, q2); |
263 |
✓✓ | 12972 |
if (dp) { |
264 |
hppDout(notice, "Random shortucut, path exist "); |
||
265 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✗✓✗✗ ✗✗ |
12971 |
if ((dp->initial() != q1) || (dp->end() != q2)) { |
266 |
hppDout(notice, "Path doesn't link the targets"); |
||
267 |
12971 |
return PathPtr_t(); |
|
268 |
} |
||
269 |
✓✗✗✓ |
12971 |
if (dp->length() <= 0.001) { |
270 |
hppDout(notice, "Path length < epsilon"); |
||
271 |
return PathPtr_t(); |
||
272 |
} |
||
273 |
✓✗ | 12971 |
if (!problem()->pathProjector()) return dp; |
274 |
PathPtr_t pp; |
||
275 |
if (problem()->pathProjector()->apply(dp, pp)) { |
||
276 |
hppDout(notice, "Path projector exist in random-shortcut"); |
||
277 |
return pp; |
||
278 |
} |
||
279 |
} |
||
280 |
1 |
return PathPtr_t(); |
|
281 |
} |
||
282 |
|||
283 |
} // namespace rbprm |
||
284 |
} // namespace hpp |
Generated by: GCOVR (Version 4.2) |