ControllerItemがLink->contactPointsを取得するタイミングについて

現象
AISTSimulatorItemでシミュレーションを行い、ControllerItemでLink->contactPointsを取得して使用させていただいているのですが、正常に取得できる周期とできない周期がありました。

原因
AISTSimulatorItemは毎周期、

  1. Link->contactPointsを全削除する
    choreonoid/src/Body/ConstraintForceSolver.cpp at 4ed77b902c9a86dd740b7b0eac5683a36c3076e1 · choreonoid/choreonoid · GitHub

  2. シミュレーション演算を行う

  3. Link->contactPointsを書き込む
    choreonoid/src/Body/ConstraintForceSolver.cpp at 4ed77b902c9a86dd740b7b0eac5683a36c3076e1 · choreonoid/choreonoid · GitHub

という手順で処理を行うため、1と3の間のタイミングでControllerItemが実行されるとLink->contactPointsが空になってしまうことが原因でした。

解決法
ControllerItemをisNoDelayMode: trueに設定したり、SimulatorItemをcontrollerThreads: falseに設定したりして、AISTSimulatorItemとControllerItemが並列で実行されることがないようにすると、毎周期正常に取得できるようになります。

同様の現象に遭遇して困った方の参考になれば幸いです。

また、ConstraintForceSolverの実装を変更し上記1と2の処理の実行順序を入れ替えることができると、AISTSimulatorItemとControllerItemを並列で実行してもこの現象がほぼ発生しなくなると思うのですが、可能でしょうか。

ごめんなさい、私の勘違いでした。

ControllerItem::control()関数中でLink->contactPointsを取得していたのが原因でした。

ControllerItem::input()関数中で取得するようにしたところ、正常に取得できました。

お騒がせしました。

状況をご説明いただきありがとうございます。
そうですね、そのように実装していただくのが正解となります。
もうお分かりかと思いますが、物理計算とコントローラの制御計算を並列化させつつも、両者の間のデータのやりとりを行うために、このような設計となっております。
ただマニュアルで十分に説明できていなかったかもしれません。その点分かりにくかったとしたらお詫びします。今後改善していきたいと思います。

お返事ありがとうございます。
少し自信が無いのですが、

ControllerItem

  • input(), output(): 物理演算と並列化しない. io->bodyにアクセス可. io->bodyはBodyアイテムが元々有するBodyオブジェクトと同じ.
  • control(): 物理演算と並列化する. io->bodyにアクセス不可.

SimpleController

  • control(): 物理演算と並列化する. io->bodyにアクセス可. io->bodyはBodyアイテムが元々有するBodyオブジェクトとは異なる.

という違いがあるのですね。勉強になりました。

そのご理解で間違いありません。
マニュアルで詳細を説明できていなく申し訳ないです。

あらためてまとめさせていただきますと、元々ControllerItemが基盤としてあって、それを継承したSimpleControllerItemでSimpleControllerを扱えるようにしています。SimpleControllerItem側で「物理演算で使用しているのとは別の入出力用のBodyオブジェクト(インスタンス)」を用意することで、「control関数内で排他制御を気にせずに入出力ができるようにし、よりシンプルな実装を可能とした」のがシンプルコントローラということになります。