目次
下の図のようなコースを各チームで作成し、「ミッション」を遂行するためのロボットを作成せよ。
・E右折(SOUND_UP)
・P一時停止(SOUND_DOWN)&左折
・Q(SOUND_UP)&直進
・R(SOUND_UP)&左折
・T一時停止(SOUND_DOWN)&直進
・T一時停止(SOUND_DOWN)&直進
・H(SOUND_UP)
・G(SOUND_UP)
・S一時停止(SOUND_DOWN)&左折
・P直進(SOUND_UP)
・Q左折(SOUND_UP)
・F(SOUND_UP)
・E直進
・A停止(SOUND_DOWN)
コーススタート地点の枠内に収めないといけなく、説明書通りに作るロボットの形だと枠からはみ出てしまうので改造が必要だった。基本の形をベースとし、光センサーをボディの部分に近づけることでコンパクトになり、枠内に収めることが出来た。
・ライトレースは黒線と白の背景の部分の境界をたどる方法をとった。これは、黒線の右側をライトレースする場合だと、光センサーが白と判断した時は左に回転、黒だと判断した時は右に回転、その中間の値と判断した時は直進するといったものだ。また、大きく線から外れた場合は旋回、少し線から外れた場合はカーブするようにと、いくつか段階に分けることでなめらかにライトレースをすることが出来た。
・私が選んだ方のコースだと、片側の境界だけをたどっていると直角の曲がり角を判断出来ない場所が出てくるので、状況に応じて右側か左側のどちらをライトレースするか調節した。
・また、交差点や曲がり角を判断するのにはカウンタ方式をとった。これは、ある一定以上黒が続いたら、それは交差点であると認識するものだ。
・このライトレースは行う動作が多く、各交差点や曲がり角での動き方が異なる。だからそれぞれの動きをサブルーチンでまとめることで、タスクメインの中をスッキリさせることが出来た。
#define THRESHOLD 50 //しきい値 #define H_SPEED 30 //直進時の出力 #define SPEED 25 //カーブ時の出力 #define OnRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL); //直進(出力) #define go_forward OnRL(H_SPEED,H_SPEED); //直進 #define turn_left1 OnRL(SPEED, -SPEED); //左に旋回 #define turn_left0 OnRL(SPEED, 0); //左にカーブ #define turn_right0 OnRL(0, SPEED); //右にカーブ #define turn_right1 OnRL(-SPEED, SPEED); //右に旋回 #define STEP 1 //1回の判定で進む時間 #define nMAX 210 //通常のカーブとして許容できる繰り返しの最大値 #define short_break Off(OUT_BC); Wait(1000); //1秒間停止 #define cross_line go_forward;Wait(250); //交差点を渡る
・ラインの右側をライトレース
sub line_right_side() { SetSensorLight(S3); int nOnline=0; //続けて黒になった回数 while (nOnline < nMAX) { //続けて黒になった回数がある回数未満のときにこの動作を行う if (SENSOR_3 < THRESHOLD-10) { turn_right1; //右に旋回 nOnline++; //カウンタを増やす } else { if (SENSOR_3 < THRESHOLD-5) { turn_right0; //右にカーブ } else if (SENSOR_3 < THRESHOLD+5) { go_forward; //直進 } else if (SENSOR_3 < THRESHOLD+10) { turn_left0; //左にカーブ } else { turn_left1; //左に旋回 } nOnline=0; //カウンタをリセット } Wait(STEP); } }
・ラインの左側をライトレース
sub line_left_side() { SetSensorLight(S3); int nOnline=0; //続けて黒になった回数 while (nOnline < nMAX) { //続けて黒になった回数がある回数未満のときにこの動作を行う if (SENSOR_3 < THRESHOLD-10) { turn_left1; //左に旋回 nOnline++; //カウンタを増やす } else { if (SENSOR_3 < THRESHOLD-7) { turn_left0; //左にカーブ } else if (SENSOR_3 < THRESHOLD+7) { go_forward; //直進 } else if (SENSOR_3 < THRESHOLD+10) { turn_right0; //右にカーブ } else { turn_right1; //右に旋回 } nOnline=0; //カウンタをリセット } Wait(STEP); } }
・A地点から出発
sub hajime() { go_forward; //直進 Wait(500); }
・E地点右折
sub E_turn_right() { PlaySound(SOUND_UP); //音を鳴らす turn_right1; //右に旋回 Wait(450); go_forward; //黒線にたどり着くまで直進 until(SENSOR_3 <60); }
・P地点一時停止&左折
sub P_stop_turn_left() { short_break; //1秒間停止 PlaySound(SOUND_DOWN); //音を鳴らす turn_left1; //白になるまで左に旋回 until(SENSOR_3 >60); }
・Q地点直進
sub Q_go_straight() { PlaySound(SOUND_UP); //音を鳴らす turn_right1; //右に旋回 Wait(800); cross_line; //線を横断 }
・R地点左折
sub R_turn_left() { PlaySound(SOUND_UP); //音を鳴らす go_forward; //白になるまで直進 until(SENSOR_3 >60); }
・T地点一時停止&直進
sub T_stop_cross_line() { short_break; //1秒間停止 PlaySound(SOUND_DOWN); //音を鳴らす turn_left1; //左に旋回 Wait(150); Off(OUT_BC); cross_line; //交差点を横断 }
・H地点右折
sub H_turn_right() { PlaySound(SOUND_UP); //音を鳴らす turn_right1; //右に旋回 Wait(450); go_forward; //黒線にたどり着くまで直進 until(SENSOR_3 <60); }
・G地点右折
sub G_turn_right() { PlaySound(SOUND_UP); //音を鳴らす turn_right1; //右に旋回 Wait(300); go_forward; //白になるまで直進 until(SENSOR_3 >60); }
・S地点一時停止&左折
sub S_stop_turn_left() { short_break; //1秒間停止 PlaySound(SOUND_DOWN); //音を鳴らす turn_left1; //白になるまで左に旋回 until(SENSOR_3 >60); }
・P地点直進
sub P_go_straight() { PlaySound(SOUND_UP); //音を鳴らす turn_right1; //右に旋回 Wait(800); cross_line; //線を横断 }
・Q地点左折
sub Q_turn_left() { PlaySound(SOUND_UP); //音を鳴らす turn_left1; //左に旋回 Wait(10); go_forward; //白になるまで直進 until(SENSOR_3 >60); }
・F地点右折
sub F_turn_right() { PlaySound(SOUND_UP); //音を鳴らす turn_right1; //右に旋回 Wait(450); go_forward; //黒線にたどり着くまで直進 until(SENSOR_3 <60); }
・A地点に車庫入れ
sub end() { turn_left1; //左に旋回 Wait(150); go_forward; //直進 Wait(2000); Off(OUT_BC); PlaySound(SOUND_DOWN); //音を鳴らす }
task main() { SetSensorLight(S3); int nOnline=0; //続けて黒になった回数 hajime(); //A地点から出発 line_right_side(); E_turn_right();nOnline=0; //E地点右折 line_right_side(); P_stop_turn_left();nOnline=0; //P地点一時停止&左折 line_left_side(); Q_go_straight();nOnline=0; //Q地点直進 line_left_side(); R_turn_left();nOnline=0; //R地点左折 line_right_side(); repeat(2){ //カッコ内のことを2回繰り返す T_stop_cross_line();nOnline=0; //T地点一時停止&直進 line_right_side(); } H_turn_right();nOnline=0; //H地点右折 line_right_side(); G_turn_right();nOnline=0; //G地点右折 line_left_side(); S_stop_turn_left();nOnline=0; //S地点一時停止&左折 line_left_side(); P_go_straight();nOnline=0; //P地点直進 line_left_side(); Q_turn_left();nOnline=0; //Q地点左折 line_right_side(); F_turn_right();nOnline=0; //F地点右折 line_right_side(); end(); //A地点に車庫入れ }
苦労したところは、H地点からG地点の間の急カーブだ。カーブがきついので間違えて交差点と判断してしまうことが度々あった。そこはカウンタの最大の値を下げたり、線から外れた時に線に軌道修正する範囲を広げたりすることで問題を解消することが出来た。ただ、軌道修正することを意識したせいで、若干なめらかさが減ってしまったので、そこはもう少し調整する必要がありそうだ。最終的には問題なく最後までライトレース出来たので良かったと思う。