RTCを接続するソフトウエアの開発


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

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

バージョン1.0になって,この辺のツール類のプログラムが様変わりしています.細かい変更です…

プログラムの流れは,

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

となります.

プロジェクトの追加

あらたにRTCConnectorというWin32コンソールプロジェクトを追加します.

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

プログラム

とりあえずこれまでと同様にプリコンパイルヘッダーにRTC系のヘッダーを集めちゃいます.このほうが再コンパイルが早いので.

// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または
// 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル
// を記述します。
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

#include <iostream>
#include <rtm/CorbaNaming.h>
#include <rtm/RTObject.h>
#include <rtm/CorbaConsumer.h>
#include <assert.h>

次にプロジェクトにCPPファイルを編集します.RTCConnector.cppがありますよね.
一応,RTCConnector.cppファイルの中身すべては以下の通りです.

// RTCConnector.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"

int main(int argc, char* argv[])
{
	// ORBを取得
	CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
	RTC::CorbaNaming naming(orb, "localhost:2809");

	// それぞれのコンポーネントを取得
	RTC::CorbaConsumer consoleIn0, consoleOut0;
	consoleIn0.setObject(naming.resolve("ConsoleIn0.rtc"));
	consoleOut0.setObject(naming.resolve("ConsoleOut0.rtc"));

	// それぞれのコンポーネントからポートのリストを取得
	RTC::PortServiceList *portIn, *portOut;
	portIn = consoleIn0->get_ports();
	portOut = consoleOut0->get_ports();
	assert(portIn->length() > 0);
	assert(portOut->length() > 0);

	// とりあえず全部切断
	(*portIn)[0]->disconnect_all();
	(*portOut)[0]->disconnect_all();

	// 接続のためのコネクションプロファイルを作成
	RTC::ConnectorProfile prof;
	prof.connector_id = "cn0";
	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_cdr"));
	CORBA_SeqUtil::push_back(prof.properties,
		   NVUtil::newNV("dataport.dataflow_type",
				 "push"));
	CORBA_SeqUtil::push_back(prof.properties,
		   NVUtil::newNV("dataport.subscription_type",
				 "new"));

	// 接続を確立
	RTC::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);
        //Console**コンポーネントのインスタンスをアクティブ化
        RTC::ExecutionContextList_var ExecutionContextListOut = consoleOut0->get_owned_contexts();
	ExecutionContextListOut[0]->activate_component(RTC::RTObject::_duplicate(consoleOut0._ptr()));
	RTC::ExecutionContextList_var ExecutionContextListIn = consoleIn0->get_owned_contexts();
	ExecutionContextListIn[0]->activate_component(RTC::RTObject::_duplicate(consoleIn0._ptr()));

	orb->destroy();
	return 0;
}
Pythonの場合はビルド環境の設定などは必要なく,下記のコードを実行するだけでオーケーです.
コードは長いように見えて,重なってる部分が多いので,実はもっと簡単に出来ますが,いちおう,サンプルということで.

#!/usr/bin/env python                                                                                                                                                  
# -*- coding: utf-8 -*-                                                                                                                                                
# -*- Python -*-                                                                                                                                                       
 
"""                                                                                                                                                                    
 @file RTCConnect.py                                                                                                                                                  
 @brief ModuleDescription                                                                                                                                              
 @date $Date$                                                                                                                                                          
 
 
"""
import sys
import time
sys.path.append(".")
 
# Import RTM module                                                                                                                                                    
import RTC
import OpenRTM_aist
import omniORB
import CORBA
 
def main():
                print ' - Connecting ', selfAddr, ' ServicePort to ', addr
 
                clientAddr = 'ConsoleOut0.rtc'
                clientPortName = 'in'
                hostAddr   = 'ConsoleIn0.rtc'
                hostPortName   = 'out'
 
                corbaNaming = OpenRTM_aist.CorbaNaming(OpenRTM_aist.Manager.instance().getORB(), "localhost:2809")
 
                clientObj = corbaNaming.resolve(clientAddr)
                if CORBA.is_nil(clientObj):
                        sys.stdout.write(' -- Failed to connect %s' % clientAddr)
                        return
 
                client = OpenRTM_aist.CorbaConsumer()
                client.setObject(clientObj)
                clientPorts = client._ptr().get_ports()
                clientPort = None
                for p in clientPorts:
                        if p.get_port_profile().name.split('.')[1] == clientPortName: # ver1.1からはポート名が ConsoleIn0.out のようになってる.
                                clientPort = p
 
                if not clientPort:
                        sys.stdout.write(' -- Failed to find port %s' % clientPort)
 
                hostObj = corbaNaming.resolve(hostAddr)
                if CORBA.is_nil(hostObj):
                        sys.stdout.write(' -- Failed to connect %s' % clientAddr)
                        return
 
		host = OpenRTM_aist.CorbaConsumer()
                host.setObject(hostObj)
                hostPorts = host._ptr().get_ports()
		hostPort = None
                for p in hostPorts:
                        if p.get_port_profile().name.split('.')[1] == hostPortName: # ver1.1からはポート名が ConsoleIn0.out のようになってる.
				hostPort = p
 
                if not hostPort:
                        sys.stdout.write(' -- Failed to find port %s' % hostPort)
			return
 
                name = clientPortName + '_to_' + hostPortName
		connector_id = name
                ports = [hostPort, clientPort]
                properties = []
		prof = RTC.ConnectorProfile(name, connector_id, ports, properties)
 
                ret = hostPort.connect(prof)
 
if __name__ == "__main__":
        main()

rtc.confの設定

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

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

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

実行

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

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

まとめ

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

RTCConnector.zip

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