目次

課題2

下の図のようなコースを作成し、指定されたコースを走行し途中でゴール付近の空き缶にボールを当てるロボットを作成する。

10

今回、私が走行させるコースは第一コースで

   ロボットを長方形X内におき、Aをスタート
   Bを右折
   Kで一時停止して左折
   Jを直進
   Iを直進
   Hを左折
   Gで一時停止して左折
   Eで一時停止して右折
   Lを経て正方形Y内に入って停止
   ボールはロボットが弧KJIH上にある時にQ地点の空き缶に当てる

というものだ

図で表すと・・・ 

ko-su.png

ロボットの概要

ロボットの全体像↓(進行方向は写真右方向)

19651.jpg

一つ目のモーターにボールを転がす機能を付け、二つ目と三つ目にタイヤを付けた。また、後方にタイヤを付け前回の課題1と同様に三輪車型のロボットにした。NXT本体は重心ができるだけモーターについているタイヤの上付近に来るようにした。しかし本体の両脇を計2本の棒でしか支えていないので不安定なのが反省点。

矢印の方向に棒を動かしボールを転がす↓

19651_LIV2.jpg

光センサーと超音波センサー、後輪は以下の写真のように取り付けた。

19655_LI.jpg

進行方向とは逆向きに超音波センサーを付けている。はじめは超音波センサーで空き缶を発探知した後に360度旋回してボールを当てる「だけ」と軽く考えていたが、あまかった。誤差が生じる原因となり、空き缶を精確に探知することはできたが旋回時に回りすぎたり回らなすぎたりしてボールが空き缶に当たらないことがあった。

プログラム

使える光センサーが一つだけなので幅2cmの黒線のふちを光センサーで探知しながらトレースしていくようにした。

「白」「白と黒の境界線」「黒」で動きを変えるようにした。このときの光センサーの値はそれぞれ60より上、60以下50より上、50以下を示す(細かい値は下図を参照)。それぞれの動きは黒の領域に曲がる、直進、白の領域に曲がる という動きをする。そして「白」または「黒」の時間が150を超えると旋回に切り替わる様にプログラムした。

それぞれの光センサーの細かい値↓

line.png

以上より

   1,ラインの右端をトレースする関数
   2,ラインの左端をトレースする関数
   3,円周上を走行する関数
   4,空き缶を探知しボールを当てる関数

合計4つの関数を使用しプログラムを作成した。

ラインの右端をトレースする関数

はじめの何秒かは交差点を判断しても停止せず、その時間の経過後は交差点判断をすると停止する関数となっている。

   void follow_line_migi(long t_min)
   {
   SetSensorLight(S1);
   long t_start=CurrentTick();         			       //初期値
   long t0=CurrentTick();            			       //白or黒の時間
   long t_max=150;                			       //連続して黒の限界値
   long t1=CurrentTick();          			       //経過時間
   long t_kosa=200;							//交差点の判断までの時間
   while(t1-t_start<t_min){					//t_minの間交差点の判断をしない
       if(SENSOR_1>60){
           if(t1-t0<t_max){
               OnFwd(OUT_C,40);Off(OUT_A);			//少し白の部分に入ったら左折
           }else{
               OnFwd(OUT_C,20);OnRev(OUT_A,50);			//大きく白の部分に出たら左旋回
           }
       }else if(SENSOR_1>50){
           OnFwd(OUT_AC,30);					//白と黒の境界線なので直進
           t0=CurrentTick();
       }else{
           if(t1-t0<t_max){
               OnFwd(OUT_A,40);Off(OUT_C);			//少し黒の部分に入ったら右折
           }else{
               OnFwd(OUT_A,20);OnRev(OUT_C,50);			//大きく黒の部分に出たら右旋回
           }
       }
       t1=CurrentTick();						//時間更新
   }
   PlaySound(SOUND_CLICK);						//音を鳴らしここから交差点の判断をするようになる
   while(true){
      if(SENSOR_1>60){
           if(t1-t0<t_max){
               OnFwd(OUT_C,40);Off(OUT_A);			//少し白の部分に入ったら左折
           }else{
               OnFwd(OUT_C,20);OnRev(OUT_A,50);			//大きく白の部分に出たら左旋回
           }
       }else if(SENSOR_1>50){
           OnFwd(OUT_AC,40);					//白と黒の境界線なので直進
           t0=CurrentTick();
       }else{
           if(t1-t0<t_max){
               OnFwd(OUT_A,40);Off(OUT_C);			//少し黒の部分に入ったら右折
           }else if(t1-t0<t_kosa){
               OnFwd(OUT_A,20);OnRev(OUT_C,50);			//大きく黒の部分に出たら右旋回
        }else{
         Off(OUT_AC);break;					//黒の時間が一定値以上になったら交差点と判断しwhileのループから抜ける
           }
       }
       t1=CurrentTick();						//時間更新
   }
   Off(OUT_AC);							//止まる
   PlaySound(SOUND_CLICK);						//音を鳴らし交差点と判断したことを知らせる
   }

ラインの左端をトレースする関数

「ラインの右端をトレースする関数」と同様に、はじめの何秒かは交差点を判断しても停止せず、その時間の経過後は交差点判断をすると停止する関数となっている。

   void follow_line_hidari(long t_min)
   {
   SetSensorLight(S1);
   long t_start=CurrentTick();           			//初期値
   long t0=CurrentTick();            				//白or黒の時間
   long t_max=150;               				       //連続して黒の限界値
   long t1=CurrentTick();            				//経過時間
   long t_kosa=200;
   while(t1-t_start<t_min){					//t_minの間交差点の判断をしない
       if(SENSOR_1>60){
           if(t1-t0<t_max){
               OnFwd(OUT_A,40);Off(OUT_C);			//少し白の部分に入ったら右折
           }else{
               OnFwd(OUT_A,20);OnRev(OUT_C,50);			//大きく白の部分に出たら右旋回
           }
       }else if(SENSOR_1>50){
           OnFwd(OUT_AC,40);					//白と黒の境界線なので直進
           t0=CurrentTick();
       }else{
           if(t1-t0<t_max){
               OnFwd(OUT_C,40);Off(OUT_A);			//少し黒の部分に入ったら左折
           }else{
               OnFwd(OUT_C,20);OnRev(OUT_A,50);			//大きく黒の部分に出たら左旋回
            }
       }
       t1=CurrentTick();						//時間更新
   }
   Off(OUT_AC);
   PlaySound(SOUND_CLICK);						//音を鳴らしここから交差点の判断をするようになる
   while(true){
       if(SENSOR_1>60){
           if(t1-t0<t_max){
               OnFwd(OUT_A,40);Off(OUT_C);			//少し白の部分に入ったら右折
           }else{
               OnFwd(OUT_A,20);OnRev(OUT_C,50);			//大きく白の部分に出たら右旋回
           }
       }else if(SENSOR_1>50){
           OnFwd(OUT_AC,30);					//白と黒の境界線なので直進
           t0=CurrentTick();
       }else{
           if(t1-t0<t_max){
               OnFwd(OUT_C,40);Off(OUT_A);			//少し黒の部分に入ったら左折
           }else if(t1-t0<t_kosa){
               OnFwd(OUT_C,20);OnRev(OUT_A,50);			//大きく黒の部分に出たら左旋回
           }else{
                 Off(OUT_AC);break;				//黒の時間が一定値以上になったら交差点と判断しwhileのループから抜ける
             }
       }
       t1=CurrentTick();						//時間更新
   }
   Off(OUT_AC);							//止まる
   PlaySound(SOUND_CLICK);						//音を鳴らし交差点と判断したことを知らせる
   }

円周上を走行する関数

円周上を交差点判断しても停止せずに進む関数。上記の「ラインの左端をトレースする関数」「ラインの右端をトレースする関数」とほとんど同じ関数。しかし、円周上を走行中に「空き缶を探知しボールを当てる関数」を組み込むため、わかりやすくするためにこの関数を使用した。

   void follow_line_ensyu(long t_min)
   {
   SetSensorLight(S1);
   long t_start=CurrentTick();            			//初期値
   long t0=CurrentTick();          			        //白or黒の時間
   long t_max=150;                				//連続して黒の限界値
   long t_kousa=200;        					//交差点判断
   long t1=CurrentTick();            				//経過時間
   while(t1-t_start<t_min){
       if(SENSOR_1>60){
           if(t1-t0<t_max){
               OnFwd(OUT_A,40);Off(OUT_C);
           }else{
               OnFwd(OUT_A,30);OnRev(OUT_C,60);
           }
       }else if(SENSOR_1>50){
           OnFwd(OUT_AC,30);
           t0=CurrentTick();
       }else{
           if(t1-t0<t_max){
               OnFwd(OUT_C,40);Off(OUT_A);
           }else if(t1-t0<t_kousa){
               OnFwd(OUT_C,30);OnRev(OUT_A,50);
            }else{
          OnFwd(OUT_AC,40);Wait(200);PlaySound(SOUND_CLICK);
         }
       }
       t1=CurrentTick();
   }
   Off(OUT_AC);
   PlaySound(SOUND_CLICK);
   }

空き缶を探知しボールを当てる関数

超音波センサーで空き缶を探知しその方向を向いてボールを当てる関数。

   void search_direction()
   {
	ResetTachoCount(OUT_ABC);			//モーターの角度をリセット
	OnFwd(OUT_A,50);
	OnRev(OUT_C,50);
	SetSensorLowspeed(S4);			    //端子4に超音波センサー
	int d1;
	d1=1000;					//最小距離を1000と定義する
	long t0=CurrentTick();
	long t1=CurrentTick();
	long t2=CurrentTick();
	while(t2-t0<=3570){				//3570の間回り続ける
		t2=CurrentTick();
		if(SensorUS(S4)<d1){			//センサーで探知し最小距離より短い場合
			d1=SensorUS(S4);		//最小値を再定義
			PlaySound(SOUND_CLICK);
			t1=CurrentTick();
		}
		t2=CurrentTick();
	}
	t0=CurrentTick();
	Off(OUT_AC);
	OnFwd(OUT_C,50);
	OnRev(OUT_A,50);
	Wait(t0-t1);					//センサーで最後に最小値のd1を探知した位置を向く
	Off(OUT_AC);
	Wait(1000);
	RotateMotorEx(OUT_AC,50,360,100,true,false);	//ボールを転がす
	RotateMotor(OUT_B,30,60);
	Wait(5000);
	RotateMotor(OUT_B,50,-60);
	RotateMotorEx(OUT_AC,50,380,100,true,false);
   }

没案

はじめに作った「空き缶を探知しボールを当てる関数」。先生に指摘され精確性を欠くことが発覚したため没になった。

   void search_direction()
   {
   OnFwd(OUT_A,50);
   OnRev(OUT_C,50);
   SetSensorLowspeed(S4);            
   int d1;
   d1=1000;
   long t0=CurrentTick();
   long t1=CurrentTick();
   while(t1-t0<3570){
       if(SensorUS(S4)<d1){
           d1=SensorUS(S4);
           PlaySound(SOUND_CLICK);
       }
   t1=CurrentTick();
   }
   while(true){
   if(SensorUS(S4)==d1){
       PlaySound(SOUND_CLICK);
       Off(OUT_AC);
       break;
   }
   }
   }

なぜ精確性を欠くかというと、二つ目のwhile文にある"if(SensorUS(S4)==d1)"が最大の原因。この一文の意味は「もしセンサーの値が"全く"同じなら」という意味になる。この"全く"というものが曲者で、1mmでもずれていたら実行されないことを示している。ロボットは動いているので"全く"同じことはほぼあり得ないのでほとんど実行されないために、この関数は精確性を欠くのである。

完成したプログラム

   task main()
   {
	follow_line_migi(1);				//A~Bの右を進む
	OnFwd(OUT_AC,50);				//車線変更
	Wait(200);
	follow_line_hidari(1);			    //B~Kの左を進む
	PlaySound(SOUND_CLICK);
	Wait(1000);					//Kにて一時停止
	OnFwd(OUT_C,50);
	Wait(500);
	follow_line_ensyu(15000);			//円周回る
	search_direction();				//缶にボール当てる
	follow_line_hidari(5000);			//&#12316;Gまで進む
	Wait(1000);					//Gにて一時停止
	OnFwd(OUT_C,50);				//Gを左折
	Wait(500);
	follow_line_migi(1);				//G~Eの右を進む
	follow_line_migi(15000);
	Wait(1000);					//Eにて一時停止
	follow_line_migi(3000);			    //E~Lの右を進む
	Wait(1000);
	OnFwd(OUT_AC,50);
	Wait(1000);
	Off(OUT_AC);
	OnFwd(OUT_A,50);
	Wait(2000);
	Off(OUT_AC);
   }

まとめ

結果

 ・結論からいうと、発表日に発表することが出来なかった。

 ・発表日当日、先生からの指摘により「空き缶を探知しボールを当てる関数」の探知の仕方が精確性を欠く事が発覚。

 ・上記されている「空き缶を探知しボールを当てる関数」は当日の講義後に書き直したもの。

 ・その他の関数の動作にあまり不備はなかったが電池の消耗が激しかった。

考察

 ・「空き缶を探知しボールを当てる関数」を作る際先生がおっしゃっていたことを正確に理解していなかったので、完璧に理解するまで先生に質問すべきだった。

 ・電池の消耗が激しかった。機体かプログラムに工夫を加えればもう少し電池の消耗の軽減できたと考えられる。

 ・NXT本体の支えが非常に不安定でちょっとした振動でバランスを崩しかけてしまうことがあったので改良が必要。また限られた部品をいかに工夫するかが今後の課題だと考えられる。

感想

今回は授業日の午前中にプログラムが完成し課題も達成していた。しかし、上記にあるように「空き缶を探知しボールを当てる関数」がうまく作動せず先生からの指摘によりその関数だけ作り直すことになり発表することが出来なかった。また、悪い意味で手本になってしまった。これらより前回以上に悔しさが募った。次回は絶対に発表したい。


添付ファイル: file19651_LIV2.jpg [詳細] file19651.jpg [詳細] file19655_LI.jpg [詳細] fileInked19651_LI.jpg 1件 [詳細] fileko-su.png [詳細] fileline.png [詳細] file2018b-mission2v3.png 1件 [詳細] file2018b-mission2v2.png [詳細] file2018b-mission2v2.xcf 12件 [詳細] file2018b-mission2.png 9件 [詳細]

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