目次
#contents

*課題2:黒い線上を動くロボット [#s2a9e895]
次のような周回コース(黒い線)を動くロボットを作成せよ。

-通常の交差点が2箇所以上ある
-ロータリー型の交差点が1箇所以上ある (ロータリーでは反時計まわりに進む)
-直角に曲がるコーナーおよびそのコーナーをショートカットするコース(点線)が存在する
-急なヘアピンカーブが1箇所以上ある
-スタート地点に目印がある
-黒い線の幅は15〜20mm程度

センサー、モーターはいくつ使ってもよい。プログラムは次の2つを作成すること。

 1. 直角のコーナーを通る
 2. 直角のコーナーを通らない(近道する)

ただし互いに逆方向に周回すること。

*メンバー紹介 [#qf933802]
-イシイ(近道担当)
-ゆきち(直角コーナー担当)

*課題 [#q735ffe3]
**コースについて [#e3f78d38]
先生が例として挙げたコースとほとんど同じコースを作った。
コースの線の幅は15mmで統一した。

●コースの概要
#ref(course.jpg)

以下は、メンバーのロボットがたどるコース。

●イシイ(近道担当)のコース
#ref(course_ishii.jpg)
●ゆきち(直角コーナー担当)のコース
#ref(course_yukichi.JPG)
**ロボットについて [#ic2a75be]
ロボットは四輪の車体に光センサーを取り付けたシンプルな作りになった。

●全体
#ref(trace_robot.JPG)

●光センサー

シンプル、と言っても、光センサーの取り付け方には注意した。
#ref(sensor.JPG)
3センチという幅は組み立ての際に偶然たどり着いた値だが、広すぎず狭すぎない幅だった。広すぎればラインに対する反応が遅れ、カーブを曲がりきれない。また、狭すぎればロボットがコースの曲線に過剰に反応してしまい、一周を回るのにかかる時間が長くなると予想できる。

もう一点、光センサーとロボットを旋回させたときの回転軸との距離に注意した。
#ref(trace_robot_side.JPG)
この距離が長ければ、わずかに旋回しただけでも光センサーが大きく動くことになってしまい、急カーブでラインを追いかけることが難しくなると考えた。その点を意識してロボットを作った。


*プログラム [#o770212f]
**イシイ [#d645274a]
#ref(course_ishii.jpg)
 #define go(t) OnFwd(OUT_A+OUT_C);Wait(t);Off(OUT_A+OUT_C);             //直進
 #define turn_r(t) OnFwd(OUT_A);OnRev(OUT_C);Wait(t);Off(OUT_A+OUT_C);  //右旋回
 #define turn_l(t) OnFwd(OUT_C);OnRev(OUT_A);Wait(t);Off(OUT_A+OUT_C);  //左旋回
 #define THRESHOLD 45                                                   //閾値
 
 task main()
 {
   SetSensor(SENSOR_1,SENSOR_LIGHT);
   SetSensor(SENSOR_3,SENSOR_LIGHT);
  
   ClearTimer(0);                     //タイマーをリセット
   while(FastTimer(0)<=500)           //5秒後まで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_1<THRESHOLD)
     {
       turn_l(10);                    //センサー1が反応したら左旋回
       turn_l(10);                    //センサー1が反応したら0.1秒左旋回
     }
     if(SENSOR_3<THRESHOLD)
     {
       go(20);                        //センサー3が反応したら直進
       go(20);                        //センサー3が反応したら0.2秒直進
     }
   }
   ClearTimer(0);                     //タイマーをリセット
   while(FastTimer(0)<=800)           //8秒後まで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_3<THRESHOLD)
     {
       turn_r(10);                    //センサー3が反応したら右旋回
       turn_r(10);                    //センサー3が反応したら0.1秒右旋回
     }
     if(SENSOR_1<THRESHOLD)
     {
       go(20);                        //センサー1が反応したら直進
       go(20);                        //センサー1が反応したら0.2秒直進
     }
   }
   ClearTimer(0);                     //タイマーをリセット
   while(FastTimer(0)<=150)           //1.5秒後まで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_3<THRESHOLD)
     {
       turn_r(10)
       turn_r(10)                     //センサー3が反応したら0.1秒右旋回
     }
     if(SENSOR_1<THRESHOLD)
     {
       go(50);
       turn_r(70);
       turn_r(70);                    //センサー1が反応したら0.5秒直進し、0.7秒右旋回
     }
   }
                                      //1回目のロータリー
   ClearTimer(0);                     //タイマーをリセット
   while(FastTimer(0)<=350)           //3.5秒後まで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_1<THRESHOLD)
     {
       turn_l(10)                     //センサー1が反応したら左旋回
       turn_l(10)                     //センサー1が反応したら0.1秒左旋回
     }
   }
   ClearTimer(0);                     //タイマーをリセット
   while(FastTimer(0)<=250)           //2.5秒後まで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_1<THRESHOLD)
     {
       turn_l(10);                    //センサー1が反応したら左旋回
       turn_l(10);                    //センサー1が反応したら0.1秒左旋回
     }
     if(SENSOR_3<THRESHOLD)
     {
       go(50)
       turn_r(60);                    //センサー3が反応したら
       turn_r(60);                    //センサー3が反応したら0.5秒直進し、0.6秒右旋回
     }
   }
   ClearTimer(0);                     //タイマーをリセット
   while(FastTimer(0)<=550)           //5.5秒後まで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_3<THRESHOLD)
     {
       turn_r(20);
       turn_r(20);                    センサー3が反応したら0.2秒右旋回
     }
   }
   ClearTimer(0);                     //タイマーをリセット
   while(FastTimer(0)<=300)           //3秒後まで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_3<=THRESHOLD)
     {
       turn_r(10);
       turn_r(10);                    //センサー3が反応したら0.1秒右旋回
     }
     if(SENSOR_1<=THRESHOLD)
     {
       go(50);
       turn_r(80);
       turn_r(80);                    //センサー1が反応したら0.5秒直進し、0.8秒右旋回
     }
   }
                                      //2回目のロータリー
   ClearTimer(0);                     //タイマーをリセット
   while(FastTimer(0)<=350)           //3.5秒後まで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_1<THRESHOLD)
     {
       turn_l(10)
       turn_l(10)                     //センサー1が反応したら0.1秒左旋回
     }
   }
   ClearTimer(0);                     //タイマーをリセット
   while(FastTimer(0)<=250)           //2.5秒後まで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_1<THRESHOLD)
     {
       turn_l(10);
       turn_l(10);                    //センサー1が反応したら0.1秒左旋回
     }
     if(SENSOR_3<THRESHOLD)
     {
       go(50)
       turn_r(100);
       turn_r(100);                   //センサー3が反応したら0.5秒直進し、1秒右旋回
     }
   }
   ClearTimer(0);                     //タイマーをリセット
   while(FastTimer(0)<=400)           //4秒後まで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_3<=THRESHOLD)
     {
       turn_r(10);
       turn_r(10);                    //センサー3が反応したら0.1秒右旋回
     }
     if(SENSOR_1<=THRESHOLD)
     {
       go(25);
       OnFwd(OUT_A);
       Wait(20);
       Off(OUT_A);
       Off(OUT_A);                    センサー1が反応したら0.25秒直進し、0.2秒左車輪のみ前進
     }
   }
                                      //ヘアピンカーブ
   ClearTimer(0);                     //タイマーをリセット
   while(FastTimer(0)<=600)           //6秒後まで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_3<=THRESHOLD)
     {
       OnRev(OUT_A+OUT_C);
       Wait(10);
       Off(OUT_A+OUT_C);
       turn_r(20);
       turn_r(20);                    //センサー3が反応したら0.1秒後退し、0.2秒右旋回
     }
   }
   ClearTimer(0);                     //タイマーをリセット
   while(FastTimer(0)<=400)           //4秒後まで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_1<THRESHOLD)
     {
       turn_l(10);
       turn_l(10);                    //センサー1が反応したら0.1秒左旋回
     }
     if(SENSOR_3<THRESHOLD)
     {
       go(25);
       go(25);                        //センサー3が反応したら0.25秒直進
     }
   }
   while(SENSOR_3<THRESHOLD)          //センサー3が反応するまで繰り返し
   {
     OnFwd(OUT_A+OUT_C);
     OnFwd(OUT_A+OUT_C);              //前進
     if(SENSOR_1<THRESHOLD)
     {
       turn_l(10);
       turn_l(10);                    //センサー1が反応したら0.1秒左旋回
     }
   }
   Off(OUT_A+OUT_C);
 } 


**ゆきち [#i0f9386d]
#ref(course_yukichi.JPG)
-右カーブと左カーブのそれぞれを曲がるだけならば必要なセンサーがどちらか一方であることを考え、交差点などでのコースの誤認をかなり少なくできた。
-右カーブ、左カーブ、ロータリーを移動するプログラムのサブルーチンを定義し、プログラムを短くできた。
-タイマーをアバウトに使い、さらに光センサーによる判定を組み合わせることで、ライントレースの精度を高めることができた。
 #define GO(t) OnFwd(OUT_A+OUT_C);Wait(t);Off(OUT_A+OUT_C); //前にt秒進む
 #define THRESHOLD 45  //明るさを判定する基準値。
 
 
 sub RIGHT_CURVE()                      //コースが右にカーブしているときのプログラム
   {                  //右側のセンサー3のみを考慮します。
         if (SENSOR_3>THRESHOLD)//センサーに反応がなければ直進。
           {
             OnFwd(OUT_A+OUT_C);
           }
         if (SENSOR_3<THRESHOLD)//センサーに反応があれば、右にカーブします。
           {
             Off(OUT_C);
             OnFwd(OUT_A);
           }
    }
 sub LEFT_CURVE()                       //コースが左にカーブしているときのプログラム
   {                  //左側のセンサー1のみを考慮します。
         if (SENSOR_1>THRESHOLD)        //センサーに反応がなければ直進。
           {
             OnFwd(OUT_A+OUT_C);
           }
         if (SENSOR_1<THRESHOLD)        //センサーに反応があれば、左にカーブします。
           {
             Off(OUT_A);
             OnFwd(OUT_C);
           }
   }
 
 sub ROTARY()               //ロータリーのプログラム。
  {                    //ロータリーに入った時点から、このプログラムを使用します。
    GO(35);
    OnFwd(OUT_A);OnRev(OUT_C);Wait(20)   //ロボットの回転の中心がロータリーの黒線上に来るように移動。
    
   while(SENSOR_1>THRESHOLD)          
      {
    OnFwd(OUT_A);
    OnRev(OUT_C);
          } 
     Off(OUT_A+OUT_C);                 
 
     OnFwd(OUT_A+OUT_C);         //この時点で、ロータリーの黒線が二つのセンサーの間にあります。
 
     ClearTimer(0);
 
   while(FastTimer(0)<400)        //4秒という時間は、一つ目の分岐を通りすぎるのに十分な時間です。
     {
            LEFT_CURVE();                 //その間、ロータリーを左カーブとみなすことができます。 
     }
 
   while(SENSOR_3>THRESHOLD)       //4秒以降に3センサーが黒線を感知するとき、ロータリーの出口に達したことになります。
     {
             LEFT_CURVE();        //それまでは、ロータリーを左カーブとみなします。
     } 
 
    Off(OUT_A+OUT_C);GO(35);
    OnFwd(OUT_A);OnRev(OUT_C);Wait(20);   //入ったときと同様に、ロボットの回転の中心がロータリーの黒線上にあるように移動します。
    
   while(SENSOR_1>THRESHOLD)
      {
    OnFwd(OUT_A);OnRev(OUT_C);
          }                 //この時点でロータリーから伸びる黒線が二つのセンサーの間にあります。
  }                        //ロータリーを抜けました。
 
 
 task main()
 {
     SetSensor(SENSOR_1,SENSOR_LIGHT);
     SetSensor(SENSOR_3,SENSOR_LIGHT);     //センサー1、3を光センサーと定義。
 
     ClearTimer(0);
 
    while(FastTimer(0)<=330)         //最初はなだらかな右カーブ。
       {
          RIGHT_CURVE();
        }
 
    while(FastTimer(0)<=850)        //ここは左の急カーブなので、別のプログラムを使います。
        {
         if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD))
           {
             OnFwd(OUT_A+OUT_C);
           }
         if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)) 
                                          //反対のタイヤを逆回転させることで、急カーブを回りきります。
           {
             OnRev(OUT_A);
             OnFwd(OUT_C);
           }
        }
 
    while(FastTimer(0)<=1100)          //緩やかな左カーブ
       {
             LEFT_CURVE();
     }
 
   while(SENSOR_3>THRESHOLD)          //ロータリーまで、左カーブが続きます。
      {
            LEFT_CURVE();
          }
 
    Off(OUT_A+OUT_C);             //ロータリー入り口で停止。
 
    ROTARY;
 
    ClearTimer(0);
 
   while(FastTimer(0)<300)
     {
        LEFT_CURVE();
     }
 
   GO(50);                 //近道を無視します。
 
   while(FastTimer(0)<700||SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD)
                                         //直角カーブを回るため、急カーブのときと同じプログラムを使用。
     {                  //ロータリーを感知するまでこのプログラムを継続します。
        if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD))
          {
            OnFwd(OUT_A+OUT_C);
          }
        if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD))
          {
            OnRev(OUT_A);
            OnFwd(OUT_C);
          }
    }
 
    Off(OUT_A+OUT_C);           //ロータリー入り口。
 
    ROTARY;
 
    ClearTimer(0);
 
   while(SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD)
     {
            LEFT_CURVE();    
     }
 
   GO(15);                 //交差点を無視して進みます。
 
   while(SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD)
     {
            LEFT_CURVE();    
     }
 
   GO(10);                 //交差点を無視。
 
   while(SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD)
                                            //「どちらかが白である間、継続」つまり「ゴールの黒線を感知するまで継続」
     {
        if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD))
        {
            OnFwd(OUT_A+OUT_C);
          }
        if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD))
          {
            OnRev(OUT_A);OnFwd(OUT_C);
          } 
        if ((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD))
          {
            OnRev(OUT_C);OnFwd(OUT_A);
          } 
     }
 
   Off(OUT_A+OUT_C);                        //ゴール
 }

*反省・感想 [#m39f9cd2]
-タイマーを上手く利用して動かすことができたが、時間の調整がとても大変だった。
-論理式を有効に活用することでコースの判定の精度を高めることができた。
-プログラムを短くするのが大変だった。
-プログラムには試行錯誤を繰り返したが、ロボットの改良はほとんどしなかった。先輩方のホームページを見ると、「光センサーと回転軸の距離」を詰めるためにロボットを大幅に改造したものもあり、次回の課題ではロボットとプログラムの二面から課題にアプローチしたいと感じた。


*コメントをお願いします [#d155cfe7]
#comment



トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS