2019a/Member

目次

課題について

課題の内容

下の図のようなコースを各チームで作成し、「ミッション」を遂行するためのロボットを作成せよ
ミッションの内容等は 2019a/Mission2を参照。

課題コース

選んだコース

私たちのグループは以下のようなコースを選択した。

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

コースに関する戦略

私たちの班は以下のようにこのコースを進む作戦を立てた。

コース

スタート地点からまっすぐ進んだ後、右側の直線をライントレースしていく。
交差点(図では交)では交差点で一時停止後、直進する。
それまでの過程を緑→で表している。
その後、K地点からボールをキャッチするまでは手動で設定していく。
その過程を青→で表している。
最後は左側の直線をライントレースしていき、ゴール直前で球をシュートして自身がゴールする。
それまでの過程をオレンジ→で表している。

ライントレースや交差点での動作(プログラミング)の仕組みについては #adc6e636 を参照。

ロボットについて

全体のパーツ

主なパーツは車体、本体、アーム、光センサーである。
詳しくは以下の写真を参照。

パーツ

ロボット全体像

全体像

上の写真が今回作成したロボットの全体である。
写真左向きが前方向である。

光センサー

前方には光センサーがついており、これが色の明度を測りプログラミングした通りの指示を行う。
後方にはアームがついており、これがピンポン玉をキャッチする仕組みになっている。
今回は前回の課題で失敗した点、車体の重さで後輪がスムーズに回らない点を考慮して、
重心を前方に持ってくることで克服している。

ケーブルの収納

コード

今回工夫した点の一つが、このケーブル収納である。
この課題では、モータ3つ分+センサー1つ分の4つのケーブルを使用する。
そのため必然的にケーブルがごちゃごちゃしてしまい、時としてロボットの動作を
邪魔してしまう可能性がある。それを解決するのがこの収納であり、余分な長さ分を
この囲い部分にくるくる巻き付けることでコンパクトに装着できる。
収納時の写真は #d3cbddf7 を参照。

アームの構造

これが作成したアームである。
一方の指は固定されており、もう片方の指が歯車でモータと連携されて動かすことができる。

アーム
  • 球のキャッチ
    可動する指が閉まることで球を挟みキャッチする単純な構造である。
    アーム1
    アーム2
  • 球のシュート
    挟んでいる状態から可動指が開く。そしてアームの空いた方向へ車体が傾く。
    それにより、固定指が球を押し出す。このようにしてゴールに球をシュートする仕組みになる。
    アーム3
    アーム4
    アーム5

プログラミングについいて

使用した定義


  • 以下の定義は後述するプログラミングに使う値を定義したものだ。
    この部分を変更するだけでいちいち関数に組み込んだの値を変えずに簡略化できる。~
    #define MOVE_TIME 250   //ライントレースの条件用の時間(詳細は後述)
    #define SPEED_H 35   //スピードの値(統一することで簡易化)
    #define SPEED_L 20
    #define B1 43   //明度の値(詳細は後述)
    #define G 53
    #define W1 59
    #define W2 61
  • OnRL
    この定義はOnRL(x,y)とした時、x=(モーターBの速さ)y=(モーターCの速さ)を表す。
    モーターBが右の車輪、モーターCが左の車輪に連携していて、任意の値をx,yに入れる
    ことで車体が前後運動、方向転換を行うことができる。
    この定義により後述する定義等の簡略化に貢献している。
    #define OnRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL);
  • 前後運動、方向転換
    • 前進
      #define go_straight OnRL(SPEED_H,SPEED_H);
    • 旋回(急激な方向転換)
      #define rot_r OnRL(-SPEED_L,SPEED_L);   //右旋回
      #define rot_l OnRL(SPEED_L,-SPEED_L);   //左旋回
    • 回転(緩やかな方向転換)
      #define turn_r OnRL(0,SPEED_L);   //右回転
      #define turn_l OnRL(SPEED_L,0);   //左回転
    • アームの開閉
      #define arm_open OnRev(OUT_A,20);Wait(1000);Off(OUT_A);   //アームを開く
      #define arm_close OnFwd(OUT_A,30);Wait(600);Off(OUT_A);   //アームを閉じる

subルーチンについて

今回作ったサブルーチン関数は以下の通りである。

  • ライントレース[follow_line]
    この関数は光センサーでコースの線の明度を計測し、
    条件に沿って指定した動作をしながら線上を動ていくものだ。
    以下がその関数である。
    • 左側の直線トレース
      sub follow_line_l()
      {
          SetSensorLight(S1);
          long t0=CurrentTick();
          while(CurrentTick()-t0<MOVE_TIME){
              if(SENSOR_1>W1){
                  rot_r;t0=CurrentTick();
              }
              else if(SENSOR_1>W2){
                  turn_r;t0=CurrentTick();
              }
              else if(SENSOR_1>G){
                  go_straight;t0=CurrentTick();
              }
              else if(SENSOR_1>B1){
                  turn_l;t0=CurrentTick();
              }
              else{
                  rot_l;
              }
          }
      } 
    • 右側の直線トレース
      sub follow_line_r()
      {
          SetSensorLight(S1);
          long t0=CurrentTick();
          while(CurrentTick()-t0<MOVE_TIME){
              if(SENSOR_1>W1){
                  rot_l;t0=CurrentTick();
              }
              else if(SENSOR_1>W2){
                  turn_l;t0=CurrentTick();
              }
              else if(SENSOR_1>G){
                  go_straight;t0=CurrentTick();
              }
              else if(SENSOR_1>B1){
                  turn_r;t0=CurrentTick();
              }
              else{
                  rot_r;
              }
          } 
      }

詳細について述べていく。今回は左側直線トレースを取り上げる。
光センサーがコースの線路の明度を計測。明度ごとに設定された命令をこなす。
明度と命令の設定は以下。

ライン

この表を図化したものが以下である。
緑→が前進、オレンジ→が回転、青→が旋回を示している。
(*見やすくするため、〇の中の数字は定義した値にしている。)

ライン

「follow_line_l」をフローチャート化すると次のようになる。

チャート

  始めにCurrentTickをt0に(リセット)する。
  次に「CurrentTick()-t0<MOVE_TIME」によってCurrentTickの計測時間が
  MOVE_TIME(250)を超えるまでwhileの中をループし続ける。
  while文の中にはif文、else文で構成されていて、光センサーの値によって処理が
  異なるようになっている。光センサーの値が43より大きい値の時(黒以外の時)
  CurrentTickの値は命令遂行後、常にリセットされ、ループは継続される。
  しかし光センサーの値が45以下の時(黒の時)、CurrentTickはリセットされない。
  この状態が一定の時間(MOVE_TIME)続くことで、交差点であると判断し、
  このループから抜け、止まる構造となっている。

  • 交差点での動作

ライントレース中、交差点と判断して止まった後の動作は3つに分類される

  • 交差点を緩やかに直進[cross_line_1]
    sub cross_line_1()
    {
        while(SENSOR_1<W1){
            go_straight;
        }
        while(SENSOR_1>G){
            turn_l;
        }
        Off(OUT_BC);
    }  
  • 交差点を急激に直進[cross_line_2]
    sub cross_line_2()
    {
        while(SENSOR_1<W1){
            go_straight;
        }
        while(SENSOR_1>G){
            rot_l;
        }
        Off(OUT_BC);
    }
    今回は右側直線トレース後の交差点なので右側での交差点直進を説明する。
    この2つの関数の仕組みは同じである。
    まず交差点で停止後、設定明度〈白〉を見つけるまで直進する。
    車体は右側に傾いているので直進すれば白色(線路以外の場所)を見つけられる。
    白を見つけたら、設定明度〈灰〉をみつけるまで
    緩い直進であれば左回転、急激な直進であれば左旋回をする。
    灰を見つけたら停止する。
    交差点
  • 交差点を直角に曲がる[follow_line_r]

交差点で停止後、直角に曲がる場合は再度「follow_line」を命令することで
そのままライントレースをし続け直角に曲がることができる。
今回のコースでは右に曲がるのみなので「follow_line_r」のみの使用になる。

  • 交差点での停止[short_break]

このミッションでは「交差点では1秒間停止し、丁字路では直角方向に進入する時のみ一時停止」
を義務づけている。そのためこの関数を挟むことでその条件をクリアしている。

sub short_break()
{
    Off(OUT_BC);
    Wait(1000);
}
  • 球をキャッチする[ball_catch]

コースのK地点から球をキャッチするまでは手動のプログラミングを採用している。
それが以下の関数である。キャッチの仕組みに関しては #o909993d を参照。

sub ball_catch()
{
    rot_l;                   //左旋回
    Wait(350);               
    Off(OUT_BC); 
    go_straight;             //前進
    Wait(2000);
    Off(OUT_BC);
    OnRL(-SPEED_L,0);        //右車輪を後転させ右回転
    Wait(1000);
    Off(OUT_B);
    OnRL(-SPEED_L,-SPEED_L); //後退
    Wait(1500);
    Off(OUT_BC);
    arm_close;               //アームを閉じる
    rot_r;
    Wait(1300);
    go_straight;             //前進
    Wait(800);
    Off(OUT_BC);
}
  • 球をシュート、車体もゴール[shoot_goal]

左側の直線をトレースしてM地点に到達した後の関数である。
この関数は球をシュートして車体本体がゴールするまでの関数である。
シュートの仕方については #o909993d を参照。

sub shoot_goal()
{
    rot_l;      //左旋回
    Wait(300);
    Off(OUT_BC);
    go_straight;//前進(ゴールに対して横向きになる)
    Wait(1300);
    arm_open;   //アームを開く
    rot_l;      //左旋回(動作に合わせて球をシュート)
    Wait(500);
    Off(OUT_BC);
    go_straight;//前進(車体がゴール)
    Wait(500);
    Off(OUT_BC);
}

メインプログラム

以上のサブルーチン関数を使用してロボットがスタートしボールキャッチ後
シュートをしてゴールするまでの動作のプログラミングをしていく。
以下がメインのプログラミングだ。
*コース地点の名前は #q0bf97ed を参照。

task main()
{
    go_straight;     //スタート(A)〜B
    Wait(1000); 
    Off(OUT_BC);
    follow_line_r(); //B〜C(T字路)
    cross_line_1();  //T字路直進
    follow_line_r(); //C〜D(交差点)
    short_break();   //交差点のため一時停止
    cross_line_1();  //交差点直進
    follow_line_r(); //D〜E
    follow_line_r();
    follow_line_r(); //E〜F
    follow_line_r();
    follow_line_r(); //F〜H
    cross_line_2();  //H(T字路直進)
    follow_line_r(); //H〜I
    cross_line_2();  //I(T字路直進)
    follow_line_r(); //I〜J
    follow_line_r(); //J〜K
    ball_catch();  //K〜球キャッチ
    follow_line_l(); //L〜M
    shoot_goal();    //M〜球シュート〜ゴール
}

感想

ロボットに関して

今回はペアの人がロボット作りが上手で前回のような課題点も克服してスムーズに
動くロボットを作れた。またアーム部分ではシュート動作が工夫されていると思う。

プログラミングに関して

サブルーチン関数を使うことにより、メインプログラムを簡略化することに成功した。
またNXTの取説を参考にしたOnRLの定義はサブルーチン関数も含め全体を通して
簡略化することに貢献してくれたのでこれからも使用していきたい。

全体を通して

この課題はミッションをうまくこなすことができた。ペアとの意見交流も盛んに行われ
ロボットが得意なペアの人はロボット作りを、プログラミングがある程度できる私は
プログラミングを主に分担することで作業の効率化ができた。
次の課題でもこの成功点を生かして取り組んでいきたい。


添付ファイル: file交差点改.png 5件 [詳細] file交差点.png 3件 [詳細] file表.png 7件 [詳細] fileチャート改.png 12件 [詳細] fileチャートフロート.png 1件 [詳細] fileチャート.emf 3件 [詳細] file全体図.jpg 4件 [詳細] fileケーブル.jpg 6件 [詳細] fileロボット_190718_0008.jpg 5件 [詳細] file課題コース.png 2件 [詳細] fileロボット_190718_0013 (2).jpg 2件 [詳細] fileロボット_190718_0015 (2).jpg 2件 [詳細] fileロボット_190718_0011.jpg 3件 [詳細] fileロボット_190718_0025.jpg 6件 [詳細] fileロボット_190718_0026.jpg 4件 [詳細] fileロボット_190718_0027.jpg 8件 [詳細] fileロボット_190718_0010.jpg 7件 [詳細] fileロボット_190718_0009.jpg 7件 [詳細] fileロボット_190718_0007.jpg 9件 [詳細] fileロボット_190718_0003.jpg 7件 [詳細] fileロボット_190718_0001.jpg 4件 [詳細] fileライン制御.png 5件 [詳細] fileコース.png 3件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-08-01 (木) 13:10:17 (22d)