We show in this tutorial how the setup of a QuotientSpace planning task differs from a classical ConfigurationSpace planning task. Finally, we show how the PlannerData can be extracted from the QuotientSpace planner.
Classical Configuration Space Planning
A classical planning problem in OMPL is defined by
ompl::base::SpaceInformationPtr
, the configuration spaceompl::base::ProblemDefinitionPtr
, the start and goal configurationompl::base::PlannerPtr
, the planner used
We then construct and solve a planning problem as
QuotientSpace Planning
In a QuotientSpace planning setting, we change this routine to add a finite number of QuotientSpaces, which can be exploited by an algorithm (if it supports it).
We therefore need in addition
std::vector<ompl::base::SpaceInformationPtr>
, the QuotientSpaces. Sorted in ascending order depending on number of dimensions. Last element has to be the Configuration Space.ompl::geometric::QRRT
, a specific QuotientSpace planner which inherits from ompl::geometric::QuotientSpace
A planning problem can then be solved as
Building QuotientSpaces
Let us build a small sequence of two QuotientSpaces for a Rigid Body in 2D with configuration space \(SE(2)\). This example has been implemented in demos/QuotientSpacePlanningRigidBody2D.cpp
First, we need to construct the SpaceInformationPtr for each QuotientSpace. In this case, we opt for two layers \(\{\mathbb{R}^2, SE(2)\}\). The space is bounded to be in the unit square \([0,1]^2\)
Second, we need to set the validitychecker for each SpaceInformationPtr. This is done by defining a Validity function which evaluates to true if a State is feasible and false if it is infeasible.
For the SE(2) constraint, we declare all configurations feasible where the rotation is smaller than \(\frac{\pi}{2}\) and where the position is not in a circle of radius \(0.2\) located at \((0.5,0.5)\).
The validity function for the QuotientSpace can be constructed for example by removing some of the constraints. In real experiments, we often remove links or parts of links from a robot, which implicitly removes the constraints.
Finally, we need to set the Validity function to and push the SpaceInformationPtr into the vector. Note that the SpaceInformationPtr have to be sorted in ascending order depending on number of dimensions.
NOTE: The runtime of a QuotientSpace planner depends crucially on the sequence of QuotientSpaces defined. For some spaces, planning time can be very fast, while for others it is easily outperformed by classical planner such as ompl::geometric::RRT (which is equivalent to running ompl::geometric::QRRT with a single configuration space). Which spaces work best is still an open research question. A good heuristic is to use more QuotientSpaces the more narrow passages we have in an environment. More information can be found in the QRRT paper.
AnnotatedPlannerDataVertex
Having defined a QuotientSpace planner, we can utilize it similar to a usual ompl::base::PlannerPtr, i.e. it can be added to any benchmark, and we can get the planner data.
However, the classical PlannerData structure does not know about QuotientSpaces. To add QuotientSpace information, we have written a new class ompl::base::PlannerDataVertexAnnotated, which inherits from PlannerDataVertex. PlannerDataVertexAnnotated adds new functionalities, including
getLevel()
, returns the QuotientSpace level the current vertex is ongetMaxLevel()
, returns the number of QuotientSpace levelsgetQuotientState()
, returns a QuotientSpace state on the current vertex levelgetState()
, returns a state in the original configuration space (this way the behavior is the same as for the classical PlannerData class).
Further Information
For more information, please refer to either the general introduction to QuotientSpaces or the demos.