sample/OpenRTM にあるBodtIoRTCの改造を試みています.
- デバッグのための実行中に文字や数値をChoreonoidのメッセージビューに出すにはどうしたらいいでしょうか?
- choreonoidのソースツリー以外の場所でBodtIoRTCのsoファイルを作るには,どのようにCMakeLists.txtを書けばいいでしょうか?
sample/OpenRTM にあるBodtIoRTCの改造を試みています.
デバッグ出力についてですが、RTCがChoreonoidと同じプロセスとして動いている場合は、通常のプラグインと同様に以下のコードで出力できると思います。
#include <cnoid/MessageView>
cnoid::MessageView::instance()->putln("Hello World !");
RTCとChoreonoidが別プロセスで動いている場合でも、メッセージをCORBA通信でChoreonoidに送って表示してもらう以下のような方法もあるようです。本方法を使うにはCorbaPluginを有効化する必要があり、かつ、CorbaPluginは4年前に作られたっきりのプラグインのようなので、実際に動くかどうかはやや不安ですが。
ソースツリーの外でのコンパイルに関して、choreonoidはpkg-configの形式でライブラリ情報を公開してくれているので、cmakeのfind_package文を使って外部からライブラリとしてリンクできなくもないのですが、必要なcmakeマクロ(例えばBodyIoRTCの場合はadd_cnoid_body_io_rtcが必要)がchoreonoidのソースツリーの中でしか定義されていないことが多く、ソースツリーの中でコンパイルしたほうがトラブルが少ないように思います。
choreonoid/extフォルダの下に外部レポジトリをチェックアウトして配置しておくとソースツリーの一部として自動で検出して取り込んでくれるので、
choreonoidをチェックアウト
choreonoid/extフォルダ以下に自分のモジュールをチェックアウト(自分のモジュールは別レポジトリとして管理)
choreonoidフォルダでコンパイル
ということをやることが多いです。
yosukeさんご回答ありがとうございます。
今回対象となっているのはBodyIoRTCなので、よりマッチしたやり方もありますので、紹介します。
BodyIoRTCには、initializeIOやinitializeSimulationといった初期化関数に、ControllerIO* ioという引数が渡されます。
このControllerIOというのは src/Body/ControllerIO.h で定義されているクラスで、そこに std::ostream を返す os() という関数があります。
ですので、例えば
bool BodyIoRTCX::initializeSimulation(ControllerIO* io)
{
io->os() << "Hello World !" << std::endl;
}
などとしてもOKです。
このioオブジェクトをとっておけば、他の関数内でも使用できます。
ただしBodyIoRTC.h のコメントにも注意書きがあるように、initializeIO関数に渡されたioオブジェクトは他の関数で使ってはいけません。
choreonoidのソースツリー以外の場所でBodtIoRTCのsoファイルを作るには,どのようにCMakeLists.txtを書けばいいでしょうか?
これについては、最近CMakeのconfigファイルを導入しまして、ソースツリー以外の場所で作成する関連プログラムに関して、そこのCMakeLists.txtにて
find_package(Choreonoid)
としておけば、後は
といった変数をビルドに使えるようになります。
それで、BodyIoRTCについても、このやりかたでビルドに必要な情報をとってこれるようにする必要があるのですが、すみません、まだその部分まで整備しきれていませんでした。
これを行うためのファイル自体は、Choreonoidソースの misc/cmake 以下にある choreonoid-config.cmake.in というファイルになります。ここからchoreonoid-config.cmakeが生成されて、所定のディレクトリにインストールされると、上記のfind_packageが使えるようになります。
なので後はこのchoreonoid-config.cmake.inにBodyIoRTCをビルドするのに必要な情報を記述すればよいことになります。それについてはなるべく早く対応したいと思いますが、もしできそうだったら試してみて下さい。
回答ありがとうございます.
BodyIoRTCを継承した自作のクラスの中で試してみました.
initializeIO()の中で,io->os() << … とするとメッセージビューに表示されます.一方,
initializeSimulation()の中で,io->os() << … とするとchorenoidを起動したシェルに表示されます.
そういう仕様でしょうか?
いえ、想定していたのは、どちらもメッセージビューに表示されることです。
すみません、バグだと思うので確認しますので、しばらくお待ちください。
ご指摘ありがとうございます。
回答ありがとうございます.
教えていただいた方法をコントローラRTC のRTCモジュールのコードで試そうとしています.
#include <cnoid/MessageView>
を入れるとビルド時に
"QWidget: そのようなファイルやディレクトリはありません",
というエラーになってしまいます.どうすれば解決できますか?
回答ありがとうございます.
ちょっと手に負えそうにないので,しばらくはソースツリーの下で開発してみます.
本家のリポジトリをフォークしました.
ただしBodyIoRTC.h のコメントにも注意書きがあるように、initializeIO関数に渡されたioオブジェクトは他の関数で使ってはいけません。
とのことですが,初期化の段階でなくシミュレーションループの中で変数の値などを確認したい場合にメッセージビューは使えませんか?
おそらくソースツリーの下でコンパイルする形にしないでQtが見つかっていない場合、そのエラーが出ると思います。
まずは、ソースツリーの下で動く状態まで持っていくのがおすすめですが、もし、ソースツリー外で作業する場合はCMakeLists.txtに以下の行が必要かと思います。
find_package(Qt5Widgets CONFIG REQUIRED)
initializeSimulation関数に渡されたioオブジェクトはそのように使うことができます。
initializeIO: アイテム作成時(ロード時)に呼ばれる。システムエディターでの接続作業等、シミュレーション開始前に行いたい処理がある場合、そのための準備をここでする。ioの対象はBodyItem->body()となる。
initializeSimulation: シミュレーション開始時に呼ばれる。ioの対象はシミュレータ内部でコピーされて物理計算に使われるbodyオブジェクトとなる。
そのような次第で、io->os()を使ってMessageViewに出力できますので、MessageViewを直接使う必要はありません。BodyIoRTCは本来GUIとは独立させたい部分なので、MessageViewを直接使用するのは避けた方がよいです。(yosukeさん、ご回答に対してこのようなコメントで申し訳ないです。)
ただし
initializeSimulation()の中で,io->os() << … とするとchorenoidを起動したシェルに表示されます.
というバグがあるようですので、これについては確認の上修正したいと思います。
ソースツリーの下でビルドしています.具体的には,sample/OpenRTMの下で,TankJoystickControllerRTC.{h,cpp}を真似て作っています.CMakeLists.txtにもターゲットを追加しています.
試しに,TankJoystickControllerRTC.hに
#include <cnoid/MessageView>
を追加したら,同じエラーになりました.
早とちりで申し訳ありません.クラスのなかにControllerIO*を保持するメンバ変数を追加し,シミュレーションループの中でも表示できました.今のところは,シェルに表示されていますが.
ご対応ありがとうございます。
io->os() に出力するとコンソールに出力されてしまうバグを修正し、メッセージビューに出力されるようにしました。
https://github.com/s-nakaoka/choreonoid/commit/088fa55e0f9e1ed6b1445fe1881eb92f199b2813
中岡様,
手元のソースに取り込んでビルドし,動作を確認しました.どちらの場合もメッセージビューに表示されています.
ありがとうございました.
#include <cnoid/MessageView>
とする方法ですが、私の環境でも最新のソースにして試してみたところ同様のエラーが出ました。
samples/OpenRTM/CMakeLists.txtに
include_directories(${Qt5Widgets_INCLUDE_DIRS})
の行を追加したところコンパイルは通るようになりましたが、io->os()を使った方法が標準のようですので、そちらを使ったほうが良さそうです。