Rock

the Robot Construction Kit

Go to master Flavor stable
Advanced - Writing oroGen plugins

oroGen plugins offer ways to add new statements to the oroGen specification file, allowing to integrate some libraries in the component development workflow.

TODO: add links to the aggregator and transformer plugins

General principle

The general plugin design is based on the extensible nature of the Ruby language. How the plugin loading works is:

  • the OROGEN_PLUGIN_PATH environment variable contains directories in which plugin files (actually, ruby files) are.
  • these ruby files get loaded by oroGen at startup through the normal “require” mechanism
  • the code in the Ruby file should extend the toplevel classes (Project, Typekit, TaskContext, StaticDeployment) to add new functionality. Examples can be found at the bottom of this page.

This is the general principle. In practice, only the TaskContext class allows seamless integration as it is the only one that has an API for code generation.

Example of a very simple plugin:

module OrogenSimplePlugin
    def add_boolean_attribute(name)
        add_base_member("simple_plugin", name, "bool")
    end
end
Orocos::Generation::TaskContext.include OrogenSimplePlugin

If this plugin is present, the add_boolean_attribute method becomes available on task context definitions. Then, the generated Base class for these tasks will include a boolean attribute with the name given as parameter. Below, it would be “test”.

task_context "Task" do
    add_boolean_attribute "test"
end

Edit .orogen/tasks/TaskBase.hpp to see the new attribute.

Adding methods to task contexts

The add_base_method and add_user_method methods allow to add virtual methods to (respectively) the user-visible part of a task context and the Base class of the task context.

The syntax (simply replace add_base_method by add_user_method to have the same behaviour on the user-part of the task class)

add_base_method(return_type, name, signature)

This method call declares a pure virtual method (no body has been specified yet). To give a body, one has to call #body on the value returned by add_base_method:

add_base_method(return_type, name, signature).
    body(body_of_the_method)

Where the body is the method’s implementation without the toplevel block markers

For instance, the getModelName method that oroGen adds to every task context is defined with

add_base_method("std::string", "getModelName", "").
    body("return \"#{task_model.name}\";")

Adding attributes to the base class

add_base_member("kind", "attribute_name", "attribute_type")

Additionally, related code can be added to the initializer list, constructor and/or destructor:

add_base_member("kind", "attribute_name", "attribute_type").
    initializer("code_in_initializer_list").
    constructor("code_in_constructor").
    destructor("code_in_destructor")

+kind+ is a simple string that is only used for sorting the declarations. For instance the properties use “properties” as “kind” so that all properties get grouped together.

Adding code to the base class constructor and destructor

It is simply done with:

add_base_construction(kind, name, body)
add_base_destruction(kind, name, body)

+kind+ and +name+ will have no meaning. They will only be used for sorting the code snippets, so that the generated code always stays the same (avoiding unnecessary recompilations).

Adding code the hooks in the base class

It is done with

in_base_hook(hook_name, code)

For instance, oroGen clears all input ports in the base startHook() with

each_input_port do |port|
    in_base_hook('start', "_#{port.name}.clear();")
end

Adding code at the toplevel

Code can be added at the toplevel of the Base.hpp and Base.cpp files. Simply do

add_base_header_code(code, include_before)

Where include_before should be true if the code needs to be added before the Base class declaration and false if it should be after.

and

add_base_implementation_code(code, include_before)