忍者ブログ
ロボット、千葉ロッテマリーンズについていいかげんなことを書きます。
[7]  [8]  [9]  [10]  [11]  [12]  [13]  [14]  [15]  [16]  [17
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

前回はpush型の通信を扱いましたが、今回はpull型で独自の通信を実装してみます。

とりあえずOutPortCorbaCdrConsumer、OutPortCorbaCdrProviderクラスを継承したクラスを適当に作成してください。



OutPortTestProvider.py
import OpenRTM_aist
class OutPortTestProvider(OpenRTM_aist.OutPortCorbaCdrProvider):
  def __init__(self):
    OpenRTM_aist.OutPortCorbaCdrProvider.__init__(self)
    self.setInterfaceType("test")
  def __del__(self):
    OpenRTM_aist.OutPortCorbaCdrProvider.__del__(self)
    if os.path.exists(self.file_path):
      os.remove(self.file_path)
def OutPortTestProviderInit():
  factory = OpenRTM_aist.OutPortProviderFactory.instance()
  factory.addFactory("test",
                     OutPortTestProvider,
                     OpenRTM_aist.Delete)
OutPortTestConsumer.py

import OpenRTM_aist
class OutPortTestConsumer(OpenRTM_aist.OutPortCorbaCdrConsumer):
  def __init__(self):
    OpenRTM_aist.OutPortCorbaCdrConsumer.__init__(self)
def OutPortTestConsumerInit():
  factory = OpenRTM_aist.OutPortConsumerFactory.instance()
  factory.addFactory("test",
                     OutPortTestConsumer,
                     OpenRTM_aist.Delete)


あとはrtc.confのmanager.modules.preloadにファイル名を記述して初期化関数を呼び出すようにしてください。



これで準備完了です。
前回と同じくOutPortCorbaCdrConsumer、OutPortCorbaCdrProviderクラスを継承しただけなので通常の通信と何も変わりません。


とりあえずRTC_AからRTC_Bにデータを送信するとして手順を説明します。
今回はpull型なのでRTC_B側にあるOutPortCorbaCdrConsumerのget関数内でoutportcdr.get関数を使ってデータを取得しています。outportcdrはDataPort.idlで定義されたOutPortCdrのオブジェクトリファレンスなので、これを使ってOutPortCorbaCdrProviderのget関数を呼び出しています。OutPortCorbaCdrProviderのget関数内ではバッファからデータを取り出して送信するようにしています。この時点でRTC_Bにデータは送信されています。


とりあえず前回のコードを少し拡張してpull型にも対応させたものがこれです。
rtc.confに4つもファイル名を書くのは面倒なので纏めてみました。
C++で実装する場合もまとめてビルドして、OutPort~ConsumerInit・OutPort~ProviderInit、InPort~ConsumerInit・InPort~ProviderInitを呼び出す関数を作成しておくと使いやすいかもしれないです。








にほんブログ村 科学ブログ ロボットへ
にほんブログ村のロボットのカテゴリから
全然人が来ない・・・

人気ブログランキングへ
PR
今回は独自の通信方法の実装方法をメモしておきます。

Push型の通信、OpenRTM-aistのPython版を前提にしていますが、C++版でも手順はほぼ同じです。

まずはOpenRTM-aistのPython版に含まれるInPortCorbaCdrConsumer.py、InPortCorbaCdrProvider.pyのクラスを継承したクラスを作成します。

とりあえず、InPortTestConsumer.py、InPortTestProvider.pyというファイルを作成してください。

後は適当にこんな感じでコードを書いておきます。



InPortTestConsumer.py
import OpenRTM_aist
class InPortTestConsumer(OpenRTM_aist.InPortCorbaCdrConsumer):
  def __init__(self):
    OpenRTM_aist.InPortCorbaCdrConsumer.__init__(self)
 
def InPortTestConsumerInit(manager):
  factory = OpenRTM_aist.InPortConsumerFactory.instance()
  factory.addFactory("test",
                     InPortTestConsumer,
                     OpenRTM_aist.Delete)

InPortTestProvider.py
import OpenRTM_aist
class InPortTestProvider(OpenRTM_aist.InPortCorbaCdrProvider):
  def __init__(self):
    OpenRTM_aist.InPortCorbaCdrProvider.__init__(self)
    self.setInterfaceType("test")
def InPortTestProviderInit(manager):
  factory = OpenRTM_aist.InPortProviderFactory.instance()
  factory.addFactory("test",
                     InPortTestProvider,
                     OpenRTM_aist.Delete)



次にInPortTestConsumer、InPortTestProviderのファクトリを登録しておく必要があるため、rtc.confのmanager.modules.preloadにInPortTestConsumer.py, InPortTestProvider.pyを記述しておくことで上記の初期化関数を呼び出します。

ただInPortCorbaCdrConsumer.py、InPortCorbaCdrProvider.pyの初期化関数には引数がないためrtc.confのmanager.modules.preloadに記述するとエラーが出て読み込めないみたいです。上のコードで使いもしないのにmanagerの引数を用意しているのはそのためです。





これで準備完了です。
適当なRTCを起動してデータポートを接続してください。


上手くできていればRTシステムエディタのコネクタプロファイル設定のInterface Typeにtestが追加されているはずなので、これを選択してコネクタを接続してください。





後はいつもどおり通信できていれば成功です。
ただ今回はInPortCorbaCdrProvider、InPortCorbaCdrConsumerを継承して作成しただけなので、通常の通信方法と何も変わりません。



独自の通信方法を実装するために詳細を見ていきます。
とりあえずRTC_A、RTC_Bの2つのコンポーネントがあって、RTC_AからRTC_Bにデータを送信するという事にします。

まず最初OutPortConnector.pyのwrite関数を見てください。
cdrMarshal関数でデータを符号化した後にself._publisher.write関数に渡しています。
この時点でデータはCDRというバイト列に変換されています。
当然ですがこの時点ではまだデータはRTC_A側にあります。

その後、データはInPortCorbaCdrConsumerのput関数に渡されます。
put関数を見てみると、引数のdataをinportcdr.put関数に渡しています。
inportcdrはDataPort.idlで定義されたInPortCdrのオブジェクトリファレンスなので、これを使ってInPortCorbaCdrProviderのput関数を呼び出しているという事になります。
つまりこの時点でRTC_AからRTC_Bにデータが送られたという事にはなります。pull型だと少し話は変わりますけど。

InPortCorbaCdrProviderのput関数でデータを受け取ると、self._connector.write関数に渡しています。そしてデータを受け取ったコネクタ(InPortPushConnector)のwrite関数内でcdrUnmarshalによりCDRからデータを復号化してバッファに書き込んでいます。



つまり新たにInPort~Consumer、InPort~Providerクラスを作成したとして、既にCDRに符号化したデータの通信する方法を変更する事ぐらいしか出来ないので、データを直接変数に書き込もうとした場合などはOpenRTM-aistのソースコード自体を変更するしかありません。


このコードではInPortTestConsumerクラスでput関数を定義してファイルにデータを書き込み→InPortTestProviderクラスのput関数内でファイルを読み込むという事をやっています。
ファイル名を別に送信していますが、実際にはコネクタプロファイルで設定できた方が効率的だとは思います。








今回は実験のためにInPortCorbaCdrProviderクラスとInPortCorbaCdrConsumerクラスを継承して作成しましたが、実際にはInPortProviderクラスとInPortConsumerクラスを継承して作成する事にはなると思います。



独自の通信方法を実装する場合は①あまり複雑にしない事、②仕様書を用意する事が必要かもしれないです。でないと他の言語で実装ができません。











にほんブログ村 科学ブログ ロボットへ
にほんブログ村のロボットのカテゴリから
全然人が来ない・・・

人気ブログランキングへ
前回のomniORBでSSLを使う方法について色々と補足をしておきます。

まず色々試した結果、以下のようなエラーが出るかもしれない事が分かりました。

① omniORB: openSSL error detected in sslAddress::connect. Reason: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
② omniORB: openSSL error detected in sslAddress::connect. Reason: error:14082174:SSL routines:ssl3_check_cert_and_algorithm:dh key too small
③omniORB: openSSL error detected in SSL accept from giop:ssl:[::ffff:192.168.0.2]:58767 : error:04075070:rsa routines:RSA_sign:digest too big for rsa key

まず①ですが-ORBsslVerifyMode noneというオプションをORB初期化時に追加すれば一応は消えます。あまり良くはないだろうけど、試すだけならこれでも大丈夫です。

②ですが、これはOpenSSLのバージョンが新しいと発生するみたいです。なんでもOpenSSLの新しいバージョンではDHパラメータが2048bit必要だから発生するらしいけど、どこで設定するのかは不明です。詳しい人は教えてください。1.0.2は駄目で、0.9.8は大丈夫みたいなのでこれをインストールしてください。

③ですが、これは秘密鍵の長さが短い場合に発生するみたいです。512bitだと発生するので1024bit以上にしておけば大丈夫だとは思います。



とりあえず手順を纏めておきます。
Python、omniORBpyはインストール済みと言う事で話を進めます。

まずはここからOpenSSLの0.9.8をインストールしてください。
一応、インストールしたディレクトリ(C:\OpenSSL\bin\)にパスを通しておくと便利かもしれないです。


簡単な動作確認のプログラムを作成したので、ここからダウンロードしてください。

予めネーミングサービスを起動しておいてください。
test_srv.py(サーバー)を起動した後に、test_clt.py(クライアント)を起動して通信ができていれば成功しているはずです。


SSLのよる通信を自作のプログラムで使用するまでの手順を説明します。

まずは証明書、秘密鍵を作成する必要があるので以下のコマンドで作成してください。
openssl genrsa 1024 > private-key.key
openssl req -new -key private-key.key > private-key.csr
openssl x509 -days 3650 -req -signkey private-key.key < private-key.csr > certs.crt
名前は適当に変更してください。



次にソースコードを見ていきます。
まずは何にせよsslTPをインポートします。


from omniORB import sslTP




次に証明書、秘密鍵、パスワードを設定してください。
sslTP.certificate_authority_file("certs.crt")
sslTP.key_file("private-key.key")
sslTP.key_file_password("test")



そしてSSLを有効にするためにオプションを追加します。
sys.argv.extend(["-ORBendPoint","giop:ssl::"])



さらに証明書がいい加減でも通信できるように以下のような記述を追加します。

sys.argv.extend(["-ORBsslVerifyMode","none"])
※小技ですが、以下のように環境変数でも設定できます。

os.environ['ORBendPoint'] = 'giop:ssl::'
os.environ['ORBsslVerifyMode'] = 'none'

これで準備完了です。
他に変更する点はありません。


ただ、これでは本当にSSLで暗号化して通信しているのかは謎です。
一応、ORBtraceLevelオプションを25にして詳細まで表示するようにすれば、

クライアント
omniORB: Scavenger task execute.
omniORB: LocateRequest to remote: root<0>
omniORB: Client attempt to connect to giop:ssl:192.168.0.2:63241
omniORB: Client opened connection to giop:ssl:192.168.0.2:63241
omniORB: sendChunk: to giop:ssl:192.168.0.2:63241 38 bytes
omniORB: inputMessage: from giop:ssl:192.168.0.2:63241 20 bytes
omniORB: Send codeset service context: (ISO-8859-1,UTF-16)
omniORB: sendChunk: to giop:ssl:192.168.0.2:63241 110 bytes
omniORB: inputMessage: from giop:ssl:192.168.0.2:63241 46 bytes
サーバー
omniORB: Accepted connection from giop:ssl:[::ffff:192.168.0.2]:63278 because of
 this rule: "* unix,ssl,tcp"
omniORB: inputMessage: from giop:ssl:[::ffff:192.168.0.2]:63278 38 bytes
omniORB: Handling a GIOP LOCATE_REQUEST.
omniORB: sendChunk: to giop:ssl:[::ffff:192.168.0.2]:63278 20 bytes
omniORB: inputMessage: from giop:ssl:[::ffff:192.168.0.2]:63278 110 bytes
omniORB: Receive codeset service context and set TCS to (ISO-8859-1,UTF-16)
echoString() called with message: Hello from Python
omniORB: sendChunk: to giop:ssl:[::ffff:192.168.0.2]:63278 46 bytes
omniORB: Scanning Python thread states.

と言う風な感じでSSLで通信しているらしいという事は分かるのですが、実態がどうなっているかは謎です。確認する方法があれば教えてください。













にほんブログ村 科学ブログ ロボットへ
にほんブログ村のロボットのカテゴリから
全然人が来ない・・・

人気ブログランキングへ
最近知った事をメモしていきます。

まずomniORBpyでSSLでの保護を有効にする手順をメモします。

最初にをsslTPインポートしてください。

from omniORB import sslTP

この際にdll load failedが出る場合はOpenSSLをインストールしてください。


次にこんな感じで鍵ファイル、パスワードを指定してください。
ORB_initの前に記述するようにしてください。
sslTP.certificate_authority_file("root.pem")
sslTP.key_file("client.pem")
sslTP.key_file_password("password")
鍵ファイルはOpenSSLで適当に作成してください。

そしてORB_initのオプションに-ORBendPoint giop:ssl::を追加すれば有効になっているらしい。
有効になっているかどうかをどう確認するのかは分かりませんけど。






次にオブジェクトリファレンスからサーバントを取得する方法です。
このコードのonExecuteみたいにするだけです。
Pythonだから簡単に見えますけど、C++だとダイナミックキャストをする必要があるので簡単ではありません。特にサービスポートの場合は難しいように思います。required側では実態が分からないのでどうすればキャストできるのでしょうね?
CORBAの初歩らしいので今更感がするのですが、実際に使ったことがなかったのであまり理解していませんでした。まあ知ったかぶりしてもいい事なんてないし。










にほんブログ村 科学ブログ ロボットへ
にほんブログ村のロボットのカテゴリから
全然人が来ない・・・

人気ブログランキングへ
RTCはマネージャで動的ライブラリをロードしてRTCを起動する事を基本としています。
この場合、関数やクラス内で使用したグローバル変数は共有されているので複数のRTCを起動すると都合が悪いです。

なので極力使わない事をお勧めします。


初歩的な事ですけど、

#include <stdlib.h>
#include <iostream>
class testClass
{
public:
        testClass(int v)
        {
                testValue = v;
        };
        void testPrint()
        {
                std::cout << testValue << std::endl;
        }
        int testValue;
};
int main()
{
        testClass A(10);
        testClass B(20);
        A.testPrint();
        B.testPrint();
        return 0;
}



#include <stdlib.h>
#include <iostream>
int testValue;
class testClass
{
public:
        testClass(int v)
        {
                testValue = v;
        };
        void testPrint()
        {
                std::cout << testValue << std::endl;
        }
};
int main()
{
        testClass A(10);
        testClass B(20);
        A.testPrint();
        B.testPrint();
        return 0;
}

では動作が違います。

静的メンバ変数やシングルトンも同じです。
確かに使った方が便利な場合も多いのですが、使いどころは考えてください。


先ほどの例だと、静的メンバ変数は以下のようになります。

#include <stdlib.h>
#include <iostream>
class testClass
{
public:
        testClass(int v)
        {
                testValue = v;
        };
        void testPrint()
        {
                std::cout << testValue << std::endl;
        }
        static int testValue;
};
int testClass::testValue;
int main()
{
        testClass A(10);
        testClass B(20);
        A.testPrint();
        B.testPrint();
        return 0;
}

つまりこの場合も変数testValueの実体は1つしかないので後から初期化したクラスで上書きされます。
シングルトンの場合は以下のようになります。


#include <stdlib.h>
#include <iostream>
class testClass
{
private:
        testClass(int v)
        {
                testValue = v;
        };
public:
        static testClass& get_instance(int v) {
                static testClass inst(v);
                return inst;
        }
        void testPrint()
        {
                std::cout << testValue << std::endl;
        }
        int testValue;
};
int main()
{
        testClass A = testClass::get_instance(10);
        testClass B = testClass::get_instance(20);
        A.testPrint();
        B.testPrint();
        return 0;
}
この場合はクラスの実体が1つしか生成されません。


Pythonの場合少し分かりづらいのですが、

# -*- coding: utf-8 -*-
class testClass:
    def __init__(self, v):
        self.testValue = v
    def testPrint(self):
        print self.testValue
        
def main():
    A = testClass(10)
    B = testClass(20)
    A.testPrint()
    B.testPrint()
if __name__ == "__main__":
    main()


と、
# -*- coding: utf-8 -*-
class testClass:
    testValue = 0
    def __init__(self, v):
        testClass.testValue = v
    def testPrint(self):
        print self.testValue
        
def main():
    A = testClass(10)
    B = testClass(20)
    A.testPrint()
    B.testPrint()
if __name__ == "__main__":
    main()

では動作が違います。
下のコードはtestValueが静的な変数になっています。




つまりrtcdでRTCを起動する場合にグローバル変数を使うと、別々のRTCから同じ変数が操作される可能性があります。

int testValue;

(中略)

RTC::ReturnCode_t testRTC::onExecute(RTC::UniqueId ec_id)
{
     testValue += 1;
}

(以下略)


この場合、testRTC0とtestRTC1を起動したとすると変数testValueは共有されています。


バグの温床になる可能性が高いので注意してください。
















やはり盗用の件を放置するのはまずいです。
過去にこういう問題があったにも拘らず充分な対策をしていなかったという事なので、もう一度同じ問題が起きた時の印象が悪いです。
流石に責任を取れと言う事にはならないと思いますけど、印象としては最悪です。

既に今年の作品が公開されてしまっている時点でいつこうなってもおかしくはありません。
しかも盗用をした作者と同じ大学院の人が応募していますね。
それも例の作品の共著者の一部と研究室が同じだったと思います。
まだソースコードは公開されていないみたいですが、問題が発生する可能性が極めて高くなりました。
と言うか去年あんな事があったら普通は参加するのを躊躇うと思うのですが、一体どういう心境なのかを聞いてみたいです。何の処分もなかったので味を占めたという事でしょうか?


仮に例の作品と関係のある研究室だとすれば何の謝罪もなしに参加する事自体が大問題です。
このままRTM自体と関わらないのであればどう責任を取ろうとどうでもよかったのですが、これは癪に障ります。

言い過ぎかもしれませんが、この作品を審査する必要はないとすら思っています。
僕もこの作品のソースコードは読まないつもりです。なのでこの作品に盗用があったとしても僕は知りません。

そもそもあれは作者個人の問題ではありません。
ソースコードを公開する前に確認しなかった管理責任の問題です。
盗用したソースコードが9割近くを占めているのに盗用元の著者が指摘するまで1年近くも気付かなかったというのは常軌を逸しています。
普通は著作権に問題がないかどうかぐらいは確認するわけで、ソースコードのほとんどに問題があるのに気づかないのはただの怠慢です。
なので作者が違ったから盗用はないだろうと考える事はできません。

だいたい、数十人単位の人間に迷惑をかけたという事を理解しているのでしょうか?






コンテスト運営側にしても盗用した作品と関連する研究室にしても、いつ爆発するかわからない爆弾を抱えてしまっている状態です。
ちなみに爆発したらHSPプログラムコンテスト2013みたいになります。


他人事ですけど、こんなことになったら大変ですね。










にほんブログ村 科学ブログ ロボットへ
にほんブログ村のロボットのカテゴリから
全然人が来ない・・・

人気ブログランキングへ
カレンダー
03 2024/04 05
S M T W T F S
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
フリーエリア
最新CM
[08/31 ysuga]
[08/31 Nobu]
[08/31 ysuga]
[12/11 Nobu]
[12/11 Kanamura]
最新TB
プロフィール
HN:
Nobu
年齢:
35
性別:
男性
誕生日:
1988/09/22
職業:
あれ
趣味:
妄想、自堕落
バーコード
ブログ内検索
P R
カウンター
忍者ブログ [PR]