目次
#contents
* 課題2 [#ca17a593]
下の図のようなコースを各チームで作成し、「ミッション」を遂行するためのロボットを作成せよ。

&ref(2017b/Member/riko/Mission2/コース.png,500x300,コース);
&ref(2017b/Member/riko/Mission2/第三コース.png,500x300,第三コース);

今回、私が走らせるコースは第三コースであり、詳しいコースの内容は以下の通りである。
赤い線はおおよその第三コースである。
 ��Aをスタート
 ��Bを直進
 ��Cを直進
 ��D地点の紙コップを取得して来たコース戻りCへ向かう
 ��Cを左折
 ��Fを直進
 ��Rを左折(一時停止)
 ��Pを直進
 ��X地点に紙コップを置いてコースに戻る
 ��Qを左折
 ��Sを右折(一時停止)
 ��Fを左折(一時停止)
 ��Cを右折(一時停止)
 ��D地点へ(ゴール)
 (一時停止の指定がある場所は、1秒間停止すること)

* 今回の機体について [#rd7db7ba]
** 全体 [#t27325fb]
&ref(2017b/Member/riko/Mission2/本体.png,400x300,本体);

今回の機体を制作するにあたって、できるだけ小回りがきくようなものにした。
理由としては機体が大きすぎると移動中に紙コップと接触してしまう可能性が挙げられる。

** 動力(タイヤ)部分 [#jf455781]

&ref(2017b/Member/riko/Mission2/タイヤ.png,400x300,タイヤ);

タイヤと光センサーの距離を近づけることにより急なカーブやUターンなどがしやすくなっている。

Aに出力を与えると右のタイヤが動き、Bに出力を与えると左のタイヤが動く。

** 光センサー部分 [#uc7ca4d4]
&ref(2017b/Member/riko/Mission2/光センサー.png,400x300,光センサー);

光センサーと紙の距離は近すぎても遠すぎても正確に測ることができない。そのため、正しく数値が取れる適切な位置に組み立てることは大変苦労した。

できる限り光センサーと紙を平行にすることも正しく数値を取ることに貢献していると考えられたため、今回の光センサーの位置となった。

** 紙コップ回収部分 [#o36c614c]

&ref(2017b/Member/riko/Mission2/紙コップ取る.PNG,600x300,紙コップ取る);

紙コップを取るにあたって上から紙コップよりも大きい輪をかぶせることで、紙コップを本体との動きに同期させる機構にした。

上の写真は紙コップを取る際の動きである。

Cに出力を与えると機構が動く。

* プログラム [#t3e7a27b]

** ライントレース [#w8e0718c]

今回の「黒の線を追従する」ためのライントレースというプログラムの制作が必要となる。
ライントレースのプログラムは、NXTの資料に記載されている練習問題49と同様の考え方で作成する。

「完全に白」「白と境界付近の間」「境界付近」「黒と境界付近の間」「完全 に黒」 の5段階で動きを作るにあたり、5段階の明るさを実際にコースの上で測定する。5つの測定できた値は以下のものとなった。

&ref(2017b/Member/riko/Mission2/明るさの数値.PNG,600x300,明るさの数値);

明るさの数値が五段階に分けられた時、それらに対応する五種類の動きが存在することになる。
下の図はその五種類の動く方向であり、それらのプログラムは以下の通りとする。
&ref(2017b/Member/riko/Mission2/動き方.PNG,600x300,動き方);

 #define move1 OnFwd(OUT_A,40);OnFwd(OUT_B,-35); //1の方向へ向かう為のプログラム
 #define move2 OnFwd(OUT_A,30);OnFwd(OUT_B,-20); //2の方向に向かう為のプログラム
 #define move3 OnFwd(OUT_A,54);OnFwd(OUT_B,54); //3の方向へ向かう為のプログラム
 #define move4 OnFwd(OUT_B,30);OnFwd(OUT_A,-20); //4の方向に向かう為のプログラム
 #define move5 OnFwd(OUT_B,40);OnFwd(OUT_A,-35); //5の方向に向かう為のプログラム

*** 左側のライントレース [#xeaa8f9c]
上の結果からプログラムを作っていく。その際、黒線の左端か右端をとるかでプログラミングが変わる為、分けて考える。

それにあたって白と黒の境界線の明るさの値45を
 #define average 45 //今回のラインと余白部分の境界線上の値
と定義しておく。
 sub L_Assist_line(int Assist_time) //Assist_timeにいれた時間分だけラインの左側をライントレースし続けるプログラム
 {
     long ta=CurrentTick();
     while (CurrentTick()-ta<=Assist_time){
         if (SENSOR_1<average-11) {
             move1;                      //明るさ34以下の時、move1の動きをする
         }else if (SENSOR_1<average-7){
             move2;                      //明るさ38以下の時、move2の動きをする
         } else if (SENSOR_1<average+7){  
             move3;                      //明るさ52以下の時、move3の動きをする
         } else if (SENSOR_1<average+11){
             move4;                      //明るさ56以下の時、move4の動きをする
         } else {
             move5;                      //それ以外の時、move5の動きをする
          }
      }
 }

&ref(2017b/Member/riko/Mission2/左側のライントレース.PNG,500x400,左側のライントレース);

灰色の円は光センサーの位置を表しており、その中の数字はその時の明るさの数値を表している。赤い矢印はプログラムによる移動を表している。
*** 右側のライントレース [#u9dc89ce]
左側のライントレースと同様の考え方でプログラムを書いていく。注意する点は左側のプログラムと右側のプログラムは逆転しているだけということである。

 sub R_Assist_line(int Assist_time) //Assist_timeにいれた時間分だけラインの右側をライントレースし続けるプログラム
 {
     long tb=CurrentTick();
      while (CurrentTick()-tb<=Assist_time){
         if (SENSOR_1<average-11) {
             move5;                      //明るさ34以下の時、move5の動きをする
         } else if (SENSOR_1<average-7){
             move4;                      //明るさ38以下の時、move4の動きをする
         } else if (SENSOR_1<average+7){  
             move3;                      //明るさ52以下の時、move3の動きをする
         } else if (SENSOR_1<average+11){
             move2;                      //明るさ56以下の時、move2の動きをする
         } else {
             move1;                      //それ以外の時、move1の動きをする
          }
      }
 }

&ref(2017b/Member/riko/Mission2/右側のライントレース.PNG,600x400,右側のライントレース);

灰色の円は光センサーの位置を表しており、その中の数字はその時の明るさの数値を表している。赤い矢印はプログラムによる移動を表している。

** 交差点認識 [#ld26a553]
ライントレースをしている際、交差点に差し掛かることがある。何も対策していない場合、そのまま角に沿ってライントレースすることとなってしまう。

その対策として、交差点認識するライントレースのプログラムを作成する。
交差点認識の仕組みは、ライントレースの最中にある動作を連続で何秒間か行った場合、ライントレースを終了させるというものである。
左側のライントレースの場合、move1が連続で動作したときに交差点があると考えられるのでmove1について考える。また、右側のライントレースの場合はmove5の動作と考えられる。

〇左側のライントレースの場合の交差点認識
 sub L_line(int Stop_time) //Stop_timeにいれた分の時間、move1をし続けるとこのプログラムは終了するようになっている
 {
     long t1=CurrentTick();
     while (CurrentTick()-t1<=Stop_time){
         if (SENSOR_1<average-11) {
             move1;
         } else if (SENSOR_1<average-7){
             move2;
             t1=CurrentTick();                      //この動作の最中はライントレースを続ける。
         } else if (SENSOR_1<average+7){  
             move3;
             t1=CurrentTick();                      //この動作の最中はライントレースを続ける。
         } else if (SENSOR_1<average+11){
             move4;
             t1=CurrentTick();                      //この動作の最中はライントレースを続ける。
         } else {
             move5;
             t1=CurrentTick();                      //この動作の最中はライントレースを続ける。
          }
      }
     Off(OUT_AB);                                   //ライントレースを終了させる。
 }

〇右側のライントレースの場合の交差点認識
 sub R_line(int Stop_time) //Stop_timeにいれた分の時間、move5をし続けると、このプログラムは終了するようになっている
 {
     long t2=CurrentTick();
     while (CurrentTick()-t2<=Stop_time){
         if (SENSOR_1<average-11) {
             move5;
         } else if (SENSOR_1<average-8){
             move4;
             t2=CurrentTick();                      //この動作の最中はライントレースを続ける。
         } else if (SENSOR_1<average+6){  
             move3;
             t2=CurrentTick();                      //この動作の最中はライントレースを続ける。
         } else if (SENSOR_1<average+11){
             move2;
             t2=CurrentTick();                      //この動作の最中はライントレースを続ける。
         } else {
             move1;
             t2=CurrentTick();                      //この動作の最中はライントレースを続ける。
          }
      }
     Off(OUT_AB);                                   //ライントレースを終了させる。
 }

** 交差点横断 [#a9201be2]
交差点認識した後、直進、左折、右折、Uターンなどの動作が要求される。そのためのプログラムとして「何秒間ある動作をすることによって交差点横断をする」というものが考えられた。
しかし、上記のやり方であると電池の減り具合によって、その度にプログラムを変えなければならない。
最終的な方法として、ある明るさの値に達するまで一定の動作をするプログラムを組み合わせることで、電池の減り具合と関係なく交差点横断できるプログラムを作るという方法に至った。

〇白い部分(明るい時の値)から黒い部分(暗い時の値)へいくプログラム
 sub White_to_Black(int blight,int A_speed,int B_speed) //白い部分から黒い部分に移行する(光センサーの値がblightに入れた数値以下になる)まで動作し続けるプログラム
 {
     while (SENSOR_1>blight){
         OnFwd(OUT_A,A_speed); //A_speedに入れた数値分、Aに接続されたモーターが回る
         OnFwd(OUT_B,B_speed); //B_speedに入れた数値分、Bに接続されたモーターが回る
      }
     Off(OUT_AB);
 }


〇黒い部分(暗い時の値)から白い部分(明るい時の値)へいくプログラム
 sub Black_to_White(int blight,int A_speed,int B_speed) //黒い部分から白い部分に移行する(光センサーの値がblightに入れた数値以上になる)まで動作し続けるプログラム
 {
     while (SENSOR_1<blight){
         OnFwd(OUT_A,A_speed); //A_speedに入れた数値分、Aに接続されたモーターが回る
         OnFwd(OUT_B,B_speed); //B_speedに入れた数値分、Bに接続されたモーターが回る
      }
     Off(OUT_AB);
 }

上の二つのプログラムの組み合わせによってできたプログラムは以下に表記する。

*** 直進のプログラム [#yac768d2]
交差点認識してから直進するプログラムである。交差点認識したあとから下のプログラムが始まることに注意する。つまり、交差点認識をした直後の明るさの数値は30位となっている。このことは以下すべてのプログラムにいえることである。

 sub Straight() //交差点認識をした後、交差点を直進するプログラム
 {
     Black_to_White(48,40,35);
 }

&ref(2017b/Member/riko/Mission2/直進.PNG,600x300,直進);

言葉だけでは分かりずらいの図で表す。上の図では右から左に黒線を直進する際の動きを表している。灰色の円は光センサーの位置を表しており、その中の数字はその時の明るさの数値を表している。赤い矢印はプログラムによる移動を表している。

*** 右折のプログラム [#m7984a97]
交差点認識してからの右折するプログラムである。

 sub Right() //交差点認識した後、交差点を右折する為のプログラム
 {
     Black_to_White(48,-10,30);
 }

&ref(2017b/Member/riko/Mission2/右折.PNG,600x300,右折);

上図では下から進んで交差点認識した後、黒線を横断しつつ右折している様子を表している。
*** 左折のプログラム [#d103e450]
交差点認識してからの左折するプログラムである。

 sub Leght() //交差点認識した後、交差点を左折する為のプログラム
 {
     Black_to_White(48,40,10);
 }

&ref(2017b/Member/riko/Mission2/左折.PNG,600x300,左折);

上図では下から進んで交差点認識した後、黒線を横断しつつ左折している様子を表している。
*** 紙コップを取る為のプログラム [#g655c2f1]
紙コップを取る際、できる限り同じ位置で紙コップを取る機構を動かした方がよいと考えられる。そこで紙コップを取る前に交差点認識する場所があるのでそれを利用する。
都合がいいため、ここで紙コップを取る機構を動かすプログラムも入れておく。

 sub Get_cup() //紙コップを取る為のプログラム
 {
     Black_to_White(53,0,30); //このプログラムを入れることでできるだけ、紙コップを取るときの機体の左右のブレを減らし、且つコースに復帰する為の光センサーの値を確定させる為にある
     OnFwd(OUT_C,30); //Cに接続されたモーター回す為のプログラム(紙コップを取る機構を動かす)
     Wait(800);
     Off(OUT_C);
 }

&ref(2017b/Member/riko/Mission2/紙コップを取る.PNG,600x300,紙コップを取る);

上の図では実際に紙コップを取る場所を再現している。動きとしては下から進んで交差点認識した後、紙コップ取るのに丁度良い場所にもっていく。そして紙コップ取る機構を動かしている。
*** 紙コップを取った後、コースに復帰する為(Uターン)のプログラム [#k1f1d895]
上のプログラムで紙コップを取った後、コースに復帰するためのプログラム。動きとしてはUターンと変わらない。明るさの値は紙コップを取った時から変わっていないと考えられることを考慮する。

 sub Return_cource_1() //紙コップを取った後、コースに復帰する為のプログラム
 {
     White_to_Black(33,-28,35);
     Black_to_White(48,-20,35);
 }

&ref(2017b/Member/riko/Mission2/Uターン.PNG,600x300,Uターン);

紙コップを取った後からの図である。動きとしては複雑であるが最終的にUターンをする動きとなる。

*** 紙コップを置く為にコースから外れる為のプログラム [#wf348a21]
円形のコースを走行中、紙コップを置くためにコースから外れる必要がある。その際、ただコースから外れるのではなく紙コップが適切な位置にもっていくように動かなければならない。

 sub Derailment_cource() //紙コップを置く為にコースから外れる為のプログラム
 {
     White_to_Black(30,-50,0);
     Black_to_White(53,-30,0); 
 }

&ref(2017b/Member/riko/Mission2/コースから外れる.PNG,600x300,コースから外れる);

上図の通り、円の内側を走行中にコースから外れるようにする。紙コップの位置に気を付けなければならないのでバックするように動くことになる。
*** 紙コップを置く為のプログラム [#c094d48c]
ただの紙コップを取る機構を逆に動かしたプログラムである。このときは交差点横断のプログラムは使われていない。

 sub Put_cup() //紙コップを置く為のプログラム
 {
     OnFwd(OUT_C,-30);
     Wait(900);
     Off(OUT_C);
 }

*** 紙コップを置いた後、コースに復帰する為のプログラム [#ae50d159]
紙コップを置いた後、コースに復帰する必要があるのでそのプログラム。

 sub Return_cource_2() //紙コップを置いた後、コースに復帰する為のプログラム
 {
     White_to_Black(35,30,-10);
 }

&ref(2017b/Member/riko/Mission2/コースに復帰.PNG,600x300,コースに復帰);

紙コップを置く動作からの続きであることに注意すれば、特に難しい動きはしていない。コースに復帰した後は円の外側(左側)を走る。
*** 最期の一時停止をした後からのプログラム [#h22ed960]
一番最後に一時停止した後、ゴールするまでのプログラムは少しだけ特殊な為、ここだけ特別にサブのプログラムを書いた。

 sub Go_goal() //最期の一時停止をした後からのプログラム
 {
     Black_to_White(48,10,40);
     L_line(200,100);
     Black_to_White(48,20,30); 
 
     OnFwd(OUT_A,20);
     OnFwd(OUT_B,40);
     Wait(500);
     Off(OUT_AB);
 }

&ref(2017b/Member/riko/Mission2/最後.PNG,600x300,最後);

上図は左の線から右側進んで来ており、交差点認識したところからはじまっていることを想定している。最初の線を横断した後の青矢印はライントレースを表している。また、最後の横断をした後の前進でゴールとなる。

*** ライントレースを始める(出発する)為のプログラム [#t09cd7d9]
このコースの出発時は黒線で囲まれているため、まずそこを抜け出さなければならない。その後、コースに復帰もしなくてはならないため少し特殊なサブのプログラムを書いた。

 sub Start_Set() //ライントレースを始める為のプログラム
 {
     move3; //初めのラインの囲いから出る為のプログラム
     Wait(100);
     White_to_Black(48,5,30); //このプログラムでラインの境界線を確実に探し当てることができる
 }

&ref(2017b/Member/riko/Mission2/初め.PNG,600x300,初め);

上図はスタート地点から始まっている。黄色の矢印はただの直進を表している。


** 安心安全なライントレースの為に [#zeadfdb1]
ライントレースをし、交差点認識し、交差点横断や特殊な動きをする。その後、またライントレースをする際、誤った箇所で交差点認識してしまうことが間々ある。そのため、交差点認識のライントレースの前に何秒間(Assist_time)か絶対にライントレースをするというプログラミングを入れておく。
そうすることによって誤った箇所での交差点認識がなくなった。

また、このプログラムを用いることによりヘアピンカーブのような急なカーブで認識してしまっても対処が可能となる。

〇左側のライントレースの二つのプログラムを組み合わせる
 sub L_Assist_line(int Assist_time) //Assist_timeにいれた時間分だけラインの左側をライントレースし続けるプログラム
 {
     long ta=CurrentTick();
     while (CurrentTick()-ta<=Assist_time){
         if (SENSOR_1<average-11) {
             move1
         }else if (SENSOR_1<average-7){
             move2;
         } else if (SENSOR_1<average+7){  
             move3;
         } else if (SENSOR_1<average+11){
             move4;
         } else {
             move5;
          }
      }
 }
 sub L_line(int Assist_time,int Stop_time) //Stop_timeにいれた分の時間、move1をし続けるとこのプログラムは終了するようになっている
 {
     L_Assist_line(Assist_time); //交差点認識をし、方向転換をしたその後の機体が角度によって誤って交差点認識してしまわないように交差点認識をしないアシストのプログラムを入れている
     long t1=CurrentTick();
     while (CurrentTick()-t1<=Stop_time){
         if (SENSOR_1<average-11) {
             move1;
         } else if (SENSOR_1<average-7){
             move2;
             t1=CurrentTick();
         } else if (SENSOR_1<average+7){  
             move3;
             t1=CurrentTick();
         } else if (SENSOR_1<average+11){
             move4;
             t1=CurrentTick();
         } else {
             move5;
             t1=CurrentTick();
          }
      }
     Off(OUT_AB);
 } 

〇右側のライントレースの二つのプログラムを組み合わせる
 sub R_Assist_line(int Assist_time) //Assist_timeにいれた時間分だけラインの右側をライントレースし続けるプログラム
 {
     long tb=CurrentTick();
     while (CurrentTick()-tb<=Assist_time){
         if (SENSOR_1<average-11) {
             move5;
         } else if (SENSOR_1<average-7){
             move4;
         } else if (SENSOR_1<average+7){  
             move3;
         } else if (SENSOR_1<average+11){
             move2;
         } else {
             move1;
          }
      }
 }
 sub R_line(int Assist_time,int Stop_time) //Stop_timeにいれた分の時間、move5をし続けると、このプログラムは終了するようになっている
 {
     R_Assist_line(Assist_time); //交差点認識をし、方向転換をしたその後の機体が角度によって誤って交差点認識してしまわないように交差点認識をしないアシストのプログラムを入れている
     long t2=CurrentTick();
     while (CurrentTick()-t2<=Stop_time){
         if (SENSOR_1<average-11) {
             move5;
         } else if (SENSOR_1<average-8){
             move4;
            t2=CurrentTick();
         } else if (SENSOR_1<average+6){  
             move3;
             t2=CurrentTick();
         } else if (SENSOR_1<average+11){
             move2;
             t2=CurrentTick();
         } else {
             move1;
             t2=CurrentTick();
          }
      }
     Off(OUT_AB);
 }



* SE(効果音) [#qd70a075]
今回の課題の中に何らかのアクションを起こしたとき、音を鳴らすということも含まれている。そのため「一時停止するとき」「紙コップに関する動作をするとき」「ゴールしたとき」「交差点認識をしたとき」「Assist_timeが終わったとき」「スタートするとき」の六つの場面で四つの音を鳴らす。

(「紙コップに関する動作をするとき」「ゴールしたとき」のSEを同じものにする。「交差点認識をしたとき」「Assist_timeが終わったとき」のSEを同じものとする)

以下の定義が音の数値とする

 #define SO 392 //ソの音
 #define DO 523 //ドの音
 #define MI 659 //ミの音
 #define SO_H 784 //高いソの音
 #define SI 988 //シの音
 #define DO_H 1047 //高いドの音
 #define MI_H 1318 //高いミの音
 #define RE 1175 //レの音
 #define SO_SH 1568 //一番高いソの音

** 一時停止の時になる音 [#lefd89a6]
マ〇オのポーズの音のプログラムである。
 sub pose_SE() //一時停止の時になる音(マ〇オのポーズの音)
 {
     PlayTone(MI_H,90);Wait(100);
     PlayTone(DO_H,90);Wait(100);
     PlayTone(MI_H,90);Wait(100);
     PlayTone(DO_H,90);Wait(100);
 }

** 紙コップに関する動作をする時の音、ゴールした時の音 [#r57c506d]
マ〇オの1UPの音のプログラムである。
 sub one_UP_SE() //紙コップに関する動作をする時の音、ゴールした時の音(マ〇オの1UPの音)
 {
     PlayTone(MI,110);Wait(120);
     PlayTone(SO_H,110);Wait(120);
     PlayTone(MI_H,110);Wait(120);
     PlayTone(DO_H,110);Wait(120);
     PlayTone(RE,110);Wait(120);
     PlayTone(SO_SH,110);Wait(120);
 }


** 交差点認識をした時の音、Assist_timeが終わった時の音 [#k6796e5a]
マ〇オのコインを獲得した時の音のプログラムである。
 sub coin_SE() //交差点認識をした時の音、Assist_timeが終わった時の音(マ〇オのコインを獲得した時の音)
 {
     PlayTone(SI,90);Wait(100);
     PlayTone(MI_H,140);Wait(150);
 }



** ライントレースを始める時の音 [#b83a62ec]
マ〇オのゲームで一番お馴染みのBGMのイントロ部分のプログラムである。
 sub Start_SE() //ライントレースを始める時の音(マ〇オのゲームで一番お馴染みのBGMのイントロ部分)
 {
     PlayTone(MI,100);Wait(110);
     PlayTone(MI,100);Wait(250);
     PlayTone(MI,100);Wait(160);
     PlayTone(DO,90);Wait(100);
     PlayTone(MI,90);Wait(230);
     PlayTone(SO_H,90);Wait(420);
     PlayTone(SO,170);Wait(180);
 }



* 全体のプログラム [#k59ec0d9]
以上のプログラム合わせ、適切な位置にSEのプログラムを入れる。

以下は完成した全体のプログラミングとなる。

 #define SO 392 //ソの音
 #define DO 523 //ドの音
 #define MI 659 //ミの音
 #define SO_H 784 //高いソの音
 #define SI 988 //シの音
 #define DO_H 1047 //高いドの音
 #define MI_H 1318 //高いミの音
 #define RE 1175 //レの音
 #define SO_SH 1568 //一番高いソの音
 
 
 sub pose_SE() //一時停止の時になる音(マリオのポーズの音)
 {
     PlayTone(MI_H,90);Wait(100);
     PlayTone(DO_H,90);Wait(100);
     PlayTone(MI_H,90);Wait(100);
     PlayTone(DO_H,90);Wait(100);
 }
 sub one_UP_SE() //紙コップに関する動作をする時の音、ゴールした時の音(マリオの1UPの音)
 {
     PlayTone(MI,110);Wait(120);
     PlayTone(SO_H,110);Wait(120);
     PlayTone(MI_H,110);Wait(120);
     PlayTone(DO_H,110);Wait(120);
     PlayTone(RE,110);Wait(120);
     PlayTone(SO_SH,110);Wait(120);
 
 }
 sub coin_SE() //交差点認識をした時の音、アシストタイムが終わった時の音(マリオのコインを獲得した時の音)
 {
     PlayTone(SI,90);Wait(100);
     PlayTone(MI_H,140);Wait(150);
 }
 
 sub Start_SE() //ライントレースを始める時の音(マリオのゲームで一番お馴染みのBGMのイントロ部分)
 {
     PlayTone(MI,100);Wait(110);
     PlayTone(MI,100);Wait(250);
     PlayTone(MI,100);Wait(160);
     PlayTone(DO,90);Wait(100);
     PlayTone(MI,90);Wait(230);
     PlayTone(SO_H,90);Wait(420);
     PlayTone(SO,170);Wait(180);
 }
 
 
 #define move1 OnFwd(OUT_A,40);OnFwd(OUT_B,-35); //1の方向へ向かう為のプログラム
 #define move2 OnFwd(OUT_A,30);OnFwd(OUT_B,-20); //2の方向に向かう為のプログラム
 #define move3 OnFwd(OUT_A,54);OnFwd(OUT_B,54); //3の方向へ向かう為のプログラム
 #define move4 OnFwd(OUT_B,30);OnFwd(OUT_A,-20); //4の方向に向かう為のプログラム
 #define move5 OnFwd(OUT_B,40);OnFwd(OUT_A,-35); //5の方向に向かう為のプログラム
 
 #define average 45 //今回のラインと余白部分の境界線上の値
 
 
 sub Stop_Motion() //一時停止をする時のプログラム
 {
     Wait(300); //交差点認識をした時の音と下の音を混同させない為の待ち時間
     pose_SE(); //ポーズ音
     Wait(1000); //一時停止の時間
 }
 
 sub L_Assist_line(int Assist_time) //Assist_timeにいれた時間分だけラインの左側をライントレースし続けるプログラム
 {
     long ta=CurrentTick();
     while (CurrentTick()-ta<=Assist_time){
         if (SENSOR_1<average-11) {
             move1
         }else if (SENSOR_1<average-7){
             move2;
         } else if (SENSOR_1<average+7){  
             move3;
         } else if (SENSOR_1<average+11){
             move4;
         } else {
             move5;
          }
      }
     coin_SE(); //コインの音
 }
 
 sub R_Assist_line(int Assist_time) //Assist_timeにいれた時間分だけラインの右側をライントレースし続けるプログラム
 {
     long tb=CurrentTick();
     while (CurrentTick()-tb<=Assist_time){
         if (SENSOR_1<average-11) {
             move5;
         } else if (SENSOR_1<average-7){
             move4;
         } else if (SENSOR_1<average+7){  
             move3;
         } else if (SENSOR_1<average+11){
             move2;
         } else {
             move1;
          }
      }
     coin_SE(); //コインの音
 }
 
 sub L_line(int Assist_time,int Stop_time) //Stop_timeにいれた分の時間、move1をし続けるとこのプログラムは終了するようになっている
 {
     L_Assist_line(Assist_time); //交差点認識をし、方向転換をしたその後の機体が角度によって誤って交差点認識してしまわないように交差点認識をしないアシストのプログラムを入れている 
     long t1=CurrentTick();
     while (CurrentTick()-t1<=Stop_time){
         if (SENSOR_1<average-11) {
             move1;
         } else if (SENSOR_1<average-7){
             move2;
             t1=CurrentTick();
         } else if (SENSOR_1<average+7){  
             move3;
             t1=CurrentTick();
         } else if (SENSOR_1<average+11){
             move4;
             t1=CurrentTick();
         } else {
             move5;
             t1=CurrentTick();
          }
      }
     Off(OUT_AB);
     coin_SE(); //コインの音
 }
 
 sub R_line(int Assist_time,int Stop_time) //Stop_timeにいれた分の時間、move5をし続けると、このプログラムは終了するようになっている
 {
     R_Assist_line(Assist_time); //交差点認識をし、方向転換をしたその後の機体が角度によって誤って交差点認識してしまわないように交差点認識をしないアシストのプログラムを入れている
  
     long t2=CurrentTick();
     while (CurrentTick()-t2<=Stop_time){
         if (SENSOR_1<average-11) {
             move5;
         } else if (SENSOR_1<average-8){
             move4;
             t2=CurrentTick();
         } else if (SENSOR_1<average+6){  
             move3;
             t2=CurrentTick();
         } else if (SENSOR_1<average+11){
             move2;
             t2=CurrentTick();
         } else {
             move1;
             t2=CurrentTick();
          }
      }
     Off(OUT_AB);
     coin_SE(); //コインの音
 }
 
 sub White_to_Black(int blight,int A_speed,int B_speed) //白い部分から黒い部分に移行する(光センサーの値がblightに入れた数値以下になる)まで動作し続けるプログラム
 {
     while (SENSOR_1>blight){
         OnFwd(OUT_A,A_speed); //A_speedに入れた数値分、Aに接続されたモーターが回る
         OnFwd(OUT_B,B_speed); //B_speedに入れた数値分、Bに接続されたモーターが回る
      }
     Off(OUT_AB);
 }
 
 sub Black_to_White(int blight,int A_speed,int B_speed) //黒い部分から白い部分に移行する(光センサーの値がblightに入れた数値以上になる)まで動作し続けるプログラム
 {
     while (SENSOR_1<blight){
         OnFwd(OUT_A,A_speed); //A_speedに入れた数値分、Aに接続されたモーターが回る
         OnFwd(OUT_B,B_speed); //B_speedに入れた数値分、Bに接続されたモーターが回る
      }
     Off(OUT_AB);
 }
 
 sub Get_cup() //紙コップを取る為のプログラム
 {
     Black_to_White(53,0,30); //このプログラムを入れることでできるだけ、紙コップを取るときの機体の左右のブレを減らし、且つコースに復帰する為の光センサーの値を確定させる為にある
     OnFwd(OUT_C,30); //Cに接続されたモーター回す為のプログラム
     Wait(800);
     Off(OUT_C);
     one_UP_SE(); //1UPの音
 }
 
 sub Put_cup() //紙コップを置く為のプログラム
 {
     OnFwd(OUT_C,-30);
     Wait(900);
     Off(OUT_C);
     one_UP_SE(); //1UPの音
 }
 
 sub Straight() //交差点認識をした後、交差点を直進するプログラム
 {
     Black_to_White(48,40,35);
 }
 
 sub Right() //交差点認識した後、交差点を右折する為のプログラム
 {
     Black_to_White(48,-10,30);
 }
 
 sub Leght() //交差点認識した後、交差点を左折する為のプログラム
 {
     Black_to_White(48,40,10);
 } 
 
 sub Return_cource_1() //紙コップを取った後、コースに復帰する為のプログラム
 {
     White_to_Black(33,-28,35);
     Black_to_White(48,-20,35);
 } 
 
 sub Derailment_cource() //紙コップを置く為にコースから外れる為のプログラム
 {
     White_to_Black(30,-50,0);
     Black_to_White(53,-30,0); 
 }
 
 sub Return_cource_2() //紙コップを置いた後、コースに復帰する為のプログラム
 {
     White_to_Black(35,30,-10);
 }
 
 sub Go_goal() //最期の一時停止をした後からのプログラム。少しだけ特殊なプログラムな為、ここだけ特別にサブのプログラムを書いた
 {
     Black_to_White(48,10,40);
     L_line(200,100);
     Black_to_White(48,20,30);
     OnFwd(OUT_A,20);
     OnFwd(OUT_B,40);
     Wait(500);
     Off(OUT_AB);
     one_UP_SE(); //1UPの音
 }
 
 sub Start_Set() //ライントレースを始める為のプログラム
 {
     move3; //初めのラインの囲いから出る為のプログラム
     Start_SE(); //スタートの音
     Wait(100);
     White_to_Black(48,5,30); //このプログラムでラインの境界線を確実に探し当てることができる
 }
 
 task main()
 {
     SetSensorLight(S1); //光センサーの起動
     Start_Set(); //スタート
     L_line(6000,150); //左側のライントレース、6秒のアシストトレース、0.15秒で交差点認識
     Get_cup(); //紙コップを取る
     Return_cource_1(); //コースに戻る
     L_line(200,200); //左側のライントレース、0.2秒のアシストトレース、0.2秒で交差点認識
     Leght(); //交差点を左折
     R_line(700,110); //右側のライントレース、0.7秒のアシストトレース、0.11秒で交差点認識
     Straight(); //交差点認識を直進
     R_line(3000,120); //右側のライントレース、3秒のアシストトレース、0.12秒で交差点認識
     R_line(3500,120); //右側のライントレース、3.5秒のアシストトレース、0.12秒で交差点認識
     R_line(1000,100); //右側のライントレース、1秒のアシストトレース、0.1秒で交差点認識
     Stop_Motion(); //一時停止
     Leght(); //交差点を左折
     R_Assist_line(5000); //5秒のアシストトレース(紙コップの置くところまでの移動)
     Derailment_cource(); //コースを脱線(紙コップを置く場所を調整)
     Put_cup(); //紙コップを置く
     Return_cource_2(); //コースに戻る
     L_line(2000,150); //左側のライントレース、2秒のアシストトレース、0.15秒で交差点認識
     Leght(); //交差点を左折
     R_line(1000,180); //右側のライントレース、1秒のアシストトレース、0.18秒で交差点認識
     Stop_Motion(); //一時停止
     Right(); //交差点を右折
     L_line(1000,250); //右側のライントレース、1秒のアシストトレース、0.25秒で交差点認識
     Stop_Motion(); //一時停止
     Leght(); //交差点を左折
     R_line(1000,130); //右側のライントレース、1秒のアシストトレース、0.13秒で交差点認識
     Stop_Motion(); //一時停止
     Go_goal(); //ゴールへ向かう
 }


* まとめ [#w1fa85b1]
今回の課題の結果としてはミスなくコースを完走することができ、タイムは一分と少しぐらいであった。
結果としては良かったが、プログラム制作に時間がかかってしまった。理由としては、ライントレースの制御を五段階制御ではなく比例制御でしようとしたりと色々としなくてよいことをしていたことだと考える。

今回の機体の出来としては結構よくできた方だと思っている。しかし、パーツを少なく、かつ頑丈に、一体感のあるものを目標に制作したが、センサーの位置などまだまだ考慮すべき点はまだまだ大量にあると分かったので課題3ではよりよい機体を作りたいと思う。

* 参考文献 [#o8b09dc4]
松本成司(2013)「自律型ロボットを作ろう!(2013年度版)」(マインドストームを使ったロボット製作の体験教室資料), [online] http://yakushi.shinshu-u.ac.jp/robotics-jr/robotics-jr-2013.pdf(参照2017-1-7).

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS