2019a/Member

目次

課題2

下の図のようなコースを各チームで作成し、「ミッション」を遂行するためのロボットを作成せよ。

画像1

ミッション

A地点を出発し、次の経路を黒い線にそって動くロボットを作成する。

A地点から出発 → B → C(直進) → D(一時停止の後、直進) → E → F → G(一時停止の後、右折) → H → I → J(右折) → K(左折) → L(ピンポン玉をつかむ) → K(直進) → M(一時停止) → シュート→ A地点に入る(ゴール)

交差点では1秒間停止し、丁字路では直角方向に進入する時のみ一時停止すること。

ロボット

組み立て説明書にある基本のロボットをベースに、光センサーと玉を扱う部品を組み込んだ。

画像1

光センサーとタイヤの回転軸の距離が遠すぎるとカーブを曲がれないので、注意した。 玉を扱う部品は、アームが一回転するようになっており、玉をつかんだりシュートしたりできる。

画像1

実際に走らせたところ、パワーがなくカーブで止まってしまったので、左右のモーターにギアを組み込みトルクを上げた。

画像1

プログラム

まず、線の左側の、白と黒の境界線をたどるプログラムを作った。 黒、黒寄りのグレー、白寄りのグレー、白の閾値を定義し、黒なら左、グレーなら直進、白寄りのグレーなら少しだけ右、といったように進むようにした。 また、D地点のような交差点やK地点のような丁字路では、黒の値をとる時間が一定値以上になったときに交差点と判断し、直進や左折等をするようにした。

しかし、このシステムでは G→H→I→J 間で円の内側をたどるため交差点の判断をすることができず、また K→M 間の R=4 のカーブを曲がりきることができなかった。 そこで、G地点を超えたところから線の右側の境界線をたどるようにすることでどちらもクリアすることができた。

これで一通りミッションを遂行できるが、問題は左右の境界線それぞれのプログラムが必要になり、サブルーチンの量が倍になってしまうことだ。 試行錯誤の結果、左を1、右を-1とする方法を見つけた。

  • follow_line(left);
  • turn_right(right);

のように使い、マクロ内の変数に1または-1が代入される。こうすることで、左右で反対の命令を出すことができる。

定数、マクロ

  • left、rightを定数として扱い、サブルーチンの変数に代入して使う。
    #define left 1
    #define right -1
  • 左(右)に回転する(xに1または-1が代入される)
    #define go(x)         OnRev(OUT_B,30*x); OnRev(OUT_C,-30*x);
  • 左前(右前)に進む(xに1または-1が代入される)
    #define go_little(x)  OnRev(OUT_B,35*(x+1)/2); OnRev(OUT_C,35*(-1*x+1)/2);
  • まっすぐ進む
    #define go_straight   OnRev(OUT_BC,35);
  • その他の定義
    #define BLACK      40
    #define GRAY_BLACK 45
    #define GRAY_WHITE 52
    #define WHITE      60
    #define short_brake Wait(1000);

サブルーチン

  • 線の左側(右側)境界線に沿って進み、交差点で止まる(aに1または-1が代入される)
    sub follow_line(int a)
    {
      SetSensorLight(S3);
      long t0=CurrentTick();
      while(CurrentTick()-t0<150) {
        if (SENSOR_3 < BLACK) {
          go(a);
        } else if (SENSOR_3 < GRAY_BLACK) {
          go_little(a);    t0=CurrentTick();
        } else if (SENSOR_3 < GRAY_WHITE) {
          go_straight;     t0=CurrentTick();
        } else if (SENSOR_3 < WHITE) {
          go_little(-1*a); t0=CurrentTick();
        } else {
          go(-1*a);        t0=CurrentTick();
        }
      }
      Off(OUT_BC);
    }
  • 交差点を直進(bに1または-1が代入される)
    sub cross_line(int b)
    {
      go_little(-1*b);
      Wait(300);
      go_straight;
      Wait(300);
      Off(OUT_BC);
    }
  • 交差点を左折(cに1または-1が代入される)
    sub turn_left(int c)
    {
      go_little(left);
      Wait(800-100*c);
      go(left);
      Wait(800-100*c);
      Off(OUT_BC);
    }
  • 交差点を右折(dに1または-1が代入される)
    sub turn_right(int d)
    {
      go_little(right);
      Wait(800+100*d);
      go(right);
      Wait(800+100*d);
      Off(OUT_BC);
    }
  • 線の左側から右側(右側から左側)に切り替える(eに1または-1が代入される)
    sub change_line(int e)
    {
      go(-1*e);
      Wait(750);
      Off(OUT_BC);
    }
  • K地点からL地点まで移動、玉をつかむ
    sub ball_catch()
    {
      go(left);
      Wait(1000);
      go_little(left);
      Wait(1200);
      go_straight;
      Wait(800);
      Off(OUT_BC);
      OnFwd(OUT_A,30);
      Wait(600);
      Off(OUT_A);
      go(left);
      Wait(1000);
    }
  • 玉をシュートする
    sub shoot()
    {
      go(left);
      Wait(200);
      Off(OUT_BC);
      Wait(1000);
      OnRev(OUT_A,70);
      Wait(900);
      Off(OUT_A);
    }

task main

あとはサブルーチン等を並べるだけ。同じものが連続する箇所はrepeatでまとめている。

task main()
{
 go_straight; Wait(500);   // A→B
 follow_line(left); short_brake; cross_line(left);   // B→C→D
 follow_line(left); short_brake; turn_right(left);   // D→E→F→G
 change_line(left);   // 左側境界線→右側境界線
 repeat(2){follow_line(right); cross_line(right);};   // G→H→I
 follow_line(right); turn_right(right);   // I→J
 follow_line(right);   // J→K
 ball_catch();   // K→L→ボールをつかむ
 follow_line(right); cross_line(right);   // L→K
 follow_line(right);   // K→M
 shoot();   // シュート
 go_straight; Wait(1500);   // M→A
}

まとめ

今回は早く完成させることができた。サブルーチンや定数を使いこなせるようになった。プログラムを短くするのに苦労したが、結果的にうまくいってよかった。


添付ファイル: filelinetrace_1.jpg [詳細] filelinetrace_4.jpg [詳細] filelinetrace_3.jpg 2件 [詳細] filelinetrace_2.jpg [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-07-19 (金) 08:46:51 (3d)