GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/planner/random-shortcut-dynamic.cc Lines: 112 125 89.6 %
Date: 2024-02-02 12:21:48 Branches: 117 214 54.7 %

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