[[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