[[2015b/Member]]

* ルール [#n75eb5e6]
#ref(2015b/Member/North/Mission3/2015b-mission31.png,100%)
ロボットAはSTART A地点から出発し、P地点におかれた赤いボールを拾って缶に当てる。その後、青いボールについても同様の動作をする。ロボットBはSTART B地点から出発し、ボールを回収、GOAL Bまでボールを運ぶ。

* ロボットの説明 [#i6e421df]
#ref(2015b/Member/North/Mission3/DSC_0770.JPG,10%)
#ref(2015b/Member/North/Mission3/DSC_0772.JPG,10%)
上:ボールを缶に当てるロボット~
下:ボールを運ぶロボット~
どちらも超音波センサーと光センサーを使用している。
** ボールを缶に当てるロボット [#l6159447]
#ref(2015b/Member/North/Mission3/robo--1.jpg,50%)
アームと超音波センサーが連動しており、アームが閉じるとセンサーは正面を向く。~
ライントレースをしながら下向きのセンサーでボールを感知し、アームを閉じてボールを捕まえる。~
アームが閉じたことでセンサーは正面を向き、その状態で缶のある方向を割り出す。ボールはその方向へ押し出すように発射する。~
** ボールを運ぶロボット [#u140eee6]
#ref(2015b/Member/North/Mission3/robo-2.jpg,40%)
斜め下を向いた超音波センサーでボールを感知し、アームを閉じてボールを捕まえる。~
その後、ライントレースを使いボールをゴールへ運ぶ。
* プログラム [#o30f785e]
** ボールを当てる側 [#s04bf884]
#ref(2015b/Member/North/Mission3/shoot.jpg,40%)
1.ボールの位置までライントレース後、ボールをつかむ~
2.所定の位置まで移動し、缶の方向を調べる~
3.その方向へボールを発射
 #define straight OnFwd(OUT_BC,30);
 #define turn_left OnFwd(OUT_B,30);Off(OUT_C);
 #define turn_right OnFwd(OUT_C,30);Off(OUT_B);
 #define TURN_LEFT OnFwd(OUT_B,30);OnRev(OUT_C,30);
 #define TURN_RIGHT OnFwd(OUT_C,30);OnRev(OUT_B,30);
 #define THRESHOLD 35
 #define get OnFwd(OUT_A,45);Wait(300);Off(OUT_A);Wait(1000);
 #define open OnRev(OUT_A,45);Wait(300);Off(OUT_A);Wait(1000);
 
 const float diameter=5.45; 
 const float track=10.35; 
 const float pi=3.1415;
 void fwdDist(float d) {	//dcm進む
	long angle;
 	angle=d/(diameter*pi)*360.0;
	RotateMotorEx(OUT_BC,30,angle,0,true,true);
 }
 void turnAng(long ang) {	//ang度右旋回
 
	long angle;
	angle=track/diameter*ang;
	RotateMotorEx(OUT_BC,30,angle,100,true,true);
 }
 int searchDirection(long ang) {	//最短距離の物体の方を向く
	long angle,tacho_min=0,tacho_corr;
	int d_min;  
	d_min=55; 
	angle=(track/diameter)*ang;
	turnAng(ang/2);
	ResetTachoCount(OUT_BC);
	OnFwdSync(OUT_BC,30,-100);
	while(MotorTachoCount(OUT_B)<=angle){
		if(SensorUS(S4)<d_min){
			PlaySound(SOUND_CLICK);
			d_min=SensorUS(S4);
			tacho_min=MotorTachoCount(OUT_B);
		}
	} 
	OnFwdSyncEx(OUT_BC,30,100,RESET_NONE);
	until(MotorTachoCount(OUT_B)<=tacho_min||SensorUS(S4)<=d_min);
	Wait(14);
	Off(OUT_BC);Wait(500);
 	return d_min; 
 }
 task main() {
	SetSensorLight(S3);
	SetSensorLowspeed(S4);
	int catch=0;
	straight;
	Wait(500);
	RotateMotor(OUT_A,30,-80);
	while(true){
 		if(SensorUS(S4)>=12){	//超音波センサ値 >= 12 つまり、センサがボールを感知するまで
			if(SENSOR_3<THRESHOLD-9){
				TURN_LEFT;
			}else if(SENSOR_3<THRESHOLD-5){
				turn_left;
			}else if(SENSOR_3<THRESHOLD+5){
				straight;
      			}else if(SENSOR_3<THRESHOLD+9){
         			turn_right;
      			}else{
         			TURN_RIGHT;
       		}
   		}else{				//センサがボールを感知したとき
      			Off(OUT_BC);
      			get;
      			Wait(1000);
      			catch++;
 			if(catch==1){
        			RotateMotorEx(OUT_BC,40,-200,0,true,false);
        			RotateMotorEx(OUT_BC,40,200,-100,true,false);
        			Off(OUT_BC);
        			Wait(500);
        			RotateMotorEx(OUT_BC,40,700,0,true,false);
        			Off(OUT_BC);
        			Wait(500);
       			int d=searchDirection(130);
        			PlaySound(SOUND_UP);
	 			if(d<=50){	//超音波センサが缶を感知した時した時
       				Off(OUT_BC);		//↓ここからボールを放つ動作
        				Wait(500);
        				RotateMotorEx(OUT_BC,40,-300,0,true,false);  //下がる
        				Wait(6000);
        				open;	//アームを開く
        				RotateMotorEx(OUT_BC,90,340,0,true,false);  //ボールを掴んだまま速い速度で直進
        				Off(OUT_BC);	//急停止、このときボールを放つ
        				Wait(1000);
        				RotateMotorEx(OUT_BC,65,-730,0,true,true);	//下がる	
        				RotateMotorEx(OUT_BC,40,150,100,true,false);	//40度の右旋回
        				RotateMotor(OUT_A,60,50);	//アームを閉じる
        				straight;  //少しの直進
         				Wait(2500);
	 			}
	 		}
	 	}
	} 
 }
** ボールを運ぶ側 [#p5db5235]
#ref(2015b/Member/North/Mission3/catch'.jpg,40%)
1.所定の位置まで進み、ボールを待つ~
2.前方にボールがある場合、前進してライントレース。無い場合は引き返しボールを走査、捕獲。~
3.ゴールへ向け移動、ボールを離す
 #define SPEED 50	//Distなどのモータのパワーに、幅広く使用
 #define SPEED_SLOW 30      //関数hand,turnAngなどで使用
 #define THRESHOLD 45		//閾値
 #define STEP 1		//Waitの引数として使う
 #define STOP 3		//「ボールがセンサの前を横切った」かどうかを調べる値
 const float diameter=5.45;	     //タイヤの直径(cm)
 const float pi=3.1415;          //円周率
 const float track = 10.35;	//タイヤのトレッド幅
 
 sub hand(int ang, int plmi) {	//ボールをつかむ動作
       /*plmi = 1 → アーム開
         plmi = -1 → アーム閉 */
	RotateMotor(OUT_A, SPEED_SLOW * plmi, ang);
 }
 sub Dist(float d, int fwd_or_rev){  //dcm前転(後転)
	/*fwd_or_rev = 1 → 前転
	  fwd_or_rev = -1 → 後転 */
	long angle;
	angle = d / (diameter * pi) * 360.0;
	RotateMotorEx(OUT_BC, SPEED * fwd_or_rev, angle, 0, true, true);
	Wait(100);
 }
 sub turnAng(int ang, int R_or_L)  //ang度旋回
 {
	/* R_or_L = 1 → 時計回り
	   R_or_L = -1 → 半時計回り */
	long angle;
	angle = track / diameter * ang;
	RotateMotorEx(OUT_BC, SPEED_SLOW , angle, 100* R_or_L, true, true);
	Wait(100);
 }
 int searchDirection(int ang) //ボールを探す関数
 {
	SetSensorLowspeed(S1);
	long angle, tacho_min = 0, tacho_corr;
	int d_min;
	d_min= 300;  //仮の最小値
	angle = (track / diameter) * ang;
	turnAng(10, 1);  //10度右旋回(缶の誤認を防ぐため、10度しか旋回しない)
	ResetTachoCount(OUT_B);
 	
	OnFwdSync(OUT_BC, SPEED, -100);
	while(MotorTachoCount(OUT_B) <= angle) {  //angleだけ左旋回
		if (SensorUS(S1) < d_min) {
			d_min = SensorUS(S1);
			tacho_min = MotorTachoCount(OUT_B);
		}
	}
	if (d_min < 30) {  //「超音波センサの示した最小値」が30以下のとき
		OnFwdSyncEx(OUT_BC,SPEED, 100, RESET_NONE);  //最小値だった方向を向く
		until(MotorTachoCount(OUT_B) <= tacho_min || SensorUS(S1) <= d_min);
	}
	else {  //30以上のとき
		turnAng(ang - 10, 1);  //ang-10だけ右旋回(関数開始前と同じ向きに戻る)
	}
	Off(OUT_BC); Wait(500);  //0.5秒間停止
	return d_min;  //「超音波センサの示した最小値」を返す
 }
 
 sub turn_left(int speedA, int speedB) {	//左に曲がる
 	OnFwd(OUT_B,speedA); 			//引数speedAのパワーで、モータBを前転
 	OnRev(OUT_C,speedB);				//引数speedBのパワーで、モータCを後転
 }
 sub turn_right(int speedA, int speedB) {	//右に曲がる
 	OnFwd(OUT_C,speedB); 			//引数speedBのパワーで、モータCを前転
 	OnRev(OUT_B,speedA);				//引数speedAのパワーで、モータBを後転
 }
 sub go_forward(int speed3) {		//まっすぐ進む
 	OnFwd(OUT_BC,speed3);			//speed3のパワーで、モータBCを前転
 } 
 
 sub trace(int time, long target, int speed3) {  //(time秒以内 && TachoCount < target)の間ライントレース
	SetSensorLight(S2);
 	int speed1 = 25;  		//モータのパワー用
 	int speed2 = 20;  		//モータのパワー用(speed1より少し弱い)
 	long tacho = 0;    		//「その場で左旋回する」動作をし続けたときの、回転角の合計
 	long t;	    		//タイマーを使うときに使用
 
 	t = CurrentTick();	//ここで現在時刻をtに代入(CurrentTick() - t と使うことで、経過時間がわかる)
 	while (CurrentTick() - t < time && tacho < target) {
 	     	if (SENSOR_2 < THRESHOLD -15){  		//光センサの数値が、THRESHOLD-15より低いとき                       		
 			turn_left(speed1, speed1); 			//左右のモータをspeed1で左旋回(その場で左回転)
  						
 		} else if (SENSOR_2 < THRESHOLD -7) {	//光センサの数値が、THRESHOLD-7より低いとき						
			tacho = 0;				//tacho(turn_left1し続けた時の、タイヤの回転角の合計)を0にする。
 			turn_left(speed1, speed2);			//右モータをspeed1、左モータをspeed2(speed1より少し弱い)にして、左旋回
 	
 		} else if (SENSOR_2 < THRESHOLD +7){	//光センサの数値が、THRESHOLD+7より低いとき
 			tacho = 0;					//tachoを0にする
 			go_forward(speed3);				//左右のモータをspeed3にして、直進
 
 		} else if (SENSOR_2 < THRESHOLD +15){	//光センサの数値が、THRESHOLD+15より低いとき
 			tacho = 0;					/*tachoを0にする*/
 			turn_right(speed1, speed2);			/*右モータをspeed2、左モータをspeed1にして、右旋回*/
  		
 		} else {					/*光センサの数値が、THRESHOLD+15より高いとき*/
 			tacho = 0;					/*tachoを0にする*/
 			turn_right(speed1, speed1);			/*左右のモータをspeed1で右旋回(その場で右回転)*/
 			
 		}		
 		Wait(STEP);					//STEP(0.001)秒だけ動く
 		if (SENSOR_2 >= THRESHOLD-15) {		/*光センサの数値が、THRESHOLD-15より高いとき (=その場で左回転していないとき) */
 			ResetTachoCount(OUT_B);			/*モータの回転数をリセット(その場で左回転したとき以外はリセット)*/
 		} 
 		tacho += MotorTachoCount(OUT_B);		/*tachoに、モータの回転角を代入(「その場で左回転した時」の回転角しか代入されない)*/
 	}
	Off(OUT_BC); Wait(STEP); 
	PlaySound(SOUND_CLICK);	
 }	  
 
 task main() {
	long t;
	Wait(30000);  //30秒待機
	Dist(48, 1);  //48cm前進
	turnAng(91, -1);  //90度左旋回
	SetSensorLowspeed(S1);  //超音波センサ起動
	int ball = 0;  //変数「ball」...超音波センサの値 < 30 を示した回数を示す
	while (1) { //ボールが通過する様子を調べる
		if (SensorUS(S1) < 30) {  /*センサ値 < 30(ボールがセンサの前を通り過ぎたとき、センサ値が20程度を示すため)*/
			ball++;
		}
		if (ball == STOP) {  //通過した回数がSTOP(=3)になったら
			break;  //ループを抜け出す
		}
		Wait(STEP);  //STEP(0.001)秒間
	}
	Wait(800);  //0.8秒間待機
	PlaySound(SOUND_CLICK);  //次の動作に入ることを知らせる
	t = CurrentTick();
	while (CurrentTick() - t < 2000) {  //2秒の間繰り返す
		if (SensorUS(S1) < 30) {  //センサ値 < 30のとき
			ball++;  //ball + 1 ..つまりball = STOP + 1
			break;  //ループを抜け出す
		}
		Wait(STEP);
	}
	
	if (ball == STOP + 1) {  //超音波センサ < 30を示すまで前進
		OnFwd(OUT_BC, SPEED_SLOW);  //SPEED_SLOW(=30)のパワーで前進
		while (ball < STOP + 2) {
			if (SensorUS(S1) < 30) {
				ball++;
			}
		}
		Off(OUT_BC);  //0.001秒停止
		Wait(1);
		Dist(35, 1);  //35cm前進
		hand(70, -1);  //ボールをつかむ
		turnAng(30, -1);  //30度右旋回(ライントレースの黒線に入るため)
		Dist(8, 1);  //8cm前進(ライントレースの黒線に入るため)
		trace(20000, 15, 40);  /*「20秒以内 && TachoCount < 15」の間ライントレース*/
		trace(7000, 1000, 50);  /*「7秒以内 && TachoCount < 1000」の間ライントレース*/
		trace(15000, 10, 40);  /*「15秒以内 && TachoCount < 10」の間ライントレース*/
		turnAng(75, 1);  //75度右旋回
		Dist(15,1);  //15cm前進
		turnAng(20, 1);  //20度右旋回
		SetSensorLight(S2);  //光センサー起動
		OnFwd(OUT_BC, SPEED);  //黒線までSPEED(=50)のパワーで前進
		while (SENSOR_2 > THRESHOLD - 15) {}
		Off(OUT_BC);  //停止
		hand(70, 1);  //ボールを離す
	}
	else {
		turnAng(90, -1);  //90度左旋回
		Dist(40, 1);  //40cm進む
		turnAng(90, 1);  //90度右旋回
		Off(OUT_BC); Wait(STEP);  //0.001秒間停止
 		while (1) {
 			int d = searchDirection(60);  //60度の範囲でボールを探す
			if (d < 30) {  /*searchDirection(60)の返り値 < 30のとき(探した範囲にボールがあったとき)*/
				Dist(20, 1);  //20cm進む
				hand(70, -1);  //ボールをつかむ
				break;  //ループから抜け出す
			}
			else {				
				OnFwd(OUT_BC, SPEED);  //0.5秒進む
				Wait(500);
				searchDirection(0);  /*searchDirectionを2連続で使うとバグるためseachDirection(0)をはさむ*/
			}
		}
		trace(10000, 10000, 45); //どこかのラインにのる,ロボットの向きをゴール方向に向ける
		Dist(40, 1); //40cm進む、
		SetSensorLight(S2);  //光センサー起動
		OnFwd(OUT_BC, SPEED); //SPEED(=50)のパワーで、黒線に到達するまで直進
		while (SENSOR_2 > THRESHOLD - 15) {}
		trace(3000, 10000, 40); //「3秒以内 && TachoCount < 10000」の間ライントレース
		hand(70, 1);  //ボールを離す
	}
 
 				
 }
* 感想 [#g2eafa7d]
** 結果 [#y10d6b87]
1つのボールについてはうまくゴールまで運べたが、時間がなく2つ目のボールまで手が回らなかった。
** 反省 [#v4f86b8b]
ロボットの組み立てが中心だったため、プログラムの部分を他人任せにしてしまった。~
また、リハーサルではうまくいったのに本番は失敗してしまったなど、精度に課題が残った。
** 感想 [#u0e2d378]
ロボットやプログラムといった今まで関わりのなかった分野に触れることができた。これからに生かしていきたいと思う。

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