黒い線に沿って動き紙コップを移動させるロボットを製作せよ。
Aをスタート→Bを直進→Cを右折→Fを直進→Rを左折(一時停止)→Pを直進→X地点の紙コップを取得してコースに戻る→Qを左折→Sを直進(一時停止)→Y地点に紙コップを置いてコースに戻る→Sを直進(一時停止)→Fを左折(一時停止)→Cを右折(一時停止)→D地点でゴール
トレースを可能にするために右と左に一つずつモーターをつけた。またトレースの際にロボットが安定するようにモーターを取り付けた後輪2つに加え自由に動く前輪を2つ取り付けた。課題1に比べてロボットの前後左右の動きがより活発になったため、壊れにくい丈夫なロボットを作るように意識した。
光センサーがロボットの中心部にできるだけ近づくように努力した。しかし光センサーをロボットのど真ん中にしてしまうと、交差点などでラインから抜け出すのが困難となったため、中心よりもやや前に取り付けた。 また後輪は一番小さいギアと一番大きいギアをかみ合わせることでタイヤの回転を遅くした。
コップを取るアームは下のように囲いを作りそれを上下に移動することで取れるようにした。あまりアームを重くし過ぎるとアームを引き上げることが出来ないため軽くする必要があったが、少しロボットがずれてもコップが取れるようにするため可能な限りアームを大きくした。
スムーズなライントレースを可能にするために5段階の移動方法を定義した。 また直進、右折、左折は時間が指定できるよう定義し、アームの上げ下げは時間も定義した。
#define go_straight OnFwd(OUT_AC); SetPower(OUT_AC,5); //直進 #define turn_right OnFwd(OUT_A);OnRev(OUT_C);SetPower(OUT_AC,5); //右旋回 #define turn_left OnFwd(OUT_C);OnRev(OUT_A);SetPower(OUT_AC,5); //左旋回 #define sift_right OnFwd(OUT_A);Off(OUT_C);SetPower(OUT_A,5); //右折 #define sift_left OnFwd(OUT_C);Off(OUT_A);SetPower(OUT_C,5); //左折 #define go(t) OnFwd(OUT_AC);Wait(t);Off(OUT_AC); //t秒間直進する #define right OnFwd(OUT_A);Wait(t);Off(OUT_A); //t秒間右折する #define left OnFwd(OUT_C);Wait(t);Off(OUT_C); //t秒間左折する #define down OnFwd(OUT_B);Wait(40);Off(OUT_B); //アームを下ろす #define up OnRev(OUT_B);Wait(40);Off(OUT_B); //アームを上げる
基本的には右側のライントレースを使ったが、右側のライントレースではR地点からQ地点へ移動することが出来なかったため左側のライントレースも作った。
SetSensorMode(SENSOR_2,SENSOR_MODE_RAW)を入れることにより詳細な値を測定することができる。 また下のライントレースのサブルーチンでは右旋回の時間(光センサーにより示される線の閾値が830より大きくなる時間)が連続で0.32秒よりも大きくなった場合whileのループから抜け出すというものである。交差点にぶつかるとき、黒を回避して右旋回をしてもまた黒が続き連続で光センサーが黒を感知するのが0,32秒を超えると、whileのループから抜けて止まるという方法で交差点を判断する。右旋回以外の動きをするときはたとえその動きが連続で0.32秒以上動いたとしてもClearTimer(0)を入れているためにその時間はカウントされないですむのである。ここでの0.32秒は実際に計測して最も良いとされた時間であり、これが0.32秒よりも小さければF地点からE地点までのカーブが急なラインをトレースすることが出来ず、また0.32秒よりも大きければ交差点判断しないときがあった。光センサーが示す閾値に次のように動くようにした。
黒(閾値が830より大きい)→右旋回
やや黒(閾値が800より大きく830以下)→右折
やや白(閾値が770より小さく750以上)→左折
白(閾値が750より小さい)→左旋回
それ以外(閾値が770以上800以下)→直進
sub torace() { SetSensor(SENSOR_2,SENSOR_LIGHT); SetSensorMode(SENSOR_2,SENSOR_MODE_RAW); ClearTimer(0); while(FastTimer(0)<32) { if(SENSOR_2>830) //閾値が830より大きいとき { turn_right; //右旋回が0.32秒以上になると止まる } else { if(SENSOR_2>800){ //閾値が800よりおおきいとき sift_right //右折 ClearTimer(0); //タイマーを0にする }else if(SENSOR_2<750){ //閾値が750より小さいとき turn_left //左旋回 ClearTimer(0); //タイマーを0にする }else if(SENSOR_2<770){ //閾値が770より小さいとき sift_left //左折 ClearTimer(0); //タイマーを0にする }else{ //上記の条件を満たさないとき go_straight //直進 ClearTimer(0); //タイマーを0にする } } } Off(OUT_AC); }
上にある線の左側のライントレースと仕組みは同じで、線の左側のライントレースのサブルーチンであ左旋回の時間(光センサーにより示される線の閾値が820より大きくなる時間)が連続で0.32秒よりも大きくなった場合whileのループから抜け出すというものである。
sub torace_left() { SetSensor(SENSOR_2,SENSOR_LIGHT); SetSensorMode(SENSOR_2,SENSOR_MODE_RAW); ClearTimer(0); while(FastTimer(0)<32) { if(SENSOR_2>820) //閾値が820より大きいとき { turn_left; //左旋回が0.32秒以上になると止まる } else { if(SENSOR_2>800){ //閾値が800より大きいとき sift_left //左折 ClearTimer(0); //タイマーを0にする }else if(SENSOR_2<760){ //閾値が760より小さいとき turn_right //右折 ClearTimer(0); //タイマーを0にする }else if(SENSOR_2<780){ //閾値が780より小さいとき sift_right //右折 ClearTimer(0); //タイマーを0にする }else{ //上記の条件を満たさないとき go_straight //直進 ClearTimer(0); //タイマーを0にする } } } Off(OUT_AC); }
task main() { go(30); torace(); //C地点 right(30); torace(); //F地点 left(20); torace(); //E地点 torace_left(); //R地点 Wait(100); left(10); torace_left(); //P地点 left(60); down; //紙コップをつかむ right(70); torace_left(); //Q地点 go(20); torace(); //S地点 go(30); Wait(100); torace(); //S地点 right(30); Wait(100); up; //紙コップ置く torace(); //F地点 Wait(100); right(30); torace(); //C地点 Wait(100); right(60); go(40); }
スタートからゴールまで行くことが出来たが、コップをうまく運ぶことが出来なかった。コップの付近まで近づいた後にコップの前で微調整をしてからコップをとるという流れにすべきだった。
今回の課題は課題1に比べて、プログラミングが大変だった。ロボットの見た目を意識しすぎてプログラミングにあまり時間を割くことが出来なかった。また電池の消耗により変わった結果が出たので最後まで調整する必要があり大変だった。