Creating a new Service

Introduction

In this tutorial we shall see how to develop and run your own Service. Our example will show how to buld a HelloService which does nothing besides printing "Hello MeRMaID::support" every second.

Please make sure you have correctly installed MeRMaID::support .

Don't be afraid to do this because of the length of this tutorial: it is just very verbose in everything it tells you to do. ;-)

Getting the Dummy files

Copy the files from the dummy example to your working directory and rename the DummyService.[ch]pp and dummy-service-configuration-file.xml files to something more suited to the service you wish to develop.

The DummyService can be found in mermaid-support/Example/DummyService .

We will use HelloService as the service's name.

At this point you should have the following files in your working directory:

Changing HelloService.hpp .

Include guards

Open the HelloService.hpp file for editing. Change the include guards. It is recommended for the include guard to reflect the path of the include file within your project. For instance, if HelloService.hpp was inside components/helloService within your project's folder, then your include guard could be:

 #ifndef COMPONENTS_HELLOSERVICE_HELLOSERVICE_HPP
 #define COMPONENTS_HELLOSERVICE_HELLOSERVICE_HPP

 \/* ... rest of the header file ... *\/

 #endif // COMPONENTS_HELLOSERVICE_HELLOSERVICE_HPP

Namespace

Change the used namespace. We will also use the header file's path as a way to build the service's namespace. Therefore, we will have this class in the following namespace:

 namespace components
 {
      namespace helloservice
      {

      ... rest of class declaration ...

      }; //namespace helloservice
 }; //namespace components

Class name

Change the class name. Our chosen class name for this service is HelloService The class declaration should look like this:

 class HelloService : public Service
 {

Also change the class's constructor name (leave all of its parameters the same):

      HelloService(CountedPtr<ActiveObject> ao, CountedPtr<Entity> entity,
 CountedPtr<ServiceInstanceDescription> serviceInstanceDescription,
 CountedPtr<ServiceConfiguration> serviceConfiguration);

End result

Your HelloService.hpp file should look like this:

#ifndef COMPONENTS_HELLOSERVICE_HELLOSERVICE_HPP
#define COMPONENTS_HELLOSERVICE_HELLOSERVICE_HPP

#include <ActiveObject.hpp>
#include <CountedPtr.hpp>
#include <Entity.hpp>
#include <EntityDescription.hpp>
#include <ServiceConfiguration.hpp>
#include <Service.hpp>
#include <ServiceInstanceDescription.hpp>
#include <ServiceInterfaceDescription.hpp>
#include <ServiceReply.hpp>
#include <ServiceRequest.hpp>
#include <XmlDocument.hpp>

namespace components
{
    namespace helloservice
{

        using mermaid::support::activeobject::ActiveObject;
        using mermaid::support::memorymanagement::CountedPtr;
        using mermaid::support::service::Entity;
        using mermaid::support::service::EntityDescription;
        using mermaid::support::service::ServiceConfiguration;
        using mermaid::support::service::Service;
        using mermaid::support::service::ServiceInstanceDescription;
        using mermaid::support::service::ServiceReply;
        using mermaid::support::service::ServiceRequest;
        using mermaid::support::xml::XmlDocument;
    
        class HelloService : public Service
{
    public:
        
                HelloService(CountedPtr<ActiveObject> ao, CountedPtr<Entity> entity, CountedPtr<ServiceInstanceDescription> serviceInstanceDescription, CountedPtr<ServiceConfiguration> serviceConfiguration);
                
                virtual void initialize();
        
                virtual void update();
        
    private:
}; // class DummyService
}; // namespace helloservice
}; // namespace dummy


#endif // COMPONENTS_HELLOSERVICE_HELLOSERVICE_HPP

Changing HelloService.cpp .

Change include

Change the include statement to the new header file name:

    #include "HelloService.hpp"

Change namespace

Change the namespace to the one in which the class was declared:

    using namespace components::helloservice;

Change class name

Wherever DummyService appears, replace it with your class name (in this case HelloService )

Implement the desired Service behavior

We want our Service to print the message "Hello MeRMaID::support" every second. In order to do this, we will write the print code in the update() method. This method is called at a fixed frequency which is set in the Service's configuration file . Therefore the update() method should look like this: void HelloService::update() { std::cout << "Hello MeRMaID::support" << std::endl; }; // update

End result

Your HelloService.cpp file should look like this:

#include "HelloService.hpp"

#include <iostream>

using namespace components::helloservice;

HelloService::HelloService(CountedPtr<ActiveObject> ao, CountedPtr<Entity> entity, CountedPtr<ServiceInstanceDescription> serviceInstanceDescription, CountedPtr<ServiceConfiguration> serviceConfiguration) : Service(ao, entity, serviceInstanceDescription, serviceConfiguration)
{
    // nothing else should be done here
}; // HelloService()

void HelloService::initialize()
{
    std::cout << "HelloService::initialize()" << std::endl;
}; // initialize

void HelloService::update()
{
    std::cout << "Hello MeRMaID::support" << std::endl;
}; // update

Changing service-type-description-file.xml

This file is used to describe the type of service we're creating. This is kind of a description of the service's class itself. You give the service type a name (typically the same name as its class name) and write a small description for it. In our example the file looks like this:

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE service-type-description-list SYSTEM "service-type-description-list.dtd">
<service-type-description-list>
    <service-type-description>
        <name>HelloService</name>
        <comment>Service that prints a hello message.</comment>
    </service-type-description>
</service-type-description-list>

Changing entity-description-file.xml

This file describes the existing entities and which services are running in them. An entity is seen as a robot or a stand-alone computer (or an array of computers that, from a system point of view, can be seen as one unit). It is important to use one entity name per robot/computer since this information may be used by MeRMaID::support to do communication routing. Declaring several services as belonging to the same entity but having them spread troughout more than one robot/computer may have nasty consequences.

In our example, we intend to use the HelloService service on a stand-alone computer which we call "MyComputer". Besides the entity name, we have to declare names for each service instance we want to have in the system. Also, each service instance should be of a service type that has been previously specified in the service type description file. In our case, we want an instance of the HelloService service type which we will call "helloService". There should also be a comment stating what is each service instance intended to do.

Having all this defined for our example, the file should look like this:

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE entity-description-list SYSTEM "entity-description-list.dtd">
<entity-description-list>
    <entity>
        <name>MyComputer</name>
        <service>
            <instance-name>helloService</instance-name>
            <type-name>HelloService</type-name>
            <comment>HelloService instance</comment>
        </service>
    </entity>
</entity-description-list>

Changing deployment-configuration.xml

The deployment-configuration.xml is used to describe how services are to be deployed. This information is used by mlgen (MeRMaID Loader Generator) to automatically create executables that deploy services. This file has several parts that are described in the following subsections:

file-search-path

The file-search-path item specifies were should MeRMaID::support look for files (such as those xml files we just changed earlier). There should be at least two entries: MeRMaID::support's config directory and the directory containing the users configuration files. There can be as much file-search-path entries as needed. In this example case we will leave it with the default parameters:

<file-search-path>/opt/mermaid/config</file-search-path>
<file-search-path>./</file-search-path>

Description files

The following entries state the name for the three description files used by MeRMaID::support: data-description-file, service-type-description-file and entity-description-file. These values should be changed from the defaults in case you changed the names for the description files that were edited earlier. In our example, we'll stick with the defaults:

<data-description-file>data-description-file.xml</data-description-file>
<service-type-description-file>service-type-description-file.xml</service-type-description-file>
<entity-description-file>entity-description-file.xml</entity-description-file>

active-object

Here we declare all the ActiveObjects that are to be deployed. An ActiveObject is who actually runs the Service (in fact, ActiveObject's run Task's that are scheduled by Services, but those are details). An ActiveObject is a means by which to ensure mutual exclusion between "pieces of code". Typically, each Service runs in its own ActiveObject and execution of any of the Service's methods are guaranteed to not run concurently. If two Service's need to run in mutual exclusion they may be set to run inside the same ActiveObject, but be cautious with this solution since it may lead to a big performance penalty.

For our example, we only want to run one Service (for now) and it should run in its own ActiveObject. Therefore, we need to state the existence of an ActiveObject in which it will run. We will name it "helloActiveObject". This section will look like this:

<active-object>
    <active-object-name>helloActiveObject</active-object-name>
</active-object>

service

The service section declares a Service. There should be one service section for each Service that is intended to be deployed. The following information is needed for each Service (the correct values for this example is stated between parentheses :

End result

After all these changes, the deployment-configuration.xml file should look like this:

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE deployment-configuration SYSTEM "deployment-configuration.dtd">
<deployment-configuration>
  <file-search-path>/opt/mermaid/config</file-search-path>
  <file-search-path>./</file-search-path>
  <data-description-file>data-description-file.xml</data-description-file>
  <service-type-description-file>service-type-description-file.xml</service-type-description-file>
  <entity-description-file>entity-description-file.xml</entity-description-file>
  <active-object>
    <active-object-name>helloActiveObject</active-object-name>
  </active-object>
  <service>
    <header-file>HelloService.hpp</header-file>
    <namespace>components::helloservice</namespace>
    <class-name>HelloService</class-name>
    <entity-name>MyComputer</entity-name>
    <instance-name>helloService</instance-name>
    <configuration-file>hello-service-configuration-file.xml</configuration-file>
    <active-object-name>helloActiveObject</active-object-name>
  </service>
</deployment-configuration>

Changing hello-service-configuration-file.xml

In the configuration file we will specify how many times per second we want our Service 's update method to be called. This is defined in the update-frequency field. Since we want our Service to update once per second this field should have the value "1".

The configuration file should look like this:

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE service-configuration SYSTEM "service-configuration.dtd">
<service-configuration>
    <update-frequency>1</update-frequency>
</service-configuration>

Changing CMakeLists.txt

MeRMaID::support uses cmake ( www.cmake.org ) to generate Makefiles and to manage the build process. We recommend to use cmake for projects using MeRMaID::support too as it simplifies your life. As a last step in order to have the Service running, you should edit the CMakeLists.txt file to reflect the new name of our Service class. A name for the generated executable should also be chosen. Here, we'll name the executable as "runHelloService" . The CMakeLists.txt file should look like this:

FIND_PACKAGE(YARP)
FIND_PACKAGE(MERMAID)

MLGEN("deployment-configuration.xml" runHelloService.cpp)

ADD_EXECUTABLE(runHelloService runHelloService.cpp HelloService.cpp)

Building your service.

Since we use cmake , building the service is just a matter of:

cmake .
make

If you get complaints like these:

CMake Error: YARP_DIR is not set.  It must be set to the directory containing YARPConfig.cmake in order to use YARP.
CMake Error: MERMAID_DIR is not set.  It must be set to the directory containing MERMAIDConfig.cmake in order to use MERMAID.

You should set your YARP_DIR environment variable to point to where you have YARP and your MERMAID_DIR environment variable to where you installed MeRMaID::support (typically /opt/mermaid )

Running your service

In order to run your service you should first make sure that you have a YARP server running. If you don't have a yarp server running, you may start one yourself:

yarp server

After that, you just need to run the executable which has the name you set for the executable in the CMakeLists.txt file. In our case, the executable is named runDrivingJoystick so you should do the following:

./runHelloService

By running the service you should see some output written by YARP followed by:

HelloService::initialize()
Hello MeRMaID::support
Hello MeRMaID::support
Hello MeRMaID::support
Hello MeRMaID::support

The first line corresponds to the execution of the HelloService::initialize() method, and each of the repeating lines with "Hello MeRMaID::support" correspond to each execution of the HelloService::update() method. The rate at which this method is called is defined in the hello-service-configuration-file.xml

Full code

The full code for this tutorial is available in the HelloService example Service .

Generated on Fri Mar 4 22:15:37 2011 for MeRMaID::support by  doxygen 1.6.3