-
Notifications
You must be signed in to change notification settings - Fork 110
Planner Design Framework
Many sampling based planners make use of similar functionalities or approaches. To make building new planners as easy as possible, we provide a modular object-oriented framework for creating new planners.
All planners have a common structure as is presented the page 'Planner Structure'. The core components of TrajectoryGenerators and TrajectoryEvaluators are supposed to have a flexible enough interface to allow for a large variety of planners. However, they don't need to implement every single of their virtual functions. Each of these functions has different implementations encapsulated as modules, allowing reusage of common implementations. All functions, which are not explicitely overridden, will be built from these modular building blocks.
Modules are specified and configured via the ros parameter server, where the main planner and other submodules forward their namespace plus the respective module namespace to the ModuleFactory. Every module needs to specify a "type" parameter, according to which the desired classes are instantiated. They are then individually configured through the ros parameter server.
This object-oriented modular approach has the advantage, that planners consisting of already existing modules can be built at run time via a ros parameter configuration. No more recompiling for testing new planners! The recommended way is to load a "my_config.yaml" into the planner node. An example configuration is given in cfg/planners/example_config.yaml
. The default namespaces for modules, relative to the planner node, are as follows:
trajectory_generator:
type: "MyTrajectoryGenerator"
segment_selector:
type: "MyExpansionPolicy"
generator_updater:
type: "MyUpdateStrategy"
trajectory_evaluator:
type: "MyTrajectoryEvaluator"
cost_computer:
type: "MyCost"
value_computer:
type: "MyValueFunc"
next_selector:
type: "MyNextBestSelection"
evaluator_updater:
type: "MyUpdateStrategy"
back_tracker:
type: "DontGetStuck"
Notice that for some functionalities multiple modules can be combined using the Decorator Pattern:
evaluator_updater:
type: "Operation1"
following_updater:
type: "Operation2"
following_updater:
...
Custom implementations for all module types can easily be added to the framework. Custom modules inherit from a base module type that specifies the interface with other classes. All base types inherit from the Module
class, which contains utilities to configure and build modules through the ModuleFactory
. To create a custom module follow these steps:
- Create your module class
All module classes should be organized as follows:
class MyModule : public ModuleBase {
public:
// default constructor with an associated planner interface
MyModule(PlannerI &planner);
// override virtual functions of the base class
bool moduleBasePureVirtualFunction(TrajectorySegment *root){
/* do some magic here */
return success;
}
protected:
// Statically register the module to the factory so that it can be constructed
static ModuleFactory::Registration<MyModule> registration;
// make the module configurable through the factory (required by Module class)
void setupFromParamMap(Module::ParamMap *param_map){
// Make sure to propagate the setup through the inheritance chain
ModuleBase::setupFromParamMap(param_map);
int my_param_default = 1;
// Use the utility function of Module to set params
setParam<int>(param_map, "my_param", &p_my_param_, my_param_default);
}
// guarantee parameters fulfill required constraints (optional by Module class)
bool checkParamsValid(std::string *error_message) {
if (p_my_param <= 0) {
*error_message = "my_param expected > 0";
return false;
}
// Make sure to propagate validation checks through the inheritance chain
return ModuleBase::checkParamsValid(error_message);
}
// params
int p_my_param_;
};
// Initialize registration with a unique name (i.e. the name of the class)
ModuleFactory::Registration<MyModule> MyModule::registration("MyModule");
If your module uses other modules, e.g. to be used in a chain of decorators, adapt these functions as follows:
class MyDecoratorModule : public ModuleBase {
public:
bool moduleBasePureVirtualFunction(TrajectorySegment *root){
// passing the request down the chain
return following_module->moduleBasePureVirtualFunction(root);
}
protected:
void setupFromParamMap(Module::ParamMap *param_map){
// Submodules are created using this formalism
std::string args; // the module args need to be specifiable
std::string param_ns = (*param_map)["param_namespace"]; // default extends the parent namespace
setParam<std::string>(param_map, "following_module_args", &args, param_ns + "/following_module");
following_module_ = ModuleFactory::Instance()->createModule<ModuleBase>(args, verbose_modules_);
}
// Modules are unique_ptrs
std::unique_ptr<ModuleBase> following_module_;
};
- Add some documentation
Please make sure the code and all parameters are human readable. Also add new modules to the Code Index of the repo with a brief description. For inspiration consider looking through some of the default modules.
If your new modules do not seem to fit with any of the existing packages, other dependencies are required or you want to deploy the planner in a specific application, consider grouping them into a separate package.
- Hint: if the package consists only of additional modules that are to be used from other packages, add a short initialization function that prevents the linker from 'optimizing the package away', since the application will not explicitly depend on it.
Add a short my_module_package/initialization/my_module_package.h/cpp:
namespace active_3d_planning {
namespace initialize {
// force the linker to include this lib
void my_module_package();
} // namespace initialize
} // namespace active_3d_planning
In app_my_cool_application call the initialization function of all module-only-packages to register them to the factory:
active_3d_planning::initialize::mav_package();
active_3d_planning::initialize::voxblox_package();
active_3d_planning::initialize::my_module_package();
// instantiate and run the planner ...
- Add some documentation
Add a short description of the package in the readme and add dependencies.
Planner Structure
Planner Design Framework
Running and Evaluating a Simulated Experiment
Code Index