目次

課題2:黒い線上を動くロボット

次のような周回コース(黒い線)を動くロボットを作成せよ。

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

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

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

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

メンバー紹介

  • イシイ(近道担当)
  • ゆきち(直角コーナー担当)

課題

コースについて

先生が例として挙げたコースとほとんど同じコースを作った。 コースの線の幅は15mmで統一した。

●コースの概要

course.jpg

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

●イシイ(近道担当)のコース

course_ishii.jpg

●ゆきち(直角コーナー担当)のコース

course_yukichi.JPG

ロボットについて

ロボットは四輪の車体に光センサーを取り付けたシンプルな作りになった。

●全体

trace_robot.JPG

●光センサー

シンプル、と言っても、光センサーの取り付け方には注意した。

sensor.JPG

3センチという幅は組み立ての際に偶然たどり着いた値だが、広すぎず狭すぎない幅だった。広すぎればラインに対する反応が遅れ、カーブを曲がりきれない。また、狭すぎればロボットがコースの曲線に過剰に反応してしまい、一周を回るのにかかる時間が長くなると予想できる。

もう一点、光センサーとロボットを旋回させたときの回転軸との距離に注意した。

trace_robot_side.JPG

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

プログラム

イシイ

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);              //前進
    if(SENSOR_1<THRESHOLD)
    {
      turn_l(10);                    //センサー1が反応したら0.1秒左旋回
    }
    if(SENSOR_3<THRESHOLD)
    {
      go(20);                        //センサー3が反応したら0.2秒直進
    }
  }
  ClearTimer(0);                     //タイマーをリセット
  while(FastTimer(0)<=800)           //8秒後まで繰り返し
  {
    OnFwd(OUT_A+OUT_C);              //前進
    if(SENSOR_3<THRESHOLD)
    {
      turn_r(10);                    //センサー3が反応したら0.1秒右旋回
    }
    if(SENSOR_1<THRESHOLD)
    {
      go(20);                        //センサー1が反応したら0.2秒直進
    }
  }
  ClearTimer(0);                     //タイマーをリセット
  while(FastTimer(0)<=150)           //1.5秒後まで繰り返し
  {
    OnFwd(OUT_A+OUT_C);              //前進
    if(SENSOR_3<THRESHOLD)
    {
      turn_r(10)                     //センサー3が反応したら0.1秒右旋回
    }
    if(SENSOR_1<THRESHOLD)
    {
      go(50);
      turn_r(70);                    //センサー1が反応したら0.5秒直進し、0.7秒右旋回
    }
  }
                                     //1回目のロータリー
  ClearTimer(0);                     //タイマーをリセット
  while(FastTimer(0)<=350)           //3.5秒後まで繰り返し
  {
    OnFwd(OUT_A+OUT_C);              //前進
    if(SENSOR_1<THRESHOLD)
    {
      turn_l(10)                     //センサー1が反応したら0.1秒左旋回
    }
  }
  ClearTimer(0);                     //タイマーをリセット
  while(FastTimer(0)<=250)           //2.5秒後まで繰り返し
  {
    OnFwd(OUT_A+OUT_C);              //前進
    if(SENSOR_1<THRESHOLD)
    {
      turn_l(10);                    //センサー1が反応したら0.1秒左旋回
    }
    if(SENSOR_3<THRESHOLD)
    {
      go(50)
      turn_r(60);                    //センサー3が反応したら0.5秒直進し、0.6秒右旋回
    }
  }
  ClearTimer(0);                     //タイマーをリセット
  while(FastTimer(0)<=550)           //5.5秒後まで繰り返し
  {
    OnFwd(OUT_A+OUT_C);              //前進
    if(SENSOR_3<THRESHOLD)
    {
      turn_r(20);                    センサー3が反応したら0.2秒右旋回
    }
  }
  ClearTimer(0);                     //タイマーをリセット
  while(FastTimer(0)<=300)           //3秒後まで繰り返し
  {
    OnFwd(OUT_A+OUT_C);              //前進
    if(SENSOR_3<=THRESHOLD)
    {
      turn_r(10);                    //センサー3が反応したら0.1秒右旋回
    }
    if(SENSOR_1<=THRESHOLD)
    {
      go(50);
      turn_r(80);                    //センサー1が反応したら0.5秒直進し、0.8秒右旋回
    }
  }
                                     //2回目のロータリー
  ClearTimer(0);                     //タイマーをリセット
  while(FastTimer(0)<=350)           //3.5秒後まで繰り返し
  {
    OnFwd(OUT_A+OUT_C);              //前進
    if(SENSOR_1<THRESHOLD)
    {
      turn_l(10)                     //センサー1が反応したら0.1秒左旋回
    }
  }
  ClearTimer(0);                     //タイマーをリセット
  while(FastTimer(0)<=250)           //2.5秒後まで繰り返し
  {
    OnFwd(OUT_A+OUT_C);              //前進
    if(SENSOR_1<THRESHOLD)
    {
      turn_l(10);                    //センサー1が反応したら0.1秒左旋回
    }
    if(SENSOR_3<THRESHOLD)
    {
      go(50)
      turn_r(100);                   //センサー3が反応したら0.5秒直進し、1秒右旋回
    }
  }
  ClearTimer(0);                     //タイマーをリセット
  while(FastTimer(0)<=400)           //4秒後まで繰り返し
  {
    OnFwd(OUT_A+OUT_C);              //前進
    if(SENSOR_3<=THRESHOLD)
    {
      turn_r(10);                    //センサー3が反応したら0.1秒右旋回
    }
    if(SENSOR_1<=THRESHOLD)
    {
      go(25);
      OnFwd(OUT_A);
      Wait(20);
      Off(OUT_A);                    センサー1が反応したら0.25秒直進し、0.2秒左車輪のみ前進
    }
  }
                                     //ヘアピンカーブ
  ClearTimer(0);                     //タイマーをリセット
  while(FastTimer(0)<=600)           //6秒後まで繰り返し
  {
    OnFwd(OUT_A+OUT_C);              //前進
    if(SENSOR_3<=THRESHOLD)
    {
      OnRev(OUT_A+OUT_C);
      Wait(10);
      Off(OUT_A+OUT_C);
      turn_r(20);                    //センサー3が反応したら0.1秒後退し、0.2秒右旋回
    }
  }
  ClearTimer(0);                     //タイマーをリセット
  while(FastTimer(0)<=400)           //4秒後まで繰り返し
  {
    OnFwd(OUT_A+OUT_C);              //前進
    if(SENSOR_1<THRESHOLD)
    {
      turn_l(10);                    //センサー1が反応したら0.1秒左旋回
    }
    if(SENSOR_3<THRESHOLD)
    {
      go(25);                        //センサー3が反応したら0.25秒直進
    }
  }
  while(SENSOR_3<THRESHOLD)          //センサー3が反応するまで繰り返し
  {
    OnFwd(OUT_A+OUT_C);              //前進
    if(SENSOR_1<THRESHOLD)
    {
      turn_l(10);                    //センサー1が反応したら0.1秒左旋回
    }
  }
  Off(OUT_A+OUT_C);
} 

ゆきち

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);                        //ゴール
    }

反省・感想

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

コメントをお願いします



添付ファイル: filetrace_robot_side.JPG 226件 [詳細] filesensor.JPG 196件 [詳細] filetrace_robot.JPG 229件 [詳細] file02.JPG 102件 [詳細] file01.JPG 117件 [詳細] filecourse_yukichi.JPG 190件 [詳細] filecourse_ishii.jpg 183件 [詳細] filecourse.jpg 179件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2011-07-15 (金) 17:32:28 (2961d)