CPUの個数でcatkin_makeが通ったり通らなかったり

Pocket
LINEで送る

表題の通り少しハマりました。ROSについては本を書いたものの、基礎的な内容+Pythonなので、C++のコードのビルドについてはほとんど勉強しておらず、良く分かってないのが良くわかりました。同じようにハマる人がこの記事を見つけてくれたらと。また、この症状の回避方法について良く知られているのならば教えていただければと。

症状

  • 1. .msgファイルと、それを使うC++のコードを含むパッケージのcatkin_makeが、.msgファイルの処理の前にノードのコードのコンパイルを始めて一度コケるが、2度目で通る。

これはたぶん回避方法があるはずでちゃんと調べろという話ですが、面白いのは続きです。

  • 2. Travis CIだと2回catkin_makeしても通らない。

これで「???」になりました。ちなみに1については、自分のデスクトップ機でもラズパイでも2回で通ります。

ちなみにエラーはこんな感じです。Buttons.hとLeds.hが、.msgファイルから作られるヘッダファイルで、これがないとC++のコードのところでヘッダファイルが無いと叱られます。

原因

自分のPCやラズパイでは1回目のcatkin_makeはエラーを出すものの.msgの処理を完了できて、一方Travis CIの場合は完了できないということは、非同期処理のズレだろうというのがまず思いつきました。そして、Travis CIのエラーに

Invoking "make -j2 -l2" failed

とあったので、たぶんズレはコア数の違いで起こるんだろうと思いました。(makeのjオプションは、何並列で処理をするかを指定するオプションです。)

ということで、手元で

$ catkin_make -j2 

を繰り返したら、何回catkin_makeしても失敗するという、Travis CIで起きたのと同じ現象が起こりました。ちなみにPCのCPUのコア数は8、ラズパイでも4だったので、Travis CIの方が少ないということになります。

解決(超小手先)

ということで、Travis CIでcatkin_makeするシェルスクリプトの行を

catkin_make -j8 || catkin_make -j8 #CPU2個だけど8並列頑張ってね。しかも1回目コケたらもう一回やってね。

というように変更したらテストにパスしました。

お断りしておきますが、小手先です。何かすればコンパイルの順番を制御できるはずなのですが・・・。

完全解決

・・・と書いたら教えていただきました。

(もっと短い書き方がありそうですが)とりあえずベタにCMakeLists.txtに以下のように書いたら一回のcatkin_make(オプションなし)で通りました。

add_dependencies(leds ${TARGET_NAME} ${PROJECT_NAME}_generate_messages_cpp)
add_dependencies(buttons ${TARGET_NAME} ${PROJECT_NAME}_generate_messages_cpp)
add_dependencies(lightsensors ${TARGET_NAME} ${PROJECT_NAME}_generate_messages_cpp)

ありがとうございました!!!

Pocket
LINEで送る

日記 —自己位置推定の実機実装

Pocket
LINEで送る

必要に迫られ、およそ10年数ぶりに実機用のパーティクルフィルタのコードを書いています。売るものではないので公開してますが、ロボットの場合、ハードウェアが違うとコードがそのまま使えないのであまり反響はありません・・・が、ロボットは日経Linuxの連載で使っているRaspberry Pi Mouseで市販品なので、ちゃんとお化粧して教科書書いて小銭を稼ぐ使ってもらうのが目標です。

リポジトリを見ても、「ああC++だなあ(逃げよう)」ということくらいしか分からんのでここに何やってるか書いておくと、次の写真のような環境で、ロボットに地図をもたせて、地図のどこにロボットがいるのか自分で把握させるコードを書いています。センサ情報はロボット前面の四つの赤外線センサから得られます。また、ロボットがどれだけ動いたかはモータへの指令から求めることができますが、壁に接触しながら動くと訳の分からん挙動を示すので大変です。

スクリーンショット 2015-08-09 20.14.35

ロボットは次のような地図を持っています。ロードした地図をテキストで描画する確認用プログラムの出力を示します。シェル芸でしょうか。いいえ、C++です。

uedambp:map ueda$ ./main ./map | head -n 15
+---+---+---+---+
|       |       |   
+   +   +   +   +
|       |       |   
+   +   +   +   +
|       |       |   
+---+   +---+---+
|   |           |   
+---+---+---+---+

この出力をFacebookに貼りつけたら「Rogueみたい」というコメントを書き込むおじさまがたがたくさん釣れたんですが、さあなんのことやら。

今日と明日はロボットのいる大学に行けないのでロボットへの行動指令とセンサの値のログを採取して開発中ですが、とりあえずそれっぽいものができましのでgifアニメをはりつけます。

animation

作っているコードはパーティクルフィルタというものです。地図の上にロボットの分身(ブツブツ)をばら撒いて、行動とセンサの履歴が説明できない分身を殺しまくって、説明できるやつを増やしてロボットの実際の位置に分身の位置を寄せていきます。

上の実行例は実際のロボットの位置を書き込んでないのですが、最終的にはロボットの最後の位置近くにブツブツが固まりました。

まだなんのことかサッパリ分からんと思いますが、続きは某所での講義で。分かってる人には「壁にぶつかったあとのパーティクルの挙動のモデル化が難しかったけど適当な方法でもうまくいった」とお伝えします。

寝る。

Pocket
LINEで送る

Raspberry Pi MouseをC++で動かすとどうなるか(けっこう楽だった)

Pocket
LINEで送る

誰か(たぶんNさん)に書けと言われたような気がするので・・・

日経Linuxで連載中の「Raspberry Piで始めるかんたんロボット製作」では、シェルスクリプトでロボットを動かしています。

まだ連載はモータを動かしたりブザーを鳴らしたりと要素の動作確認の段階ですが、8月発売の号(9月号)からロボットが走ります。こんなふうに・・・地味に・・・

シェルスクリプトで作るのは個人的な特性もありますが、ちゃんとした理由もあります。こんな感じです。

  • 行数が短くて説明しやすいこと
  • プロセスを複数使うことが簡単なこと
  • 良かれ悪かれ誰でもUNIX系のOSをイジる場合、シェルスクリプトを使わなければならないので変にシャレオツな言語を使うよりは無駄にならないこと

といったところです。

また、ロボットは私が無理言ってデバイスファイルで動かすことにしたので、字を読み書きするにはリダイレクトだけで済むようにしました。これもシェルスクリプトだと簡単です。普通の言語だとファイル開いたり閉じたり面倒です。

と言いつつC++

連載はそんな感じでシェルスクリプトでやってますが、限界もあります。

Raspberry Pi Mouseをちょっと本職に使ってみようということで、今度のICRAという学会(ロボット屋にとって一番重要な学会)の実験をやってみました。選んだのはシェルスクリプトでなくC++です。シェルスクリプトを使わない理由で一番大きいのは

  • ロボットの内部状態を表現できない

ことです。複雑なタスクをするロボットのプログラムを書くときは、ロボットが何を考えているかを変数で表現し、その値をコロコロ変えるという方法をとるのが一般的です。しかし、シェルスクリプトを使うとシェルの変数(機能が貧弱極まりない)に書くか、遅いファイル(Raspberry Piの場合はキャッシュがそんなに効かないしファイルはフラッシュメモリ上に書かないといけないので特に遅い)に書くかしないといけないのでちょっと苦しくなります。内部状態を保持してHTTPサーバのようにレスポンスしてくれるサーバのようなコマンドがあればシェルスクリプトから呼び出して使えて便利ですが、わざわざそんなもん作りたくありません。

こうなるとシェルスクリプトで書く旨味は全くないので、何か自分の知っている別の言語を使うことになります。内部状態を表現するということでオブジェクト指向言語を使うということになりますが、遅い言語だと実験がモッサリしたり、計算時間を論文に書く時にえらく損をするので、C++を選びました。

・・・と、いかにも熟慮したかのように書きましたが、ほぼノータイムでC++で、他はありません。こういうときにPython選んで「遅い遅い」言っている研究者が結構いるので、ちゃんと勉強しようよ思いつつ、人のことなので黙っております。

fstreamを使うとそんなに面倒でない

で、上で説明した「普通の言語を使うとファイルに書き込むのが面倒」ですが、C++にはfstreamという強力で素敵なサムシングがあります。例えば、以下は実験用のソース(まだまだ非公開。もちろん自分で書いた。)から、ステップモータにデバイスファイルを通じて周波数を指定するメソッドを抜粋したものです。

void Mouse::putMotorHz(int lvalue,int rvalue)
{
        ofstream r_motor("/dev/rtmotor_raw_r0");
        ofstream l_motor("/dev/rtmotor_raw_l0");
        r_motor << rvalue;
        l_motor << lvalue;
        r_motor.close();
        l_motor.close();
}

ファイル開けて値を書いて閉じるというのはやはりシェルでリダイレクトするより手間ですが、int型の数字をそのまま文字列に変換して「<<」でぶち込んでくれます。(上のメソッド、本当は値のチェックをしないといけないのですがね・・・)

今度は読み込みの例です。距離センサ(値をスペース区切りで4個出力)を読んでいます。これもデバイスファイル(/dev/rtlightsensor0)から読み出した値をintの配列sv(実は厳密にはvector<int>)に直接代入しています。

ifstream ifs("/dev/rtlightsensor0");
if(ifs.bad()){
        ifs.close();
        continue;
}

ifs >> sv[0] >> sv[1] >> sv[2] >> sv[3];
ifs.close();

比較実験はしませんが、FILE型を使うよりはかなり楽で、確か3,4倍くらいFILE型を使うより遅くて済むというくらいのトレードオフだったと記憶しています。また、ファイル処理以外はC言語と比べて最悪でも2倍くらいの減速で済みます。

あと、並列化が必要なら、新しいC++だとPOSIXスレッドがけっこう簡単に使えるので、それも変に凝った言語を使うより(慣れていれば)C++で十分だよなあと思います。たぶん、Raspberry Piのデフォルトのg++は古いので、ココ等を参考に新しいバージョンのgccをインストールして使いましょう。

もちろん、Pythonの例もGitHubに置いているように、特にシェルスクリプトにこだわる必要はなく、研究用の実験をしないならC++にこだわる必要もありません。むしろ言語を選べるように「デバイスファイルで字を読み書きする」という仕様にしましたので、みなさんもいろんな言語でロボットを動かしてみていただければと。個人的にはHaskell希望です。

ところでC++で動かしたロボットの動画はないのかというところですが、実験結果は論文が採択されるまで公表できません。また、どんな言語で動かしてもロボットの動きは一緒ですので、割愛ということで・・・

現場からは以上です。

Pocket
LINEで送る

シェル芸でC++のクラスの関係を調べる

Pocket
LINEで送る

今日発表のスライドを作っており、調査のため。面白いのでメモ。

Gitのリポジトリの
https://github.com/ryuichiueda/GlueLang/tree/master/SRC
に相当するディレクトリでシェル芸をしています。

基本クラスの抽出

uedambp:SRC ueda$ grep -h class *.h | grep -v ';' |
 grep -v '{' | awk 'NF==2'
class Data
class Element
class Environment
class Feeder

各基本クラスから派生したクラスを調査

uedambp:SRC ueda$ grep -h class *.h | grep -v ';' |
 grep -v '{' | awk 'NF==5{print $NF,$2}' | sort
Arg ArgExtCom
Arg ArgIntCom
Arg ArgProc
Arg ArgVariable
Arg ArrayVariable
Arg Literal
Data DataFile
Data DataJob
Data DataProc
Data DataStr
...

Tukubaiのコマンドを使うとこんなリストもできる。

uedambp:SRC ueda$ grep -h class *.h | grep -v ';' | grep -v '{' | awk 'NF==5{print $NF,$2}' | sort | yarr num=1 | sed 's/ /:/'
Arg:ArgExtCom ArgIntCom ArgProc ArgVariable ArrayVariable Literal
Data:DataFile DataJob DataProc DataStr
Element:Arg DefCond DefFile DefProc DefStr Exe IfBlock Import Job Pipeline Script Where
Exe:ExeEachline ExeExtCom ExeIntCom ExeProc ExeString

ただし、複数のクラスを継承しているとやり方を変えないといかん。

パワポ書きに戻る。

Pocket
LINEで送る

【お盆の勉強にどうぞ】C++11はもはやLL

Pocket
LINEで送る

研究のために科学計算のコマンドをC++で作ってます。去年もちょっと使いましたが、自分がC++ばっかり書いていた頃(1997年から10年くらい)から何年もたっているので、

を読みながらリハビリ中です。

autoを使う

この本、1000ページ以上もあり、しかもKindle版で正直読みにくいのではなっから全部読むつもりはないのですが、私の知っているC++とあまりにも違って浦島太郎状態です。まず最初に、autoというものを見つけてひっくり返りました。昔のautoとは違います(昔のautoは使ったことないけど)。

こんなふうに使います。

#そーす
uedambp:tmp ueda$ cat hoge.cc 
#include <iostream>
using namespace std;

int main(int argc, char const* argv[])
{
	double v = 1.0;
	int n = 5;

	//doubleとintのかけ算
	auto x = v*n;
	cout << "型:" << typeid(x).name() << " 値:" << x << endl;

	return 0;
}

実行すると、xの型はdoubleになっていることが分かります。

#こんぴゃーるして実行
uedambp:tmp ueda$ g++ -O3 -std=c++11 hoge.cc -o hoge
uedambp:tmp ueda$ ./hoge 
型:d 値:5

要はHaskellみたいに型推論してくれるということかと。

んで、これだと型に慣れている人はあまり有り難がらないと思いますが、私が感動したのはこういう書き方ができるということです。

int main(int argc, char const* argv[])
{
	vector<string> str;
	str.push_back("abc");
	str.push_back("あいう");
	str.push_back("!?*");

	//こう書ける
	for(auto i=str.begin();i<str.end();i++)
		cout << *i << endl;

	//昔の書き方(STLの便利さが90%減)
	for(vector<string>::iterator i=str.begin();i<str.end();i++)
		cout << *i << endl;
}

「vector<string>::iterator」を初心者に教える自信は全くなく、そして何年もブランクのある今、私もなにがなんだか分からないし、書き方を忘れていて調べてしまったのですが、autoはそんな人々を温かく出迎えてくれます。

STLを使えばポインタやデストラクタでいろいろ悩むこともなく、C++を使える人の人口をぐっと増やせると私は思っているのですが、これでまた間口が広がったような気がします。

スレッドを使う方法がバカバカしいくらいに簡単になっている

んで、今私の書いている「価値反復」というアルゴリズムは、排他なしで並列処理ができます。できるということは並列化しないと笑われるので泣く泣くPOSIXスレッドの立て方を復習していたのですが、これもC++11だとすごく簡単ということが分かりました。threadというクラスのインスタンスを作るだけです。

ueda@ubuntu:~$ cat multi.cc 
#include <iostream>
#include <thread>
using namespace std;

void tfunc(string name)
{
	int num = 0;
	for(int i=0;i<10000000;i++){//ひたすら足し算
		fprintf(stdout,"\n%s: %d",name.c_str(),num++);
	}
}

int main(int argc, char const* argv[])
{
	thread th1(tfunc,"th1");//実行したい関数と、その関数に渡したい引数を指定
	thread th2(tfunc,"th2");
	thread th3(tfunc,"th3");

	th1.join();//これで終わるのを待つ
	th2.join();
	th3.join();
}

実行して途中の出力を見てみます。th1,2,3入り乱れています。

ueda@ubuntu:~$ g++ -O3 -std=c++11 -pthread multi.cc -o multi
ueda@ubuntu:~$ ./multi | head -n 10000 | tail 
th1: 5102
th3: 2605
th2: 2282
th1: 5103
th3: 2606
th1: 5104
th3: 2607
th1: 5105
th3: 2608
th3: 2609

実行中にtopで見ると、CPUの使用率が300%近くになってます。

スクリーンショット 2014-08-12 21.52.56

ちなみに時間はこんなもん。30000000回の足し算と標準出力への吐き出しですが、なんかもうちょっと速いような気もしないでもありません。もし何かヘマをしていたら教えていただきたく。CPUの周波数は2.5GHzです。

ueda@ubuntu:~$ time ./multi > /dev/null

real	0m24.254s
user	0m34.824s
sys	0m32.161s

Macでもちゃんと動作しますが、topの出力がいまいちよく分からなかったのでUbuntuで実験しました。

もちろん、排他制御は自分でやらなければいけませんので、そこはちょっと敷居が高くなるかと思います。

おわりに

LLから入った人はC/C++にアレルギーがあるようなのですが、STLを落ち着いて勉強すればポインタを使ったり自分でメモリを解放したりということはほとんどしなくて良いので、あまり怖がる意味はないかと思います。SLTが満足に整備されていなかったときと比べると、格段に簡単になっています。生のCと比べるとLLと言っていいくらいです。

自分で書いたプログラムが何の引っかかりも無く立ち上がって、すんごい速さで動く感覚を是非味わっていただきたく。と言いますかこれが普通の速さなのですが。

ぜひC++でコマンドを書いてシェルスクリプトでシェル芸を。いや、これ書いておかないと自分がどこの会長か忘れてしまうので。

よいお盆を。

Pocket
LINEで送る