これからRTコンポーネントの作成方法について解説します。自分のロボットを作ためには、RTコンポーネント作成しなくてはなりません。この作業自体はインストールが出来ていれば実は超かんたんです.
概要
RTコンポーネントを作成する手順としては、
- RTC Builderでスケルトンコードを生成する
- CMakeでプラットフォームに特有なプロジェクトファイルやらMakefileやらを生成する
- スケルトンコードを編集する
- ビルドして実行する
という感じです。
スケルトンコードを生成する時点で殆どの手間が省かれちゃいますので、特定の関数(イベントハンドラ)を編集するのが作業の中心です。
スケルトンコードの生成
まず,骨格(スケルトン)となるソースコードを作ります.これにはEclipseを使います.というのもRTCのプログラムコードのテンプレートを作成してくれるツール,RTC BuilderをEclipseで使うのが正解.またeclipseはRTCの起動状態をRT System Editorというツールを使って操作するときにも使うので,しばらくは起動しっぱなしだと思います.
Eclipse(RTツール全部入り)のインストールについては,RTMインストール編を参考にすると良いでしょう.
RTC Builder
まず,Eclipse(ツール全部入り)を起動します.
メニューの「Window(ウィンドウ)」>「Perspective(パースペクティブ)」を選択し,「RTC Builder」を選択します.これでRTC Builderが使える状態です.
File(ファイル)から,「Open new Builder Editor」を選びます.
図のようなダイアログが出るので,プロジェクト名を入力します.これはRTコンポーネントの名前とは違いますが,同じにしても問題は無いようです.わかりやすい名前を設定してあげてください.
図のようなエディタが起動します.画面下部のタブを変更しながら,順番に設定していって,最後にBasicタブの「Generate」ボタンを選択することで,プログラムのテンプレートを作成します.
まずは超かんたんなコンポーネントを作ってみましょう.
PERIODICなコンポーネントの作成
RTC Builderのコンフィグ
ただ単純にコンソールに文字を出力するだけのプログラムを作成してみましょう.
基本的に下図のタブを選択しながら大まかなカテゴリごとに設定を勧めます.
以下のように設定して下さい.ほかの部分には何も記入しないで下さい.
タブ | 変数 | 設定値 |
Basic | Module name | Practice1 |
Module description | Periodic Console Out Component | |
Module version | 1.0 | |
Module vender | あなたの名前(半角英数字で) | |
Module category | すきなカテゴリ名(とりあえずTest) | |
Activity | onActivated | チェックボックスをONに |
onDeactivated | チェックボックスをONに | |
onExecute | チェックボックスをONに | |
言語・環境 | 言語 | C++ / Java / Python |
各パラメータの説明(読み飛ばしても出来る!)
- 基本タグ
- Module name・・・コンポーネントの名前.スペースを含まない方がいい.
- Module description・・・コンポーネントの説明.
- Module version・・・コンポーネントのバージョン.最初は低めで・・・
- Module vendor・・・コンポーネントのベンダー.あなたの名前を書きましょう.これであなたもRTCベンダーの仲間入り.
- Module category・・・とりあえずExampleとしておきます.複数のRTCを作るようになれば,これを使って管理する必要が出てくるかもしれませんが,個人でやるレベルでは必要ないと思います.
- Component type・・・STATIC,UNIQUE,COMMUNICATIVEの3種類がありますが,まだ対応していないようです.
- Component’s activity type・・・PERIODIC,SPORADIC,EVENT_DRIVENがありますが,PERIODICしか対応していません.
- Component Kind・・・「Data Flow」「FSM」「Multimode」の3種類があります.RTコンポーネントの仕様で,3つのコンポーネントの種類が定義されていますが,OpenRTM-aistではまだData Flowコンポーネントのみの対応です.
- Number of maximum instance・・・コンポーネントの同時生成可能数
- Execution type・・・実行コンテキストのタイプです.実行コンテキストによって,イベントハンドラ「on_execute」の実行タイミングの制御方式が変わります.PeriodicExecutionContext(周期実行)とExtTrigExecutionContext(外部トリガによる実行)があります.通常はPeriodicExecutionContextを選びます.
- Execution rate・・・実行周期です.単位はHz.
- Abstract・・・コンポーネントの説明.
- RTC type・・・RTCのタイプ.PERIODICとか.不要.
- アクティビティ
- onActivated・・・RTCをアクティブ化したときに実行されるイベントハンドラ.
- onDeactivated・・・RTCをインアクティブに変更した時に実行されるイベントハンドラ.
- onExecute・・・PERIODIC実行の場合,周期的に実行されるイベントハンドラ.
- 言語・環境
- 言語・・・OpenRTM-aistでは,C++,Java,Python,.Netに対応しています.Rubyにも対応予定?
生成
ここで「Basic」タブに戻り,「Generate」というボタンを押すと「Generate success」というメッセージが出て,ワークスペースにコンポーネントのテンプレートが生成されています.
言語ごとの開発
タブを選んでください.
生成されたファイルを確認するときは,ワークスペースとして設定したフォルダに移動します.「ファイル>ワークスペースの切り替え」と選択すれば,ワークスペースになっているフォルダを確認できると思います.
生成されたファイルは以下の通りです(ここも読み飛ばしていいよ).
- .project ・・・Eclipseのプロジェクトファイル.
- CMakeLists.txt・・・CMake用の設定ファイル.ここにVisual C++やUnix用Makefileを生成するための設定が書かれている
- cmake(フォルダ)・・・CMake用の設定ファイルが書かれている
- Practice1.conf・・・コンフィグレーションパラメータ.今回は不要.
- src
- CMakeLists.txt・・・srcフォルダ内のファイルのコンパイルの設定
- Practice1.cpp・・・コンポーネント本体.
- Practice1Comp.cpp・・・コンポーネント本体.
- include・・・インクルードファイル用フォルダ
- Practice1・・・コンポーネントのヘッダーファイルを格納するためのフォルダ
- Practice1.h・・・コンポーネントのヘッダーファイル
- Practice1・・・コンポーネントのヘッダーファイルを格納するためのフォルダ
- README.PeriodicCOnsoleOut・・・READMEファイル.
- rtc.conf・・・コンフィグ.後述.
- RTC.xml・・・RTC Builderの設定を保存したXMLファイル.RTCProfile形式.
CMake
CMake-GUIで
CMakeを使ってVisual C++用のソリューションを作成します.
スタートメニューからCMake2.8を起動します.「CMake (cmake-gui)」とあるCMakeを起動します.Unix系OSならばcmake-guiというコマンドで起動します.
エクスプローラでワークスペースのフォルダに移動し,CMakeのウィンドウにプロジェクトのトップディレクトリのCMakeLists.txtをドラッグ&ドロップします.
「Where is the source code」にはCMakeLists.txtファイルがあるディレクトリが入力され,「Where to build the binaries」のエディットボックスにも同じディレクトリが書かれています.
後者は出力先のディレクトリになるのですが,このままだと出力されたファイルがソースコードと同じディレクトリに展開されて,自動生成されたファイルとの区別がつきづらくなってしまいます.そこで,後者のディレクトリに「・・・Practice1/build」という具合に,buildという記述を加えます.これによりbuildディレクトリを作成して,その中に生成ファイルを展開します.
ここで,「Configure」ボタンをクリックします.「Configured」と表示されたら成功.
さらに「Generate」で必要なファイルがbuildの中に生成されます.
コマンドラインで
Windowsでもコマンドプロンプトからcmakeすることができます.cmake.exeがインストールされているフォルダを環境変数PATHに追加するだけです.
たとえば,C:\Program Files (x86)\CMake 2.8\binなどです.
まず,プロジェクトのディレクトリに移動 (cd) し,buildディレクトリを作成して,その中に移動します.
次に,cmakeコマンドを実行しますが,引数として,CMakeLists.txtが存在するディレクトリを指定します.buildディレクトリのすぐ上のディレクトリですから,「 .. 」とすればいいだけです.これでGUIと同じ処理をしたことになります.
cd ~/workspace/Practice1/ mkdir build cd build cmake ../
VC++2010による編集
さて,ここからVC++2010で開発をします.buildフォルダを開き,「Practice1.sln」を開きます.
Practice1とPratice1CompというのがRTCの本体のプロジェクトです.**CompはRTCを単体で実行するためのexeファイルを生成します.Practice1はRTCであるDLLを生成します.DLLを使ってRTCを実行する方法については別の機会に説明します.
どちらも同じPractice1.h,Practice1.cppを参照しています.
Practice1.cppを編集してRTCに望みの機能を実装していきます.
結論から言うと,
onActivated関数とonDeactivated関数に文字表示を,
onExecute関数に,コンソールに周期的に出力するコードを記入します.
先ほど使ったRTCBuilderで設定するアクティビティのタブでonExecuteのチェックボックスをonにしておくと,onExecute関数のコメントアウトが自動的に外れています.手動でこのコメントをはずすことも可能ですが,後に説明するRTCプロファイル(RTC.xml)という,RTC Builderの設定を保存しているファイルとの整合性が取れなくなります.今のところあまりデメリットはありませんが・・・
/*
RTC::ReturnCode_t PeriodicConsoleOut::onActivated(RTC::UniqueId ec_id)
{
std::cout << "onActivated Called." << std::endl;
return RTC::RTC_OK;
}
RTC::ReturnCode_t PeriodicConsoleOut::onDeactivated(RTC::UniqueId ec_id)
{
std::cout << "onDeactivated Called." << std::endl;
return RTC::RTC_OK;
}
RTC::ReturnCode_t PeriodicConsoleOut::onExecute(RTC::UniqueId ec_id) {
std::cout << "onExecute Called." << std::endl;
return RTC::RTC_OK;
}
/*
RTC::ReturnCode_t PeriodicConsoleOut::onAborting(RTC::UniqueId ec_id)
{
return RTC::RTC_OK;
}
*/ |
Unix系の場合
コマンドラインからcmakeでMakefileを生成して,buildディレクトリにMakefileがあるので,buildディレクトリに入ってmakeコマンドで実行します.
たとえば,下記のようなコマンドでビルドして実行できます.詳細は省きます.CMakeの使い方を調べてみて下さい.
$ cd ~/workspace/Practice1/ $ mkdir build $ cd build $ cmake ../ $ make $ cd src $ ./Practice1
Java言語を選択すると,自動的にJavaパースペクティブに移行してます.
生成されたプロジェクトのsrcフォルダにプロジェクトの生成物が表示されます.
- src
- (デフォルトパッケージ)
- PeriodicConsoleOut.java
- PeriodicConsoleOutComp.java
- PeriodicConsoleOutImpl.java
- (デフォルトパッケージ)
- build_PeriodicConsoleOut.xml
- PeriodicConsoleOut.conf
- rtc.conf
- RTC.xml
さて,生成されたファイルがたくさんありますが,変更するのは基本的に**Impl.javaファイルです.
しかし,最初はImplファイルがビルドできないことに気づくと思います.
OpenRTM-aistのJarファイルがインポート出来ていないからです.
これにはインストールのときに設定したユーザーライブラリーを使います.
プロジェクトのプロパティーを開き,「ビルドパス」を選択します.
さらに「ライブラリー」のタブをクリックして,「ライブラリーの追加」を選択します.
ここで「ユーザーライブラリー」を選択し,インストールのときに設定した「OpenRTM-aist」を選択しましょう.
ここで選択後にOKを押していくと,なぜかjavaファイルがsrcフォルダの外に出てしまいます.
マジふざけんな,と思いますが,ここはぐっとこらえてjavaファイルの3つをsrcフォルダにやさしく戻してあげます.
また,プロジェクトを右クリックして追加することも出来ますが,なぜかJREのデフォルトのライブラリーがインポート出来ない場合があるので,上記の手順なら確実です.
まだ×印が付いている場合は,プロジェクトを右クリックして「プロジェクトのビルド」を選択するとビルド出来ると思います.
さて,「*.impl」ファイルの中にonExecuteという関数があります.この中身を書きかえると,RTCがActive状態であれば,
設定した周期ごとにonExecute関数が呼ばれるってスンポーです.
// @Override // protected ReturnCode_t onDeactivated(int ec_id) { // return super.onDeactivated(ec_id); // } /*** * * The execution action that is invoked periodically * former rtc_active_do() * * @param ec_id target ExecutionContext Id * * @return RTC::ReturnCode_t * * */ @Override protected ReturnCode_t onExecute(int ec_id) { System.out.println("Hello RT-Component!"); return super.onExecute(ec_id); } /*** * * The aborting action when main logic error occurred. * former rtc_aborting_entry() * * @param ec_id target ExecutionContext Id * * @return RTC::ReturnCode_t * * */ // @Override // public ReturnCode_t onAborting(int ec_id) { // return super.onAborting(ec_id); // } |
言語をPythonで生成すると,PyDevがインストールされていれば,Pythonパースペクティブに移動して,Eclipseでそのまま開発が出来ます.
生成されたファイルは,
- .project・・・プロジェクトの設定
- .pydevproject・・・Pythonの設定
- PeriodicConsoleOut.conf・・・RTCの個別設定用ファイル
- PeriodicConsoleOut.py・・・RTCのソースコード本体
- rtc.conf・・・一般的なRTCの設定ファイル
- RTC.xml・・・RTC Builderへの設定ファイル.RTCプロファイルと呼ばれる
コードとしてはPeriodicConsoleOut.pyというファイルのみです.あとは後述しますが,rtc.confとPeriodicConsoleOut.confというコンフィグファイルが変更の対象です.
とりあえず,PeriodicConsoleOut.pyを開きます.
思いっきり割愛しながら書くと,コードはこんな感じ.
import sys import time sys.path.append(".") import RTC import OpenRTM_aist periodicconsoleout_spec = ["implementation_id", "PeriodicConsoleOut", "type_name", "PeriodicConsoleOut", "description", "Periodic Console Out", "version", "1.0.0", "vendor", "ysuga.net", "category", "Test", "activity_type", "STATIC", "max_instance", "1", "language", "Python", "lang_type", "SCRIPT", ""] class PeriodicConsoleOut(OpenRTM_aist.DataFlowComponentBase): # 思い切り中略! def onExecute(self, ec_id): """ The execution action that is invoked periodically former rtc_active_do() \param ec_id target ExecutionContext Id \return RTC::ReturnCode_t """ return RTC.RTC_OK |
つまり,PeriodicConsoleOutというクラスのonExecute関数のみを見てればいいです.最初はこれだけ.
この関数が周期的に実行されるので,そこに処理を書きます.たとえば,
def onExecute(self, ec_id): print "Hello RT-Component!" return RTC.RTC_OK |
という感じです.
ここではこれまで!
これでOK.ビルドしましょう.エラーはないですよね.
rtc.confの変更
コンポーネントを実行する前にやらなくてはならないことがもう一つ.rtc.confファイルの変更です.
このファイルには,RTCの実行に関する設定を記述できます.主な目的は
- RTCの実行頻度などの管理
- ネームサービスの位置(URLもしくはIPアドレス)
- ネームサービス上の名前付けルール
- ログの管理
- そのほかCORBAの設定
といったところです.ここではネームサービスの実行されているPCのネットワーク上の位置を追加する必要があります.
rtc.confを秀丸やMeadowなどのテキストエディタで編集してください.
編集前
exec_cxt.periodic.rate:1.0
編集後
exec_cxt.periodic.rate:1.0
corba.nameservers: localhost
このlocalhostの部分にネームサーバーが実行されているマシンのIPアドレスを指定します.複数台のPCで分散的にRTCを実行&接続する場合に関しては後述します.
RTCの実行
インストールのページで踏んだ手順で実行します.
- ネームサービスの起動
- Eclipse(RT System Editor)の起動
- ネームサービスをRTSystemEditorに登録(デフォルトで登録される場合も)
- RTC(今回はPeriodicConsoleOutComp)の実行 (VC2008からデバッグで実行でOK)
- RT System Editor上で接続(今回は無視)
- RT System Editorでアクティベート
文字がたくさん出ます.
周期の変更
先ほどのrtc.confの「exec_cxt.periodic.rate」に続く値が実行周期(単位Hz)です.これを変更すれば,文字が表示される頻度が変わります.
リアルタイムなの?リアルタイムにならないの?
OpenRTM-aistのコードを見ればわかりますが,リアルタイムではありません.つまり,周期を100とした場合でも,実行時に100Hzが補償出来ません.Windowsだとキツイです.
ただ,Linuxではカーネルプリエンプションを使ったリアルタイム周期実行が可能になります.いずれ解説します.
RTCの終了
注意!いきなりDOS窓を閉じない!!
終了時はRT System Editor上でRTCを右クリックし,非アクティブ化(deactivate)をした後,さらに右クリックして「終了(exit)」を選択してから終了させてください.現在の状態では,Exit関数を呼び出す方法が他にありません.
exit関数を呼ばずにDOS窓を閉じてしまうと,下図のようにRTCがネームサーバー上に登録されたまま実体の無い「ゾンビー状態」になります.ゾンビーってふざけているようですが,ふつうにハッカー達はゾンビーと呼んでます.
ゾンビが出来てしまってもバージョン1.0からは怖くありません.ゾンビをクリアボタンが付いています.これを押すとゾンビが消えます.
再度開発を行う場合
RTC Builderの設定は,RTCBuilderで自動的に生成されたRTC.xmlというファイルに,RTCProfile形式という形で記録されています.これをインポートすることによって,RTC Builderの設定を読み出し,再度スケルトンコードを生成することが出来ます.
EclipseからRTC Builderを開き,RTC Builder Editorを開きます.
基本タブからプロファイル情報のインポート・エクスポートを選び,インポートボタンをクリック!
PeriodicConsoleOutのプロジェクトフォルダからRTC.xmlファイルを選択してインポートします.
これで前回の設定が復活です.
新しい設定を追加した後に,再度「コード生成」ボタンでコードを生成します.このとき,「比較エディター」画面になります.選択肢として「Original(もとのコードを保持)」「Merge(RTCBuilderのコード生成部分のみ最新で上書き)」「Generate(最新で上書き)」の3つの選択肢があります.Mergeを選べばよいのですが,2009年7月24日現在,バグらしき箇所がありますので,基本的にGenerateを選びます.古いファイルも○○.cpp20090724・・・のようにファイル名が書きかえられて残っています.こちらから自分の手作業でコピー&ペーストしてプログラムを最新にします.
*この方法が許されるように,基本的にメインロジックをRTCコード上に書かずに,独自クラスを実装するようにしましょう.RTCのコードには最小限のコードを書く方がベター.
まとめ
いかがですか?コンポーネント作成がかなり簡単であることが分かると思います.今回はPeriodicなコンポーネントで,しかもデータの授受を全く行いませんでしたが,次回はRT
System Editorからコンフィグレーションの設定が出来るように,今回のプログラムを拡張してみましょう.
今回作成したファイル
PeriodicConsoleOut_v10(C++)
PeriodicConsoleOutJava
PeriodicConsoleOutPy