top of page

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つの値が受け渡しができていれば成功です。

ロボコンマガジン
  1. #include "BasicDataType.idl"

  2.  

  3. module Test

  4. {

  5.   struct MyLongSeq

  6.   {

  7.      RTC::Time tm;

  8.      sequence<long> data;

  9.      long data_length;

  10.   };

  11. };

  • 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から一部抜粋したものです。

  1. module RTC {

  2.  

  3.   struct Time

  4.   {

  5.         unsigned long sec;    // sec

  6.         unsigned long nsec;   // nano sec

  7.   };

  8.  

  9.   struct TimedLong

  10.   {

  11.     Time tm;

  12.     long data;

  13.   };

  14.  

  15.   struct TimedLongSeq

  16.   {

  17.     Time tm;

  18.     sequence<long> data;

  19.   };

  20. };

  • 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の コードを以下に示します。

以下のコードは抜粋となります。生成したテンプレートに当てはめて下さい。

  1. import Test

  2.  

  3. class MyIDLTestConsoleIn(OpenRTM_aist.DataFlowComponentBase):

  4.  

  5.     def __init__(self, manager):

  6.         OpenRTM_aist.DataFlowComponentBase.__init__(self, manager)

  7.         self._d_data = Test.MyLongSeq(RTC.Time(0, 0), [], 0)

  8.         """

  9.         """

  10.         self._keyboardOut = OpenRTM_aist.OutPort("keyboard", self._d_data)

  11.  

  12.     def onExecute(self, ec_id):

  13.                 self._d_data.data = []

  14.                 self._d_data.length = 3

  15.  

  16.                 for i in range(self._d_data.length):

  17.                         print("Please input (Long)data %d of 3") %(i)

  18.                         self._d_data.data.append(input())

  19.  

  20.                 OpenRTM_aist.setTimestamp(self._d_data)

  21.  

  22.                 self._keyboardOut.write()

  23.     

  24.                 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の コードを以下に示します。

以下のコードは抜粋となります。生成したテンプレートに当てはめて下さい。

  1. import Test

  2.  

  3. class MyIDLTestConsoleOut(OpenRTM_aist.DataFlowComponentBase):

  4.  

  5.     def __init__(self, manager):

  6.         OpenRTM_aist.DataFlowComponentBase.__init__(self, manager)

  7.         self._d_data = Test.MyLongSeq(RTC.Time(0, 0), [], 0)

  8.         """

  9.         """

  10.         self._receiveIn = OpenRTM_aist.InPort("receive", self._d_data)

  11.  

  12.     def onExecute(self, ec_id):

  13.                 if self._receiveIn.isNew():

  14.                         self._d_data = self._receiveIn.read()

  15.  

  16.                         for i, data in enumerate(self._d_data.data):

  17.                                 print("data %d: %d") %(i, data)

  18.  

  19.                         print("sec: %d nsec: %d") %(self._d_data.tm.sec, self._d_data.tm.nsec)

  20.     

  21.                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

bottom of page