#contents * 課題2 [#n5b84371] #ref(2015b/Member/cst321/Mission2/2015b-mission2.png,100%,コース); 次の経路を黒い線にそって動くロボットを作成する (他のメンバーとは別の経路になるようにする)。ただし、なるべく速く正確に動くロボットになるように工夫して、交差点では1秒間停止すること。 B地点からA地点へ B地点 → P右折 → Q右折 → P左折 → Q左折 → Q直進 → P直進 → A地点 * ロボット本体 [#y406f53e] 今回のロボットと前回の一番大きな違いはセンサーがついているということだ。 そして、少し調整して、本体を小さくし、センサーをより近く、ロボットの中心に設置した。 &ref(2015b/Member/cst321/Mission2/IMG_1023.JPG,10%,本体); &ref(2015b/Member/cst321/Mission2/IMG_1025.JPG,10%,センサーの位置); そうすると、ロボットの本体が、よりきれいに線に沿って動ける。 * プログラム [#ce0c7a74] 今回のプルグラムは前の課題より複雑で長い。今回の課題の中心がプログラムだと思う。 特徴としては、このプログラムは路線図に従って、細かくプログラムした。 たとえば、BからP交差点までのプログラムとP交差点を渡るプログラムとP交差点からQ交差点までのプログラムは違う。 これが全体のプログラムだ!長いと思うので飛ばして、次の目次から詳細を少しずつ説明する。 #define THRE 39 #define WHRE 48 #define HBHRE 37 #define HWHRE 46 #define start1 SetPower(OUT_A,7);SetPower(OUT_C,7);OnFwd(OUT_AC); #define TR SetPower(OUT_A,5);SetPower(OUT_C,6);Off(OUT_AC);OnFwd(OUT_A);OnRev(OUT_C); #define TL SetPower(OUT_A,6);SetPower(OUT_C,5);Off(OUT_AC);OnFwd(OUT_C);OnRev(OUT_A); #define TRL SetPower(OUT_A,4);SetPower(OUT_C,1);Off(OUT_AC);OnFwd(OUT_A); #define TLL SetPower(OUT_A,1);SetPower(OUT_C,4);Off(OUT_AC);OnFwd(OUT_C); #define ST SetPower(OUT_A,4);SetPower(OUT_C,4);Off(OUT_AC);OnFwd(OUT_AC); #define Do 1047 #define LaF 831 #define SiF 932 #define Si 988 int x; sub music() { PlayTone(Do,20); Wait(30); PlayTone(Do,20); Wait(30); PlayTone(Do,20); Wait(30); PlayTone(Do,60); Wait(62); PlayTone(LaF,60); Wait(62); PlayTone(SiF,60); Wait(62); PlayTone(Do,20); Wait(42); PlayTone(Si,20); Wait(22); PlayTone(Do,90); Wait(92); } sub trace_1(){ if(SENSOR_2>WHRE) {TR;ClearTimer(0); } else if(SENSOR_2>HWHRE) {TRL; ClearTimer(0); } else if(SENSOR_2>THRE) {ST; ClearTimer(0); } else if(SENSOR_2>HBHRE) {TLL;ClearTimer(0); } else {TL; } } task main () { start1; Wait(120); SetSensor(SENSOR_2,SENSOR_LIGHT); x=0; ClearTimer(0); while (true) { while(FastTimer(0)<30&&x==0) { trace_1() } while(x==1) {TR;Wait(15);Off(OUT_AC);ClearTimer(0);x=x+1;} while(FastTimer(0)<22&&x==2) { trace_1() } while(FastTimer(0)<28&&x==3) { trace_1() } while(x==4) {TL;Wait(60);Off(OUT_AC);ClearTimer(0);x=x+1;} while(FastTimer(0)<27&&x==5) { trace_1() } while(x==6) {TL;Wait(60);Off(OUT_AC);x=x+1;ClearTimer(0);} while(FastTimer(0)<27&&x==7) // route Q to Q { trace_1() } while(x==8) {ST;Wait(30);Off(OUT_AC);ClearTimer(0);x=x+1;} while(FastTimer(0)<27&&x==9) // route Q to P { trace_1() } while(x==10) {ST;Wait(30);Off(OUT_AC);ClearTimer(0);x=x+1;} // P cross while(FastTimer(0)<27&&x==11) // route P to end { trace_1() } while(x==12) {TR;Wait(20);ST;Wait(100);Off(OUT_AC);Wait(100);music();ClearTimer(0);x=x+1;} Off(OUT_AC);Wait(100);x+=1;ClearTimer(0); } Off(OUT_AC); } ** Defineの応用 [#f1ee28b3] まず、自分が書いた路線の意色の閾値を設定した。 より綺麗に動いてもらえるため、単に白、黒、と真ん中の閾値だけではなく、白と真ん中の間の閾値と黒と真ん中の閾値を設定した。 THREとは真ん中で、WHREとは白 #define THRE 39 #define WHRE 48 #define HBHRE 37 #define HWHRE 46 次に、 今回のロボットは小さいため、普通のパワーの出力で動かすと、早く動いてしまうので、コントロールするのが難しい。ギアを変えるより、パワーを変えることにした。 そして、大回りするとき、一つの車輪を動かすだけではなく、 もう一個の車輪がやや逆の方向へ回すように設定されている。 #define start1 SetPower(OUT_A,7);SetPower(OUT_C,7);OnFwd(OUT_AC); #define TR SetPower(OUT_A,5);SetPower(OUT_C,6);Off(OUT_AC);OnFwd(OUT_A);OnRev(OUT_C); #define TL SetPower(OUT_A,6);SetPower(OUT_C,5);Off(OUT_AC);OnFwd(OUT_C);OnRev(OUT_A); #define TRL SetPower(OUT_A,4);SetPower(OUT_C,1);Off(OUT_AC);OnFwd(OUT_A); #define TLL SetPower(OUT_A,1);SetPower(OUT_C,4);Off(OUT_AC);OnFwd(OUT_C); #define ST SetPower(OUT_A,4);SetPower(OUT_C,4);Off(OUT_AC);OnFwd(OUT_AC); start1は最初の出発するところで使うのだ。 TRとは turn rightで、TLとはturn leftで、 加えて、 TRLとは Turn right little,TLLとはTurn left little, STとは straightだ。 ** Fasttimerの応用 [#jf9c7087] 道に沿って行くようにするプログラムの一部だ。 これはBからP交差点までのプログラムだ。 ここで、ロボットを道の右側に置くと道に沿っていけます。 while (true) { while(FastTimer(0)<30&&x==0) { if(SENSOR_2>WHRE) {TL;ClearTimer(0); } else if(SENSOR_2>HWHRE) {TLL; ClearTimer(0); } else if(SENSOR_2>THRE) {ST; ClearTimer(0); } else if(SENSOR_2>HBHRE) {TRL;ClearTimer(0); } else {TR; } ここではFasttimerとCleartimerを使う。つまり、Fasttimer<30というのは0.3秒以上で黒を探知すると、 このプログラムを飛ばして、次のプログラムに移る。 そして0.3秒以下だと、 センサーが白に触れると左回る、そしてCleartimerをする。 センサーが黒に触れると右回る、またCleartimerをする。 交差点に到着しなければ、次のプログラムには移らない。 ** subの応用 [#f995041a] ここで何回もラインライントレースをするので、その長いプログラムを短くするために、サブルーチンにしました。そうすると、プログラムのサイズが小さくなります。 sub trace_1(){ if(SENSOR_2>WHRE) {TR;ClearTimer(0); } else if(SENSOR_2>HWHRE) {TRL; ClearTimer(0); } else if(SENSOR_2>THRE) {ST; ClearTimer(0); } else if(SENSOR_2>HBHRE) {TLL;ClearTimer(0); } else {TL; } } ** カウントの応用 [#q9a03612] ロボットが多くのプログラムに混乱されないため、カウントを設置した。 Fastimerが各自の時間を超えた後、 Off(OUT_AC);Wait(100);x+=1;ClearTimer(0); というプログラムに移る、つまり、Cleartimerをして、カウントが一個増える。 そうすると、また上の新しい while(x==1)のところへ行く、 それが終わった後、またカウントが一個増えて、 while(x==2)のところへ行く。 カウントを使って、路線のすべての道と交差点で、ロボットを迷わせず、違うプログラムが入れられるようになった。 ** 二つの組み合わせ [#j9659a43] この二つの応用の組み合わせで、違う道で、違うFasttimerの上限が使える。 例えば、Q交差点で右を回るのが異常に難しく、Fasttimerの上限を30に設置すると、たまに、交差点で止まらず、すぐ右へ回る場合が多い。 そのため、Fasttimerの上限を22に設置しなければ成功率が低い。 結果、 while(FastTimer(0)<22&&x==2)というプログラムを使った。xが2カウントの同時に、Fasttimerが22より低いという条件を付けることになった。 * 問題 [#f19136e8] プログラムが長すぎて、ロボットへアップロードするのが時間がかかりすぎる。 なるべく短いプログラムがいいと思われる。 ロボット自体が小さく、早いので、どこでどのぐらいパワーが必要かを把握するには時間がかかりすぎる。 * 結果 [#xdf11e3d] 失敗するのが少なく、 道にそって綺麗に動いて、BからAまでに到着し、歌もきちんと出てるので、成功した! * ボーナス、成功の歌 [#r6c9fa55] この歌はFinal Fantasy の Victory Fanfareの前半だ。ロボットが終点に到着すると放送するようにプログラムした。 #define Do 1047 #define LaF 831 #define SiF 932 #define Si 988 sub music() { PlayTone(Do,20); Wait(30); PlayTone(Do,20); Wait(30); PlayTone(Do,20); Wait(30); PlayTone(Do,60); Wait(62); PlayTone(LaF,60); Wait(62); PlayTone(SiF,60); Wait(62); PlayTone(Do,20); Wait(42); PlayTone(Si,20); Wait(22); PlayTone(Do,90); Wait(92); } * 感想 [#ce4e7597] 今回すべてのプログラムが私一人で、書いたのではなく、同じロボットを使っている友達と一緒に閾値のことを検討し、そして、プログラムのことをお互いに意見を交換した。 友達が路線を書くから、プログラムまで、すべてをきちんととても細かくした。 私は逆におおざっぱですべてをやりたかったと思った。 結局 やはり、センサーが色を探知するには、路線をきちんと書かなきゃいけないと分かった。 そして、ロボットが綺麗に動くようにするためのプログラムは、やはりもっと細かく分ける必要があることが分かった。 二人で夜遅くまで10番教室で一緒に課題をやるのは、楽しかった。 今回の課題でいろいろなことが学んでいて、友達からも学んだ、ためになった。