LazyLBTRRT.cpp
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2015, Tel Aviv 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 the Tel Aviv 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 /* Author: Oren Salzman, Mark Moll */
36 
37 #include "ompl/geometric/planners/rrt/LazyLBTRRT.h"
38 #include "ompl/tools/config/SelfConfig.h"
39 #include <limits>
40 #include <boost/foreach.hpp>
41 #include <boost/math/constants/constants.hpp>
42 
43 namespace {
44  int getK(unsigned int n, double k_rrg)
45  {
46  return std::ceil(k_rrg * log((double)(n + 1)));
47  }
48 }
49 
51  base::Planner(si, "LazyLBTRRT"),
52  goalBias_(0.05),
53  maxDistance_(0.0),
54  epsilon_(0.4),
55  lastGoalMotion_(nullptr),
56  goalMotion_(nullptr),
57  LPAstarApx_(nullptr),
58  LPAstarLb_(nullptr),
59  iterations_(0)
60 {
62  specs_.directed = true;
63 
64  Planner::declareParam<double>("range", this, &LazyLBTRRT::setRange, &LazyLBTRRT::getRange, "0.:1.:10000.");
65  Planner::declareParam<double>("goal_bias", this, &LazyLBTRRT::setGoalBias, &LazyLBTRRT::getGoalBias, "0.:.05:1.");
66  Planner::declareParam<double>("epsilon", this, &LazyLBTRRT::setApproximationFactor, &LazyLBTRRT::getApproximationFactor, "0.:.1:10.");
67 
68  addPlannerProgressProperty("iterations INTEGER",
69  std::bind(&LazyLBTRRT::getIterationCount, this));
70  addPlannerProgressProperty("best cost REAL",
71  std::bind(&LazyLBTRRT::getBestCost, this));
72 
73 }
74 
75 ompl::geometric::LazyLBTRRT::~LazyLBTRRT(void)
76 {
77  freeMemory();
78 }
79 
81 {
82  Planner::clear();
83  sampler_.reset();
84  freeMemory();
85  if (nn_)
86  nn_->clear();
87  graphLb_.clear();
88  graphApx_.clear();
89  lastGoalMotion_ = nullptr;
90 
91  iterations_ = 0;
92  bestCost_ = std::numeric_limits<double>::infinity();
93 }
94 
96 {
97  Planner::setup();
100 
101  if (!nn_)
102  nn_.reset(tools::SelfConfig::getDefaultNearestNeighbors<Motion*>(this));
103  nn_->setDistanceFunction(std::bind(
104  (double(LazyLBTRRT::*)(const Motion*, const Motion*) const)
105  &LazyLBTRRT::distanceFunction, this, std::placeholders::_1, std::placeholders::_2));
106 }
107 
109 {
110  if (idToMotionMap_.size() > 0)
111  {
112  for (unsigned int i = 0 ; i < idToMotionMap_.size() ; ++i)
113  {
114  if (idToMotionMap_[i]->state_)
115  si_->freeState(idToMotionMap_[i]->state_);
116  delete idToMotionMap_[i];
117  }
118  idToMotionMap_.clear();
119  }
120  delete LPAstarApx_;
121  delete LPAstarLb_;
122 }
123 
125 {
126  checkValidity();
127  // update goal and check validity
128  base::Goal *goal = pdef_->getGoal().get();
129  base::GoalSampleableRegion *goal_s = dynamic_cast<base::GoalSampleableRegion*>(goal);
130 
131  if (!goal)
132  {
133  OMPL_ERROR("%s: Goal undefined", getName().c_str());
135  }
136 
137  while (const base::State *st = pis_.nextStart())
138  {
139  startMotion_ = createMotion(goal_s, st);
140  break;
141  }
142 
143  if (nn_->size() == 0)
144  {
145  OMPL_ERROR("%s: There are no valid initial states!", getName().c_str());
147  }
148 
149  if (!sampler_)
150  sampler_ = si_->allocStateSampler();
151 
152  OMPL_INFORM("%s: Starting planning with %u states already in datastructure", getName().c_str(), nn_->size());
153 
154  bool solved = false;
155 
156  Motion *rmotion = new Motion(si_);
157  base::State *xstate = si_->allocState();
158 
159  goalMotion_ = createGoalMotion(goal_s);
160 
161  CostEstimatorLb costEstimatorLb(goal, idToMotionMap_);
162  LPAstarLb_ = new LPAstarLb(startMotion_->id_, goalMotion_->id_, graphLb_, costEstimatorLb); //rooted at source
163  CostEstimatorApx costEstimatorApx(this);
164  LPAstarApx_ = new LPAstarApx(goalMotion_->id_, startMotion_->id_, graphApx_, costEstimatorApx); //rooted at target
165  double approxdif = std::numeric_limits<double>::infinity();
166  // e+e/d. K-nearest RRT*
167  double k_rrg = boost::math::constants::e<double>() +
168  boost::math::constants::e<double>() / (double)si_->getStateSpace()->getDimension();
169 
171  //step (1) - RRT
173  bestCost_ = std::numeric_limits<double>::infinity();
174  rrt(ptc, goal_s, xstate, rmotion, approxdif);
175  if (ptc() == false)
176  {
177  solved = true;
178 
180  //step (2) - Lazy construction of G_lb
182  idToMotionMap_.push_back(goalMotion_);
183  int k = getK(idToMotionMap_.size(), k_rrg);
184  std::vector<Motion*> nnVec;
185  nnVec.reserve(k);
186  BOOST_FOREACH(Motion* motion, idToMotionMap_)
187  {
188  nn_->nearestK(motion, k, nnVec);
189  BOOST_FOREACH(Motion* neighbor, nnVec)
190  if (neighbor->id_ != motion->id_ && !edgeExistsLb(motion, neighbor))
191  addEdgeLb(motion, neighbor, distanceFunction(motion, neighbor));
192  }
193  idToMotionMap_.pop_back();
194  closeBounds(ptc);
195  }
196 
198  //step (3) - anytime planning
200  while (ptc() == false)
201  {
202  std::tuple<Motion*, base::State*, double> res = rrtExtend(goal_s, xstate, rmotion, approxdif);
203  Motion * nmotion= std::get<0>(res);
204  base::State *dstate = std::get<1>(res);
205  double d = std::get<2>(res);
206 
207  iterations_++;
208  if (dstate != nullptr)
209  {
210  /* create a motion */
211  Motion* motion = createMotion(goal_s, dstate);
212  addEdgeApx(nmotion, motion, d);
213  addEdgeLb(nmotion, motion, d);
214 
215  int k = getK(nn_->size(), k_rrg);
216  std::vector<Motion*> nnVec;
217  nnVec.reserve(k);
218  nn_->nearestK(motion, k, nnVec);
219 
220  BOOST_FOREACH(Motion* neighbor, nnVec)
221  if (neighbor->id_ != motion->id_ && !edgeExistsLb(motion, neighbor))
222  addEdgeLb(motion, neighbor, distanceFunction(motion, neighbor));
223 
224  closeBounds(ptc);
225  }
226 
227 
228  std::list<std::size_t> pathApx;
229  double costApx = LPAstarApx_->computeShortestPath(pathApx);
230  if (bestCost_ > costApx)
231  {
232  OMPL_INFORM("%s: approximation cost = %g", getName().c_str(),
233  costApx);
234  bestCost_ = costApx;
235  }
236  }
237 
238  if (solved)
239  {
240  std::list<std::size_t> pathApx;
241  LPAstarApx_->computeShortestPath(pathApx);
242 
243  /* set the solution path */
244  PathGeometric *path = new PathGeometric(si_);
245 
246  //the path is in reverse order
247  for (std::list<std::size_t>::reverse_iterator rit = pathApx.rbegin(); rit!=pathApx.rend(); ++rit)
248  path->append(idToMotionMap_[*rit]->state_);
249 
250  pdef_->addSolutionPath(base::PathPtr(path), !solved, 0);
251  }
252 
253  si_->freeState(xstate);
254  if (rmotion->state_)
255  si_->freeState(rmotion->state_);
256  delete rmotion;
257 
258  OMPL_INFORM("%s: Created %u states", getName().c_str(), nn_->size());
259 
260  return base::PlannerStatus(solved, !solved);
261 }
262 
263 std::tuple<ompl::geometric::LazyLBTRRT::Motion*, ompl::base::State*, double>
264 ompl::geometric::LazyLBTRRT::rrtExtend(const base::GoalSampleableRegion* goal_s,
265  base::State *xstate, Motion *rmotion, double &approxdif)
266 {
267  base::State *rstate = rmotion->state_;
268  sampleBiased(goal_s, rstate);
269  /* find closest state in the tree */
270  Motion *nmotion = nn_->nearest(rmotion);
271  base::State *dstate = rstate;
272 
273  /* find state to add */
274  double d = distanceFunction(nmotion->state_, rstate);
275  if (d > maxDistance_)
276  {
277  si_->getStateSpace()->interpolate(nmotion->state_, rstate, maxDistance_ / d, xstate);
278  dstate = xstate;
279  d = maxDistance_;
280  }
281 
282  if (checkMotion(nmotion->state_, dstate) == false)
283  return std::make_tuple((Motion*)nullptr, (base::State*)nullptr, 0.0);
284 
285  // motion is valid
286  double dist = 0.0;
287  bool sat = goal_s->isSatisfied(dstate, &dist);
288  if (sat)
289  {
290  approxdif = dist;
291  }
292  if (dist < approxdif)
293  {
294  approxdif = dist;
295  }
296 
297  return std::make_tuple(nmotion, dstate, d);
298 }
299 
300 void ompl::geometric::LazyLBTRRT::rrt(const base::PlannerTerminationCondition &ptc,
301  base::GoalSampleableRegion *goal_s, base::State *xstate, Motion *rmotion, double &approxdif)
302 {
303  while (ptc() == false)
304  {
305  std::tuple<Motion*, base::State*, double> res = rrtExtend(goal_s, xstate, rmotion, approxdif);
306  Motion* nmotion = std::get<0>(res);
307  base::State *dstate = std::get<1>(res);
308  double d = std::get<2>(res);
309 
310  iterations_++;
311  if (dstate != nullptr)
312  {
313  /* create a motion */
314  Motion* motion = createMotion(goal_s, dstate);
315  addEdgeApx(nmotion, motion, d);
316 
317  if (motion == goalMotion_)
318  return;
319  }
320  }
321 }
322 
324 {
325  Planner::getPlannerData(data);
326 
327  if (lastGoalMotion_)
329 
330  for (unsigned int i = 0 ; i < idToMotionMap_.size() ; ++i)
331  {
332  const base::State *parent = idToMotionMap_[i]->state_;
333  if (boost::in_degree(i, graphApx_) == 0)
335  if (boost::out_degree(i, graphApx_) == 0)
337  else
338  {
339  boost::graph_traits<BoostGraph>::out_edge_iterator ei, ei_end;
340  for (boost::tie(ei, ei_end) = boost::out_edges(i, graphApx_); ei != ei_end; ++ei)
341  {
342  std::size_t v = boost::target(*ei, graphApx_);
343  data.addEdge(base::PlannerDataVertex(idToMotionMap_[v]->state_),
344  base::PlannerDataVertex(parent));
345  }
346  }
347  }
348 }
349 
351  base::State *rstate)
352 {
353  /* sample random state (with goal biasing) */
354  if (goal_s && rng_.uniform01() < goalBias_ && goal_s->canSample())
355  goal_s->sampleGoal(rstate);
356  else
357  sampler_->sampleUniform(rstate);
358  return;
359 };
360 
361 
362 ompl::geometric::LazyLBTRRT::Motion* ompl::geometric::LazyLBTRRT::createMotion(
363  const base::GoalSampleableRegion *goal_s, const base::State *st)
364 {
365  if (goal_s->isSatisfied(st))
366  return goalMotion_;
367 
368  Motion *motion = new Motion(si_);
369  si_->copyState(motion->state_, st);
370  motion->id_ = idToMotionMap_.size();
371  nn_->add(motion);
372  idToMotionMap_.push_back(motion);
373  addVertex(motion);
374 
375  return motion;
376 }
377 
378 ompl::geometric::LazyLBTRRT::Motion* ompl::geometric::LazyLBTRRT::createGoalMotion(const base::GoalSampleableRegion *goal_s)
379 {
380  ompl::base::State *gstate = si_->allocState();
381  goal_s->sampleGoal(gstate);
382 
383  Motion *motion = new Motion(si_);
384  motion->state_ = gstate;
385  motion->id_ = idToMotionMap_.size();
386  idToMotionMap_.push_back(motion);
387  addVertex(motion);
388 
389  return motion;
390 }
391 
392 void ompl::geometric::LazyLBTRRT::closeBounds(const base::PlannerTerminationCondition &ptc)
393 {
394  std::list<std::size_t> pathApx;
395  double costApx = LPAstarApx_->computeShortestPath(pathApx);
396  std::list<std::size_t> pathLb;
397  double costLb = LPAstarLb_->computeShortestPath(pathLb);
398 
399  while (costApx > (1. + epsilon_) * costLb)
400  {
401  if (ptc())
402  return;
403 
404  std::list<std::size_t>::iterator pathLbIter = pathLb.end();
405  pathLbIter--;
406  std::size_t v = *pathLbIter;
407  pathLbIter--;
408  std::size_t u = *pathLbIter;
409 
410  while (edgeExistsApx(u, v))
411  {
412  v = u;
413  --pathLbIter;
414  u = *pathLbIter;
415  }
416 
417  Motion* motionU = idToMotionMap_[u];
418  Motion* motionV = idToMotionMap_[v];
419  if (checkMotion(motionU, motionV))
420  {
421  // note that we change the direction between u and v due to the diff in definition between Apx and LB
422  addEdgeApx(motionV, motionU, distanceFunction(motionU, motionV)); // the distance here can be obtained from the LB graph
423  pathApx.clear();
424  costApx = LPAstarApx_->computeShortestPath(pathApx);
425  }
426  else // the edge (u,v) was not collision free
427  {
428  removeEdgeLb(motionU, motionV);
429  pathLb.clear();
430  costLb = LPAstarLb_->computeShortestPath(pathLb);
431  }
432  }
433 }
base::State * state_
The state contained by the motion.
Definition: LazyLBTRRT.h:160
double distanceFunction(const base::State *a, const base::State *b) const
Compute distance between motions (actually distance between contained states)
Definition: LazyLBTRRT.h:221
bool approximateSolutions
Flag indicating whether the planner is able to compute approximate solutions.
Definition: Planner.h:212
void addPlannerProgressProperty(const std::string &progressPropertyName, const PlannerProgressProperty &prop)
Add a planner progress property called progressPropertyName with a property querying function prop to...
Definition: Planner.h:392
base::StateSamplerPtr sampler_
State sampler.
Definition: LazyLBTRRT.h:300
unsigned int iterations_
Number of iterations the algorithm performed.
Definition: LazyLBTRRT.h:331
Object containing planner generated vertex and edge data. It is assumed that all vertices are unique...
Definition: PlannerData.h:163
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: LazyLBTRRT.cpp:323
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 setGoalBias(double goalBias)
Set the goal bias.
Definition: LazyLBTRRT.h:84
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 goals.
Definition: Goal.h:62
std::shared_ptr< NearestNeighbors< Motion * > > nn_
A nearest-neighbors datastructure containing the tree of motions.
Definition: LazyLBTRRT.h:303
Encapsulate a termination condition for a motion planner. Planners will call operator() to decide whe...
Motion * lastGoalMotion_
The most recent goal motion. Used for PlannerData computation.
Definition: LazyLBTRRT.h:318
virtual void clear(void)
Clear all internal datastructures. Planner settings are not affected. Subsequent calls to solve() wil...
Definition: LazyLBTRRT.cpp:80
void append(const base::State *state)
Append state to the end of this path. The memory for state is copied.
double getApproximationFactor(void) const
Get the apprimation factor.
Definition: LazyLBTRRT.h:294
ProblemDefinitionPtr pdef_
The user set problem definition.
Definition: Planner.h:401
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
Representation of a motion.
Definition: LazyLBTRRT.h:139
virtual void sampleGoal(State *st) const =0
Sample a state in the goal region.
double uniform01()
Generate a random real between 0 and 1.
Definition: RandomNumbers.h:69
Base class for a vertex in the PlannerData structure. All derived classes must implement the clone an...
Definition: PlannerData.h:59
void setRange(double distance)
Set the range the planner is supposed to use.
Definition: LazyLBTRRT.h:100
Invalid start state or no start state specified.
Definition: PlannerStatus.h:56
Abstract definition of a goal region that can be sampled.
double getRange(void) const
Get the range the planner is using.
Definition: LazyLBTRRT.h:106
void freeMemory(void)
Free the memory allocated by this planner.
Definition: LazyLBTRRT.cpp:108
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
Definition: Console.h:64
virtual void setup(void)
Perform extra configuration steps, if needed. This call will also issue a call to ompl::base::SpaceIn...
Definition: LazyLBTRRT.cpp:95
Rapidly-exploring Random Trees.
Definition: LazyLBTRRT.h:60
std::size_t id_
The id of the motion.
Definition: LazyLBTRRT.h:157
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...
bool canSample() const
Return true if maxSampleCount() > 0, since in this case samples can certainly be produced.
A shared pointer wrapper for ompl::base::SpaceInformation.
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
virtual void checkValidity()
Check to see if the planner is in a working state (setup has been called, a goal was set...
Definition: Planner.cpp:100
double epsilon_
approximation factor
Definition: LazyLBTRRT.h:315
PlannerInputStates pis_
Utility class to extract valid input states.
Definition: Planner.h:404
LazyLBTRRT(const base::SpaceInformationPtr &si)
Constructor.
Definition: LazyLBTRRT.cpp:50
double goalBias_
The fraction of time the goal is picked as the state to expand towards (if such a state is available)...
Definition: LazyLBTRRT.h:306
PlannerSpecs specs_
The specifications of the planner (its capabilities)
Definition: Planner.h:410
const State * nextStart()
Return the next valid start state or nullptr if no more valid start states are available.
Definition: Planner.cpp:230
void setApproximationFactor(double epsilon)
Set the apprimation factor.
Definition: LazyLBTRRT.h:121
double getGoalBias(void) const
Get the goal bias the planner is using.
Definition: LazyLBTRRT.h:90
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: LazyLBTRRT.cpp:124
void sampleBiased(const base::GoalSampleableRegion *goal_s, base::State *rstate)
sample with goal biasing
Definition: LazyLBTRRT.cpp:350
void configurePlannerRange(double &range)
Compute what a good length for motion segments is.
Definition: SelfConfig.cpp:230
This class contains methods that automatically configure various parameters for motion planning...
Definition: SelfConfig.h:60
double bestCost_
Best cost found so far by algorithm.
Definition: LazyLBTRRT.h:333
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
double maxDistance_
The maximum length of a motion to be added to a tree.
Definition: LazyLBTRRT.h:309
RNG rng_
The random number generator.
Definition: LazyLBTRRT.h:312
const std::string & getName() const
Get the name of the planner.
Definition: Planner.cpp:55
A shared pointer wrapper for ompl::base::Path.
#define OMPL_INFORM(fmt,...)
Log a formatted information string.
Definition: Console.h:68