ロボット、千葉ロッテマリーンズについていいかげんなことを書きます。
×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
とりあえずRaspberry Pi Mouse関連のRTC、RTシステムのマニュアルを作成したので宣伝しておきます。
ちなみにRaspberry Pi Mouse フルキットで71280円です。
何だか高いなあ。
その割にはなんだか取扱説明書が雑と言うか、動作確認のコマンドを間違えるのはどうかと思います。
どこにも組み立て方がなかったのでRTCのマニュアルに載せました。しかも手書きで。
だから何だっていう感じはしますけど。写真撮れば良かったとか思っている人もいるとは思いますが、写真を加工するとコラ画像っぽくなるのがなんとなく嫌いです。
持っている人がいれば使ってください。
ちなみにRaspberry Pi Mouse フルキットで71280円です。
何だか高いなあ。
その割にはなんだか取扱説明書が雑と言うか、動作確認のコマンドを間違えるのはどうかと思います。
どこにも組み立て方がなかったのでRTCのマニュアルに載せました。しかも手書きで。
だから何だっていう感じはしますけど。写真撮れば良かったとか思っている人もいるとは思いますが、写真を加工するとコラ画像っぽくなるのがなんとなく嫌いです。
持っている人がいれば使ってください。
PR
今回はただの時事ネタです。
なんでも母校の校長が万引きで逮捕されてしまったらしく、これが全国ニュースで流れたとなると恥ずかしいです。yahooのトップページにも載っていたみたいですし、本当に勘弁してほしい。
まあ、この人の事を全く知らないし見た事もないので特に言う事もないのですけど。
万引きするのは勝手ですけど、辞表を出して学校とは無関係になってからやってほしいです。
いや別に無関係なら万引きをやっていいわけではないですけど。
赴任してからたった2年だったみたいですし、一体何がしたかったのでしょうか?嫌がらせですかね?
これが小学校、中学校、大学だったら何とも思わなかったのですが、高校は思い入れがあるので非常に遺憾です。
だいたい校長をやるのに柔道のメダリストを育てたとかよく分からない実績が必要なんですかね?
もっと大事なことがあると思うのですが。そもそもこの高校には柔道部以前に部活自体がないので全く意味がありません。体育の授業でも柔道をやった事は一度もありません。どういう経緯でこの人が赴任する事になったのか教えてほしいです。
何か不祥事やるならせめて笑いをとれよと思いますが、不謹慎なのでこれ以上はやめておきます。
なんでも母校の校長が万引きで逮捕されてしまったらしく、これが全国ニュースで流れたとなると恥ずかしいです。yahooのトップページにも載っていたみたいですし、本当に勘弁してほしい。
まあ、この人の事を全く知らないし見た事もないので特に言う事もないのですけど。
万引きするのは勝手ですけど、辞表を出して学校とは無関係になってからやってほしいです。
いや別に無関係なら万引きをやっていいわけではないですけど。
赴任してからたった2年だったみたいですし、一体何がしたかったのでしょうか?嫌がらせですかね?
これが小学校、中学校、大学だったら何とも思わなかったのですが、高校は思い入れがあるので非常に遺憾です。
だいたい校長をやるのに柔道のメダリストを育てたとかよく分からない実績が必要なんですかね?
もっと大事なことがあると思うのですが。そもそもこの高校には柔道部以前に部活自体がないので全く意味がありません。体育の授業でも柔道をやった事は一度もありません。どういう経緯でこの人が赴任する事になったのか教えてほしいです。
何か不祥事やるならせめて笑いをとれよと思いますが、不謹慎なのでこれ以上はやめておきます。
どうにも共有メモリについて根本的な勘違いをしていたみたいなのでメモしておきます。
間違ったことを書いている可能性が高いので、気づいたら指摘してください。
まずWindowsでCreateFileMappingやMapViewOfFileを使用してプロセス間通信を実装すると、ファイルを介して情報をやりとりするという事になるようです。
どこかにファイルを作成して、そのファイルの内容を実行しているプロセスの仮想アドレスにマッピングする事であたかもメモリのように操作できるという事らしいです。
このサイトの図2のようなイメージです。
WIndowsでは以下のソースコードです。
HANDLE fh=CreateFile("MapFile",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
HANDLE hMap = CreateFileMapping(fh , NULL , PAGE_READWRITE , 0 , 4 , NULL);
void* pshared = MapViewOfFile( hMap, FILE_MAP_ALL_ACCESS, 0, 0, 4 );
reinterpret_cast<int*>(pshared)[0] = 100;
UnmapViewOfFile( pshared );
CloseHandle( hMap );
CloseHandle(fh);
ちなみにCreateFileMappingの引数を変更すると仮想メモリに領域を確保
するようにできるらしいです。
HANDLE hMap = CreateFileMapping((HANDLE)0xFFFFFFFF , NULL , PAGE_READWRITE , 0 , 4 , ”MapFile”);
こうすればファイルの正確な場所が分からなくても空間名さえ分かっていればアクセスできるという事になります。
Linuxでは以下のソースコードに対応すると思います。
const int fd=open("MapFile",O_RDWR|O_CREAT,0666)
int *ptr=(int *)mmap(0,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
ptr[0] = 100;
munmap(ptr,4);
close(fd);
Pythonではmmapというライブラリで実装できます。
Windowsの場合、ファイルハンドルに0と空間名を与えると上と同じく仮想メモリに領域を確保するみたいです。
shmem = mmap.mmap(0, 4, 'MapFile')
結局のところハードディスク上のファイルを介して他のプロセスと情報のやり取りを行うので、通信速度は遅いように思えますが、それでもソケット通信等に比べれば圧倒的に速いみたいです。自分の環境で比較しただけなので確実な事は言えませんけど。
ここまではファイルの内容をマッピングする方法ですが、以下の方法もあるようです。
まずWindowsではReadProcessMemory関数、WriteProcessMemory関数を使用する事で他のプロセスの仮想アドレスに直接アクセスできるらしいです。
Linuxではshm_open関数、shmget関数等で共有メモリが使えるらしいです。
この場合、ファイルは/dev/shm以下に作成されます。この/dev/shmはディスク上ではなくメモリにマウントされているので高速な通信ができるらしいです。
つまりshm_open関数で/dev/shm/MapFIleを作成すると、一見ディスク上にファイルが作成されたように見えますが実はメモリ上で操作しているという事になります。
そして作成した/dev/shm/MapFIleを上と同じくmmapで仮想アドレスにマッピングすると、共有メモリとして扱えるようになります。
・・・・・ということで合っていますでしょうか?
ちなみに以下のコードで実装できます。
const int fd = shm_open( 'MapFile', O_RDWR|O_CREAT, 0 );
ftruncate( fd , 4);
void* ptr = mmap( NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 );
ptr[0] = 100;
munmap(ptr,4);
close( fd );
shm_unlink( 'MapFile' );
見て分かる通り、mmapの引数に入れるファイルディスクリプタを変更するだけです。
Pythonの場合は以下のコードで実装できます。
rt.close( fd )
rt.shm_unlink('MapFile')
間違ったことを書いている可能性が高いので、気づいたら指摘してください。
まずWindowsでCreateFileMappingやMapViewOfFileを使用してプロセス間通信を実装すると、ファイルを介して情報をやりとりするという事になるようです。
どこかにファイルを作成して、そのファイルの内容を実行しているプロセスの仮想アドレスにマッピングする事であたかもメモリのように操作できるという事らしいです。
このサイトの図2のようなイメージです。
WIndowsでは以下のソースコードです。
HANDLE fh=CreateFile("MapFile",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
HANDLE hMap = CreateFileMapping(fh , NULL , PAGE_READWRITE , 0 , 4 , NULL);
void* pshared = MapViewOfFile( hMap, FILE_MAP_ALL_ACCESS, 0, 0, 4 );
reinterpret_cast<int*>(pshared)[0] = 100;
UnmapViewOfFile( pshared );
CloseHandle( hMap );
CloseHandle(fh);
ちなみにCreateFileMappingの引数を変更すると仮想メモリに領域を確保
するようにできるらしいです。
HANDLE hMap = CreateFileMapping((HANDLE)0xFFFFFFFF , NULL , PAGE_READWRITE , 0 , 4 , ”MapFile”);
こうすればファイルの正確な場所が分からなくても空間名さえ分かっていればアクセスできるという事になります。
Linuxでは以下のソースコードに対応すると思います。
const int fd=open("MapFile",O_RDWR|O_CREAT,0666)
int *ptr=(int *)mmap(0,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
ptr[0] = 100;
munmap(ptr,4);
close(fd);
Pythonではmmapというライブラリで実装できます。
f = open('MapFile', 'r+')
m = mmap.mmap(f.fileno(), 4)
value = struct.pack("i",100)
value = struct.pack("i",100)
m.write(value)
m.close()
f.close()
Windowsの場合、ファイルハンドルに0と空間名を与えると上と同じく仮想メモリに領域を確保するみたいです。
shmem = mmap.mmap(0, 4, 'MapFile')
結局のところハードディスク上のファイルを介して他のプロセスと情報のやり取りを行うので、通信速度は遅いように思えますが、それでもソケット通信等に比べれば圧倒的に速いみたいです。自分の環境で比較しただけなので確実な事は言えませんけど。
ここまではファイルの内容をマッピングする方法ですが、以下の方法もあるようです。
まずWindowsではReadProcessMemory関数、WriteProcessMemory関数を使用する事で他のプロセスの仮想アドレスに直接アクセスできるらしいです。
Linuxではshm_open関数、shmget関数等で共有メモリが使えるらしいです。
この場合、ファイルは/dev/shm以下に作成されます。この/dev/shmはディスク上ではなくメモリにマウントされているので高速な通信ができるらしいです。
つまりshm_open関数で/dev/shm/MapFIleを作成すると、一見ディスク上にファイルが作成されたように見えますが実はメモリ上で操作しているという事になります。
そして作成した/dev/shm/MapFIleを上と同じくmmapで仮想アドレスにマッピングすると、共有メモリとして扱えるようになります。
・・・・・ということで合っていますでしょうか?
ちなみに以下のコードで実装できます。
const int fd = shm_open( 'MapFile', O_RDWR|O_CREAT, 0 );
ftruncate( fd , 4);
void* ptr = mmap( NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 );
ptr[0] = 100;
munmap(ptr,4);
close( fd );
shm_unlink( 'MapFile' );
見て分かる通り、mmapの引数に入れるファイルディスクリプタを変更するだけです。
Pythonの場合は以下のコードで実装できます。
try:
rt = ctypes.CDLL('librt.so')
except:
rt = ctypes.CDLL('librt.so.1')
m= mmap.mmap(fd, 4, mmap.MAP_SHARED)rt.shm_open.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.c_int]
rt.shm_open.restype = ctypes.c_int
rt.ftruncate.argtypes = [ctypes.c_int, ctypes.c_int]
rt.ftruncate.restype = ctypes.c_int
rt.close.argtypes = [ctypes.c_int]
rt.close.restype = ctypes.c_int
rt.shm_unlink.argtypes = [ctypes.c_char_p]
rt.shm_unlink.restype = ctypes.c_int
O_RDONLY = 0
O_WRONLY = 1
O_RDWR = 2
O_CREAT = 64
fd = rt.shm_open('MapFile',O_RDWR | O_CREAT ,0)
rt.ftruncate(fd, 4)fd = rt.shm_open('MapFile',O_RDWR | O_CREAT ,0)
value = struct.pack("i",100)
m.write(value)
m.close()rt.close( fd )
rt.shm_unlink('MapFile')
今回はコンポーネントオブザーバーのようにRTCが外部のサービスを使う方法について説明します。
まずは利用するサービスをIDLで定義します。
このようにSDOPackage::SDOServiceを継承したインターフェースを定義します。
次にこのようにOpenRTM_aist.SdoServiceConsumerBaseを継承したクラスを作成します。
ここで定義したtestServiceConsumerはtestServiceConsumerInit関数を呼び出すことでファクトリが登録されます。
そして外部からRTCのオブジェクトリファレンスを取得してadd_service_profile関数を呼び出すと、testServiceConsumerのinit関数が呼び出されます。
init関数ではRTCオブジェクトとプロファイルを受け取ることができます。
このプロファイルからサービスのプロバイダ等を取得することができます。
後はアクションでもポートでもいいのでリスナを追加して、その中でサービスを呼び出してやるとRTCからサービスを利用している事にはなります。
まあ独自に外部サービスを作成する人もあまりいないだろうし、あまり知ってても役には立たないような気はしますけど。
普通はRTC自体にサービスポートを作成してそれで使うので、何か事情がない限り上記の方法で追加するのはあまり好ましくないように思います。
次にコネクタのSubscription Typeを独自に作成する方法を説明します。
まずはこのようにPublisherBaseクラスを継承したクラスを作成します。
適当な例が思い浮かばなかったので、今回は1回write関数を呼び出すと2回データを送信するという謎仕様にしています。全く役には立ちません。
そしてrtc.confのmanager.modules.preloadに記述するか何かしらの方法でPublisherTestInit関数を呼び出してファクトリを登録するだけです。
後はRTシステムエディタで接続時にSubscription Typeをtestに設定してあげれば使えます。
まあこれも知っていても独自にパブリッシャーを作成する事もあまりないように思うので、あまり意味はないような気はします。
ただ独自に外部のモジュールを作成して何らかの機能を追加するにしても、RTCがそのモジュールに依存しないように設計するようにはする必要はあると思います。
例えばそのモジュールを使用するためにRTCのソースコードを変更する必要がある、というのは本末転倒なので避けるようにしましょう。
最後に独自のバッファの作り方を説明します。
と言いたいところですが、作り方自体はパブリッシャーやプロバイダ、コンシュマーとあまり変わらないので省略します。
こんな感じでBufferBaseクラスを継承したクラスを作成して、~Init関数でファクトリを登録するだけです。この例はwrite関数を呼び出すと変数にデータを書き込んで、read関数を読み込むと変数をNoneにするというだけなので、実用性は皆無です。
ただRTシステムエディタのコネクタの設定ウィンドウでバッファの種類を選択するドロップダウンリスト等はないみたいなので、詳細から直接入力してください。
dataport.buffer_typeという項目名で設定できます。
全然関係ないけどLuaのCORBA実装のOiLを使ってみたのですけど、何故かomniORBとかみたいな他のCORBA実装と通信できませんでした。何が違うのかは分かりませんけど、面倒なので調べるのはやめておきます。知っている人は教えてください。
にほんブログ村のロボットのカテゴリから
全然人が来ない・・・
まずは利用するサービスをIDLで定義します。
このようにSDOPackage::SDOServiceを継承したインターフェースを定義します。
次にこのようにOpenRTM_aist.SdoServiceConsumerBaseを継承したクラスを作成します。
ここで定義したtestServiceConsumerはtestServiceConsumerInit関数を呼び出すことでファクトリが登録されます。
そして外部からRTCのオブジェクトリファレンスを取得してadd_service_profile関数を呼び出すと、testServiceConsumerのinit関数が呼び出されます。
init関数ではRTCオブジェクトとプロファイルを受け取ることができます。
このプロファイルからサービスのプロバイダ等を取得することができます。
後はアクションでもポートでもいいのでリスナを追加して、その中でサービスを呼び出してやるとRTCからサービスを利用している事にはなります。
まあ独自に外部サービスを作成する人もあまりいないだろうし、あまり知ってても役には立たないような気はしますけど。
普通はRTC自体にサービスポートを作成してそれで使うので、何か事情がない限り上記の方法で追加するのはあまり好ましくないように思います。
次にコネクタのSubscription Typeを独自に作成する方法を説明します。
まずはこのようにPublisherBaseクラスを継承したクラスを作成します。
適当な例が思い浮かばなかったので、今回は1回write関数を呼び出すと2回データを送信するという謎仕様にしています。全く役には立ちません。
そしてrtc.confのmanager.modules.preloadに記述するか何かしらの方法でPublisherTestInit関数を呼び出してファクトリを登録するだけです。
後はRTシステムエディタで接続時にSubscription Typeをtestに設定してあげれば使えます。
まあこれも知っていても独自にパブリッシャーを作成する事もあまりないように思うので、あまり意味はないような気はします。
ただ独自に外部のモジュールを作成して何らかの機能を追加するにしても、RTCがそのモジュールに依存しないように設計するようにはする必要はあると思います。
例えばそのモジュールを使用するためにRTCのソースコードを変更する必要がある、というのは本末転倒なので避けるようにしましょう。
最後に独自のバッファの作り方を説明します。
と言いたいところですが、作り方自体はパブリッシャーやプロバイダ、コンシュマーとあまり変わらないので省略します。
こんな感じでBufferBaseクラスを継承したクラスを作成して、~Init関数でファクトリを登録するだけです。この例はwrite関数を呼び出すと変数にデータを書き込んで、read関数を読み込むと変数をNoneにするというだけなので、実用性は皆無です。
ただRTシステムエディタのコネクタの設定ウィンドウでバッファの種類を選択するドロップダウンリスト等はないみたいなので、詳細から直接入力してください。
dataport.buffer_typeという項目名で設定できます。
全然関係ないけどLuaのCORBA実装のOiLを使ってみたのですけど、何故かomniORBとかみたいな他のCORBA実装と通信できませんでした。何が違うのかは分かりませんけど、面倒なので調べるのはやめておきます。知っている人は教えてください。
にほんブログ村のロボットのカテゴリから
全然人が来ない・・・
F#とIronPythonのRTCのプログラムですが、色々おかしかったので修正しました。
F#やIronPythonで実装した方がいい時もあるかもしれないです。
C++、Python、Java、C#、VB.net、C++/CLI、Scala、Erlang、Jython、F#、IronPythonで
動くRTCは見たことがありますけど、それ以外にも何かあるかもしれないです。
さっき気付いたのですけど、InPortPushConnectorクラスとOutPortPushConnectorクラスのコンストラクタでプロバイダ(例:InPortCorbaCdrProvider)とコンシュマー(例:InPortCorbaCdrConsumer)のinit関数が呼び出されているのですが、何故かInPortPullConnectorクラスとOutPortPullConnectorクラスのコンストラクタではプロバイダ(例:OutPortCorbaCdrProvider)とコンシュマー(例:OutPortCorbaCdrConsumer)のinit関数は呼び出されていません。
Push型に設定したときにInPortCorbaCdrProviderクラスやInPortCorbaCdrConsumerクラスのinit関数は、InPortBaseクラスのcreateConsumer関数とcreateProvider関数で呼び出す分も含めて2回実行するわけですが、Pull型に設定したときにOutPortCorbaCdrProviderクラスやOutPortPullConnectorクラスのinit関数は何故か1回しか呼び出されていないのでかなり混乱しました。
C++版でもPython版でもこうなっているので仕様かもしれないです。
文字数が多くなったので簡単に言うと、Push型の場合はプロバイダ、コンシュマーのinit関数が2回呼ばれますけど、Pull型では1回しか呼び出されないというだけです。
それから独自の通信を実装してプロバイダ、コンシュマーのファクトリへの登録を行うと、RTシステムエディタで接続するときに何故かInterface_typeの選択肢が増殖します。
これはOutPortBaseクラスのinitProviders関数、initConsumers関数でappendProperty関数を使ってプロパティを追加するわけですが、appendProperty関数内部ではNVUtilのappendStringValue関数を使用しています。
initProviders関数、initConsumers関数でappendProperty関数の引数には、
corba_cdr, shared_memory, direct
のようにコンマで区切った文字列が渡されるわけですが、これがそのままappendStringValue関数に渡されています。
appendStringValue関数内部では現在のプロパティの値をコンマで分割した各文字列と新規に追加する文字列を比較するわけですが、上記のような文字列を直接入力すると正常に比較ができません。
例えば、
事前にあるプロパティにこういう値が入力されているとします。
test1, test2, test3
そして、新たに以下の要素を追加しようとします。
test1, test4, test3
すると以下の文字列同士の比較を行って、一致した場合は追加しないようにします。
まあ別にこの現象が起こっても困るわけではないので、あまり気にする事もないかもしれないです。
にほんブログ村のロボットのカテゴリから
全然人が来ない・・・
F#やIronPythonで実装した方がいい時もあるかもしれないです。
C++、Python、Java、C#、VB.net、C++/CLI、Scala、Erlang、Jython、F#、IronPythonで
動くRTCは見たことがありますけど、それ以外にも何かあるかもしれないです。
さっき気付いたのですけど、InPortPushConnectorクラスとOutPortPushConnectorクラスのコンストラクタでプロバイダ(例:InPortCorbaCdrProvider)とコンシュマー(例:InPortCorbaCdrConsumer)のinit関数が呼び出されているのですが、何故かInPortPullConnectorクラスとOutPortPullConnectorクラスのコンストラクタではプロバイダ(例:OutPortCorbaCdrProvider)とコンシュマー(例:OutPortCorbaCdrConsumer)のinit関数は呼び出されていません。
Push型に設定したときにInPortCorbaCdrProviderクラスやInPortCorbaCdrConsumerクラスのinit関数は、InPortBaseクラスのcreateConsumer関数とcreateProvider関数で呼び出す分も含めて2回実行するわけですが、Pull型に設定したときにOutPortCorbaCdrProviderクラスやOutPortPullConnectorクラスのinit関数は何故か1回しか呼び出されていないのでかなり混乱しました。
C++版でもPython版でもこうなっているので仕様かもしれないです。
文字数が多くなったので簡単に言うと、Push型の場合はプロバイダ、コンシュマーのinit関数が2回呼ばれますけど、Pull型では1回しか呼び出されないというだけです。
それから独自の通信を実装してプロバイダ、コンシュマーのファクトリへの登録を行うと、RTシステムエディタで接続するときに何故かInterface_typeの選択肢が増殖します。
これはOutPortBaseクラスのinitProviders関数、initConsumers関数でappendProperty関数を使ってプロパティを追加するわけですが、appendProperty関数内部ではNVUtilのappendStringValue関数を使用しています。
initProviders関数、initConsumers関数でappendProperty関数の引数には、
corba_cdr, shared_memory, direct
のようにコンマで区切った文字列が渡されるわけですが、これがそのままappendStringValue関数に渡されています。
appendStringValue関数内部では現在のプロパティの値をコンマで分割した各文字列と新規に追加する文字列を比較するわけですが、上記のような文字列を直接入力すると正常に比較ができません。
例えば、
事前にあるプロパティにこういう値が入力されているとします。
test1, test2, test3
そして、新たに以下の要素を追加しようとします。
test1, test4, test3
すると以下の文字列同士の比較を行って、一致した場合は追加しないようにします。
- "test1"と"test1, test4, test3"
- "test2"と"test1, test4, test3"
- "test3"と"test1, test4, test3"
まあ別にこの現象が起こっても困るわけではないので、あまり気にする事もないかもしれないです。
にほんブログ村のロボットのカテゴリから
全然人が来ない・・・