Wiki

Clone wiki

robobo-programming / native / robobo-modules

Developing Robobo Modules

The Robobo Framework is a very light framework that follows a modular architecture where each functionality of the robot is implemented a new module, and where the framework is only in charge of loading and managing the modules.

To create a new module the developer must implement the IModule interface.

public interface IModule 
{
    public void startup(RoboboManager manager) throws InternalErrorException;

    public void shutdown() throws InternalErrorException;

    public String getModuleInfo();

    public String getModuleVersion();

}

The methods startup() and shutdown() are called at the beginning and the end of the framework lifecycle. getModuleInfo() and getModuleVersion() are used for debug purposes.

The common structure of a module is the following, using as example the note production module of the sound library.

Interface of the module

A interface extending IModule is defined with the public methods of the module:

public interface INoteGeneratorModule extends IModule {

    void suscribe(INotePlayListener listener);

    void unsuscribe(INotePlayListener listener);

    void playNote(Note note,int timems);

    void addNoteToSequence(Note note,int timems);

    void playSequence();

}

Module abstract class

An optional abstract class is created implementing the module interface that manages the listeners susbscription and notifications

public abstract class ANoteGeneratorModule implements INoteGeneratorModule {
    public HashSet<INotePlayListener> listeners;
    protected RoboboManager m;
    public ANoteGeneratorModule(){
        listeners = new HashSet<INotePlayListener>();
    }
    public void suscribe(INotePlayListener listener){
        listeners.add(listener);
    }
    public void unsuscribe(INotePlayListener listener){
        listeners.remove(listener);
    }

    /**
     * Notifies when a note ends
     */
    protected void notifyNotePlayEnd(){
        for (INotePlayListener listener:listeners){
            listener.onNotePlayEnd();
        }
    };

    /**
     * Notifies when a sequence of notes end
     */
    protected void notifySequenceEnd(){
        for (INotePlayListener listener:listeners){
            listener.onSequencePlayEnd();
        }
    };

}

Listener interface

Defines the interface that must be implemented for other classes to receive notifications of the module.

public interface INotePlayListener {

    public void onNotePlayEnd();

    public void onSequencePlayEnd();
}

Module implementation

In a package with the name of the implementation the class extending the abstract one is defined, implementing the rest of the methods of the module interface, also in this example you can see how an external remote control command is implemented, inside of the startup() method.

public class AndroidNoteGenerationModule extends ANoteGeneratorModule {

    private static final int MIN_DURATION = 50;
    private static final int MAX_DURATION = 5000;

    private String TAG = "NoteGeneratorModule";
    private LinkedList<SeqNote> sequence;
    private Timer timer;
    private TimerTask waitTask;
    private boolean playingNote;
    AudioTrack lasttone = null;

    @Override
    public void playNote(Note note, int timems) {
        ...
    }

    private void playNoteByIndex(int index, int timems){
        ...
    }

    @Override
    public void addNoteToSequence(Note note, int timems) {
        ...    
    }

    @Override
    public void playSequence() {
        ...
    }

    @Override
    public void startup(RoboboManager manager) throws InternalErrorException {
        sequence = new LinkedList<>();
        m = manager;
        timer = new Timer();

        m.getModuleInstance(IRemoteControlModule.class).registerCommand("PLAY-NOTE", new ICommandExecutor() {
            @Override
            public void executeCommand(Command c, IRemoteControlModule rcmodule) {
                playNoteByIndex(Integer.parseInt(c.getParameters().get("index"))-57,Integer.parseInt(c.getParameters().get("time")));
            }
        });
    }

    @Override
    public void shutdown() throws InternalErrorException {

    }

    @Override
    public String getModuleInfo() {
        return null;
    }

    @Override
    public String getModuleVersion() {
        return null;
    }

    //region AudioGeneration

    private AudioTrack generateTone(double freqHz, int durationMs)
    {
        ...
    }


    private double noteToFreq(Note note){
        ...

    }

    private double indexToFreq(int index){
        ...

    }
    //endregion

    //region SequenceManager

    private class SeqNote{
        ...
    }

    private class WaitTask extends TimerTask {
        ...
    }

    //endregion
}

Updated