eSEATでSeqIO
SimpleIOに引き続き、SeqIOのサンプルをSEATMLで作成していきます。
作成するSeqInとSeqOutは、以下のようになっています。
作成するSeqInとSeqOutは、以下のようになっています。
- SeqOut
- TimedOcte型,TimedShort型,TimedLong型, TimedFloat型, TimedDoule型及びそれぞれのSequence型の、出力データポート(合計10個)を有し、各データポートにランダムなデータを周期的に出力する。
- SeqIn
- TimedOcte型,TimedShort型,TimedLong型, TimedFloat型, TimedDoule型及びそれぞれのSequence型の入力データポート(合計10個)を有し、コンソールに受信したデータをすべて表示します。
SeqOutの実装
まずは、ひな形のSEATMLファイルをSeqOut.seatmlといファイルにコピーします。
# cd ~/work
# source/usr/local/eSEAT/setup.bash
# gen_seatml SeqOut
次に、適当なエディタでSeqOut.seatmlを開き、出力データポートの追加を行います。
<?xml version="1.0" encoding="UTF-8" ?>
<seatml>
<general name="SeqOut">
<adaptor name="octet" type="rtcout" datatype="TimedOctet" />
<adaptor name="short" type="rtcout" datatype="TimedShort" />
<adaptor name="long" type="rtcout" datatype="TimedLong" />
<adaptor name="float" type="rtcout" datatype="TimedFloat" />
<adaptor name="double" type="rtcout" datatype="TimedDouble" />
<adaptor name="octetSeq" type="rtcout" datatype="TimedOctetSeq" />
<adaptor name="shortSeq" type="rtcout" datatype="TimedShortSeq" />
<adaptor name="longSeq" type="rtcout" datatype="TimedLongSeq" />
<adaptor name="floatSeq" type="rtcout" datatype="TimedFloatSeq" />
<adaptor name="doubleSeq" type="rtcout" datatype="TimedDoubleSeq" />
</general>
<state name="main_state">
</state>
</seatml>
SeqOutは、乱数で発生させたoctet型、short型、long型、float型、double型の数字と10個の乱数からなるoctetSeq型、shortSeq型、longSeq型、floatSeq型、doubleSeq型の数字を周期的に出力するものです。(ただし、octet型は、'A'-'Z'(0x41 - 0x5a)の文字とします)
周期的な処理は、onexecで書くことができますので、SeqOut.pyの内容をほぼそのまま書くことができます。
<state>要素の子要素として、下記のコードを書き込みます。(Python2の場合)
<onexec>
<sript>
import random
octetSeq = ""
shortSeq = []
longSeq = []
floatSeq = []
doubleSeq = []
seat._data['octet'].data=int(random.uniform(0x41, 0x5a))
seat._data['short'].data=int(random.uniform(0, 10))
seat._data['long'].data=long(random.uniform(0, 10))
seat._data['float'].data=float(random.uniform(0.0, 10.0))
seat._data['double'].data=float(random.uniform(0.0, 10.0))
print('%3.2s %10.8s %10.8s %10.8s %10.8s %10.8s' \
% (' ', 'octet', 'short', 'long', 'float', 'double'))
print('%3.2s %7s[%s] %10.8s %10.8s %10.8s %10.8s' \
% (' ', seat._data['octet'].data, chr(seat._data['octet'].data),
seat._data['short'].data, seat._data['long'].data,
seat._data['float'].data, seat._data['double'].data))
print( '-------------------------------------------------------------')
print( ' Sequence Data ')
print( '-------------------------------------------------------------')
for i in range(10):
octetSeq = octetSeq + chr(int(random.uniform(0x41, 0x5a)))
shortSeq.append(int(random.uniform(0, 10)))
longSeq.append(long(random.uniform(0, 10)))
floatSeq.append(float(random.uniform(0.0, 10.0)))
doubleSeq.append(float(random.uniform(0.0, 10.0)))
print( '%3.2s : %7s[%s] %10.8s %10.8s %10.8s %10.8s' \
% (str(i), ord(octetSeq[i]), octetSeq[i], shortSeq[i],
longSeq[i], floatSeq[i], doubleSeq[i]))
print('')
seat._data['octetSeq'].data=octetSeq
seat._data['shortSeq'].data=shortSeq
seat._data['longSeq'].data=longSeq
seat._data['floatSeq'].data=floatSeq
seat._data['doubleSeq'].data=doubleSeq
seat.writeData('octet')
seat.writeData('short')
seat.writeData('long')
seat.writeData('float')
seat.writeData('double')
seat.writeData('octetSeq')
seat.writeData('shortSeq')
seat.writeData('longSeq')
seat.writeData('floatSeq')
seat.writeData('doubleSeq')
</script>
<onexec>
Python3を利用する場合には、octetSeqの実装型が異なりますので、下のようになります。
<onexec>
<sript>
import random
octetSeq = b""
shortSeq = []
longSeq = []
floatSeq = []
doubleSeq = []
seat._data['octet'].data=int(random.uniform(0x41, 0x5a))
seat._data['short'].data=int(random.uniform(0, 10))
seat._data['long'].data=long(random.uniform(0, 10))
seat._data['float'].data=float(random.uniform(0.0, 10.0))
seat._data['double'].data=float(random.uniform(0.0, 10.0))
print('%3.2s %10.8s %10.8s %10.8s %10.8s %10.8s' \
% (' ', 'octet', 'short', 'long', 'float', 'double'))
print('%3.2s %7s[%s] %10.8s %10.8s %10.8s %10.8s' \
% (' ', seat._data['octet'].data, chr(seat._data['octet'].data),
seat._data['short'].data, seat._data['long'].data,
seat._data['float'].data, seat._data['double'].data))
print( '-------------------------------------------------------------')
print( ' Sequence Data ')
print( '-------------------------------------------------------------')
for i in range(10):
octetSeq = octetSeq + chr(int(random.uniform(0x41, 0x5a))).encode()
shortSeq.append(int(random.uniform(0, 10)))
longSeq.append(long(random.uniform(0, 10)))
floatSeq.append(float(random.uniform(0.0, 10.0)))
doubleSeq.append(float(random.uniform(0.0, 10.0)))
print( '%3.2s : %7s[%s] %10.8s %10.8s %10.8s %10.8s' \
% (str(i), ord(octetSeq[i]), octetSeq[i], shortSeq[i],
longSeq[i], floatSeq[i], doubleSeq[i]))
print('')
seat._data['octetSeq'].data=octetSeq
seat._data['shortSeq'].data=shortSeq
seat._data['longSeq'].data=longSeq
seat._data['floatSeq'].data=floatSeq
seat._data['doubleSeq'].data=doubleSeq
seat.writeData('octet')
seat.writeData('short')
seat.writeData('long')
seat.writeData('float')
seat.writeData('double')
seat.writeData('octetSeq')
seat.writeData('shortSeq')
seat.writeData('longSeq')
seat.writeData('floatSeq')
seat.writeData('doubleSeq')
</script>
<onexec>
通常のRTCを実装する場合とことなるのは、出力データポートの出力バッファとデータの書き出しのメソッドです。通常は、データポートに対して write()メソッド呼び出しを行いますが、eSEATでは、writeDataメソッドを定義しています。
SimpleIOの時に行った<script>要素にsendto属性をつけるというやり方もあるのですが、複数のデータポートに周期的に実施するのには、少し向かないので上のような実装にしています。
もちろん、<onexec>要素に、出力データごとに'<script>要素+sendto属性'でも似たような機能は実装することができます。
最終的なSeqOut.seatmlは、このページに添付しておりますので、ダウンロードして使用して下さい。
SeqInの実装
まずは、ひな形のSEATMLファイルをSeqain.seatmlといファイルにコピーします。
# cd ~/work
# source /usr/local/eSEAT/setup.bash
# gen_seatml SeqIn
次に、適当なエディタでSeqIn.seatmlを開き、入力データポートの追加を行います。
<?xml version="1.0" encoding="UTF-8" ?>
<seatml>
<general name="SeqIn">
<adaptor name="octet" type="rtcin" datatype="TimedOctet" />
<adaptor name="short" type="rtcin" datatype="TimedShort" />
<adaptor name="long" type="rtcin" datatype="TimedLong" />
<adaptor name="float" type="rtcin" datatype="TimedFloat" />
<adaptor name="double" type="rtcin" datatype="TimedDouble" />
<adaptor name="octetSeq" type="rtcin" datatype="TimedOctetSeq" />
<adaptor name="shortSeq" type="rtcin" datatype="TimedShortSeq" />
<adaptor name="longSeq" type="rtcin" datatype="TimedLongSeq" />
<adaptor name="floatSeq" type="rtcin" datatype="TimedFloatSeq" />
<adaptor name="doubleSeq" type="rtcin" datatype="TimedDoubleSeq" />
</general>
<state name="main_state">
</state>
</seatml>
SeqInは、octet型、short型、long型、float型、double型、octetSeq型、shortSeq型、longSeq型、floatSeq型、doubleSeq型の入力データポートのデータを周期的に読み込み、その値を出力します。
周期的な処理は、onexecで書くことができますので、SeqIn.pyの内容をほぼそのまま書くことができます。
<state>要素の子要素として、下記のコードを書き込みます。(Python2の場合)
<onexec>
<sript>
<!--
octet_ = seat.readData('octet')
short_ = seat.readData('short')
long_ = seat.readData('long')
float_ = seat.readData('float')
double_ = seat.readData('double')
octetSeq_ = seat.readData('octetSeq')
shortSeq_ = seat.readData('shortSeq')
longSeq_ = seat.readData('longSeq')
floatSeq_ = seat.readData('floatSeq')
doubleSeq_ = seat.readData('doubleSeq')
octetSize_ = len(octetSeq_.data)
shortSize_ = len(shortSeq_.data)
longSize_ = len(longSeq_.data)
floatSize_ = len(floatSeq_.data)
doubleSize_ = len(doubleSeq_.data)
octetSeqDisp_ = []
for i in range(octetSize_):
octetSeqDisp_.append(ord(octetSeq_.data[i]))
maxsize = max(octetSize_, shortSize_, longSize_, floatSize_, doubleSize_)
octetSeqDisp_ = octetSeqDisp_ + ['-'] * (maxsize - octetSize_)
shortSeq_.data = shortSeq_.data + ['-'] * (maxsize - shortSize_)
longSeq_.data = longSeq_.data + ['-'] * (maxsize - longSize_)
floatSeq_.data = floatSeq_.data + ['-'] * (maxsize - floatSize_)
doubleSeq_.data = doubleSeq_.data + ['-'] * (maxsize - doubleSize_)
if 0x20 <= octet_.data < 0x7e :
octetDisp_ = chr(octet_.data)
else:
octetDisp_ = ' '
print( '%3.2s %10.8s %10.8s %10.8s %10.8s %10.8s' \
% (' ', 'octet', 'short', 'long', 'float', 'double'))
print( '%3.2s %7s[%s] %10.8s %10.8s %10.8s %10.8s' \
% (' ', octet_.data, octetDisp_, short_.data, long_.data,
float_.data, double_.data))
print( '===================================================' )
print( ' Sequence Data ' )
print( '===================================================' )
for i in range(maxsize):
if 0x20 <= octetSeqDisp_[i] < 0x7e :
octetDisp_ = chr(octetSeqDisp_[i])
else:
octetDisp_ = ' '
print( '%3.2s %7s[%s] %10.8s %10.8s %10.8s %10.8s' \
% (i, octetSeqDisp_[i], octetDisp_, shortSeq_.data[i],
longSeq_.data[i], floatSeq_.data[i], doubleSeq_.data[i]))
print(' ')
-->
</script>
</onexec>
Python3で実行する場合には、下のようになります。
<onexec>
<sript>
<!--
octet_ = seat.readData('octet')
short_ = seat.readData('short')
long_ = seat.readData('long')
float_ = seat.readData('float')
double_ = seat.readData('double')
octetSeq_ = seat.readData('octetSeq')
shortSeq_ = seat.readData('shortSeq')
longSeq_ = seat.readData('longSeq')
floatSeq_ = seat.readData('floatSeq')
doubleSeq_ = seat.readData('doubleSeq')
octetSize_ = len(octetSeq_.data)
shortSize_ = len(shortSeq_.data)
longSize_ = len(longSeq_.data)
floatSize_ = len(floatSeq_.data)
doubleSize_ = len(doubleSeq_.data)
octetSeqDisp_ = []
for i in range(octetSize_):
octetSeqDisp_.append(ord(octetSeq_.data[i]))
maxsize = max(octetSize_, shortSize_, longSize_, floatSize_, doubleSize_)
octetSeqDisp_ = octetSeqDisp_ + ['-'] * (maxsize - octetSize_)
shortSeq_.data = shortSeq_.data + ['-'] * (maxsize - shortSize_)
longSeq_.data = longSeq_.data + ['-'] * (maxsize - longSize_)
floatSeq_.data = floatSeq_.data + ['-'] * (maxsize - floatSize_)
doubleSeq_.data = doubleSeq_.data + ['-'] * (maxsize - doubleSize_)
if 0x20 <= octet_.data < 0x7e :
octetDisp_ = chr(octet_.data)
else:
octetDisp_ = ' '
print( '%3.2s %10.8s %10.8s %10.8s %10.8s %10.8s' \
% (' ', 'octet', 'short', 'long', 'float', 'double'))
print( '%3.2s %7s[%s] %10.8s %10.8s %10.8s %10.8s' \
% (' ', octet_.data, octetDisp_, short_.data, long_.data,
float_.data, double_.data))
print( '===================================================' )
print( ' Sequence Data ' )
print( '===================================================' )
for i in range(maxsize):
octetDisp_ = ord(octetSeqDisp_[i])
print( '%3.2s %7s[%s] %10.8s %10.8s %10.8s %10.8s' \
% (i, octetSeqDisp_[i], octetDisp_, shortSeq_.data[i],
longSeq_.data[i], floatSeq_.data[i], doubleSeq_.data[i]))
print(' ')
-->
</script>
</onexec>
このコードもほぼOpenRTM-aistのサンプルであるSeqIn.pyのonExecuteメソッドをそのまま書くことができます。通常のRTCとことなるのは、 入力データポートからのデータ取得の部分を、seat.readDataメソッドを使っている点です。
また、この実装では、<script>要素のPythonスクリプトの部分が <!-- --> で囲まれており、XMLのコメントになっています。これは、XMLの文書では、'<'の文字が予約語となっており、SEATMLの構文解釈のときにエラーが起こってしまうためです。
また、
print( '===================================================' )
の部分も '-' から '='に変更しています。これも、XMLの構文による制限のためです。(XMLでは、コメント内部で、'--'を記述することができません。)
この実装でも、通常のeSEATの記法と異なるやり方をしています。通常のeSEATでは、'<rule>要素+source属性'で入力データをハンドリングするのですが、このように周期的に一括してデータ利用する場合(複数adaptorの同期的な使用)には、<onexec>要素の中で処理する方がよいと思います。
最終的なSeqIn.seatmlは、このページに添付しておりますので、ダウンロードして使用して下さい。
SeqInとSeqOutの動作確認
最後に、作成したSeqInとSeqOutを実行してみましょう。実行は、eSEATコマンドで行います。
ターミナルを2つ起動し、下記のコマンドを入力します。
ターミナル1:
# cd ~/work
# eSEAT SeqIn.seatml
ターミナル2:
# cd ~/work
# eSEAT SeqOut.seatml
SeqInとSeqOutが起動したら各データポートを接続し、アクティベートすれば、SeqOutで生成されたランダムデータがSeqInに送信されることが確認できると思います。
RTCの操作は、通常、RT SystemEditorで行いますが、今回は接続するポートが多いこともあり、rtshellを使用することを推奨いたします。このページに、データポートの接続、切断、RTCのアクティベート、ディアクティベート、終了を行うためのシェルスクリプトを添付しています。(seq_cmd.sh)
Windows上で動作させる場合には、eSEATのrtcmdコマンドを使います。rtcmdで作成したバッチファイルを添付しています。(seq_cmd.bat)
このスクリプトを使用すると下のようになります。
- データポートの接続
# bash ./seq_cmd.sh con
- SeqIn, SeqOutのアクティベート
# bash ./seq_cmd.sh act
この時点で、SeqInのコンソールには、下記のような表示が出力されると思います。
octet short long float double
88[X] 2 1 0.066247 3.844291
===================================================
Sequence Data
===================================================
0 88[X] 5 6 2.672402 7.964075
1 85[U] 6 8 3.296362 3.640238
2 85[U] 9 9 1.650067 8.078001
3 82[R] 0 0 2.689078 7.322640
4 75[K] 4 1 7.294220 0.574901
5 74[J] 4 3 6.709820 0.236388
6 73[I] 2 2 8.187395 3.643058
7 77[M] 1 8 7.101873 7.989470
8 86[V] 4 9 5.151458 7.829076
9 85[U] 3 6 4.885576 8.390419
動作確認ができれば、RTCをでアクティベートして、終了させて下さい。
- SeqIn, SeqOutのデアクティベート
# bash ./seq_cmd.sh deact
- 接続されたデータポートの切断
# bash ./seq_cmd.sh dis
- SeqIn, SeqOutの終了
# bash ./seq_cmd.sh exit
以上で、SeqIOの実装と動作確認は終了です。
資料