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で送る