Plugin System#

How a type: string in YAML becomes a configured object: parameter parsing (open_apero::Configurable), self-registration (open_apero::PluginRegistry), loading a library of plugins (open_apero::loadPluginLibrary()) and construction (open_apero::PluginFactory).

class Configurable#
#include <open_apero_core/plugin/plugin.h>

Parameter parsing and validation shared by plugins and other configurable objects.

Subclassed by open_apero::Agent, open_apero::BoundingVolume, open_apero::Plugin

Public Types

using ParamMap = std::map<std::string, std::string>#

Public Functions

void assureParamsValid()#

Validate the parameters; throws std::invalid_argument on failure.

Call after setupFromParamMap().

virtual bool checkParamsValid(std::string *error_message)#

Check whether the current parameter set is valid.

Parameters:

error_message – Pointer to a string that will be filled with an error description on failure.

Returns:

True if parameters are valid, false otherwise. Default implementation always returns true.

Configurable()#
virtual void setupFromParamMap(ParamMap *param_map) = 0#

Set up the object from a parameter map.

Besides the configured keys, a PluginFactory supplies “param_namespace” (the namespace the keys came from; a plugin derives its children’s default namespaces from it) and “verbose_text”.

Parameters:

param_map – Pointer to a map of parameter name-value string pairs.

virtual void setVerbose(bool verbose)#

Enable or disable verbose output for this object.

Parameters:

verbose – If true, plugin creation details are printed.

virtual ~Configurable() = default#

Public Static Functions

static std::set<std::string> consumedParams(const ParamMap &map)#

Keys of map that setParam() or markParamConsumed() have read.

Parameters:

map – Parameter map a setup has run on.

Returns:

The recorded keys; empty when nothing was read.

Public Static Attributes

static constexpr const char *kConsumedParamsKey = "\x01consumed_params"#

Reserved key recording every key setParam() reads, one per line; its leading 0x01 byte is in no ROS name or plain YAML key.

Protected Functions

template<typename T>
inline void setParam(ParamMap *map, std::string param_name, std::vector<T> *param, std::optional<std::vector<T>> param_default = std::nullopt)#

Parse a vector parameter from the parameter map (comma-delimited) and build verbose text.

Each comma-separated element is parsed like the scalar overload’s value (a bool element is “1” or “0”).

Template Parameters:

T – The element type of the vector (must support stream extraction).

Parameters:
  • map – Pointer to the parameter map.

  • param_name – Name of the parameter to look up.

  • param – Pointer to the vector that will receive the parsed values.

  • param_default – Optional default vector used when the parameter is absent.

Throws:

std::runtime_error – if the parameter is absent and has no default, or an element does not parse.

template<typename T>
inline void setParam(ParamMap *map, std::string param_name, T *param, std::optional<T> param_default = std::nullopt)#

Parse a single parameter from the parameter map and build verbose text.

The value is read with operator>>, which must consume all of it: a bool must be “1” or “0” (“true” and “false” throw), and a std::string must be a single non-empty token without whitespace. The key is recorded as consumed (see consumedParams()) whether or not it is present.

Template Parameters:

T – The parameter type (must support stream extraction).

Parameters:
  • map – Pointer to the parameter map.

  • param_name – Name of the parameter to look up.

  • param – Pointer to the variable that will receive the parsed value.

  • param_default – Optional default value used when the parameter is absent.

Throws:

std::runtime_error – if the parameter is absent and has no default, or its value does not parse.

Protected Attributes

bool verbose_plugins_ = false#

Whether to display plugin creation info.

Protected Static Functions

static void markParamConsumed(ParamMap *map, const std::string &param_name)#

Record param_name as read from map, for a key parsed without setParam().

Parameters:
  • map – Parameter map the key belongs to.

  • param_name – Name of the key that was read.

class Plugin : public open_apero::Configurable#
#include <open_apero_core/plugin/plugin.h>

Configurable object with access to its owning agent: the base of every plugin.

Subclassed by open_apero::Backtracker, open_apero::CostComputer, open_apero::Evaluator, open_apero::Generator, open_apero::Layer, open_apero::Map, open_apero::PathPlanner, open_apero::RobotModel, open_apero::SensorModel

Public Functions

template<class T>
inline T *as()#

Safely downcast this plugin to a derived type.

Template Parameters:

T – Target derived type.

Returns:

Pointer to the derived type, or nullptr if the cast fails.

template<class T>
inline const T *as() const#

Safely downcast this plugin to a derived const type.

Template Parameters:

T – Target derived type.

Returns:

Pointer to the derived type, or nullptr if the cast fails.

explicit Plugin(AgentInterface &agent)#

Construct a Plugin with a reference to the owning agent.

Parameters:

agent – Reference to the agent interface.

virtual void resetEpisode() = 0#

Reset all per-episode plugin state.

virtual ~Plugin() = default#

Protected Attributes

AgentInterface &agent_#

Reference to the owning agent.

class PluginRegistry#
#include <open_apero_core/plugin/plugin_registry.h>

Singleton registry that maps plugin type names to their constructors.

Plugins register themselves at static-initialization time using the nested Registration helper struct, when the executable or a library it links starts up, or when loadPluginLibrary() loads their library. At runtime, the factory looks up a type name in this registry to instantiate the corresponding plugin.

Public Functions

template<class PluginType>
inline std::unique_ptr<PluginType> createPlugin(const std::string &plugin_name, AgentInterface &agent, bool)#

Create a plugin by its registered type name.

Never returns nullptr: throws std::runtime_error if the name is unregistered or the plugin is not a PluginType (destroying it first). The verbose flag is unused.

Template Parameters:

PluginType – The expected base type for the created plugin.

Parameters:
  • plugin_name – Registered name of the plugin type to create.

  • agent – Reference to the agent that will own this plugin.

Returns:

A unique pointer to the created plugin (always non-null on return).

virtual ~PluginRegistry() = default#

Public Static Functions

static std::string availableTypes()#

Comma-separated list of all registered type names, for error messages.

static const std::vector<std::string> &duplicateNames()#

The names registerPlugin() refused because they were already taken, in the order of the attempts; a name repeats when refused more than once.

static const PluginConstructor *findConstructor(const std::string &plugin_name)#

Look up a constructor by name.

Returns:

Pointer to the stored constructor, or nullptr if unregistered. The pointer stays valid as long as the plugin is registered (std::map node addresses are stable across further insertions).

static PluginRegistry &instance()#

Access the singleton instance of the registry.

Returns:

Reference to the global PluginRegistry.

static std::vector<std::string> registeredNames()#

Sorted list of all registered plugin type names (for introspection).

static void registerPlugin(const std::string &plugin_name, PluginConstructor constructor)#

Register a constructor under a name. A name that already exists keeps its constructor; the attempt is logged as an error and recorded in duplicateNames(). Defined out-of-line so all callers, in any shared object, mutate the one registry map inside core.

template<class PluginType>
struct Registration#
#include <open_apero_core/plugin/plugin_registry.h>

Helper struct for static self-registration of plugin types.

Declare a static instance of Registration<MyPlugin>(“MyPlugin”) in a translation unit to register MyPlugin with the factory at program startup. The registered name is the string selected by “type:” in YAML.

Template Parameters:

PluginType – The concrete plugin class to register.

Public Functions

inline explicit Registration(const std::string &plugin_name)#

Register a plugin type under the given name.

Parameters:

plugin_name – Unique name to register the plugin under.

using open_apero::PluginConstructor = std::function<Plugin*(AgentInterface &agent)>#

Constructs a plugin for an agent.

void open_apero::loadPluginLibrary(const std::string &library)#

Load a shared library so the plugins it holds register themselves.

Loading runs the library’s static initializers, and with them every PluginRegistry::Registration it holds. The library is never unloaded, since the registry keeps constructors that live in it. A library that is already loaded, by the executable’s link line or an earlier call, registers nothing again. The name is resolved as dlopen() does: an absolute path as given, a bare file name through the loader’s search path (LD_LIBRARY_PATH, the executable’s RPATH, the system directories).

Parameters:

library – File name or path of the shared library.

Throws:

std::runtime_error – if the library cannot be loaded (with the loader’s reason), or if it registers a type name that was already registered.

class PluginFactory#
#include <open_apero_core/plugin/plugin_factory.h>

Abstract factory for creating and configuring agent plugins.

Subclass this factory to provide concrete parameter sources (e.g., ROS parameters, config files). The factory delegates actual plugin instantiation to the PluginRegistry and then configures each plugin via its parameter map.

Subclassed by open_apero::PluginFactoryConfig, open_apero::ros::PluginFactoryRos

Public Functions

void configure(Configurable &configurable, const std::string &args, bool verbose)#

Configure an already constructed Configurable (e.g. BoundingVolume) from a parameter source.

Runs setup and validation without any registry lookup or type resolution.

Parameters:
  • configurable – The object to configure (already constructed).

  • args – Configuration arguments string (interpretation depends on the concrete factory).

  • verbose – If true, print configuration details.

Throws:

std::runtime_error – and std::invalid_argument as createPlugin() does for setup, validation and strict mode; the prefix names the configurable’s class.

template<class PluginType>
inline std::unique_ptr<PluginType> createPlugin(const std::string &args, AgentInterface &agent, bool verbose)#

Create, configure, and validate a plugin of the given type.

Resolves the type from the parameter source, instantiates it via the registry, then runs setup and validation. Total: returns a configured non-null plugin or throws; a missing “type” is a configuration error. Keys the setup never read are reported once (see setStrictParams()).

Template Parameters:

PluginType – The base plugin type to create (e.g., Evaluator).

Parameters:
  • args – Configuration arguments string (interpretation depends on the concrete factory).

  • agent – Reference to the agent that will own this plugin.

  • verbose – If true, print plugin configuration details.

Throws:
  • std::runtime_error – if no type is configured, the type is unknown, the constructed plugin is not a PluginType, a parameter is missing or does not parse (Configurable::setParam), or strict mode finds an unread key.

  • std::invalid_argument – if the plugin’s checkParamsValid() rejects the configuration (Configurable::assureParamsValid). A std::runtime_error or std::invalid_argument raised by setup or validation is thrown again with the prefix “<type> at ‘<namespace>’: “.

Returns:

A unique pointer to the newly created and configured plugin (never null).

virtual bool getParamMapAndType(Configurable::ParamMap *map, std::string *type, std::string args) = 0#

Parse configuration arguments into a parameter map and resolve the plugin type.

Subclasses implement this to support different configuration sources (ROS params, files, etc.). Leave type untouched when the source configures no “type”: an empty result means “not configured”, which createPlugin reports as an error.

Besides the leaf keys, an implementation must set map[“param_namespace”] to the resolved namespace (Agent and Layer derive their children’s default namespaces from it) and map[“verbose_text”] to the header printVerbose() prints; both built-in factories do. Values must be strings Configurable::setParam() parses, e.g. a bool as “1”/”0”.

Parameters:
  • map – Output parameter map to populate.

  • type – Output string that receives the configured type name, if any.

  • args – Configuration arguments string.

Returns:

True on success. createPlugin() and configure() currently ignore it.

inline bool isStrictParams() const#

Whether an unread key throws (see setStrictParams()).

virtual std::vector<std::string> listChildNamespaces(const std::string &ns)#

List the immediate child sub-namespaces configured under ns.

Returns final path segments only, sorted and de-duplicated. The default returns none; overrides backed by a parameter tree must throw std::runtime_error on malformed content (a scalar or list where a dictionary is required).

Parameters:

ns – Namespace whose immediate child dictionaries should be listed.

Returns:

Sorted child names; empty when ns is absent or unconfigured.

PluginFactory() = default#
void reportIgnoredParams(const std::string &label, const std::vector<std::string> &supplied_keys, const Configurable::ParamMap &param_map) const#

Warn about, or in strict mode throw for, the supplied keys the setup never read.

Parameters:
  • label – Name used in the message, normally the plugin type.

  • supplied_keys – Keys the parameter source provided, captured before setup.

  • param_map – The map after setup, holding the consumed-key record.

inline void setStrictParams(bool strict)#

Choose how keys a setup never read are reported: a warning (default) or a throw.

Applies to every later createPlugin() and configure(). Reserved keys (“type”, “verbose_text”, “param_namespace”) and keys of a sub-namespace (“child/key”) are exempt.

Parameters:

strict – If true, an unread key throws std::runtime_error instead of warning.

virtual ~PluginFactory() = default#

Public Static Functions

static std::vector<std::string> paramKeys(const Configurable::ParamMap &map)#

The keys of map, in map order.

Protected Functions

virtual void printError(const std::string &message) = 0#

Print an error message through the framework’s logging mechanism.

Parameters:

message – The error message to display.

virtual void printVerbose(const Configurable::ParamMap &map) = 0#

Print the verbose configuration text accumulated in the parameter map.

Parameters:

map – Parameter map containing a “verbose_text” entry.

class PluginFactoryConfig : public open_apero::PluginFactory#
#include <open_apero_core/plugin/plugin_factory_config.h>

Concrete PluginFactory that serves parameters from an in-memory namespace -> {key: value} map, so no ROS parameter server is needed.

Namespaces are normalized on storage and lookup (one leading ‘/’, no trailing or duplicated slashes), so “/planner/map”, “planner/map/” and “//planner//map” are equivalent.

Public Functions

void clear()#

Forget all configured namespaces.

virtual bool getParamMapAndType(Configurable::ParamMap *map, std::string *type, std::string args) override#

Parse configuration arguments into a parameter map and resolve the plugin type.

Subclasses implement this to support different configuration sources (ROS params, files, etc.). Leave type untouched when the source configures no “type”: an empty result means “not configured”, which createPlugin reports as an error.

Besides the leaf keys, an implementation must set map[“param_namespace”] to the resolved namespace (Agent and Layer derive their children’s default namespaces from it) and map[“verbose_text”] to the header printVerbose() prints; both built-in factories do. Values must be strings Configurable::setParam() parses, e.g. a bool as “1”/”0”.

Parameters:
  • map – Output parameter map to populate.

  • type – Output string that receives the configured type name, if any.

  • args – Configuration arguments string.

Returns:

True on success. createPlugin() and configure() currently ignore it.

virtual std::vector<std::string> listChildNamespaces(const std::string &ns) override#

List the immediate child sub-namespaces configured under ns.

Returns final path segments only, sorted and de-duplicated. The default returns none; overrides backed by a parameter tree must throw std::runtime_error on malformed content (a scalar or list where a dictionary is required).

Parameters:

ns – Namespace whose immediate child dictionaries should be listed.

Returns:

Sorted child names; empty when ns is absent or unconfigured.

PluginFactoryConfig() = default#
void setParams(const std::string &ns, const Configurable::ParamMap &params)#

Install the leaf parameters for one namespace, replacing any existing entry.

Parameters:
  • ns – Namespace the parameters belong to (normalized on storage).

  • params – Leaf key -> value map (values are strings; “type” selects the plugin class). Values are parsed by Configurable::setParam(): write a bool as “1”/”0” (“true” throws) and a list as “a,b,c”.

~PluginFactoryConfig() override = default#
struct BoundingVolume : public open_apero::Configurable#
#include <open_apero_core/geometry/bounding_volume.h>

Axis-aligned bounding box with optional Z-rotation for constraining the planning space.

Not a factory-created plugin: owners (Evaluator, SimpleRobot) construct it directly and configure it via PluginFactory::configure(). Diagnostics go to an optional callback.

Public Types

using InfoLogger = std::function<void(const std::string&)>#

Callback used to surface human-readable setup diagnostics.

Public Functions

BoundingVolume() = default#
bool contains(const Eigen::Vector3d &point)#

Check whether a point lies inside the bounding volume.

Parameters:

point – The 3D point to test for containment.

Returns:

True if the bounding volume is set up and the point is inside it.

inline void setInfoLogger(InfoLogger info_logger)#

Install a callback for diagnostic messages (e.g. forwarding to the owning agent’s printInfo). Optional; unset means messages are dropped.

virtual void setupFromParamMap(Configurable::ParamMap *param_map) override#

Populate the bounding volume parameters from a parameter map.

Parameters:

param_map – Pointer to the parameter map containing volume extents and rotation.

void visualize(VisualizationMarkers *markers)#

Generate an orange world-frame wireframe for the bounding volume.

Parameters:

markers – Pointer to the marker collection to populate.

~BoundingVolume() override = default#

Public Members

bool is_setup = false#

Whether the bounding volume has been initialized.

double rotation#
Eigen::Quaterniond rotation_quat#

Quaternion representation of the Z-axis rotation.

double x_max#
double x_min#

Axis-aligned extents in meters and rotation around Z axis in degrees.

double y_max#
double y_min#
double z_max#
double z_min#

Seeded Randomness#

inline std::mt19937 open_apero::makeSeededEngine(int random_seed, std::string_view instance_ns)#

Build a Mersenne-Twister engine for one stochastic plugin instance.

With random_seed < 0 the engine is seeded nondeterministically. Otherwise the seed is derived from random_seed and instance_ns (FNV-1a), so runs reproduce and instances of one plugin type draw decorrelated streams.

struct SeededRng#
#include <open_apero_core/common/seeding.h>

A persistent per-plugin RNG that reproduces across episodes.

Hold one as a member of a stochastic plugin: call seed() once from setupFromParamMap (passing the plugin’s “param_namespace”) and reseed() from resetEpisode(), then draw from engine.

Public Functions

inline void reseed(int random_seed)#
inline void seed(int random_seed, const std::string &ns)#

Public Members

std::mt19937 engine#
std::string instance_ns#