今回の課題は下図のようなコースを各チームで作成し、ミッションを遂行することである。
ミッションとは指定された3つのコースのうち1つを選択し、ライントレースしながら紙コップを指定の場所まで運ぶことである。自分の場合は Aをスタート、Bを直進、Cを直進、D地点の紙コップを取得して来たコース戻りCへ向かう、Cを左折、Fを直進、Rを左折(一時停止)、Pを直進、X地点に紙コップを置いてコースに戻る、Qを左折、Sを右折(一時停止)、Fを左折(一時停止)、Cを右折(一時停止)、D地点へ(ゴール) (一時停止の指定がある場所は、1秒間停止すること)
キットに載っているような基本的な3輪駆動のロボットに前側に光センサ、後ろ側の基盤と駆動輪の間にコップを掴むアームを取り付けた。アームは3つ目のモーターを使って、上下に動くようになっていて、アームを下に降ろし掴むというよりは中に入れて引きずっていくようにした。なるべく正確な値を測りライントレースさせるために光センサはできるだけ地面に近づけるようにした。
#define speed_fast 20 //直線上での速さ #define speed_curve 25 //曲がる時の速さ
#define speedRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL); //タイヤBを speedR%,タイヤCをspeedL%の速さでそれぞれ進ませる(+:前進,-:後進) #define go_fwd speedRL(speed_fast,speed_fast); //前進 #define turn_right_high speedRL(-speed_curve - 5,speed_curve); //右旋回 #define turn_right_low speedRL(0,speed_curve + 10); //右折 #define turn_left_high speedRL(speed_curve ,-speed_curve - 10); //左旋回 #define turn_left_low speedRL(speed_curve + 10,0); //左折 #define turn_left_90 OnFwd(OUT_B,25); OnFwd(OUT_C,-25); Wait(1100); //左90度回転 #define turn_left_150 OnFwd(OUT_B,25); OnFwd(OUT_C,-25); Wait(2500); Off(OUT_BC); //左150 度回転 #define turn_right_150 OnFwd(OUT_B,-25); OnFwd(OUT_C,25); Wait(2500); Off(OUT_BC); //右150度回転 #define turn_left_180 OnFwd(OUT_B,25); OnFwd(OUT_C,-25); Wait(3100); Off(OUT_BC); //左180度回転 #define turn_right_180 OnFwd(OUT_B,-25); OnFwd(OUT_C,25); Wait(3100); Off(OUT_BC); //右180度回転 #define arm_down OnFwd(OUT_A,-10); Wait(1000); Off(OUT_A); // アームダウン #define arm_up OnFwd(OUT_A,20); Wait(1000); Off(OUT_A); //アームアップ
自分のコースの場合光センサが黒線のラインと左側の白い部分の境界線上を走ることにした。ライントレースをする上で重要な明るさを5段階に分けて測り各動作を決定した。暗い順に左旋回、左折、直進、右折、右旋回するようになっている。測った結果しきい値は60になった。
|右旋回|右折|直進|左折|左旋回| |70 |66 |60 |52 |45 | #define threthold 60 //しきい値
交差点認識に関しては時間ではなく最も黒い時が連続して何回続いたかという方法を採用した。調べた結果160回が最適だと判断した。つまり光センサが最も暗いとき(値でいうと45以下の時)、を160回計測したとき、そこを交差点だと判断し、各動作を行う。そして、値が45以下でなくなった瞬間最も暗いときの回数を初期化(0回)するようにしている。
#define nMAX 160 //交差点認識のための最も黒い時の回数
sub follow_line() //ライントレース { SetSensorLight(S1); int n = 0; //nは続けてもっとも暗いときになった回数 while(n <= nMAX){ //最も暗い時がnMAX以下のときライントレースを繰り返す if(SENSOR_1 < threthold -15 ){ turn_left_high; n++; //回数を増やす }else { if (SENSOR_1 < threthold -7){ turn_left_low; }else if (SENSOR_1 < threthold +6){ go_fwd; }else if (SENSOR_1 < threthold +10){ turn_right_low; }else{ turn_right_high; } n = 0; //最も黒い時の回数の初期化 } } Off(OUT_BC); Wait(1000); PlaySound(SOUND_CLICK); //交差点で音を鳴らす Wait(1000); }
ロボットが交差点だと判断したら音を鳴らして分かりやすくしている。
3パターンを用意した。
sub inter_left() //交差点左折 { OnFwd(OUT_BC,25); Wait(1000); Off(OUT_BC); turn_left_90; Off(OUT_BC); Wait(1000); }
sub inter_straight() //交差点直進 { OnFwd(OUT_BC,25); Wait(500); Off(OUT_BC); }
通常は上記の2パターンで大丈夫だと思うが自分の場合は直角の部分が曲がりにくかったのでもうひとつ余分に作った
sub inter_left_90() //交差点を90度左折 { OnFwd(OUT_BC,25); Wait(600); Off(OUT_BC); turn_left_90; Off(OUT_BC); Wait(1000); }
通常のライントレースでは急カーブがうまく行かなかったので仕方なくそれ専用のライントレースサブルーチンを作った。このサブルーチンはnMAX_EFが指定された回数になるまでライントレースを繰り返すようになっている。通常のライントレースサブルーチンと違うのは、nの値を初期化しないところにある。
#define nMAX_EF 3800 //交差点認識のための最も黒い時の回数(EF間のみ)
sub follow_line_EF() //EF間で適用したライントレース { SetSensorLight(S1); int n = 0; while(n <= nMAX_EF){ if(SENSOR_1 < threthold -15 ){ OnFwd(OUT_B,50); OnFwd(OUT_C,-60); n++; }else { if (SENSOR_1 < threthold -7){ turn_left_low; }else if (SENSOR_1 < threthold + 6){ go_fwd; }else if (SENSOR_1 < threthold + 10){ turn_right_low; }else{ OnFwd(OUT_B,-30); OnFwd(OUT_C,20); } } } Off(OUT_BC); Wait(1000); }
sub catch_cup() //コップを掴む { turn_left_180; Wait(500); arm_down; Wait(500); turn_right_180; }
コップを掴むときはアームを下におろしている。
sub release_cup() //コップを離す { turn_left_180; Wait(500); arm_up; Wait(500); turn_right_180; }
コップを離すときはアームを上に上げている。 アームが進行方向とは後ろについているので掴む、離すときにロボットを180度回転(turn_right_180やturn_left_180)させている。
task main() { follow_line(); inter_straight(); //C直進 follow_line(); Off(OUT_BC); follow_line(); inter_left_90(); //B左折 OnFwd(OUT_B,25); //微調整 Wait(500); Off(OUT_B); follow_line(); inter_left(); //P左折 follow_line(); inter_straight(); //Q直進 OnFwd(OUT_C,30); //微調整 Wait(1100); Off(OUT_C); follow_line(); inter_left(); //R左折 follow_line(); inter_left_90(); //E左折 follow_line_EF(); follow_line(); inter_left_90(); //F左折 OnFwd(OUT_B,25); //微調整 Wait(500); Off(OUT_B); follow_line(); catch_cup(); //コップ掴む inter_straight(); //S直進 follow_line(); inter_straight(); //S直進 follow_line(); release_cup(); //コップ離す inter_left(); //Q左折 OnFwd(OUT_C,30); //微調整 Wait(800); Off(OUT_C); follow_line(); inter_straight(); //R直進 follow_line(); inter_left(); //P左折 follow_line(); inter_left(); //B左折 OnFwd(OUT_B,25); //微調整 Wait(700); Off(OUT_B); follow_line(); inter_straight(); OnFwd(OUT_BC,30); //Aの中にゴール Wait(800); }
交差点を曲がるときに常にではないが、曲がりすぎて脱線したり、逆に曲がらな過ぎて上手くいかなかったりということが起こったのでそれらを防ぐために//微調整というものは入っている。微調整具合が各々違ったのでサブルーチンにはできなかった。
プログラムに関してはサブルーチンやマクロを使いながら前回の課題よりは大分コンパクトに収まっていて見やすくなったので良かった。ただ実際に動かしてみると成功率は50%というところで完全性に関しては反省すべき点が多々あった。電池の残量によって変化したり、僅かな光の変化などもう少し完全性に注意すべきだった。次の課題では反省を活かせるようにしたい。