さて,今回のテーマは交差点を越えてライントレースをすることである。ロボットには,NXTの光センサーとRCXの光センサーが1個ずつ付いているので,単に黒い線をトレースするのは難しいことではない。どちらかのセンサーが黒い線の上に来たら,一方のモーターを止めて,方向を修正すればいいのである。
しかし,行く手に交差点があると,少し難しくなってくる。片方のセンサーが黒いと判断したときに,もう一方のセンサーの値を判断することで交差点だと判断する。
つぎに,交差点を曲がる動作を考える必要がある。また,ゴールにたどり着くには,交差点で曲がる方向を間違えてはいけない。コースを見ていただくとわかるように,最初の交差点は右折,次の交差点では左折しなければならない。
なお,筆者の目的はゴールにたどり着くまでに,NXC言語の制御文と配列について説明することである。
今回のプログラムは,これまでのサンプルと比べると,かなり複雑なものになる。だから,プログラム自体は1ファイルなのだが,途中,途中に解説をはさみながら紹介していく(プログラム自体はずっとつながっている)。
-------------------------------------------------------------- #define THRESHOLD 45 #define CORRECT 14 #define SPEED 60 #define MSEC 50 --------------------------------------------------------------
プログラムが長く,複雑になると,関数とともに定数宣言が重要になる。定数THRESHOLDとCORRECTは前回説明した通り,黒い線を判断するしきい値とRCXの光センサー用の補正値である。今回追加したのは定数SPEEDとMSECだ。
SPEEDはモーターの回転速度で,MSECはモーターを回す時間だ。このように定数を宣言する目的は,この定数をプログラムの各個所で利用し,定数値を一カ所だけ直すことで,プログラム全体に変更を波及させることだ。
-------------------------------------------------------------- inline void setSensor() { SetSensorLight(IN_2); SetSensorType(IN_3,SENSOR_TYPE_LIGHT); SetSensorMode(IN_3,SENSOR_MODE_PERCENT); } --------------------------------------------------------------
setSensor関数はセンサーの初期設定をするインライン関数だ。
-------------------------------------------------------------- inline void Start() { TextOut(1,LCD_LINE2,"Start B"); TextOut(1,LCD_LINE3,"Start C"); OnFwd(OUT_BC, SPEED); } --------------------------------------------------------------
Start関数はLCDにStartと表示して,B,Cのモーターを回転させる。
-------------------------------------------------------------- void StopB(int msec) { Off(OUT_B); OnFwd(OUT_C, SPEED); TextOut(1,LCD_LINE2,"Stop B"); Wait(msec); } --------------------------------------------------------------
StopB関数は引数msecに指定された時間,Bポートにつないだモーターを停止させる。光センサーの値がしきい値を下回ったときの方向を調整する処理である。
-------------------------------------------------------------- void StopC(int msec) { Off(OUT_C); OnFwd(OUT_B, SPEED); TextOut(1,LCD_LINE3,"Stop C"); Wait(msec); } --------------------------------------------------------------
StopC関数はStopB関数と停止させるモーターのポートが違うだけだ。
-------------------------------------------------------------- void turnRight() { int j=0; while (j < 2) { TextOut(1,LCD_LINE4,"turn Right"); OnFwd(OUT_C, SPEED); if (Sensor(IN_3) + CORRECT < THRESHOLD) { j++; if (j < 2) { while (Sensor(IN_3) + CORRECT < THRESHOLD) { } } } } TextOut(1,LCD_LINE4,"Go Straight"); } --------------------------------------------------------------
turnRight関数は交差点を右折する処理である。繰り返しの制御文whileで二重のループを作っている。外側のループはjが2になると抜ける。何が2なのかというと,最初の画像をもう一度見てほしい。交差する黒い線をロボットが発見したあと,ポート3,つまり左側に付いている光センサーは,黒い線を2本見つけないといけない。
一本目はロボットの前に真っ直ぐ伸びている線だ。一本目を見つけると,j++でjに1を足す。この時点で,jは1だから,if (j < 2)の条件に合致するので,次のwhileループに入る。このwhile文を抜けるのは,センサーがTHRESHOLD以上の値を返したとき,つまり,右に旋回して黒い線を超えたときだ。続いて,2本目の黒い線を見つけるが,このときjは2になっているので,この線は越えずにturnRight関数を抜ける。2本目の線が,この後トレースして進む線なので,この線を越えてしまうとコースを見失ってしまう。
-------------------------------------------------------------- void turnLeft() { int j=0; while (j < 2) { TextOut(1,LCD_LINE4,"turn Left"); OnFwd(OUT_B, SPEED); if (Sensor(IN_2) < THRESHOLD) { j++; if (j < 2) { while (Sensor(IN_2) < THRESHOLD) { } } } } TextOut(1,LCD_LINE4,"Go Straight"); } --------------------------------------------------------------
turnLeft関数は左折用の関数だ。