下の図のようなコースを各チームで作成し、「ミッション」を遂行するためのロボットを作成せよ。
A地点から出発 → M → K(直進) → L(ピンポン玉をつかむ) → K(右折) → J(一時停止の後、左折) → I(直進) → H(直進) → G(左折) → F → E → D(一時停止の後、直進) → C(直進) → B(一時停止) → シュート→ A地点に入る(ゴール)
※赤丸地点で一時停止
モーターは左側のタイヤをA、右側のタイヤをCに接続しました。アームを稼働させるモーターはBに接続しました。
上図にあるようにロボット本体を四輪のタイヤに対して真ん中に来るように設置しました。 これによって重心の偏りを無くし、タイヤが旋回時に滑らないようにしました。
光センサーを2に接続し、光センサーを地面に近くなるようロボットに設置することによって光センサーの数字が明暗の違いによって大きく変動するようにしました。これによって、動きを細かく分けやすいようにしました。
光センサーが48より大きい値を示すとき(白)で右に曲がる
光センサーが45と49の間の値を示すとき(灰色)で左に曲がる
光センサーが44より小さい値を示すとき(黒)で左に旋回する
このように3つの曲がる動きだけを入力し、大きなカーブを曲がりやすいようにしました。0.3秒以上同じ動きを続けることによって停止のプログラムに移るようにしています。
タイマーリセットのプログラムは黒(光センサーが44以下で左に旋回)の時だけでなく、灰色時(光センサーの値が45以上49以下で左に曲がる)にもあえて置かず、交差点で止まりやすいようにしました。このプログラミングによる直線ライントレースでの停止の誤作動はありませんでした。
黒が連続する時間をもとに交差点の判断を行うようにした。
上の画像は少し大げさに表しているが交差点では黒が連続する時間が通常のライントレースに比べて長い。そのため、通常のライントレースで光センサーが黒の上にいるより長く、光センサーが交差点で黒の上にいる時間より短い時間として0.3秒を設定し、交差点上でロボットが止まるようにした。
アームを前面に設置するとアームやピンポン玉の影が光センサーに干渉する可能性を考えてアームを背面に設置しました。
ピンポン玉をアームでしっかりと掴んで固定するのではなく、ボールの周りをアームで囲うような形にしました。これによってボールを掴むときに多少のズレがあってもボールをアームで確保できるようになります。
↓下図のようにピンポン玉をホールドした際に隙間が大きくできるように作られています。↓
B地点でアームを展開→ロボットをバック→アームを閉じる→アームをpower(s)を使わずに展開→ピンポン玉を下図で示すように弾く
光センサーの数値の定義に関しては状況によってセンサーの反応の具合が異なるため、 プログラムを見てすぐに変えられるよう多くを定義しませんでした。
#define THRESHOLD 42
#define runtime 1450 #define runtime1 50 #define RUN_TIME1 30 #define RUN_TIME_JIH 170 #define RUN_TIME_HGF 380 #define RUN_TIME_FE 180 #define RUN_TIME_DB 1000 #define STEP 1
#define turn90 OnFwd(OUT_A);OnRev(OUT_C);Wait(100);Off(OUT_AC);//90度回転 #define power(s) SetPower(OUT_B,s); //モータのパワーをsにする #define turn_left Off(OUT_A); OnFwd(OUT_C); //左に旋回 #define turn180 OnFwd(OUT_C);OnRev(OUT_A);Wait(190);Off(OUT_AC);//180度左回転 #define turn_right OnFwd(OUT_A);OnRev(OUT_C); //右回転 #define turn_left90 OnRev(OUT_A);OnFwd(OUT_C);Wait(100); //左に90度曲がる #define go_straight OnFwd(OUT_AC); //直進 #define go_back OnRev(OUT_AC); //後退
ライントレースをそれぞれの区間ごとに時間内で繰り返すように設定し、細かく分けてあります。
sub across_turn() { SetSensor(SENSOR_2, SENSOR_LIGHT); ClearTimer(0); while (FastTimer(0) <= runtime) { //14.5秒でAからLまで動き続ける if (SENSOR_2 < THRESHOLD){ // 線上なら turn_left; // 左へ } else { // 線上でなければ turn_right; // 右へ } Wait(STEP); // STEPの値 } }
sub across_turn1() { SetSensor(SENSOR_2, SENSOR_LIGHT); ClearTimer(0); while (FastTimer(0) <= runtime1) { //0.5秒以上続いたら次のプログラムへ if (SENSOR_2 < THRESHOLD){ // 線上なら turn_left; // 左へ } else { // 線上でなければ turn_right; // 右へ } Wait(STEP); // STEPの値 } }
sub line_trace1() { SetSensor(SENSOR_2,SENSOR_LIGHT); ClearTimer(0); while ( FastTimer(0) <= RUN_TIME1 ) { //0.3秒以上続いたら次の動作へ if ( 48 < SENSOR_2 ){ OnFwd(OUT_A); Off(OUT_C);ClearTimer(0); //白なら右へ } else if (45 <SENSOR_2 < 49) { Off(OUT_A); OnFwd(OUT_C); //灰色なら左へ } else { OnRev(OUT_A);OnFwd(OUT_C); //黒なら左へ旋回 } } Off(OUT_AC);Wait(100); //1秒停止 }
sub line_trace_JIH() { SetSensor(SENSOR_2,SENSOR_LIGHT); ClearTimer(0); while ( FastTimer(0) <= RUN_TIME_JIH ) { //それぞれの区間で1.7秒間動き続ける if ( 48 < SENSOR_2 ){ OnFwd(OUT_A); Off(OUT_C); //白なら右へ } else if (45 <SENSOR_2 < 49) { Off(OUT_A); OnFwd(OUT_C); //灰色なら左へ } else { OnRev(OUT_A);OnFwd(OUT_C); //黒なら左へ旋回 } } turn_right;Wait(22);OnFwd(OUT_AC);Wait(15); //交差点で脱線しないよう右へ方向を調整 }
sub line_trace_HGF() { SetSensor(SENSOR_2,SENSOR_LIGHT); ClearTimer(0); while ( FastTimer(0) <= RUN_TIME_HGF ) { //3.8秒間動き続ける if ( 48 < SENSOR_2 ){ OnFwd(OUT_A); Off(OUT_C); //白なら右へ } else if (45 <SENSOR_2 < 49) { Off(OUT_A); OnFwd(OUT_C); //灰色なら左へ } else { OnRev(OUT_A);OnFwd(OUT_C); //黒なら左へ旋回 } } }
sub line_trace_FE() { SetSensor(SENSOR_2,SENSOR_LIGHT); ClearTimer(0); while ( FastTimer(0) <= RUN_TIME_FE ) { //1.8秒間動き続ける if ( 48 < SENSOR_2 ){ OnFwd(OUT_A); Off(OUT_C); //白なら右へ } else if (45 <SENSOR_2 < 49) { Off(OUT_A); OnFwd(OUT_C); //灰色なら左へ } else { OnRev(OUT_A);OnFwd(OUT_C); //黒なら左へ旋回 } } }
sub line_trace_DB() { SetSensor(SENSOR_2,SENSOR_LIGHT); ClearTimer(0); while ( FastTimer(0) <= RUN_TIME_DB ) { //10秒間動き続ける if ( 48 < SENSOR_2 ){ OnFwd(OUT_A); Off(OUT_C); //白なら右へ } else if (45 <SENSOR_2 < 49) { Off(OUT_A); OnFwd(OUT_C); //灰色なら左へ } else { OnRev(OUT_A);OnFwd(OUT_C); //黒なら左へ旋回 } } }
AからMを通って出発
task main(){ across_turn(); //Aから出発しLに到着
ピンポン玉を掴む動き
turn180; OnFwd(OUT_B); //アームを閉じる power(0); Wait(25); Off(OUT_B);
L地点から出発
across_turn1(); //LからKまでライントレース
K地点到達
turn90; //K地点において次に進む方向を向くために回転 Off(OUT_AC); line_trace1(); //kから出発
J地点到達秒、1秒間停止
line_trace_JIH(); //JからI
I地点到達
line_trace_JIH(); //IからH
H地点到達
line_trace_HGF(); //HからF
F地点到達
turn_left90; //Fで左90度旋回 line_trace_FE(); //FからE
E地点到達
turn_left; //Eで左旋回(90度以下) Wait(30); line_trace1(); //EからDまでのライントレース後、一時停止
D地点到達、1秒間停止
turn_right;Wait(25); //Dで左へ傾いた分、右に曲がって位置調整 line_trace_DB(); //DからB
B地点到達
turn180; //180度旋回
アーム展開
OnRev(OUT_B); power(0); Wait(25); Off(OUT_B); go_straight; //ボールから離れる Wait(100); OnFwd(OUT_B); //アームを閉じる power(0); Wait(25); go_back; //後ろに下がって位置調整 Wait(55);
アームでピンポン玉を弾いてAにシュート
OnFwd(OUT_B); Wait(10); //ボールをアームで弾いてAにシュート }
終了
シュートをする際にピンポン玉が動いてAに向かって上手くシュートできないこともあった。しかし、ライントレースの動きに関しては正確に、スムーズに動いた。
前回に比べて早くロボットを完成させることができた。動きに関しても課題1の時に比べて滑らかに動いてくれた。急カーブでロボットがラインから逸れて予想と大きく異なる動きをすることがあったがそのたびに問題点を見つけ出し、適切に対処することが出来た。