[[2015a/Member]]
*ライントレースロボットR7班目次 [#rc800bb8]
#contents

*課題内容 [#m12bd1e5]
今回の内容は、「ライントレースロボット」。 Mindstorms Robotics Invention System(以下RIS)を用いて下図のコースを走り、道中のボールを捕球、そのボールを指定されたゴールへシュートしろという内容であった。

なお、ボールは点Pから点Q間の線上であればどこにおいてもよいものとする。
#ref(./ライントレースマップ.png,50%)

**難点 [#e10c84a5]
+直角の曲がり角、交差点の認識
+急カーブへの対応
+ライントレースにおいてミスのないようにすること
+捕球行為
+シュート行為
+車体を滑らかに走行
+トレースのミスがないうえでの高速化
+安定性の確保

*課題攻略時の条件設定 [#dbf62c02]
今回、自分はB➡Aを担当した。

ボールは直線PQ間の中間少しQ寄りに設置。

機体は線の左側をトレースし、判断しながら走行。

*ロボットの説明 [#w59046ab]
今回も車体部分、ボールを補給するためのアーム部分と大まかに2つの部分から成り立つ。

**車体部分 [#y51504f2]
&ref(./sketch-1438965025944.jpg,30%);
&ref(./body3.jpg,30%);
&ref(./sketch-1438983372407.jpg,30%);

***ポイント [#l17b8411]
-難点1を克服するために両車輪の中心とセンサーとの距離を縮める。
-難点2を克服するためにタイヤ2つとキャスター1つで構成。
-難点3を克服するために90°に曲がるブロックを用い、地面ギリギリの位置にセンサーを設置
-小回りが利くように小さいサイズのタイヤを使用。

**アーム部分 [#d06617c1]
&ref(./sketch-1438964690052.jpg,30%);
&ref(./arm3.jpg,30%);
&ref(./sketch-1438964834760.jpg,30%);

***ポイント [#ad765672]
-難点4で挟む型ではモーターの回転速度が速く、安定しないため囲う型を採用。
-難点5では、回る軸に足をつけることにより囲いを開けると同時にボールを押し出す。
-ボールをしっかり囲うことにより、移動中も取りこぼさない。

**完成 [#c0694e23]
上記のパーツを組み合わせることにより完成。

&ref(./完成3.jpg,30%);
&ref(./完成1.jpg,30%);
&ref(./完成2.jpg,30%);
&ref(./完成4.jpg,30%);

*プログラムの説明 [#a563890b]

**実際のプログラム [#h99af015]

 #define BLACK 42	//以下は黒
 #define BLACK 45	//以下は黒
 #define WHITE 50	//以上は白
 #define go_forward OnFwd(OUT_AC);	//前へ
 #define go_back OnRev(OUT_AC);		//後ろへ
 #define turn_right OnRev(OUT_C); OnFwd(OUT_A);		//右旋回
 #define turn_left OnFwd(OUT_C); OnRev(OUT_A);		//左旋回
 #define STEP 1  // 一回の判定で進む時間
 #define short_break Off(OUT_AC); Wait(200); // 小休止
 #define CROSS_TIME 20  // 交差点通過にかかる時間
 #define cross_line go_forward;Wait(CROSS_TIME);short_break;	//交差点を渡る
 #define FIX_TIME 18
 #define nMAX 8
 #define clip_on OnFwd(OUT_B);Wait(10);Off(OUT_B);
 #define clip_off OnRev(OUT_B);Wait(10);Off(OUT_B);
 #define shoot go_back;Wait(50);go_forward;Wait(30);clip_off;	//シュート
 task main()
 {
   SetSensor(SENSOR_2, SENSOR_LIGHT);
   int nOnline=0; // 続けて黒になった回数 (カウンタ)
       if (true) {	//黒を続けてnMAX回繰り返さない間、通常のライントレースをする
           while (nOnline <nMAX) {
               if (SENSOR_2 < BLACK){  // 線上なら
                   turn_left;                // 左へ
                   nOnline++;		//カウンタ増やす
               } else {
                   if (SENSOR_2 < WHITE){                    // 境界付近なら
                       go_forward;               // 直進
                   } else { 		//線から外れれば 
 	               turn_right;	//右へ
                   }
                   nOnline=0;		//カウンタをリセット
               }			
               Wait(STEP);
           }
           short_break;		//小休憩
           turn_left;Wait(FIX_TIME);	//方向左修正
           clip_on;		//捕球
           nOnline=0;		//カウンタをリセット
       }
       if (true) {	//黒を続けてnMAX回繰り返さない間、通常のライントレースをする
           while (nOnline <nMAX) {
               if (SENSOR_2 < BLACK){  // 線上なら
                   turn_left;                // 左へ
                   nOnline++;		//カウンタ増やす
               } else {
                   if (SENSOR_2 < WHITE){                    // 境界付近なら
                   go_forward;               // 直進
               } else { 		//線から外れれば 
 	           turn_right;	//右へ
               }
               nOnline=0;		//カウンタをリセット
           }			
           Wait(STEP);
       }
       short_break;		//小休憩
       turn_right;Wait(FIX_TIME);	//方向修正
       cross_line;		//交差点を渡る
       nOnline=0;		//カウンタをリセット
   }
   if (true) {	//黒を続けてnMAX回繰り返さない間、通常のライントレースをする
       while (nOnline <nMAX) {
           if (SENSOR_2 < BLACK){  // 線上なら
               turn_left;                // 左へ
               nOnline++;		//カウンタ増やす
           } else {
               if (SENSOR_2 < WHITE){                    // 境界付近なら
                   go_forward;               // 直進
           } else { 		//線から外れれば
 	       turn_right;	//右へ
           }
           nOnline=0;		//カウンタをリセット
       }			
       Wait(STEP);
   }
   short_break;		//小休憩
   go_forward;Wait(100);	//ゴール前へ
   turn_right;Wait(80);	//方向修正
   shoot;		//シュート
   Off(OUT_AC);	//停止
   nOnline=0;		//カウンタをリセット
  }
     SetSensor(SENSOR_2, SENSOR_LIGHT);
     int nOnline=0; // 続けて黒になった回数 (カウンタ)
     while (nOnline <nMAX) {
         if (SENSOR_2 < BLACK){  // 線上なら
             turn_left;                // 左へ
             nOnline++;		//カウンタ増やす
         } else {
             if (SENSOR_2 < WHITE){                    // 境界付近なら
                 go_forward;               // 直進
             } else { 		//線から外れれば
	         turn_right;	//右へ
             }
             nOnline=0;		//カウンタをリセット
         }
         Wait(STEP);
     }
     short_break;		//小休憩
     turn_left;Wait(FIX_TIME);	//方向左修正
     clip_on;		//捕球
     nOnline=0;		//カウンタをリセット
     while (nOnline <nMAX) {
         if (SENSOR_2 < BLACK){  // 線上なら
             turn_left;                // 左へ
             nOnline++;		//カウンタ増やす
         } else {
             if (SENSOR_2 < WHITE){                    // 境界付近なら
                 go_forward;               // 直進
             } else { 		//線から外れれば
	         turn_right;	//右へ
             }
             nOnline=0;		//カウンタをリセット
         }
         Wait(STEP);
     }
     short_break;		//小休憩
     turn_right;Wait(FIX_TIME);	//方向修正
     cross_line;		//交差点を渡る
     nOnline=0;		//カウンタをリセット
     while (nOnline <nMAX) {
         if (SENSOR_2 < BLACK){  // 線上なら
             turn_left;                // 左へ
             nOnline++;		//カウンタ増やす
         } else {
             if (SENSOR_2 < WHITE){                    // 境界付近なら
                 go_forward;               // 直進
             } else { 		//線から外れれば
	         turn_right;	//右へ
             }
             nOnline=0;		//カウンタをリセット
         }
         Wait(STEP);
     }
     short_break;		//小休憩
     go_forward;Wait(100);	//ゴール前へ
     turn_right;Wait(80);	//後退&前進
     shoot;		//シュート
     Off(OUT_AC);	//停止
     nOnline=0;		//カウンタをリセット
 }
**使用した関数 [#ma76d432]

 #define BLACK 42	//以下は黒
 #define WHITE 50	//以上は白
 #define go_forward OnFwd(OUT_AC);	//前へ
 #define go_back OnRev(OUT_AC);		//後ろへ
 #define turn_right OnRev(OUT_C); OnFwd(OUT_A);		//右旋回
 #define turn_left OnFwd(OUT_C); OnRev(OUT_A);		//左旋回
 #define STEP 1  // 一回の判定で進む時間
 #define short_break Off(OUT_AC); Wait(200); // 小休止
 #define CROSS_TIME 20  // 交差点通過にかかる時間
 #define cross_line go_forward;Wait(CROSS_TIME);short_break;	//交差点を渡る
 #define FIX_TIME 18
 #define nMAX 8
 #define clip_on OnFwd(OUT_B);Wait(10);Off(OUT_B);
 #define clip_off OnRev(OUT_B);Wait(10);Off(OUT_B);
 #define shoot go_back;Wait(50);go_forward;Wait(30);clip_off;	//シュート

***解説 [#h6bcc6d4]
+黒色と判断する値の設定
+白色と判断する値の設定
+前進
+後退
+時計回りに旋回
+反時計回りに旋回
+センサーの判断を1/100秒に設定
+交差点と判断した時の2秒間停止
+交差点通過にかかる時間の設定
+交差点を渡る動作
+交差点と判断した時の方向修正の時間の設定
+交差点と判断するための連続回数の上限設定
+囲いを上げる動作
+囲いを下す動作
+後ろへ下がり、前進して勢いをつけてから囲いを上げることによりシュート

**B地点&#10145;曲がり角 [#i97421fe]

 task main()
 {
   SetSensor(SENSOR_2, SENSOR_LIGHT);
   int nOnline=0; // 続けて黒になった回数 (カウンタ)
   if (true) {	//黒を続けてnMAX回繰り返さない間、通常のライントレースをする
       while (nOnline <nMAX) {
           if (SENSOR_2 < BLACK){  // 線上なら
                turn_left;                // 左へ
                nOnline++;		//カウンタ増やす
             } else {
               if (SENSOR_2 < WHITE){                    // 境界付近なら
                    go_forward;               // 直進
                 } else { 		//線から外れれば 
 	           turn_right;	//右へ
   while (nOnline <nMAX) {
       if (SENSOR_2 < BLACK){  // 線上なら
             turn_left;                // 左へ
             nOnline++;		//カウンタ増やす
         } else {
           if (SENSOR_2 < WHITE){                    // 境界付近なら
                 go_forward;               // 直進
             } else { 		//線から外れれば
               turn_right;	//右へ
             }
             nOnline=0;		//カウンタをリセット
         }			
       Wait(STEP);
         }
       Wait(STEP);
     }

***解説 [#t4dfca47]
+センサー2番にライトセンサーを接続し、使用可能状態に。
+続けて黒と判断した時にその連続回数をカウントさせる。
+連続で黒であるとnMAX回判断したらァ銑┐瞭虻遒鮟了させる。
+連続で黒であるとnMAX回判断しない限りァ銑┐瞭虻遒鯊海韻気擦襦
+黒であると判断したなら左へ旋回し、カウンタを1増やす。
+難点6および7を克服するために境界線上であれば直進させ、カウンタをリセットさせる。
+白であると判断したなら右へ旋回し、カウンタをリセットさせる。
+ァ銑Г虜邏箸STEP/100秒ごとに行う。

**曲がり角 [#w0dea0c0]
   short_break;		//小休憩
     short_break;		//小休憩
   turn_left;Wait(FIX_TIME);	//方向左修正
   clip_on;		//捕球
   nOnline=0;		//カウンタをリセット
  }
     nOnline=0;		//カウンタをリセット

***解説 [#k007d8ac]
+曲がり角と判断し、捕球できる角度に調整。
+捕球し、ボールを運んでいく。

**曲がり角&#10145;交差点Q [#b091a242]
   if (true) {	//黒を続けてnMAX回繰り返さない間、通常のライントレースをする
       while (nOnline <nMAX) {
           if (SENSOR_2 < BLACK){  // 線上なら
               turn_left;                // 左へ
               nOnline++;		//カウンタ増やす
           } else {
               if (SENSOR_2 < WHITE){                    // 境界付近なら
                   go_forward;               // 直進
               } else { 		//線から外れれば 
 	           turn_right;	//右へ
               }
               nOnline=0;		//カウンタをリセット
           }			
           Wait(STEP);
       }
     while (nOnline <nMAX) {
         if (SENSOR_2 < BLACK){  // 線上なら
             turn_left;                // 左へ
             nOnline++;		//カウンタ増やす
         } else {
             if (SENSOR_2 < WHITE){                    // 境界付近なら
                 go_forward;               // 直進
             } else { 		//線から外れれば
                 turn_right;	//右へ
             }
             nOnline=0;		//カウンタをリセット
         }
         Wait(STEP);
     }

***解説 [#y9e77c75]
「B地点&#10145;曲がり角」と同様

**交差点Q [#y68389dc]
   short_break;		//小休憩
     short_break;		//小休憩
   turn_right;Wait(FIX_TIME);	//方向修正
   cross_line;		//交差点を渡る
   nOnline=0;		//カウンタをリセット
  }
     nOnline=0;		//カウンタをリセット

***解説 [#bef05d71]
+交差点と判断した時には8/100秒分反時計回りをしているので元の方向へ修正。
+交差点を通過し、元のライントレースへ戻す。

**交差点Q&#10145;A地点 [#i2f08f15]
 if (true) {	//黒を続けてnMAX回繰り返さない間、通常のライントレースをする
     while (nOnline <nMAX) {
         if (SENSOR_2 < BLACK){  // 線上なら
             turn_left;                // 左へ
             nOnline++;		//カウンタ増やす
         } else {
             if (SENSOR_2 < WHITE){                    // 境界付近なら
             go_forward;               // 直進
         } else { 		//線から外れれば
 	     turn_right;	//右へ
                 go_forward;               // 直進
             } else { 		//線から外れれば
                 turn_right;	//右へ
             }
             nOnline=0;		//カウンタをリセット
         }
         nOnline=0;		//カウンタをリセット
     }			
     Wait(STEP);
 }
         Wait(STEP);
     }

***解説 [#sddfa79d]
「B地点&#10145;曲がり角」と同様

なお、交差点Pは左側に沿って進んでいるため交差点と判断せずに通過

***A地点&#10145;シュート [#sab8905f]
   short_break;		//小休憩
     short_break;		//小休憩
   go_forward;Wait(100);	//ゴール前へ
   turn_right;Wait(80);	//方向修正
   shoot;		//シュート
   Off(OUT_AC);	//停止
   nOnline=0;		//カウンタをリセット
  }
   turn_right;Wait(80);	//後退&前進
     shoot;		//シュート
     Off(OUT_AC);	//停止
     nOnline=0;		//カウンタをリセット
 }

***解説 [#i5832d27]
+ゴール前へ移動
+時計回りに旋回し、ゴールの方向へ向く。

*動画 [#pf5f8942]
https://www.youtube.com/watch?v=4MCEfXaGeHw

*感想 [#bcb3b9ac]
今回の課題は、ボールを挟もうとしたら、勢いが強く上から抜けて行ってしまってり、急なカーブを曲がり切れなかったりと予想と同じ動きをしないようなことが多くあった。

そのたびに解決策を出していった結果この形にたどり着いた。

そのため、かなりの時間を費やしたと思う。

やはり、こういった課題は順序立ててゆっくりとでも時間をかけてやっていくことが攻略への糸口なのだと思う。

この機体は皆の前でも成功を収めることができたのでなかなかの出来だと思いたい。

ただ、プログラムが複雑になってしまい、見づらいところがある。サブルーチンを用いればもう少し簡略化できるのだが、今回は知識が足らず断念した。

次回の課題までにはサブルーチンも覚え、もっと見やすいプログラムの構成をしていきたい。



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