ロボコンに向けた準備を進めていく中で以前よりも精度の高いロボット、プログラムができたので新しいロボットについてレポートします。
コースはAからB
モーターの役割はそれぞれ
三輪車タイプの本体に光センサーを前方に取り付け、上部には写真のようにボールを挟むためのアームを取り付けている。
ボールをつかむ動作はイメージとしてはアトラスオオカブトの角を上下逆さにしたようなものである。
下の2本の角で一時的にボールを確保し、その後時間で制御される上の角を降ろしてボールを挟み込む。
つかんだ状態
下の角
NXTはもともと大きく重いためあまり凝ったロボットを作るとライントレースという細かい動作の連続には不向きになるのでシンプルで小さいロボットの製作を試みた。
最初はクワガタのような動作でボールをつかむ予定だったが、角が前方に飛び出しすぎてしまうためトレース中にボールを弾き飛ばしてしまったので、前方下にある角を極力小さくできる構造をとった。
#define THRESHOLD 50 #define SPEED_H 40 #define SPEED_L 25 #define turn_left_0 OnFwd(OUT_B,SPEED_H);Off(OUT_C); //左転回 大 #define turn_left_1 OnFwd(OUT_B,SPEED_L);Off(OUT_C); //左転回 小 #define turn_right_0 OnFwd(OUT_C,SPEED_H);Off(OUT_B); //右転回 大 #define turn_right_1 OnFwd(OUT_C,SPEED_L);Off(OUT_B); //右転回 小 #define go_forward OnFwd(OUT_BC,SPEED_L); //前進 #define STEP 1 //一回の判定で進む時間 #define nMax 180 //交差点認識に必要な数 #define short_break Off(OUT_BC);Wait(2000); #define turn_straight OnRev(OUT_B,SPEED_H);Wait(nMax*STEP);Off(OUT_BC);OnFwd(OUT_BC,30);Wait(200);Off(OUT_BC); //交差点で方向転換し渡る #define catch_boal Off(OUT_BC);OnFwd(OUT_A,30);Wait(800);Off(OUT_A); //ボールをつかむ #define catch_bboal OnFwd(OUT_A,-30);Wait(1000);Off(OUT_A); //ボールをはなす sub line_trace() //P三叉路を通過するまでトレースしボールをつかむ { SetSensorLight(S1); SetSensorTouch(S2); int nOnline=0; long t0 = CurrentTick(); while(CurrentTick()-t0<14000) //14秒間続ける { while(nOnline < nMax) //交差点を認識するまで続ける { if(CurrentTick()-t0==13000) { catch_boal; //スタートして13秒後にボールを掴む。 } if (SENSOR_1<THRESHOLD-14) //線上 中央 { turn_left_0; nOnline++; //線上にいたのでカウンタを増やす } else { if (SENSOR_1<THRESHOLD-10) //線上 端 { turn_left_1; nOnline++; //線上にいたのでカウンタを増やす } else if (SENSOR_1<THRESHOLD-5) //境界線付近 { turn_left_1; nOnline=0; } else if (SENSOR_1<THRESHOLD+3) //境界線付近 { go_forward; nOnline=0; } else if (SENSOR_1<THRESHOLD+7) //ほぼ線上ではない { turn_right_1; nOnline=0; } else //線上ではない { turn_right_0; nOnline=0; } } Wait(STEP); } short_break; //交差点で2秒止まる turn_straight; //交差点と判定したので方向変換して交差点を渡る nOnline=0; //カウンターをリセット } } sub line_trace2() //P三叉路からQ交差点までトレース(急カーブ) { SetSensorLight(S1); SetSensorTouch(S2); int nOnline=0; long t0 = CurrentTick(); while(CurrentTick()-t0<9000) //9秒間続ける { if (SENSOR_1<THRESHOLD-14) { turn_left_1; nOnline++; } else { if (SENSOR_1<THRESHOLD-7) { turn_left_1; nOnline++; } else if (SENSOR_1<THRESHOLD-3) { turn_left_1; nOnline=0; } else if (SENSOR_1<THRESHOLD+7) { go_forward; nOnline=0; } else if (SENSOR_1<THRESHOLD+15) { turn_right_1; nOnline=0; } else { turn_right_1; nOnline=0; } } Wait(STEP); } } sub line_trace3() //Bゴールまでトレース、ゴールの三叉路を直進する { SetSensorLight(S1); SetSensorTouch(S2); int nOnline=0; long t0 = CurrentTick(); while(CurrentTick()-t0<6000) //6秒間続ける { while(nOnline < nMax) { if (SENSOR_1<THRESHOLD-14) { turn_left_0; nOnline++; } else { if (SENSOR_1<THRESHOLD-10) { turn_left_1; nOnline++; } else if (SENSOR_1<THRESHOLD-7) { turn_left_1; nOnline=0; } else if (SENSOR_1<THRESHOLD+3) { go_forward; nOnline=0; } else if (SENSOR_1<THRESHOLD+7) { turn_right_1; nOnline=0; } else { turn_right_0; nOnline=0; } } Wait(STEP); } short_break; turn_straight; nOnline=0; } } task main() { line_trace(); line_trace2(); line_trace3(); }
ボールをつかむのをタッチセンサーから時間に変えたため無駄なプログラムが残っているが完成した時のままにしてある。
線の左側をトレースしていくプログラム。
コースを時間で3つのブロックに分けた。
スタートして
A→Bコースは最後に右に直角に曲がるところがあり、そこを交差点判定しなくても済むよう線の左側をトレースすることにした。
線上だったときカウンターを増やし交差点を判定するのだが、交差点の認識が甘かったので線の中央、端にわけた。
急カーブをトレースするときは交差点判定しないようにし、線を飛び出さないように少しだけ速度を抑えた。
ボールをシュートすることはできなかったがAからBまでトレースすることはできた。
交差点を認識させようとすると急カーブも交差点として認識してしまった。タイマーをつけ、ある程度時間で制御するのと急カーブでは速度を落とすことで改善した。また、線の左側をトレースすることで右に直角に曲がるところを外側から回りこむようになるので交差点と錯覚させないことに成功した。
当初はタッチセンサーでアームを降ろすタイミングを決めていたがボールを押さえていないとセンサーが反応しないので時間でタイミングを決めることにした。超音波センサーを使えばうまくできるはず。
線の濃さにそれぞれの場所によってむらがあったので苦労した。コースを3つのブロックに分けたのでそれぞれのブロックによって線上かどうか判断する値を少し変えた。
プログラムを順序立てて書いていくことの大切さがわっかた。プログラムの上と下の兼ね合いを考えて条件式など考えていくことは難しかったが頭を使ったのでとても楽しかった。
小さい頃、今回のロボットと同じような黒い線をトレースするおもちゃを動物園のお土産コーナーで買い、遊んだことがあったのだが、そのおもちゃの仕組みを理解することができたうえにプログラムがどのようになっているか想像することができるようになった。