STRRTstar.cpp
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2021, Technische Universität Berlin (TU Berlin)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the TU Berlin nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Francesco Grothe */
36 
37 #include "ompl/geometric/planners/rrt/STRRTstar.h"
38 #include <ompl/util/Exception.h>
39 
41  : Planner(si, "SpaceTimeRRT"), sampler_(&(*si), startMotion_, goalMotions_, newBatchGoalMotions_, sampleOldBatch_)
42 {
43  if (std::dynamic_pointer_cast<ompl::base::SpaceTimeStateSpace>(si->getStateSpace()) == nullptr)
44  {
45  OMPL_ERROR("%s: State Space needs to be of type SpaceTimeStateSpace.", getName().c_str());
46  throw ompl::Exception("Non-SpaceTimeStateSpace");
47  }
48  specs_.optimizingPaths = true;
50  Planner::declareParam<double>("range", this, &STRRTstar::setRange, &STRRTstar::getRange, "0.:1.:10000.");
51  distanceBetweenTrees_ = std::numeric_limits<double>::infinity();
52 }
53 
54 ompl::geometric::STRRTstar::~STRRTstar()
55 {
56  freeMemory();
57 }
58 
60 {
61  Planner::setup();
62  ompl::tools::SelfConfig sc(si_, getName());
63  sc.configurePlannerRange(maxDistance_);
64 
65  if (!tStart_)
66  tStart_.reset(new ompl::NearestNeighborsLinear<Motion *>());
67  if (!tGoal_)
68  tGoal_.reset(new ompl::NearestNeighborsLinear<Motion *>());
69  tStart_->setDistanceFunction([this](const Motion *a, const Motion *b) { return distanceFunction(a, b); });
70  tGoal_->setDistanceFunction([this](const Motion *a, const Motion *b) { return distanceFunction(a, b); });
71 
72  if (si_->getStateSpace()->as<ompl::base::SpaceTimeStateSpace>()->getTimeComponent()->isBounded())
73  {
74  upperTimeBound_ =
75  si_->getStateSpace()->as<ompl::base::SpaceTimeStateSpace>()->getTimeComponent()->getMaxTimeBound();
76  isTimeBounded_ = true;
77  }
78  else
79  {
80  upperTimeBound_ = std::numeric_limits<double>::infinity();
81  isTimeBounded_ = false;
82  }
83  initialTimeBound_ = upperTimeBound_;
84 
85  si_->getStateSpace()->as<ompl::base::SpaceTimeStateSpace>()->updateEpsilon();
86  // Calculate some constants:
87  calculateRewiringLowerBounds();
88 }
89 
91 {
92  std::vector<Motion *> motions;
93 
94  if (tStart_)
95  {
96  tStart_->list(motions);
97  for (auto &motion : motions)
98  {
99  if (motion->state != nullptr)
100  si_->freeState(motion->state);
101  delete motion;
102  }
103  }
104 
105  if (tGoal_)
106  {
107  tGoal_->list(motions);
108  for (auto &motion : motions)
109  {
110  if (motion->state != nullptr)
111  si_->freeState(motion->state);
112  delete motion;
113  }
114  }
115 
116  if (tempState_)
117  si_->freeState(tempState_);
118 }
119 
121 {
122  checkValidity();
123  auto *goal = dynamic_cast<ompl::base::GoalSampleableRegion *>(pdef_->getGoal().get());
124 
125  if (goal == nullptr)
126  {
127  OMPL_ERROR("%s: Unknown type of goal", getName().c_str());
129  }
130 
131  while (const ompl::base::State *st = pis_.nextStart())
132  {
133  auto *motion = new Motion(si_);
134  si_->copyState(motion->state, st);
135  motion->root = motion->state;
136  tStart_->add(motion);
137  startMotion_ = motion;
138  }
139 
140  if (tStart_->size() == 0)
141  {
142  OMPL_ERROR("%s: Motion planning start tree could not be initialized!", getName().c_str());
144  }
145 
146  if (!goal->couldSample())
147  {
148  OMPL_ERROR("%s: Insufficient states in sampleable goal region", getName().c_str());
150  }
151 
152  OMPL_INFORM("%s: Starting planning with %d states already in datastructure", getName().c_str(),
153  (int)(tStart_->size() + tGoal_->size()));
154 
155  TreeGrowingInfo tgi;
156  tgi.xstate = si_->allocState();
157 
158  std::vector<Motion *> nbh;
159  const ompl::base::ReportIntermediateSolutionFn intermediateSolutionCallback =
160  pdef_->getIntermediateSolutionCallback();
161 
162  Motion *approxsol = nullptr;
163  double approxdif = std::numeric_limits<double>::infinity();
164  auto *rmotion = new Motion(si_);
165  ompl::base::State *rstate = rmotion->state;
166  bool startTree = true;
167  bool solved = false;
168 
169  // samples to fill the current batch
170  unsigned int batchSize = initialBatchSize_;
171 
172  // number of samples in the current batch
173  int numBatchSamples = static_cast<int>(tStart_->size() + tGoal_->size()); // number of samples in the current batch
174 
175  // number of goal samples in the new batch region
176  int newBatchGoalSamples = 0;
177 
178  bool firstBatch = true;
179 
180  // probability to sample the old batch region
181  double oldBatchSampleProb = 1.0;
182 
183  // Time Bound factor for the old batch.
184  double oldBatchTimeBoundFactor = initialTimeBoundFactor_;
185 
186  // Time Bound factor for the new batch.
187  double newBatchTimeBoundFactor = initialTimeBoundFactor_;
188 
189  bool forceGoalSample = true;
190 
191  OMPL_INFORM("%s: Starting planning with time bound factor %.2f", getName().c_str(), newBatchTimeBoundFactor);
192 
193  while (!ptc)
194  {
195  numIterations_++;
196  TreeData &tree = startTree ? tStart_ : tGoal_;
197  tgi.start = startTree;
198  startTree = !startTree;
199  TreeData &otherTree = startTree ? tStart_ : tGoal_;
200 
201  // batch is full
202  if (!isTimeBounded_ && (unsigned int)numBatchSamples >= batchSize)
203  {
204  if (firstBatch)
205  {
206  firstBatch = false;
207  oldBatchSampleProb = 0.5 * (1 / timeBoundFactorIncrease_);
208  }
209  increaseTimeBound(false, oldBatchTimeBoundFactor, newBatchTimeBoundFactor, startTree, batchSize,
210  numBatchSamples);
211  // transfer new batch goals to old batch
212  if (!newBatchGoalMotions_.empty())
213  {
214  goalMotions_.insert(goalMotions_.end(), newBatchGoalMotions_.begin(), newBatchGoalMotions_.end());
215  newBatchGoalMotions_.clear();
216  }
217  continue;
218  }
219 
220  // determine whether the old or new batch is sampled
221  sampleOldBatch_ =
222  (firstBatch || isTimeBounded_ || !sampleUniformForUnboundedTime_ || rng_.uniform01() <= oldBatchSampleProb);
223 
224  // *** Begin Goal Sampling ***
225 
226  ompl::base::State *goalState{nullptr};
227  if (sampleOldBatch_)
228  {
229  // sample until successful or time is up
230  if (goalMotions_.empty() && isTimeBounded_)
231  goalState = nextGoal(ptc, oldBatchTimeBoundFactor, newBatchTimeBoundFactor);
232  // sample for n tries, with n = batch size
233  else if (goalMotions_.empty() && !isTimeBounded_)
234  {
235  goalState = nextGoal(static_cast<int>(batchSize), oldBatchTimeBoundFactor, newBatchTimeBoundFactor);
236  // the goal region is most likely blocked for this time period -> increase upper time bound
237  if (goalState == nullptr)
238  {
239  increaseTimeBound(true, oldBatchTimeBoundFactor, newBatchTimeBoundFactor, startTree, batchSize,
240  numBatchSamples);
241  continue;
242  }
243  }
244  // sample for a single try
245  else if (forceGoalSample ||
246  goalMotions_.size() < (tGoal_->size() - newBatchGoalSamples) / goalStateSampleRatio_)
247  {
248  goalState = nextGoal(1, oldBatchTimeBoundFactor, newBatchTimeBoundFactor);
249  forceGoalSample = false;
250  }
251  }
252  else
253  {
254  if (newBatchGoalMotions_.empty())
255  {
256  goalState = nextGoal(static_cast<int>(batchSize), oldBatchTimeBoundFactor, newBatchTimeBoundFactor);
257  // the goal region is most likely blocked for this time period -> increase upper time bound
258  if (goalState == nullptr)
259  {
260  increaseTimeBound(false, oldBatchTimeBoundFactor, newBatchTimeBoundFactor, startTree, batchSize,
261  numBatchSamples);
262  continue;
263  }
264  }
265  else if (forceGoalSample ||
266  newBatchGoalMotions_.size() < (unsigned long)(newBatchGoalSamples / goalStateSampleRatio_))
267  {
268  goalState = nextGoal(1, oldBatchTimeBoundFactor, newBatchTimeBoundFactor);
269  forceGoalSample = false;
270  }
271  }
272 
273  if (goalState != nullptr)
274  {
275  auto *motion = new Motion(si_);
276  si_->copyState(motion->state, goalState);
277  motion->root = motion->state;
278  tGoal_->add(motion);
279  if (sampleOldBatch_)
280  goalMotions_.push_back(motion);
281  else
282  {
283  newBatchGoalMotions_.push_back(motion);
284  newBatchGoalSamples++;
285  }
286 
287  minimumTime_ =
288  std::min(minimumTime_, si_->getStateSpace()->as<ompl::base::SpaceTimeStateSpace>()->timeToCoverDistance(
289  startMotion_->state, goalState));
290  numBatchSamples++;
291  }
292 
293  // *** End Goal Sampling ***
294 
295  /* sample random state */
296  bool success = sampler_.sample(rstate);
297  if (!success)
298  {
299  forceGoalSample = true;
300  continue;
301  }
302 
303  // EXTEND
304  GrowState gs = growTree(tree, tgi, rmotion, nbh, false);
305  if (gs != TRAPPED)
306  {
307  numBatchSamples++;
308  /* remember which motion was just added */
309  Motion *addedMotion = tgi.xmotion;
310  Motion *startMotion;
311  Motion *goalMotion;
312 
313  /* rewire the goal tree */
314  bool newSolution = false;
315  if (!tgi.start && rewireState_ != OFF)
316  {
317  newSolution = rewireGoalTree(addedMotion);
318  if (newSolution)
319  {
320  // find connection point
321  std::queue<Motion *> queue;
322  queue.push(addedMotion);
323  while (!queue.empty())
324  {
325  if (queue.front()->connectionPoint != nullptr)
326  {
327  goalMotion = queue.front();
328  startMotion = queue.front()->connectionPoint;
329  break;
330  }
331  else
332  {
333  for (Motion *c : queue.front()->children)
334  queue.push(c);
335  }
336  queue.pop();
337  }
338  }
339  }
340 
341  /* if reached, it means we used rstate directly, no need to copy again */
342  if (gs != REACHED)
343  si_->copyState(rstate, tgi.xstate);
344 
345  tgi.start = startTree;
346 
347  /* attempt to connect trees, if rewiring didn't find a new solution */
348  // CONNECT
349  if (!newSolution)
350  {
351  int totalSamples = static_cast<int>(tStart_->size() + tGoal_->size());
352  GrowState gsc = growTree(otherTree, tgi, rmotion, nbh, true);
353  if (gsc == REACHED)
354  {
355  newSolution = true;
356  startMotion = startTree ? tgi.xmotion : addedMotion;
357  goalMotion = startTree ? addedMotion : tgi.xmotion;
358  // it must be the case that either the start tree or the goal tree has made some progress
359  // so one of the parents is not nullptr. We go one step 'back' to avoid having a duplicate state
360  // on the solution path
361  if (startMotion->parent != nullptr)
362  startMotion = startMotion->parent;
363  else
364  goalMotion = goalMotion->parent;
365  }
366  numBatchSamples += static_cast<int>(tStart_->size() + tGoal_->size()) - totalSamples;
367  }
368 
369  /* update distance between trees */
370  const double newDist = tree->getDistanceFunction()(addedMotion, otherTree->nearest(addedMotion));
371  if (newDist < distanceBetweenTrees_)
372  {
373  distanceBetweenTrees_ = newDist;
374  // OMPL_INFORM("Estimated distance to go: %f", distanceBetweenTrees_);
375  }
376 
377  /* if we connected the trees in a valid way (start and goal pair is valid)*/
378  if (newSolution && goal->isStartGoalPairValid(startMotion->root, goalMotion->root))
379  {
380  constructSolution(startMotion, goalMotion, intermediateSolutionCallback, ptc);
381  solved = true;
382  if (ptc || upperTimeBound_ == minimumTime_)
383  break; // first solution is enough or optimal solution is found
384  // continue to look for solutions with the narrower time bound until the termination condition is met
385  }
386  else
387  {
388  // We didn't reach the goal, but if we were extending the start
389  // tree, then we can mark/improve the approximate path so far.
390  if (!startTree)
391  {
392  // We were working from the startTree.
393  double dist = 0.0;
394  goal->isSatisfied(tgi.xmotion->state, &dist);
395  if (dist < approxdif)
396  {
397  approxdif = dist;
398  approxsol = tgi.xmotion;
399  }
400  }
401  }
402  }
403  }
404 
405  si_->freeState(tgi.xstate);
406  si_->freeState(rstate);
407  delete rmotion;
408 
409  OMPL_INFORM("%s: Created %u states (%u start + %u goal)", getName().c_str(), tStart_->size() + tGoal_->size(),
410  tStart_->size(), tGoal_->size());
411 
412  if (approxsol && !solved)
413  {
414  /* construct the solution path */
415  std::vector<Motion *> mpath;
416  while (approxsol != nullptr)
417  {
418  mpath.push_back(approxsol);
419  approxsol = approxsol->parent;
420  }
421 
422  auto path(std::make_shared<ompl::geometric::PathGeometric>(si_));
423  for (int i = mpath.size() - 1; i >= 0; --i)
424  path->append(mpath[i]->state);
425  pdef_->addSolutionPath(path, true, approxdif, getName());
427  }
428  if (solved)
429  {
430  // Add the solution path.
431  ompl::base::PlannerSolution psol(bestSolution_);
432  psol.setPlannerName(getName());
433 
434  ompl::base::OptimizationObjectivePtr optimizationObjective =
435  std::make_shared<ompl::base::MinimizeArrivalTime>(si_);
436  psol.setOptimized(optimizationObjective, ompl::base::Cost(bestTime_), false);
437  pdef_->addSolutionPath(psol);
438  }
439 
441 }
442 
445  std::vector<Motion *> &nbh, bool connect)
446 {
447  // If connect, advance from single nearest neighbor until the random state is reached or trapped
448  if (connect)
449  {
450  GrowState gsc = ADVANCED;
451  while (gsc == ADVANCED)
452  {
453  // get nearest motion
454  Motion *nmotion = tree->nearest(rmotion);
455  gsc = growTreeSingle(tree, tgi, rmotion, nmotion);
456  }
457  return gsc;
458  }
459  if (rewireState_ == OFF)
460  {
461  Motion *nmotion = tree->nearest(rmotion);
462  return growTreeSingle(tree, tgi, rmotion, nmotion);
463  }
464  // get Neighborhood of random state
465  getNeighbors(tree, rmotion, nbh);
466  // in start tree sort by distance
467  if (tgi.start)
468  {
469  std::sort(nbh.begin(), nbh.end(),
470  [this, &rmotion](Motion *a, Motion *b)
471  { return si_->distance(a->state, rmotion->state) < si_->distance(b->state, rmotion->state); });
472  }
473  // in goal tree sort by time of root node
474  else
475  {
476  std::sort(
477  nbh.begin(), nbh.end(),
478  [](Motion *a, Motion *b)
479  {
480  auto t1 =
481  a->root->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position;
482  auto t2 =
483  b->root->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position;
484  return t1 < t2;
485  });
486  }
487 
488  // attempt to grow the tree for all neighbors in sorted order
489  GrowState gs = TRAPPED;
490  auto rt = rmotion->state->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position;
491  for (Motion *nmotion : nbh)
492  {
493  auto nt =
494  nmotion->state->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position;
495  // trees grow only in one direction in time
496  if ((tgi.start && nt > rt) || (!tgi.start && nt < rt))
497  continue;
498  gs = growTreeSingle(tree, tgi, rmotion, nmotion);
499  if (gs != TRAPPED)
500  return gs;
501  }
502  // when radius_ is used for neighborhood calculation, the neighborhood might be empty
503  if (nbh.empty())
504  {
505  Motion *nmotion = tree->nearest(rmotion);
506  return growTreeSingle(tree, tgi, rmotion, nmotion);
507  }
508  // can't grow Tree
509  return gs;
510 }
511 
514  Motion *nmotion)
515 {
516  /* assume we can reach the state we go towards */
517  bool reach = true;
518 
519  /* find state to add */
520  ompl::base::State *dstate = rmotion->state;
521  double d = si_->distance(nmotion->state, rmotion->state);
522 
523  if (d > maxDistance_)
524  {
525  si_->getStateSpace()->interpolate(nmotion->state, rmotion->state, maxDistance_ / d, tgi.xstate);
526  /* Check if we have moved at all. Due to some stranger state spaces (e.g., the constrained state spaces),
527  * interpolate can fail and no progress is made. Without this check, the algorithm gets stuck in a loop as it
528  * thinks it is making progress, when none is actually occurring. */
529  if (si_->equalStates(nmotion->state, tgi.xstate))
530  return TRAPPED;
531  dstate = tgi.xstate;
532  reach = false;
533  }
534 
535  bool validMotion = tgi.start ? si_->checkMotion(nmotion->state, dstate) :
536  si_->isValid(dstate) && si_->checkMotion(dstate, nmotion->state);
537 
538  if (!validMotion)
539  return TRAPPED;
540 
541  auto *motion = new Motion(si_);
542  si_->copyState(motion->state, dstate);
543  motion->parent = nmotion;
544  motion->root = nmotion->root;
545  motion->parent->children.push_back(motion);
546  tree->add(motion);
547  tgi.xmotion = motion;
548 
549  return reach ? REACHED : ADVANCED;
550 }
551 
552 void ompl::geometric::STRRTstar::increaseTimeBound(bool hasSameBounds, double &oldBatchTimeBoundFactor,
553  double &newBatchTimeBoundFactor, bool &startTree,
554  unsigned int &batchSize, int &numBatchSamples)
555 {
556  oldBatchTimeBoundFactor =
557  hasSameBounds ? newBatchTimeBoundFactor * timeBoundFactorIncrease_ : newBatchTimeBoundFactor;
558  newBatchTimeBoundFactor *= timeBoundFactorIncrease_;
559  startTree = true;
560  if (sampleUniformForUnboundedTime_)
561  batchSize =
562  std::ceil(2.0 * (timeBoundFactorIncrease_ - 1.0) * static_cast<double>(tStart_->size() + tGoal_->size()));
563  numBatchSamples = 0;
564  OMPL_INFORM("%s: Increased time bound factor to %.2f", getName().c_str(), newBatchTimeBoundFactor);
565 }
566 
567 void ompl::geometric::STRRTstar::constructSolution(
568  Motion *startMotion, Motion *goalMotion,
569  const ompl::base::ReportIntermediateSolutionFn &intermediateSolutionCallback,
571 {
572  if (goalMotion->connectionPoint == nullptr)
573  {
574  goalMotion->connectionPoint = startMotion;
575  Motion *tMotion = goalMotion;
576  while (tMotion != nullptr)
577  {
578  tMotion->numConnections++;
579  tMotion = tMotion->parent;
580  }
581  }
582  // check whether the found solution is an improvement
583  auto newTime =
584  goalMotion->root->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position;
585  if (newTime >= upperTimeBound_)
586  return;
587 
588  numSolutions_++;
589  isTimeBounded_ = true;
590  if (!newBatchGoalMotions_.empty())
591  {
592  goalMotions_.insert(goalMotions_.end(), newBatchGoalMotions_.begin(), newBatchGoalMotions_.end());
593  newBatchGoalMotions_.clear();
594  }
595 
596  /* construct the solution path */
597  Motion *solution = startMotion;
598  std::vector<Motion *> mpath1;
599  while (solution != nullptr)
600  {
601  mpath1.push_back(solution);
602  solution = solution->parent;
603  }
604 
605  solution = goalMotion;
606  std::vector<Motion *> mpath2;
607  while (solution != nullptr)
608  {
609  mpath2.push_back(solution);
610  solution = solution->parent;
611  }
612 
613  std::vector<const ompl::base::State *> constPath;
614 
615  auto path(std::make_shared<ompl::geometric::PathGeometric>(si_));
616  path->getStates().reserve(mpath1.size() + mpath2.size());
617  for (int i = mpath1.size() - 1; i >= 0; --i)
618  {
619  constPath.push_back(mpath1[i]->state);
620  path->append(mpath1[i]->state);
621  }
622  for (auto &i : mpath2)
623  {
624  constPath.push_back(i->state);
625  path->append(i->state);
626  }
627 
628  bestSolution_ = path;
629  auto reachedGaol = path->getState(path->getStateCount() - 1);
630  bestTime_ = reachedGaol->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position;
631 
632  if (intermediateSolutionCallback)
633  {
634  intermediateSolutionCallback(this, constPath, ompl::base::Cost(bestTime_));
635  }
636 
637  // Update Time Limit
638  upperTimeBound_ = (bestTime_ - minimumTime_) * optimumApproxFactor_ + minimumTime_;
639 
640  if (ptc)
641  return;
642  // Prune Start and Goal Trees
643  pruneStartTree();
644  Motion *newSolution = pruneGoalTree();
645 
646  // loop as long as a new solution is found by rewiring the goal tree
647  if (newSolution != nullptr)
648  constructSolution(newSolution->connectionPoint, goalMotion, intermediateSolutionCallback, ptc);
649 }
650 
652 {
653  std::queue<Motion *> queue;
654 
655  tStart_->clear();
656  tStart_->add(startMotion_);
657  for (auto &c : startMotion_->children)
658  queue.push(c);
659  while (!queue.empty())
660  {
661  double t = queue.front()
662  ->state->as<ompl::base::CompoundState>()
663  ->as<ompl::base::TimeStateSpace::StateType>(1)
664  ->position;
665  double timeToNearestGoal = std::numeric_limits<double>::infinity();
666  for (const auto &g : goalMotions_)
667  {
668  double deltaT = si_->getStateSpace()->as<ompl::base::SpaceTimeStateSpace>()->timeToCoverDistance(
669  queue.front()->state, g->state);
670  if (deltaT < timeToNearestGoal)
671  timeToNearestGoal = deltaT;
672  }
673  // Motion is still valid, re-add to tree
674  if (t + timeToNearestGoal <= upperTimeBound_)
675  {
676  tStart_->add(queue.front());
677  for (auto &c : queue.front()->children)
678  queue.push(c);
679  }
680  // Motion is invalid due to the new time limit, delete motion
681  else
682  {
683  // Remove the motion from its parent
684  removeFromParent(queue.front());
685 
686  // for deletion first construct list of all descendants
687  std::queue<Motion *> deletionQueue;
688  std::vector<Motion *> deletionList;
689 
690  deletionQueue.push(queue.front());
691  while (!deletionQueue.empty())
692  {
693  for (auto &c : deletionQueue.front()->children)
694  deletionQueue.push(c);
695  deletionList.push_back(deletionQueue.front());
696  deletionQueue.pop();
697  }
698 
699  // then free all descendants
700  for (auto &m : deletionList)
701  {
702  // Erase the actual motion
703  // First free the state
704  if (m->state)
705  si_->freeState(m->state);
706  // then delete the pointer
707  delete m;
708  }
709  }
710  // finally remove motion from the queue
711  queue.pop();
712  }
713 }
714 
716 {
717  // it's possible to get multiple new solutions during the rewiring process. Store the best.
718  double bestSolutionTime = upperTimeBound_;
719  Motion *solutionMotion{nullptr};
720 
721  tGoal_->clear();
722  std::vector<Motion *> validGoals;
723  std::vector<Motion *> invalidGoals;
724 
725  // re-add goals with smallest time first
726  std::sort(
727  goalMotions_.begin(), goalMotions_.end(),
728  [](Motion *a, Motion *b)
729  {
730  return a->state->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position <
731  b->state->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position;
732  });
733  for (auto &m : goalMotions_)
734  {
735  double t = m->state->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position;
736  // add goal with all descendants to the tree
737  if (t <= upperTimeBound_)
738  {
739  tGoal_->add(m);
740  addDescendants(m, tGoal_);
741  validGoals.push_back(m);
742  }
743  // try to rewire descendants to a valid goal
744  else
745  {
746  invalidGoals.push_back(m);
747  std::queue<Motion *> queue;
748  for (auto &c : m->children)
749  queue.push(c);
750  while (!queue.empty())
751  {
752  bool addedToTree = false;
753  if (tGoal_->size() != 0)
754  {
755  double costToGo = std::numeric_limits<double>::infinity();
756  double costSoFar = queue.front()
757  ->state->as<ompl::base::CompoundState>()
758  ->as<ompl::base::TimeStateSpace::StateType>(1)
759  ->position;
760  for (auto &g : validGoals)
761  {
762  auto deltaT = si_->getStateSpace()->as<ompl::base::SpaceTimeStateSpace>()->timeToCoverDistance(
763  queue.front()->state, g->state);
764  if (deltaT < costToGo)
765  costToGo = deltaT;
766  }
767  // try to rewire to the nearest neighbor
768 
769  if (costSoFar + costToGo <= upperTimeBound_)
770  {
771  TreeGrowingInfo tgi{};
772  tgi.xstate = si_->allocState();
773  tgi.start = false;
774  std::vector<Motion *> nbh;
775  GrowState gsc = growTree(tGoal_, tgi, queue.front(), nbh, true);
776  // connection successful, add all descendants and check if a new solution was found.
777  if (gsc == REACHED)
778  {
779  // the motion was copied and added to the tree with a new parent
780  // adjust children and parent pointers
781  tgi.xmotion->children = queue.front()->children;
782  for (auto &c : tgi.xmotion->children)
783  {
784  c->parent = tgi.xmotion;
785  }
786  tgi.xmotion->connectionPoint = queue.front()->connectionPoint;
787  tgi.xmotion->numConnections = queue.front()->numConnections;
788  Motion *p = tgi.xmotion->parent;
789  while (p != nullptr)
790  {
791  p->numConnections += tgi.xmotion->numConnections;
792  p = p->parent;
793  }
794  addDescendants(tgi.xmotion, tGoal_);
795  // new solution found
796  if (tgi.xmotion->numConnections > 0 &&
797  tgi.xmotion->root->as<ompl::base::CompoundState>()
799  ->position < bestSolutionTime)
800  {
801  bestSolutionTime = tgi.xmotion->root->as<ompl::base::CompoundState>()
802  ->as<ompl::base::TimeStateSpace::StateType>(1)
803  ->position;
804  solutionMotion = computeSolutionMotion(tgi.xmotion);
805  }
806  addedToTree = true;
807  }
808  }
809  }
810  // Free motion and state
811  if (!addedToTree)
812  {
813  // add children to queue, so they might be rewired
814  for (auto &c : queue.front()->children)
815  queue.push(c);
816  }
817  // Erase the actual motion
818  // First free the state
819  if (queue.front()->state)
820  si_->freeState(queue.front()->state);
821  // then delete the pointer
822  delete queue.front();
823 
824  queue.pop();
825  }
826  }
827  }
828 
829  removeInvalidGoals(invalidGoals);
830  return solutionMotion;
831 }
832 
834 {
835  std::queue<Motion *> connectionQueue;
836  connectionQueue.push(motion);
837  while (!connectionQueue.empty())
838  {
839  if (connectionQueue.front()->connectionPoint != nullptr)
840  {
841  return connectionQueue.front();
842  }
843  else
844  {
845  for (Motion *c : connectionQueue.front()->children)
846  connectionQueue.push(c);
847  }
848  connectionQueue.pop();
849  }
850  // suppress compiler warning
851  return nullptr;
852 }
853 
854 void ompl::geometric::STRRTstar::removeInvalidGoals(const std::vector<Motion *> &invalidGoals)
855 {
856  for (auto &g : invalidGoals)
857  {
858  for (auto it = goalMotions_.begin(); it != goalMotions_.end(); ++it)
859  {
860  if (*it == g)
861  {
862  goalMotions_.erase(it);
863  break;
864  }
865  }
866  if (g->state)
867  si_->freeState(g->state);
868  delete g;
869  }
870 }
871 
873 {
874  setup_ = false;
875  Planner::clear();
876  freeMemory();
877  if (tStart_)
878  tStart_->clear();
879  if (tGoal_)
880  tGoal_->clear();
881  distanceBetweenTrees_ = std::numeric_limits<double>::infinity();
882  bestSolution_ = nullptr;
883  bestTime_ = std::numeric_limits<double>::infinity();
884  minimumTime_ = std::numeric_limits<double>::infinity();
885  numIterations_ = 0;
886  numSolutions_ = 0;
887  startMotion_ = nullptr;
888  goalMotions_.clear();
889  newBatchGoalMotions_.clear();
890  tempState_ = nullptr;
891  sampleOldBatch_ = true;
892  upperTimeBound_ = initialTimeBound_;
893  isTimeBounded_ = initialTimeBound_ != std::numeric_limits<double>::infinity();
894 }
895 
897 {
898  Planner::getPlannerData(data);
899 
900  std::vector<Motion *> motions;
901  if (tStart_)
902  tStart_->list(motions);
903 
904  for (auto &motion : motions)
905  {
906  if (motion->parent == nullptr)
907  data.addStartVertex(ompl::base::PlannerDataVertex(motion->state, 1));
908  else
909  {
910  data.addEdge(ompl::base::PlannerDataVertex(motion->parent->state, 1),
911  ompl::base::PlannerDataVertex(motion->state, 1));
912  }
913  }
914 
915  motions.clear();
916  if (tGoal_)
917  tGoal_->list(motions);
918 
919  for (auto &motion : motions)
920  {
921  if (motion->parent == nullptr)
922  data.addGoalVertex(ompl::base::PlannerDataVertex(motion->state, 2));
923  else
924  {
925  // The edges in the goal tree are reversed to be consistent with start tree
926  data.addEdge(ompl::base::PlannerDataVertex(motion->state, 2),
927  ompl::base::PlannerDataVertex(motion->parent->state, 2));
928  }
929  // add edges connecting the two trees
930  if (motion->connectionPoint != nullptr)
931  data.addEdge(data.vertexIndex(motion->connectionPoint->state), data.vertexIndex(motion->state));
932  }
933 
934  // Add some info.
935  data.properties["approx goal distance REAL"] = ompl::toString(distanceBetweenTrees_);
936 }
937 
939 {
940  for (auto it = m->parent->children.begin(); it != m->parent->children.end(); ++it)
941  {
942  if (*it == m)
943  {
944  m->parent->children.erase(it);
945  break;
946  }
947  }
948 }
949 
958 {
959  std::queue<Motion *> queue;
960  for (auto &c : m->children)
961  queue.push(c);
962  while (!queue.empty())
963  {
964  for (auto &c : queue.front()->children)
965  queue.push(c);
966  queue.front()->root = m->root;
967  tree->add(queue.front());
968  queue.pop();
969  }
970 }
971 
973  std::vector<Motion *> &nbh) const
974 {
975  auto card = static_cast<double>(tree->size() + 1u);
976  if (rewireState_ == RADIUS)
977  {
978  // r = min( r_rrt * (log(card(V))/card(V))^(1 / d + 1), distance)
979  // for the formula change of the RRTStar paper, see 'Revisiting the asymptotic optimality of RRT*'
980  double r = std::min(maxDistance_, r_rrt_ * std::pow(log(card) / card,
981  1.0 / 1.0 + static_cast<double>(si_->getStateDimension())));
982  tree->nearestR(motion, r, nbh);
983  }
984  else if (rewireState_ == KNEAREST)
985  {
986  // k = k_rrt * log(card(V))
987  unsigned int k = std::ceil(k_rrt_ * log(card));
988  tree->nearestK(motion, k, nbh);
989  }
990 }
991 
992 bool ompl::geometric::STRRTstar::rewireGoalTree(Motion *addedMotion)
993 {
994  bool solved = false;
995  std::vector<Motion *> nbh;
996  getNeighbors(tGoal_, addedMotion, nbh);
997  double nodeT =
998  addedMotion->state->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position;
999  double goalT =
1000  addedMotion->root->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position;
1001 
1002  for (Motion *otherMotion : nbh)
1003  {
1004  double otherNodeT =
1005  otherMotion->state->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position;
1006  double otherGoalT =
1007  otherMotion->root->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position;
1008  // rewire, if goal time is improved and the otherMotion node can be connected to the added node
1009  if (otherNodeT < nodeT && goalT < otherGoalT && si_->checkMotion(otherMotion->state, addedMotion->state))
1010  {
1011  if (otherMotion->numConnections > 0)
1012  {
1013  Motion *p = otherMotion->parent;
1014  while (p != nullptr)
1015  {
1016  p->numConnections--;
1017  p = p->parent;
1018  }
1019  }
1020  removeFromParent(otherMotion);
1021  otherMotion->parent = addedMotion;
1022  otherMotion->root = addedMotion->root;
1023  addedMotion->children.push_back(otherMotion);
1024  // increase connection count of new ancestors
1025  if (otherMotion->numConnections > 0)
1026  {
1027  Motion *p = otherMotion->parent;
1028  while (p != nullptr)
1029  {
1030  p->numConnections++;
1031  p = p->parent;
1032  }
1033  if (otherMotion->root->as<ompl::base::CompoundState>()
1035  ->position < upperTimeBound_)
1036  {
1037  solved = true;
1038  }
1039  }
1040  }
1041  }
1042 
1043  return solved;
1044 }
1045 
1047 {
1048  const auto dim = static_cast<double>(si_->getStateDimension());
1049 
1050  // r_rrt > (2*(1+1/d))^(1/d)*(measure/ballvolume)^(1/d)
1051  // prunedMeasure_ is set to si_->getSpaceMeasure();
1052  r_rrt_ = rewireFactor_ * std::pow(2 * (1.0 + 1.0 / dim) *
1053  (si_->getSpaceMeasure() / ompl::unitNBallMeasure(si_->getStateDimension())),
1054  1.0 / dim);
1055 
1056  // k_rrg > e * (1 + 1 / d). K-nearest RRT*
1057  k_rrt_ = rewireFactor_ * boost::math::constants::e<double>() * (1.0 + 1.0 / dim);
1058 }
1059 
1060 bool ompl::geometric::STRRTstar::sampleGoalTime(ompl::base::State *goal, double oldBatchTimeBoundFactor,
1061  double newBatchTimeBoundFactor)
1062 {
1063  double ltb, utb;
1064  double minTime =
1065  si_->getStateSpace()->as<ompl::base::SpaceTimeStateSpace>()->timeToCoverDistance(startMotion_->state, goal);
1066  if (isTimeBounded_)
1067  {
1068  ltb = minTime;
1069  utb = upperTimeBound_;
1070  }
1071  else if (sampleOldBatch_)
1072  {
1073  ltb = minTime;
1074  utb = minTime * oldBatchTimeBoundFactor;
1075  }
1076  else
1077  {
1078  ltb = minTime * oldBatchTimeBoundFactor;
1079  utb = minTime * newBatchTimeBoundFactor;
1080  }
1081 
1082  if (ltb > utb)
1083  return false; // goal can't be reached in time
1084 
1085  double time = ltb == utb ? ltb : rng_.uniformReal(ltb, utb);
1086  goal->as<ompl::base::CompoundState>()->as<ompl::base::TimeStateSpace::StateType>(1)->position = time;
1087  return true;
1088 }
1089 
1090 ompl::base::State *ompl::geometric::STRRTstar::nextGoal(int n, double oldBatchTimeBoundFactor,
1091  double newBatchTimeBoundFactor)
1092 {
1094  return nextGoal(ptc, n, oldBatchTimeBoundFactor, newBatchTimeBoundFactor);
1095 }
1096 
1098  double oldBatchTimeBoundFactor, double newBatchTimeBoundFactor)
1099 {
1100  return nextGoal(ptc, -1, oldBatchTimeBoundFactor, newBatchTimeBoundFactor);
1101 }
1102 
1104  double oldBatchTimeBoundFactor, double newBatchTimeBoundFactor)
1105 {
1106  if (pdef_->getGoal() != nullptr)
1107  {
1108  const ompl::base::GoalSampleableRegion *goal = pdef_->getGoal()->hasType(ompl::base::GOAL_SAMPLEABLE_REGION) ?
1109  pdef_->getGoal()->as<ompl::base::GoalSampleableRegion>() :
1110  nullptr;
1111 
1112  if (goal != nullptr)
1113  {
1114  if (tempState_ == nullptr)
1115  tempState_ = si_->allocState();
1116  int tryCount = 0;
1117  do
1118  {
1119  goal->sampleGoal(tempState_); // sample space component
1120  // sample time component dependant on sampled space
1121  bool inTime = sampleGoalTime(tempState_, oldBatchTimeBoundFactor, newBatchTimeBoundFactor);
1122  bool bounds = inTime && si_->satisfiesBounds(tempState_);
1123  bool valid = bounds && si_->isValid(tempState_);
1124  if (valid)
1125  {
1126  return tempState_;
1127  }
1128  } while (!ptc.eval() && ++tryCount != n);
1129  }
1130  }
1131 
1132  return nullptr;
1133 }
1134 
1136 {
1137  maxDistance_ = distance;
1138 }
1139 
1141 {
1142  return maxDistance_;
1143 }
1144 
1146 {
1147  return optimumApproxFactor_;
1148 }
1149 
1151 {
1152  if (optimumApproxFactor <= 0 || optimumApproxFactor > 1)
1153  {
1154  OMPL_ERROR("%s: The optimum approximation factor needs to be between 0 and 1.", getName().c_str());
1155  }
1156  optimumApproxFactor_ = optimumApproxFactor;
1157 }
1158 
1159 std::string ompl::geometric::STRRTstar::getRewiringState() const
1160 {
1161  std::vector<std::string> s{"Radius", "KNearest", "Off"};
1162  return s[rewireState_];
1163 }
1164 
1166 {
1167  rewireState_ = OFF;
1168 }
1169 
1171 {
1172  rewireState_ = RADIUS;
1173 }
1174 
1176 {
1177  rewireState_ = KNEAREST;
1178 }
1179 
1180 double ompl::geometric::STRRTstar::getRewireFactor() const
1181 {
1182  return rewireFactor_;
1183 }
1184 
1185 void ompl::geometric::STRRTstar::setRewireFactor(double v)
1186 {
1187  if (v <= 1)
1188  {
1189  OMPL_ERROR("%s: Rewire Factor needs to be greater than 1.", getName().c_str());
1190  }
1191  rewireFactor_ = v;
1192 }
1193 
1195 {
1196  return initialBatchSize_;
1197 }
1198 
1199 void ompl::geometric::STRRTstar::setBatchSize(int v)
1200 {
1201  if (v < 1)
1202  {
1203  OMPL_ERROR("%s: Batch Size needs to be at least 1.", getName().c_str());
1204  }
1205  initialBatchSize_ = v;
1206 }
1207 
1209 {
1210  if (f <= 1.0)
1211  {
1212  OMPL_ERROR("%s: Time Bound Factor Increase needs to be higher than 1.", getName().c_str());
1213  }
1214  timeBoundFactorIncrease_ = f;
1215 }
1216 
1218 {
1219  if (f <= 1.0)
1220  {
1221  OMPL_ERROR("%s: Initial Time Bound Factor Increase needs to be higher than 1.", getName().c_str());
1222  }
1223  initialTimeBoundFactor_ = f;
1224 }
1225 
1227 {
1228  sampleUniformForUnboundedTime_ = uniform;
1229 }
void setSampleUniformForUnboundedTime(bool uniform)
Whether the state space is sampled uniformly or centered at lower time values.
Definition: STRRTstar.cpp:1226
Definition of a compound state.
Definition: State.h:150
void removeInvalidGoals(const std::vector< Motion * > &invalidGoals)
Remove invalid goal states from the goal set.
Definition: STRRTstar.cpp:854
@ UNRECOGNIZED_GOAL_TYPE
The goal is of a type that a planner does not recognize.
A shared pointer wrapper for ompl::base::SpaceInformation.
void configurePlannerRange(double &range)
Compute what a good length for motion segments is.
Definition: SelfConfig.cpp:225
@ APPROXIMATE_SOLUTION
The planner found an approximate solution.
void getPlannerData(base::PlannerData &data) const override
Get information about the current run of the motion planner. Repeated calls to this function will upd...
Definition: STRRTstar.cpp:896
double position
The position in time.
const T * as(unsigned int index) const
Cast a component of this instance to a desired type.
Definition: State.h:159
static void addDescendants(Motion *m, const TreeData &tree)
Adds given all descendants of the given motion to given tree and checks whether one of the added moti...
Definition: STRRTstar.cpp:957
static Motion * computeSolutionMotion(Motion *motion)
Find the solution (connecting) motion for a motion that is indirectly connected.
Definition: STRRTstar.cpp:833
Definition of an abstract state.
Definition: State.h:113
void setRewiringToKNearest()
Rewire by k-nearest.
Definition: STRRTstar.cpp:1175
This class contains methods that automatically configure various parameters for motion planning....
Definition: SelfConfig.h:122
unsigned int getBatchSize() const
The number of samples before the time bound is increased.
Definition: STRRTstar.cpp:1194
A state space consisting of a space and a time component.
bool sampleGoalTime(base::State *goal, double oldBatchTimeBoundFactor, double newBatchTimeBoundFactor)
Samples the time component of a goal state dependant on its space component. Returns false,...
Definition: STRRTstar.cpp:1060
void setTimeBoundFactorIncrease(double f)
The value by which the time bound factor is multiplied in each increase step.
Definition: STRRTstar.cpp:1208
Representation of a solution to a planning problem.
Information attached to growing a tree of motions (used internally)
Definition: STRRTstar.h:230
void log(const char *file, int line, LogLevel level, const char *m,...)
Root level logging function. This should not be invoked directly, but rather used via a logging macro...
Definition: Console.cpp:120
void increaseTimeBound(bool hasEqualBounds, double &oldBatchTimeBoundFactor, double &newBatchTimeBoundFactor, bool &startTree, unsigned int &batchSize, int &numBatchSamples)
Definition: STRRTstar.cpp:552
Definition of a cost value. Can represent the cost of a motion or the cost of a state.
Definition: Cost.h:111
double getRange() const
Get the range the planner is using.
Definition: STRRTstar.cpp:1140
#define OMPL_INFORM(fmt,...)
Log a formatted information string.
Definition: Console.h:68
@ TIMEOUT
The planner failed to find a solution.
A shared pointer wrapper for ompl::base::OptimizationObjective.
const T * as() const
Cast this instance to a desired type.
Definition: State.h:162
GrowState
The state of the tree after an attempt to extend it.
Definition: STRRTstar.h:238
double getOptimumApproxFactor() const
The Optimum Approximation factor (0 - 1).
Definition: STRRTstar.cpp:1145
Object containing planner generated vertex and edge data. It is assumed that all vertices are unique,...
Definition: PlannerData.h:238
double unitNBallMeasure(unsigned int N)
The Lebesgue measure (i.e., "volume") of an n-dimensional ball with a unit radius.
Motion * pruneGoalTree()
Prune the goal tree after a solution was found. Return the goal motion, that is connected to the star...
Definition: STRRTstar.cpp:715
double timeToCoverDistance(const ompl::base::State *state1, const ompl::base::State *state2) const
The time to get from state1 to state2 with respect to vMax.
Encapsulate a termination condition for a motion planner. Planners will call operator() to decide whe...
std::vector< Motion * > children
The set of motions descending from the current motion.
PlannerSpecs specs_
The specifications of the planner (its capabilities)
Definition: Planner.h:486
@ INVALID_GOAL
Invalid goal state.
unsigned int vertexIndex(const PlannerDataVertex &v) const
Return the index for the vertex associated with the given data. INVALID_INDEX is returned if this ver...
void getNeighbors(TreeData &tree, Motion *motion, std::vector< Motion * > &nbh) const
Gets the neighbours of a given motion, using either k-nearest or radius_ as appropriate.
Definition: STRRTstar.cpp:972
bool optimizingPaths
Flag indicating whether the planner attempts to optimize the path and reduce its length until the max...
Definition: Planner.h:263
A class to store the exit status of Planner::solve()
base::State * nextGoal(int n, double oldBatchTimeBoundFactor, double newBatchTimeBoundFactor)
N tries to sample a goal.
Definition: STRRTstar.cpp:1090
double distanceBetweenTrees_
Distance between the nearest pair of start tree and goal tree nodes.
Definition: STRRTstar.h:302
bool canReportIntermediateSolutions
Flag indicating whether the planner is able to report the computation of intermediate paths.
Definition: Planner.h:275
base::PlannerStatus solve(const base::PlannerTerminationCondition &ptc) override
Function that can solve the motion planning problem. This function can be called multiple times on th...
Definition: STRRTstar.cpp:120
GrowState growTree(TreeData &tree, TreeGrowingInfo &tgi, Motion *rmotion, std::vector< Motion * > &nbh, bool connect)
Attempt to grow a tree towards a random state for the neighborhood of the random state....
Definition: STRRTstar.cpp:443
void calculateRewiringLowerBounds()
Calculate the k_RRG* and r_RRG* terms.
Definition: STRRTstar.cpp:1046
std::shared_ptr< ompl::NearestNeighbors< Motion * > > TreeData
A nearest-neighbor datastructure representing a tree of motions.
Definition: STRRTstar.h:226
The definition of a time state.
A nearest neighbors datastructure that uses linear search.
void setRange(double distance)
Set the range the planner is supposed to use.
Definition: STRRTstar.cpp:1135
bool eval() const
The implementation of some termination condition. By default, this just calls fn_()
@ GOAL_SAMPLEABLE_REGION
This bit is set if casting to sampleable goal regions (ompl::base::GoalSampleableRegion) is possible.
Definition: GoalTypes.h:152
std::map< std::string, std::string > properties
Any extra properties (key-value pairs) the planner can set.
Definition: PlannerData.h:474
void freeMemory()
Free the memory allocated by this planner.
Definition: STRRTstar.cpp:90
@ EXACT_SOLUTION
The planner found an exact solution.
void setRewiringToRadius()
Rewire by radius.
Definition: STRRTstar.cpp:1170
void setRewiringToOff()
Do not rewire at all.
Definition: STRRTstar.cpp:1165
PlannerTerminationCondition plannerNonTerminatingCondition()
Simple termination condition that always returns false. The termination condition will never be met.
void setOptimized(const OptimizationObjectivePtr &opt, Cost cost, bool meetsObjective)
Set the optimization objective used to optimize this solution, the cost of the solution and whether i...
std::function< void(const Planner *, const std::vector< const base::State * > &, const Cost)> ReportIntermediateSolutionFn
When a planner has an intermediate solution (e.g., optimizing planners), a function with this signatu...
unsigned int addStartVertex(const PlannerDataVertex &v)
Adds the given vertex to the graph data, and marks it as a start vertex. The vertex index is returned...
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
Definition: Console.h:64
void clear() override
Clear all internal datastructures. Planner settings are not affected. Subsequent calls to solve() wil...
Definition: STRRTstar.cpp:872
void setPlannerName(const std::string &name)
Set the name of the planner used to compute this solution.
static void removeFromParent(Motion *m)
Removes the given motion from the parent's child list.
Definition: STRRTstar.cpp:938
virtual bool addEdge(unsigned int v1, unsigned int v2, const PlannerDataEdge &edge=PlannerDataEdge(), Cost weight=Cost(1.0))
Adds a directed edge between the given vertex indexes. An optional edge structure and weight can be s...
unsigned int addGoalVertex(const PlannerDataVertex &v)
Adds the given vertex to the graph data, and marks it as a start vertex. The vertex index is returned...
Abstract definition of a goal region that can be sampled.
void pruneStartTree()
Prune the start tree after a solution was found.
Definition: STRRTstar.cpp:651
GrowState growTreeSingle(TreeData &tree, TreeGrowingInfo &tgi, Motion *rmotion, Motion *nmotion)
Grow a tree towards a random state for a single nearest state.
Definition: STRRTstar.cpp:512
The exception type for ompl.
Definition: Exception.h:78
void setOptimumApproxFactor(double optimumApproxFactor)
Set the Optimum Approximation factor. This allows the planner to converge more quickly,...
Definition: STRRTstar.cpp:1150
void setup() override
Perform extra configuration steps, if needed. This call will also issue a call to ompl::base::SpaceIn...
Definition: STRRTstar.cpp:59
STRRTstar(const ompl::base::SpaceInformationPtr &si)
Constructor.
Definition: STRRTstar.cpp:40
const std::string & getName() const
Get the name of the planner.
Definition: Planner.cpp:56
@ INVALID_START
Invalid start state or no start state specified.
std::string toString(float val)
convert float to string using classic "C" locale semantics
Definition: String.cpp:82
void setInitialTimeBoundFactor(double f)
The initial time bound factor.
Definition: STRRTstar.cpp:1217
Base class for a vertex in the PlannerData structure. All derived classes must implement the clone an...
Definition: PlannerData.h:122