TRRT.cpp
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2008, Willow Garage, Inc.
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 Willow Garage 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: Dave Coleman, Ryan Luna */
36 
37 #include "ompl/geometric/planners/rrt/TRRT.h"
38 #include "ompl/base/objectives/MechanicalWorkOptimizationObjective.h"
39 #include "ompl/base/goals/GoalSampleableRegion.h"
40 #include "ompl/tools/config/SelfConfig.h"
41 #include "ompl/tools/config/MagicConstants.h"
42 #include <limits>
43 
44 ompl::geometric::TRRT::TRRT(const base::SpaceInformationPtr &si) : base::Planner(si, "TRRT")
45 {
46  // Standard RRT Variables
48  specs_.directed = true;
49 
50  goalBias_ = 0.05;
51  maxDistance_ = 0.0; // set in setup()
52  lastGoalMotion_ = nullptr;
53 
54  Planner::declareParam<double>("range", this, &TRRT::setRange, &TRRT::getRange, "0.:1.:10000.");
55  Planner::declareParam<double>("goal_bias", this, &TRRT::setGoalBias, &TRRT::getGoalBias, "0.:.05:1.");
56 
57  // TRRT Specific Variables
58  frontierThreshold_ = 0.0; // set in setup()
59  setTempChangeFactor(0.1); // how much to increase the temp each time
60  costThreshold_ = base::Cost(std::numeric_limits<double>::infinity());
61  initTemperature_ = 100; // where the temperature starts out
62  frontierNodeRatio_ = 0.1; // 1/10, or 1 nonfrontier for every 10 frontier
63 
64  Planner::declareParam<double>("temp_change_factor", this, &TRRT::setTempChangeFactor, &TRRT::getTempChangeFactor,"0.:.1:1.");
65  Planner::declareParam<double>("init_temperature", this, &TRRT::setInitTemperature, &TRRT::getInitTemperature);
66  Planner::declareParam<double>("frontier_threshold", this, &TRRT::setFrontierThreshold, &TRRT::getFrontierThreshold);
67  Planner::declareParam<double>("frontierNodeRatio", this, &TRRT::setFrontierNodeRatio, &TRRT::getFrontierNodeRatio);
68  Planner::declareParam<double>("cost_threshold", this, &TRRT::setCostThreshold, &TRRT::getCostThreshold);
69 }
70 
71 ompl::geometric::TRRT::~TRRT()
72 {
73  freeMemory();
74 }
75 
77 {
78  Planner::clear();
79  sampler_.reset();
80  freeMemory();
81  if (nearestNeighbors_)
82  nearestNeighbors_->clear();
83  lastGoalMotion_ = nullptr;
84 
85  // Clear TRRT specific variables ---------------------------------------------------------
86  temp_ = initTemperature_;
87  nonfrontierCount_ = 1;
88  frontierCount_ = 1; // init to 1 to prevent division by zero error
89  if (opt_)
90  bestCost_ = worstCost_ = opt_->identityCost();
91 }
92 
94 {
95  Planner::setup();
96  tools::SelfConfig selfConfig(si_, getName());
97 
98  if (!pdef_ || !pdef_->hasOptimizationObjective())
99  {
100  OMPL_INFORM("%s: No optimization objective specified. Defaulting to mechanical work minimization.", getName().c_str());
101  opt_.reset(new base::MechanicalWorkOptimizationObjective(si_));
102  }
103  else
104  opt_ = pdef_->getOptimizationObjective();
105 
106  // Set maximum distance a new node can be from its nearest neighbor
107  if (maxDistance_ < std::numeric_limits<double>::epsilon())
108  {
109  selfConfig.configurePlannerRange(maxDistance_);
111  }
112 
113  // Set the threshold that decides if a new node is a frontier node or non-frontier node
114  if (frontierThreshold_ < std::numeric_limits<double>::epsilon())
115  {
116  frontierThreshold_ = si_->getMaximumExtent() * 0.01;
117  OMPL_DEBUG("%s: Frontier threshold detected to be %lf", getName().c_str(), frontierThreshold_);
118  }
119 
120  // Create the nearest neighbor function the first time setup is run
121  if (!nearestNeighbors_)
122  nearestNeighbors_.reset(tools::SelfConfig::getDefaultNearestNeighbors<Motion*>(this));
123 
124  // Set the distance function
125  nearestNeighbors_->setDistanceFunction(std::bind(&TRRT::distanceFunction, this, std::placeholders::_1, std::placeholders::_2));
126 
127  // Setup TRRT specific variables ---------------------------------------------------------
128  temp_ = initTemperature_;
129  nonfrontierCount_ = 1;
130  frontierCount_ = 1; // init to 1 to prevent division by zero error
131  bestCost_ = worstCost_ = opt_->identityCost();
132 }
133 
135 {
136  // Delete all motions, states and the nearest neighbors data structure
137  if (nearestNeighbors_)
138  {
139  std::vector<Motion*> motions;
140  nearestNeighbors_->list(motions);
141  for (unsigned int i = 0 ; i < motions.size() ; ++i)
142  {
143  if (motions[i]->state)
144  si_->freeState(motions[i]->state);
145  delete motions[i];
146  }
147  }
148 }
149 
152 {
153  // Basic error checking
154  checkValidity();
155 
156  // Goal information
157  base::Goal *goal = pdef_->getGoal().get();
158  base::GoalSampleableRegion *goalRegion = dynamic_cast<base::GoalSampleableRegion*>(goal);
159 
160  // Input States ---------------------------------------------------------------------------------
161 
162  // Loop through valid input states and add to tree
163  while (const base::State *state = pis_.nextStart())
164  {
165  // Allocate memory for a new start state motion based on the "space-information"-size
166  Motion *motion = new Motion(si_);
167 
168  // Copy destination <= source
169  si_->copyState(motion->state, state);
170 
171  // Set cost for this start state
172  motion->cost = opt_->stateCost(motion->state);
173 
174  if (nearestNeighbors_->size() == 0) // do not overwrite best/worst from previous call to solve
175  worstCost_ = bestCost_ = motion->cost;
176 
177  // Add start motion to the tree
178  nearestNeighbors_->add(motion);
179  }
180 
181  // Check that input states exist
182  if (nearestNeighbors_->size() == 0)
183  {
184  OMPL_ERROR("%s: There are no valid initial states!", getName().c_str());
186  }
187 
188  // Create state sampler if this is TRRT's first run
189  if (!sampler_)
190  sampler_ = si_->allocStateSampler();
191 
192  // Debug
193  OMPL_INFORM("%s: Starting planning with %u states already in datastructure", getName().c_str(), nearestNeighbors_->size());
194 
195 
196  // Solver variables ------------------------------------------------------------------------------------
197 
198  // the final solution
199  Motion *solution = nullptr;
200  // the approximate solution, returned if no final solution found
201  Motion *approxSolution = nullptr;
202  // track the distance from goal to closest solution yet found
203  double approxDifference = std::numeric_limits<double>::infinity();
204 
205  // distance between states - the intial state and the interpolated state (may be the same)
206  double randMotionDistance;
207 
208  // Create random motion and a pointer (for optimization) to its state
209  Motion *randMotion = new Motion(si_);
210  Motion *nearMotion;
211 
212  // STATES
213  // The random state
214  base::State *randState = randMotion->state;
215  // The new state that is generated between states *to* and *from*
216  base::State *interpolatedState = si_->allocState(); // Allocates "space information"-sized memory for a state
217  // The chosen state btw rand_state and interpolated_state
218  base::State *newState;
219 
220  // Begin sampling --------------------------------------------------------------------------------------
221  while (plannerTerminationCondition() == false)
222  {
223  // I.
224 
225  // Sample random state (with goal biasing probability)
226  if (goalRegion && rng_.uniform01() < goalBias_ && goalRegion->canSample())
227  {
228  // Bias sample towards goal
229  goalRegion->sampleGoal(randState);
230  }
231  else
232  {
233  // Uniformly Sample
234  sampler_->sampleUniform(randState);
235  }
236 
237  // II.
238 
239  // Find closest state in the tree
240  nearMotion = nearestNeighbors_->nearest(randMotion);
241 
242  // III.
243 
244  // Distance from near state q_n to a random state
245  randMotionDistance = si_->distance(nearMotion->state, randState);
246 
247  // Check if the rand_state is too far away
248  if (randMotionDistance > maxDistance_)
249  {
250  // Computes the state that lies at time t in [0, 1] on the segment that connects *from* state to *to* state.
251  // The memory location of *state* is not required to be different from the memory of either *from* or *to*.
252  si_->getStateSpace()->interpolate(nearMotion->state, randState,
253  maxDistance_ / randMotionDistance, interpolatedState);
254 
255  // Update the distance between near and new with the interpolated_state
256  randMotionDistance = si_->distance(nearMotion->state, interpolatedState);
257 
258  // Use the interpolated state as the new state
259  newState = interpolatedState;
260  }
261  else // Random state is close enough
262  newState = randState;
263 
264  // IV.
265  // this stage integrates collision detections in the presence of obstacles and checks for collisions
266  if (!si_->checkMotion(nearMotion->state, newState))
267  continue; // try a new sample
268 
269 
270  // Minimum Expansion Control
271  // A possible side effect may appear when the tree expansion toward unexplored regions remains slow, and the
272  // new nodes contribute only to refine already explored regions.
273  if (!minExpansionControl(randMotionDistance))
274  continue; // give up on this one and try a new sample
275 
276  base::Cost childCost = opt_->stateCost(newState);
277 
278  // Only add this motion to the tree if the transition test accepts it
279  if (!transitionTest(opt_->motionCost(nearMotion->state, newState)))
280  continue; // give up on this one and try a new sample
281 
282  // V.
283 
284  // Create a motion
285  Motion *motion = new Motion(si_);
286  si_->copyState(motion->state, newState);
287  motion->parent = nearMotion; // link q_new to q_near as an edge
288  motion->cost = childCost;
289 
290  // Add motion to data structure
291  nearestNeighbors_->add(motion);
292 
293  if (opt_->isCostBetterThan(motion->cost, bestCost_)) // motion->cost is better than the existing best
294  bestCost_ = motion->cost;
295  if (opt_->isCostBetterThan(worstCost_, motion->cost)) // motion->cost is worse than the existing worst
296  worstCost_ = motion->cost;
297 
298  // VI.
299 
300  // Check if this motion is the goal
301  double distToGoal = 0.0;
302  bool isSatisfied = goal->isSatisfied(motion->state, &distToGoal);
303  if (isSatisfied)
304  {
305  approxDifference = distToGoal; // the tolerated error distance btw state and goal
306  solution = motion; // set the final solution
307  break;
308  }
309 
310  // Is this the closest solution we've found so far
311  if (distToGoal < approxDifference)
312  {
313  approxDifference = distToGoal;
314  approxSolution = motion;
315  }
316 
317  } // end of solver sampling loop
318 
319 
320  // Finish solution processing --------------------------------------------------------------------
321 
322  bool solved = false;
323  bool approximate = false;
324 
325  // Substitute an empty solution with the best approximation
326  if (solution == nullptr)
327  {
328  solution = approxSolution;
329  approximate = true;
330  }
331 
332  // Generate solution path for real/approx solution
333  if (solution != nullptr)
334  {
335  lastGoalMotion_ = solution;
336 
337  // construct the solution path
338  std::vector<Motion*> mpath;
339  while (solution != nullptr)
340  {
341  mpath.push_back(solution);
342  solution = solution->parent;
343  }
344 
345  // set the solution path
346  PathGeometric *path = new PathGeometric(si_);
347  for (int i = mpath.size() - 1 ; i >= 0 ; --i)
348  path->append(mpath[i]->state);
349 
350  pdef_->addSolutionPath(base::PathPtr(path), approximate, approxDifference, getName());
351  solved = true;
352  }
353 
354  // Clean up ---------------------------------------------------------------------------------------
355 
356  si_->freeState(interpolatedState);
357  if (randMotion->state)
358  si_->freeState(randMotion->state);
359  delete randMotion;
360 
361  OMPL_INFORM("%s: Created %u states", getName().c_str(), nearestNeighbors_->size());
362 
363  return base::PlannerStatus(solved, approximate);
364 }
365 
367 {
368  Planner::getPlannerData(data);
369 
370  std::vector<Motion*> motions;
371  if (nearestNeighbors_)
372  nearestNeighbors_->list(motions);
373 
374  if (lastGoalMotion_)
375  data.addGoalVertex(base::PlannerDataVertex(lastGoalMotion_->state));
376 
377  for (unsigned int i = 0 ; i < motions.size() ; ++i)
378  {
379  if (motions[i]->parent == nullptr)
380  data.addStartVertex(base::PlannerDataVertex(motions[i]->state));
381  else
382  data.addEdge(base::PlannerDataVertex(motions[i]->parent->state),
383  base::PlannerDataVertex(motions[i]->state));
384  }
385 }
386 
388 {
389  // Disallow any cost that is not better than the cost threshold
390  if (!opt_->isCostBetterThan(motionCost, costThreshold_))
391  return false;
392 
393  // Always accept if the cost is near or below zero
394  if (motionCost.value() < 1e-4)
395  return true;
396 
397  double dCost = motionCost.value();
398  double transitionProbability = exp(-dCost / temp_);
399  if (transitionProbability > 0.5)
400  {
401  double costRange = worstCost_.value() - bestCost_.value();
402  if (fabs(costRange) > 1e-4) // Do not divide by zero
403  // Successful transition test. Decrease the temperature slightly
404  temp_ /= exp(dCost / (0.1 * costRange));
405 
406  return true;
407  }
408 
409  // The transition failed. Increase the temperature (slightly)
410  temp_ *= tempChangeFactor_;
411  return false;
412 }
413 
414 bool ompl::geometric::TRRT::minExpansionControl(double randMotionDistance)
415 {
416  if (randMotionDistance > frontierThreshold_)
417  {
418  // participates in the tree expansion
419  ++frontierCount_;
420 
421  return true;
422  }
423  else
424  {
425  // participates in the tree refinement
426 
427  // check our ratio first before accepting it
428  if ((double)nonfrontierCount_ / (double)frontierCount_ > frontierNodeRatio_)
429  // reject this node as being too much refinement
430  return false;
431 
432  ++nonfrontierCount_;
433  return true;
434  }
435 }
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
double getFrontierThreshold(void) const
Get the distance between a new state and the nearest neighbor that qualifies that state as being a fr...
Definition: TRRT.h:185
double initTemperature_
The initial value of temp_.
Definition: TRRT.h:308
An optimization objective which defines path cost using the idea of mechanical work. To be used in conjunction with TRRT.
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
double getFrontierNodeRatio(void) const
Get the ratio between adding nonfrontier nodes to frontier nodes, for example .1 is 1/10 or one nonfr...
Definition: TRRT.h:199
double getGoalBias() const
Get the goal bias the planner is using.
Definition: TRRT.h:110
double getCostThreshold() const
Get the cost threshold (default is infinity). Any motion cost that is not better than this cost (acco...
Definition: TRRT.h:158
Motion * parent
The parent motion in the exploration tree.
Definition: TRRT.h:241
Encapsulate a termination condition for a motion planner. Planners will call operator() to decide whe...
void setTempChangeFactor(double factor)
Set the factor by which the temperature is increased after a failed transition test. This value should be in the range (0, 1], typically close to zero (default is 0.1). This value is an exponential (e^factor) that is multiplied with the current temperature.
Definition: TRRT.h:136
double maxDistance_
The maximum length of a motion to be added to a tree.
Definition: TRRT.h:275
void append(const base::State *state)
Append state to the end of this path. The memory for state is copied.
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
virtual void sampleGoal(State *st) const =0
Sample a state in the goal region.
double frontierThreshold_
The distance between an old state and a new state that qualifies it as a frontier state...
Definition: TRRT.h:319
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.
double getInitTemperature(void) const
Get the temperature at the start of planning.
Definition: TRRT.h:171
bool transitionTest(const base::Cost &motionCost)
Filter irrelevant configuration regarding the search of low-cost paths before inserting into tree...
Definition: TRRT.cpp:387
TRRT(const base::SpaceInformationPtr &si)
Constructor.
Definition: TRRT.cpp:44
void setGoalBias(double goalBias)
Set the goal bias.
Definition: TRRT.h:104
base::Cost costThreshold_
All motion costs must be better than this cost (default is infinity)
Definition: TRRT.h:301
double getRange() const
Get the range the planner is using.
Definition: TRRT.h:126
Representation of a motion.
Definition: TRRT.h:220
Motion * lastGoalMotion_
The most recent goal motion. Used for PlannerData computation.
Definition: TRRT.h:281
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
Definition: Console.h:64
base::Cost cost
Cost of the state.
Definition: TRRT.h:244
double value() const
The value of the cost.
Definition: Cost.h:54
void setRange(double distance)
Set the range the planner is supposed to use.
Definition: TRRT.h:120
base::State * state
The state contained by the motion.
Definition: TRRT.h:238
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.
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: TRRT.cpp:366
double distanceFunction(const Motion *a, const Motion *b) const
Compute distance between motions (actually distance between contained states)
Definition: TRRT.h:252
double getTempChangeFactor(void) const
Get the factor by which the temperature rises based on current acceptance/rejection rate...
Definition: TRRT.h:142
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 bool isSatisfied(const State *st) const =0
Return true if the state satisfies the goal constraints.
virtual base::PlannerStatus solve(const base::PlannerTerminationCondition &plannerTerminationCondition)
Function that can solve the motion planning problem. This function can be called multiple times on th...
Definition: TRRT.cpp:151
double goalBias_
The fraction of time the goal is picked as the state to expand towards (if such a state is available)...
Definition: TRRT.h:272
PlannerSpecs specs_
The specifications of the planner (its capabilities)
Definition: Planner.h:410
#define OMPL_DEBUG(fmt,...)
Log a formatted debugging string.
Definition: Console.h:70
void setFrontierNodeRatio(double frontierNodeRatio)
Set the ratio between adding nonfrontier nodes to frontier nodes, for example .1 is 1/10 or one nonfr...
Definition: TRRT.h:192
static const double COST_MAX_MOTION_LENGTH_AS_SPACE_EXTENT_FRACTION
For cost-based planners it has been observed that smaller ranges are typically suitable. The same range computation strategy is used for all planners, but for cost planners an additional factor (smaller than 1) is multiplied in.
bool minExpansionControl(double randMotionDistance)
Use ratio to prefer frontier nodes to nonfrontier ones.
Definition: TRRT.cpp:414
void setInitTemperature(double initTemperature)
Set the initial temperature at the beginning of the algorithm. Should be high to allow for initial ex...
Definition: TRRT.h:165
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
Definition of a geometric path.
Definition: PathGeometric.h:60
void freeMemory()
Free the memory allocated by this planner.
Definition: TRRT.cpp:134
double frontierNodeRatio_
Target ratio of non-frontier nodes to frontier nodes. rho.
Definition: TRRT.h:322
void setCostThreshold(double maxCost)
Set the cost threshold (default is infinity). Any motion cost that is not better than this cost (acco...
Definition: TRRT.h:150
virtual void setup()
Perform extra configuration steps, if needed. This call will also issue a call to ompl::base::SpaceIn...
Definition: TRRT.cpp:93
virtual void clear()
Clear all internal datastructures. Planner settings are not affected. Subsequent calls to solve() wil...
Definition: TRRT.cpp:76
Definition of a cost value. Can represent the cost of a motion or the cost of a state.
Definition: Cost.h:47
void setFrontierThreshold(double frontier_threshold)
Set the distance between a new state and the nearest neighbor that qualifies that state as being a fr...
Definition: TRRT.h:178
A shared pointer wrapper for ompl::base::Path.
#define OMPL_INFORM(fmt,...)
Log a formatted information string.
Definition: Console.h:68