All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
Geometric planning for a rigid body in 3D

This tutorial shows how to plan for a rigid body in 3D. We show how to do this in two ways: with and without the ompl::geometric::SimpleSetup class. The main difference is that in the latter case ompl::base::SpaceInformation and ompl::base::ProblemDefinition need to be explicitly instantiated. Furthermore, the planner to be used must be explicitly instantiated as well. The recommended approach is using ompl::geometric::SimpleSetup as this is less bug prone and does not limit the functionality of the code in any way.

Setting up geometric planning for a rigid body in 3D requires the following steps:
  • identify the space we are planning in: SE(3)
  • select a corresponding state space from the available ones, or implement one. For SE(3), the ompl::base::SE3StateSpace is appropriate.
  • since SE(3) contains an R3 component, we need to define bounds.
  • define the notion of state validity.
  • define start states and a goal representation.

Once these steps are complete, the specification of the problem is conceptually done. The set of classes that allow the instantiation of this specification is shown below.

Using the ompl::geometric::SimpleSetup class

Assuming the following namespace definitions:
namespace ob = ompl::base;
namespace og = ompl::geometric;
And a state validity checking function defined like this:
bool isStateValid(const ob::State *state)
We first create an instance of the state space we are planning in.
void planWithSimpleSetup(void)
{
    // construct the state space we are planning in
    ob::StateSpacePtr space(new ob::SE3StateSpace());
We then set the bounds for the R3 component of this state space:
    ob::RealVectorBounds bounds(3);
    bounds.setLow(-1);
    bounds.setHigh(1);

    space->as<ob::SE3StateSpace>()->setBounds(bounds);
Create an instance of ompl::geometric::SimpleSetup. Instances of ompl::base::SpaceInformation, and ompl::base::ProblemDefinition are created internally.
    og::SimpleSetup ss(space);
Set the state validity checker
    ss.setStateValidityChecker(boost::bind(&isStateValid, _1));
Create a random start state:
    ob::ScopedState<> start(space);
    start.random();
And a random goal state:
    ob::ScopedState<> goal(space);
    goal.random();
Set these states as start and goal for SimpleSetup.
    ss.setStartAndGoalStates(start, goal);
We can now try to solve the problem. This will also trigger a call to ompl::geometric::SimpleSetup::setup() and create a default instance of a planner, since we have not specified one. Furthermore, ompl::base::Planner::setup() is called, which in turn calls ompl::base::SpaceInformation::setup(). This chain of calls will lead to computation of runtime parameters such as the state validity checking resolution. This call returns a boolean flag indicating whether a solution has been found within the specified amount of time (in seconds).
    bool solved = ss.solve(1.0);
If a solution has been found, we can optionally simplify it and the display it
    if (solved)
    {
        std::cout << "Found solution:" << std::endl;
        // print the path to screen
        ss.simplifySolution();
        ss.getSolutionPath().print(std::cout);
    }

Without ompl::geometric::SimpleSetup

Assuming the following namespace definitions:
namespace ob = ompl::base;
namespace og = ompl::geometric;
And a state validity checking function defined like this:
bool isStateValid(const ob::State *state)
We first create an instance of the state space we are planning in.
void plan(void)
{
    // construct the state space we are planning in
    ob::StateSpacePtr space(new ob::SE3StateSpace());
We then set the bounds for the R3 component of this state space:
    ob::RealVectorBounds bounds(3);
    bounds.setLow(-1);
    bounds.setHigh(1);

    space->as<ob::SE3StateSpace>()->setBounds(bounds);
Create an instance of ompl::base::SpaceInformation for the state space Set the state validity checker
    si->setStateValidityChecker(boost::bind(&isStateValid, _1));
Create a random start state:
    ob::ScopedState<> start(space);
    start.random();
And a random goal state:
    ob::ScopedState<> goal(space);
    goal.random();
Create an instance of ompl::base::ProblemDefinition Set the start and goal states for the problem definition.
    pdef->setStartAndGoalStates(start, goal);
Create an instance of a planner
    ob::PlannerPtr planner(new og::RRTConnect(si));
Tell the planner which problem we are interested in solving
    planner->setProblemDefinition(pdef);
Make sure all the settings for the space and planner are in order. This will also lead to the runtime computation of the state validity checking resolution.
    planner->setup();
We can now try to solve the problem. This call returns a boolean flag indicating whether a solution has been found within the specified amount of time (in seconds).
    bool solved = planner->solve(1.0);
If a solution has been found, we display it. Simplification could be done, but we would need to create an instance of ompl::geometric::PathSimplifier.
    if (solved)
    {
        // get the goal representation from the problem definition (not the same as the goal state)
        // and inquire about the found path
        ob::PathPtr path = pdef->getGoal()->getSolutionPath();
        std::cout << "Found solution:" << std::endl;

        // print the path to screen
        path->print(std::cout);
    }