bitterharvest’s diary

A Bitter Harvestは小説の題名。作者は豪州のPeter Yeldham。苦闘の末に勝ちえた偏見からの解放は命との引換になったという悲しい物語

Lego BotsをHaskellで動かす-ライントレースカーを分析する

3.ライントレースカーを分析する

今回開発するのは写真のようなライントレースカーである。
f:id:bitterharvest:20150721103903j:plain

このライントレースカーは二つの光センサを有している。これらの光センサの間には導線となる黒い線が引かれている。ライントレースカーが正常に動いているときは、光センサのいずれもが、白い面からの反射光を受ける。ライントレースカーが黒い線から外れ始めると、光センサの一つが黒い線の上に来る。黒い線の上にある光センサは、黒い線が光が吸収するため、光を受けない。

もし、右側の光センサが光を受けなくなると、ライントレースカーは左の方へ外れようとしている。このとき、正常な状態に戻すためには、ライントレースカーを右の方に曲げないといけない。これは、左側の車の回転を右側のそれより速くすることで達成される。

逆に、左側の光センサが光を受けなくなったときは、逆にすればよい。

ライントレースカーの原理がわかったので、物理の法則を利用して、ライントレースカーの操作法をもう少し詳しく分析する。
f:id:bitterharvest:20150720125802p:plain

上図に示すように、\(t\)時には、黒い線をまたいでいたとする。また、この時の速度は\(v_t\)とする。ライントレースカーに力を加えないと(モーターにトルクを加えてないと)、摩擦力の影響などで停止してしまう。そこで、ライントレースカーの速度を維持するためには、外部から力を加える必要がある。ライントレースカーが正常に動いているときは、進んでいる方向に(前方がどのようになっているかの予知能力がないため)力を加えるのが自然である。\(F\)の力を微小な時間\(\Delta t\)だけ加えた結果、下図のようになったとする。この時、速度は、\(v_t\)から\(v_{t+\Delta t}\)だけ変化したものとする。
f:id:bitterharvest:20150720125826p:plain

このとき、ライントレースカーは、黒い線から右側で外れそうになっている(左側の光センサが光を受けていない)。そこで、正常な位置に戻すためには、左側の方に曲げる必要がある。このため、ライントレースカーには、下図のように、これまでの進行方向ではなく、左側の方進むように力をかける。
f:id:bitterharvest:20150720130413p:plain

これがうまくいけば、ライントレースカーは正常な位置に戻る。
f:id:bitterharvest:20150720130553p:plain

ところで、システム思考で考えるためには、ストックとフローを考えなければならない。フローの方は、ライントレースカーを動かそうとする力\(F'\)(実際にはモータに与えるトルク)と止めようとする力\(F''\)(実際には摩擦力)である。微小な時間\(\Delta t\)を単位として考えると分かりやすいので、フローの方はライントレースカーを動かすための力積\(F' \Delta t\)と止めようとする力積\(F'' \Delta t\)である。

ストックの方は、フローの蓄積なので、運動量\(mv_t\)となる。これは、運動方程式 \(F= \frac{d mv} { dt} \) より得ることができる。この式を、\(Fdt= d mv \)と変形して、\(t\)から\(t+\Delta t\)の間で積分すると\(F \Delta t=mv_{t + \Delta t} - mv_t\)となる。この式は、フロー\(F \Delta t\)によるストック\(mv_t\)の変化を表している。ここで、\(m\)はライントレースカーの質量で、\(F = F' -F''\)である。なお、運動量は、とても大雑把にいうと、同じ動きを続けようとする強さである。質量が大きくなるとその強さは増し、速度が増してもその強さは大きくなる。

バークレイの学生だった頃、知人が免許取得中で、高速道路での実習をひかえていた時、高速道路で対向車がこちら側に向かって突っ込んできたときどのように対処したらよいかが話題にのぼったことがある。アメリカ人の常識として、運動量を増やすことだと冗談交じりに誰かが言ったことを覚えている。
f:id:bitterharvest:20150720210931p:plain

4.理論から実践へ

ライントレースカーの原理をシステム思考に基づいて、システムとして描くことに成功したので、次に、黒い線の中心線に沿って動かすためには、どのように制御したらよいのかを考えることとする。初めに、制御するのに必要な情報がすべて得られているような恵まれた環境下で考える。さらに、すべてが滑らかに変化するものとし、微小な時間においては直線で近似できるような状況下での制御を考えることにする。

今、時間\(t\)で、図に示すように、ライントレースカーの進行方向と黒い線の中心方向はずれているとする。制御すべきことは、これに外部から力を加えて、中心線に沿ってライントレースカーを動かことである。
f:id:bitterharvest:20150721090850p:plain

ここでは議論を簡単にするために、ライントレースカーの速度は一定とする(但し、方向は異なってもよいものとする)。いま、微小時間\(\Delta t\)経ったとすると、ライントレースカーは\(v_t\Delta t\)だけ進み、うまく制御されていれば、黒い線の中心線の上にあるはずである。また、そのときの運動量は\(mv_{t + \Delta t}\)である(但し\(v_t=v_{t + \Delta t}\))。

以上のことから、微小時間\(\Delta t\)の間に加えるべき力が分かる。力を加えた結果、ライントレースカーはこの間、黒の中心線に沿って動くので、加えるべき力積\(F \Delta t\)は図のようになる。
f:id:bitterharvest:20150721091700p:plain

これらから、フィードバックを加えたライントレースカーのシステム図は以下のようになる。
f:id:bitterharvest:20150721092949p:plain

しかし、残念ながら、Lego Botsのライントレースカーでは、上記で求めている全ての情報を得ることはできない。我々が得ることができるのは、光センサからの情報だけである。それぞれの光センサからは、それが白地の上にあるのか黒い線の上にあるかの情報だけである。二値の簡単な情報だが、制御の上で重要な情報を光センサはもたらしてくれる。

光センサの片方が白地の上にあり、他方が黒い線の上にあるとき、ライントレースカーは黒い線の中心線から大きく離れているという情報を与えてくれる。これは、先ほどの議論で、車の進行方向が中心線の方向と大きくずれていることを示している。重大な事態を引き起こす前に、中心線の方に戻すような力を働かせれば、回避できる可能性があることを先の理論が示している。この力をどのくらいかけたらよいのかを様々な情報が欠けているため、計算式から導き出すことは不可能なのだが、何回か実験を行っているうちに経験的な値を決められそうである。

当面分かっていることは、力積の方向に、ライントレースカーに力を加えることである。これは、ライントレースカーのモーターの回転速度を制御することで実現できる。即ち、求められている力積の方向にあるモータの回転を低速にし、反対側のモータを高速にすることである。

ここまでの考察で得られた知見は以下のとおりである。

中心線の方向 左の光センサ 右の光センサ 力積の方向 回転方向 左のモータ 右のモータ
前方 白地 白地 前方 前進 高速で回転 高速で回転
左側 黒い線 白地 左側 左にカーブ 低速で回転 高速で回転
右側 白地 黒い線 右側 右にカーブ 高速で運転 低速で運転
黒い線 黒い線    

なお、上記の表で二つの光センサが両方とも黒い線の上にあることを想定していなかったことが分かる。これは、ラントレースカーが黒い線と直角あるいはそれと近い時に生じる現象である。モータをどのように制御したらよいかは適当に決めればよい。

また、ライントレースカーは常に黒い線を跨いでいることを想定しているが、全く跨いでない場合にも、両方の光センサは白地の上にある。この場合も、モータをどのように制御したらよいかはやはり適当に決めればよい。

先のシステム図を修正すると以下のようになる(これは冒頭で説明したことと同じであるが、違いは理論的に説明されていることである)。
f:id:bitterharvest:20150721101411p:plain

ライントレースカーのシステム図が完成したので、次はいよいよNetwireを利用してプログラムを実装する。

注:情報が不足あるいは正確でない状況でもある程度の制御ができることを示してくれたのはデイビット・スミスである。彼は、複雑系の研究の中で、継続的な操作が可能であることを示してくれた。