openrave.org

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Planner Concepts

Reference: OpenRAVE::PlannerBase

Introduction

In OpenRAVE, the basic purpose of a planner is to find a trajectory starting at some initial configuration that reaches a goal condition while satisfying various navigation constraints. All planners are assumed to be geometric in nature (ie, not planning in the space of policies that depend on sensor data). Planners can have any configuration space defined by using the OpenRAVE::PlannerBase::PlannerParameters structure. A planner should never use the raw joint values functions defined in KinBody.

The usage of a planner is simple:

Planning Details

Planner Parameters - Calling a Planner

All the information defining a planning problem should be specified in PlannerBase::PlannerParameters. PlannerParameters tries to cover most of the common data like distance metrics, sampling distributions, initial and goal configurations. However there are many different types of inputs to a planner, so it is impossible to cover everything with one class. Instead, PlannerParameters has a very flexible and safe way to extend its parameters without destroying compatibility with a particular planner or user of the planner. This is enabled by the serialization to XML capabilities of PlannerParameters

PlannerBase::PlannerParametersPtr params(new PlannerBase::PlannerParameters());
params->vinitialconfig.push_back(2);
ostream os;
os << *params;

will produce something in the form of

<PlannerParameters>
  <initialconfig>2</initialconfig>
</PlannerParameters>

Furthermore PlannerParameters can read such an XML file given an input stream

istream is;
is >> *params;

Using XML as a medium, it is easy to exchange data across different derivations of PlannerParameters without much effort. To add new parameters for planners to take advantage of

As long as the user of the planner passes a PlannerParameters that can serialize to the same format of data that the planner expects, the data will be passed. This allows the planner and the caller of PlanPath to use different PlannerParameters. definitions without any conflicts.

Basic Usage

This is a simple call to a birrt planner, let activegoal hold the goal configuration and activejoints hold indices to the robot joints interested to plan for.

PlannerBase::PlannerParametersPtr params(new PlannerBase::PlannerParameters);
params->SetRobotActiveJoints(robot); // sets the active joint indices
robot->GetActiveDOFValues(params.vinitialconfig); // set initial config (use current robot configuration)
params.vgoalconfig = activegoal;
// set other params values like
PlannerBasePtr rrtplanner = RaveCreatePlanner(GetEnv(),"rBiRRT");
TrajectoryBasePtr ptraj = RaveCreateTrajectory(GetEnv(),robot->GetActiveDOF());
if( !rrtplanner->InitPlan(robot, params) ) {
return false;
}
PlannerStatus status = rrtplanner->Plan(ptraj);
if( status & PS_HasSolution ) {
robot->SetActiveMotion(ptraj); // trajectory is done, execute on the robot
}

In order to speed up computations further, planners can use the CO_ActiveDOFs collision checker option, which only focuses collision on the currently moving links in the robot. If using the robot active DOF, before calling the planner, the user should insert this statement:

CollisionOptionsStateSaver optionstate(GetEnv()->GetCollisionChecker(),GetEnv()->GetCollisionChecker()->GetCollisionOptions()|CO_ActiveDOFs,false);

Defining Extra Planner Parameters

Here is how to derive from a PlannerParameters class in order to introduce new parameters.

class BasicRRTParameters : public PlannerBase::PlannerParameters
{
public:
BasicRRTParameters() : _fGoalBiasProb(0.05f), _bProcessing(false) {
_vXMLParameters.push_back("goalbias");
}
dReal _fGoalBiasProb;
protected:
bool _bProcessing;
virtual bool serialize(std::ostream& O) const
{
if( !PlannerParameters::serialize(O) )
return false;
O << "<goalbias>" << _fGoalBiasProb << "</goalbias>" << endl;
return !!O;
}
ProcessElement startElement(const std::string& name, const std::list<std::pair<std::string,std::string> >& atts)
{
if( _bProcessing )
return PE_Ignore;
switch( PlannerBase::PlannerParameters::startElement(name,atts) ) {
case PE_Pass: break;
case PE_Support: return PE_Support;
case PE_Ignore: return PE_Ignore;
}
_bProcessing = name=="goalbias";
return _bProcessing ? PE_Support : PE_Pass;
}
virtual bool endElement(const string& name)
{
if( _bProcessing ) {
if( name == "goalbias")
_ss >> _fGoalBiasProb;
else
RAVELOG_WARN(str(boost::format("unknown tag %s\n")%name));
_bProcessing = false;
return false;
}
// give a chance for the default parameters to get processed
return PlannerParameters::endElement(name);
}
};

Planner Development

Most planners do their computation iteratively, and they take lots of computation time. It is very frequent for a user to want to early-terminate the planner, or tell it to return the best solution it has founds immediately. Users might also want to visualize the planning process without getting into the internals of the planner. In order to do this, OpenRAVE allows users to register callbacks via OpenRAVE::PlannerBase::RegisterPlanCallback. Planner developers should always call OpenRAVE::PlannerBase::_CallCallbacks inside their planning loop and process the input correctly.

Planner Examples

Examples of planners are:

Planner should be able to query sensor information from the Robot like its current camera image etc. Planner should be compatible with Robot presented; some hand-shaking should happen between the two during InitPlan function.

Path Optimization

Path smoothing/optimization can be regarded as a post-processing step to planners. "Path optimization" algorithms take in an existing trajectory and filter it using the existing constraints of the planner. In fact, functionality there is no difference between a "path optimization" planner and a regular planner besides the fact that a trajectory is used as input. Because PlannerBase::PlanPath already has a trajectory as an argument, this does not cause any major API changes to the infrastructure.

However, the PlannerParameters structure had to reflect what 'path optimization' algorithm to use for post processing the trajectory. This is now reflected in the PlannerParameters::_sPostProcessingPlanner and PlannerParameters::_sPostProcessingParameters arguments. By default, this is the default "linear shortcut" path optimizer. There is also a helper function in PlannerBase to help users easily call the post-processing step:

_ProcessPostPlanners(RobotBasePtr probot, TrajectoryBasePtr ptraj);

Please take a look at how the default RRT algorithms are now structured.

Planner post-processing actually allows users to chain planners in the same way that filters are chained, all through specifying planner parameters. Of course, users can continue to smooth in planners without relying on this framework. However, explicit control of path smoothing allows custom parameter to be easily specified.