単純な入出力コンポーネント
eSEATのGUI作成機能を使って、簡単な文字列の入出力コンポーネントを作成してみます。
まず、目標とするコンポーネントの機能を考えます。なるべく単純な入出力のコンポーネントにしたいと思いますので、同じ仕様のコンポーネントを接続して文字列の受け渡しができるようにするというので良いでしょう。
したがって以下のような仕様にしたいと思います。
- データポートとして、TimedString型の入力ポートとTimedString型の出力ポートを備える
- ユーザからの文字列入力は、一行入力アイテムから行う
- 外部から来た文字列は、履歴も見たいのでスクロールできるテキストアイテムにする
この仕様に従ってSEATMLスクリプトを作成しましょう。
ひな形を用意する
最初にSEATMLのひな形を用意します。ひな形といっても何も入っていないSEATMLファイルです。下記のような内容をもつファイルです。
<?xml version="1.0" encoding="UTF-8"?> <seatml> <general name="SimpleIO"> </general> <state name="main_state"> </state> </seatml>
このSEATMLファイルでeSEATは起動可能ですが、全く何のポートも持っていないし、コアロジックも持たないRTCになります。
確認のため、この内容をもつファイルをSimpleIO.seatmlとして保存し、
python eSEAT.py SimpleIO.seatml
として起動してみましょう。
起動してRT SystemEditorで見てみると下図のようになっていると思います
確認できれば、RT SystemEditorからコンポーネントの右クリックでメニューを出して''Exit''を選択&終了しましょう。
入出力ポートの追加
次に、文字列の入出力ポートを追加します。最初に考えたようにTimedString型の入力ポート1つとTimedString型の出力ポート1つを定義します。データポートの設定は、general要素の子要素として、下記の2つのadaptor要素を追加しましょう。
<adaptor name="str_out" type="rtcout" datatype="TimedString" /> <adaptor name="str_in" type="rtcin" datatype="TimedString" />
このようにadaptor要素を定義して、起動すると下図ようになコンポーネントになります。
GUIアイテムの追加
次にユーザインターフェースとなるGUIアイテムを追加していく。最初に、
''ユーザからの文字列入力は、一行入力アイテムから行う''
としていたので、input要素を追加する
<input id="textIn" ></input>
次に、
''外部から来た文字列は、履歴も見たいのでスクロールできるテキストアイテムにする''
ということで、text要素を追加する。
<text id="textOut" /></text>
上記の2つを追加して起動すると下の図のようなGUIパネルが生成されます。
これでも必要機能はあるのですが、少し寂しいので、label要素、button要素、brk要素などを追加して見た目を改善しましょう。
<label text="SimpleIO" colspan="3" bg_color="blue" /> <brk /> <label text="Input:" /> <input id="textIn" width="50" ></input> <button label="Send"></button> <brk /> <label text="Coming Text:" /> <text id="textOut" width="50" height="5" colspan="2" />
このような記述に変更すると下記のようなGUIパネルになります
なお、GUIパネルがある場合には、右上のパネル終了ボタンを押下すれば、コンポーネントを終了できるようになります。
コマンド要素の追加
前述までに、データポートとGUIパネルまでできました。しかし、このコンポーネントには、まだ、何のコアロジックも入っていません。eSEATでは、コアロジックをonExecuteに記載するのではなく、入力データがあった場合にそのデータに対応して動作するようになっています。つまり、データポートを作成していますが、イベント駆動型のコンポーネントになっています。
実装としては、各データポートにListenerオブジェクトがバインドされており、データ受信フラグがあれば登録されているコマンドを動作させるというのが基本動作になっています。
コマンド要素の追加の方法としては、rule要素の追加、button要素に追加、input要素に追加の3つの方法があります。上記で作成したGUIパネルには、button要素も付け加えていましたので、
- 入力アイテムで<ENTER>キーが押されたらデータを送信
- ''Send''ボタンを押下時にデータを送信
- 入力データポートにデータが来たら、text要素にその文字列を出力して改行する。
というイベントハンドラを実装しましょう。
1に関しては、input要素の子要素として設定、2に関しては、button要素の子要素として追加すれば良いでしょう。また、3に関しては、rule要素を追加することにします。
下記のように実装してみてください。
2014/07/24 のアップデートで、seatml内のlabel, button, input, textの要素の指定は、「stateの識別子+":"+要素の識別子」に仕様変更しました
<label text="SimpleIO" colspan="3" bg_color="blue" /> <brk /> <label text="Input:" /> <input id="textIn" width="50" > <message sendto="str_out" input="main_mode:textIn" /> </input> <button label="Send"> <message sendto="str_out" input="main_mode:textIn" /> </button> <brk /> <label text="Coming Text:" /> <text id="textOut" width="50" height="5" colspan="2" /> <rule source="str_in"> <script> seat.appendText("main_mode:textOut", rtc_in_data.data+"\n") </script> </rule>
最終的なSEATMLスクリプトは、本ページに添付しています。
後は、eSEATを起動して、相互に接続して動作確認をして見ましょう。
しかしながら、単純に
python eSEAT.py SimpleIO.seatml
を同じ計算機上で実行してしまうと、NameServerに同じ名前で登録してしまい、2つのコンポーネントを参照することができません。そこで、名前を指定して起動してみましょう。
OpenRTM-aistでは、rtc.confにコンポーネントの名前をカスタマイズする機能があります。そこで、プロセスIDを利用した名前付けを行えば、問題なく2つのコンポーネントを起動できるのですが、eSEATでは、コマンドラインでの起動時に、-n オプションで起動するコンポーネントの名前を指定することができます。
python eSEAT.py -n SimpleIO1 SimpleIO.seatml python eSEAT.py -n SimpleIO2 SimpleIO.seatml
上記のコマンドでeSEATを起動すると、SimpleIO1とSimpleIO2が起動していると思います。
2つのeSEATが無事に起動した後、相互のデータポートを接続し、入力テストで確認をしてください。
資料