目次 #contents * メンバー [#ibb85475] kiyomizu : スタート→ゴールを担当 suiden : ゴール→スタートを担当 * 課題の内容 [#w222b816] 図のようなコースを各自で作成した上で、次のような動作をするロボットを作成せよ。 コースの詳細については授業中説明する(下の図において、黒い線の太さは20mmで、線の中央までの距離がcm表示されている)。 + スタート地点から出発し、黒い線にそって動く。 + 一つ目の十字の交差点と二つめの十字の交差点の間に置かれたピンポン玉をつかむ。 + さらに黒線に沿って動いてゴール地点を目指す。 + ゴールに向けてピンポン玉をシュートする。 ただしT字路では、直進、右折、左折を正しく判断させること。また二人一組で同じロボットを使用し、互いにスタート地点とゴール地点を入れ替えること。ロボット本体は共通のものを使うとする。 さらに以下のような動作に挑戦することが望ましい。 + ゴールエリア外からピンポン玉をシュートする。 + 曲線部中央の障害物に接触しないようにすること。 &ref(2014a-mission1.png); * ロボットの紹介 [#qd0e48a4] &ref(robo1.jpg); &ref(robo2.jpg); &ref(robo3.jpg); &ref(robo4.jpg); &ref(robo5.jpg); &ref(robo6.jpg); &ref(robo7.jpg); * プログラムの内容 [#n91931a1] &ref(2014a-mission1-kouryaku.png); プログラムの内容を上の図のPartごとに分けて説明する。 ** Part0:定義 [#c2c9cc66] #define THRESHOLD 50 // しきい値を50に設定 #define turn_left0 OnFwd(OUT_B,50); // 左折 #define turn_left1 OnFwd(OUT_B,30);OnFwd(OUT_C,-30); // 左旋回 #define turn_right0 OnFwd(OUT_C,50); // 右折 #define turn_right1 OnFwd(OUT_C,30);OnFwd(OUT_B,-30); // 右旋回 #define STEP 1 // 1回の判断で動作させる時間 #define nMAX 250 // 通常のカーブとして許容できる繰り返し時間の最大値 #define short_break Off(OUT_BC);Wait(1000); // 小休止 #define cross_line OnFwd(OUT_BC,50);Wait(250);short_break;PlaySound(SOUND_UP); // ラインを横断 ** Part1 [#u87a2841] task main() { SetSensorLight(S1); long t0 = CurrentTick(); int nOnline = 0; int nPoint = 0; OnFwd(OUT_BC,30); Wait(700); Part1は、スタートの枠内から出るためのプログラムである。 ** Part2 [#q3248486] while (CurrentTick() - t0 < 10000) { if (SENSOR_1 < THRESHOLD -7) { turn_left1; } else { if (SENSOR_1 < THRESHOLD -5) { turn_left0; } else if (SENSOR_1 < THRESHOLD +2) { OnFwd(OUT_BC,50); } else if (SENSOR_1 < THRESHOLD +7) { turn_right0; } else { turn_right1; } Wait(STEP); } } Part2は、開始10秒未満のとき、ラインの左側をトレースするプログラムである。 ** Part3 [#c5040110] while (nPoint == 0) { while (nOnline < nMAX){ if (SENSOR_1 < THRESHOLD -7) { turn_left1; nOnline++; } else { if (SENSOR_1 < THRESHOLD -5) { turn_left0; } else if (SENSOR_1 < THRESHOLD +2) { OnFwd(OUT_BC,50); } else if (SENSOR_1 < THRESHOLD +7) { turn_right0; } else { turn_right1; } nOnline=0; } Wait(STEP); } short_break; turn_right1; Wait(nMAX*STEP); cross_line; nPoint++; nOnline=0; } Part3は、"nPoint=0"のとき(初期状態)、ラインの左側をトレースしつつ、交差点を渡るプログラムである。また、交差点を渡ったとき、nPointを+1してPart4に移行する。 ** Part4 [#t9300c7c] long t1 = CurrentTick(); while (nPoint == 1) { if (CurrentTick() - t1 == 5000) { Off(OUT_BC); RotateMotor(OUT_A,85,210); nPoint++; PlaySound(SOUND_UP); } else { if (SENSOR_1 < THRESHOLD -10) { turn_left1; } else if (SENSOR_1 < THRESHOLD -5) { turn_left0; } else if (SENSOR_1 < THRESHOLD +10) { turn_right0; } else { turn_right1; } Wait(STEP); } } Part4は、"nPoint=1"のとき、ラインの左側をトレースしつつ、Part4開始から5秒が経過したとき、アームを下ろしボールを確保するプログラムである。また、ボールを確保したとき、nPointを+1してPart5に移行する。 ** Part5 [#m89b5795] while (nPoint == 2) { while (nOnline < nMAX - 100){ if (SENSOR_1 < THRESHOLD -7) { turn_left1; nOnline++; } else { if (SENSOR_1 < THRESHOLD -5) { turn_left0; } else if (SENSOR_1 < THRESHOLD +2) { OnFwd(OUT_BC,50); } else if (SENSOR_1 < THRESHOLD +7) { turn_right0; } else { turn_right1; } nOnline=0; } Wait(STEP); } short_break; turn_right1; Wait(nMAX*STEP); cross_line; nOnline=0; nCross++; } Part5は、"nPoint=2"のとき、ラインの左側をトレースしつつ、交差点を渡るプログラムである。また、交差点を渡ったとき、nPointを+1してPart6に移行する。 中央の交差点を渡るとき、交差点ではなく通常のカーブと誤認識してしまうことが多かったため、"nMAX"を"nMAX - 100"に変更することで、誤認識を減らしている。 ** Part6 [#oa31f38f] while (nPoint == 3) { while (nOnline < nMAX){ if (SENSOR_1 < THRESHOLD -7) { turn_left1; nOnline++; } else { if (SENSOR_1 < THRESHOLD -5) { turn_left0; } else if (SENSOR_1 < THRESHOLD +2) { OnFwd(OUT_BC,50); } else if (SENSOR_1 < THRESHOLD +7) { turn_right0; } else { turn_right1; } nOnline=0; } Wait(STEP); } short_break; turn_left1; Wait(nMAX*STEP -50); cross_line; nOnline=0; nPoint++; } Part6は、"nPoint=3"のとき、ラインの左側をトレースしつつ、交差点を渡るプログラムである。また、交差点を渡ったとき、nPointを+1してPart7に移行する。 上部の交差点を渡るとき、斜めに横断してしまいラインの右側に出てしまうことが多かったため、"turn_right1"を"turn_left1"に、"nMAX*STEP"を"nMAX*STEP -50"変更することで、適当な時間で左に曲がりながら交差点を渡り、ラインの左側に出られるようにしている。 ** Part7 [#ibc0bdc7] while (nPoint == 4) { while (nOnline < nMAX){ if (SENSOR_1 < THRESHOLD -7) { turn_left1; nOnline++; } else { if (SENSOR_1 < THRESHOLD -5) { turn_left0; } else if (SENSOR_1 < THRESHOLD +2) { OnFwd(OUT_BC,50); } else if (SENSOR_1 < THRESHOLD +7) { turn_right0; } else { turn_right1; } nOnline=0; } Wait(STEP); } short_break; turn_right1; Wait(nMAX*STEP +100); OnFwd(OUT_BC,-50); Wait(500); nOnline=0; nPoint++; } Part7は、"nPoint=4"のとき、ラインの左側をトレースするプログラムである。また、ゴール前の直角カーブを交差点と認識するが、"cross_line"を"OnFwd(OUT_BC,-50); Wait(500)"に、nMAX*STEP"を"nMAX*STEP +100"に変更することで、正確にゴールに正対した後、後退する。そして、nPointを+1してPart7に移行する。 ** Part8 [#d79427ce] while (nPoint == 5) { RotateMotor(OUT_A,-100,90); PlaySound(SOUND_UP); Off(OUT_ABC); nPoint++; } } Part8は、"nPoint=5"のとき、アームを上げ、シュートを打つプログラムである。また、シュートを打った後、nPointを+1して"nPoint=6"にすることで条件から外し、プログラムを終了する。 ** 実際のプログラム [#g3c01e9c] 理解しやすくするためにPartごとに区切って説明したが、実際のプログラムはPart0:定義〜Part8までをつなげたものである。 * 感想・反省 [#y966b4ba] 今回の課題は、成功率10割を目指す中で細かい数値調整が必要だったため、全体で172行という膨大なプログラムになってしまった。 また、当初は超音波センサーを利用してボールを確保する予定であったが、うまくプログラムを組むことができず、簡単に組むことができるタイマーを利用するプログラムに変更したため、成功率が下がってしまった。 次の課題では、妥協することなく、ベストなプログラムを組めるようにしたい。