2011a

課題の内容

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

メンバー

  • taka
  • Chris (クリス)

ロボットの組み立て

方針

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

ロボットのデザイン

全体

body.jpg

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

光センサー

sensor_track.JPG

光センサーを左右に並べたら、線を非常に太くする以外に、黒をたどるプログラムが使用出来なかった。そのため、上の写真のように互いの裏を合わせた。

ボディー

compact.JPG

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

コース

course.JPG
course_write.JPG

コード

taka(近道使わない)

#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);
}

クリス(近道使う)

//一つ一つの光センサーの敷居の値
#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(); //成功!
	
}

重要な点

  • ちゃんとタイミングよくできるように、タイマーと長く曲がる場合の数の組み合わせを使用した。
  • ロータリーを通るために、右のセンサーの値しか使わないコードと左のセンサーの値しか使わないコードを作った。
  • キットの説明書のキャタピラのデザインを使わないで、もうちょっとスムーズに動けるデザインを使った。

苦労した点

  • 最初に、ロボットがうまく動作せず、一つのセンサーが壊れているかと思った。しかし、RCXの表示を見たら、一つ一つのセンサーの測った値に誤差があることが分かってきた。コード通り、違う敷居を使わなければならなかった。
  • コースを完璧にたどるようにプログラムを作ったが、実際はロータリーの部分で違う進み方をしてしまった。
  • 締め切りの前の日、まだ完成していなく、RCXをちょっとだけ(約4センチ)落としてしまったら、ファームウェアがリセットしてしまった。
  • 成功率は電池の電力に密に関係していた。もう切れてしまった電池から新しいものに変えたら、ロボットが早く動きすぎて、うまくいかなかった。この問題に対して、SetPower()という機能を使った。

感想

taka

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

クリス

今回こそ、デザインには満足し、コードには満足し、実際にはちょっとがっかりした。

コメント

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


添付ファイル: filecourse_write.JPG 198件 [詳細] filesensor_track.JPG 214件 [詳細] filecourse.JPG 168件 [詳細] filecompact.JPG 169件 [詳細] filebody.jpg 186件 [詳細]

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