[[2015a/Member]]
* 課題内容 [#sf34144c]
** ライントレース [#e0a11e64]
ライントレースをしながら,途中にあるピンポン玉をゴールまで運び,ゴールにシュートする.

私はAからBのコース(P地点,Q地点ともに直進)でライントレースをすることになった.

#ref(2015a/Mission2/2015a-mission2.png,50%)
*** ルール [#t0506adb]
-P地点とQ地点の間のどこかにピンポン玉を置く.
-三叉路および交差点では2秒間停止する.
-可能であればA,B,Cのそれぞれにエリアに入る三叉路付近からボールをシュートする.

[[課題2>2015a/Mission2]]参照

* 目次 [#j88475a2]
#contents
* コース [#e79a5a13]
私は黄色い丸の場所にピンポン玉を置いて,次のようなコースでライントレースをした.


#ref(./course.png,30%)

* ロボット [#b280d77c]

** 全体 [#n12d0019]
ピンポン玉を挟んでシュートする動作をするため,クワガタのようなロボットを作った.

&ref(./DSC_0221 (2).JPG,10%);
&ref(./DSC_0223.JPG,11%);

** タイヤ部分 [#ecacf051]

挟んでシュートする機構のため縦に長くなってしまったから,車体を安定させる必要があった.

また,前タイヤと後ろタイヤの間隔が広いとうまく曲がれずライントレースできない.

そこで,インストラクションのロボットのタイヤ部分を参考にして組み立てた.

** アーム部分 [#fd189801]

&ref(./DSC_0230_01.jpg,9%);
&ref(./DSC_0233_01.jpg,9%);
&ref(./DSC_0233_01(1).jpg,9%);
&ref(./DSC_0241 (2).JPG,9%);

ピンポン玉を挟む,押し出してシュートするという動作をすることができる.

上の真ん中の図の黄色で囲って示してあるブロックはシャフトを通せるようになっているブロックで,RCXブロックに取り付けてあり,

水色で囲って示してある部分が動かせる部分になっている.

仕組みは上図のようになっていて,

+モーターBについているギアが回る(橙矢印)
+ラックギアが平行移動する(赤矢印)
+その先に取り付けてあるウォームギアが前後する(青矢印)
+アーム部分が開閉する(緑矢印)

という仕組みだ.開くと同時にピンポン玉を押し出せるようになっている.

また,開くときと閉じるときに本体の部品にあたって,開きすぎたり閉じすぎたりしないようにしているのだが,そのままではモーターや部品に負荷がかかってしまい故障の原因となってしまう.

そこで,モーターBの軸の部分にクラッチギアを用いることで,必要以上に負荷をかけないようにしている.

** 光センサー [#w358038f]

光センサーはできるだけ左右のタイヤの中心に持ってくると,左右に曲がったときのセンサーの振れ幅が小さくて済むから,車体の内側に取り付けた.

#ref(./DSC_0228.JPG,10%)
#ref(./DSC_0228(1).JPG,10%)

またこのロボットは,ピンポン玉をシュートする部分があるため,中心には取り付けることができなかったから,ロボットの少し左側に取り付けることにした.

プログラムがラインの左側をトレースするようになっているため,光センサーが少し左側にあるとロボットはちょうどラインの真ん中をなぞって見えるようになった.
* プログラム [#tc80bb2f]

** 定数[#e95297f7]
- THRESHOLD・・・一番黒い場所,白い場所のライトセンサーの値からしきい値THRESHOLDを設定した.最も黒い場所ではセンサーの値が37,最も白い場所では51であったため,44とした.

- STEP・・・定数STEPはライントレースをするときに,1回の判定によって行動する時間である.設定できる最小の値である1としたから,1回の判定で0.01秒行動することになる.

- EYE・・・光センサーの値をEYEとした.

 #define THRESHOLD 44
 #define STEP 1
 #define EYE SENSOR_2

** マクロ[#z0ce7e8f]

- pause・・・交差点,三叉路に入ったと判定したとき,2秒間停止する.

- go_forward・・・ライントレースでセンサーの値が丁度しきい値の時と,交差点を直進するときに使う.

- correct_direction(t)・・・交叉点,三叉路に入った後は少し左を向いているはずだから,そのずれを修正する.交差点や三叉路の角度がそれぞれ異なるため,引数を取り時間を設定できるようにした.

 #define pause Off(OUT_AC);Wait(200);
 #define go_forward OnFwd(OUT_AC); 
 #define correct_direction(t) OnFwd(OUT_A);OnRev(OUT_C);Wait(t);

** サブルーチン [#c64b4935]

- catch_ball・・・進みながらピンポン玉をキャッチする.

- shoot・・・少し止まってからピンポン玉をシュートする.速いシュートが出来るようにパワーを7に設定した.

 sub catch_ball()
 {
 	go_forward;Wait(30);
 	OnFwd(OUT_B);Wait(15);
 	Off(OUT_ABC);
 	PlaySound(SOUND_FAST_UP);
 }
 
 sub shoot()
 {
 	Off(OUT_AC);Wait(10);
 	SetPower(OUT_B,7);
 	OnRev(OUT_B);Wait(13);
 	Off(OUT_B);
 	PlaySound(SOUND_UP);
 }

** 変数 [#v21dee11]

cross_point・・・交差点に差し掛かった回数をカウントするために使った.

この変数を使って,交差点を通った回数でmainタスクの中のwhile文を大きく3つに分割している.

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

*** 直線や緩いカーブをトレースするプログラム [#v0a15963]

サブルーチンline_traceとして定義した.

このプログラムではセンサーの値によってロボットの行動を3つに分けている.光センサーの値がしきい値より低いと黒と判別して左に曲がる,高いと白と判別して右に曲がる,黒と白のちょうど中間は灰色と判別して真っ直ぐ進む.

曲がるときは片方のタイヤを止めて曲がるようにしている.

また,真っ直ぐ進むときのパワーは3とし,曲がるときのパワーを絶対値|(しきい値)―(センサーの値)|とすることで,ラインの境界線から離れているほど大きい力で,近いと小さい力で曲がるようにした.センサーの値は37〜51を示すから,パワーの最大値は6となり,程よいパワーでスムーズにライントレースができた.



 sub line_trace()
 {
 	if(EYE < THRESHOLD) {				//センサーの値がしきい値よりも低いとき(黒)左に曲がる
 	  SetPower(OUT_AC,THRESHOLD-EYE);		
 	  OnFwd(OUT_C);Off(OUT_A);
 	  ClearTimer(1);
 	if(EYE < THRESHOLD) {				        //センサーの値がしきい値よりも低いとき(黒)左に曲がる
 	        SetPower(OUT_AC,THRESHOLD-EYE);		
 	        OnFwd(OUT_C);Off(OUT_A);
 	        ClearTimer(1);
 	} else {
 	 if(EYE == THRESHOLD) {				//センサーの値がちょうどしきい値のとき(灰色)まっすぐ進む
 	  SetPower(OUT_AC,3);			
 	  go_forward;
 	  ClearTimer(1);
 	 } else {					//センサーの値がしきい値よりも高いとき(白)右に曲がる
 	  SetPower(OUT_AC,EYE-THRESHOLD);		
 	  OnFwd(OUT_A);Off(OUT_C);
 	 }
 	 ClearTimer(0);					
 	        if(EYE == THRESHOLD) {				//センサーの値がちょうどしきい値のとき(灰色)まっすぐ進む
 	                SetPower(OUT_AC,3);			
 	                go_forward;
 	                ClearTimer(1);
 	        } else {					//センサーの値がしきい値よりも高いとき(白)右に曲がる
 	                SetPower(OUT_AC,EYE-THRESHOLD);		
 	                OnFwd(OUT_A);Off(OUT_C);
 	        }
 	        ClearTimer(0);					
 	}
 	Wait(STEP);
                                                         /*黒になったときはFastTimer(0)はそのまま,白と灰色のときはリセット(連続で黒になった時間を計測)
 							  白になったときはFastTimer(1)はそのまま,黒と灰色のときはリセット(連続で白になった時間を計測)*/
                                      /*黒になったときはFastTimer(0)はそのまま,白と灰色のときはリセット(連続で黒になった時間を計測)
 				      白になったときはFastTimer(1)はそのまま,黒と灰色のときはリセット(連続で白になった時間を計測)*/
 
 	if(FastTimer(1) > 80){                 /*一定の時間(0.8秒)以上白い場所にいるとき
 	OnRev(OUT_AC);until(EYE < THRESHOLD);Off(OUT_AC);	黒い場所まで下がる*/
 	ClearTimer(0);
 	}
 	        if(FastTimer(1) > 80){                         /*一定の時間(0.8秒)以上白い場所にいるとき
 	                OnRev(OUT_AC);until(EYE < THRESHOLD);Off(OUT_AC);	黒い場所まで下がる*/
 	                ClearTimer(0);
 	        }
 }

*** タイマー FastTimer(0),FastTimer(1) [#r4a9195d]

- FastTimer(0)・・・初めは変数を使って「連続で黒になった(左に曲がった)回数」で交差点だと判定するようにしていた.

   しかしタイマーを使って「連続で黒になった時間」で交差点を判定するようにしたところ,より正確に交差点と急なカーブを判別できるようになった.

   そのため,FastTimer(0)を使って,時間で交差点の判別をするようにした.

- FastTimer(1)・・・FastTimer(0)とは逆で,「連続で白になった時間」をカウントする.

   これを使って一定の時間白と判定し続けた場合,ラインの上に乗っていないと判断し,センサーの値が黒になるまで下がるようにしている.




mainタスクではサブルーチンline_traceをwhile文で囲ってあるから,一定の時間以上黒の判定になったとき,ループを抜け出し交差点や三叉路を進むようになっている.

 while(FastTimer(0) < 35)
 {
  line_trace();					
 while(FastTimer(0) < 35) {
         line_trace();					
 }
 pause;
 correct_direction(20);	
 go_forward;Wait(15);

*** 急なカーブをトレースするプログラム [#k52c9766]

P地点からQ地点には半径7.5(このプログラムではラインの左側をトレースするから実際に曲がるのはは6.5)の円がある.

このカーブはサブルーチンline_traceでは曲がりきることができなかった.

そこでサブルーチンline_traceにOnRevを追加し,急なカーブを曲がれるプログラムをサブルーチンcurve_traceとした.反転するタイヤのパワーが2を超えるとスピードが極端に落ちてしまったため,パワーは1とした.

 sub curve_trace()					//OnRevを追加し急なカーブを曲がれるようにした
 {
 	if(EYE < THRESHOLD) {
 	  SetPower(OUT_C,THRESHOLD-EYE);SetPower(OUT_A,1);
 	  OnFwd(OUT_C);OnRev(OUT_A);
 	  ClearTimer(1);
 	        SetPower(OUT_C,THRESHOLD-EYE);SetPower(OUT_A,1);
 	        OnFwd(OUT_C);OnRev(OUT_A);
 	        ClearTimer(1);
 	} else {
 	 if(EYE == THRESHOLD) {
 	  SetPower(OUT_AC,3);
 	  go_forward;
 	  ClearTimer(1);
 	 } else {
 	  SetPower(OUT_A,EYE-THRESHOLD);SetPower(OUT_C,1);
 	  OnFwd(OUT_A);OnRev(OUT_C);
 	 }
 	 ClearTimer(0);
 	        if(EYE == THRESHOLD) {
 	                SetPower(OUT_AC,3);
 	                go_forward;
 	                ClearTimer(1);
 	        } else {
 	                SetPower(OUT_A,EYE-THRESHOLD);SetPower(OUT_C,1);
 	                OnFwd(OUT_A);OnRev(OUT_C);
 	        }
 	        ClearTimer(0);
 	}
 	Wait(STEP);
 
 	if(FastTimer(1) > 80){
 	OnRev(OUT_AC);until(EYE < THRESHOLD);Off(OUT_AC);
 	ClearTimer(0);
 	        OnRev(OUT_AC);until(EYE < THRESHOLD);Off(OUT_AC);
 	        ClearTimer(0);
 	}
 }

** mainタスク [#tccf2fc7]

*** while文の分割 [#h72f4766]

交差点と三叉路ごとに,ピンポン玉をとってから直進,直進,ピンポン玉をシュート,とそれぞれ違った動作をするため,変数cross_pointを使ってwhile文を3分割した.また,そうすることで各while文によって交差点,三叉路の基準(FastTimer(0)が何秒以下か)を変えることができるようになった.
交差点と三叉路ごとに,ピンポン玉をとってから直進,直進,ピンポン玉をシュート,とそれぞれ違った動作をするため,変数cross_pointを使ってwhile文を大きく3分割した.また,そうすることで各while文によって交差点,三叉路の基準(FastTimer(0)が何秒以下か)を変えることができるようになった.

*** タイマー FastTimer(2) [#fc6471ea]

FastTimer(2)・・・P地点からQ地点の間に,半径7.5僂離ーブがある.そのカーブはそれまでのライントレースでは曲がれない.そのためFastTimer(2)を使い,ピンポン玉をとってから急カーブまでの一定時間はサブルーチンline_trace.急カーブに差し掛かってから一定時間は急カーブを曲がるためのサブルーチンcurve_traceをするようにした.

*** task main [#ic456ea0]

 task main()
 {
 	SetSensor(SENSOR_2,SENSOR_LIGHT);
 	ClearTimer(0);
 	int cross_point=0;					
 	ClearTimer(2);
 
 //////////////////////
 //
 // エリアAからP地点 
 //
 //////////////////////
 
 	while(cross_point==0)					//cross_pointが0(AからP)のとき繰り返す
 	{
 	 while(FastTimer(0) < 35) 			    //最初の三叉路までサブルーチンline_trace繰り返し
 	 {
 	  line_trace();					
 	 }
 	 pause;
 	 correct_direction(30);			
 	 catch_ball();					     //ピンポン玉を挟む
 	 ClearTimer(0);
 	 cross_point++;					       //ループ終わり
 	while(cross_point==0) {                                          //cross_pointが0(AからP)のとき繰り返す
 	        while(FastTimer(0) < 35) { 			         //最初の三叉路までサブルーチンline_trace繰り返し
 	                line_trace();					
 	        }
 	        pause;
 	        correct_direction(30);			
 	        catch_ball();					         //ピンポン玉を挟む
 	        ClearTimer(0);
 	        cross_point++;					         //ループ終わり
 	}
 	
 
 //////////////////////
 //
 // P地点からQ地点 
 //
 //////////////////////
 
 	ClearTimer(2);
 
 	while(cross_point==1)				       //cross_pointが1(PからQ)のとき繰り返す
 	{
 	 while((FastTimer(2) < 500)&&(FastTimer(0) < 100))     //交差点を通ってから5秒間は,交差点を認識しにくくしてサブルーチンline_trace繰り返し
 	 {
 	  line_trace();
 	 }
 	PlaySound(SOUND_CLICK);				     //判定が切り替わる合図
 	while(cross_point==1) {				                 //cross_pointが1(PからQ)のとき繰り返す
                while((FastTimer(2) < 500)&&(FastTimer(0) < 100)) {      //交差点を通ってから5秒間は,交差点を認識しにくくしてサブルーチンline_trace繰り返し
 	                line_trace();
 	        }
 	        PlaySound(SOUND_CLICK);				       //判定が切り替わる合図
 
 	 while((FastTimer(2) < 1200)&&(FastTimer(0) < 100))   //交差点を通ってから5秒経ってから,7秒間はサブルーチンcurve_trace繰り返し
 	 {
 	  curve_trace();
 	 }
 	PlaySound(SOUND_CLICK);			         //判定が切り替わる合図
 	        while((FastTimer(2) < 1200)&&(FastTimer(0) < 100)) {    //交差点を通ってから5秒経ってから,7秒間はサブルーチンcurve_trace繰り返し
 	                curve_trace();
 	        }
 	        PlaySound(SOUND_CLICK);			           //判定が切り替わる合図
 	
 	 while(FastTimer(0) < 35)			     //急カーブをだいたい曲がりきったあと,交差点までサブルーチンline_trace繰り返し
 	 {
 	  line_trace();
 	 }
 	        while(FastTimer(0) < 35) {			       //急カーブをだいたい曲がりきったあと,交差点判定を元に戻して交差点までサブルーチンline_trace繰り返し
 	                line_trace();
 	        }
 	
 	 pause;
 	 correct_direction(20);	
 	 go_forward;Wait(15);				    //交差点を直進
 	 ClearTimer(0);			
 	 cross_point++;					      //ループ終わり
 	        pause;
       	        correct_direction(20);	
 	        go_forward;Wait(15);				       //交差点を直進
 	        ClearTimer(0);			
 	        cross_point++;					         //ループ終わり
 	}
 	
 //////////////////////
 //
 // Q地点からエリアB 
 //
 //////////////////////
 
 	while(cross_point==2)				      //cross_pointが2(QからB)のとき繰り返す
 	{
 	 while(FastTimer(0) < 30)			     //最後の三叉路までサブルーチンline_trace繰り返し
 	 {
 	  line_trace();
 	 }
 	 pause;
 	 correct_direction(10);
 	 shoot();			                    //シュート
 	 cross_point++;					      //ループ終わり
 	while(cross_point==2) {				                 //cross_pointが2(QからB)のとき繰り返す
 	        while(FastTimer(0) < 30) {			        //最後の三叉路までサブルーチンline_trace繰り返し
 	                 line_trace();
 	        }
 	        pause;
 	        correct_direction(10);
 	        shoot();			                       //シュート
 	        cross_point++;					         //ループ終わり
 	}
 }

* 動画 [#w7140d73]

http://youtu.be/5y0AsZu49UQ

* まとめと反省 [#db143145]

ピンポン玉を挟んでシュートする機構のために,ロボットが大きくなってしまった.
そのため,小回りが利きにくくなってしまい,急カーブ用のライントレースのプログラムを作ることになってしまった.
しかし,タイマーを使ってライントレースのプログラムを切り替えることで,その問題をうまく解決できたと思う.

このプログラムだと,タイマーで制御している部分も大幅にずれることもなく,成功率の高い安定した走りをした.


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