さて,今回のテーマは交差点を越えてライントレースをすることである。ロボットには,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関数は左折用の関数だ。