FMT.cpp
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2013, Autonomous Systems Laboratory, Stanford University
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 Stanford University 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 /* Authors: Ashley Clark (Stanford) and Wolfgang Pointner (AIT) */
36 /* Co-developers: Brice Rebsamen (Stanford), Tim Wheeler (Stanford)
37  Edward Schmerling (Stanford), and Javier V. Gómez (UC3M - Stanford)*/
38 /* Algorithm design: Lucas Janson (Stanford) and Marco Pavone (Stanford) */
39 /* Acknowledgements for insightful comments: Oren Salzman (Tel Aviv University),
40  * Joseph Starek (Stanford) */
41 
42 #include <limits>
43 #include <iostream>
44 
45 #include <boost/math/constants/constants.hpp>
46 #include <boost/math/distributions/binomial.hpp>
47 
48 #include <ompl/datastructures/BinaryHeap.h>
49 #include <ompl/tools/config/SelfConfig.h>
50 #include <ompl/base/objectives/PathLengthOptimizationObjective.h>
51 #include <ompl/geometric/planners/fmt/FMT.h>
52 
53 
54 ompl::geometric::FMT::FMT(const base::SpaceInformationPtr &si)
55  : base::Planner(si, "FMT")
56  , numSamples_(1000)
57  , collisionChecks_(0)
58  , nearestK_(true)
59  , cacheCC_(true)
60  , heuristics_(false)
61  , radiusMultiplier_(1.1)
62  , extendedFMT_(true)
63 {
64  // An upper bound on the free space volume is the total space volume; the free fraction is estimated in sampleFree
65  freeSpaceVolume_ = si_->getStateSpace()->getMeasure();
66  lastGoalMotion_ = nullptr;
67 
69  specs_.directed = false;
70 
71  ompl::base::Planner::declareParam<unsigned int>("num_samples", this, &FMT::setNumSamples, &FMT::getNumSamples, "10:10:1000000");
72  ompl::base::Planner::declareParam<double>("radius_multiplier", this, &FMT::setRadiusMultiplier, &FMT::getRadiusMultiplier, "0.1:0.05:50.");
73  ompl::base::Planner::declareParam<bool>("nearest_k", this, &FMT::setNearestK, &FMT::getNearestK, "0,1");
74  ompl::base::Planner::declareParam<bool>("cache_cc", this, &FMT::setCacheCC, &FMT::getCacheCC, "0,1");
75  ompl::base::Planner::declareParam<bool>("heuristics", this, &FMT::setHeuristics, &FMT::getHeuristics, "0,1");
76  ompl::base::Planner::declareParam<bool>("extended_fmt", this, &FMT::setExtendedFMT, &FMT::getExtendedFMT, "0,1");
77 }
78 
79 ompl::geometric::FMT::~FMT()
80 {
81  freeMemory();
82 }
83 
85 {
86  if (pdef_)
87  {
88  /* Setup the optimization objective. If no optimization objective was
89  specified, then default to optimizing path length as computed by the
90  distance() function in the state space */
91  if (pdef_->hasOptimizationObjective())
92  opt_ = pdef_->getOptimizationObjective();
93  else
94  {
95  OMPL_INFORM("%s: No optimization objective specified. Defaulting to optimizing path length.", getName().c_str());
96  opt_.reset(new base::PathLengthOptimizationObjective(si_));
97  // Store the new objective in the problem def'n
98  pdef_->setOptimizationObjective(opt_);
99  }
100  Open_.getComparisonOperator().opt_ = opt_.get();
101  Open_.getComparisonOperator().heuristics_ = heuristics_;
102 
103  if (!nn_)
104  nn_.reset(tools::SelfConfig::getDefaultNearestNeighbors<Motion*>(this));
105  nn_->setDistanceFunction(std::bind(&FMT::distanceFunction, this,
106  std::placeholders::_1, std::placeholders::_2));
107 
108  if (nearestK_ && !nn_->reportsSortedResults())
109  {
110  OMPL_WARN("%s: NearestNeighbors datastructure does not return sorted solutions. Nearest K strategy disabled.", getName().c_str());
111  nearestK_ = false;
112  }
113  }
114  else
115  {
116  OMPL_INFORM("%s: problem definition is not set, deferring setup completion...", getName().c_str());
117  setup_ = false;
118  }
119 }
120 
122 {
123  if (nn_)
124  {
125  std::vector<Motion*> motions;
126  motions.reserve(nn_->size());
127  nn_->list(motions);
128  for (unsigned int i = 0 ; i < motions.size() ; ++i)
129  {
130  si_->freeState(motions[i]->getState());
131  delete motions[i];
132  }
133  }
134 }
135 
137 {
138  Planner::clear();
139  lastGoalMotion_ = nullptr;
140  sampler_.reset();
141  freeMemory();
142  if (nn_)
143  nn_->clear();
144  Open_.clear();
145  neighborhoods_.clear();
146 
147  collisionChecks_ = 0;
148 }
149 
151 {
152  Planner::getPlannerData(data);
153  std::vector<Motion*> motions;
154  nn_->list(motions);
155 
156  if (lastGoalMotion_)
157  data.addGoalVertex(base::PlannerDataVertex(lastGoalMotion_->getState()));
158 
159  unsigned int size = motions.size();
160  for (unsigned int i = 0; i < size; ++i)
161  {
162  if (motions[i]->getParent() == nullptr)
163  data.addStartVertex(base::PlannerDataVertex(motions[i]->getState()));
164  else
165  data.addEdge(base::PlannerDataVertex(motions[i]->getParent()->getState()),
166  base::PlannerDataVertex(motions[i]->getState()));
167  }
168 }
169 
171 {
172  // Check to see if neighborhood has not been saved yet
173  if (neighborhoods_.find(m) == neighborhoods_.end())
174  {
175  std::vector<Motion*> nbh;
176  if (nearestK_)
177  nn_->nearestK(m, NNk_, nbh);
178  else
179  nn_->nearestR(m, NNr_, nbh);
180  if (!nbh.empty())
181  {
182  // Save the neighborhood but skip the first element, since it will be motion m
183  neighborhoods_[m] = std::vector<Motion*>(nbh.size() - 1, 0);
184  std::copy(nbh.begin() + 1, nbh.end(), neighborhoods_[m].begin());
185  }
186  else
187  {
188  // Save an empty neighborhood
189  neighborhoods_[m] = std::vector<Motion*>(0);
190  }
191  } // If neighborhood hadn't been saved yet
192 }
193 
194 // Calculate the unit ball volume for a given dimension
195 double ompl::geometric::FMT::calculateUnitBallVolume(const unsigned int dimension) const
196 {
197  if (dimension == 0)
198  return 1.0;
199  else if (dimension == 1)
200  return 2.0;
201  return 2.0 * boost::math::constants::pi<double>() / dimension
202  * calculateUnitBallVolume(dimension - 2);
203 }
204 
205 double ompl::geometric::FMT::calculateRadius(const unsigned int dimension, const unsigned int n) const
206 {
207  double a = 1.0 / (double)dimension;
208  double unitBallVolume = calculateUnitBallVolume(dimension);
209 
210  return radiusMultiplier_ * 2.0 * std::pow(a, a) * std::pow(freeSpaceVolume_ / unitBallVolume, a) * std::pow(log((double)n) / (double)n, a);
211 }
212 
214 {
215  unsigned int nodeCount = 0;
216  unsigned int sampleAttempts = 0;
217  Motion *motion = new Motion(si_);
218 
219  // Sample numSamples_ number of nodes from the free configuration space
220  while (nodeCount < numSamples_ && !ptc)
221  {
222  sampler_->sampleUniform(motion->getState());
223  sampleAttempts++;
224 
225  bool collision_free = si_->isValid(motion->getState());
226 
227  if (collision_free)
228  {
229  nodeCount++;
230  nn_->add(motion);
231  motion = new Motion(si_);
232  } // If collision free
233  } // While nodeCount < numSamples
234  si_->freeState(motion->getState());
235  delete motion;
236 
237  // 95% confidence limit for an upper bound for the true free space volume
238  freeSpaceVolume_ = boost::math::binomial_distribution<>::find_upper_bound_on_p(sampleAttempts, nodeCount, 0.05) * si_->getStateSpace()->getMeasure();
239 }
240 
242 {
243  // Ensure that there is at least one node near each goal
244  while (const base::State *goalState = pis_.nextGoal())
245  {
246  Motion *gMotion = new Motion(si_);
247  si_->copyState(gMotion->getState(), goalState);
248 
249  std::vector<Motion*> nearGoal;
250  nn_->nearestR(gMotion, goal->getThreshold(), nearGoal);
251 
252  // If there is no node in the goal region, insert one
253  if (nearGoal.empty())
254  {
255  OMPL_DEBUG("No state inside goal region");
256  if (si_->getStateValidityChecker()->isValid(gMotion->getState()))
257  {
258  nn_->add(gMotion);
259  goalState_ = gMotion->getState();
260  }
261  else
262  {
263  si_->freeState(gMotion->getState());
264  delete gMotion;
265  }
266  }
267  else // There is already a sample in the goal region
268  {
269  goalState_ = nearGoal[0]->getState();
270  si_->freeState(gMotion->getState());
271  delete gMotion;
272  }
273  } // For each goal
274 }
275 
277 {
278  if (lastGoalMotion_) {
279  OMPL_INFORM("solve() called before clear(); returning previous solution");
280  traceSolutionPathThroughTree(lastGoalMotion_);
281  OMPL_DEBUG("Final path cost: %f", lastGoalMotion_->getCost().value());
282  return base::PlannerStatus(true, false);
283  }
284  else if (Open_.size() > 0)
285  {
286  OMPL_INFORM("solve() called before clear(); no previous solution so starting afresh");
287  clear();
288  }
289 
290  checkValidity();
291  base::GoalSampleableRegion *goal = dynamic_cast<base::GoalSampleableRegion*>(pdef_->getGoal().get());
292  Motion *initMotion = nullptr;
293 
294  if (!goal)
295  {
296  OMPL_ERROR("%s: Unknown type of goal", getName().c_str());
298  }
299 
300  // Add start states to V (nn_) and Open
301  while (const base::State *st = pis_.nextStart())
302  {
303  initMotion = new Motion(si_);
304  si_->copyState(initMotion->getState(), st);
305  Open_.insert(initMotion);
306  initMotion->setSetType(Motion::SET_OPEN);
307  initMotion->setCost(opt_->initialCost(initMotion->getState()));
308  nn_->add(initMotion); // V <-- {x_init}
309  }
310 
311  if (!initMotion)
312  {
313  OMPL_ERROR("Start state undefined");
315  }
316 
317  // Sample N free states in the configuration space
318  if (!sampler_)
319  sampler_ = si_->allocStateSampler();
320  sampleFree(ptc);
321  assureGoalIsSampled(goal);
322  OMPL_INFORM("%s: Starting planning with %u states already in datastructure", getName().c_str(), nn_->size());
323 
324  // Calculate the nearest neighbor search radius
326  if (nearestK_)
327  {
328  NNk_ = std::ceil(std::pow(2.0 * radiusMultiplier_, (double)si_->getStateDimension()) *
329  (boost::math::constants::e<double>() / (double)si_->getStateDimension()) *
330  log((double)nn_->size()));
331  OMPL_DEBUG("Using nearest-neighbors k of %d", NNk_);
332  }
333  else
334  {
335  NNr_ = calculateRadius(si_->getStateDimension(), nn_->size());
336  OMPL_DEBUG("Using radius of %f", NNr_);
337  }
338 
339  // Execute the planner, and return early if the planner returns a failure
340  bool plannerSuccess = false;
341  bool successfulExpansion = false;
342  Motion *z = initMotion; // z <-- xinit
343  saveNeighborhood(z);
344 
345  while (!ptc)
346  {
347  if ((plannerSuccess = goal->isSatisfied(z->getState())))
348  break;
349 
350  successfulExpansion = expandTreeFromNode(&z);
351 
352  if (!extendedFMT_ && !successfulExpansion)
353  break;
354  else if (extendedFMT_ && !successfulExpansion)
355  {
356  //Apply RRT*-like connections: sample and connect samples to tree
357  std::vector<Motion*> nbh;
358  std::vector<base::Cost> costs;
359  std::vector<base::Cost> incCosts;
360  std::vector<std::size_t> sortedCostIndices;
361 
362  // our functor for sorting nearest neighbors
363  CostIndexCompare compareFn(costs, *opt_);
364 
365  Motion *m = new Motion(si_);
366  while (!ptc && Open_.empty())
367  {
368  sampler_->sampleUniform(m->getState());
369 
370  if (!si_->isValid(m->getState()))
371  continue;
372 
373  if (nearestK_)
374  nn_->nearestK(m, NNk_, nbh);
375  else
376  nn_->nearestR(m, NNr_, nbh);
377 
378  // Get neighbours in the tree.
379  std::vector<Motion*> yNear;
380  yNear.reserve(nbh.size());
381  for (std::size_t j = 0; j < nbh.size(); ++j)
382  {
383  if (nbh[j]->getSetType() == Motion::SET_CLOSED)
384  {
385  if (nearestK_)
386  {
387  // Only include neighbors that are mutually k-nearest
388  // Relies on NN datastructure returning k-nearest in sorted order
389  const base::Cost connCost = opt_->motionCost(nbh[j]->getState(), m->getState());
390  const base::Cost worstCost = opt_->motionCost(neighborhoods_[nbh[j]].back()->getState(), nbh[j]->getState());
391 
392  if (opt_->isCostBetterThan(worstCost, connCost))
393  continue;
394  else
395  yNear.push_back(nbh[j]);
396  }
397  else
398  yNear.push_back(nbh[j]);
399  }
400  }
401 
402  // Sample again if the new sample does not connect to the tree.
403  if (yNear.empty())
404  continue;
405 
406  // cache for distance computations
407  //
408  // Our cost caches only increase in size, so they're only
409  // resized if they can't fit the current neighborhood
410  if (costs.size() < yNear.size())
411  {
412  costs.resize(yNear.size());
413  incCosts.resize(yNear.size());
414  sortedCostIndices.resize(yNear.size());
415  }
416 
417  // Finding the nearest neighbor to connect to
418  // By default, neighborhood states are sorted by cost, and collision checking
419  // is performed in increasing order of cost
420  //
421  // calculate all costs and distances
422  for (std::size_t i = 0 ; i < yNear.size(); ++i)
423  {
424  incCosts[i] = opt_->motionCost(yNear[i]->getState(), m->getState());
425  costs[i] = opt_->combineCosts(yNear[i]->getCost(), incCosts[i]);
426  }
427 
428  // sort the nodes
429  //
430  // we're using index-value pairs so that we can get at
431  // original, unsorted indices
432  for (std::size_t i = 0; i < yNear.size(); ++i)
433  sortedCostIndices[i] = i;
434  std::sort(sortedCostIndices.begin(), sortedCostIndices.begin() + yNear.size(),
435  compareFn);
436 
437  // collision check until a valid motion is found
438  for (std::vector<std::size_t>::const_iterator i = sortedCostIndices.begin();
439  i != sortedCostIndices.begin() + yNear.size();
440  ++i)
441  {
442  if (si_->checkMotion(yNear[*i]->getState(), m->getState()))
443  {
444  m->setParent(yNear[*i]);
445  yNear[*i]->getChildren().push_back(m);
446  const base::Cost incCost = opt_->motionCost(yNear[*i]->getState(), m->getState());
447  m->setCost(opt_->combineCosts(yNear[*i]->getCost(), incCost));
448  m->setHeuristicCost(opt_->motionCostHeuristic(m->getState(), goalState_));
449  m->setSetType(Motion::SET_OPEN);
450 
451  nn_->add(m);
452  saveNeighborhood(m);
453  updateNeighborhood(m,nbh);
454 
455  Open_.insert(m);
456  z = m;
457  break;
458  }
459  }
460  } // while (!ptc && Open_.empty())
461  } // else if (extendedFMT_ && !successfulExpansion)
462  } // While not at goal
463 
464  if (plannerSuccess)
465  {
466  // Return the path to z, since by definition of planner success, z is in the goal region
467  lastGoalMotion_ = z;
468  traceSolutionPathThroughTree(lastGoalMotion_);
469 
470  OMPL_DEBUG("Final path cost: %f", lastGoalMotion_->getCost().value());
471 
472  return base::PlannerStatus(true, false);
473  } // if plannerSuccess
474  else
475  {
476  // Planner terminated without accomplishing goal
477  return base::PlannerStatus(false, false);
478  }
479 }
480 
482 {
483  std::vector<Motion*> mpath;
484  Motion *solution = goalMotion;
485 
486  // Construct the solution path
487  while (solution != nullptr)
488  {
489  mpath.push_back(solution);
490  solution = solution->getParent();
491  }
492 
493  // Set the solution path
494  PathGeometric *path = new PathGeometric(si_);
495  int mPathSize = mpath.size();
496  for (int i = mPathSize - 1 ; i >= 0 ; --i)
497  path->append(mpath[i]->getState());
498  pdef_->addSolutionPath(base::PathPtr(path), false, -1.0, getName());
499 }
500 
502 {
503  // Find all nodes that are near z, and also in set Unvisited
504 
505  std::vector<Motion*> xNear;
506  const std::vector<Motion*> &zNeighborhood = neighborhoods_[*z];
507  const unsigned int zNeighborhoodSize = zNeighborhood.size();
508  xNear.reserve(zNeighborhoodSize);
509 
510  for (unsigned int i = 0; i < zNeighborhoodSize; ++i)
511  {
512  Motion *x = zNeighborhood[i];
513  if (x->getSetType() == Motion::SET_UNVISITED)
514  {
515  saveNeighborhood(x);
516  if (nearestK_)
517  {
518  // Only include neighbors that are mutually k-nearest
519  // Relies on NN datastructure returning k-nearest in sorted order
520  const base::Cost connCost = opt_->motionCost((*z)->getState(), x->getState());
521  const base::Cost worstCost = opt_->motionCost(neighborhoods_[x].back()->getState(), x->getState());
522 
523  if (opt_->isCostBetterThan(worstCost, connCost))
524  continue;
525  else
526  xNear.push_back(x);
527  }
528  else
529  xNear.push_back(x);
530  }
531  }
532 
533  // For each node near z and in set Unvisited, attempt to connect it to set Open
534  std::vector<Motion*> yNear;
535  std::vector<Motion*> Open_new;
536  const unsigned int xNearSize = xNear.size();
537  for (unsigned int i = 0 ; i < xNearSize; ++i)
538  {
539  Motion *x = xNear[i];
540 
541  // Find all nodes that are near x and in set Open
542  const std::vector<Motion*> &xNeighborhood = neighborhoods_[x];
543 
544  const unsigned int xNeighborhoodSize = xNeighborhood.size();
545  yNear.reserve(xNeighborhoodSize);
546  for (unsigned int j = 0; j < xNeighborhoodSize; ++j)
547  {
548  if (xNeighborhood[j]->getSetType() == Motion::SET_OPEN)
549  yNear.push_back(xNeighborhood[j]);
550  }
551 
552  // Find the lowest cost-to-come connection from Open to x
553  base::Cost cMin(std::numeric_limits<double>::infinity());
554  Motion *yMin = getBestParent(x, yNear, cMin);
555  yNear.clear();
556 
557  // If an optimal connection from Open to x was found
558  if (yMin != nullptr)
559  {
560  bool collision_free = false;
561  if (cacheCC_)
562  {
563  if (!yMin->alreadyCC(x))
564  {
565  collision_free = si_->checkMotion(yMin->getState(), x->getState());
566  ++collisionChecks_;
567  // Due to FMT* design, it is only necessary to save unsuccesful
568  // connection attemps because of collision
569  if (!collision_free)
570  yMin->addCC(x);
571  }
572  }
573  else
574  {
575  ++collisionChecks_;
576  collision_free = si_->checkMotion(yMin->getState(), x->getState());
577  }
578 
579  if (collision_free)
580  {
581  // Add edge from yMin to x
582  x->setParent(yMin);
583  x->setCost(cMin);
584  x->setHeuristicCost(opt_->motionCostHeuristic(x->getState(), goalState_));
585  yMin->getChildren().push_back(x);
586 
587  // Add x to Open
588  Open_new.push_back(x);
589  // Remove x from Unvisited
590  x->setSetType(Motion::SET_CLOSED);
591  }
592  } // An optimal connection from Open to x was found
593  } // For each node near z and in set Unvisited, try to connect it to set Open
594 
595  // Update Open
596  Open_.pop();
597  (*z)->setSetType(Motion::SET_CLOSED);
598 
599  // Add the nodes in Open_new to Open
600  unsigned int openNewSize = Open_new.size();
601  for (unsigned int i = 0; i < openNewSize; ++i)
602  {
603  Open_.insert(Open_new[i]);
604  Open_new[i]->setSetType(Motion::SET_OPEN);
605  }
606  Open_new.clear();
607 
608  if (Open_.empty())
609  {
610  if(!extendedFMT_)
611  OMPL_INFORM("Open is empty before path was found --> no feasible path exists");
612  return false;
613  }
614 
615  // Take the top of Open as the new z
616  *z = Open_.top()->data;
617 
618  return true;
619 }
620 
622 {
623  Motion *min = nullptr;
624  const unsigned int neighborsSize = neighbors.size();
625  for (unsigned int j = 0; j < neighborsSize; ++j)
626  {
627  const base::State *s = neighbors[j]->getState();
628  const base::Cost dist = opt_->motionCost(s, m->getState());
629  const base::Cost cNew = opt_->combineCosts(neighbors[j]->getCost(), dist);
630 
631  if (opt_->isCostBetterThan(cNew, cMin))
632  {
633  min = neighbors[j];
634  cMin = cNew;
635  }
636  }
637  return min;
638 }
639 
640 void ompl::geometric::FMT::updateNeighborhood(Motion *m, const std::vector<Motion*> nbh)
641 {
642  for (std::size_t i = 0; i < nbh.size(); ++i)
643  {
644  // If CLOSED, the neighborhood already exists. If neighborhood already exists, we have
645  // to insert the node in the corresponding place of the neighborhood of the neighbor of m.
646  if (nbh[i]->getSetType() == Motion::SET_CLOSED || neighborhoods_.find(nbh[i]) != neighborhoods_.end())
647  {
648  const base::Cost connCost = opt_->motionCost(nbh[i]->getState(), m->getState());
649  const base::Cost worstCost = opt_->motionCost(neighborhoods_[nbh[i]].back()->getState(), nbh[i]->getState());
650 
651  if (opt_->isCostBetterThan(worstCost, connCost))
652  continue;
653  else
654  {
655  // Insert the neighbor in the vector in the correct order
656  std::vector<Motion*> &nbhToUpdate = neighborhoods_[nbh[i]];
657  for (std::size_t j = 0; j < nbhToUpdate.size(); ++j)
658  {
659  // If connection to the new state is better than the current neighbor tested, insert.
660  const base::Cost cost = opt_->motionCost(nbh[i]->getState(), nbhToUpdate[j]->getState());
661  if (opt_->isCostBetterThan(connCost, cost))
662  {
663  nbhToUpdate.insert(nbhToUpdate.begin()+j, m);
664  break;
665  }
666  }
667  }
668  }
669  else
670  {
671  std::vector<Motion*> nbh2;
672  if (nearestK_)
673  nn_->nearestK(m, NNk_, nbh2);
674  else
675  nn_->nearestR(m, NNr_, nbh2);
676 
677  if (!nbh2.empty())
678  {
679  // Save the neighborhood but skip the first element, since it will be motion m
680  neighborhoods_[nbh[i]] = std::vector<Motion*>(nbh2.size() - 1, 0);
681  std::copy(nbh2.begin() + 1, nbh2.end(), neighborhoods_[nbh[i]].begin());
682  }
683  else
684  {
685  // Save an empty neighborhood
686  neighborhoods_[nbh[i]] = std::vector<Motion*>(0);
687  }
688  }
689  }
690 }
void setExtendedFMT(bool e)
Activates the extended FMT*: adding new samples if planner does not finish successfully.
Definition: FMT.h:200
bool approximateSolutions
Flag indicating whether the planner is able to compute approximate solutions.
Definition: Planner.h:212
Object containing planner generated vertex and edge data. It is assumed that all vertices are unique...
Definition: PlannerData.h:163
void sampleFree(const ompl::base::PlannerTerminationCondition &ptc)
Sample a state from the free configuration space and save it into the nearest neighbors data structur...
Definition: FMT.cpp:213
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 setParent(Motion *parent)
Set the parent motion of the current motion.
Definition: FMT.h:255
bool getNearestK() const
Get the state of the nearestK strategy.
Definition: FMT.h:130
void setRadiusMultiplier(const double radiusMultiplier)
The planner searches for neighbors of a node within a cost r, where r is the value described for FMT*...
Definition: FMT.h:142
void addCC(Motion *m)
Caches a failed collision check to m.
Definition: FMT.h:300
virtual void setup()
Perform extra configuration steps, if needed. This call will also issue a call to ompl::base::SpaceIn...
Definition: FMT.cpp:84
double distanceFunction(const Motion *a, const Motion *b) const
Compute the distance between two motions as the cost between their contained states. Note that for computationally intensive cost functions, the cost between motions should be stored to avoid duplicate calculations.
Definition: FMT.h:373
bool getExtendedFMT() const
Returns true if the extended FMT* is activated.
Definition: FMT.h:206
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...
Encapsulate a termination condition for a motion planner. Planners will call operator() to decide whe...
Representation of a motion.
Definition: FMT.h:214
void freeMemory()
Free the memory allocated by this planner.
Definition: FMT.cpp:121
void append(const base::State *state)
Append state to the end of this path. The memory for state is copied.
void setNumSamples(const unsigned int numSamples)
Set the number of states that the planner should sample. The planner will sample this number of state...
Definition: FMT.h:112
virtual void clear()
Clear all internal datastructures. Planner settings are not affected. Subsequent calls to solve() wil...
Definition: FMT.cpp:136
bool directed
Flag indicating whether the planner is able to account for the fact that the validity of a motion fro...
Definition: Planner.h:220
std::vector< Motion * > & getChildren()
Get the children of the motion.
Definition: FMT.h:318
bool expandTreeFromNode(Motion **z)
Complete one iteration of the main loop of the FMT* algorithm: Find K nearest nodes in set Unvisited ...
Definition: FMT.cpp:501
void traceSolutionPathThroughTree(Motion *goalMotion)
Trace the path from a goal state back to the start state and save the result as a solution in the Pro...
Definition: FMT.cpp:481
virtual base::PlannerStatus solve(const base::PlannerTerminationCondition &ptc)
Function that can solve the motion planning problem. This function can be called multiple times on th...
Definition: FMT.cpp:276
unsigned int getNumSamples() const
Get the number of states that the planner will sample.
Definition: FMT.h:118
Base class for a vertex in the PlannerData structure. All derived classes must implement the clone an...
Definition: PlannerData.h:59
Invalid start state or no start state specified.
Definition: PlannerStatus.h:56
Abstract definition of a goal region that can be sampled.
Motion * getBestParent(Motion *m, std::vector< Motion * > &neighbors, base::Cost &cMin)
Returns the best parent and the connection cost in the neighborhood of a motion m.
Definition: FMT.cpp:621
double getRadiusMultiplier() const
Get the multiplier used for the nearest neighbors search radius.
Definition: FMT.h:151
The goal is of a type that a planner does not recognize.
Definition: PlannerStatus.h:60
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
Definition: Console.h:64
void setCacheCC(bool ccc)
Sets the collision check caching to save calls to the collision checker with slightly memory usage as...
Definition: FMT.h:175
void setSetType(const SetType currentSet)
Specify the set that this motion belongs to.
Definition: FMT.h:279
void saveNeighborhood(Motion *m)
Save the neighbors within a neighborhood of a given state. The strategy used (nearestK or nearestR de...
Definition: FMT.cpp:170
Motion * getParent() const
Get the parent motion of the current motion.
Definition: FMT.h:261
A class to store the exit status of Planner::solve()
Definition: PlannerStatus.h:48
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...
An optimization objective which corresponds to optimizing path length.
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...
Definition of an abstract state.
Definition: State.h:50
base::State * getState() const
Get the state associated with the motion.
Definition: FMT.h:249
void setCost(const base::Cost cost)
Set the cost-to-come for the current motion.
Definition: FMT.h:267
#define OMPL_WARN(fmt,...)
Log a formatted warning string.
Definition: Console.h:66
PlannerSpecs specs_
The specifications of the planner (its capabilities)
Definition: Planner.h:410
void setHeuristics(bool h)
Activates the cost to go heuristics when ordering the heap.
Definition: FMT.h:187
void setNearestK(bool nearestK)
If nearestK is true, FMT will be run using the Knearest strategy.
Definition: FMT.h:124
bool getHeuristics() const
Returns true if the heap is ordered taking into account cost to go heuristics.
Definition: FMT.h:194
#define OMPL_DEBUG(fmt,...)
Log a formatted debugging string.
Definition: Console.h:70
void assureGoalIsSampled(const ompl::base::GoalSampleableRegion *goal)
For each goal region, check to see if any of the sampled states fall within that region. If not, add a goal state from that region directly into the set of vertices. In this way, FMT is able to find a solution, if one exists. If no sampled nodes are within a goal region, there would be no way for the algorithm to successfully find a path to that region.
Definition: FMT.cpp:241
void setHeuristicCost(const base::Cost h)
Set the cost to go heuristic cost.
Definition: FMT.h:306
virtual void getPlannerData(base::PlannerData &data) const
Get information about the current run of the motion planner. Repeated calls to this function will upd...
Definition: FMT.cpp:150
double freeSpaceVolume_
The volume of numSathe free configuration space, computed as an upper bound with 95% confidence...
Definition: BFMT.h:542
double calculateRadius(unsigned int dimension, unsigned int n) const
Calculate the radius to use for nearest neighbor searches, using the bound given in L...
Definition: FMT.cpp:205
SetType getSetType() const
Get the set that this motion belongs to.
Definition: FMT.h:285
double getThreshold() const
Get the distance to the goal that is allowed for a state to be considered in the goal region...
Definition: GoalRegion.h:88
void updateNeighborhood(Motion *m, const std::vector< Motion * > nbh)
For a motion m, updates the stored neighborhoods of all its neighbors by by inserting m (maintaining ...
Definition: FMT.cpp:640
Definition of a geometric path.
Definition: PathGeometric.h:60
SpaceInformationPtr si_
The space information for which planning is done.
Definition: Planner.h:398
virtual bool isSatisfied(const State *st) const
Equivalent to calling isSatisfied(const State *, double *) with a nullptr second argument.
Definition: GoalRegion.cpp:46
bool getCacheCC() const
Get the state of the collision check caching.
Definition: FMT.h:181
double calculateUnitBallVolume(const unsigned int dimension) const
Compute the volume of the unit ball in a given dimension.
Definition: FMT.cpp:195
Definition of a cost value. Can represent the cost of a motion or the cost of a state.
Definition: Cost.h:47
A shared pointer wrapper for ompl::base::Path.
bool alreadyCC(Motion *m)
Returns true if the connection to m has been already tested and failed because of a collision...
Definition: FMT.h:292
#define OMPL_INFORM(fmt,...)
Log a formatted information string.
Definition: Console.h:68