黒い線の進行方向向かって左側の境界を走行する。ボールはアームではさみこみゴールまで運ぶ。最初のT字路を右折、次の交差点を直進し、A→B,A→Cのルートを走行する。
アームが開いている状態
アームが閉じている状態
モーターの回転の方向を90°変換するために十字のギヤを使用した。
赤外線センサーを用い、入射した赤外線の反射強度を取得することにより、ロボットが黒い線のどの辺を走行しているか判断する。
ロボットはコース上を、
1)線の外側
2)線の境界上
3)線の上
の三種類として認識する。進行方向向かって左側の境界上を移動させるので、ロボットの場所によりそれぞれ
1)右にシフト
2)直進
3)左にシフト
しながら進んでいく。基本的にはwhileループで1[ms]ごとにセンサーの値を取得し、上記の動作を繰り返す。T字路、交差点、ゴール地点では上記の動作とは別の専用のタスクを割り込ませる。
センサーの値は0から100の整数値で与えられる。数値が大きいほど反射強度が高い。
A→CとA→Bでは、交差点での処理とゴール後の処理が若干違うだけで基本的には同じである。
交差点の判定は、スタートからの経過時間と黒の線上にいる時間[ms]によって判定している。1ループ1[ms]に設定している為、黒の処理に入ったときに黒カウンタnをインクリメントする。nの次元は[ms]となる。マシンの処理速度に対して1[ms]は十分に遅いと考えられるので、whileループ内の処理にかかる時間は無視できると考えた。交差点に到達する前にも、長時間黒の上に滞在するポイントが存在したので、それらを省くためにCurrentTick()関数を用いてプログラム開始からの時間を条件に補助的に採用している。
ボールキャッチ処理は完全にスタート時からの秒数に依存している。これはプログラムの汎用性を下げる要因となるのであまり良い処理だとは言えない。
ボールキャッチ用の処理とゴール後のシュートの処理はtask()として定義してtask main()のなかから呼び出している。後で気づいたのだが、task main()のなかで呼び出された他のtask()は、task main()内のそれ以降の行の指示と平行に実行されるようである。今回のプログラムではたまたま動作に矛盾は生じなかったが、動作の並行処理を防ぐために#defineで定義して実行させたほうがよさそうだ。
以下にプログラムの詳細を記述する。
#define BLACK 36 #define WHITE 48 #define SPEED 25 #define go_forward OnRev(OUT_BC,SPEED); #define turn_left OnRev(OUT_B,SPEED);Off(OUT_C); #define turn_left2 OnFwd(OUT_C,SPEED);OnRev(OUT_B,SPEED); #define turn_right Off(OUT_B);OnRev(OUT_C,SPEED); #define STEP 1 //センサーのデータの取得頻度を1[ms]に設定
ボールをキャッチする動作
task ball_catch(){ //ボールキャッチ OnFwd(OUT_A,SPEED); Wait(1000); Off(OUT_A); }
ボールをゴールにシュートする動作
A→Bの場合
task shoot(){ turn_right; Wait(1000); go_forward; Wait(300); Off(OUT_B); Off(OUT_C); OnRev(OUT_A,SPEED); Wait(1000); Off(OUT_A); }
A→Cの場合
task shoot(){ turn_left; Wait(800); go_forward; Wait(300); OnRev(OUT_A,SPEED); Wait(1000); Off(OUT_A); }
変数の初期化
task main(){ SetSensorLight(S3); int n=0; //黒の上にいる時間を計測するための変数 int flg1=0; //交差点通過前=0 交差点通過後=1 int flg2=0; //ゴール判定用のフラグ int flg3=0; //ボールキャッチ前=0 ボールキャッチ後=1 long t0=CurrentTick();
ループさせるメインタスク。ゴール判定用のフラグが立つまで繰り返す。
while(flg2==0){ if(CurrentTick()-t0>7500 && flg3==0){ //ボールキャッチ start ball_catch; flg3=1; //ボールキャッチ用のフラグを立てる }else if(SENSOR_3 < BLACK){ //黒の上なら turn_left; n++; //黒カウンタインクリメント if(n>1200 && CurrentTick()-t0>9000 && flg1==0){ //交差点用の処理 Off(OUT_BC); n=0; //黒カウンタリセット flg1=1; //交差点通過フラグをたてる
A→Bの場合
turn_left2; //左折 Wait(700);
A→Cの場合
go_forward; //交差点突破(直進) Wait(1000);
以下共通
}else if(n>1400 && flg1==1){ flg2=1; //ゴール判定用のフラグをたてる } }else if(SENSOR_3 < WHITE){ //境界線上ならば go_forward; n=0; //黒カウンタリセット }else{ //それ以外(白)なら turn_right; n=0; //黒カウンタリセット } Wait(STEP); //1[ms]間待つ。1サイクル1[ms]に設定 }
ゴール判定後にシュートさせるサブルーチンを呼び出す。
start shoot; }