課題2を参照。
ロボット全体の写真と、車体部分の写真である。
光センサーは上の写真のようにL字型のブロックを用いて地面と接し、細かい値を取れるようにした。
車体の重心が後ろにあり、後ろに傾いてしまうので、上の写真のようにブロックを一つつけ、支えるようにした。
特に、急カーブでも光センサーで道をたどりやすいよう、次のような工夫をした。
(1)左右のタイヤ間の距離を小さくし、小回りがきくようにした
(2)光センサをできるだけ車体に近づけ光センサーの動きを小さくし、コースアウトしにくくした。
今回のプログラムはif文など論理展開が複雑でとても難しかった。 左折のみだったのでプログラムの量が少なくて済んだ。
#define BLACK 40 //強い黒 #define Black 42 //弱い黒 #define White 52 //弱い白 #define WHITE 55 //強い黒 #define RIGHT OnFwd(OUT_A);OnRev(OUT_C); //右旋回 #define right OnFwd(OUT_A); //右折 #define fore OnFwd(OUT_AC); //直進 #define left OnFwd(OUT_C); //左折 #define LEFT OnRev(OUT_A);OnFwd(OUT_C); //左旋回 #define UP PlaySound(SOUND_UP); #define DOWN PlaySound(SOUND_DOWN); #define MaxTime 28 //黒の上を走る時間の上限 int turntime=0; //黒の上にMaxTime以上いた回数 sub Tstop() //一時停止するところでの動作 { Off(OUT_AC);Wait(100); DOWN; } //一時停止し、音を鳴らす。 sub corner() //直角に左折するところでの動作 { UP; LEFT;until(SENSOR_1>Black); } //音を鳴らし、黒から出るまで左旋回する sub crossroad() //黒線を乗り越える動作 { right;Wait(20); fore;until(SENSOR_1>Black); right;until(SENSOR_1<WHITE); } //白になるまで黒線をのりこえ、黒になるまで右折 sub linetrace() //黒の時間がMaxTimeを超えるまで、黒線の左側をたどる { SetSensor(SENSOR_1,SENSOR_LIGHT); SetPower(OUT_A,0);SetPower(OUT_C,0); ClearTimer(0); while(FastTimer(0)<MaxTime){ if(SENSOR_1<BLACK){ LEFT; //強い黒のときは左旋回 }else if(SENSOR_1<Black){ left; //弱い黒のときは左折 }else if(SENSOR_1<White){ fore; // 灰色のときは直進 }else if(SENSOR_1<WHITE){ right; //弱い白のときは右折 }else { RIGHT; //強い白のときは左折 } if(SENSOR_1>BLACK){ ClearTimer(0); } //強い黒の上にいる時間を計る } turntime+=1; //強い黒の上にいる時間がMaxTimeをこえたらturntimeを1増やす } void linetrace_nocount(int t) //t秒間黒線の上の時間を計らずただ黒線の左をたどる { SetSensor(SENSOR_1,SENSOR_LIGHT); SetPower(OUT_A,0);SetPower(OUT_C,0); ClearTimer(2); while(FastTimer(2)<t){ if(SENSOR_1<BLACK){ LEFT; }else if(SENSOR_1<Black){ left; }else if(SENSOR_1<White){ fore; }else if(SENSOR_1<WHITE){ right; }else { RIGHT; } ClearTimer(0); } } sub linetrace_sensitive() //linetraceで、曲がる部分を感じやすくした { SetSensor(SENSOR_1,SENSOR_LIGHT); SetPower(OUT_A,0);SetPower(OUT_C,0); while(FastTimer(0)<25){ if(SENSOR_1<BLACK){ LEFT; }else if(SENSOR_1<Black){ left; }else if(SENSOR_1<White){ fore; }else if(SENSOR_1<WHITE){ right; }else { RIGHT; } if(SENSOR_1>BLACK){ ClearTimer(0); } } turntime+=1; } //MaxTimeを25に減らした
スタートからF地点までのプログラムを例にとる。
if(turntime==0){ linetrace_nocount(4000); linetrace(); corner(); //F }
turntime==0のとき、上のifカッコの中に入る。上の場合、始めの40秒間はただライントレースをし、そのあとは曲がりを判別するライントレースをする。F地点で曲がりを見つけるとlinetraceのサブルーチンは終わり(このときturntimeは1になるが、ifカッコの動作が終わるまでifカッコの中からは出ない。)cornerのサブルーチンに移る。 cornerのサブルーチンが終わるとturntime==0のifカッコから抜け、turntime==1のifカッコに入る。
task main() { SetSensor(SENSOR_1,SENSOR_LIGHT); SetPower(OUT_A,0);SetPower(OUT_C,0); ClearTimer(0); while(n<=12){ if(turntime==0){ linetrace_nocount(6000); //60秒間はただ黒線の左をたどる linetrace(); corner(); //F地点(直角に曲がる) }else if((turntime==1)||(turntime==8)||(turntime==11)){ linetrace(); Tstop(); LEFT;until(SENSOR_1>White); //Q,二回目のR,E地点(一時停止・左旋回) }else if((turntime==2)||(turntime==9)){ linetrace_nocount(500); linetrace_sensitive(); UP; crossroad(); //R,二回目のS地点(黒線を乗り越える) }else if((turntime==3)||(turntime==10)){ linetrace_nocount(500); linetrace(); corner(); //S,P地点(ロータリーから抜ける) }else if(turntime==4){ linetrace(); corner(); //G地点(直角に曲がる) }else if(turntime==5){ linetrace_nocount(4000); //急カーブは40秒ただたどる linetrace(); corner(); ClearTimer(0); //H地点(直角に曲がる) }else if(turntime==6){ linetrace(); Tstop(); crossroad(); //1回目のT地点(一時停止・乗り越える) }else if(turntime==7){ linetrace_nocount(2000); linetrace(); Tstop(); crossroad(); //2回目のT地点(一時停止・乗り越える) }else if(turntime==12){ linetrace(); DOWN; Off(OUT_AC); //A地点(終わり) } } }
黒の上にいる時間から曲がりを判別するプログラムのみだと、普通の直進の道でも曲がりと判別されてしまうことがあったため、黒の上にいる時間を測定せずに黒線の左をたどるプログラムを入れ、誤作動が起きる確率を小さくした。
はじめは「黒・灰色・白」の3つに判別してライントレースのプログラムを作った。交差点の判別のプログラミングをするときには、「黒・黒っぽい灰色・灰色・白っぽい灰色・白」の5つに判別する方法のほうがやりやすいとは思っていたが、頑固にも3つの判別方式に固執してしまった。その後挫折して5つの判別方式に乗り換えたが、もう少し早く5つの判別方式に乗り換えていればよかったと思う。また、ロボットの光センサーの位置を車体に近づける、という工夫ももう少し早く導入すればよかった。
5つの判別方式にした後も自分の思った通りにプログラムが進まず、最終的にはペアの人のプログラムをかなり参考にさせて頂いた。自分の考えたプログラムのどこがよくなかったのか考えてそれを直してもよかったと思う。とにかく時間が足りなかったので、次回は計画的に、また無駄な作業を最小限にしようと思う。