光を追いかけるロボット

マシンの正面に2個の光センサーが横に並んで付いています。

//    作成者:山崎 畠山
//    作成日:2005-12-9
//    変更日:2005-12-16
//    変更点:明るい方向を探す回転の速度を遅くし、変数の使い方を工夫(詳細はこのページ下の工夫した点の項をご覧ください。)
 
int L = 0; //明るさの最大値
int i;     //明るい方向を探すサブルーチンの終了フラグ用
int d;     //センサー間の値の誤差
int turn_time1;  //マシンの1回転する時間(Timer用。Wait用ではありません。)
int turn_time2;  //この時間はサブルーチンによって異なります。

//明るい方向を探すサブルーチン
sub light (){
              turn_time1 = 60; //このサブルーチン内専用変数(詳細はこのページ下の工夫した点の項をご覧ください。)

           ClearTimer(0);
           while(Timer(0) < turn_time1){
              OnFwd(OUT_A);  //マシン回転
              OnRev(OUT_C);
              Wait(10);
              Off(OUT_A+OUT_C); //少しずつ止まりながら
              Wait(1);
              PlayTone(SENSOR_1*10,1) ;
              if(SENSOR_1>L){L=SENSOR_1;} //Lに明るさの最大値を入れる。
                       }
         }

//明るい方向を向くサブルーチン
sub turn (){
             turn_time2 = 20;  //このサブルーチン内専用変数

           for (i=0; i==0; L--){
               OnFwd(OUT_A);  //マシン回転
               OnRev(OUT_C);
               ClearTimer(0);
               until(SENSOR_1>=L||Timer(0)>turn_time2); //最も明るい方向が見つかるか、一回転するまで
               if(SENSOR_1>=L){i=1;}  //見つかれば次の処理へ
               }  //見つからなければ明るさの最大値を1つ低くしてまた回転
            }

//光を追うサブルーチン
sub trace (){
              d=SENSOR_1-SENSOR_2;  //センサー間の値の誤差を測ります。以降、このサブルーチン内ではセンサー2には誤差を加えます。
 
            while(true){
               if (SENSOR_1==SENSOR_2+d) //センサーが二つとも同じ明るさなら前進
               { OnFwd(OUT_A+OUT_C);}
               else{if(SENSOR_1>SENSOR_2+d)   //左のセンサーが明るければ左折
               {OnFwd(OUT_C);Off(OUT_A);}
               else{OnFwd(OUT_A);Off(OUT_C);} //それ以外(右のセンサーが明るい)なら右折
                   }
               Wait(3);  //移動時間
               Off(OUT_A+OUT_C);
               Wait(20); //マシンが高速なため、少しずつ移動するよう一時停止する時間です。
                        }
            }
            
task main (){
SetSensor(SENSOR_1, SENSOR_LIGHT); //左の光センサー
SetSensor(SENSOR_2, SENSOR_LIGHT); //右の光センサー
light();  //明るい方向を探します。
turn ();  //明るい方向を向きます。
trace (); //光を追いかけます。
}

工夫した点

  • 明るい方向を向くサブルーチンで、最初に作ったのは
    OnFwd(OUT_A);OnRev(OUT_C);     //マシン回転
    until(SENSOR>=明るさの最大値) //計測した明るさの最大値(またはそれを超える)の場所を見つけるまで
    というプログラムでしたが、これでは計測したときの値から少しでも明るさが低くなるとその場所が見つからなくなり、回転し続けます。 そこで、forとL--を使い、見つからない場合は最大値を1ずつ減らして見つけるようにしました。これで回転し続けることは無くなります。
  • 同じ光センサーにも個体差があり、そのせいでどうも片側のセンサーだけが強く反応したりします。 そこで、明るい方向をマシンが向いたときに左右のセンサーがともに同じ明るさになったと仮定し、(実際はセンサー1の方がやや明るいが)そのときのセンサー間の誤差dを測り、以降は誤差を埋めてプログラムしました。(光を追うサブルーチンのところ)
  • turn_timeというのはマシンが1回転する時間を表しますが、サブルーチンによって1回転する時間は異なります。そこでサブルーチン毎にturn_timeを用意しました。(turn_time1、turn_time2)こういった流れから、どのサブルーチン用の変数なのかわかりやすいように、このプログラムではサブルーチンと変数をまとめて記述するようにしました。nqcの仕様や変数の名前の重複を防ぐ理由で宣言は最初にしています。Lは二つのサブルーチンで使うのでまとめていません。

難しかった点

  • 工夫した点を文章で説明するのが難しかった。
  • 明るい方向まで向く方法を考えるのが大変だった。
  • 右のセンサーが強く反応して、右折ばかりするのを修正するのに苦労した。

対処方法は工夫した点をご覧下さい。

反省点

  • マシンの回転が速すぎてPlay Toneを使っても聞いてる暇がない。(プログラムがどこまで実行されたかの目安にはなったが)(修正して回転を遅くしました。)

感想

  • 意外と早くできた。ロボットなんて簡単じゃん(爆)

コメントはこちらまで

  • センサを個体差をプログラムでうまくカバーするあたり素晴らしいです (こういう調整をキャリブレーションと言います)。 -- 松本(教員)? 2005-12-12 (月) 12:58:42
  • ロボを見せて下さいね。 -- かとりーぬ(TA)? 2006-01-06 (金) 18:47:22
  • プログラムや工夫した点など、とても詳しく書かれていますね。わかりやすくてよいページです。 -- かとりーぬ(TA)? 2006-02-07 (火) 12:53:38

C6のTOPへ

tya1 0 &counter([total|today|yesterday]);

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2006-02-07 (火) 12:53:38