Loading...
Searching...
No Matches
BiEST.cpp
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2015, Rice 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 Rice 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: Ryan Luna */
36
37#include "ompl/geometric/planners/est/BiEST.h"
38#include "ompl/base/goals/GoalSampleableRegion.h"
39#include "ompl/tools/config/SelfConfig.h"
40#include <limits>
41#include <cassert>
42
43ompl::geometric::BiEST::BiEST(const base::SpaceInformationPtr &si) : base::Planner(si, "BiEST")
44{
45 specs_.recognizedGoal = base::GOAL_SAMPLEABLE_REGION;
46 specs_.directed = true;
47
48 Planner::declareParam<double>("range", this, &BiEST::setRange, &BiEST::getRange, "0.:1.:10000.");
49}
50
51ompl::geometric::BiEST::~BiEST()
52{
53 freeMemory();
54}
55
57{
58 Planner::setup();
59
62
63 // Make the neighborhood radius smaller than sampling range to
64 // keep probabilities relatively high for rejection sampling
66
67 if (!nnStart_)
69 if (!nnGoal_)
71 nnStart_->setDistanceFunction([this](const Motion *a, const Motion *b) { return distanceFunction(a, b); });
72 nnGoal_->setDistanceFunction([this](const Motion *a, const Motion *b) { return distanceFunction(a, b); });
73}
74
76{
77 Planner::clear();
78 sampler_.reset();
79 freeMemory();
80 if (nnStart_)
81 nnStart_->clear();
82 if (nnGoal_)
83 nnGoal_->clear();
84
85 startMotions_.clear();
86 startPdf_.clear();
87
88 goalMotions_.clear();
89 goalPdf_.clear();
90
91 connectionPoint_ = std::make_pair<base::State *, base::State *>(nullptr, nullptr);
92}
93
95{
96 for (auto &startMotion : startMotions_)
97 {
98 if (startMotion->state != nullptr)
99 si_->freeState(startMotion->state);
100 delete startMotion;
101 }
102
103 for (auto &goalMotion : goalMotions_)
104 {
105 if (goalMotion->state != nullptr)
106 si_->freeState(goalMotion->state);
107 delete goalMotion;
108 }
109}
110
112{
114 auto *goal = dynamic_cast<base::GoalSampleableRegion *>(pdef_->getGoal().get());
115
116 if (goal == nullptr)
117 {
118 OMPL_ERROR("%s: Unknown type of goal", getName().c_str());
120 }
121
122 std::vector<Motion *> neighbors;
123
124 while (const base::State *st = pis_.nextStart())
125 {
126 auto *motion = new Motion(si_);
127 si_->copyState(motion->state, st);
128 motion->root = motion->state;
129
130 nnStart_->nearestR(motion, nbrhoodRadius_, neighbors);
131 addMotion(motion, startMotions_, startPdf_, nnStart_, neighbors);
132 }
133
134 if (startMotions_.empty())
135 {
136 OMPL_ERROR("%s: There are no valid initial states!", getName().c_str());
138 }
139
140 if (!goal->couldSample())
141 {
142 OMPL_ERROR("%s: Insufficient states in sampleable goal region", getName().c_str());
144 }
145
146 if (!sampler_)
147 sampler_ = si_->allocValidStateSampler();
148
149 OMPL_INFORM("%s: Starting planning with %u states already in datastructure", getName().c_str(),
150 startMotions_.size() + goalMotions_.size());
151
152 base::State *xstate = si_->allocState();
153 auto *xmotion = new Motion();
154
155 bool startTree = true;
156 bool solved = false;
158
159 while (!ptc && !solved)
160 {
161 // Make sure goal tree has at least one state.
162 if (goalMotions_.empty() || pis_.getSampledGoalsCount() < goalMotions_.size() / 2)
163 {
164 const base::State *st = goalMotions_.empty() ? pis_.nextGoal(ptc) : pis_.nextGoal();
165 if (st != nullptr)
166 {
167 auto *motion = new Motion(si_);
168 si_->copyState(motion->state, st);
169 motion->root = motion->state;
170
171 nnGoal_->nearestR(motion, nbrhoodRadius_, neighbors);
172 addMotion(motion, goalMotions_, goalPdf_, nnGoal_, neighbors);
173 }
174
175 if (goalMotions_.empty())
176 {
177 OMPL_ERROR("%s: Unable to sample any valid states for goal tree", getName().c_str());
179 break;
180 }
181 }
182
183 // Pointers to the tree structure we are expanding
184 std::vector<Motion *> &motions = startTree ? startMotions_ : goalMotions_;
185 PDF<Motion *> &pdf = startTree ? startPdf_ : goalPdf_;
186 std::shared_ptr<NearestNeighbors<Motion *>> nn = startTree ? nnStart_ : nnGoal_;
187
188 // Select a state to expand from
189 Motion *existing = pdf.sample(rng_.uniform01());
190 assert(existing);
191
192 // Sample a state in the neighborhood
193 if (!sampler_->sampleNear(xstate, existing->state, maxDistance_))
194 continue;
195
196 // Compute neighborhood of candidate state
197 xmotion->state = xstate;
198 nn->nearestR(xmotion, nbrhoodRadius_, neighbors);
199
200 // reject state with probability proportional to neighborhood density
201 if (!neighbors.empty())
202 {
203 double p = 1.0 - (1.0 / neighbors.size());
204 if (rng_.uniform01() < p)
205 continue;
206 }
207
208 // Is motion good?
209 if (si_->checkMotion(existing->state, xstate))
210 {
211 // create a motion
212 auto *motion = new Motion(si_);
213 si_->copyState(motion->state, xstate);
214 motion->parent = existing;
215 motion->root = existing->root;
216
217 // add it to everything
218 addMotion(motion, motions, pdf, nn, neighbors);
219
220 // try to connect this state to the other tree
221 // Get all states in the other tree within a maxDistance_ ball (bigger than "neighborhood" ball)
222 startTree ? nnGoal_->nearestR(motion, maxDistance_, neighbors) :
223 nnStart_->nearestR(motion, maxDistance_, neighbors);
224 for (size_t i = 0; i < neighbors.size() && !solved; ++i)
225 {
226 if (goal->isStartGoalPairValid(motion->root, neighbors[i]->root) &&
227 si_->checkMotion(motion->state, neighbors[i]->state)) // win! solution found.
228 {
229 connectionPoint_ = std::make_pair(motion->state, neighbors[i]->state);
230
231 Motion *startMotion = startTree ? motion : neighbors[i];
232 Motion *goalMotion = startTree ? neighbors[i] : motion;
233
234 Motion *solution = startMotion;
235 std::vector<Motion *> mpath1;
236 while (solution != nullptr)
237 {
238 mpath1.push_back(solution);
239 solution = solution->parent;
240 }
241
242 solution = goalMotion;
243 std::vector<Motion *> mpath2;
244 while (solution != nullptr)
245 {
246 mpath2.push_back(solution);
247 solution = solution->parent;
248 }
249
250 auto path(std::make_shared<PathGeometric>(si_));
251 path->getStates().reserve(mpath1.size() + mpath2.size());
252 for (int i = mpath1.size() - 1; i >= 0; --i)
253 path->append(mpath1[i]->state);
254 for (auto &i : mpath2)
255 path->append(i->state);
256
257 pdef_->addSolutionPath(path, false, 0.0, getName());
258 solved = true;
259 }
260 }
261 }
262
263 // swap trees for next iteration
264 startTree = !startTree;
265 }
266
267 si_->freeState(xstate);
268 delete xmotion;
269
270 OMPL_INFORM("%s: Created %u states (%u start + %u goal)", getName().c_str(),
271 startMotions_.size() + goalMotions_.size(), startMotions_.size(), goalMotions_.size());
272 return solved ? base::PlannerStatus::EXACT_SOLUTION : status;
273}
274
275void ompl::geometric::BiEST::addMotion(Motion *motion, std::vector<Motion *> &motions, PDF<Motion *> &pdf,
276 const std::shared_ptr<NearestNeighbors<Motion *>> &nn,
277 const std::vector<Motion *> &neighbors)
278{
279 // Updating neighborhood size counts
280 for (auto neighbor : neighbors)
281 {
282 PDF<Motion *>::Element *elem = neighbor->element;
283 double w = pdf.getWeight(elem);
284 pdf.update(elem, w / (w + 1.));
285 }
286
287 motion->element = pdf.add(motion, 1. / (neighbors.size() + 1.)); // +1 for self
288 motions.push_back(motion);
289 nn->add(motion);
290}
291
293{
294 Planner::getPlannerData(data);
295
296 for (auto startMotion : startMotions_)
297 {
298 if (startMotion->parent == nullptr)
299 data.addStartVertex(base::PlannerDataVertex(startMotion->state, 1));
300 else
301 data.addEdge(base::PlannerDataVertex(startMotion->parent->state, 1),
302 base::PlannerDataVertex(startMotion->state, 1));
303 }
304
305 for (auto goalMotion : goalMotions_)
306 {
307 if (goalMotion->parent == nullptr)
308 data.addGoalVertex(base::PlannerDataVertex(goalMotion->state, 2));
309 else
310 // The edges in the goal tree are reversed to be consistent with start tree
311 data.addEdge(base::PlannerDataVertex(goalMotion->state, 2),
312 base::PlannerDataVertex(goalMotion->parent->state, 2));
313 }
314
315 // Add the edge connecting the two trees
316 data.addEdge(data.vertexIndex(connectionPoint_.first), data.vertexIndex(connectionPoint_.second));
317}
Abstract representation of a container that can perform nearest neighbors queries.
A class that will hold data contained in the PDF.
Definition PDF.h:53
A container that supports probabilistic sampling over weighted data.
Definition PDF.h:49
double getWeight(const Element *elem) const
Returns the current weight of the given Element.
Definition PDF.h:171
_T & sample(double r) const
Returns a piece of data from the PDF according to the input sampling value, which must be between 0 a...
Definition PDF.h:132
Element * add(const _T &d, const double w)
Adds a piece of data with a given weight to the PDF. Returns a corresponding Element,...
Definition PDF.h:97
void update(Element *elem, const double w)
Updates the data in the given Element with a new weight value.
Definition PDF.h:155
Abstract definition of a goal region that can be sampled.
Base class for a vertex in the PlannerData structure. All derived classes must implement the clone an...
Definition PlannerData.h:59
Object containing planner generated vertex and edge data. It is assumed that all vertices are unique,...
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...
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...
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...
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...
Encapsulate a termination condition for a motion planner. Planners will call operator() to decide whe...
PlannerInputStates pis_
Utility class to extract valid input states.
Definition Planner.h:407
PlannerSpecs specs_
The specifications of the planner (its capabilities).
Definition Planner.h:413
ProblemDefinitionPtr pdef_
The user set problem definition.
Definition Planner.h:404
const std::string & getName() const
Get the name of the planner.
Definition Planner.cpp:56
SpaceInformationPtr si_
The space information for which planning is done.
Definition Planner.h:401
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:106
Definition of an abstract state.
Definition State.h:50
The definition of a motion.
Definition BiEST.h:104
base::State * state
The state contained by the motion.
Definition BiEST.h:116
const base::State * root
The root node of the tree this motion is in.
Definition BiEST.h:125
Motion * parent
The parent motion in the exploration tree.
Definition BiEST.h:119
PDF< Motion * >::Element * element
A pointer to the corresponding element in the probability distribution function.
Definition BiEST.h:122
base::ValidStateSamplerPtr sampler_
Valid state sampler.
Definition BiEST.h:155
PDF< Motion * > startPdf_
The probability distribution function over states in each tree.
Definition BiEST.h:143
void addMotion(Motion *motion, std::vector< Motion * > &motions, PDF< Motion * > &pdf, const std::shared_ptr< NearestNeighbors< Motion * > > &nn, const std::vector< Motion * > &neighbors)
Add a motion to the exploration tree.
Definition BiEST.cpp:275
void freeMemory()
Free the memory allocated by this planner.
Definition BiEST.cpp:94
void setup() override
Perform extra configuration steps, if needed. This call will also issue a call to ompl::base::SpaceIn...
Definition BiEST.cpp:56
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 BiEST.cpp:111
double getRange() const
Get the range the planner is using.
Definition BiEST.h:92
double nbrhoodRadius_
The radius considered for neighborhood.
Definition BiEST.h:161
std::shared_ptr< NearestNeighbors< Motion * > > nnStart_
A nearest-neighbors datastructure containing the tree of motions.
Definition BiEST.h:135
RNG rng_
The random number generator.
Definition BiEST.h:164
void clear() override
Clear all internal datastructures. Planner settings are not affected. Subsequent calls to solve() wil...
Definition BiEST.cpp:75
double maxDistance_
The maximum length of a motion to be added to a tree.
Definition BiEST.h:158
BiEST(const base::SpaceInformationPtr &si)
Constructor.
Definition BiEST.cpp:43
std::vector< Motion * > startMotions_
The set of all states in the start tree.
Definition BiEST.h:139
void setRange(double distance)
Set the range the planner is supposed to use.
Definition BiEST.h:82
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 BiEST.cpp:292
std::pair< base::State *, base::State * > connectionPoint_
The pair of states in each tree connected during planning. Used for PlannerData computation.
Definition BiEST.h:167
double distanceFunction(const Motion *a, const Motion *b) const
Compute distance between motions (actually distance between contained states).
Definition BiEST.h:129
This class contains methods that automatically configure various parameters for motion planning....
Definition SelfConfig.h:59
static NearestNeighbors< _T > * getDefaultNearestNeighbors(const base::Planner *planner)
Select a default nearest neighbor datastructure for the given space.
Definition SelfConfig.h:105
void configurePlannerRange(double &range)
Compute what a good length for motion segments is.
#define OMPL_INFORM(fmt,...)
Log a formatted information string.
Definition Console.h:68
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
Definition Console.h:64
This namespace contains sampling based planning routines shared by both planning under geometric cons...
@ GOAL_SAMPLEABLE_REGION
This bit is set if casting to sampleable goal regions (ompl::base::GoalSampleableRegion) is possible.
Definition GoalTypes.h:56
A class to store the exit status of Planner::solve().
StatusType
The possible values of the status returned by a planner.
@ INVALID_START
Invalid start state or no start state specified.
@ EXACT_SOLUTION
The planner found an exact solution.
@ INVALID_GOAL
Invalid goal state.
@ UNRECOGNIZED_GOAL_TYPE
The goal is of a type that a planner does not recognize.
@ TIMEOUT
The planner failed to find a solution.