[[2015b/Member]]

目次
#contents

* 課題 [#edfea612]
#ref(2015b/Member/fujiTaka/Mission2/2015b-mission2.png,100%)

上の図の黒い線をたどって動くロボットを作成する。

道順は、B→P右折→Q右折→P左折→Q左折→Q直進→P直進→A
(ロボットは黒線の左側を通るようになっている)


* ロボット本体 [#qbb7029a]

#ref(2015b/Member/fujiTaka/Mission2/1452177869585.jpg,50%)

コースの紙を折って保管していたため、折り目でもスムーズに進むために光センサー部分の両脇に滑らかな円形の部品を付けた。結果的に光の強さを一定にする効果もあった。



* プログラム [#a92e2067]

** 定義 [#q0f3be68]
 #define RIGHT OnRev(OUT_C);OnFwd(OUT_A);  //右旋回
 #define LEFT OnRev(OUT_A);OnFwd(OUT_C);  //左旋回
 #define TURN_RIGHT OnFwd(OUT_A);Off(OUT_C);  //右折
 #define TURN_LEFT OnFwd(OUT_C);Off(OUT_A);  //左折
 #define STREIGHT OnFwd(OUT_AC);  //直進
 #define TMAX 20


** メインプログラム [#m96c14f0]
 task main()
 {
      int t;
      t = 0;
 
      SetSensor(SENSOR_2, SENSOR_LIGHT);
 
***ライントレース [#hcc7294e]

光センサーによって計測された値が大きいほど前方が白く小さいほど黒いことを表している。
今回はロボットが黒線の左側を通るので、黒と判断した時は左へ、白と判断した時は右へ進むようにして、できるだけ黒線の左側と白紙部分の境目を進むようになっている。

   while(t <= 11){
 
       ClearTimer(0);
 
          while(FastTimer(0) < TMAX){
 
               if(SENSOR_2 > 54){               //とても白いとき右旋回
                  RIGHT;ClearTimer(0);
               } else if (SENSOR_2 < 42){       //とても黒いとき左旋回
                  LEFT;
               } else if (SENSOR_2 > 50){       //少し白いとき右折
                  TURN_RIGHT;ClearTimer(0);                                  //…&#65533;
                  TURN_RIGHT;ClearTimer(0);                                  
               } else if (SENSOR_2 < 44){       //少し黒いとき左折
                  TURN_LEFT;ClearTimer(0);
               } else {                         //黒線の境目で直進
                  STREIGHT;ClearTimer(0);
               }
          }

*** tについて [#k336d1b4]

変数を使い角を通る度に決められた動きをするようにしている。一つ前の所でwhileから出てくるとtの値が一つ増えるようにしている。それをif文でtの値ごとに違う動きをするようにプログラミングした。それぞれ決められた動きが終わるとライントレースに戻り、tの値が一定値を超えるまで続く。

                    t =  t + 1;
 
                       if(t == 1){                                            //P右折
                            PlaySound(SOUND_DOWN);Off(OUT_AC);Wait(100);             //…&#65533;
                            TURN_RIGHT;Wait(100);                                    //…&#65533;
                            PlaySound(SOUND_DOWN);Off(OUT_AC);Wait(100);            
                            TURN_RIGHT;Wait(100);                                   
                            Off(OUT_AC);Wait(100);
 
                       } else if(t == 2){                                     //Q右折
                            PlaySound(SOUND_UP);Off(OUT_AC);Wait(100);
                            STREIGHT;Wait(20);TURN_RIGHT;Wait(30);
                            Off(OUT_AC);Wait(100);
 
                       } else if(t == 3){                                     //一つ目の角を左折
                            TURN_LEFT;Wait(70);
 
                       } else if(t == 4){                                     //二つ目の角を左折
                            TURN_LEFT;Wait(150);
 
                       } else if(t == 5){                                     //三つ目の角を左折
                            LEFT;Wait(100);
 
                       } else if(t == 6){                                     //P左折
                            PlaySound(SOUND_DOWN);Off(OUT_AC);Wait(100);
                            TURN_LEFT;Wait(150);
                            Off(OUT_AC);Wait(100);
 
                       } else if(t == 7){                                     //Q左折
                            PlaySound(SOUND_UP);Off(OUT_AC);Wait(100);
                            LEFT;Wait(150);
                            Off(OUT_AC);Wait(100);
 
                       } else if(t == 8){                                     //Q直進
                            PlaySound(SOUND_DOWN);Off(OUT_AC);Wait(100);
                            STREIGHT;Wait(30);
                            Off(OUT_AC);Wait(100);
 
                       } else if(t == 9){                                     //P直進
                            PlaySound(SOUND_UP);Off(OUT_AC);Wait(100);
                            STREIGHT;Wait(30);
                            Off(OUT_AC);Wait(100);
 
                       } else if(t == 10){                                    //急カーブ
                            LEFT;Wait(50);                                 //…&#65533;
                            LEFT;Wait(50);                             
 
                       } else if(t == 11){                                    //急カーブ
                            LEFT;Wait(50);
 
                       }
   }
      STREIGHT;Wait(30);Off(OUT_AC);                                          //A到着
 }

** その他 [#p625b4e0]


***交差点 [#v2f2a97b]
交差点の判断にはタイマーを利用した。このプログラムでは光センサーによってとても黒いと判断された場合以外ではタイマーがリセットされることになっている。逆にタイマーが継続されるということは前方が黒い状態が続いているということになる。交差点では前方に黒線が横向きに現れ、継続的に黒を認識し続けることになるのでタイマーは継続されていく。これが一定時間以上継続されたときに交差点であるという判断をする。Tmaxはその目安の時間を定義したものである。

*** 閾値 [#ic6bed99]

閾値の設定ではロボットができるだけ滑らかに動くことが出来るように直線時の範囲が広くなるようにした。また、交差点の判別がしやすいようにLEFT、TURN_LEFTの範囲を特に狭くすることでTMAXが蓄積しやすいようにした。

*** 音 [#u031962b]

二種類の音が交差点のたびに交互になるようにし、ロボットが交差点を判別しているかどうかわかるようにした。

*** 交差点での動き [#kfffb5f3]

最初はuntilを使いセンサーが進行方向の黒線を読み取るまで回転するようにしていたが、回転する途中で関係ない黒線を読み取ってしまうことがあり安定しなかったため、ルール違反ではあるが回転時間を決めることにした。

*** 最後のカーブについて [#xf5e0704]

閾値の範囲やTMAXを変更すると交差点が曲がれなくなるため、最後の急カーブは交差点と同じように対処することにした。


プログラムについては、サブルーチンを使い黒線の右側を通る場合と左側を通る場合で分けてプログラムを組むつもりだったが、左右の切り替え時などがなかなか上手くいかず、期限に間に合いそうになかったためサブルーチンを使わないプログラムを作成した。



* 感想とまとめ [#a0f7f626]

今回はプログラムの意味をよく理解していなかったせいで効率の悪い曖昧なロボット制作となってしまった。その点は深く反省し二度とこんなことがないようにしたい。

プログラムについては、最後に試した段階でも成功率は6〜7割程度とあまり高くない。失敗の原因は主にただの直線を交差点や角と判別してしまうこと、最後の急カーブの二つであった。これらは閾値やTMAXの設定がうまくできていなかったせいだと考えている。もしくはセンサーの高さを工夫すれば良かったのかもしれない。

今回も反省点が多かったが次に生かしていきたいと思う。

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS