[[2011a]] #contents *メンバー紹介 [#s79573c3] ***くまちゃん [#e0c68ca0] ***hiros [#t0a10068] *コース[#o7b65f32] #ref(map.JPG) 交差点がナナメだったりして、対策に苦労した。 *ハードウェア [#f69f9e3c] **マシン解説 [#c5dc4b39] #ref(machine.JPG) これがマシン。どことなくアプ○ラス。この形にしたのは、以前の形が直角を曲がるのに不向きな形だった為。 特徴は、タイヤの間を縮める事で回転したときのずれを少なくした事。 #ref(front.JPG) センサをタイヤのそばに置いて、制御のずれを減らした。 色々のせられる広いボディ。センサなどもつけやすい。 #ref(bottom.JPG) タイヤが近いので小回りが利く。 *ソフトウェア [#x9bb2a61] **くまちゃん [#g371cfff] #define THRESHOLD 40 #define FIRST_TIME 1700 #define SECOND_TIME 1500 #define THIRD_TIME 1500 #define FOURTH_TIME 1500 #define FIFTH_TIME 1500 #define TURN_TIME 0 task main() { SetSensor(SENSOR_1,SENSOR_LIGHT); SetSensor(SENSOR_3,SENSOR_LIGHT); ClearTimer(0); while (Timer(0) <= FIRST_TIME){ if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)){ OnFwd(OUT_A+OUT_C); } else if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)){ OnFwd(OUT_C); Off(OUT_A);} else if ((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD)){ OnFwd(OUT_A); Off(OUT_C);} else if ((SENSOR_1<THRESHOLD)&&(SENSOR_3<THRESHOLD)){ OnFwd(OUT_A); Off(OUT_C); PlaySound(SOUND_CLICK) ;} } ClearTimer(1); while (FIRST_TIME < Timer(1) <= SECOND_TIME) { if ((SENSOR_1<THRESHOLD)&&(SENSOR_3<THRESHOLD)){ Off(OUT_A+OUT_C); OnFwd(OUT_C); Wait(30); OnRev(OUT_A); Wait(30);} else if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)){ OnFwd(OUT_A); Off(OUT_C);} else if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)){ OnFwd(OUT_C); Off(OUT_A);} else if ((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD)){ OnFwd(OUT_A); Off(OUT_C); PlaySound(SOUND_CLICK) ;} } ClearTimer(2); while ( SECOND_TIME < Timer(2) <= THIRD_TIME ) { if ((SENSOR_1<THRESHOLD)&&(SENSOR_3<THRESHOLD)){ Off(OUT_A+OUT_C); OnFwd(OUT_C); Wait(50);} else if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)){ OnFwd(OUT_A); Off(OUT_C);} else if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)){ OnFwd(OUT_C); Off(OUT_A);} else if ((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD)){ OnFwd(OUT_A); Off(OUT_C); PlaySound(SOUND_CLICK) ;} } ClearTimer(3); while ( THIRD_TIME < Timer(3) <= FOURTH_TIME ) { if ((SENSOR_1<THRESHOLD)&&(SENSOR_3<THRESHOLD)){ Off(OUT_A+OUT_C); OnFwd(OUT_A); Wait(30); OnRev(OUT_C); Wait(30);} else if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)){ OnFwd(OUT_A); Off(OUT_C);} else if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)){ OnFwd(OUT_C); Off(OUT_A);} else if ((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD)){ OnFwd(OUT_A); Off(OUT_C); PlaySound(SOUND_CLICK) ;} ClearTimer(0); while (FOURTH_TIME <= Timer(0) <= FIFTH_TIME){ if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)){ OnFwd(OUT_C); } else if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)){ OnFwd(OUT_C); Off(OUT_A);} else if ((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD)){ OnFwd(OUT_A); Off(OUT_C);} else if ((SENSOR_1<THRESHOLD)&&(SENSOR_3<THRESHOLD)){ OnFwd(OUT_A); Off(OUT_C); PlaySound(SOUND_CLICK) ;} } ClearTimer(3); while ( Timer(3)<FIFTH_TIME ) { if ((SENSOR_1<THRESHOLD)&&(SENSOR_3<THRESHOLD)){ OnFwd(OUT_A);} else if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)){ OnFwd(OUT_A); Off(OUT_C);} else if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)){ OnFwd(OUT_C); Off(OUT_A);} else if ((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD)){ OnFwd(OUT_A); Off(OUT_C); PlaySound(SOUND_CLICK) ;} } } **hiros [#gfa35d61] 目標: できるだけ短く書きたい、とにかくわかりやすくしたい。そして出来ればどの紙でやっても動くようにしたい。 ***作戦(ロータリーなし) [#wbec58d9] 2つの光センサを使って、黒線を挟み、適時修正しながら進めていく。 まずはロータリーについては考えない事にした。 交差点に到達したら、まっすぐ先に進んでいくというプログラムを考えた。 交差点の判定は、「右も左も黒であれば、交差点」と考えた。 ***コード [#ca6c9af8] #define isBlack <40 #define isWhite >40 #define R SENSOR_3 #define L SENSOR_1 #define RM OUT_C #define LM OUT_A #define LINE 8 void go(){ OnFwd(RM+LM); } void tr(){ OnFwd(LM); //Off(RM); OnRev(RM); } void tl(){ OnFwd(RM); // Off(LM); OnRev(LM); } void move(){ if (L isWhite && R isWhite) go(); else if (L isWhite && R isBlack) tr(); else if (L isBlack && R isWhite) tl(); else if (L isBlack && R isBlack){ /* PlaySound(SOUND_CLICK); go(); Wait(LINE); } } task main (){ SetSensor (R, SENSOR_LIGHT); SetSensor (L, SENSOR_LIGHT); while (1){ move(); } } ***作戦(ロータリーなし改) [#qc954620] 上のコードでは、直角な交差点ではまっすぐに進むが、私たちの交差点はかなり斜めで、「右も左も黒」、という判定になりにくい。よって、コードを新しく考える必要があった。このコードは寝ぼけていたのでアイディア自体がおかしいかもしれない。 まず、右か左のどちらが最初に黒(道)にあたったかを変数で覚えておいて、そのときに反対側(つまり回転の外側)が何回行われたかを格納しておき、その回数だけ反対側(内側)のモータを動かせば機体を道に対して平行に出来ると考えた。 ***コード [#pf8e7b07] #define isBlack <40 #define isWhite >40 #define R SENSOR_3 #define L SENSOR_1 #define RM OUT_C #define LM OUT_A #define LINE 8 void go(){ OnFwd(RM+LM); } void tr(){ OnFwd(LM); OnRev(RM); } void tl(){ OnFwd(RM); OnRev(LM); } int whichWay = 0; // if 1 then it found the way on its right first. (else if 2 then left first.) int rcount = 0; //L is rcount late. int lcount = 0; //R is lcount late. void move(){ if (L isWhite && R isWhite) go(); else if (L isWhite && R isBlack){ tr(); whichWay = 1; rcount++; lcount = 0; } else if (L isBlack && R isWhite){ tl(); whichWay = 2; lcount++; rcount = 0; } else if (L isBlack && R isBlack){ if (whichWay == 1) PlaySound(SOUND_CLICK); if (whichWay == 2) PlaySound(SOUND_DOUBLE_BEEP); while (1){ go(); if (L isWhite && R isWhite){ if (whichWay == 1) { tl(); Wait (lcount); go(); Wait (LINE); / / if (L isWhite && R isWhite) break; }else if (whichWay == 2){ tr(); Wait (rcount); go(); Wait (LINE); / / if (L isWhite && R isWhite) break; } break; } } go(); Wait (LINE); Off(RM+LM); } } task main (){ SetSensor (R, SENSOR_LIGHT); SetSensor (L, SENSOR_LIGHT); while (1){ move(); } } ***作戦(ロータリーなし改改) [#w644155f] 上のコードは、交差点に入る前、機体が線に対して平行であればうまく行くが、現実的にはそれは難しいので、改良する必要があった。例えば、右が黒で、左は白であるとき、上のコードでは「右に道がある」ということになり、すぐ右に回転をしてしまう。これだと、斜めな交差点にさしかかると「右に回転ー>左に回転」の無限ループに陥って、その場から動かなくなってしまう。 なので、回転する前に判定を入れる事にした。 ***コード [#zdd515b3] ***作戦(ロータリーあり) [#kbebd074] ロータリーについて考えてみると、交差点との共通点である、「右も左も黒」という判定がある。 違いとしては、「前に道がない」ことなので、黒&黒となったときに、前に道があるかを探索して、もしなければもどり、右の道に進む。そのとき、「ロータリーである」と判定し、明らかな道がロータリー途中の道で、右にあったときにそれを一回とばす。 ちなみに、ここでハードウェアが大きく変わった。 ***コード [#z0dc924d] #define isBlack <40 #define isWhite >40 #define R SENSOR_3 #define L SENSOR_1 #define RM OUT_A #define LM OUT_C #define LINE 15 void go(){ OnFwd(RM+LM); } void tr(){ Off(LM + RM); OnRev(RM); OnFwd(LM); } void tl(){ Off(LM + RM); OnRev(LM); OnFwd(RM); } void gogo(){ if (R isWhite && L isWhite){ //road ahead go(); } else if (R isBlack && L isWhite){ //road on right tr(); } else if (R isWhite && L isBlack){ //road on left tl(); } else if (R isBlack && L isBlack){ //rotary or intersection // Cross line and look for road. If there was no road, then it must be the rotary. go(); Wait (LINE); // turn right a little, and if L isBlack then turn left to correct. // else turn right so that it will find the way, and this should be the rotary. tr(); Wait (5); if (L isBlack) { tl(); Wait (5); } else { // R (W -> B -> W) while (1){ if (R isBlack) break; tr(); } while (1){ if (R isWhite || L isBlack) break; tr(); } } } } task main (){ SetSensor (R, SENSOR_LIGHT); SetSensor (L, SENSOR_LIGHT); while (1){ gogo(); } } ***作戦(ロータリー改) [#eb1a9c52] 前回のコードは、何度も実行すれば何度か無事ゴールできた。ロータリーの処理をうっかり忘れていたので、多分まぐれだと思う。今回は、確実に自分の紙の上を走ればよしとした。よって、「黒&黒」になる回数をカウントして、ロータリーのところにあたったら左の道を通るようにした。そして、移動中に左ー>右のループに陥り動かなくなったときは前に進むように、bbbbという変数でコントロールする事にした。 #ref(markedmap.jpg) 上のピンクが黒黒判定の場所。青のところでループに陥る。 ***コード [#ac6664c5] //言い換え #define isBlack <40 #define isWhite >40 #define R SENSOR_3 #define L SENSOR_1 #define RM OUT_A #define LM OUT_C //各秒数 線を越すための値と90度回転 #define LINE 27 #define TTIME 70 //ターンするところ #define TURN_RIGHT1 3 #define TURN_RIGHT2 5 #define TURN_RIGHT3 8 #define TURN_RIGHT4 10 //とばすところ #define SKIP1 4 #define SKIP2 9 int bb = 0; //黒&黒のときの回数 int bbbb = 0; //動かなくなったかを判定 void go(){//前に進む OnFwd(RM+LM); } void tr(){//右に回転 Off(LM + RM); OnRev(RM); OnFwd(LM); } void tl(){//左に回転 Off(LM + RM); OnRev(LM); OnFwd(RM); } void gogo(){//一連の動き if (bbbb > 10) { //もし動かなかったら線は無視して前に進む go(); Wait (LINE); bbbb = 0; } if (R isWhite && L isWhite){ //road ahead go(); bbbb = 0; } else if (R isBlack && L isWhite){ //road on right tr(); bbbb++; } else if (R isWhite && L isBlack){ //road on left tl(); bbbb++; } else if (R isBlack && L isBlack){ //rotary or intersection bb++; PlaySound(SOUND_CLICK); Off(RM+LM); Wait (100); if (bb == TURN_RIGHT1 || bb == TURN_RIGHT2 || bb == TURN_RIGHT3 || bb == TURN_RIGHT4){ //rotary PlaySound(SOUND_UP); go(); Wait (LINE); tl(); Wait (TTIME); } else if (bb == SKIP1 || bb == SKIP2){ //skip ロータリー内のスキップ PlaySound(SOUND_LOW_BEEP); go(); Wait (LINE); tr(); Wait (40); } else { //skip 通常時の交差点 PlaySound(SOUND_DOWN); go(); Wait (LINE); } } } task main (){ SetSensor (R, SENSOR_LIGHT); SetSensor (L, SENSOR_LIGHT); while (1){// 無限ループ gogo(); } } *感想 [#y22b0902] **くまちゃん [#jd2fe435] ロータリーと急角度十字路の違いをプログラムするのが大変でした。 プログラムで乗り越えようと思ったのですが、できなかったのでコースを5ブロックに分けてタイマーをセットして乗り切りました。 **hiros [#b3330aaa] 最後のロータリー改で一応クリアしたが、納得がいく結果にならなかった。これだと、線を変えたときいちいち調整する必要が出てきて、非常に面倒。満足が出来ない結果となった。あと、紙のでこぼこ具合がかなり影響してしまうのがつらかった。比較的短く書けたのはよかったかもしれない。 #comment