Skip to content

Latest commit

 

History

History
234 lines (176 loc) · 7.02 KB

hello_4.rst

File metadata and controls

234 lines (176 loc) · 7.02 KB

Hello world 4 - RTT Tutorial: Operations

The source code of this tutorial can be found in the GitHub repository.

In this tutorial we will introduce you to operations and how they expose functions so they can be used in scripting and by other processes. To illustrate this two components will be created in HelloWorld.cpp. It is advised to read operation-interface before starting this tutorial.

Contents of HelloWorld.cpp:

#include <rtt/Logger.hpp>
#include <rtt/TaskContext.hpp>

/**
* Include this header in order to call component operations.
*/
#include <rtt/OperationCaller.hpp>
#include <rtt/Component.hpp>

using namespace std;
using namespace RTT;

namespace Example
{

    /**
    * Every component inherits from the 'TaskContext' class.  This base
    * class allow a user to add a primitive to the interface and contain
    * an ExecutionEngine which executes application code.
    */
    class Hello
        : public TaskContext
    {
    protected:

        /**
        * Returns a string.
        */
        string getMessage() {
            return "Hello World";
        }

    public:
        /**
        * This example sets the interface up in the Constructor
        * of the component.
        */
        Hello(std::string name)
            : TaskContext(name)
        {
            this->addOperation("getMessage", &Hello::getMessage, this).doc("Returns a friendly word.");
        }

    };

    /**
    * World is the component that shows how to call an Operation
    * of the Hello component in C++.
    */
    class World
      : public TaskContext
    {
    protected:
      /**
      * This OperationCaller serves to store the
      * call to the Hello component's Operation.
      * It is best practice to have this object as
      * a member variable of your class.
      */
      OperationCaller< string(void) > getMessage;


    public:
      World(std::string name)
    : TaskContext(name, PreOperational)
      {
      }

      bool configureHook()
      {
          // Lookup the Hello component.
          TaskContext* peer = this->getPeer("hello");
          if ( !peer ) {
            log(Error) << "Could not find Hello component!"<<endlog();
            return false;
          }

          // It is best practice to lookup methods of peers in
          // your configureHook.
          getMessage = peer->getOperation("getmessage");
          if ( !getMessage.ready() ) {
            log(Error) << "Could not find Hello.getMessage Operation!"<<endlog();
            return false;
          }
          return true;
      }

      void updateHook() {
        log(Info) << "Receiving from 'hello': " << getMessage() <<endlog();
      }
    };
}

ORO_CREATE_COMPONENT_LIBRARY()
ORO_LIST_COMPONENT_TYPE( Example::Hello )
ORO_LIST_COMPONENT_TYPE( Example::World )

Tutorial 4

Note

This tutorial assumes that you have installed Orocos through the pre-compiled packages distributed via ROS in Ubuntu. If you don't have it installed, try following the instructions from installation-options.

Creating an Operation

In our example the Hello component provides an operation, the operation is just a function which returns a string "Hello World". Adding the operation can be done with the addOperation method:

this->addOperation("getMessage", &Hello::getMessage, this).doc("Returns a friendly word.");

Calling an Operation

From the deployer

Start the Orocos deployer (deployer-gnulinux -lInfo), and create the Hello component:

import("hello_4_operations")

loadComponent("hello", "Example::Hello")

// Print the interface of the hello component, the new "getMessage" operation should now be listed.
ls hello

Calling the operation is then as simple as:

hello.getMessage()

Using the OperationCaller

Components can call operations of other components using an instance of OperationCaller. It is considered best practice to have this OperationCaller as a member of your class. The OperationCaller needs to be templated with the signature of the operation you wish to call. In the above example we wish to call string getMessage(), so our OperationCaller looks like this: OperationCaller<string(void)>. In order to be able to call operations of other components, the components must first be connected using connectPeers in the Orocos deployer:

import("hello_4_operations")

loadComponent("hello","Example::Hello")
loadComponent("world","Example::World")

connectPeers("hello","world")

The component that wants to call the operation of the other component first needs to look up the peer using this->getPeer("hello"), and retrieve the operation it wishes to call using peer->getOperation("getmessage"). All this is preferable done in the configureHook method:

bool configureHook()
{
    // Lookup the Hello component.
    TaskContext* peer = this->getPeer("hello");
    if ( !peer ) {
      log(Error) << "Could not find Hello component!"<<endlog();
      return false;
    }

    // It is best practice to lookup methods of peers in
    // your configureHook.
    getMessage = peer->getOperation("getmessage");
    if ( !getMessage.ready() ) {
      log(Error) << "Could not find Hello.getMessage Operation!"<<endlog();
      return false;
    }
}

The operation can then be called using the OperationCaller getMessage, for example in the updateHook:

void updateHook()
{
  log(Info) << "Receiving from 'hello': " << getMessage() <<endlog();
}