VFRRT.cpp
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2015, Caleb Voss and Wilson Beebe
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 /* Authors: Caleb Voss, Wilson Beebe */
36 
37 #include "ompl/geometric/planners/rrt/VFRRT.h"
38 #include "ompl/base/goals/GoalSampleableRegion.h"
39 
40 namespace ompl
41 {
42  namespace magic
43  {
45  static const unsigned int VFRRT_MEAN_NORM_SAMPLES = 1000;
46  }
47 }
48 
50  double exploration, double initial_lambda, unsigned int update_freq)
51  : RRT(si), vf_(vf), efficientCount_(0), inefficientCount_(0), explorationInefficiency_(0.),
52  explorationSetting_(exploration), lambda_(initial_lambda),
53  nth_step_(update_freq), step_(0), meanNorm_(0.), vfdim_(0)
54 {
55  setName("VFRRT");
56  maxDistance_ = si->getStateValidityCheckingResolution();
57 }
58 
60 {
61 }
62 
64 {
65  RRT::clear();
66  efficientCount_ = 0;
67  inefficientCount_ = 0;
68  explorationInefficiency_ = 0.;
69  step_ = 0;
70 }
71 
73 {
74  RRT::setup();
75  vfdim_ = si_->getStateSpace()->getValueLocations().size();
76 }
77 
79 {
80  ompl::base::State *rstate = si_->allocState();
81  double sum = 0.;
82  for (unsigned int i = 0; i < magic::VFRRT_MEAN_NORM_SAMPLES; i++)
83  {
84  sampler_->sampleUniform(rstate);
85  sum += vf_(rstate).norm();
86  }
87  si_->freeState(rstate);
88  return sum / magic::VFRRT_MEAN_NORM_SAMPLES;
89 }
90 
91 Eigen::VectorXd ompl::geometric::VFRRT::getNewDirection(const base::State *qnear, const base::State *qrand)
92 {
93  // Set vrand to be the normalized vector from qnear to qrand
94  Eigen::VectorXd vrand(vfdim_);
95  for (unsigned int i = 0; i < vfdim_; i++)
96  vrand[i] = *si_->getStateSpace()->getValueAddressAtIndex(qrand, i)
97  - *si_->getStateSpace()->getValueAddressAtIndex(qnear, i);
98  vrand /= si_->distance(qnear, qrand);
99 
100  // Get the vector at qnear, and normalize
101  Eigen::VectorXd vfield = vf_(qnear);
102  const double lambdaScale = vfield.norm();
103  // In the case where there is no vector field present, vfield.norm() == 0,
104  // return the direction of the random state.
105  if (lambdaScale < std::numeric_limits<float>::epsilon())
106  return vrand;
107  vfield /= lambdaScale;
108  // Sample a weight from the distribution
109  const double omega = biasedSampling(vrand, vfield, lambdaScale);
110  // Determine updated direction
111  return computeAlphaBeta(omega, vrand, vfield);
112 }
113 
114 double ompl::geometric::VFRRT::biasedSampling(const Eigen::VectorXd &vrand,
115  const Eigen::VectorXd &vfield, double lambdaScale)
116 {
117  double sigma = .25 * (vrand - vfield).squaredNorm();
118  updateGain();
119  double scaledLambda = lambda_ * lambdaScale / meanNorm_;
120  double phi = scaledLambda / (1. - std::exp(-2. * scaledLambda));
121  double z = - std::log(1. - sigma * scaledLambda / phi) / scaledLambda;
122  return std::sqrt(2. * z);
123 }
124 
126 {
127  if (step_ == nth_step_)
128  {
129  lambda_ = lambda_ * (1 - explorationInefficiency_ + explorationSetting_);
130  efficientCount_ = inefficientCount_ = 0;
131  explorationInefficiency_ = 0;
132  step_ = 0;
133  }
134  else
135  step_++;
136 }
137 
139  double omega, const Eigen::VectorXd &vrand, const Eigen::VectorXd &vfield)
140 {
141  double w2 = omega * omega;
142  double c = vfield.dot(vrand);
143  double cc_1 = c * c - 1.;
144  double root = std::sqrt(cc_1 * w2 * (w2 - 4.));
145  double beta = -root / (2. * cc_1);
146  double sign = (beta < 0.) ? -1. : 1.;
147  beta *= sign;
148  double alpha = (sign * c * root + cc_1 * (2. - w2)) / (2. * cc_1);
149  return alpha * vfield + beta * vrand;
150 }
151 
153  Motion *m, base::State* rstate, const Eigen::VectorXd &v)
154 {
155  base::State* newState = si_->allocState();
156  si_->copyState(newState, m->state);
157 
158  double d = si_->distance(m->state, rstate);
159  if (d > maxDistance_)
160  d = maxDistance_;
161 
162  const base::StateSpacePtr &space = si_->getStateSpace();
163  for (unsigned int i = 0; i < vfdim_; i++)
164  *space->getValueAddressAtIndex(newState, i) += d * v[i];
165  if (!v.hasNaN() && si_->checkMotion(m->state, newState))
166  {
167  Motion *motion = new Motion(si_);
168  motion->state = newState;
169  motion->parent = m;
171  nn_->add(motion);
172  return motion;
173  }
174  else
175  {
176  si_->freeState(newState);
177  inefficientCount_++;
178  return nullptr;
179  }
180 }
181 
183 {
184  Motion *near = nn_->nearest(m);
185  if (distanceFunction(m, near) < si_->getStateValidityCheckingResolution())
186  inefficientCount_++;
187  else
188  efficientCount_++;
189  explorationInefficiency_ = inefficientCount_ / (double)(efficientCount_ + inefficientCount_);
190 }
191 
193 {
194  checkValidity();
195  base::Goal *goal = pdef_->getGoal().get();
196  base::GoalSampleableRegion *goal_s = dynamic_cast<base::GoalSampleableRegion*>(goal);
197 
198  if (!sampler_)
199  sampler_ = si_->allocStateSampler();
200 
201  meanNorm_ = determineMeanNorm();
202 
203  while (const base::State *st = pis_.nextStart())
204  {
205  Motion *motion = new Motion(si_);
206  si_->copyState(motion->state, st);
207  nn_->add(motion);
208  }
209 
210  if (nn_->size() == 0)
211  {
212  OMPL_ERROR("%s: There are no valid initial states!", getName().c_str());
214  }
215 
216  OMPL_INFORM("%s: Starting planning with %u states already in datastructure", getName().c_str(), nn_->size());
217 
218  Motion *solution = nullptr;
219  Motion *approxsol = nullptr;
220  double approxdif = std::numeric_limits<double>::infinity();
221  Motion *rmotion = new Motion(si_);
222  base::State *rstate = rmotion->state;
223  base::State *xstate = si_->allocState();
224 
225  while (ptc == false)
226  {
227  // Sample random state (with goal biasing)
228  if (goal_s && rng_.uniform01() < goalBias_ && goal_s->canSample())
229  goal_s->sampleGoal(rstate);
230  else
231  sampler_->sampleUniform(rstate);
232 
233  // Find closest state in the tree
234  Motion *nmotion = nn_->nearest(rmotion);
235 
236  // Modify direction based on vector field before extending
237  Motion *motion = extendTree(nmotion, rstate, getNewDirection(nmotion->state, rstate));
238  if (!motion)
239  continue;
240 
241  // Check if we can connect to the goal
242  double dist = 0;
243  bool sat = goal->isSatisfied(motion->state, &dist);
244  if (sat)
245  {
246  approxdif = dist;
247  solution = motion;
248  break;
249  }
250  if (dist < approxdif)
251  {
252  approxdif = dist;
253  approxsol = motion;
254  }
255  }
256 
257  bool solved = false;
258  bool approximate = false;
259  if (solution == nullptr)
260  {
261  solution = approxsol;
262  approximate = true;
263  }
264 
265  if (solution != nullptr)
266  {
267  lastGoalMotion_ = solution;
268 
269  // Construct the solution path
270  std::vector<Motion*> mpath;
271  while (solution != nullptr)
272  {
273  mpath.push_back(solution);
274  solution = solution->parent;
275  }
276 
277  // Set the solution path
278  PathGeometric *path = new PathGeometric(si_);
279  for (int i = mpath.size() - 1 ; i >= 0 ; --i)
280  path->append(mpath[i]->state);
281  pdef_->addSolutionPath(base::PathPtr(path), approximate, approxdif, name_);
282  solved = true;
283  }
284 
285  si_->freeState(xstate);
286  if (rmotion->state)
287  si_->freeState(rmotion->state);
288  delete rmotion;
289 
290  OMPL_INFORM("%s: Created %u states", getName().c_str(), nn_->size());
291 
292  return base::PlannerStatus(solved, approximate);
293 }
double maxDistance_
The maximum length of a motion to be added to a tree.
Definition: RRT.h:176
base::StateSamplerPtr sampler_
State sampler.
Definition: RRT.h:167
Eigen::VectorXd computeAlphaBeta(double omega, const Eigen::VectorXd &vrand, const Eigen::VectorXd &vfield)
Definition: VFRRT.cpp:138
virtual ~VFRRT()
Definition: VFRRT.cpp:59
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
virtual void setup()
Perform extra configuration steps, if needed. This call will also issue a call to ompl::base::SpaceIn...
Definition: RRT.cpp:70
std::shared_ptr< NearestNeighbors< Motion * > > nn_
A nearest-neighbors datastructure containing the tree of motions.
Definition: RRT.h:170
A shared pointer wrapper for ompl::base::StateSpace.
double biasedSampling(const Eigen::VectorXd &vrand, const Eigen::VectorXd &vfield, double lambdaScale)
Definition: VFRRT.cpp:114
Motion * parent
The parent motion in the exploration tree.
Definition: RRT.h:153
Abstract definition of goals.
Definition: Goal.h:62
Encapsulate a termination condition for a motion planner. Planners will call operator() to decide whe...
void append(const base::State *state)
Append state to the end of this path. The memory for state is copied.
virtual void clear()
Clear all internal datastructures. Planner settings are not affected. Subsequent calls to solve() wil...
Definition: RRT.cpp:60
virtual base::PlannerStatus solve(const base::PlannerTerminationCondition &ptc)
Definition: VFRRT.cpp:192
double determineMeanNorm()
Definition: VFRRT.cpp:78
Motion * extendTree(Motion *m, base::State *rstate, const Eigen::VectorXd &v)
Definition: VFRRT.cpp:152
ProblemDefinitionPtr pdef_
The user set problem definition.
Definition: Planner.h:401
virtual void sampleGoal(State *st) const =0
Sample a state in the goal region.
void setName(const std::string &name)
Set the name of the planner.
Definition: Planner.cpp:60
double uniform01()
Generate a random real between 0 and 1.
Definition: RandomNumbers.h:69
Invalid start state or no start state specified.
Definition: PlannerStatus.h:56
void updateExplorationEfficiency(Motion *m)
Definition: VFRRT.cpp:182
Abstract definition of a goal region that can be sampled.
Main namespace. Contains everything in this library.
Definition: Cost.h:42
RNG rng_
The random number generator.
Definition: RRT.h:179
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
Definition: Console.h:64
double distanceFunction(const Motion *a, const Motion *b) const
Compute distance between motions (actually distance between contained states)
Definition: RRT.h:161
A class to store the exit status of Planner::solve()
Definition: PlannerStatus.h:48
Rapidly-exploring Random Trees.
Definition: RRT.h:65
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.
Definition of an abstract state.
Definition: State.h:50
Motion * lastGoalMotion_
The most recent goal motion. Used for PlannerData computation.
Definition: RRT.h:182
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
virtual bool isSatisfied(const State *st) const =0
Return true if the state satisfies the goal constraints.
PlannerInputStates pis_
Utility class to extract valid input states.
Definition: Planner.h:404
Eigen::VectorXd getNewDirection(const base::State *qnear, const base::State *qrand)
Definition: VFRRT.cpp:91
const State * nextStart()
Return the next valid start state or nullptr if no more valid start states are available.
Definition: Planner.cpp:230
std::string name_
The name of this planner.
Definition: Planner.h:407
VFRRT(const base::SpaceInformationPtr &si, const VectorField &vf, double exploration, double initial_lambda, unsigned int update_freq)
Definition: VFRRT.cpp:49
Representation of a motion.
Definition: RRT.h:132
Definition of a geometric path.
Definition: PathGeometric.h:60
SpaceInformationPtr si_
The space information for which planning is done.
Definition: Planner.h:398
virtual void setup()
Perform extra configuration steps, if needed. This call will also issue a call to ompl::base::SpaceIn...
Definition: VFRRT.cpp:72
double goalBias_
The fraction of time the goal is picked as the state to expand towards (if such a state is available)...
Definition: RRT.h:173
const std::string & getName() const
Get the name of the planner.
Definition: Planner.cpp:55
static const unsigned int VFRRT_MEAN_NORM_SAMPLES
Number of sampler to determine mean vector field norm in gVFRRT.
Definition: VFRRT.cpp:45
A shared pointer wrapper for ompl::base::Path.
virtual void clear()
Definition: VFRRT.cpp:63
base::State * state
The state contained by the motion.
Definition: RRT.h:150
#define OMPL_INFORM(fmt,...)
Log a formatted information string.
Definition: Console.h:68