Пример 2. Операции
Если нужно не только передать какие данные, но и получить в ответ другие данные используются операции — аналог сервисов из ROS. Создаем два пакета-компонента. Первый будет отправлять данные второму.
$ cd ~/catkin_ws/src/
$ mkdir -p orocos_tests/example2
$ cd orocos_tests/example2
$ orocreate-catkin-pkg summer_client component
Using templates at /opt/ros/indigo/share/ocl/templates...
Package summer_client created in directory /home/ignat/catkin_ws/src/orocos_tests/example2/summer_client
$ orocreate-catkin-pkg summer_server component
Using templates at /opt/ros/indigo/share/ocl/templates...
Package summer_server created in directory /home/ignat/catkin_ws/src/orocos_tests/example2/summer_server
summer_client/src/summer_client-component.cpp
#include "summer_client-component.hpp"
#include <rtt/Component.hpp>
#include <iostream>
Summer_client::Summer_client(std::string const& name) :
TaskContext(name),
summer_caller("sum_two_doubles_caller")
{
this->requires()->addOperationCaller(summer_caller);
std::cout << "Summer_client constructed !" <<std::endl;
}
bool Summer_client::configureHook(){
std::cout << "Summer_client configured !" <<std::endl;
this->setPeriod(1);
return summer_caller.ready();
}
bool Summer_client::startHook(){
std::cout << "Summer_client started !" <<std::endl;
return true;
}
void Summer_client::updateHook(){
std::cout << "Summer_client executes updateHook !" <<std::endl;
double a = rand() % 100;
double b = rand() % 100;
log(Info)<<"summer_caller(" << a << ", " << b << ") = " << summer_caller.call(a,b) <<endlog();
}
void Summer_client::stopHook() {
std::cout << "Summer_client executes stopping !" <<std::endl;
}
void Summer_client::cleanupHook() {
std::cout << "Summer_client cleaning up !" <<std::endl;
}
ORO_CREATE_COMPONENT(Summer_client)
summer_client/src/summer_client-component.hpp
#ifndef OROCOS_SUMMER_CLIENT_COMPONENT_HPP
#define OROCOS_SUMMER_CLIENT_COMPONENT_HPP
#include <rtt/RTT.hpp>
using namespace RTT;
class Summer_client : public RTT::TaskContext{
protected:
OperationCaller<double(double,double)> summer_caller;
public:
Summer_client(std::string const& name);
bool configureHook();
bool startHook();
void updateHook();
void stopHook();
void cleanupHook();
};
#endif
summer_server/src/summer_server-component.cpp
#include "summer_server-component.hpp"
#include <rtt/Component.hpp>
#include <iostream>
Summer_server::Summer_server(std::string const& name) : TaskContext(name){
addOperation( "sum_two_doubles", &Summer_server::summer, this, OwnThread)
.doc("Sum two doubles")
.arg("Value A", "First value")
.arg("Value B", "Second value");
std::cout << "Summer_server constructed !" <<std::endl;
}
double Summer_server::summer(double a, double b) {
log(Info)<<"Summer_server::summer()"<<endlog();
return a+b;
}
bool Summer_server::configureHook(){
std::cout << "Summer_server configured !" <<std::endl;
return true;
}
bool Summer_server::startHook(){
std::cout << "Summer_server started !" <<std::endl;
return true;
}
void Summer_server::updateHook(){
std::cout << "Summer_server executes updateHook !" <<std::endl;
}
void Summer_server::stopHook() {
std::cout << "Summer_server executes stopping !" <<std::endl;
}
void Summer_server::cleanupHook() {
std::cout << "Summer_server cleaning up !" <<std::endl;
}
ORO_CREATE_COMPONENT(Summer_server)
summer_server/src/summer_server-component.hpp
#ifndef OROCOS_SUMMER_SERVER_COMPONENT_HPP
#define OROCOS_SUMMER_SERVER_COMPONENT_HPP
#include <rtt/RTT.hpp>
using namespace RTT;
class Summer_server : public RTT::TaskContext{
public:
Summer_server(std::string const& name);
double summer(double a, double b);
bool configureHook();
bool startHook();
void updateHook();
void stopHook();
void cleanupHook();
};
#endif
Создадим скрипты запуска и конфигурационные файлы. Примечание: Их можно создать в любом компоненте, или же создать отдельный компонент для конфигов и скриптов запуска. В данном примере мы создадим их в пакете summer_server.
mkdir -p summer_server/config summer_server/launch summer_server/scripts
summer_server/config/start.ops
# Импортируем оба компонента
import("summer_server");
import("summer_client");
# Данная функция выведет список импортированных компонентов
displayComponentTypes();
# Создадим экземпляры классов каждого компонента
loadComponent("summer_server", "Summer_server");
loadComponent("summer_client", "Summer_client");
# Соединим выходной и входной порты
connectPeers("summer_server", "summer_client")
connectOperations("summer_client.sum_two_doubles_caller", "summer_server.sum_two_doubles");
# Конфигурация
summer_server.configure()
summer_client.configure()
# Запуск
summer_server.start()
summer_client.start()
summer_server/launch/start.launch
<launch>
<node name="send_recv" pkg="rtt_ros" type="deployer" args="-s $(find summer_server)/config/start.ops --" output="screen">
</node>
</launch>
summer_server/scripts/start.sh
#!/bin/sh
BASEDIR=$(dirname "$0")
deployer-gnulinux -s $BASEDIR/../config/start.ops -linfo
$ chmod a+x summer_server/scripts/start.sh

Компилируем:
$ cd ~/catkin_make
$ catkin_make
Проверяем:
$ rosrun summer_server start.sh
или
$ roslaunch summer_server start.launch
В последнем случае будет запущено ядро ROS, хотя сами компоненты никак его не используют. Помимо прочего вывод должен содержать повторяющиеся строки:
Summer_client executes updateHook !
1.080 [ Info ][Logger] Summer_server::summer()
Summer_server executes updateHook !
1.080 [ Info ][Logger] summer_caller(83, 86) = 169
Summer_client executes updateHook !
2.080 [ Info ][Logger] Summer_server::summer()
Summer_server executes updateHook !
2.080 [ Info ][Logger] summer_caller(77, 15) = 92
...