GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/planner/oriented-path-optimizer.cc Lines: 0 112 0.0 %
Date: 2024-02-02 12:21:48 Branches: 0 216 0.0 %

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/oriented-path-optimizer.hh>
29
#include <hpp/util/assertion.hh>
30
#include <hpp/util/debug.hh>
31
#include <hpp/util/timer.hh>
32
#include <limits>
33
34
namespace hpp {
35
namespace rbprm {
36
using core::Configuration_t;
37
using core::ConfigurationIn_t;
38
using core::ConfigurationPtr_t;
39
using core::DistancePtr_t;
40
using core::KinodynamicOrientedPath;
41
using core::KinodynamicOrientedPathPtr_t;
42
using core::KinodynamicPath;
43
using core::KinodynamicPathPtr_t;
44
using core::PathPtr_t;
45
using core::PathVector;
46
using core::PathVectorPtr_t;
47
using core::Problem;
48
using pinocchio::value_type;
49
50
OrientedPathOptimizerPtr_t OrientedPathOptimizer::create(
51
    core::ProblemConstPtr_t problem) {
52
  OrientedPathOptimizer* ptr = new OrientedPathOptimizer(problem);
53
  return OrientedPathOptimizerPtr_t(ptr);
54
}
55
56
OrientedPathOptimizer::OrientedPathOptimizer(core::ProblemConstPtr_t problem)
57
    : PathOptimizer(problem),
58
      sm_(dynamic_pointer_cast<SteeringMethodKinodynamic>(
59
          problem->steeringMethod())),
60
      rbprmPathValidation_(dynamic_pointer_cast<RbPrmPathValidation>(
61
          problem->pathValidation())) {
62
  assert(sm_ &&
63
         "Random-shortcut-dynamic must use a kinodynamic-steering-method");
64
  assert(
65
      rbprmPathValidation_ &&
66
      "Path validation should be a RbPrmPathValidation class for this solver");
67
68
  // retrieve parameters from problem :
69
  sizeFootX_ = problem->getParameter(std::string("DynamicPlanner/sizeFootX"))
70
                   .floatValue() /
71
               2.;
72
  sizeFootY_ = problem->getParameter(std::string("DynamicPlanner/sizeFootY"))
73
                   .floatValue() /
74
               2.;
75
  if (sizeFootX_ > 0. && sizeFootY_ > 0.)
76
    rectangularContact_ = 1;
77
  else
78
    rectangularContact_ = 0;
79
  tryJump_ =
80
      problem->getParameter(std::string("DynamicPlanner/tryJump")).boolValue();
81
  hppDout(notice, "tryJump in steering method = " << tryJump_);
82
  mu_ = problem->getParameter(std::string("DynamicPlanner/friction"))
83
            .floatValue();
84
  hppDout(notice, "mu define in python : " << mu_);
85
  orientationIgnoreZValue_ =
86
      problem->getParameter(std::string("Kinodynamic/forceYawOrientation"))
87
          .boolValue();
88
  hppDout(notice, "oriented path only constraint yaw (ignore z value) : "
89
                      << orientationIgnoreZValue_);
90
}
91
92
PathVectorPtr_t OrientedPathOptimizer::optimize(const PathVectorPtr_t& path) {
93
  hppDout(notice, "!! Start optimize()");
94
  hppStartBenchmark(ORIENTED_OPTIMIZER);
95
  using std::make_pair;
96
  using std::numeric_limits;
97
  PathPtr_t unusedValidPart;
98
  core::PathValidationReportPtr_t unusedReport;
99
  PathVectorPtr_t result =
100
      PathVector::create(path->outputSize(), path->outputDerivativeSize());
101
  const size_t numPaths = path->numberPaths();
102
  std::vector<bool> orientedValid(numPaths);
103
  std::vector<bool> replaceValid(numPaths);
104
  std::vector<KinodynamicOrientedPathPtr_t> orientedPaths(numPaths);
105
  std::vector<KinodynamicPathPtr_t> resultPaths(numPaths);
106
  KinodynamicPathPtr_t castedPath;
107
  // iterate over all elements of path (all kinodynamicPath), convert them to
108
  // orientedPath and test collision
109
  for (std::size_t i = 0; i < numPaths; ++i) {
110
    orientedValid[i] = false;
111
    const PathPtr_t& element(path->pathAtRank(i));
112
    castedPath = dynamic_pointer_cast<KinodynamicPath>(element);
113
    if (castedPath) {
114
      resultPaths[i] = castedPath;
115
      orientedPaths[i] = core::KinodynamicOrientedPath::create(
116
          castedPath, orientationIgnoreZValue_);
117
      if (orientedPaths[i]) {
118
        orientedValid[i] = rbprmPathValidation_->validate(
119
            orientedPaths[i], false, unusedValidPart, unusedReport);
120
      }
121
    } else
122
      hppDout(
123
          error,
124
          "paths inside path vector could not be casted to kinodyamic paths");
125
  }
126
  // then test if previous/next path can be adjusted to the new orientation
127
  for (size_t i = 0; i < numPaths; i++) {
128
    replaceValid[i] = false;
129
  }
130
  hppDout(notice, "Number of paths : " << numPaths);
131
  std::ostringstream oss;
132
  for (size_t i = 0; i < numPaths; i++) oss << orientedValid[i] << " ; ";
133
  hppDout(notice, "orientedValid : " << oss.str());
134
135
  for (size_t i = 0; i < numPaths; i++) {
136
    if (!replaceValid[i]) {
137
      hppDout(notice, "init check for index : " << i);
138
      replaceValid[i] = checkReplaceOrientation(
139
          i, numPaths, replaceValid, orientedValid, orientedPaths, resultPaths);
140
    }
141
  }
142
143
  std::ostringstream oss2;
144
  for (size_t i = 0; i < numPaths; i++) oss2 << replaceValid[i] << " ; ";
145
  hppDout(notice, "replaceValid : " << oss2.str());
146
  // concatenate resultPath in a pathVector :
147
  // TODO
148
  for (size_t i = 0; i < numPaths; i++) {
149
    result->appendPath(resultPaths[i]);
150
  }
151
  hppStopBenchmark(ORIENTED_OPTIMIZER);
152
  hppDisplayBenchmark(ORIENTED_OPTIMIZER);
153
154
  return result;
155
}
156
157
/**
158
 * @brief OrientedPathOptimizer::checkReplaceOrientation recursively check if an
159
 * element of the path vector can be changed to an oriented path : the final
160
 * state of the previous element and the initial state of the next element must
161
 * be changed and this changes must be valid
162
 * @param index
163
 * @param replaceValid
164
 * @param orientedValid
165
 * @param orientedPaths
166
 * @param resultPaths
167
 * @return
168
 */
169
bool OrientedPathOptimizer::checkReplaceOrientation(
170
    const size_t index, const size_t lastIndex, std::vector<bool> replaceValid,
171
    std::vector<bool> orientedValid,
172
    std::vector<core::KinodynamicOrientedPathPtr_t> orientedPaths,
173
    std::vector<core::KinodynamicPathPtr_t> resultPaths) {
174
  KinodynamicPathPtr_t previousPath, nextPath;
175
  bool previousValid(false);
176
  PathPtr_t unusedValidPart;
177
  core::PathValidationReportPtr_t unusedReport;
178
179
  if (!orientedValid[index]) return false;
180
181
  if (index > 0) {  // test if previous element can be adjusted:
182
    if (orientedValid[index - 1] && replaceValid[index - 1]) {
183
      previousValid = true;
184
    } else {
185
      previousPath = KinodynamicPath::createCopy(resultPaths[index - 1]);
186
      if (previousPath) {
187
        previousPath->endConfig(orientedPaths[index]->initial());
188
        previousValid = rbprmPathValidation_->validate(
189
            previousPath, false, unusedValidPart, unusedReport);
190
      }
191
    }
192
  } else {  // if first element of the pathvector : always valid
193
    previousValid = true;
194
  }
195
196
  if (!previousValid) return false;
197
198
  if (index < lastIndex - 1) {  // test if next element can be adjusted
199
    if (orientedValid[index +
200
                      1]) {  // make a recursive test for the next elements
201
      replaceValid[index] =
202
          true;  // needed for the recursive call to test the previous part
203
      hppDout(notice, "iterative check of index " << index);
204
      replaceValid[index] =
205
          checkReplaceOrientation(index + 1, lastIndex, replaceValid,
206
                                  orientedValid, orientedPaths, resultPaths);
207
      hppDout(notice, "end iterative check of index "
208
                          << index
209
                          << ", replaceValid = " << replaceValid[index]);
210
      nextPath = orientedPaths[index + 1];
211
    } else {
212
      nextPath = KinodynamicPath::createCopy(resultPaths[index + 1]);
213
      if (nextPath) {
214
        nextPath->initialConfig(orientedPaths[index]->end());
215
        replaceValid[index] = rbprmPathValidation_->validate(
216
            nextPath, false, unusedValidPart, unusedReport);
217
      }
218
    }
219
  } else {  // if last element of the pathVector : always valid
220
    replaceValid[index] = true;
221
  }
222
223
  if (replaceValid[index]) {  // replace values in resultPaths
224
    resultPaths[index] = orientedPaths[index];
225
    if (index > 0) resultPaths[index - 1] = previousPath;
226
    if (index < lastIndex - 1) resultPaths[index + 1] = nextPath;
227
  }
228
229
  return replaceValid[index];
230
}
231
232
core::PathPtr_t OrientedPathOptimizer::steer(ConfigurationIn_t q1,
233
                                             ConfigurationIn_t q2) const {
234
  // according to optimize() method : the path is always in the direction q1 ->
235
  // q2 first : create a node and fill all informations about contacts for the
236
  // initial state (q1):
237
  core::RbprmNodePtr_t x1(
238
      new core::RbprmNode(ConfigurationPtr_t(new Configuration_t(q1))));
239
  core::ValidationReportPtr_t report;
240
  rbprmPathValidation_->getValidator()->computeAllContacts(true);
241
  problem()->configValidations()->validate(q1, report);
242
  rbprmPathValidation_->getValidator()->computeAllContacts(false);
243
  hppDout(notice, "Random shortucut, fillNodeMatrices : ");
244
  x1->fillNodeMatrices(
245
      report, rectangularContact_, sizeFootX_, sizeFootY_,
246
      problem()->robot()->mass(), mu_,
247
      dynamic_pointer_cast<pinocchio::RbPrmDevice>(problem()->robot()));
248
249
  // call steering method kinodynamic with the newly created node
250
  hppDout(notice, "Random shortucut, steering method  : ");
251
  PathPtr_t dp = (*sm_)(x1, q2);
252
  if (dp) {
253
    hppDout(notice, "Random shortucut, path exist ");
254
    if ((dp->initial() != q1) || (dp->end() != q2)) {
255
      hppDout(notice, "Path doesn't link the targets");
256
      return PathPtr_t();
257
    }
258
    if (dp->length() <= 0.001) {
259
      hppDout(notice, "Path length < epsilon");
260
      return PathPtr_t();
261
    }
262
    if (!problem()->pathProjector()) return dp;
263
    PathPtr_t pp;
264
    if (problem()->pathProjector()->apply(dp, pp)) return pp;
265
  }
266
  return PathPtr_t();
267
}
268
269
}  // namespace rbprm
270
}  // namespace hpp