[openrtm-users 00406] Re: リングバッファからのデータ取得につきまして

kurihara shinji shinji.kurihara @ aist.go.jp
2008年 3月 28日 (金) 15:47:42 JST


産総研 中島様

栗原です。

> また、コールバック実装サンプルのページを記載のある、以下の2行
> 
>  #include <rtm/RingBuffer.h> 
>   InPort<TimedLong, RTC::RingBuffer> m_inIn;
> 
> を追記が必要と知らず、デフォルトでリングバッファを使用しているものと
> 思い込んでおりました。
> (昨日までは、通常のFIFOバッファを使用していた?)
OpenRTM-aist-0.4.1では、InPort,OutPortともに上記のように明示的にRingBuffer
を指定しなくてもデフォルトでRingBufferが使用される実装となっております。
しかし、現状のRingBufferの実装では、下記のようにwrite()の際にだけ読み込み
用ポインタ、書き込み用ポインタの操作をしているため、連続してwrite()が行わ
れた場合、read()で読めるデータは最後にwrite()したデータだけとなります。

 <OpenRTM-aist-0.4.1でのRingBuffer>
  r: 読み込み用ポインタ, w: 書き込み用ポインタ

   (1回目のwrite)
   +---+---+---+---+---+---+
   | r | w |   |   |   |   |   <--- バッファ
   +---+---+---+---+---+---+
     0   1   2   3   4   5     <--- 要素番号

   (2回目のwrite: ここで、r,wポインタ共にインクリメントされます)
   +---+---+---+---+---+---+
   |   | r | w |   |   |   | 
   +---+---+---+---+---+---+
     0   1   2   3   4   5   

   この時点でread()を行った場合、1回目のwrite()で書き込まれたデータ
   要素番号0に格納されておりますが、2回目のwrite()で読み込み用ポイ
   ンタが要素番号1を指すようになりますので、要素番号0のデータは取得
   する事ができません。

この問題の回避策としましては、write()では書き込み用のポインタだけの
操作を行い、read()の際に読み込み用のポインタを操作するといったリング
バッファを実装し、それをInPort側で使用して頂く事でデータの欠落は無く
なるのではないかと思います。
※ 自作のリングバッファではRingBufferを継承する必要があります。
   OpenRTM-aist/rtm/RingBuffer.hを参考にして下さい。

dataInComp.hで以下のように記述する事でユーザー作成のバッファが使用
されるようになります。

  #include "MyRingBuffer.h"
   InPort<TimedLong, RTC::MyRingBuffer> m_inIn;

以上、宣しくお願い致します。

> 
> 産総研の中島です。
> 
> 情報提供ありがとうございました。
> 結果は、栗原様の指摘された通りでした。
> 
> 早速コールバックの実装をしてトライしたところ、
> [dataInComp]側INPORTのバッファにはデータが正常に
> 入っており[dataOutComp]からの書き込みには問題が
> 無いことが分かりました。
> [dataInComp]の実行サイクルが必ずしも[dataOutComp]より早いわけではなく、
> read()-read()の間に複数回のwrite()があり、データの取得が出来ず結果的に
> 欠落した状態でした。
> 
> また、コールバック実装サンプルのページを記載のある、以下の2行
> 
>  #include <rtm/RingBuffer.h> 
>   InPort<TimedLong, RTC::RingBuffer> m_inIn;
> 
> を追記が必要と知らず、デフォルトでリングバッファを使用しているものと
> 思い込んでおりました。
> (昨日までは、通常のFIFOバッファを使用していた?)
> 
> 今回コールバックの実装に併せて追記しましたが、通常のバッファ/リングバッファ
> の両方でテストしても、結果は同じでした。
> 
> 
> ---
> 少し話しがRTMのMLの趣旨からずれますが、今回は、
> 
> [OpenHRP3]----------[dataOutComp]---[dataInComp]---[他のコンポーネント]
>            ↑ControllBridgeで接続
> 
> の構成でコンポーネントを走らせてシミュレーション値をデータポートで取得し
> ようとしておりましたが、
> 
> [dataInComp]実行周期は、”rtc.conf”内で「exec_cxt.periodic.rate」の値を
> 調整できると思いますが(今回はデフォルト1000で実施)
> 
> [dataOutComp]は”rtc.conf”内で「exec_cxt.periodic.type」に
> 'OpenHRPExecutionContext'を指定し使用していたので、実行周期は
> [dataInComp]と同期せず、デバッグしている限りでは、シミュレーションが
> 軽い場合(例えば何も処理しなかった)ではサイクルが早く、不定期にデータ
> をwrite()しているように思えました。そのため、[dataInComp]側が定周期で
> read()していては、データ待ちをしたり、取りこぼしたりという状態が発生
> するものかと思われます。
> 
> もし、OpenHRPを同じ用に使用している方で、何か情報がありましたら、お願いします。
> 
> 
> 
> > 産総研 中島様
> > 
> > 産総研タスクグループ 栗原です。
> > 
> > > [dataOutComp]が急にサイクルが早くなり、データを2度書き終えてしまった可能
> > > 性もありますが、これは考えにくいため、
> > > [dataOutComp]側がバッファへのデータ書き込みに失敗していると考えているの
> > > ですが、”ロック”がかかる状況が発生したのでしょうか?
> > dataOutCompの方が実行サイクルが早く、dataInComp側でread()から次回のread()ま
> > でにdataOutCompがwrite()を2回行う事がない事が保証されている場合は別ですが、
> > もし保証されていない(なんらかの原因で2回write()が行われる可能性がある)場合、
> > OpenRTM-aist-0.4.1のRingBufferの実装では、1回目のwrite()で書き込まれたデー
> > タは2回目のwirte()以降read()する事ができません。
> > ですので、データが欠落する事となります。
> > 
> > 問題の切り分けのために、dataInComp側にOnWriteコールバックオブジェクトを実装
> > し、OnWriteオブジェクトの中でもタイムスタンプデータをファイル等に出力し、
> > read()で得られるデータと比較する事でread()-read()間にwrite()が複数回行われ
> > たかどうかを判定する事ができますので、お試し頂ければと思います。
> > なお、コールバックオブジェクトの実装方法は、OpenRTMオフィシャルサイトのマニ
> > ュアル > RTコンポーネント作成 > データポートのあるコンポーネント > ConsoleOut
> > の実装 > コールバックオブジェクト に記述されております。
> > 
> > また、質問内容にあります"ロックがかかる状況"に関してですが、OutPortのwrite()
> > からInPortのread()までの間にOpenRTMでは相互排除のロック機構は実装されており
> > ません。
> > 
> > 以上、宣しくお願い致します。
> > 
> > 
> > 
> > > 安藤様
> > > 
> > > 産総研の中島です。
> > > 
> > > 2つのRTC間でデータポートでのデータ送受信を行う際に、
> > > 以下に示しますようにデータ取得にて欠落が発生するため、
> > > 原因or対処法についてご教示願います。
> > > 
> > > 
> > > <現象>
> > >   [dataOutComp][dataInComp]の2つコンポーネントがあり、データポートにて
> > > TimedDoubleSeqのデータを[dataOutComp]-->[dataInComp]方向に送信しており、
> > > 実行サイクルは「dataInComp」の方が早いため、何回かonExecuteがループして
> > > から「dataOutComp」よりデータを取得できているのですが、稀に、データを取
> > > 得していない状態が発生します。(以下のサンプルソースとデバッグ参照)
> > > 
> > >   データの取得は、まず、isNew()でバッファに新たなデータが入っていないか
> > > 確認し、なければ今回のonExecuteは何も処理せず、データがあればそれをread()
> > > しています。
> > > サイクルが早い[dataInComp]がデータを取得し損ねているのは、その時だけ
> > > [dataOutComp]が急にサイクルが早くなり、データを2度書き終えてしまった可能
> > > 性もありますが、これは考えにくいため、
> > > [dataOutComp]側がバッファへのデータ書き込みに失敗していると考えているの
> > > ですが、”ロック”がかかる状況が発生したのでしょうか?
> > > たとえば、[dataInComp]がisNew()でバッファにアクセスしている最中に、丁度
> > > [dataOutComp]がデータ書き込みを試みて、ロックがかかっているため失敗した
> > > など。
> > > 
> > >  ちなみに、[dataOutComp]はOpenHRP3のシミュレータとControllBridgeを介し
> > >  て、毎シミュレーションstep毎(0.002sec)にデータをもらい、そのまま、
> > > [ dataInComp]にスルーさせる構成です。
> > > 
> > > 
> > > 情報、よろしくお願いします。
> > > 
> > > 
> > > 
> > > ----------------------------------------------------------------
> > > [[dataOutComp側のonExecute部(必要部のみ記述)]]
> > > 
> > > onExecute(){
> > > 
> > >   //データセット
> > >   unsigned long sec,nsec;
> > > 
> > >    ・・・
> > >      「省略(0.002[sec]毎にシミュレータからデータ取得し、時刻をセット)」
> > >    ・・・
> > > 
> > >   m_dataOut.tm.sec = sec;
> > >   m_dataOut.tm.nsec = nsec;
> > > 
> > >   //データ出力
> > >   m_dataOut.write();
> > > 
> > >   //時刻デバッグ
> > >   double time = sec + 1.0e-9*nsec;
> > >   std::cout << "--[送信][TIME]: " << time << std::endl;
> > > 
> > >   return RTC::RTC_OK;
> > > }
> > > 
> > > 
> > > 
> > > [[dataInComp側のonExecute部(必要部のみ記述)]]
> > > 
> > > onExecute(){
> > > 
> > >   //新しいデータが得られたら実行
> > >   if (m_dataIn.isNew()) {
> > > 
> > >     //データ取得
> > >     m_dataIn.read();
> > > 
> > >     //データセット
> > >     unsigned long sec,nsec;
> > >     sec = m_dataIn.tm.sec;
> > >     nsec = m_dataIn.tm.nsec;
> > > 
> > >     //時刻デバッグ
> > >     double time = sec + 1.0e-9*nsec;
> > >     std::cout << "--[受信][TIME]: " << time << std::endl;
> > > 
> > >   } else {
> > >     //新しいデータが得られていないので処理をスキップ
> > >     std::cout << "---[SKIP] " << std::endl;			
> > >   } 
> > > 
> > >   return RTC::RTC_OK;
> > > 
> > > }
> > > 
> > > 
> > > 
> > > ----------------------------------------------------------------
> > > <dataOutComp側のデバッグ>
> > > ・・・
> > > [送信][TIME]: 0.788 
> > > [送信][TIME]: 0.79 
> > > [送信][TIME]: 0.792   <- このデータを送信はきちんとしているはず
> > > [送信][TIME]: 0.794 
> > > ・・・
> > > 
> > > <dataInComp側のデバッグ>
> > > ・・・
> > > [受信][TIME]: 0.788 
> > > ---[SKIP]
> > > ---[SKIP]
> > > ---[SKIP] 
> > > ---[SKIP] 
> > > [受信][TIME]: 0.79 
> > > ---[SKIP]
> > > ---[SKIP]
> > > ---[SKIP] 
> > > ---[SKIP] 
> > > ---[SKIP] 
> > >          <--  しかし、この部分のデータの取得が出来ていない(time:0.792)
> > > [受信][TIME]: 0.794 
> > > ---[SKIP]
> > > ---[SKIP]
> > > ---[SKIP] 
> > > [受信][TIME]: 0.796 
> > > ・・・
> > > 
> > > 
> > 
> > 
> > -- 
> > ----------
> > 栗原 眞二
> > shinji.kurihara @ aist.go.jp
> > kurihara @ imagination.co.jp
> 
> -----------------------------------------------------
> 〒305-8568 
> 茨城県つくば市梅園1-1-1 つくば中央第2  2-12棟
> 独立行政法人 産業技術総合研究所
>  知能システム研究部門 自律行動制御研究グループ
> 
>    中島 裕介 (Yusuke Nakajima)
> 
>  TEL:029-861-5080(内線55267)
>  mailto:y.nakajima @ aist.go.jp
> -----------------------------------------------------
> 


-- 
----------
栗原 眞二
shinji.kurihara @ aist.go.jp
kurihara @ imagination.co.jp



openrtm-users メーリングリストの案内