bitterharvest’s diary

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

Raspberry PiからLego Mindstormsを使用できるようにする―BrickPiの解剖(1)

1.BrickPiは少し賢い

Lego Mindstromsを用いてロボットを作成しようと思うが、Lego Mindstormsに付属しているパソコンNXTあるいはEV3では自由にシステムを作成できない。そこで、Raspberry Piを用いて、Lego Mindstormsを制御することにした。しかも、C言語ではなく、Haskellを用いて、実現することにした。

Haskellは純関数型言語で、プログラムを構造的に書ける。手続き的であるJavaやCとは、プログラミングの開発方法が大いに異なっている。JavaやCがhow的な記述を行うのに対して、Haskellはwhat的である。Haskell.orgのホームページに素数を求めるプログラムが書いてある。

primes = filterPrime [2..] 
  where filterPrime (p:xs) = p : filterPrime [x | x <- xs, x `mod` p /= 0]

このプログラムはHaskellの良さを見事に体現している。二行という短い記述で素数というものを定義している。即ち、先頭が素数pで、その後に、xsから素数pの倍数を取り除いた(filterPrime)リストが続いている。xsは、pよりは大きな数が小さい方から順に並んでいる。しかも、pよりも小さい素数の倍数はxsには含まれていない。そして、このリストxsに対して、pの倍数を取り除いたリストを作成する。このように作られた新しいリストの先頭を次の大きな素数なので、これに対して同じことを行えば、順次、素数を得ることができる。数学的帰納法を用いれば、プログラムの正しさを証明することも簡単である(JavaC言語のプルグラムはこうはいかない)。

Haskellはこのように素晴らしい性質を有しているので、ロボットもこの言語で実装すれば、その振舞いはわかりやすいプログラムで表現されると期待される。

Raspberry PiからLego Mindsotromsのモータやセンサを利用する方法にはいくつか考えられる。Lego Mindstormsのモータやセンサは8芯8極の電話線を用いてコンピュータと接続するようになっているので、コンピュータ側にコネクタを設けてもよいのだが、ここでは、工作の手間が省けるBrickPiを利用することにした。BrickPiは少し賢くて、ファームウェアが実装されている。これは、シリアル通信(UART)によりRaspberry Piから送られてくる情報を、Brick Piに接続されているモータやセンサに伝える。このため、RaspberryPiからBrick Piへの情報の伝達方法について知る必要がある。

Brick Piの製造元(Dexter Industries)の資料には、Raspberry Pi, BrickPi,モータ、センサの関係が分かりやすく描かれている。
f:id:bitterharvest:20150701142748p:plain

上記の図で、Brick Piとモータやセンサとの間の情報のやり取りはI2Cプロトコルを用いて行われる。Raspberry PiとBrick PiはUART(シリアル通信)プロトコルで行われている。このプロトコルを便利に使えるようにするため、Raspberry Pi側には、C言語Pythonでの開発者のために便利なライブラリを用意している。このため、これらの言語で開発する場合にはRaspberry PiとBrick Piの間の情報のやり取りがどのように行われているのかについて知る必要はない。

しかし、これ以外の言語で開発する場合には、独自にライブラリを開発する必要があり、そのためには、プロトコルを知る必要がある。そこで、Dexter Industries社が公表しているC言語用のライブラリを解析しなければならない。

この解析の過程では、様々な情報を必要とする。そこで、BrickPiのハードウェアがどのようになっているかを解析する。BrickPiではハードウェアの回路図を公表している。モータとセンサの部分は以下のように、似たような回路が二つある。
f:id:bitterharvest:20150701142719p:plain
f:id:bitterharvest:20150701143154p:plain
この図から、センサ1,2、モータA,Bを一組として、また、センサ3,4、モータC,Dを別の組として制御していることが分かる。

次に、モータやセンサがどのように設定されるかを知りたいのだが、ここでは、モータの方が簡単そうなので、こちらから解析する。UARTプロトコルは、もともとは、コンピュータとテレタイプ端末との情報の伝搬のために設けられた通信手段である。最初に通信の速度(Baud Rate)を設定し、文字列からなる情報をやり取りしていた。文字列は文字に分解され、一文字(多くの場合、8ビット)を単位に、送り出される。

それでは、Cでプログラムを作成するときに利用するライブラリBrickPi.hを用いて、モータを駆動するために、RaspberryPIの方からBrickPiにどのようなデータが送り出されているのかを調べる。モータに関係するところはBrickPiUpdateValue()である。解析にだいぶ時間を費やしたが、Rasberry PiからBrickPiに送られるデータは次の図のようになっていた(あとで説明するが、データの並びは通常とは異なり、下から上に、また、右から左になっている)。
f:id:bitterharvest:20150704204151p:plain

Raspberry PiからBrick Piに送る信号はビット列になっている。モータのAとBは一緒のビット列で設定され、残りのCとDは別のビット列で設定される。どちらの組の情報であるかはDestination(最初の8ビット)で示される。1の時は、A,Bの組であり、2の時は、C,Dの組である。

その次の8ビットは和による簡単なパリティである。これについては後で説明する。

この後はデータの部分になる。Byte Countの8ビットはこの後のデータのバイト数である。モータの場合は4である。

ここまでのビット列は次のようになっている。なお、各バイトでは、左端が最上位ビットである。また、バイトの並びは、左の方が小さいとする。即ち、左側からOut0,Out1,Out2となっている。
f:id:bitterharvest:20150704204525p:plain

次は送るモータやセンサの種類を示すためのタイプ(8ビット)の指定だが、ここは、モータなので3とする。

次は、モータを制御するために必要なデータである。これは少し厄介である。データは複数あるので、これらを左から順番に詰め込んでいく。必要とするデータの数はデバイスによって異なる。このため、可変長の長さになるが、モータの場合は、3バイトとなる。

それでは、モータを制御するのに必要なデータのビット列を作成する方法を示す。

最初のデータで、モータのそれぞれに対してエンコードのオフセット(1ビットずつ)を指定するが、ここでは、エンコードを使わないので、それぞれ、0とする。

次のデータでは、最初のモータ(アドレスが0の場合にはモータのA,1ならばC)についてスピード(8ビット)、方向(1ビット)、稼働か否か(1ビット)を指定する。続いて、次のモータ(アドレスが0の場合にはB,1ならばD)について、設定する。

得られたビット列の信号は、バイトを単位としてBrickPiに送られる。そこで、バイトの構成となるように、空白部分(2ビット)を埋める。

これまでの操作で得られたデータは次のようになる。
f:id:bitterharvest:20150704064851p:plain
ところで、データを詰め込んでいる部分は、データは並びの小さい方から並びの大きい方へと操作されていると見なす。このため、最後に入ってきた方が、バイトの並びでは最初の方になる。この図では分かりにくいので、最初に示したように、データの並びを下から上に、右から左に、我々の通常の世界とは全く反対に並べる。これが、最初に示した解析結果である。こうするとビット単位で整然と並んでいることが分かる。再掲すると次のようになっている。
f:id:bitterharvest:20150704204151p:plain

なお、Sumには、出来上がったビット列のデータを、バイト単位で切り、それを符号なしの整数と考えて、それらの総和を計算し、結果を書き込む(この計算には、もちろん、Simple Parityのところは含まずに行う)。なお、結果が255を超えた場合には、256で割った余りを書き込む。

次回は、実際にこのビット列を得て、8バイトずつに区切る処理をHaskellで実現することを考える。