目次
今回、私が担当したのはコースBである。下の写真はロボットの全体像である。
今回の課題のコースは、急なカーブがあったりたくさんの交差点があったりと、一つの光センサーで乗り越えるには厳しいコースだった。そのため、精密なプログラムを組む必要があった。しかしながら、いくらプログラムが良くても電池の減り具合などの要因で正しくプログラムを実行できないという可能性があった。よって、ロボットはタイヤを前方の2つのみとし、後方は下が丸い部品で滑りをよくし、小回りが利くようにした。また、光センサーはタイヤの近くに設置し、急激なセンサー値の変化によるエラーを防いだ。
今回私のペアは、リング状の部品(バー)を作成し、そこにボールを閉じ込めることにした。
バーは台車の乗せたモーターを動力として上下に動く。ボールはピンポン玉であるためバーは低い位置に、地面と平行になるのが望ましいと考えている。しかしながら、台車の構造の都合でモーターは低い位置に設置するのは困難であった。そこで上の写真でもわかるように、モーターが動力を伝える軸から下方にさらに軸を伸ばした。こうすることで、バーが低い位置で地面に平行になるようにし、正常に上下できるようにした。
また、上の写真を見てもわかるように台車に直接設置してある平な部品(スカート)がある。仮にこの部品が無いと、光センサーが出っ張った構造となってしまう。そうなると、最後にボールをシュートするときにボールが横に逃げてしまう。そこでそれを防ぐためにこの部品を設置した。幅はバーとの間に隙間がなくなるようにし、両側にブロックを取り付けることでさらに正確性を向上させた。
台車は、正確な動作を実現するために少ない部品で構成している。そのため、制御装置も台車を補強する役割がある。今まで載せてきた写真を見てもわかるように、前方ぎりぎりに設置してある。これを一つでも後方に移すと後方にかかる重さが大きくなり、後方の滑りが悪くなってしまう。そうなれば、正しくプログラムを実行することができなくなってしまう。
プログラムはB→P、P→Q、Q→ボールキャッチ、ボールキャッチ→C、C→シュートの5つのプロセスにわけて書いた。そのうち、「P→Q」と「ボールキャッチ→C」は同じサブルーチンで動作する。
//とても明るい(白) #define KYOKAI_1 50 //境界 //明るい(白黒境界よりやや白側) #define KYOKAI_2 46 //境界 //普通(白黒境界) #define KYOKAI_3 42 //境界 //暗い(白黒境界よりやや黒側) #define KYOKAI_4 38 //境界 //とても暗い(黒)
#define TURN_L OnRev(OUT_A);OnFwd(OUT_C); //左回転 #define L OnFwd(OUT_C);Off(OUT_A); //左折 #define R OnFwd(OUT_A);Off(OUT_C); //右折 #define TURN_R OnRev(OUT_C);OnFwd(OUT_A); //右回転
#define CROSS_TIME 32 //交差点と判断する基準となる回転時間 #define CHECK_TIME 25 //十字路かT字路かを判断するために直進するときの直進時間
#define WAIT Off(OUT_ABC);Wait(20); //動作安定のために一時停止するプログラム
#define BER_UP PlayTone(500,30);OnFwd(OUT_B);Wait(30);Off(OUT_B); //バーを上げる(音付き) #define BER_DOWN PlayTone(500,30);OnRev(OUT_B);Wait(30);Off(OUT_B); //バーを下げる(音付き)
#define START_SOUND Wait(100);PlaySound(SOUND_UP);Wait(150); //一番最初に鳴らす音 #define CROSS_SOUND PlaySound(SOUND_DOUBLE_BEEP);Wait(150); //交差点と判断した時に鳴らす音 #define CROSS_FORWARD_SOUND PlayTone(440,100);Wait(150); //十字路と判断した時の音 #define CROSS_T_SOUND PlaySound(SOUND_LOW_BEEP);Wait(150); //T字路と判断した時の音 #define GOAL_SOUND Wait(100);repeat(3){PlayTone(600,50);Wait(100);}PlayTone(900,100);Wait(200); //最後のシュートする前に鳴らす音 #define END_SOUND Wait(100);PlaySound(SOUND_DOWN);Wait(150); //最後に鳴らす音
以下では4つのサブルーチンを紹介する。サブルーチン内で使われているマクロは上に記されている。
sub P1() { ClearTimer(1); //タイマー1をリセット while(FastTimer(1) < CROSS_TIME) //ラインの左側を走行するプログラム(交差点と判断するまで左回転をすると次のプログラムに進む) { if(SENSOR_2 > KYOKAI_1) { TURN_R; ClearTimer(1); } else if(SENSOR_2 > KYOKAI_2) { R; ClearTimer(1); } else if(SENSOR_2 > KYOKAI_3) { OnFwd(OUT_AC); ClearTimer(1); } else if(SENSOR_2 > KYOKAI_4) { L; ClearTimer(1); } else { TURN_L; } } Off(OUT_AC); CROSS_SOUND; //停止して交差点と判断した音を鳴らす TURN_R; Wait(70); OnFwd(OUT_AC); Wait(30); Off(OUT_AC); //次のサブルーチンの始点に移動 }
このプログラムは、途中Rを直進するという難所がある。しかし、RはT字路なのでラインの左側を走行することで難所を攻略できた。
sub P2() { TURN_L; Wait(20); WAIT; //次の走行の時に、間違えて交差点と判断しないように光センサーを白のエリアに移す ClearTimer(0); //タイマー0をリセット while(FastTimer(0) < 300) //3秒間、線の左側を走行 { if(SENSOR_2 > KYOKAI_1) { TURN_R; } else if(SENSOR_2 > KYOKAI_2) { R; } else if(SENSOR_2 > KYOKAI_3) { OnFwd(OUT_AC); } else if(SENSOR_2 > KYOKAI_4) { L; } else { TURN_L; } } BER_DOWN; //ボールをキャッチする WAIT; }
このプログラムはサブルーチン「P3」の次に実行されるため、このサブルーチンが始まる時はかなりラインの内側に光センサーがある可能性がある。すると、いきなり交差点と判断してしまうというエラーが起こる可能性が高まる。その対策として、上記のように最初に左回転を実行することにした。また、ボールはライン上にある。そのため、ロボットの構造上、どうしてもラインの右側を走行するとバーがボールに当たり、ボールをキャッチできない。そこでラインの左側を走行させることにした。
sub P3() { ClearTimer(1); while(FastTimer(1) < CROSS_TIME) //ラインの左側を走行するプログラム(交差点と判断するまで左回転をすると次のプログラムに進む) { if(SENSOR_2 > KYOKAI_1) { TURN_R; ClearTimer(1); } else if(SENSOR_2 > KYOKAI_2) { R; ClearTimer(1); } else if(SENSOR_2 > KYOKAI_3) { OnFwd(OUT_AC); ClearTimer(1); } else if(SENSOR_2 > KYOKAI_4) { L; ClearTimer(1); } else { TURN_L; } } Off(OUT_AC); CROSS_SOUND; //交差点と判断し、停止して音を鳴らす TURN_R; Wait(CROSS_TIME); WAIT; //交差点に進入した時の位置に戻る OnFwd(OUT_AC); Wait(CHECK_TIME); Off(OUT_AC); //十字路かT字路かを判断 if(SENSOR_2 < KYOKAI_1) //十字路だった場合は音を鳴らし、タイマー1をリセットして次に進む { CROSS_FORWARD_SOUND; ClearTimer(1); // } else //T字路だった場合は音を鳴らした後、0.5秒間右回転し、タイマー1をリセットして次に進む { CROSS_T_SOUND; TURN_R; Wait(50); WAIT; ClearTimer(1); } }
このプログラムは、十字路なら直進、T字路なら右に曲がるという動作をする。これにより、複雑な「ボールキャッチ→C」のプロセスを単純にwhileで繰り返せるようにした。また、このプロセスの間には半径4cmの急カーブがある。そのため、ラインの右側を走行すると光センサーが黒い部分を通り続け、交差点と判断する可能性が高かった。そこでラインの左側を走行することにした。これは、白い部分は交差点の判断材料にならないからだ。
sub END() { TURN_L; Wait(50); Off(OUT_AC); WAIT; //サブルーチン「P3」終了後、ロボットをゴールの方向に戻すプログラム OnRev(OUT_AC); Wait(100); WAIT; //ボールに勢いをつけるために下がる GOAL_SOUND; //シュートまでのカウントダウン OnFwd(OUT_AC); BER_UP; //前進を開始するのと同時にバーを上げる Wait(180); Off(OUT_AC); //シュート }
このプログラムはサブルーチン「P3」のあとに実行されるため、このサブルーチンが始まる時、ロボットはゴールに対して斜めになっている。だからと言って、最後の直線のために新たにサブルーチンを作るのは効率が悪い。そのため、最初にそれを修正するためのプログラムを書いた。また、シュートの成功率を上げるためにシュート時に進む距離をシュート前に下がる距離より長くし、ロボットをゴールに近い位置で止まるようにした。
task main() { SetSensor(SENSOR_2,SENSOR_LIGHT); //光センサーを定義 int x = 0; //変数xを定義 BER_UP; //バーを持ち上げる START_SOUND; //スタート音を鳴らす P1(); //B→P P3(); //P→Q P2(); //Q→ボールキャッチ while(x < 5) //ボールキャッチ→C(交差点を4回通過、5回目の交差点で次に進む) { P3(); x++; //xを1増加させる } END(); //C→シュート END_SOUND; //終了音を鳴らす }
上記のように、ロボットが走行を始める前にバーを上げるプログラムがある。バーの動く時間は定数で定義してあるが、電池の減り具合によってバーの位置が変わってくる。もしも十分に下がらなければボールをつかめないし、下がりすぎると地面に接触して正確にプログラムを実行できなくなる。そこでプログラム実行ボタンを押す前にあらかじめバーをちょうどよい位置にし、ボタンを押したら初めにバーを上げるという方法をとった。こうすることで、バーを下げるときちょうどよい位置で泊まれるようにした。
今回の課題は、前回の反省を活かし、マクロやサブルーチンを多用し、正確なプログラムの実行のために動作間に一時停止する時間を作った。私は、今回は前回よりも良い出来だと感じている。しかしながら、まだ改良できるのではないかとも感じている。なので、次回の課題は今回の反省を活かしながら進められればよいと思った。