コンポーネント間を接続するプログラム

ここでは2つのデータポートを持つコンポーネントを接続するためのプログラムについて紹介します.

ここでは前節で作ったConsoleInコンポーネントとConsoleOutコンポーネントを接続してみましょう.

プロジェクトの追加

PeriodicConsoleOutコンポーネントを作成するためのプロジェクトに,あらたにComponentConnectorという空のWin32プロジェクトを追加します.

次に,プロジェクトのプロパティの変更が必要です.このあたりはComponentActivatorの章で行った操作と同じです.

プログラム

次にプロジェクトにCPPファイルを追加します.ここではファイル名はComponentConnector.cppとしましょう.

プログラムの流れは,

  1. CORBAオブジェクトを作成して,ネームサーバーを取得.
  2. ネームサーバーから起動しているコンポーネントの中からConsoleInコンポーネントのインスタンスを取得.同時に入力データポートを取得.コンポーネントをアクティブ化.
  3. ネームサーバーから起動しているコンポーネントの中からConsoleOutコンポーネントのインスタンスを取得.同時に出力データポートを取得.コンポーネントのアクティブ化.
  4. ConnectorProfileオブジェクトを利用して,これから生成する接続のプロファイルを設定しています.
  5. connector0による接続.
  6. CORBAオブジェクトを破棄.

となります.一応,ComponentConnectorcppファイルの中身すべては以下の通りです.

#include <iostream>
#include <vector>
#include <string>
#include <rtm/CorbaNaming.h>
#include <rtm/RTObject.h>
#include <rtm/NVUtil.h>
#include <rtm/CORBA_SeqUtil.h>
#include <rtm/CorbaConsumer.h>
#include <assert.h>




using namespace RTC;

int main (int argc, char** argv)
{
  CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
  CorbaNaming naming(orb, "localhost:2809");

  CorbaConsumer<RTObject> consoleIn0, consoleOut0;
  PortList_var portIn;
  PortList_var portOut;

  consoleIn0.setObject(naming.resolve("ConsoleIn0.rtc"));
  portIn = consoleIn0->get_ports();
  portIn[0]->disconnect_all();
  assert(portIn->length() > 0);
  ExecutionContextServiceList_var eclisti;
  eclisti = consoleIn0->get_execution_context_services();
  eclisti[0]->activate_component(RTObject::_duplicate(consoleIn0._ptr()));

  consoleOut0.setObject(naming.resolve("ConsoleOut0.rtc"));
  portOut = consoleOut0->get_ports();
  portOut[0]->disconnect_all();
  assert(portOut->length() > 0);
  ExecutionContextServiceList_var eclisto;
  eclisto = consoleOut0->get_execution_context_services();
  eclisto[0]->activate_component(RTObject::_duplicate(consoleOut0._ptr()));


  ConnectorProfile prof;
  prof.connector_id = "";
  prof.name = CORBA::string_dup("connector0");
  prof.ports.length(2);
  prof.ports[0] = portIn[0];
  prof.ports[1] = portOut[0];
  CORBA_SeqUtil::push_back(prof.properties,
  NVUtil::newNV("dataport.interface_type", "CORBA_Any"));
  CORBA_SeqUtil::push_back(prof.properties, NVUtil::newNV("dataport.dataflow_type", "Push"));
  CORBA_SeqUtil::push_back(prof.properties, NVUtil::newNV("dataport.subscription_type", "New"));

  ReturnCode_t ret;
  ret = portIn[0]->connect(prof);
  assert(ret == RTC::RTC_OK);

  std::cout << "Connector ID: " << prof.connector_id << std::endl;
  NVUtil::dump(prof.properties);

  orb->destroy();
  exit(1);
}

コンパイルするとたくさんwarningが出ます.何でなのかは今検討中.でもコンパイルは出来ます.

rtc.confの設定

実行前にrtc.confファイルの変更が必要です.今回もnamingサービスの設定が必要になります.コンポーネントをネームサーバーから検索するときにコンポーネントの名前を使うので,この設定は絶対必要です.気をつけましょう.

RTCがネームサーバーに登録される際の名前付けの規則を変更します.新しいrtc.confに"naming.formats: %n.rtc"の行を追加します.これによって,ConsoleOutコンポーネントが作成された場合,名前はConsoleOut0.rtcとなります.同様にConsoleInの場合はConsoleIn0.rtcになります.

この名前を使って,ネームサーバーからインスタンスを検索&取得するのです.

実行

ネームサーバーを起動してから,ConsoleOutコンポーネントとConsoleInコンポーネントを起動してください.RtcLinkを使っているなら,ネームサーバーにConsoleOut0.rtcとConsoleIn0.rtcというコンポーネントが登録されいてることがわかるでしょう.

次に,ComponentConnectorを実行すると,ConsoleIn0コンソールに"input number"文字列が出力されます.ここで数字を入力してEnterを押すと,ConsoleOut0のコンソールに入力した数字が出力されますので,二つのコンポーネントが接続されたことが確認できます.

まとめ

いかがでしたか?簡単でしょ?

今回作成したファイル:ComponentConnector.zip (ver. 0.4.1対応)

ComponentConnector042.zip (ver. 0.4.2対応)

ここまででRTミドルウェアのプログラミングの一連の流れが分かったといえます.次は単純なINT型のデータの受け渡しを超えて,画像や文字列などの大きく,洗練されたデータの流れを作る方法をやりましょう♪


RTミドルウェア入門