Defining Own Data Type
on OpenRTM-aist Python for Windows
Windows OS上のOpenRTM-aist Python版で独自データ型の使用方法を解説します。
▶ 更新履歴

4. IDLファイルの登録
作成したIDLファイルは、RTC Builderに登録することで、デフォルトのデータ型と変わらず使用することができます。
それでは、RTC BuilderにIDLファイルを登録します。
RTC Builderを起動し、メニューバーから「ウィンドウ(Window)」 > 「設定(Preferences)」と選択して下さい。
すると、設定ダイアログが立ちあがります。
①のRtcBuilderを選択し、②の新規(New)ボタンを押します。
すると、フォルダー参照ダイアログが現れるので、そこから先ほど作成したMyIDLフォルダを指定してOKバタンを押して下さい。
1. はじめに
RTコンポーネント間の通信に使用するデータポートの型は、開発者が独自に定義することができます。
ここでは、独自データ型の定義方法と、それを使用したRTCの作成方法を学びます。
独自データ型を使用したRTコンポーネントの作成手順は以下のようになります。
(1) 独自データ型が記述されたIDL(インターフェイス定義言語)ファイルの作成
(2) RTC Builderに独自データ型のIDLファイルの登録
それでは早速、RTコンポーネントを作成してみましょう。
7. おわりに
これでOpenRTM-aist Python版で独自データ型を使用できるようになりました。
この例では単純なデータ構造でしたが、送信したいデータに適した型を設計することで、データ通信とその後の処理が簡単になります。
今回はデータの長さを格納できるようにすることで、受け取り側のRTCがいちいちデータの長さを数えなくて済むようにしてみました。
*Pythonでは有効に働きませんでしたが、C++ではループの回数を決定するのに使用できます。
このように、独自データ型は適切に用いれば非常に強力な道具となります。
しかし、独自データ型で定義したデータポートは、他のRTCと交互性を保ちにくという欠点もあります。
独自データ型は、デフォルトのデータ型では表現できないときにのみ使用するよう心がけて下さい。

MyIDLフォルダを指定すると①のようにフォルダへのパスが入力されます。
次に、②のOKボタンを押せばしてください。
入力後RTC Builderを再起動します。これで、IDLファイルの登録は完了です。
5. テストRTCの作成
先ほど定義したMyLongSeq型を利用したRTCを作成します。
今回は、MyIDLTestConsoleInとMyIDLTestConsoleOutを作成します。
MyIDLTestConsoleInはMyLongSeq型のコンソールから入力されたデータを出力します。
MyIDLTestConsoleOutはMyLongSeq型のデータを受け取り、コンソール上に表示します。
いつものように、RTC Builderを使用して各RTCを作成します。
6. 動作確認
いつものように、作成したRTCを実行し、動作確認を行って下さい。
下図のように、3つの値が受け渡しができていれば成功です。
-
#include "BasicDataType.idl"
-
-
module Test
-
{
-
struct MyLongSeq
-
{
-
RTC::Time tm;
-
sequence<long> data;
-
long data_length;
-
};
-
};
-
1行目
BasiDataType.idlをincludeします。
これで、RTC::Time型のタイムスタンプが使用できます。
-
3-11行目
Testというモジュールの中に、MyLongSeqという型を定義します。
モジュールの中には複数の型や、サービスを定義することができます。
わかりやすいモジュール名を設定し、型を定義して下さい。
-
5-10行目
MyLongSeqというデータ型を定義します。
このデータ型は、以下のメンバを持ちます。
RTC::Time型のタイムスタンプ tm
longのsequence型の変数 data
long型の変数 data_length
このデータ型は、TimedLongSeq型のdataの長さを格納できるように拡張したデータ型になっています。
data_lengthはdataの長さを格納することを想定しています。
入力したら、コードはTestDataType.idlというファイル名で、MyIDLディレクトリ内に保存してください。
*拡張子はtxtではなくidlで保存してください。
これで、独自データ型を定義したIDLファイルの完成です。
3.4 TestDataType.idlのコンパイル
TestDataType.idlをIDLコンパイラでコンパイルします。
先ほど作成した「TestDataType.idl」と「BasicDataType.idl」をPython 2.6.6のフォルダにコピーします。
デフォルトであればパスは以下のようになります。
C:\Python26
IDLファイルをコピーしたらコマンドプロンプトを起動します。
コマンドプロンプトに以下のコマンドを入力してください。
Python 2.6.6のフォルダに移動し、IDLコンパイルを行います。
3. IDLファイルの作成
独自データ型はBasicDataTypeのように、IDLファイルに定義することで使用できます。
独自データ型を記述したIDLファイルを作成しましょう。
3.1 保存ディレクトリの作成
IDLファイルを作成する前に、「MyIDL」というディレクトリを作成して下さい。
ここでは、以下の場所に作成したして説明します。
C:\Users\ユーザ名\Documents\OpenRTM\MyIDL
IDLファイルは一度作成したら何度も使用することになるので、頻繁に移動する必要がない場所に保存してください。
3.2 BasicDataType.idlのコピー
繰り返しになりますが、RTC::Time型のタイムスタンプを持つことが推奨されています。
そこで、RTC::Time型が定義されている、「BasicDataType.idl」というファイルを先ほど作成したMyIDLディレクトリにコピーします。
デフォルトでは以下のディレクトリに格納されていますので、MyIDLディレクトリにコピーして下さい。
C:\Python26\Lib\site-packages\OpenRTM_aist\RTM_IDL
3.3 TestDataType.idlの作成
TestDataType.idlというIDLファイルを作成します。
以下のコードを、適当なテキストエディタで入力してください。
2. BasicDataType
普段、私たちが使用しているRTMのデフォルトのデータ型は「BasicDataType.idl」というファイルに記述されています。
BasicDataType.idlは本Webページのインストール方法に従ってインストールした場合は以下の場所にあります。
C:\Python26\Lib\site-packages\OpenRTM_aist\RTM_IDL
このBasicDataType.idlから、IDLファイルの記述方法を学びます。
以下のコードはBasicDataType.idlから一部抜粋したものです。
-
module RTC {
-
-
struct Time
-
{
-
unsigned long sec; // sec
-
unsigned long nsec; // nano sec
-
};
-
-
struct TimedLong
-
{
-
Time tm;
-
long data;
-
};
-
-
struct TimedLongSeq
-
{
-
Time tm;
-
sequence<long> data;
-
};
-
};
-
1-20行目
RTCというモジュールの中に、Time、TimedLong、TimedLongSeqという型が定義されています。
モジュールの中には複数のデータ型、ここにはありませんがサービスを定義することもできます。
普段、私たちが使用しているデフォルトのデータ型は、RTCというモジュールに属していることがわかります。
-
3-7行目
Timeというデータ型を定義しています。
このデータ型は、以下のメンバを持ちます。
unsigned long型のsec
unsigned long型のnsec
この型はタイムスタンプとして使用されます。
特に理由がない場合は、データ型はこのタイムスタンプを持つことを推奨されています。
-
9-13行目
TimedLongというデータ型を定義しています。
このデータ型は、以下のメンバを持ちます。
Time型のtm
long型のdata
この型はConsolein、ConsoleOutにも使用され馴染み深いと思います。
Timed~という型はTime型のタイムスタンプを持つことを意味することがわかります。
このように、基本型以外に独自に定義したデータ型を使用して、新たに型を定義することができます。
-
15-19行目
TimedLongSeqというデータ型を定義しています。
このデータ型は、以下のメンバを持ちます。
Time型のtm
longのsequence型のdata
dataがsequence型である以外は、TimedLong型と一緒です。
~seqというのはsequence型のデータを持つことを意味することがわかります。
*sequence型がどのようなものかわからない方は、配列のようなものだと考えて下さい。
このように、IDLファイルはC言語の構造体のように記述できるので、記述に際して、特に戸惑うことはないと思います。
IDLファイルでは、以下の様な型を使用することができます。
short
long
unsinged short
unsinged long
float
double
char
wchar
boolean
octet
longlong
ulonglong
sequence<T>
short型整数
long型整数
符号なしshort型整数
符号なしlong型整数
単精度浮動小数点
倍精度浮動小数点
文字型
wchar文字型
bool型
octet型
longlong型整数
符号なしlonglong型整数
Tのsequence型
5.1 MyIDLTestConsoleInの作成
MyIDLTestConsoleInのテンプレートの設定は以下のようになります。
-
モジュール名 MyIDLTestConsoleIn
-
ベンダ名 あなたの名前
-
モジュールカテゴリ TEST
-
実行周期 1000
-
アクションコールバック
onExecute
-
ポート名(OutPort) keyboard
-
データ型 Test::MyLongSeq
-
変数名 data
-
表示位置 RIGHT
-
言語 Python
設定が済んだらいつものようにテンプレートを生成してください。
次に、生成したプロジェクトのディレクトリの直下に先ほどIDLコンパイラで生成したフォルダとファイルをコピーします。
通常であれば以下のようになります。
C:\Users\ユーザ名\workspace/MyIDLTestConsoleInにTestDataTyep_idl.py、Test、Test_POAをコピーします。
これで、いつものようにコーディングできます。
MyIDLTestConsoleIn.pyの コードを以下に示します。
以下のコードは抜粋となります。生成したテンプレートに当てはめて下さい。
-
import Test
-
-
class MyIDLTestConsoleIn(OpenRTM_aist.DataFlowComponentBase):
-
-
def __init__(self, manager):
-
OpenRTM_aist.DataFlowComponentBase.__init__(self, manager)
-
self._d_data = Test.MyLongSeq(RTC.Time(0, 0), [], 0)
-
"""
-
"""
-
self._keyboardOut = OpenRTM_aist.OutPort("keyboard", self._d_data)
-
-
def onExecute(self, ec_id):
-
self._d_data.data = []
-
self._d_data.length = 3
-
-
for i in range(self._d_data.length):
-
print("Please input (Long)data %d of 3") %(i)
-
self._d_data.data.append(input())
-
-
OpenRTM_aist.setTimestamp(self._d_data)
-
-
self._keyboardOut.write()
-
-
return RTC.RTC_OK
-
1行目
独自データ型をimportします。
-
7行目
OpenRTM-aist Python版では、基本データ型以外は正しく初期化されません。
赤字のように書き直し、正しく初期化してください。
-
12行目
sequence型の変数dataを初期化しています。
Pythonではsequence型はリストとして扱われます。
後ほど、キー入力された値をこのリストにappendしていくので、一周期ごとに初期化する必要があります。
-
13行目
TimedLongSeq型のデータの長さを格納する変数に、データの長さを代入しています。
-
16-18行目
TimedLongSeq型のデータ領域に1つずつ数値を格納します。
TimedLongSeq型のデータの長さ分だけ繰り返すので、今回は3回繰り返します。
-
17行目
Long型のデータを入力するようユーザに促します。
-
18行目
キーボードに入力されたデータを、データ領域に1つずつappendします。
-
20行目
タイムスタンプを取得し、格納します。
OpenRTM_aist.setTimestamp()を用いることで、タイムスタンプを取得し、格納することができます。
-
22行目
データを出力します。
5.2 MyIDLTestConsoleOutの作成
MyIDLTestConsoleOutのテンプレートの設定は以下のようになります。
-
モジュール名 MyIDLTestConsoleOut
-
ベンダ名 あなたの名前
-
モジュールカテゴリ TEST
-
実行周期 1000
-
アクションコールバック
onExecute
-
ポート名(InPort) receive
-
データ型 Test::MyLongSeq
-
変数名 data
-
表示位置 LEFT
-
言語 Python
設定が済んだらいつものようにテンプレートを生成してください。
テンプレート生成後は、先ほどと同様にプロジェクトのフォルダ内にIDLコンパイラで生成したフォルダとファイルをコピーします。
通常であれば以下のようになります。
C:\Users\ユーザ名\workspace/MyIDLTestConsoleOutにTestDataTyep_idl.py、Test、Test_POAをコピーします。
MyIDLTestConsoleOut.pyの コードを以下に示します。
以下のコードは抜粋となります。生成したテンプレートに当てはめて下さい。
-
import Test
-
-
class MyIDLTestConsoleOut(OpenRTM_aist.DataFlowComponentBase):
-
-
def __init__(self, manager):
-
OpenRTM_aist.DataFlowComponentBase.__init__(self, manager)
-
self._d_data = Test.MyLongSeq(RTC.Time(0, 0), [], 0)
-
"""
-
"""
-
self._receiveIn = OpenRTM_aist.InPort("receive", self._d_data)
-
-
def onExecute(self, ec_id):
-
if self._receiveIn.isNew():
-
self._d_data = self._receiveIn.read()
-
-
for i, data in enumerate(self._d_data.data):
-
print("data %d: %d") %(i, data)
-
-
print("sec: %d nsec: %d") %(self._d_data.tm.sec, self._d_data.tm.nsec)
-
-
return RTC.RTC_OK
-
1行目
独自データ型をimportします。
-
7行目
OpenRTM-aist Python版では、基本データ型以外は正しく初期化されません。
赤字のように書き直し、正しく初期化してください。
-
13-19行目
_receiveInというInPortオブジェクトのisNewメソッドで新しいデータがあるか調べます。
データを取得した場合、コンソールに表示します。
-
14行目
_receiveInのreadメソッドで受け取った値を読み込みます。
-
16-17行目
dataを1つずつコンソールに出力します。
*C++言語ではdata_lengthを用いてループ回数の決定できます。
pythonでは不要だったので、data_lengthは使用しませんでした。
-
19行目
受け取ったタイムスタンプをコンソールに表示します。
タイムスタンプは秒とナノ秒を格納する変数に分かれて格納されています。


MyIDLTestConsoleIn RTC
MyIDLTestConsoleOut RTC
コンパイルに成功すると、以下のフォルダやファイルが生成されます。
・TestDataTyep_idl.py
・Test
・Test_POA
cd C:\Python26
omniidl.exe -bpython TestDataType.idl