A地点を出発し、次のいずれかの経路を黒い線にそって動くロボットを作成する (他のメンバーとは別の経路になるようにする)。
A地点から出発 → B → C(直進) → D(一時停止の後、直進) → E → F → G(一時停止の後、右折) → H → I → J(右折) → K(左折) → L(ピンポン玉をつかむ) → K(直進) → M(一時停止) → シュート→ A地点に入る(ゴール)
A地点から出発 → M → K(直進) → L(ピンポン玉をつかむ) → K(右折) → J(一時停止の後、左折) → I(直進) → H(直進) → G(左折) → F → E → D(一時停止の後、直進) → C(直進) → B(一時停止) → シュート→ A地点に入る(ゴール)
交差点では1秒間停止し、丁字路では直角方向に進入する時のみ一時停止すること。
僕は後者のMからBに向かうルートを選びました。
今回は走らせるロボットをできるだけコンパクトにすることを意識しました。また、より曲がりやすくするために光センサーを機体の中心の真下に付けようとも思ったのですが、相方のあらかじめ組んでいたプログラムに(悪い意味での)影響を与えてしまったため、写真のように前につける形に落ち着きました。
ピンポン玉を掴むアームは上下に動かすことができ、振り下ろすことでピンポン玉を前後に挟み、また横にも逃げられないようになっているので、この型でゴールまでこぼさずに運びきることができました。
Aを左のホイール、Cを右のホイール、Bをアームにそれぞれ接続しました。
まずは明るさと交差点で止まるまでの時間を以下のように設定しました。 明るさについては複数色に分けることも考えたのですが、プログラムを簡潔にすることを優先視した結果、一つの値でやることに決定しました。
#define black 39 #define run_time 30
次に、左右回転や直進などの簡単な動作について以下のように設定しました。 一つ目と二つ目は右左折、四つ目と五つ目はその場回転です。
#define right OnFwd(OUT_A);Off(OUT_C); #define left OnFwd(OUT_C);Off(OUT_A); #define straight OnFwd(OUT_AC); #define turn_left OnFwd(OUT_C);OnRev(OUT_A); #define turn_right OnFwd(OUT_A);OnRev(OUT_C);
ここではdefineとは違い、複雑な動作をサブルーチンによって8つ定義しました。
光センサーの示す値が‘black’よりも高い(白の上を走っている)なら右折(right)、そうでない(黒線の上を走っている)なら左折するように定義しました。また、黒線の上を‘run_time’よりも長く走っていた場合は1秒間止まるように定義しました。 2はこれの左右対称版です。
sub follow_line_left() { ClearTimer(0); while(FastTimer(0)<run_time){ if(SENSOR_2>black){ right; ClearTimer(0); }else{ left; } }Off(OUT_AC);Wait(100); }
sub follow_line_right() { ClearTimer(0); while(FastTimer(0)<run_time){ if(SENSOR_2>black){ left; ClearTimer(0); }else{ right; } }Off(OUT_AC);Wait(100); }
ここでは、直角の外側を曲がる際に、光センサーの位置が前にあることもあり遠回りをしてしまったため、前の二つとは逆に、白の上を長く走った際に一旦止まって回転するように定義しました。4は1、2の時と同様、これの左右対称版です。
sub corner_stop_left() { ClearTimer(0); while(FastTimer(0)<100){ if(SENSOR_2<black){ left; ClearTimer(0); }else{ right; } } Off(OUT_AC);Wait(50); while(SENSOR_2>black){ turn_right; } }
sub corner_stop_right() { ClearTimer(0); while(FastTimer(0)<100){ if(SENSOR_2<black){ right; ClearTimer(0); }else{ left; } } Off(OUT_AC);Wait(50); while(SENSOR_2>black){ turn_left; } }
これは黒の上にいる間はまっすぐ走り続けるプログラムで、交差点を乗り越える際にはこれを使いました。
sub cross_line() { while(SENSOR_2<black){ straight; } }
機体をピンポン玉の直前で止めるためには、1では難しいと感じたため、基本的には1と同様の、一定時間で止まるサブルーチンを新たに定義しました。
sub go_to_ball() { ClearTimer(1); FastTimer(1); while(FastTimer(1)<200){ if(SENSOR_2<black){ left; }else{ right; } } Off(OUT_AC); }
簡単です。アームを下げるだけです。ただ、下げる時間の調整には多少手間がかかりました。
sub ball_catch() { OnFwd(OUT_B);Wait(24); Off(OUT_B); }
アームを上げるのですがそれだけではシュートにならないのでそこに機体で押し込んでシュートを打つ動きをプラスしました。
sub ball_shoot() { OnRev(OUT_B);Wait(30); Off(OUT_B); straight;Wait(10); }
光センサーはセンサー2につなぎ、タイマーはFastTimerを使用しました。
task main() { SetSensor(SENSOR_2,SENSOR_LIGHT); ClearTimer(0); FastTimer(0);
はじめのカーブは右側トレースで、急なカーブにかかった時に変に曲がろうとせずにあえて線を乗り越えさせて、そこから左側トレースに切り替えました。
follow_line_right(); cross_line(); corner_stop_left(); follow_line_left();
左側トレースでLに向かい、ピンポン玉を掴みました。
cross_line(); Off(OUT_AC);Wait(50); go_to_ball(); ball_catch();
その場で左回転をし、右側トレースでKに戻ります。
turn_left;Wait(170); follow_line_right();
できるだけ円に沿うようにトレースさせるために一旦右を向かせて、ただ、それだけだと縁で急に曲がることができないため、軽く左折を挟んで自然に円のトレースに移行できるようにしました。
turn_right;Wait(20); cross_line(); Off(OUT_AC);Wait(50); left;Wait(40);
左側トレースと交差点の乗り越えを、交互に2回ずつ行い、最後に左側トレースでGに向かいます。
repeat(2){ follow_line_left(); cross_line(); } follow_line_left();
Gの交差点を乗り越え、左回転によってFの方向を向きます。
cross_line(); Off(OUT_AC);Wait(50); turn_left;Wait(20);
サブルーチンの4を使ってE、Fの外側をきれいに曲がり、右側トレースでDに向かいます。
corner_stop_right(); corner_stop_right(); follow_line_right();
Dの交差点を乗り越えて、右側トレースでBに向かいます。
cross_line(); Off(OUT_AC);Wait(50); follow_line_right();
最後止まる際に多少右側に向きが傾いてしまうので、左小回転で向きを微調整し、アームを上げて機体を前進させてシュートを打ちます。
turn_left;Wait(10); ball_shoot(); Off(OUT_AC); }
今回、走らせるロボットの概形自体は簡単にできたのですが、構想上では完璧だと思っていたプログラムが全く機能しないなど、非常に多くの点(特に左側トレースでやろうとしていた時のはじめのカーブ)で苦労しました。ですが、相方が解決策を一緒に練るのを手伝ってくれて、前に述べたカーブ問題を、二つ目のカーブで乗り越えるという形で解決することができました。 悔しかったと感じたのは、「丁字路では直角方向に進入する時のみ一時停止すること」に関してで、I、Hにおいて達成することができませんでした。 また、プログラムのほかにもピンポン玉をつかむことやシュート、運ぶ際にピンポン玉をこぼさないような設計をするのはとても難しく、ほかのチームのように発想の豊かな型にはなりませんでしたが、自分たちなりにはよくできたのではないかと思います。
総合的には、難しい点や失敗も多々あったけど、多くの達成感を得られた課題でした。