[[2011a]]

#contents

*課題の内容 [#waad21b2]

周回コース(黒い線)を動くロボットを作成する。

*メンバー [#y40385d4]
-taka

-Chris (クリス)
*ロボットの組み立て [#j3e30aa6]
**方針 [#cda6272a]

黒をたどるプログラムを使用しロボットを作る。

**ロボットのデザイン [#b298589d]
***全体 [#v78ff0fb]

#ref(body.jpg)
後ろにタイヤを付けたら、曲がるとき、必ず元の位置から外れてしまう。そのため、センサーを曲がる動作の中心にするため、キャタピラを使用した。
***光センサー [#te7713b5]

#ref(sensor_track.JPG)
光センサーを左右に並べたら、線を非常に太くする以外に、黒をたどるプログラムが使用出来なかった。そのため、上の写真のように互いの裏を合わせた。
***ボディー [#r2789665]

#ref(compact.JPG)
今回は、ロボットを小さく作るために努力した。結局キャタピラを付けたので、多少大きくなってしまったのは仕方がないことだが、このデザインは誇りだ。

**コース [#s7577536]

#ref(course.JPG)

#ref(course_write.JPG)

**コード [#c418ae97]
***taka(近道使わない) [#m6079769]
 
 #define THRESHOLD1 40
 #define THRESHOLD3 50
 
 int move_time ; // 変数(move_time)を定義  
 
 sub std_move() //基準の動き
 {
 	OnFwd(OUT_A+OUT_C) ;
 	ClearTimer(0); // Timer(0) をリセット
 	while ( Timer(0) <= move_time ) {
 	if (SENSOR_3 > THRESHOLD3) //右センサーが白のとき黒まで右に旋回
 	{
 		OnFwd(OUT_C);	
 		until(SENSOR_3 < THRESHOLD3);
 		OnFwd(OUT_A);
 	} 
 	else if (SENSOR_1 > THRESHOLD1) //左センサーが白のとき黒まで左に旋回
 	{
 		OnRev(OUT_C);
 		until(SENSOR_1 < THRESHOLD1);
 		OnFwd(OUT_C);
 	}
     }
 }
 
 sub right_pref() //右優先
 {
 	OnFwd(OUT_A+OUT_C) ;
 	ClearTimer(0); // Timer(0) をリセット
 	while ( Timer(0) <= move_time ) {
 	if (SENSOR_3 < THRESHOLD3) { //右センサーが黒のとき右に旋回
 	OnFwd(OUT_A);
 	} else { //右センサーが白のとき左に旋回
 	OnFwd(OUT_C);
         }
     }
 }
 
 sub left_pref() //左優先
 {
 	OnFwd(OUT_A+OUT_C) ;
 	ClearTimer(0); // Timer(0) をリセット
 	while ( Timer(0) <= move_time ) {
 	if (SENSOR_1 < THRESHOLD1) { //左センサーが黒のとき左に旋回
 	OnFwd(OUT_C);
 	} else { //左センサーが白のとき右に旋回
 	OnFwd(OUT_C);
 	OnRev(OUT_A);
         }
     }
 }
 
 void rotary() //ロータリーの動き
 {
 	OnFwd(OUT_A+OUT_C);
 	until((SENSOR_1 > THRESHOLD1) && (SENSOR_3 > THRESHOLD3)); //白まで進む
 	
 	OnFwd(OUT_A);
 	OnRev(OUT_C);
 	until(SENSOR_1 < THRESHOLD1); //左センサーが黒まで右に旋回
 	
 	move_time = 40 ;    // (move_time)に「40」を代入
 	ClearTimer(0);                    // Timer(0) をリセット
 	while(Timer(0) <= move_time )
 	{
 		left_pref();
 	} //左優先
 	
 	OnFwd(OUT_C);
 	OnRev(OUT_A);
 	until(SENSOR_3 > THRESHOLD3); //右センサーが白まで右に旋回
 
 	OnFwd(OUT_A);
 	OnRev(OUT_C);
 	until(SENSOR_3 < THRESHOLD3); //右センサーが黒まで左に旋回
 }
 
 task main()
 {
 	SetSensor(SENSOR_1,SENSOR_LIGHT);
 	SetSensor(SENSOR_3,SENSOR_LIGHT);
 	SetPower(OUT_A+OUT_C,4);
 	
 
 	OnFwd(OUT_A+OUT_C);
 	until((SENSOR_1 < THRESHOLD1) && (SENSOR_3 < THRESHOLD3)); //黒まで進む
 
 	move_time = 140 ;    // (move_time)に「140」を代入
 	ClearTimer(0);
 	while(Timer(0) < move_time )
 	{
 		std_move(); //基準の動き
 	}
 
 	rotary(); //ロータリー直進
 
 	move_time = 50 ;    // (move_time)に「50」を代入
 	ClearTimer(0);                    // Timer(0) をリセット
 	while(Timer(0) <= move_time )
 	{
 		right_pref();
 	} //右優先
 
 	move_time = 30 ;    // (move_time)に「30」を代入
 	ClearTimer(0);                    // Timer(0) をリセット
 	while(Timer(0) <= move_time )
 	{
 		left_pref();
 	} //左優先
 
 	move_time = 20 ;    // (move_time)に「20」を代入
 	ClearTimer(0);                    // Timer(0) をリセット
 	while(Timer(0) <= move_time )
 	{
 		right_pref();
 	} //右優先
 
 	OnFwd(OUT_A);
 	OnRev(OUT_C);
 	until((SENSOR_1 < THRESHOLD1) && (SENSOR_3 < THRESHOLD3)); //黒まで左に旋回
 
 	move_time = 50 ;    // (move_time)に「50」を代入
 	ClearTimer(0);
 	while(Timer(0) < move_time )
 	{
 		std_move(); //基準の動き
 	}
 
 	rotary(); //ロータリー直進
 
 	move_time = 20 ;    // (move_time)に「20」を代入
 	ClearTimer(0);                    // Timer(0) をリセット
 	while(Timer(0) <= move_time )
 	{
 		right_pref();
 	} //右優先
 
 	OnFwd(OUT_A);
 	OnRev(OUT_C);
 	until((SENSOR_1 < THRESHOLD1) && (SENSOR_3 < THRESHOLD3)); //黒まで左に旋回
 
 	move_time = 150 ;    // (move_time)に「150」を代入
 	ClearTimer(0);
 	while(Timer(0) < move_time )
 	{
 		std_move(); //基準の動き
 	}
 
 	Off(OUT_A+OUT_C);
 }
***クリス(近道使う) [#f54750c7]
 
 //一つ一つの光センサーの敷居の値
 #define THRESHOLD1 40
 #define THRESHOLD3 50
 
 //コースをうまくたどるための時間
 #define FIRST_LEG 45
 #define SECOND_LEG 55
 #define RUN_TIME1 40
 #define RUN_TIME2 35
 #define RUN_TIME3 13
 
 //長く曲がることを数えるための値
 int long_turn = 0;
 int turn_time1 = 0;
 int turn_time2 = 0;
 int turn_time3 = 0;
 int turn_time_total = 0;
 
 //音楽用の値
 #define a 440
 #define A 880
 #define b 466
 #define B 932
 #define c 262
 #define C 523
 #define d 294
 #define D 587
 #define e 330
 #define E 659
 #define f 349
 #define F 698
 #define g 392
 #define G 784
 
 //コースをうまくたどったら、最後の成功のテーマを流す
 sub ffwin()
 {
 	PlayTone(A,15); Wait(25);
 	PlayTone(A,15); Wait(25);
 	PlayTone(A,15); Wait(25);
 	PlayTone(A,30); Wait(40);
 	PlayTone(f,30); Wait(40);
 	PlayTone(G,30); Wait(40);
 	PlayTone(A,15); Wait(30);
 	PlayTone(G,15); Wait(25);
 	PlayTone(A,30); Wait(30);
 }
 
 //コースをたどりながら、BGMを流す
 task shiptheme()
 {
 	while(true)
 	{
 		PlayTone(C,60); Wait(70);
 		PlayTone(D,30); Wait(40);
 		PlayTone(E,30); Wait(40);
 		PlayTone(1000,60); Wait(70);
 		PlayTone(A,60); Wait(70);
 		PlayTone(C,30); Wait(40);
 		PlayTone(D,30); Wait(40);
 		PlayTone(E,30); Wait(40);
 		PlayTone(G,30); Wait(40);
 		PlayTone(F,30); Wait(40);
 		PlayTone(C,30); Wait(40);
 		PlayTone(D,30); Wait(40);
 	}
 }
 
 //基準の動き方
 sub std_move()
 {
 	OnFwd(OUT_A+OUT_C);
 	ClearTimer(1); //曲がる時間を計るため
 	if (SENSOR_3 > THRESHOLD3) //右のセンサーが白を見たら、左に曲がる
 	{
 		OnRev(OUT_A);
 		until(SENSOR_3 < THRESHOLD3);
 		OnFwd(OUT_A);
 	} 
 	else if (SENSOR_1 > THRESHOLD1) //左のセンサーが白を見たら、右に曲がる
 	{
 		OnRev(OUT_C);
 		until(SENSOR_1 < THRESHOLD1);
 		OnFwd(OUT_C);
 	}
 	if(Timer(1) > 5) //曲がる時間が十分長かったら、長く曲がるカウントに1を足す
 	{
 		long_turn++;
 	}
 }
 
 //右の光センサーを使い、線の右側をたどる、右を優先する関数
 sub right_pref()
 {
 	OnFwd(OUT_A+OUT_C);
    	ClearTimer(1);
 
 	//前回と前々回の曲がる時間を保存する
    	turn_time3 = turn_time2;
  	turn_time2 = turn_time1;
 
  	if(SENSOR_3 > THRESHOLD3) //センサーが白を見たら、黒まで曲がる
 	{
    		OnRev(OUT_A);
    		until(SENSOR_3 < THRESHOLD3);
    		OnFwd(OUT_A);
    		Wait(1);
    		turn_time1 = -Timer(1); //左に曲がったら、値をマイナスにする
 	}
 	else //センサーが黒を見たら、白まで曲がる
 	{
    		OnRev(OUT_C);
    		until(SENSOR_3 > THRESHOLD3);
    		OnFwd(OUT_C);
    		Wait(1);
 	   	turn_time1 = Timer(1); //右に曲がったら、値をプラスにする
 	}
 	
 	turn_time_total = turn_time1 + turn_time2 + turn_time3; //今回+前回+前々回を合計するとどんな風に曲がっているかわかる
   
 	if(turn_time_total > 6) //曲がる時間が十分長かったら、長く曲がるカウントに1を足す
 	{
 		long_turn++;
 		turn_time_total = 0;
 		turn_time1 = 0;
 		turn_time2 = 0;
 	}
 }
 
 //左の光センサーを使い、線の左側をたどる、左を優先する関数
 sub left_pref()
 {
 	OnFwd(OUT_A+OUT_C);
 	ClearTimer(1);
 
 	//前回と前々回の曲がる時間を保存する
 	turn_time3 = turn_time2;
 	turn_time2 = turn_time1;
 
 	if(SENSOR_1 > THRESHOLD1) //センサーが白を見たら、黒まで曲がる
 	{
 		OnRev(OUT_C);
 		until(SENSOR_1 < THRESHOLD1);
 		OnFwd(OUT_C);
 		Wait(1);
 		turn_time1 = -Timer(1); //右に曲がったら、値をマイナスにする
 	}
 	else //センサーが黒を見たら、白まで曲がる
 	{
 		OnRev(OUT_A);
 		until(SENSOR_1 > THRESHOLD1);
 		OnFwd(OUT_A);
 		Wait(1);
 		turn_time1 = Timer(1); //左に曲がったら、値をプラスにする
 	}
 	
 	turn_time_total = turn_time1 + turn_time2 + turn_time3; //今回+前回+前々回を合計するとどんな風に曲がっているかわかる
 
 	if(turn_time_total > 6) //曲がる時間が十分長かったら、長く曲がるカウントに1を足す
 	{
 		long_turn++;
 		turn_time_total = 0;
 		turn_time1 = 0;
 		turn_time2 = 0;
 	}
 }
 
 task main()
 {
 	SetSensor(SENSOR_1,SENSOR_LIGHT);
 	SetSensor(SENSOR_3,SENSOR_LIGHT);
 	SetPower(OUT_A+OUT_C,4); //電池は強すぎたから、パワーを減らさないとすぐコースからずれてしまう
 	start shiptheme; //BGMを流す
 	
 	//だいたい同じスタートから始めるため、両方の光センサーが黒を見るまで進む。
 	OnFwd(OUT_A+OUT_C);
 	until((SENSOR_1 < THRESHOLD1) && (SENSOR_3 < THRESHOLD3));
 	
 	ClearTimer(0);
 	while(Timer(0)< FIRST_LEG)
 	{
 		//std_moveで測った長く曲がるカウントを使い、コースの初めの部分を通るまで進む
 	 	if(long_turn < 3)
 		{
 			ClearTimer(0);
 		}
 		std_move();
 	}
 
 	//ロータリーまで続く
 	OnFwd(OUT_A+OUT_C);
 	until((SENSOR_1 > THRESHOLD1) && (SENSOR_3 > THRESHOLD3));
 	
 	//左優先の関数がうまくいくために地位を変える
 	OnRev(OUT_C);
 	until(SENSOR_1 < THRESHOLD1);
 	
 	ClearTimer(0);                    // Timer(0) をリセット
 
 	//ロータリの一番目の交差点を通るまでロータリーの内側をたどる
 	while(Timer(0) <= RUN_TIME1)
 	{
 		left_pref();
 	}
 	
 	//右優先の関数がうまくいくために地位を変える
 	OnRev(OUT_A);
 	until(SENSOR_3 < THRESHOLD3);
 
 	ClearTimer(0); // Timer(0) をリセットする
 	long_turn = 0; //長く曲がることのカウントをリセットする
 
 	//右優先を使い、ロータリーの次の交差点を曲がる
 	while(Timer(0) <= RUN_TIME2)
 	{
 		if(long_turn == 0)
 		{
 			ClearTimer(0);
 		}
 		right_pref();
 	}
 
 	//近道を飛ばす
 	OnRev(OUT_C);
 	OnFwd(OUT_A);
 	Wait(120);
 	OnFwd(OUT_A+OUT_C);
 	until((SENSOR_1 < THRESHOLD1) || (SENSOR_3 < THRESHOLD3));
 	OnRev(OUT_C);
 	Wait(70);
 	OnFwd(OUT_A+OUT_C);
 	until((SENSOR_1 < THRESHOLD1) && (SENSOR_3 < THRESHOLD3));
 	OnFwd(OUT_A+OUT_C);
 	until(SENSOR_1 > THRESHOLD1);
 	OnRev(OUT_C);
 	until((SENSOR_1 < THRESHOLD1) && (SENSOR_3 < THRESHOLD3));
 	
 	ClearTimer(0);
 
 	//ロータリーに戻る
 	while(Timer(0) < RUN_TIME3)
 	{
 		std_move();
 	}
 	
 	//ロータリーまで続く
 	OnFwd(OUT_A+OUT_C);
 	until((SENSOR_1 > THRESHOLD1) && (SENSOR_3 > THRESHOLD3));
 
 	//左優先の関数がうまくいくために地位を変える
 	OnRev(OUT_C);
 	until(SENSOR_1 < THRESHOLD1);
 
 	ClearTimer(0);                    // Timer(0) をリセット
 
 	//ロータリの一番目の交差点を通るまでロータリーの内側をたどる
 	while(Timer(0) <= RUN_TIME1)
 	{
 		left_pref();
 	}
 	
 	OnRev(OUT_A);Wait(10);
 	
 	//右優先の関数がうまくいくために地位を変える
 	OnFwd(OUT_A);
 	until(SENSOR_3 < THRESHOLD3);
 
 	ClearTimer(0);                    // Timer(0) をリセット
 
 	//右優先を使い、ロータリーの次の交差点を曲がる
 	while(Timer(0) <= RUN_TIME1)
 	{
 		right_pref();
 	}
 
 	//基準の動き方の関数がうまくいくために地位を変える
 	OnRev(OUT_A);
 	until((SENSOR_1 < THRESHOLD1) && (SENSOR_3 < THRESHOLD3));
 	
 	long_turn = 0; //長く曲がることのカウントをリセットする
 
 	//コースの最後まで続く
 	while(long_turn == 0)
 	{
 		std_move();
 	}
 
 	stop shiptheme; //BGMを止める
 	Off(OUT_A+OUT_C); //ロボットを止める
 	ffwin(); //成功!
 	
 }

*重要な点 [#yfc882c6]

-ちゃんとタイミングよくできるように、タイマーと長く曲がる場合の数の組み合わせを使用した。


-ロータリーを通るために、右のセンサーの値しか使わないコードと左のセンサーの値しか使わないコードを作った。


-キットの説明書のキャタピラのデザインを使わないで、もうちょっとスムーズに動けるデザインを使った。

*苦労した点 [#a494866f]

-最初に、ロボットがうまく動作せず、一つのセンサーが壊れているかと思った。しかし、RCXの表示を見たら、一つ一つのセンサーの測った値に誤差があることが分かってきた。コード通り、違う敷居を使わなければならなかった。


-コースを完璧にたどるようにプログラムを作ったが、実際はロータリーの部分で違う進み方をしてしまった。


-締め切りの前の日、まだ完成していなく、RCXをちょっとだけ(約4センチ)落としてしまったら、ファームウェアがリセットしてしまった。


-成功率は電池の電力に密に関係していた。もう切れてしまった電池から新しいものに変えたら、ロボットが早く動きすぎて、うまくいかなかった。この問題に対して、SetPower()という機能を使った。

*感想 [#uf60a5e8]

**taka [#ja41c9a2]
今回の課題も、多くの時間をかけて作業を行ったが、非常に難しく大変だった。

**クリス [#n83b12a2]
今回こそ、デザインには満足し、コードには満足し、実際にはちょっとがっかりした。

*コメント [#if20a57a]
- ある程度の距離を正確に移動させるためには、時間の指定だけでは難しいです。タイマとセンサを組み合わせて確実に制御しましょう。 -- [[松本]] &new{2011-06-30 (木) 16:12:22};

#comment

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