目次
詳しくは課題(2017a/Mission2)を参照。私はE地点右折コースでこの課題に取り組んだ。
当初私たちはタイヤとタイヤの間にセンサーを設置していた。しかしそれではロボット本体の影で白が正確に認識されなくなり上手くいかなかった。ロボット本体よりもセンサーを前方に取り付けることによりロボット本体の影によるセンサーで読み取る値のブレを軽減した。ただ説明書通りの設計だと規定のサイズを超えてしまうため、センサーをロボット本体に近づけて極力コンパクトにもした。
まず、今回のプログラムの中で使う頻度の高そうなものを定義した。
#define THRESHOLD 53 //しきい値を53に設定 #define SPEED 20 //速さは20% #define turn_left OnFwd(OUT_B,SPEED);OnRev(OUT_C,SPEED); //左旋回 #define turn_right OnFwd(OUT_C,SPEED);OnRev(OUT_B,SPEED); //右旋回 #define go_forward OnFwd(OUT_BC,SPEED); //直進 #define STEP 1 ////一回の判定で進む時間 #define cross_line go_forward;Wait(450); //交差点を直進
まず初めに線の右側をライントレースするプログラムを作成した。タイマーを使って、センサーが一定の時間以上“黒”に反応すると停止するプログラムである。
sub line_trace1() { SetSensorLight(S1); long t0 = CurrentTick(); while (CurrentTick()-t0 < 200) { if (SENSOR_1 < THRESHOLD -12) { //黒に反応したとき turn_right; } else if (SENSOR_1 > THRESHOLD +5) { //白に反応したとき turn_left; t0 = CurrentTick() } else { //その他、つまり境界線上であるとき go_forward; t0 = CurrentTick() } Wait(STEP); } }
次に線の左側をライントレースするプログラムを作成した。タイマーを使って、センサーが一定の時間以上“黒”に反応すると停止するプログラムである。line_trace1ではCurrentTick()-t0 < 200となっていたが左側をトレースする際には200の値を150にするほうが上手くいったので,その点でも少しline_trace1とは違う。
sub line_trace2() { SetSensorLight(S1); long t0 = CurrentTick(); while (CurrentTick()-t0 < 150) { if (SENSOR_1 < THRESHOLD -12) { turn_left; } else if (SENSOR_1 > THRESHOLD +5) { turn_right; t0 = CurrentTick() } else { go_forward; t0 = CurrentTick() } Wait(STEP); } }
このline_trace3は基本的にはline_trace1と同じではあるが、点FにおいてCurrentTick()-t0 < 200では反応を示さなかったため200の値を100に下げ、QF間専用のライントレースのサブルーチンを作った。
sub line_trace3() { SetSensorLight(S1); long t0 = CurrentTick(); while (CurrentTick()-t0 < 100) { if (SENSOR_1 < THRESHOLD -12) { turn_right; } else if (SENSOR_1 > THRESHOLD +5) { turn_left; t0 = CurrentTick() } else { go_forward; t0 = CurrentTick() } Wait(STEP); } }
line_trace4も基本的にはline_trace2と同じであるが、これが作られた理由はline_trace3が作られた理由と同じである。なおこのサブルーチンはQR間とPR2間専用のサブルーチンである。(このコースでは2回PRを通ることになるため二回目のPRをPR2とする)
sub line_trace4() { SetSensorLight(S1); long t0 = CurrentTick(); while (CurrentTick()-t0 < 100) { if (SENSOR_1 < THRESHOLD -12) { turn_left; } else if (SENSOR_1 > THRESHOLD +5) { turn_right; t0 = CurrentTick() } else { go_forward; t0 = CurrentTick() } Wait(STEP); } }
ここからはコースを13分割して細かくプログラミングしていくことで最後のtask mainをすっきりさせた。
sub AE() //AE間におけるサブルーチン { go_forward; //Aの枠内から出る Wait(500); Off(OUT_BC); line_trace1(); PlaySound(SOUND_UP); turn_right; Wait(300); Off(OUT_BC); }
PQからは線の左側をライントレースすることになるから、このサブルーチンの最後に左旋回を入れることで線の左側にロボットが出られるようにした。
sub EP() //EP間におけるサブルーチン { line_trace1(); Off(OUT_BC); PlaySound(SOUND_DOWN); Wait(200); go_forward; Wait(100); turn_left; //ここで線の左側に出る Wait(900); Off(OUT_BC); }
sub PQ() //PQ間におけるサブルーチン { line_trace2(); cross_line; Off(OUT_BC); }
ここで先述の通りR地点での反応が弱く反応するときと反応しないときが存在したので,QR間専用のライントレースのサブルーチンを作成した。以下PQ2でもQFでも同じであるのでその二つのところではこの文章を割愛させていただく。
sub QR() //QR間におけるサブルーチン { PlaySound(SOUND_UP); line_trace4(); PlaySound(SOUND_UP); }
TT間の円をライントレースする際に内側を回ると、センサーが黒に連続して反応してしまうため外側を回るようなプログラムにしたかった。そのために、RからTの交差点についたとき線の右に出られるようなプログラミングをした。
sub RT() //RT間におけるサブルーチン { turn_left; Wait(200); line_trace2(); Off(OUT_BC); PlaySound(SOUND_DOWN); Wait(200); Off(OUT_BC); turn_right; //ここで線の右側に出る Wait(500); cross_line; Off(OUT_BC); }
sub TT() //TT間におけるサブルーチン { line_trace1(); Off(OUT_BC); PlaySound(SOUND_DOWN); Wait(200); Off(OUT_BC); cross_line; Off(OUT_BC); }
sub TH() //TH間におけるサブルーチン { line_trace1(); PlaySound(SOUND_UP); }
ここのS字カーブのところで急カーブの内側をライントレースする際にセンサーが反応してしまうのでそこで右旋回を入れることで急カーブにも対応できるプログラムを作成した。
sub HG() //HG間におけるサブルーチン { line_trace1(); turn_right; Wait(1500); line_trace1(); PlaySound(SOUND_UP); turn_right; Wait(300); }
sub GS() //GS間におけるサブルーチン { line_trace1(); PlaySound(SOUND_DOWN); Wait(200); turn_left; Wait(1500); cross_line; Off(OUT_BC); }
sub SP() //SP間におけるサブルーチン { line_trace2(); cross_line; Off(OUT_BC); }
ここで線の右側に出るプログラムを作成した理由としては、地点Fでライントレースのサブルーチンを反応させるためと、地点Eでライントレースのサブルーチンを反応させないためである。
sub PQ2() //PQ2間におけるサブルーチン { PlaySound(SOUND_UP); line_trace4(); cross_line; //ここで線の右側に出る Off(OUT_BC); }
sub QF() //QF間におけるサブルーチン { PlaySound(SOUND_UP); line_trace3(); PlaySound(SOUND_UP); }
sub FA() //FA間におけるサブルーチン { line_trace1(); turn_left; Wait(500); go_forward; //ここでAの枠内に入る Wait(1000); Off(OUT_BC); PlaySound(SOUND_DOWN); }
task main() { AE(); EP(); PQ(); QR(); RT(); TT(); TH(); HG(); GS(); SP(); PQ2(); QF(); FA(); }
直進のときのスピードをもう少し上げていればミッション遂行タイムが早くなっていたかもしれない。 少し無駄な動きもあったのでもっとライントレースのサブルーチンの数値を厳密にすればもっとスマートな動きになったのではないかと思った。
今回も感じたことはやはり電池の電圧による差は大きいということである。少し前までうまくいっていたことであっても、電池の残量が減っていくにつれて走り方に微妙な差が生じてしまう。ただ、エンジニアはどんな環境におかれても機能する機構を作る必要があると感じた。今回はS字カーブのところで一番苦戦したが、なんとか間に合わせることができてよかった。前回の課題のときには定義を一つも入れていなかったので今回はその反省を生かして、定義をいろいろと作成しておき、全体的によりシンプルなプログラムにすることができた。次はよりスッキリとしたプログラムを目指していきたい。