はじめに
ROSのC++のコードは実行時エラーが起きても
どこでエラーが起きたかわかりにくいので
デバッグしずらいという問題があります。
特に行列演算ライブラリであるEigenを使って
プログラムを書いている場合、
要素のアクセスエラーが起きると、いつも同じエラーが出て
プログラムのどの部分でアクセスエラーが起きたかわかりません。
最も簡単なのは、プログラムの各所にcoutを仕込んで、
どこでプログラムが落ちているかを、ちょっとずつ調べていく、
いわゆるprintfデバックの方法がありますが、正直面倒ですね。
下記のROSソフト開発者ガイドを見るとわかる通り、
ROSではバグの深刻度に応じて
二つのツールの使ってデバックすることが推奨されています。
一つ目はgdbであり、二つめはValgrindです。
単純なバグに関しては、gdbを使用し、
複雑なバグに関しては、
Valgrindを使用することが推奨されています。
今回の記事では、
まずはじめにノードの振る舞いを確認する方法と、
その後にgdbとValgrindを使用
ROSソフトのデバック方法について説明したいと思います。
マクロ的にノードの振る舞いを確認する。
いきなりコードの細かい部分を確認する前に、
各ノードの振る舞いを確認するのが、
デバックへの近道です。
まず初めに、
rosrun rqt_graph rqt_graph
で、現在の立ち上がっているノードとそのコネクションの状態を
グラフとして可視化し、確認することができます。
また、問題が起きているであろうノードが特定されている場合は、
rosnode info hogehoge
で各ノードのtopicの送受信状態、serviceの一覧などを確認することができます。
また、ある特定のtopicに問題があると分かっている場合は、
rostopic info hogetopic
や
rostopic echo hogetopic
で各トピックを確認することができます。
また、あるlaunchファイルが
どのノードを起動するかどうかが分からない時は、
roslaunch --nodes hogepackage hoge.launch
とすると、hogepackage内のhoge.launchが
どのような種類のノードを起動するかを確認することができます。
gdbとは
gdbとは、GNUにおけるデバックツールのことです。
Gnu DeBuggerの略で、主にGNUのコンパイラであるgcc用です。
多くのUnix環境で動作し、CやC++, FORTRANなどの
言語機能としてのデバック機能が乏しい言語環境で使用できます。
(逆にPythonやPerlなどでは、自動的にスタックトレースの表示などがされます)
元々はGNUプロジェクトの創始者である
リチャードストールマンによって開発され、
GNUプロジェクトの一つとして開発されてきました。
gpdはステップ実行、
ブレークポイントの指定や、
変数の監視・変更などの
デバック機能を使用することができます。
gdbを使ったROS C++ソフトのデバック方法
下記は、ROSのC++ソフトがSegmentation faultなどで
異常終了した時に、その時に生成されるCoreファイルを解析して、
プログラムのどこで異常終了したのかを解析する方法です。
1.下記のコマンドを打ち込む
ulimit -c unlimited
これで、プログラムが落ちた時の情報ファイルであるCoreファイルが作成されるようになります。
(このコマンドを.bashrcに書いておくと、いちいちこのコマンドを打ち込まなくても、
常にcoreファイルを作成してくれます。)
2. バグのあるプログラムを起動します。
3. プログラムが落ちます。
4. カレントディレクトリにCoreファイルが生成されているのを確認します。
5. 下記のコマンドを打ち込んで、プログラムを起動し,Coreファイルをgdbで解析します。
gdb bin/package_name core
6. そしてgdbが起動したらbtと打ち込んで、バックトレースを表示します
7. するとどのファイルのどの行でプログラムが落ちたかを確認できます。
Valgrindとは
valgrind は、linux 環境で動く、かなり強力なメモリーデバッガーです。
メモリーリークや Segmentation falt などの具体的な位置を教えてくれます。
UbuntuへのValgrindのインストール
下記のコマンドでインストールできます。
sudo apt-get install valgrind
ValgrindによるROS C++ソフトのデバック
1. Valgrind上でバグがあるソフトを起動する。
下記のコマンドをターミナルで起動します。
valgrind --leak-check=full bin/package_name
これで、メモリリークの解析結果が表示されます。
ただ、この解析結果は非常に長くなることが多いので、
下記のように解析結果をteeでファイルに出力すると
結果が見やすくなります。
valgrind --leak-check=full bin/package_name 2>&1 | tee a.log
ただ、今のところEigenのアクセスエラーの場合、
gdbのようにバグが含まれているプログラムの行数が
うまく表示されないので、
自分の場合はgdbを使ってデバックをしています。
gprofを使ってROSのコードのプロファイリングをする
プロファイリングツールであるgprofを使うことにより、
コードの計算コストの内訳を知ることができ、
意図しない無駄な処理などを、見つけることができます。
詳しくはこちらの記事をどうぞ