下の図のようなコースを各チームで作成し、「ミッション」を遂行するためのロボットを作成せよ。
私は一人目のコースを担当した。
1.A地点から出発
2.B
3.C (直進)
4.D (一時停止の後、直進)
5.E, F 通過
6.G (一時停止の後、左折)
7.H (一時停止の後、左折)
8.I (ボールをつかんでUターン)
9.H (直進)
10.J (一時停止)
11.A地点に入る(ゴール)
結論から言うと今回のロボットはこのように機体が大きくなってしまった。
光センサーとタイヤ用の2つのモーターの位置は説明書のものと同じ作りになっている。
斜角で設置した部品もあるため、全体的に固定がしっかりできなかった。
最も苦労したのは超音波センサーの位置だ。ボールを正確に感知するため前方下部に付けたいと考える反面、光センサーも同じ場所にあるため取り付け方に手間取ってしまった。
ボールを持ち上げるような機構は思いつかなかったため、囲って引きずることでゴールまで持って行く手法をとった。
写真の通りボールを取るためのモーターを機体中央に配置したことによって、NXT本体を最上部に設置するしか方法が無かった。
また超音波センサーも前方にあるため、NXT本体とセンサーを避けてボールを捕まえにいくアームは上から覆い被さるような大きめのサイズで作ってある。
#define BLACK 43 #define THRESHOLD 53 #define WHITE_GRAY 58 #define WHITE 63 #define SPEED 30
まずは明るさやスピードの定義をする。行う場所によって挙動が変わりやすいため、黒は少し明るめに、白は少し暗めに設定している。
#define go_forward OnFwdSync(OUT_BC,SPEED,0); #define curve_left Off(OUT_C); OnFwd(OUT_B,SPEED); #define curve_right Off(OUT_B); OnFwd(OUT_C,SPEED); #define turn_left OnFwdSync(OUT_BC,SPEED,-100); #define turn_right OnFwdSync(OUT_BC,SPEED,100); #define few_go(t) OnFwdSync(OUT_BC,SPEED,0); Wait(t); Off(OUT_BC); Wait(1000);
few_goをtの関数にし、交差点を通過するときと、左折する際の光センサーの位置によるラインからのずれを修正するときに使用できるようにしている。
void line_followleft() { SetSensorLight(S3); long t0=CurrentTick(); while(CurrentTick()-t0<150){ if(SENSOR_3<BLACK){ turn_left; //黒より暗ければ左回転 }else{ if(SENSOR_3>WHITE){ turn_right; //白より明るければ右回転 }else if(SENSOR_3>WHITE_GRAY){ curve_right; //白灰より明るければ右折 }else if(SENSOR_3>THRESHOLD-5){ go_forward; //境界線付近の明るさなら直進 }else{ curve_left; //それ以外の明るさ、つまり黒灰なら左折 } t0=CurrentTick(); //黒以外のときリセット } } Off(OUT_BC); Wait(1000); turn_right; //進行方向の調整 Wait(200); Off(OUT_BC); Wait(500); }
最初はラインの左側の境界線をトレースする。
CurrentTick()を使い、黒い部分以外のときはt0をリセットし、黒い部分はリセットしない。こうすることで最後にリセットされたCurrentTick()から一定時間立った場合、つまり黒のときが長く続いた場合にそこを交差点と判断する。
void line_followright() { SetSensorLight(S3); long t0=CurrentTick(); while(CurrentTick()-t0<230){ if(SENSOR_3<BLACK){ turn_right; //黒より暗ければ右回転 }else{ if(SENSOR_3>WHITE){ turn_left; //白より明るければ左回転 }else if(SENSOR_3>WHITE_GRAY){ curve_left; //白灰より明るければ左折 }else if(SENSOR_3>THRESHOLD-5){ go_forward; //境界線付近の明るさなら直進 }else{ curve_right; //それ以外の明るさ、つまり黒灰なら右折 } t0=CurrentTick(); //黒以外のときリセット } } Off(OUT_BC); Wait(1000); turn_left; //進行方向の調整 Wait(200); Off(OUT_BC); Wait(500); }
ボールを取った後は右側の境界線をトレースしてゴールへと向かう。
左境界のときとほとんど同じだが、帰り道は少々急なカーブであるため、交差点と判断するまでの時間を先程よりも少し長くしてある。
#define u_turn OnFwdSync(OUT_BC,SPEED,-100); Wait(700); Off(OUT_BC); #define catch_ball OnFwd(OUT_A,SPEED); Wait(500); Off(OUT_A);
先に動きを定義する。
u_turnの時間が短いのは、ボールを取った直後から右側の境界線のトレースに移行するためである。
このu_turnではせいぜいラインの左側に飛び出すことしかできないが、右境界をトレースするときは白い場所だと左側に回転していくため問題ない。
void fetch_ball() { SetSensorLight(S3); SetSensorLowspeed(S4); while(SensorUS(S4)>8){ //超音波センサーとの距離が8cm以上である限り if(SENSOR_3<BLACK){ turn_left; }else if(SENSOR_3>WHITE){ turn_right; }else if(SENSOR_3>WHITE_GRAY){ curve_right; }else if(SENSOR_3>THRESHOLD-5){ go_forward; }else{ curve_left; //左側のライントレースをする } } Off(OUT_BC); //8cmまで近づけば止まる Wait(500); catch_ball; //ボールを捕らえる few_go(400); u_turn; Wait(1000); }
task main() { line_followleft(); few_go(400); //交差点を越える line_followleft(); few_go(600); //位置の調整のため少し前に出る turn_left; //左折する Wait(1100); line_followleft(); few_go(600); //位置の調整のため少し前に出る turn_left; //左折する Wait(1100); fetch_ball(); line_followright(); few_go(400); //交差点を越える line_followright(); few_go(400); //交差点を越える(ゴールに侵入する) }
すでに上で述べた通り、ボールを取るまではラインの左側を行き、取った後はラインの右側を行く。