最初に、pythonのためのパッケージのインストールが必要になります。
端末から、次のコマンドを実行してください。
% sudo aptitude install openrtm-aist-python openrtm-aist-python-example omniidl4-python python-omniorb2-omg
PyDev は、Eclipse で python を扱うプラグインです。
Eclipse のメニューから「ヘルプ」~「ソフトウェア更新」を選びます。
「ソフトウェア更新およびアドオン」ダイアログが開くので、「サイトの追加」ボタンを押してロケーションに「http://pydev.org/updates 」を入力します。
使用可能なソフトウェアのタブに、この http://pydev.org/updates が追加されるので、これを開いてPyDev の下にある PyDev for Eclipse をチェックして、インストールボタンを押します。
二つのRTコンポーネント VisionManipulation と MyScheduler を作成して、すでに作成済みの RTコンポーネント VVVRecogTrigger からデータを取得します。
メインとなるのは VisionManipulation です。
スケジューラからモデルのIDを受け取ったら、recogSDL サービスポートを通して VVVRecogTrigger に渡します。
VVVRecogTrigger がモデルIDを認識した結果は、recogResult データポート経由で受けとります。
二つのRTコンポーネントができたので、まずはローカルで接続してみます。
Eclipse で RT System Editor パースペクティブを開き、ツールバーのONを押して System Diagram を開きます。
ツリーの「localhost:2809」を開くと、その下にさらに「(ホスト名)|host_cxt」というツリーがあると思うので、それも開いておきます。
いくつかRTコンポーネントが表示されるかもしれませんが、どれも□のアイコンで、起動できません。
端末ウインドウを二つ開き、一つでMyScheduler.py, もう一つで VisionManipulation.py を実行します。
すると、「(ホスト名)|host_cxt」ツリーの下に「MyScheduler0|rtc」「VisionManipulation|rtc」という項目が増えます。凸凹の文字を底でくっつけて倒したような形のアイコンになっています。
これを両方 System Diagram にドラッグ&ドロップすると、小さな□のついたブルーの長方形が現れます。これがRTコンポーネントです。
それぞれの下に、MyScheduler0, VisionManipulation0 と名前がついているのを確認してください。
また、小さな□はポートを示しています。ポートにマウスカーソルを合わせると、ポートの名前がわかります。
VisionManipulation には4つのサービスポートと1つのデータポートがあるので、右側に4つの□、左側に欠けた□が出ています。
4つの□のひとつが VisionManipulation0.scheduler となっています。
これをMyScheduler0の□にドラッグ&ドロップすると、「ポートプロファイルを入力してください」というダイアログが出るので、そのままOKを押します。
するとポートとポートが線でつながれます。
ここでツールバーの緑のプレイボタンを押すと、RTコンポーネントがアクティベートされます。
双方が一瞬緑になったあと、MyScheduler側がエラーで赤くなります。
VisionManipulation を実行している端末のエラーメッセージを確認してください。
setModelID: 42 omniORB: Caught an unexpected Python exception during up-call. Traceback (most recent call last): File "/home/asahi/workspace/VisionManipulation/VisionManipulation_idl_example.py", line 48, in setModelID coord = self.recogSDL_service._ptr().recognize_by_ID(ModelID) AttributeError: 'NoneType' object has no attribute 'recognize_by_ID'
これは VisionManipulation0 の recogSDL ポートに何もつないでいないのだから、当然です。
これでひとまず、MySchedulerからVisionManipulationの呼び出しができたということで、いよいよカメラとつないでみることにします。
(作成中)
MyScheduler は、VisionManipulation にモデルIDを送るだけの、シンプルなRTコンポーネントです。
ここでは、EclipseやRTC Builderのチュートリアルも兼ねて、画面キャプチャつきで詳細に説明します。
新規プロジェクトとして、PyDevの下にあるPyDev Project を選び、「次へ」。
PyDev Project は、
• Project name: MyScheduler
• Project contents: use default
• Project type: Python
• Grammer Version: 2.6
• Interpreter: Default
• Don't configure PYTHONPATH
とします。ほとんどデフォルトのままだと思いますが、Project name と Grammer Version には注意してください。
PyDev パースペクティブを開きますか?と尋ねられますが、すぐに RTC Builder パースペクティブを開くので、いいえで済ませましょう。
PyDev Project を作成すると、workspace ディレクトリに新しく MyScheduler ディレクトリができます。
workspace の下に idl ディレクトリを作り、そこに VisionManipulation.idl をコピーします。
Eclipse で、RTC Builder パースペクティブを開きます。
メニューバーの「ウィンドウ(W)」~「パースペクティブを開く」~「その他」を選ぶと、下のような画面が開きます。
ここでRTC Builder を選びます。
ツールバーのトンカチアイコンをクリックすると、空のRTC Builderが開きます。
最初は基本タブが表示されていますが、この画面は RtcBuilderのエディタ画面の下にあるタブで、切り替えることができます。
このタブを切り替えながら、必要な項目を入力していくことになります。
RT-Component Basic Profile 内の項目を以下のように設定します。
Output Project セクションでは、参照ボタンをクリックして、さきほど作成した MyScheduler プロジェクトを選びます。
利用するアクションコールバック関数をONにします。
今回は onExecute のみを使います。
各コールバック関数の名前がアクションごとに並んでいますが、
「Dataflow型コンポーネントのアクション」のコーナーの左端にある「onExecute」をクリックして、Documentation セクションのアクティビティ名: onExecute となっている右側のスイッチで、ONを選択します。
アクティビティセクションのonExecuteのバックに色がつきます。
と設定したら、今度はインターフェースの設定です。
Add Interfaceボタンを押すと、Scheduer ポートに if_name インターフェースが現れます。if_nameをクリックすると、RT-Component Service Port Interface Profile 画面が開きます。
ポートとインターフェースの設定は、下のBuildViewに反映します。
これが最後の設定部分です。
言語セクションで、Python を選択してください。
設定がすべて終わったので、基本タブに戻ります。
「コード生成とパッケージ化」セクションのコード生成ボタンをクリックしてください。
「Generate success.」というダイアログが出れば無事完了です。
ここで、「'SchedulerService' is not found in IDL」というエラーが出ることがあります。
そのときは、VisionManipulation.idl を編集して、一行目の #include 文をコメントアウトしてください。
//#include <rtm/idl/BasicDataType.idl>
一連の設定は、MyScheduler ディレクトリの下に、RTC.xml というファイルとして保存されます。
RTコンポーネントの設定を変更する必要が出たときは、基本タブの下にある「インポート」ボタンでこのファイルを読み込み直せば、ここまでの設定が再現されます。
MyScheduler.conf は空のファイルなので、以下の内容に書き換えます。
corba.nameservers: localhost:2809
exec_cxt.periodic.rate:2
% ln -s MyScheduler.conf rtc.conf
端末を作成し、workspace/MyScheduler に chdir します。
ここで
% sh idlcompile.sh
VisionManipulation.idl:19: Error in look-up of 'RTC::TimedDoubleSeq': 'RTC' not found VisionManipulation.idl:34: Error in look-up of 'RTC::TimedDoubleSeq': 'RTC' not found omniidl: 2 errors.
そして、idlcompile.sh を次のように書き換えます。
omniidl -bpython -I/usr/include VisionManipulation.idl
編集したファイルをすべて保存したら、あらためて
% sh idlcompile.sh
実はこれでもう動きます。端末で python MyScheduler.py を実行してください。
% python MyScheduler.py comp_args: MyScheduler
端末へ戻り、Controlキーを押しながらCを押してみます。
実行中のRTコンポーネントが終了すると、System Diagram 上のRTコンポーネントも消えることを確認してください。
Eclipse のパースペクティブを PyDev に切り替え、PyDev Package Explorer で MyScheduler を開きます。
アウトラインビューで、MySchedulerクラスの onExecute メソッドを見つけたら、クリックしてください。
return RTC.RTC_OK
ここでやりたいのは、Scheduler ポートの scheduler インターフェースの先に接続したRTコンポーネント(これから作成する VisionManipulation)の、setModelID メソッドを呼ぶことです。
そのためのコードはこうです。
self._scheduler._ptr().setModelID(42)
その _scheduler が持つ、_ptr() というメソッドが、System Diagram画面で接続された先のRTコンポーネントを指しています。
このコンポーネントが持つ setModelID を呼び出しているわけです。
ついでに print 文も追加して、setModelIDを呼ぶと同時にメッセージを表示させましょう。
def onExecute(self, ec_id): self._scheduler._ptr().setModelID(42) print "setModelID(42)" return RTC.RTC_OK
python なので、再コンパイルの必要はありません。
先ほどと同じように python MyScheduler.py を実行し、エラーが出ないことを確認してください。
これで MyScheduler RTC は完成しました。
引き続き、VisionManipulation RTC を作る に移ります。
いよいよ本体の VisionManipulation RTC の作成に入ります。
MyScheduler RTC からの setModelID の呼び出しを受けたら、VVVRecogTrigger RTC にこのコマンドを飛ばし、結果を recogResult データポートで受け取って表示するRTコンポーネントです。
概念としてはこういう形になります。
設定する項目だけ列挙します。設定の仕方の詳細は MyScheduler RTC を作る を参照してください。
Eclipse プロジェクト名: VisionManipulation
MyScheduler の Schedulerポートとほぼ同じですが、コマンドを呼ばれる側なので方向が Provided になります。
以下のポートは今回は実装しませんが、今後の拡張のためにあらかじめ定義しておきます。
ここでrecogResult ポートを定義します。
前回は設定しなかったタブなので、ここだけ詳しく解説します。
DataPort プロファイルのセクションが、「*ポート名(InPort)」と「「*ポート名(OutPort)」」の二つのリストに分かれています。
このうちのInPort側のAddボタンを押すと、ポート名リストに「dp_name」が加わり、Detail セクションにポート情報が入ります。
ポート名リストのdp_nameをクリックすると名前の変更ができるので、ポート名 recogResult を設定します。
すると、ここで設定したポート名がDetailセクションのポート名として反映します。
さらに、Detail セクションの項目を以下のように設定します。
このとき、データ型が選択できないことがあります。
そのときは、RtcBuilder にIDLファイルのパスを設定します。
メニューバーからウィンドウ~設定を選び、左のツリーからRtcBuilderを選択します。
すると「データ型: IDL File Directories」というリストが現れます。
右の「新規」ボタンを押して、場所に「/usr/include/rtm/idl」を追加します。
そうすると、IDLファイルからデータ型を読み込んで、たくさんの候補が選択できるようになります。
これで、倍精度浮動小数点数の配列が流れてくる入力データポート、recogResult が定義できました。
BuildViewはこのような形になっています。
コード生成を行ってください。
「'SchedulerService' is not found in IDL」が出るようなら、IDLのinclude文をコメントアウトします。
VisionManipulation.conf の内容を以下のように修正して、rtc.conf にシンボリックリンクを貼ります。
corba.nameservers: localhost:2809
exec_cxt.periodic.rate: 10
次に、idlcompile.sh を実行します。
エラーが出る場合は、スクリプトのコマンドラインに -I/usr/include を挿入して、やり直してください。
MyScheduler RTC が setModelID を呼び出すと、VisionManipulation では SchedulerService_i::setModelID が呼び出されます。
そこで、VisionManipulation_idl_example.py の該当部分を以下のように修正します。
# void setModelID(in long ModelID) def setModelID(self, ModelID): print "setModelID: %s" % ModelID coord = self.recogSDL_service._ptr().recognize_by_ID(ModelID) print "recognize_by_ID: %s" % coord
その結果はデータポート recogResultIn で受けることになります。
ところで、self.recogSDL_service はまだ定義していません。
これは、呼び出し元からセットしてもらうことにします。
SchedulerService_i クラスに新しいメソッドを追加します。
def setRecogSDLService(self, recogSDL_service): self.recogSDL_service = recogSDL_service
self._scheduler.setRecogSDLService(self._recogSDL)
def onExecute(self, ec_id): if self._recogResultIn.isNew(): print "resultIn:" indata = self._recogResultIn.read() val = indata.data print val print "\n" time.sleep(0.01) return RTC.RTC_OK