First step
[MicoleLib documentation]

Collaboration diagram for First step:

The architecture is based on a software bus. All the commands, information are sent on the bus. When the system wants some information, it must find it on the bus. The goal is to be able to render the same information with different output devices. The visual and haptic rendering use the Reachin API. The VTPlayer rendering uses an API developped at the University of Metz and uses the libusb.

Basics

MicoleAgent

The system is divided in agents. An agent is a little program who has a simple task to do, for example: send the Phantom's coordinates on the bus, display an object on a Braille cell, etc. Each agent can send information on the bus, or add callback to execute a task when a message matching a given regular expression is sent on the bus.

Callbacks

The base architecture defines the AbstractMicoleApplication that allows to send a message on the Micole bus. The agents are managed with the MicoleAgent class. These objects binds callbacks with the bindMessage method. A binding uses a regular expression, and a callback. When a message on the bus matches the regular expression, the callback is called. The captured part on the regular expression are given to the callback with argv, though a callback declaration must be like :

void callbackExample(MicoleBus *app, int argc, const char **argv)

Example of binding :

class ExampleAgent: public MicoleAgent
{
  ExampleAgent() 
  {
     ...
     bindMessage("^(.*) quitting$", BUS_CALLBACK_OF(ExampleAgent, handleQuitMessage));
     ...
  }
  ...
};

...

void ExampleAgent::handleQuitMessage(MicoleBus *bus, int argc, const char **argv)
{
  /********
 Here code to quit application
   ********/
}

If you add "catch" parenthesis in regular expression, "caught" vars are in argv.

In this case, the regular expression "^(.*) quitting$" will catch all message that will finish by " quitting". In argv[0] you can get the catched message juste before " quitting". argc return number of vars "catched". This is usefull only if your parameters number is not fixed. If you are not familiar with regular expressions, I recommend you to see some documentations before going further.

MicoleAgentThread

See also:
MicoleAgentThread Some agents need their own thread because they work in parallel with the main program (coordinates SenderAgent agent for example). AgentsThreads are "threaded" version of Agents.
If you inherit MicoleAgentThread you can use two methods "start" and "run".

start(); //Start thread

This is a sample code of implementation of the run method in FF3DDeviceSenderAgent

void FF3DDeviceSenderAgent::run ()
{
        Vec3f p = Vec3f(0,0,0);
        MicoleStringStream s;
        while(getState()==ACTIVE)
        {
                p = _FF3DCoord->get();

                        s<< "IN FF3D : pos=(" << p.x << ", "<< p.y << ", " << p.z<<");";

                        if (_buttonPress->eventPressed())
                                s << " evt=PRESSED;";


                        if (_buttonPress->eventReleased())
                                s << " evt=RELEASED;";


                        sendMessage(s.str());
                }
                ::Sleep(_delay);
                s.flush();
        }
}

Your first program

LoggerAgent

The LoggerAgent catch all informations on the bus and write it in a log file. Learn how works the LoggerAgent is a good training course.

Declaration

We decide to create "MyLoggerAgent" a quite simple Logger agent class"

MyLoggerAggent.h

 #ifndef MYLOGGERAGENT_H
 #define MYLOGGERAGENT_H
 #include "micolelib.h"
 #include "MicoleAgent.h"
 #include <iostream>
 #include <fstream>
 using namespace std;

 class MyLoggerAgent: public MicoleAgent
 {
        public:
                MyLoggerAgent();
                virtual ~MyLoggerAgent();
                void handleAllMessage ( MicoleBus *app, int argc, const char **argv );
        private:
                ofstream _log; 
                FILE *_logFile;
 }; 

 #endif

This is a classic class definition.

You can notice the handleAllMessage function prototypes. This is a "bindable" method by MicoleBus. Return type is always void and you have 3 parameters. MicoleBus (we will not take a look on this for the moment), argc (number of arguments in argv), argv: all strings catched by a regular expression. If you want to create new "bindable" method, you MUST follow this prototype.

Your first bind

LoggerAggent bind "all information" on the bus with the regular expression "(.*)". Notice the catch parenthesis, all caracters will be put in first argument (argv[0]). All messages is logged in a log file.

#include "MyLoggerAgent.h"

MyLoggerAgent::MyLoggerAgent()
: MicoleAgent("MyLoggerAgent", "Logger")
{
        _log.open(s.str().c_str());
        bindMessage("(.*)", BUS_CALLBACK_OF(LoggerAgent, handleAllMessage));
}

MyLoggerAgent::~LoggerAgent()
{
        _log.close();
}

void MyLoggerAgent::handleAllMessage ( MicoleBus *app, int argc, const char **argv )
{
        _log <<  argv[0] << endl;
}

This example is pretty short and usefull to debug Micole messages system.

This class already exist in Micole Architecture his name is "LoggerAgent" and I recommend you to use it to monitor your applications.

If you want to filter specific message, you can, for example, catch only input message with "^IN (.*)" regular expression. Prefixes choice is important if you want to filter specific messages.

Time to play with haptic devices

Intialization of you first haptic devices

To receive ForceFeedBack 3D Devices (device configured in reachin) you just need to instanciate

FF3DDeviceSenderAgent sa = FF3DDeviceSenderAgent(16);

And each 16ms you receive device coordinate on the bus. FF3DDeviceSenderAgent messages is like that

IN FF3D : pos=(-1.330810785e-003, -8.182675362e-002, -4.387708664e-002); evt=RELEASED;

Use DeviceInputAgent Helpers

You don't need to "bind" FF3DDeviceSenderAgent messages if you inherit "FF3DDeviceInputAgent".

All *DeviceInputAgent are "helpers" and provide you an adapter to handle all "common" possibility of a device.

Each DeviceInputAgent has his own "method" to implement, following his own possibilites. FF3DDeviceInputAgent has virtuals methods onInput and onButtonPress and onButtonRelease. Methods names here are quite explicit.

More information in section Use haptic devices with MicoleLib

Initialize a DeviceOuputAgent

To give some order to a device, you need to Instanciate a DeviceOutputAgent.

FF3DDeviceOutputAgent oa;

After that, you need to send specific messages that corresponding devices can understand.

MicoleStringStream ss;
ss << "OUT FF3D : line=(("<<_grab.x<<", "<<_grab.y<<", "<<_grab.z<<"),("<<_position.x<<", "<<_position.y<<", "<<_position.z<<"));";
sendMessage(ss.getString().c_str());

This is an example of a recognized message. If you want all possible messages you can see it at section : Use haptic devices with MicoleLib

InputAgentExample

void InputAgentExample::onInput() {
        if (_recording) {
                _path.push_back(_position);
        }

        if (_replay) {

                Vec3f _diff = _magneticPoint - _position;
                if (_diff.length()<=0.025) {

                        if (_path.size() > 0) {
                                _magneticPoint = _path.front();
                                _path.pop_front();

                                MicoleStringStream s;
                                s << "OUT FF3D GUIDE : point=("<<_magneticPoint.x<<", "<<_magneticPoint.y<<", "<<_magneticPoint.z<<");";
                                FF3DDeviceInputAgent::sendMessage(s.str());
                        } else { //no more point in path
                                _replay = 0;
                                FF3DDeviceInputAgent::sendMessage("OUT FF3D GUIDE : none;");
                                FF3DDeviceInputAgent::sendMessage("OUT VTP : left=(0000000000000000);");
                                FF3DDeviceInputAgent::sendMessage("OUT VTP : right=(0000000000000000);");
                        }
                }
        }

}


Generated on Tue Oct 16 17:10:46 2007 for Micole by  doxygen 1.4.7