下の図のようなコースを各チームで作成し、「ミッション」を遂行するためのロボットを作成せよ。
次のいずれかのコースで黒い線に沿って動き、途中でボールをゴール付近に立てた350mlの空き缶(黄色で表示)に当てるロボットを製作せよ。 (相棒と違うコースを選ぶこと)
ボールはロボットが弧IHKJ上にある時にQ地点の空き缶に当てる
車体自体は参考書のサンプルを基本とすることで安定した動きができるようにした。ボールを持ち上げない構造にすることで、ボールを持っている時と持っていない時とでの重心やバランスの違いを無くし、プログラムを作りやすくした。また、ボールを囲むアームを少し大きめに作ることで、ボール自体が転がり、ロボットが動いた時に摩擦などによって動きの妨げにならないようにした。光センサーを設計図よりタイヤに近づけるためにできるだけ元の車体バランスを崩さないようにしながらNXTの真下の部品を1段分後ろに下げた。 それによって急なカーブをより良い精度で通過できるようになった。
超音波センサーをアームや光センサーの邪魔にならない程度で、できる限り低く設置することで缶を見つけやすくした。 光センサーをタイヤの近くに設置することで急なカーブの成功率を上げた。 タッチセンサーは、今回の課題においてボールを探すことからまず始まると勘違いしていたので、余分に取り付けてあるように見えるが、ボールを缶に当てる時に、このタッチセンサーにぶつけることでボールのスピードや飛距離がより伸び、成功率が高まったことを考慮し、取り付けたままの状態となっている。
缶の方向を向いた後にアームを上げ、少しスピードをつけて前進することでボールに体当たりをする。ここでタッチセンサーに当てることで、タッチセンサーの物体が当たった時の反発を用いてスピードと飛距離を伸ばした。 ***ほかのグループの方法を見て ボールを車体に乗せて、ボールを保持している位置と地面との高低差を生かして、スロープを用いて転がして缶に当てるという方法は正直想像もしていなかったのでかなり驚き感動した。
#define THRESHOLD 54 [#o897b273]
#define SPEED 30
#define speed 20
#define OnRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL);
#define LEFT OnRL(speed,-speed);
#define left OnRL(speed,0);
#define straight OnRL(SPEED,SPEED);
#define right OnRL(0,speed);
#define RIGHT OnRL(-speed,speed);
#define STEP 1
#define nMAX 300
#define short_break Off(OUT_BC);Wait(1000);
#define CROSS_TIME 700
#define cross_line OnFwd(OUT_BC,speed);Wait(CROSS_TIME);short_break;
#define turn_time 3000
#define turn_left LEFT;Wait(turn_time);short_break;
#define turn_right RIGHT;Wait(turn_time);short_break;
#define kaiten OnRL(SPEED,-SPEED);
#define kaiten_time 5500
#define arm_up OnRev(OUT_A,SPEED);Wait(500);Off(OUT_A);
sub kousaten_trace() {
SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { //黒を認識した回数がnMAX(300)を越えたら交差点判断して横断 if (SENSOR_3 < THRESHOLD-10) { RIGHT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {right;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {left;} else {LEFT;} nOnline=0;} Wait(STEP); } short_break; LEFT; Wait(nMAX*STEP); cross_line; nOnline=0; }
sub kousaten_usetsu(){
SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { //黒を認識した回数がnMAX(300)を越えたら交差点判断して横断 if (SENSOR_3 < THRESHOLD-8) { LEFT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {left;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {right;} else {RIGHT;} nOnline=0;} Wait(STEP); } short_break; RIGHT; Wait(nMAX*STEP); turn_right; nOnline=0; }
sub kousaten_teishi() {
SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { if (SENSOR_3 < THRESHOLD-8) { LEFT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {left;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {right;} else {RIGHT;} nOnline=0;} Wait(STEP); } short_break; nOnline=0; }
sub serch_kan() {
SetSensorLowspeed(S4); long t10,t11; int L=10000; //仮の最小値 t10=CurrentTick(); //回転前の時刻 while(CurrentTick()-t10<=kaiten_time){ OnRL(speed,-speed); if(SensorUS(S4)<L) { L=SensorUS(S4); t11=CurrentTick()-t10; //仮の最小値より近いものを見つけた時の時間 } } OnRL(-speed,speed); Wait(kaiten_time-t11); Off(OUT_BC); }
sub shoot(){
arm_up; OnFwd(OUT_BC,100); Wait(200); Off(OUT_BC); }
※このサブルーチン関数はチームで話し合われた結果、結局使用することはなかったのですが、用いることでより良いプログラムを作成できるのではないかと勝手に制作したものです。単なる自己満であり、今回のプログラムには含まれていません。
sub line_trace_R() {
while (true) { if(SENSOR_3<THRESHOLD-8){RIGHT;} else if(SENSOR_3<THRESHOLD-3){right;} else if(SENSOR_3<THRESHOLD+2){straight;} else if(SENSOR_3<THRESHOLD+6){left;} else{LEFT;} Wait(STEP);
}
sub line_trace_L() {
while (true) { if(SENSOR_3<THRESHOLD-8){LEFT;} else if(SENSOR_3<THRESHOLD-3){left;} else if(SENSOR_3<THRESHOLD+2){straight;} else if(SENSOR_3<THRESHOLD+6){right;} else{RIGHT;} Wait(STEP); }
sub kousaten_trace_R() {
SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { if (SENSOR_3 < THRESHOLD-10) { RIGHT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {right;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {left;} else {LEFT;} nOnline=0;} Wait(STEP); } short_break; LEFT; Wait(nMAX*STEP); cross_line; nOnline=0; }
sub kousaten_trace_L() {
SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { if (SENSOR_3 < THRESHOLD-10) { LEFT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {left;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {right;} else {RIGHT;} nOnline=0;} Wait(STEP); } short_break; RIGHT; Wait(nMAX*STEP); cross_line; nOnline=0; }
sub kousaten_sasetsu_R() {
SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { if (SENSOR_3 < THRESHOLD-8) { RIGHT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {right;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {left;} else {LEFT;} nOnline=0;} Wait(STEP); } short_break; LEFT; Wait(nMAX*STEP); turn_left; nOnline=0; }
sub kousaten_usetsu_L() {
SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { if (SENSOR_3 < THRESHOLD-8) { LEFT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {left;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {right;} else {RIGHT;} nOnline=0;} Wait(STEP); } short_break; RIGHT; Wait(nMAX*STEP); turn_right; nOnline=0; }
task main() {
SetSensorLight(S3); SetSensorLowspeed(S4); long t0,t1,t2,t3; //それぞれの時間を定義 t0=CurrentTick(); //スタートした時間をt0とする while(CurrentTick()-t0<=15000){ //15秒間ライントレースをする if(SENSOR_3<THRESHOLD-8){RIGHT;} else if(SENSOR_3<THRESHOLD-3){right;} else if(SENSOR_3<THRESHOLD+2){straight;} else if(SENSOR_3<THRESHOLD+6){left;} else{LEFT;} Wait(STEP); } kousaten_trace(); //交差点Kを発見したら横断 t1=CurrentTick(); //K地点を横断したらその時間をt1とする while(CurrentTick()-t1<=15000){ //15秒間ライントレースをする if(SENSOR_3<THRESHOLD-8){RIGHT;} else if(SENSOR_3<THRESHOLD-3){right;} else if(SENSOR_3<THRESHOLD+2){straight;} else if(SENSOR_3<THRESHOLD+6){left;} else{LEFT;} Wait(STEP); } serch_kan(); //缶を探す。見つけたらボールに体当たりしてシュートする shoot(); t2=CurrentTick(); while(CurrentTick()-t2<=18000){ if(SENSOR_3<THRESHOLD-8){LEFT;} else if(SENSOR_3<THRESHOLD-3){left;} else if(SENSOR_3<THRESHOLD+2){straight;} else if(SENSOR_3<THRESHOLD+6){right;} else{RIGHT;} Wait(STEP); } kousaten_teishi(); //交差点Gを発見したら一時停止 t3=CurrentTick(); //地点Gを出発する時間をt3とする while(CurrentTick()-t3<=40000){ //40秒間ライントレースをする if(SENSOR_3<THRESHOLD-8){LEFT;} else if(SENSOR_3<THRESHOLD-3){left;} else if(SENSOR_3<THRESHOLD+2){straight;} else if(SENSOR_3<THRESHOLD+6){right;} else{RIGHT;} Wait(STEP); } kousaten_usetsu(); //交差点Eを発見したら右折 kousaten_trace(); //交差点Lを発見したら横断 OnFwd(OUT_BC,SPEED); 前進して枠内に入る Wait(2000); Off(OUT_BC); }
交差点判断をしないライントレースについては白から黒の色の値を白、白よりの灰色、灰色、黒よりの灰色、黒の五段階に分けそれぞれについて順に大きくライン側に旋回、ライン側に曲がる、スピードを出して直進、ラインから離れる方向に曲がる、ライン側から離れるように旋回という風にしてラインのどちらかをジグザグと移動するような形にした。
結局チームで話し合った結果、ラインの右側をトレースするサブルーチン関数しか用いなかった。個人的には両方用いたプログラムで動かしてみたかったので、プライベートで挑戦してみたい。 基本的にはタイマーで時間を計りながら交差点判断をするかしないかを決めている。そのためこのコースでしか使えないうえに想定した以上にスムーズに進んだり時間がかかったりしてしまうとコースを間違えてしまうためコースを完走しないことが多くなってしまった。 時間ではなく、タイヤの回転角などで距離を測りながら進むと今よりは成功率の高いプログラムになったのではないだろうか。また、task mainの中の時間を計測しながらのライントレースもサブルーチンとして簡略化できたなどの改善点も見つかった。
課題1の時と比べてかなりプログラムも改善されたとは思うが、まだ学んだことを最大限に生かし切れていないので課題3ではより高度なプログラムを作成したいと感じた。また、ジグザグ走行ではなく、よりラインに合わせてスムーズに動くロボットを制作したい気持ちが高まった。