1.GitHubに掲載
BrickPiをHaskellから利用するための外部関数インタフェースを完成させると、HaskellからLEGO社のモータやセンサが使えるようになる。外部関数インタフェースとC言語でのプログラムはこの記事で掲載するのには無理なほど大きなサイズになった。そこで、GitHubにアップロードしたので、適宜参照して欲しい。github.com
プログラムの中で、BrickPi.cとBrickPi.hは、Dexter Industry社が提供していたBrickPi.hを修正したものである。これらは、モータやセンサへの制御データを設定するのに利用する。tick.hとtick.cは、tick.hを修正したもので、時間の制御に利用する。
また、BrickHS.hsは、上記のプログラムへの外部関数インタフェースを定義したものである。Haskellでプログラムを作成したときは、次のようにコンパイルして実行プログラムを作成する。
ghc --make 応用プログラム.hs BrickPi.o tick.o
なお、BrickPi.o, tick.oのかわりにBrickPi.c, tick.cを用いてもよい。
GitHubには、c言語用のライブラリに含まれていたテストプログラムも一緒にアップロードしてある。
これらは次のようになっている。
プログラム名 | 機能 |
---|---|
Motor-test.hs | 二つのモータを利用した車を前進、後退、左折、右折させる |
LEGO-Motor-Test.h | 二つのモータを使い前進と交代を繰り返す |
Lego-TouchSensor-Test.hs | タッチセンサに触れたかどうかを返す |
Lego-UltrasonicSensor-Test.hs | センサと障害物の間がどれだけ離れているかを計測する。出てくる数値は実際の長さ(cm)よりも少し大きめである |
Lego-ColorSensor-Test.hs | 6種類に分けて色情報を返す |
simplebot-simple.hs | 二つのモータを利用した車が、w,a,s,d,xのキーを押すと前進、左折、後退、右折、停止する |
2.プログラムの紹介
GitHubにアップロードしてあるプログラムの二つだけ、即ち、LEGO-Motor-Test.hsとLEGO-TouchSesor-Test.hsを紹介する。他は同じような構造なので、これから推察することができる。プログラムは次のようになっている。
import BrickHs import Control.Concurrent.Thread.Delay main = do clearTick result <- brickPiSetup print "BrickPiSetup: " print (show result) if result /= 0 then return () else do setAddress 0 1 setAddress 1 2 setMotorEnable port_a 1 setMotorEnable port_b 1 result1 <- brickPiSetupSensors print "BrickPiSetupSensors:" print (show result1) delay 10000 motor 0 1 return () motor time rot = do let time1 = if rot == 1 then time + 1 else time - 1 if rot == 1 then do setMotorSpeed port_a 200 setMotorSpeed port_b 200 else do setMotorSpeed port_a (-200) setMotorSpeed port_b (-200) brickPiUpdateValues delay 10000 if time1 > 300 then motor time1 0 else if time1 < 0 then motor time1 1 else motor time1 rot
このプログラムは前進と交代を繰り返す。それを実際に行っているのは関数motorの部分である。この関数で、回転方向を示しているのが、rotである。rotが1の時は前進で、そうでないときは後退である。また、その持ち時間はtimeで表している。前進しているときには、timeは増えていくが300に達したとき終わりで、今度は、後ろ向きに回転する。また、timeは減っていく。減っていくことの限界は0である。ここに達すると、前進となり、再び増えることになる。
モータやセンサへの制御データの伝達の仕方には一定のパターンがあって、最初に、刻んでいる時間をclearTickで初期化する。次に、BrickPiが使える状態にあるかどうかをbrickPiSetupで調べる。もしよければ、BrickPiのアドレスを設定する。ハードウェアのところで述べたが、BrickPiは分離した二つの部分(一つはモータA,B,ポート1,2、他の一つはモータC,D,ポート3,4)から成り立っているので、これらのアドレスである。次の、モータであれば、稼働させるための情報をsetMotorEnableで与える。この制御情報が伝達されたかどうかをbrickPiSetupSensorsで調べる。大丈夫のようならモータの回転速度をsetMotorSpeedで指定し、この情報をbrickPiUpdateValuesで伝達する。後は、この部分を繰り返す。
次は、タッチセンサである。このプログラムは以下のようになっている。モータのプログラムとの相違は、モータを駆動していた部分で、このセンサのタイプをsetSensorTypeで指定していることである。センサの場合にはタイプを指定することでどのセンサを使うかを特定する。このセンサが触られているかどうかの情報はgetSensorで得る。触っていれば1が返ってくる。そうでなければ0である。
import BrickHs import Control.Concurrent.Thread.Delay main = do clearTick result <- brickPiSetup print "BrickPiSetup: " print (show result) if result /= 0 then return () else do setAddress 0 1 setAddress 1 2 setSensorType port_1 type_sensor_touch result1 <- brickPiSetupSensors print "BrickPiSetupSensors:" print (show result1) if result1 /= 0 then return () else do delay 10000 touch return () touch = do result <- brickPiUpdateValues if result == 0 then do print "Results: " value <- getSensor port_1 print (show value) delay 10000 else delay 10000 touch return ()
なお、両方のプログラムで時間間隔を作るために、delayを用いた。これはマイクロ秒を単位としているが、この関数を利用するためにはconcurrent-extraのモジュールを必要とする。