SEATMLファイルの書き方
Simple Wiki Based Contents Management System
ソフトウェア関連 >> RTコンポーネント関連 >> eSEAT_v2.5 >> SEATMLファイルの書き方

SEATMLファイルの書き方

SEATMLは、eSEATのコンポーネントの入出力アダプタやGUIを設計、実装するためのXMLファイルです。
以前のドキュメントはこちらです。
以前は、XSDを必須としていましたが、様々な機能拡張に伴いXSDを必要としないようにしています。ただし現在でも、XSDを指定も可能です。
ここでは、SEATMLの基本とRTコンポーネント、ROSノード、RTC-ROS連携コンポーネントの作成の例を通して、SEATMLの書き方等を書いていきたいと思います。

SEATMLの基本構成

SEATMLは、独自のスキーマで定義されたXMLファイルです。そのため、下記のような文書構造になっています。
  <?xml version="1.0" encoding="UTF-8" ?>
  <seatml>
    <general>
      - Adaptorの定義<adaptor>
      - 周期実行スクリプト<onexec>
      - 起動時に実行されるスクリプト<script>
      - 大域変数の定義<var>
      - 一つの状態で一定時間入出力がない場合に実行される共通スクリプト(各状態でontimeoutがない場合有効になる)<ontimeout>
      - Active化の時に実行される共通スクリプト(RTCのみ)<onactivated>
      - Deactive化の時に実行される共通スクリプト(RTCのみ)<ondeactivated>
    </general>
    <state name="st1">
      - 状態遷移時に実行するスクリプトなど<onentry>(state内に1つのみ定義可能)
      - 状態を抜けるときに実行するスクリプトなど<onexit>(state内に1つのみ定義可能)
      - 周期実行スクリプト<onexec>(state内に1つのみ定義可能)
      - 一定時間入出力がなかった時に実行するスクリプトなど<ontimeout>(state内に1つのみ定義可能)
      - ruleの定義<rule>
      - GUI部品の定義 <label, button, input, text, combobox, listbox, radiobutton, scale, frame, labelframe, brk, space> 
    </state>
    <state name="st2">
        ...
        ...
    </state>
       ....
       ....
  </seatml>
上の例からもわかるとは思いますが、SEATMLのファイルは、XMLの宣言1つの<seatml>タグによる定義で構成されています。また、<seatml>タグには、
  • <general>タグによるeSEATの内部状態によらない機能の定義(アダプタや周期タスクなど)
  • <state>タグによる内部状態の定義
の2つの部分から構成されています。
eSEATの内部状態に依存しない機能の定義は <general>タグで行い、1つのSEATMLファイルでは1つのみ有効になっています。
<state>タグには name属性は必須であり、1つのSEATML内では、1つ以上の<state>タグによる内部状態の定義が必要になります。

<general>

<general>タグの中では、eSEATの内部状態によらない機能を定義します。<general>タグは、1つのSEATMLファイルには、1つのみ定義することができます。ここでは、通常、外部のコンポーネントとの通信を行うためのadaptorの定義を行いますが、adaptor定義を行うときに必要な関数やクラスを読込ために<script>タグを使って、モジュールのインポートを行うことができます。
さらに、eSEATをRTCとして動作させる場合に、RTCの有効化(<onactivated>)/無効化(<ondeactivated>)や1つの状態におけるタイムアウト時(<ontimeout>)の処理、すべての内部状態で常に動作する処理(<onexec>)を定義することができます。
onexec, onactivated, ondeactivated, ontimeoutの各タグには、<message>,<script>, <shell>, <statetransition>, <log>の5つのタグを使って、eSEATが実行すべき処理(Task)を定義することができます。eSEATの内部では、これらの処理はTaskクラスに変換されています。
<adaptor>
現在のeSEATでは、外部のコンポーネントとの通信はすべてadaptorを介して行われます。adaptorでサポートされている通信は、
  • Raw Scoket
  • HTTPD (Cometによる通信)
  • OpenRTM-aistのデータポートおよびサービスポート
  • ROSまたはROS2によるPublisher, Subscriber, RosService(Server, Client)
の4つです。
元々、eSEATはRTコンポーネントとして開発されてきましたが、adaptorを定義することで、ROSやHTTPとの連携も可能です。
adaptorを定義する場合には、name属性とtype属性は、必ず必要となります。その他の属性(dir, document_root, port, host, datatype, size, callback, file, service, service_type, impl, if_class, interface)は、生成するadaptorのタイプに応じて必要なものが決まります。
name属性は、adaptorの識別子として使用しますので、1つのSEATML内で重複してしようすることができません。また、type属性で指定可能な値は、socket, web, rtc_in, rtc_out, consumer, provider, ros_pub, ros_sub, ros_server, ros_clientです。
ROSのアダプタに関しては、使用されている環境に応じてROS1かROS2のいづれかが使用可能です。(同時利用は不可能です)
各adaptorのタイプ別に、使用する属性は下記の通りです。
type設定可能な属性説明
socketport接続先のポート番号
host接続先のホスト名またはIPアドレス
webportHTTPサーバーのポート番号
document_rootまたはdirHTMLのドキュメントルート(オプション)(省略時は html)
host接続可能なホスト名のリスト(オプション)(省略時はすべてのホストから接続可能)
rtc_in, rtc_outdatatypeデータポートのデータ型
providerinterfaceサービスポートのインターフェースタイプ(interface_type|interface_nameの書式とする)
if_class実装クラス名
impl_file実装クラスが定義されたファイル名
consumerinterfaceサービスポートのインターフェースタイプ(interface_type|interface_nameの書式とする)
if_classインターフェース名
ros_pubdatatypePublisherのメッセージ型
sizeROS1の時、queue_sizeのサイズ(デフォルトは1)
ROS2の場合は無視される
ros_subdatatypeSubscriberのメッセージ型
callbackSubscriberのコールバック関数(デフォルトは、seat.onData)
fileSubscriberを生成する前に読み込むPythonスクリプト(オプション)
ros_serverserviceROSサービス名
service_typeROSサービスの型
impl実装関数名
fileROS Serverを生成する前に読み込むPythonスクリプト(オプション)
ros_clientserviceROSサービス名
service_typeROSサービスの型

<state>

<state>タグは、eSEATの内部状態とその振る舞いを定義するためのものです。1つのSEATMLファイルには、1つ以上の<state>(状態)が必要です。
SEATML内で最初に定義された<state>が初期状態となります。他の状態遷移を行うには、<statetransition>タグを使うかstateTransferメソッドを利用します。
stateTransferメソッドを使うと状態遷移の履歴保持ができませんので、<statetransition>タグで設定することを推奨しています。
<state>タグの中には、
  • 状態遷移時に実行する処理(状態に入るとき(<onentry>)と出るとき(<onexit>))
  • 状態に滞在中に実行する周期タスク(<onexec>)
  • 状態に滞在中のタイムアウトに対する処理(<ontimeout>)
  • 状態に滞在中に非活性化が行われた時の処理(<ondeactivated>)
  • adaptorから受けっとったデータまたはGUIの操作に対する処理 (<rule>)
  • GUIパネルの要素(label, brk, space, frame, labelframe, button, input, text, combobox, checkbutton, listbox, radiobutton, scale)
で定義した子要素を記述することができます。
<state>タグで定義する内部状態は、状態遷移マシンの"状態”そのものと同値です。また、状態遷移マシンのイベントは、<rule>または<ontimeout>であると考えると、このSEATMLの表現は、SCXMLで表現された状態遷移マシンに置換可能です。
<onentry><onexit><onexec><ondeactivated>
これらのタグには、eSEATで行う処理(Task)を定義することができます。これらは<general>タグで定義したものと同じです。eSEATの処理(Task)の詳細については、後述します。
<ontimeout>
このタグで記述できるのは、上記の4つのタグと同じようにeSEATで行う処理です。上記のタグと異なるのは、<ontimeout>には、timout属性を取ります。この属性で設定された数字の単位はであり、この状態に滞在中に、adaptorからの入力およびGUIパネルへの操作がtimeoutで属性で指定された秒数経過すれば、ここで定義された処理(Task)が実行されます。
これによって、一定時間に何もなければ、内部状態を初期状態に戻すなどの記述が可能です。
<rule>
このタグは、eSEATにおける振舞の大部分を占めるものです。<key>タグかつsource属性で定義された条件で、実行される処理(Task)を定義します。
実行される処理に<cond>タグで設定された条件があった場合には、その条件を満たす場合にのみ処理が実行されます。
<key>タグに関しては、単純な文字列ですが、adaptorからの入力およびGUI部品のラベルとのマッチングを取ります。マッチングには、Pythonのmatch関数が用いられています。
実際にどのような振る舞いをするかは、サンプル等を見ていただけるとわかりやすいと思います。
GUI部品
GUI部品は、eSEATの内部状態ごとのUIを設定することができます。現在利用可能な部品は、Tkinterにおけるlabel, frame, labelframe, button, input, text, combobox, checkbutton, listbox, radiobutton, scaleです。パネルのレイアウトは、GridLayoutを使っており、多段やスキップをおこなうためにbrkspace等のタグを使います。
具体的な例は、examplesにあるサンプルを参照してください。

eSEATの処理(Task)について

eSEATにおける処理(Task)とは、<message>,<script>, <shell>, <statetransition>, <log>の5つのタグを使って、定義します。eSEATの内部では、これらの処理はTaskGroupクラスに変換され、各タグは、Taskクラスに変換、保持されています。
Taskクラス、TaskGroupクラスには、<cond>タグで定義された conditionを設定することができます。
また、各タグで定義される処理は下のようになっています。
<message>
sendto属性で指定されたadaptorに対し、設定された文字列または処理結果(rtc_result)を出力します
<script>
子要素として記載されたPythonスクリプトを実行し、その結果が__result__に格納されます。sendto属性があり、__result__が真であれば、rtc_resultに格納されたデータをsendto属性で指定されたadaptorに出力する。また、このタグに記載されたPythonスクリプトでは、rtc_in_data,web_in_dataがadaptorからの受信したデータとして参照可能です。
<shell>
子要素として記載されたシェルコマンドを実行します。sendto属性があれば、実行結果を指定されたadaptorに出力します。
<log>
子要素の文字列をloggerに出力します
<statetransition>
eSEATの内部状態を子要素に指定された状態に遷移します
SEATMLで記述された処理がどのようになるかは、サンプル等を参照して頂ければよりわかりやすいと思います。