Loading...
Searching...
No Matches
SpaceInformation.cpp
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2010, 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: Ioan Sucan */
36
37#include "ompl/base/SpaceInformation.h"
38#include <cassert>
39#include <queue>
40#include <utility>
41#include "ompl/base/DiscreteMotionValidator.h"
42#include "ompl/base/samplers/UniformValidStateSampler.h"
43#include "ompl/base/spaces/DubinsStateSpace.h"
44#include "ompl/base/spaces/OwenStateSpace.h"
45#include "ompl/base/spaces/VanaStateSpace.h"
46#include "ompl/base/spaces/VanaOwenStateSpace.h"
47#include "ompl/base/spaces/Dubins3DMotionValidator.h"
48#include "ompl/base/spaces/DubinsMotionValidator.h"
49#include "ompl/base/spaces/ReedsSheppStateSpace.h"
50#include "ompl/base/spaces/TrochoidStateSpace.h"
51#include "ompl/base/spaces/constraint/ConstrainedStateSpace.h"
52#include "ompl/tools/config/MagicConstants.h"
53#include "ompl/util/Exception.h"
54#include "ompl/util/Time.h"
55
56ompl::base::SpaceInformation::SpaceInformation(StateSpacePtr space) : stateSpace_(std::move(space)), setup_(false)
57{
58 if (!stateSpace_)
59 throw Exception("Invalid space definition");
61 params_.include(stateSpace_->params());
62}
63
65{
67 {
68 stateValidityChecker_ = std::make_shared<AllValidStateValidityChecker>(this);
69 OMPL_WARN("State validity checker not set! No collision checking is performed");
70 }
71
74
75 stateSpace_->setup();
76 if (stateSpace_->getDimension() <= 0)
77 throw Exception("The dimension of the state space we plan in must be > 0");
78
79 params_.clear();
80 params_.include(stateSpace_->params());
81
82 setup_ = true;
83}
84
86{
87 return setup_;
88}
89
91{
92 class FnStateValidityChecker : public StateValidityChecker
93 {
94 public:
95 FnStateValidityChecker(SpaceInformation *si, StateValidityCheckerFn fn)
96 : StateValidityChecker(si), fn_(std::move(fn))
97 {
98 }
99
100 bool isValid(const State *state) const override
101 {
102 return fn_(state);
103 }
104
105 protected:
107 };
108
109 if (!svc)
110 throw Exception("Invalid function definition for state validity checking");
111
112 setStateValidityChecker(std::make_shared<FnStateValidityChecker>(this, svc));
113}
114
116{
117 if (dynamic_cast<ReedsSheppStateSpace *>(stateSpace_.get()))
118 motionValidator_ = std::make_shared<DubinsMotionValidator<ReedsSheppStateSpace>>(this);
119 else if (dynamic_cast<DubinsStateSpace *>(stateSpace_.get()))
120 motionValidator_ = std::make_shared<DubinsMotionValidator<DubinsStateSpace>>(this);
121 else if (dynamic_cast<TrochoidStateSpace *>(stateSpace_.get()))
122 motionValidator_ = std::make_shared<DubinsMotionValidator<TrochoidStateSpace>>(this);
123 else if (dynamic_cast<OwenStateSpace *>(stateSpace_.get()))
124 motionValidator_ = std::make_shared<Dubins3DMotionValidator<OwenStateSpace>>(this);
125 else if (dynamic_cast<VanaStateSpace *>(stateSpace_.get()))
126 motionValidator_ = std::make_shared<Dubins3DMotionValidator<VanaStateSpace>>(this);
127 else if (dynamic_cast<VanaOwenStateSpace *>(stateSpace_.get()))
128 motionValidator_ = std::make_shared<Dubins3DMotionValidator<VanaOwenStateSpace>>(this);
129 else if (dynamic_cast<ConstrainedStateSpace *>(stateSpace_.get()))
130 motionValidator_ = std::make_shared<ConstrainedMotionValidator>(this);
131 else
132 motionValidator_ = std::make_shared<DiscreteMotionValidator>(this);
133}
134
140
146
148 unsigned int steps, std::vector<State *> &states,
149 bool alloc) const
150{
151 if (alloc)
152 {
153 states.resize(steps);
154 for (unsigned int i = 0; i < steps; ++i)
155 states[i] = allocState();
156 }
157 else if (states.size() < steps)
158 steps = states.size();
159
160 const State *prev = start;
161 std::pair<State *, double> lastValid;
162 unsigned int j = 0;
163 for (unsigned int i = 0; i < steps; ++i)
164 {
165 sss->sampleUniform(states[j]);
166 lastValid.first = states[j];
167 if (checkMotion(prev, states[j], lastValid) || lastValid.second > std::numeric_limits<double>::epsilon())
168 prev = states[j++];
169 }
170
171 return j;
172}
173
175 const State *near, double distance) const
176{
177 if (state != near)
178 copyState(state, near);
179
180 // fix bounds, if needed
181 if (!satisfiesBounds(state))
182 enforceBounds(state);
183
184 bool result = isValid(state);
185
186 if (!result)
187 {
188 // try to find a valid state nearby
189 State *temp = cloneState(state);
190 result = sampler->sampleNear(state, temp, distance);
191 freeState(temp);
192 }
193
194 return result;
195}
196
198 unsigned int attempts) const
199{
200 if (satisfiesBounds(near) && isValid(near))
201 {
202 if (state != near)
203 copyState(state, near);
204 return true;
205 }
206 else
207 {
208 // try to find a valid state nearby
209 auto uvss = std::make_shared<UniformValidStateSampler>(this);
210 uvss->setNrAttempts(attempts);
211 return searchValidNearby(uvss, state, near, distance);
212 }
213}
214
216 std::vector<State *> &states, unsigned int count,
217 bool endpoints, bool alloc) const
218{
219 // add 1 to the number of states we want to add between s1 & s2. This gives us the number of segments to split the
220 // motion into
221 count++;
222
223 if (count < 2)
224 {
225 unsigned int added = 0;
226
227 // if they want endpoints, then at most endpoints are included
228 if (endpoints)
229 {
230 if (alloc)
231 {
232 states.resize(2);
233 states[0] = allocState();
234 states[1] = allocState();
235 }
236 if (states.size() > 0)
237 {
238 copyState(states[0], s1);
239 added++;
240 }
241
242 if (states.size() > 1)
243 {
244 copyState(states[1], s2);
245 added++;
246 }
247 }
248 else if (alloc)
249 states.resize(0);
250 return added;
251 }
252
253 if (alloc)
254 {
255 states.resize(count + (endpoints ? 1 : -1));
256 if (endpoints)
257 states[0] = allocState();
258 }
259
260 unsigned int added = 0;
261
262 if (endpoints && states.size() > 0)
263 {
264 copyState(states[0], s1);
265 added++;
266 }
267
268 /* find the states in between */
269 for (unsigned int j = 1; j < count && added < states.size(); ++j)
270 {
271 if (alloc)
272 states[added] = allocState();
273 stateSpace_->interpolate(s1, s2, (double)j / (double)count, states[added]);
274 added++;
275 }
276
277 if (added < states.size() && endpoints)
278 {
279 if (alloc)
280 states[added] = allocState();
281 copyState(states[added], s2);
282 added++;
283 }
284
285 return added;
286}
287
288bool ompl::base::SpaceInformation::checkMotion(const std::vector<State *> &states, unsigned int count,
289 unsigned int &firstInvalidStateIndex) const
290{
291 assert(states.size() >= count);
292 for (unsigned int i = 0; i < count; ++i)
293 if (!isValid(states[i]))
294 {
295 firstInvalidStateIndex = i;
296 return false;
297 }
298 return true;
299}
300
301bool ompl::base::SpaceInformation::checkMotion(const std::vector<State *> &states, unsigned int count) const
302{
303 assert(states.size() >= count);
304 if (count > 0)
305 {
306 if (count > 1)
307 {
308 if (!isValid(states.front()))
309 return false;
310 if (!isValid(states[count - 1]))
311 return false;
312
313 // we have 2 or more states, and the first and last states are valid
314
315 if (count > 2)
316 {
317 std::queue<std::pair<int, int>> pos;
318 pos.emplace(0, count - 1);
319
320 while (!pos.empty())
321 {
322 std::pair<int, int> x = pos.front();
323
324 int mid = (x.first + x.second) / 2;
325 if (!isValid(states[mid]))
326 return false;
327
328 pos.pop();
329
330 if (x.first < mid - 1)
331 pos.emplace(x.first, mid);
332 if (x.second > mid + 1)
333 pos.emplace(mid, x.second);
334 }
335 }
336 }
337 else
338 return isValid(states.front());
339 }
340 return true;
341}
342
343ompl::base::ValidStateSamplerPtr ompl::base::SpaceInformation::allocValidStateSampler() const
344{
345 if (vssa_)
346 return vssa_(this);
347 else
348 return std::make_shared<UniformValidStateSampler>(this);
349}
350
352{
353 if (attempts == 0)
354 return 0.0;
355
356 unsigned int valid = 0;
357 unsigned int invalid = 0;
358
360 State *s = allocState();
361
362 for (unsigned int i = 0; i < attempts; ++i)
363 {
364 ss->sampleUniform(s);
365 if (isValid(s))
366 ++valid;
367 else
368 ++invalid;
369 }
370
371 freeState(s);
372
373 return (double)valid / (double)(valid + invalid);
374}
375
377{
378 // take the square root here because we in fact have a nested for loop
379 // where each loop executes #attempts steps (the sample() function of the UniformValidStateSampler if a for loop
380 // too)
381 attempts = std::max((unsigned int)floor(sqrt((double)attempts) + 0.5), 2u);
382
384 auto uvss(std::make_shared<UniformValidStateSampler>(this));
385 uvss->setNrAttempts(attempts);
386
387 State *s1 = allocState();
388 State *s2 = allocState();
389
390 std::pair<State *, double> lastValid;
391 lastValid.first = nullptr;
392
393 double d = 0.0;
394 unsigned int count = 0;
395 for (unsigned int i = 0; i < attempts; ++i)
396 if (uvss->sample(s1))
397 {
398 ++count;
399 ss->sampleUniform(s2);
400 if (checkMotion(s1, s2, lastValid))
401 d += distance(s1, s2);
402 else
403 d += distance(s1, s2) * lastValid.second;
404 }
405
406 freeState(s2);
407 freeState(s1);
408
409 if (count > 0)
410 return d / (double)count;
411 else
412 return 0.0;
413}
414
415void ompl::base::SpaceInformation::samplesPerSecond(double &uniform, double &near, double &gaussian,
416 unsigned int attempts) const
417{
419 std::vector<State *> states(attempts + 1);
420 allocStates(states);
421
422 time::point start = time::now();
423 for (unsigned int i = 0; i < attempts; ++i)
424 ss->sampleUniform(states[i]);
425 uniform = (double)attempts / time::seconds(time::now() - start);
426
427 double d = getMaximumExtent() / 10.0;
428 ss->sampleUniform(states[attempts]);
429
430 start = time::now();
431 for (unsigned int i = 1; i <= attempts; ++i)
432 ss->sampleUniformNear(states[i - 1], states[i], d);
433 near = (double)attempts / time::seconds(time::now() - start);
434
435 start = time::now();
436 for (unsigned int i = 1; i <= attempts; ++i)
437 ss->sampleGaussian(states[i - 1], states[i], d);
438 gaussian = (double)attempts / time::seconds(time::now() - start);
439
440 freeStates(states);
441}
442
444{
445 out << "Settings for the state space '" << stateSpace_->getName() << "'" << std::endl;
446 out << " - state validity check resolution: " << (getStateValidityCheckingResolution() * 100.0) << '%'
447 << std::endl;
448 out << " - valid segment count factor: " << stateSpace_->getValidSegmentCountFactor() << std::endl;
449 out << " - state space:" << std::endl;
450 stateSpace_->printSettings(out);
451 out << std::endl << "Declared parameters:" << std::endl;
452 params_.print(out);
454 out << "Valid state sampler named " << vss->getName() << " with parameters:" << std::endl;
455 vss->params().print(out);
456}
457
459{
460 out << "Properties of the state space '" << stateSpace_->getName() << "'" << std::endl;
461 out << " - signature: ";
462 std::vector<int> sig;
463 stateSpace_->computeSignature(sig);
464 for (int i : sig)
465 out << i << " ";
466 out << std::endl;
467 out << " - dimension: " << stateSpace_->getDimension() << std::endl;
468 out << " - extent: " << stateSpace_->getMaximumExtent() << std::endl;
469 if (isSetup())
470 {
471 bool result = true;
472 try
473 {
474 stateSpace_->sanityChecks();
475 }
476 catch (Exception &e)
477 {
478 result = false;
479 out << std::endl
480 << " - SANITY CHECKS FOR STATE SPACE ***DID NOT PASS*** (" << e.what() << ")" << std::endl
481 << std::endl;
482 OMPL_ERROR(e.what());
483 }
484 if (result)
485 out << " - sanity checks for state space passed" << std::endl;
486 out << " - probability of valid states: " << probabilityOfValidState(magic::TEST_STATE_COUNT) << std::endl;
487 out << " - average length of a valid motion: " << averageValidMotionLength(magic::TEST_STATE_COUNT)
488 << std::endl;
489 double uniform, near, gaussian;
490 samplesPerSecond(uniform, near, gaussian, magic::TEST_STATE_COUNT);
491 out << " - average number of samples drawn per second: sampleUniform()=" << uniform
492 << " sampleUniformNear()=" << near << " sampleGaussian()=" << gaussian << std::endl;
493 }
494 else
495 out << "Call setup() before to get more information" << std::endl;
496}
The exception type for ompl.
Definition Exception.h:47
A StateSpace that has a Constraint imposed upon it. Underlying space functions are passed to the ambi...
An SE(2) state space where distance is measured by the length of Dubins curves.
An R^3 x SO(2) state space where distance is measured by the length of a type Dubins airplane curves.
An SE(2) state space where distance is measured by the length of Reeds-Shepp curves.
StateValidityCheckerPtr stateValidityChecker_
The instance of the state validity checker used for determining the validity of states in the plannin...
void setStateValidityChecker(const StateValidityCheckerPtr &svc)
Set the instance of the state validity checker to use. Parallel implementations of planners assume th...
void freeState(State *state) const
Free the memory of a state.
void setDefaultMotionValidator()
Set default motion validator for the state space.
virtual unsigned int getMotionStates(const State *s1, const State *s2, std::vector< State * > &states, unsigned int count, bool endpoints, bool alloc) const
Get count states that make up a motion between s1 and s2. Returns the number of states that were adde...
void samplesPerSecond(double &uniform, double &near, double &gaussian, unsigned int attempts) const
Estimate the number of samples that can be drawn per second, using the sampler returned by allocState...
bool satisfiesBounds(const State *state) const
Check if a state is inside the bounding box.
double distance(const State *state1, const State *state2) const
Compute the distance between two states.
bool searchValidNearby(State *state, const State *near, double distance, unsigned int attempts) const
Find a valid state near a given one. If the given state is valid, it will be returned itself....
double probabilityOfValidState(unsigned int attempts) const
Estimate probability of sampling a valid state. setup() is assumed to have been called.
virtual void setup()
Perform additional setup tasks (run once, before use). If state validity checking resolution has not ...
void freeStates(std::vector< State * > &states) const
Free the memory of an array of states.
void enforceBounds(State *state) const
Bring the state within the bounds of the state space.
StateSamplerPtr allocStateSampler() const
Allocate a uniform state sampler for the state space.
double averageValidMotionLength(unsigned int attempts) const
Estimate the length of a valid motion. setup() is assumed to have been called.
double getStateValidityCheckingResolution() const
Get the resolution at which state validity is verified. This call is only applicable if a ompl::base:...
ParamSet params_
Combined parameters for the contained classes.
virtual void printSettings(std::ostream &out=std::cout) const
Print information about the current instance of the state space.
bool isSetup() const
Return true if setup was called.
virtual void printProperties(std::ostream &out=std::cout) const
Print properties of the current instance of the state space.
StateSpacePtr stateSpace_
The state space planning is to be performed in.
void allocStates(std::vector< State * > &states) const
Allocate memory for each element of the array states.
void copyState(State *destination, const State *source) const
Copy a state to another.
MotionValidatorPtr motionValidator_
The instance of the motion validator to use when determining the validity of motions in the planning ...
ValidStateSamplerAllocator vssa_
The optional valid state sampler allocator.
unsigned int randomBounceMotion(const StateSamplerPtr &sss, const State *start, unsigned int steps, std::vector< State * > &states, bool alloc) const
Produce a valid motion starting at start by randomly bouncing off of invalid states....
double getMaximumExtent() const
Get the maximum extent of the space we are planning in. This is the maximum distance that could be re...
ValidStateSamplerPtr allocValidStateSampler() const
Allocate an instance of a valid state sampler for this space. If setValidStateSamplerAllocator() was ...
State * cloneState(const State *source) const
Clone a state.
State * allocState() const
Allocate memory for a state.
void setValidStateSamplerAllocator(const ValidStateSamplerAllocator &vssa)
Set the allocator to use for a valid state sampler. This replaces the default uniform valid state sam...
void clearValidStateSamplerAllocator()
Clear the allocator used for the valid state sampler. This will revert to using the uniform valid sta...
bool setup_
Flag indicating whether setup() has been called on this instance.
bool isValid(const State *state) const
Check if a given state is valid or not.
virtual bool checkMotion(const State *s1, const State *s2, std::pair< State *, double > &lastValid) const
Incrementally check if the path between two motions is valid. Also compute the last state that was va...
A shared pointer wrapper for ompl::base::StateSampler.
A shared pointer wrapper for ompl::base::StateSpace.
Abstract definition for a class checking the validity of states. The implementation of this class mus...
Definition of an abstract state.
Definition State.h:50
An SE(2) state space where distance is measured by the length of Trochoid shortest paths curves.
A shared pointer wrapper for ompl::base::ValidStateSampler.
An R^4 x SO(2) state space where distance is measured by the length of a type of Dubins airplane curv...
An R^4 x SO(2) state space where distance is measured by the length of a type Dubins airplane curves.
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
Definition Console.h:64
#define OMPL_WARN(fmt,...)
Log a formatted warning string.
Definition Console.h:66
std::function< ValidStateSamplerPtr(const SpaceInformation *)> ValidStateSamplerAllocator
Definition of a function that can allocate a valid state sampler.
std::function< bool(const State *)> StateValidityCheckerFn
If no state validity checking class is specified (StateValidityChecker), a std::function can be speci...
static const unsigned int TEST_STATE_COUNT
When multiple states need to be generated as part of the computation of various information (usually ...
std::chrono::system_clock::time_point point
Representation of a point in time.
Definition Time.h:52
point now()
Get the current time point.
Definition Time.h:58
duration seconds(double sec)
Return the time duration representing a given number of seconds.
Definition Time.h:64
STL namespace.