*目次 [#q0beaeb0]
#contents

*課題の説明 [#ib723224]
&ref(./img.jpeg,20%);
-画像のようなコースを作成し、与えられた条件を満たしてゴールせよ。
***条件 [#ndfbf27e]
+A,B,Cのいずれかから、それぞれ指定された場所までコースに沿って移動する。(AからB,BからA,CからA)
+交差点は曲がらずに通過する。
+途中に設置されたボールをゴールまで持っていく。(可能ならシュートする)

今回私が担当するのは、BからスタートしてAまで移動するものである。~
コースは下の画像のとおり。(S=スタート,G=ゴール)

&ref(./img2.jpeg,20%);

*ロボットの説明 [#bd77b578]
**本体 [#s425d79f]
&ref(./image[2].jpeg,20%);

これが今回私たちのチームが制作したロボットである。~
アームでボールを囲み、ゴールまで運ぶ。
**アーム [#ie485727]
***アーム1 [#wf712d8e]
&ref(./image.jpeg,13%);

本体の下部にあり、ボールをキャッチし外に出ないようにする役割をもつ。
***アーム2 [#peeefd4c]
&ref(./image[6].jpeg,15%);

本体の上部にあり、最初は開いている。~
ボールが射程範囲に入るころに閉じ、ゴールまで運べるようにプログラムしてある。~
シュートのときは再度開く。
*コンセプト [#a317f46d]
光センサの値が低い(黒〜灰色)ときは右に、高い(灰色〜白)ときは左に曲がる。~
そのためラインの左側に沿ってゴールまで移動していく。~
光センサの値が低い場合が続いたら交差点と判断し、突破用のプログラムが作動する。~
光センサの値が高い場合が続いたらゴール前だと判断し、シュートして動作を終了する。~
ただし最初のカーブで光センサの値が高い場合が続いてしまう箇所があるため、最初の10秒はシュートプログラムのないものでライントレースを行う。~
ボールは上で書いたように、2つのアームを使って運ぶ。~
ボールが射程範囲に入る時間をあらかじめ測っており、そのころにアーム2が閉じるようになっている。~
シュートはアーム2を開き、体当たりすることで行う。

*プログラム [#ye3fb51e]
**マクロ [#y9ccd10e]
 #define THRESHOLD 39           //光センサの基準値
 #define SPEED_H 30       //直線に進むときのスピード
 #define SPEED_L 20       //曲線に進むときのスピード
 #define downtime 10000         //ボールが射程範囲に入る時間で、この時間あたりでアーム2を下げる
 #define down OnFwd(OUT_A,40);Wait(500);Off(OUT_A);Wait(300);      //アーム2を下げる
 #define up OnRev(OUT_A,40);Wait(500);Off(OUT_A);Wait(300);        //アーム2を上げる
 #define OnRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL);    //引数に応じて運動する
 #define go_forward OnRL(SPEED_H, SPEED_H);    //まっすぐ進む
 #define turn_left1 OnRL(SPEED_L, -SPEED_L);   // 左旋回
 #define turn_left0 OnRL(SPEED_L, 0);          // 左折
 #define turn_right0 OnRL(0, SPEED_L);         // 右折
 #define turn_right1 OnRL(-SPEED_L, SPEED_L);  // 右旋回
 #define STEP 1
 #define nMAX 300    //光センサの値が低い状態がこの時間だけ続いたら、交差点突破プログラムを発動する 
 #define CROSS_TIME 200  //交差点突破に必要な時間
 #define goal OnRev(OUT_BC,50);Wait(500);Off(OUT_BC);Wait(500);\
 up;OnFwd(OUT_BC,100);Wait(300);Off(OUT_BC);        //シュートするプログラム
**サブルーチン [#mc07ce40]
***小休止 [#yd51f688]
 sub short_break(long s){
     int a=0;
     while(a<1000){
         Off(OUT_BC);
         Wait(STEP);
         if(CurrentTick()-s<=downtime+1.0 && downtime<=CurrentTick()-s){
             down;
         }
      a++;
     }
 } 
激しい動作を行った後の小休止用サブルーチン。~
メインプログラム上では発進時刻を引数にとる。~
休止中にアーム2を下げる時間がきてもいいように、0.001秒ごとに判定を行っている。~
判定は、開始時刻と現在の時刻の差がアーム2を下げる予定時間と誤差0.001秒以内で一致するかどうかを確かめるものである。~
判定をクリアしたら、アーム2が下がる。

***交差点突破 [#qa0ca622]
 sub cross_line(long t){
     int b=0;
     while(b<CROSS_TIME){
         OnRL(SPEED_L,SPEED_L);
         Wait(STEP);
         if(CurrentTick()-t<=downtime+1.0 && downtime<=CurrentTick()-t){
             down;
         } 
         b++;
     }
 } 
交差点突破用サブルーチン。~
定義したCROSS_TIMEの分だけ前進する。~
これも小休止用と同じく、0.001秒ごとに判定を行っている。

***進行方向修正 [#v9214ccc]
 sub c_direction(long u){
     int c=0;
     while(c<nMAX){
         turn_left1;
         Wait(STEP);
         if(CurrentTick()-u<=downtime+1.0 && downtime<=CurrentTick()-u){
             down;
         }
         c++;
     }
 }

進行方向を修正するサブルーチン。~
交差点判定後に進行方向を修正するためのものである。~
これも上記の2つと同様に判定を行っている。

**メイン [#a1376baa]
開始から10秒まで(前半)と、10秒以降(後半)とで違うプログラムを動かす。

***開始から10秒まで [#i2b8cf80]
 task main(){
     SetSensorLight(S3);      //光センサ
     int nOnline=0;           //黒線上にいる回数のカウンター(カウンター(黒))
     long t0=CurrentTick();   //開始時刻
     while (CurrentTick()-t0<10000) //開始から10秒までの間{
         while (nOnline < nMAX) //黒線上にいる時間が一定未満の間{
             if(CurrentTick()-t0<=downtime+1 && downtime<=CurrentTick()-t0){ //アーム2を下げる時間になったらアーム2を下げる
                 down;
             }
             if (SENSOR_3 < THRESHOLD-8){ //黒線上にいるとき
                 turn_right1; //右旋回
                 nOnline++;   //カウンター(黒)を増やす
             }
             else {
                 if (SENSOR_3 < THRESHOLD-5){ //黒線よりの境界にいるとき
                     turn_right0; //右折
                 }
             else if (SENSOR_3 < THRESHOLD+5){ //境界付近にいるとき
                 go_forward; //直進
             }
             else if (SENSOR_3 < THRESHOLD+8){ //白よりの境界にいるとき
                 turn_left0; //左折
             }
             else{                            //白紙上にいるとき
                 turn_left1;  //左旋回
             }
             nOnline=0;//カウンター(黒)をリセット
         }
         Wait(STEP);//0.001秒動作を継続
     }
    //カウンターが一定数に達したら
     short_break(t0); //小休止
     c_direction(t0); //軌道修正
     cross_line(t0);  //交差点突破
     nOnline=0;       //カウンター(黒)をリセット
 }
開始から10秒まではこのプログラムに従って動く。~
光センサの値に従って、右旋回・右折・直進・左折・左旋回をする。~
右旋回が一定時間続いた場合、交差点を突破する。


***開始から10秒以降 [#c297922f]
 int g=0;                 //白紙上にいる回数のカウンター(カウンター(白))
 while(CurrentTick()-t0>10000.0 && CurrentTick()-t0<10000000.0){ //開始から10秒以上10,000秒未満の間
     while (nOnline < nMAX){ //カウンター(黒)が一定数未満のとき
         if(CurrentTick()-t0<=downtime+1 && downtime<=CurrentTick()-t0){//アーム2を下げる時間になったらアーム2を下げる
             down;
         }
         if (SENSOR_3 < THRESHOLD-8){ //黒線上にあるとき  
             turn_right1; //右旋回
             nOnline++;   //カウンター(黒)を増やす
             g=0;         //カウンター(白)をリセット
         }
         else if (SENSOR_3 >= THRESHOLD+8){ //白紙上にいるとき
             turn_left1; //左旋回
             g++;        //カウンター(白)を増やす
             nOnline=0;  //カウンター(黒)をリセット
             if(g==nMAX){ //カウンター(白)が一定数に達したら
                 nOnline=nMAX;//カウンター(黒)を一定値する、これはwhile()から抜け出すため
             }
         }
         else{
             if (SENSOR_3 < THRESHOLD-5){ //黒線よりの境界にいるとき
                 turn_right0; //右折
             }
             else if (SENSOR_3 < THRESHOLD+5){ //境界付近にいるとき
                 go_forward; //直進
             }
             else if (SENSOR_3 < THRESHOLD+8){ //白よりの境界にいるとき
                 turn_left0; //左折              }
                 nOnline=0; //カウンター(黒)をリセット
                 g=0; //カウンター(白)をリセット
             }
             Wait(STEP);0.001秒動作を継続
         }
         if(g<nMAX){ //カウンター(黒)が一定数に達した場合、交差点突破
             short_break(t0);//小休止
             c_direction(t0);//軌道修正
             cross_line(t0); //交差点突破
             nOnline=0; //カウンター(黒)をリセット
         }
         else if(g==nMAX){カウンター(白)が一定数に達した場合、シュートして終了
             short_break(t0);//小休止
             turn_right1;Wait(nMAX*STEP);//軌道修正
             goal;//シュート
             t0-=10000000;//開始時刻の数値を減らすことで、開始から10000秒たったことにしてプログラムを終了させる
         }
     }
 }

開始から10秒以降はこのプログラムに従って動く。~
前半と同じく光センサの値に従って、右旋回・右折・直進・左折・左旋回し、右旋回が一定時間続いた場合、交差点を突破する。~
また左旋回が一定時間続いた場合、シュートして終了する。~
なお、条件に開始から10000秒で終了するとあるが、これはt0の値を操作してプログラムを終了できるようにするためのものである。

*結果 [#e41fff56]
スタートからライントレースを行い、交差点突破、ボールの確保、シュートまでクリアすることができた。

*苦労したところ・反省点 [#h7ce2d02]
**苦労したことと解決法 [#b65b839b]
**苦労したこと [#b65b839b]
-ロボット製作において、ボールをキャッチさせるためにタッチセンサを使おうと考えたが、ボールがタッチセンサを反応させないほど軽かったため、タイマー機能を使う方向でロボットを製作した。タイマーを使うとロボットの体調によってボールに到達するまでの時間がずれるため、ボール確保用のアームはゆったりしたものを用意した。

-プログラミングにおいては様々な苦労があった。前回につづき電池の影響で微調整が必要になったり、アームを下げる判定を行うために多くのサブルーチンを書いたり、プログラムを終了させるために少し強引なこと(t0を1000万マイナスすること)をしたりした。

**反省点 [#o868e8fc]
-ロボット制作においては、もっと時間を費やしたほうがよかったと感じた。今回のものは2時間くらいで制作したもので、発生した問題点はパーツの豊富さでゴリ押しした面があり、とてもゴツイ。そのうえで実現したのがボールを囲んで引きずっていき体当たりでシュートするという独創性のかけらもないものだった。次の課題ではギアなどをうまく使ったすばらしいものを作ってみたい。

-プログラミングにおいては、考えを整理して一から組むべきだったと感じた。今回のものは配布物にかいてあったものに肉付けをしていったもので、動きはするもののとてもごちゃごちゃしている。次の課題ではサブルーチンや関数をうまく使って、よりスマートに、よりフレクシブルなプログラムを組みたい。

*感想 [#f439ae4e]
反省点の項では今回のロボットやプログラムについてネガティブなことを書いたが、ロボットを班員と3人でいっしょに作っていく過程は、思いもよらない意見を聞けたりしてとても参考になった。そしてそれぞれが解決策を出し合って完成した今回のロボットはゴツイが安定感は抜群なので達成感もあった。
またプログラミングにおいても、新しく習ったタイマー機能やセンサー機能、サブルーチンなどを使いながらプログラムを組む過程は充実していたと感じている。


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