[[2017a/Member]] 目次 #contents * 課題について [#j76490ed] 課題は、ロボットにライントレースをさせることである。 詳しくは[[課題2>2017a/Mission2]]を参照 自分は、二つのコースからE地点直進コースを選択した。 * ロボット本体について [#r5ac83d8] #ref(2017a/Member/mitsu/Mission2/mission2-1.JPG,50%,光センサーのロボット) 今回のロボットはスタンダードな作りで、個人的に工夫した点は特にない。 しかし、センサーが中心にあるのでイメージはしやすくかんじた。 * プログラムについて [#e17d89c7] ** プログラムの大筋 [#wc0a1fca] ライントレースは黒線の左側をたどるようにし、交差点では、黒の部分の時間が長くなるので現在時刻CurrentTick()とt0の差の時間が一定時間を超えるとライントレースのループを抜け出すようにして判断した。 交差点から次の交差点までをひとつの塊と見なし、それぞれのサブルーチンを作った。 while(CurrentTick()-t0 < 250){ // 0.25秒でループから抜け出す if(SENSOR_1 > SIRO0){ turn_r1(); t0 = CurrentTick(); // リセット } else if (SENSOR_1 > SIRO1){ turn_r0(); t0 = CurrentTick(); // リセット } else if (SENSOR_1 > KURO1){ go_f(); t0 = CurrentTick(); // リセット } else if (SENSOR_1 > KURO0){ turn_l0(); t0 = CurrentTick(); // リセット } else { turn_l1(); // 最後はリセットしない } } また、交差点から次の交差点までをひとつの塊と見なし、それぞれのサブルーチンを作った。 ** モーターの対応 [#y962231c] //OUT_B -> 右側のモーター //OUT_C -> 左側のモーター ** 定義 [#z301f044] #define SPEED_H 25 // 速いスピードの出力 #define SPEED_L 20 // 遅いスピードの出力 #define KURO0 37 // より黒いところのしきい値 #define KURO1 44 // 少し黒いところのしきい値 #define SIRO0 57 // より白いところのしきい値 #define SIRO1 50 // 少し白いところのしきい値 #define OnRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL); // 直接出力を打ち込み、前後や回転させるもの SPEED_HとSPEED_Lを定義したのはいいが、途中からOnRL(speedR,speedL)ばかり使っているので、 あまり意味がなくなってしまった。 ** サブルーチン [#d0ab0057] sub oto1() // 停止してSOUND_UPの音を鳴らす { Off(OUT_BC); PlaySound(SOUND_UP); Wait(1000); } sub oto2() // 停止してSOUND_DOWNの音を鳴らす { Off(OUT_BC); PlaySound(SOUND_DOWN); Wait(1000); } 音は二種類使うのでサブルーチンを作った。 sub turn_l0() // 右側のモーターだけを動かして左折 { OnFwd(OUT_B,SPEED_H); Off(OUT_C); } sub turn_l1() // 両方のモーターを動かして左折 { OnRL(SPEED_H,-SPEED_L); } sub go_f() // 前進 { OnFwd(OUT_BC,SPEED_H); } sub turn_r0() // 左側のモーターだけを動かして右折 { OnFwd(OUT_C,SPEED_H); Off(OUT_B); } sub turn_r1() // 両方のモーターを動かして右折 { OnRL(-SPEED_L,SPEED_H); } 上記の五種類のサブルーチンは、作らなくてもよかったと思う。 sub sen_l() // 黒線の左側をトレースする { SetSensorLight(S1); long t0 = CurrentTick(); // 現在の時刻 while(CurrentTick()-t0 < 250){ // 0.25秒以内の時 if(SENSOR_1 > SIRO0){ // より白いところのとき turn_r1(); t0 = CurrentTick(); } else if (SENSOR_1 > SIRO1){ // 少し白いところのとき turn_r0(); t0 = CurrentTick(); } else if (SENSOR_1 > KURO1){ // 黒と白の間のとき go_f(); t0 = CurrentTick(); } else if (SENSOR_1 > KURO0){ // 少し黒いところのとき turn_l0(); t0 = CurrentTick(); } else { // より黒いところのとき turn_l1(); } // if } // 0.25秒 } sub hosei_l() // sen_lが止まったときに方向を戻す { turn_r1(); Wait(300); } sub en_l() // 円のところでトレースするとき { SetSensorLight(S1); long t0 = CurrentTick(); // 現在の時刻 while(CurrentTick()-t0 < 180){ if(SENSOR_1 > SIRO0){ OnRL(-20,20); t0 = CurrentTick(); } else if (SENSOR_1 > SIRO1){ OnRL(0,20); t0 = CurrentTick(); } else if(SENSOR_1 > KURO1){ go_f(); t0 = CurrentTick(); } else if (SENSOR_1 > KURO0){ OnRL(20,0); t0 = CurrentTick(); } else { OnRL(20,-10); } // if } // 0.18sec } hosei_lも必要なかったと思う。 円をトレースするときのサブルーチンは時間を短くした。 sub iti() { SetSensorLight(S1); long t0 = CurrentTick(); // 現在の時刻 while(CurrentTick()-t0 < 300){ if(SENSOR_1 > SIRO0){ OnRL(-30,15); t0 = CurrentTick(); } else if (SENSOR_1 > SIRO1){ turn_r0(); t0 = CurrentTick(); } else if (SENSOR_1 > KURO1){ go_f(); t0 = CurrentTick(); } else if (SENSOR_1 > KURO0){ turn_l0(); t0 = CurrentTick(); } else { OnRL(20,0); } // if } // 0.3sec oto1(); OnRL(20,20); while(SENSOR_1 < SIRO0){} OnRL(20,-30); while(SENSOR_1 > SIRO1){} while(SENSOR_1 < SIRO0){} } AからFまでのサブルーチン。 途中に急なカーブがあるので右折のときに大きく右側を引くようにした。 次につなげる部分では、一旦前進してから、線を横切って再び線の左に来るようにした。 少し前に出ることで次に真っ直ぐ入れるようにした。 sub ni() { sen_l(); oto1(); OnRL(30,-20); while(SENSOR_1 > SIRO1){} while(SENSOR_1 < SIRO0){} } FからQのサブルーチン。 次につなげる部分では、明るさで調節されるようにした。 sub san() { en_l(); oto1(); go_f(); while(SENSOR_1 < KURO1){} OnRL(-10,30); while(SENSOR_1 > KURO1){} } QからRのサブルーチン。 つなぎ部は、そのままではTの方向に行ってしまうので、一旦前進してから円の軌道に乗るようにした。 sub yon() { SetSensorLight(S1); long t0 = CurrentTick(); // 現在の時刻 while(CurrentTick()-t0 < 30){ if(SENSOR_1 > SIRO0){ OnRL(-10,20); t0 = CurrentTick(); } else if (SENSOR_1 > SIRO1){ OnRL(0,20); t0 = CurrentTick(); } else if (SENSOR_1 > KURO1){ go_f(); t0 = CurrentTick(); } else if (SENSOR_1 > KURO0){ OnRL(20,0); t0 = CurrentTick(); } else { OnRL(10,-10); } // if } // 0.03sec oto1(); } RからSのサブルーチン。 ここでは、普通の時間でやるとそのまま行ってしまうので、ぎりぎり止まるところまで調節した。 sub go() { sen_l(); oto1(); OnRL(30,-30); while(SENSOR_1 > SIRO1){} while(SENSOR_1 < SIRO1){} } SからGまでのサブルーチン。 ここは特に問題なく行けたので、あまり考えることはなかった。 sub roku() { SetSensorLight(S1); long t0 = CurrentTick(); // 現在の時刻 while(CurrentTick()-t0 < 400){ if(SENSOR_1 > SIRO0){ OnRL(-30,15); t0 = CurrentTick(); } else if (SENSOR_1 > SIRO1){ turn_r0(); t0 = CurrentTick(); } else if (SENSOR_1 > KURO1){ go_f(); t0 = CurrentTick(); } else if (SENSOR_1 > KURO0){ turn_l0(); t0 = CurrentTick(); } else { OnRL(15,-30); } // if } // 0.3sec Off(OUT_BC); OnRL(40,-20); while(SENSOR_1 > SIRO1){} while(SENSOR_1 < SIRO1){} Off(OUT_BC); t0 = CurrentTick(); // 現在の時刻 while(CurrentTick()-t0 < 250){ if(SENSOR_1 > SIRO0){ OnRL(-30,15); t0 = CurrentTick(); } else if (SENSOR_1 > SIRO1){ turn_r0(); t0 = CurrentTick(); } else if (SENSOR_1 > KURO1){ go_f(); t0 = CurrentTick(); } else if (SENSOR_1 > KURO0){ turn_l0(); t0 = CurrentTick(); } else { OnRL(20,0); } // if } // 0.3sec oto1(); turn_l1(); while(SENSOR_1 < KURO0){} } GからHのサブルーチン。 個人的にここが一番難しかった。 対応としては、カーブで最初のトレースのループから出て、そこから左折させて線の左にセンサーが来るようにした。 その後、再びトレースさせることで何とか乗り切った。 sub nana() { sen_l(); oto2(); go_f(); while(SENSOR_1 < KURO1){} OnRL(20,-20); while(SENSOR_1 < SIRO0){} } HからTのサブルーチン。 工夫した点は、停止後に前進してから左折させた点。 sub hati() { en_l(); oto2(); OnRL(-10,20); Wait(200); go_f(); Wait(300); OnRL(-10,20); while(SENSOR_1 > KURO1){} } TからTの円。 ここもnanaと同じようにして直進させた。 sub kyu() { sen_l(); oto2(); OnRL(20,20); while(SENSOR_1 < SIRO1){} OnRL(30,-20); while(SENSOR_1 > SIRO1){} while(SENSOR_1 < SIRO0){} } TからRのサブルーチン。 ここでは、つなぎの部分で一旦前進してから左折するようにした。 左折だけでやろうとすると曲がりきらずに止まってしまった。 sub itizero() { en_l(); oto1(); go_f(); while(SENSOR_1 < SIRO1){} OnRL(-20,30); while(SENSOR_1 > KURO1){} } RからSのサブルーチン。 ここはsanと同じようにして作った。 sub itiiti() { SetSensorLight(S1); long t0 = CurrentTick(); // 現在の時刻 while(CurrentTick()-t0 < 30){ if(SENSOR_1 > SIRO0){ OnRL(-10,20); t0 = CurrentTick(); } else if (SENSOR_1 > SIRO1){ OnRL(0,20); t0 = CurrentTick(); } else if (SENSOR_1 > KURO1){ go_f(); t0 = CurrentTick(); } else if (SENSOR_1 > KURO0){ OnRL(20,0); t0 = CurrentTick(); } else { OnRL(10,-10); } // if } // 0.3sec oto1(); } SからPのサブルーチン。 ここは、yonと同じようにして作った。 sub itini() { sen_l(); oto2(); turn_l1(); while(SENSOR_1 < SIRO0){} } PからEのサブルーチン。 ここは、goと同様にあまり難しくなかったと思った。 sub itisan() { sen_l(); oto2(); OnRL(30,-30); until (SENSOR_1 > KURO1) OnRL(30,-30); until (SENSOR_1 < KURO1) SetSensorLight(S1); long t0 = CurrentTick(); // 現在の時刻 while(CurrentTick()-t0 < 300){ if(SENSOR_1 > SIRO0){ OnRL(10,-20); t0 = CurrentTick(); } else if (SENSOR_1 > SIRO1){ OnRL(0,-20); t0 = CurrentTick(); } else if(SENSOR_1 > KURO1){ OnRL(-20,-20); t0 = CurrentTick(); } else if (SENSOR_1 > KURO0){ OnRL(-20,0); t0 = CurrentTick(); } else { OnRL(-20,10); } // if } // 0.3sec PlaySound(SOUND_DOWN); Off(OUT_BC); Wait(1000); } EからAのサブルーチン。 個人的には、ここが一番面白かったと思う。 AのT字路で止まるのではあまりおもしろくなかったので、180度回転して、バックで車庫入れをするようにした。 回転させるときは、KURO1より大きくなるまでとKURO1より小さくなるまでを続けた。 ** メイン [#of514cec] task main() { iti(); ni(); san(); yon(); go(); roku(); nana(); hati(); kyu(); itizero(); itiiti(); itini(); itisan(); } // main 前回の課題と同様にメインは確認がしやすいように一通りずつのサブルーチンで作った。 * 結果と反省 [#kdeac01c] また、プログラムを見てわかるように統一感がなく、無駄が多いものになってしまっている。 途中からやり方を変えたのに、その前のやり方が残っていたり、必要のないサブルーチンを作ってあったり、と変なものになってしまった。 次にプログラムを作るときは、全体的にしっかり統一したいと思う。 * 感想 [#x7517e8c] 今回の課題は、実際にやってみる前は簡単そうだと思っていたが、実際にやってるときはあまり上手くいかないことが多かった。前回の課題のときよりも反省すべき点は多いので、しっかりと振り返って悪い点をまとめていかなければならないと思った。 ペアで活動するものだが、あまり会話もなく、連携も取れてなかったと思う。 最後の課題ではしっかり協力したいと思った。