ライントレースをしながら途中のピンポン球を拾い、コースの最後にあるゴールに入れる。自分がやるのはコース2。交差点では直進か右折しかない(左折がない)のが特徴。先生にもらったピンポン球を使用した。
形としてはコンパクトで、かつ光センサーが2つの駆動輪の真ん中より少し前で床と近くなるようにするのを目指した。
ボールの取り方としては超音波センサーでボールを認識して電源の下に取り付けたモーターでアームを動かして取る。この機構を電源の下に取り付けることで機体の左右に出すことなく取り付けられたので、よりコンパクトな機体になった。
取扱説明書に載っている機体だとセンサーの位置が高くタイヤから遠いと思ったので、できるだけタイヤに近く、床に近くしようと思ってこの形になった。床にはかなり近くなったが、タイヤからの距離はあまり変わらなかった。しかし、床にかなり近くなったので光センサーの誤作動はほとんど無くなった。
#define SENKAIR OnFwdSync(OUT_BC,-50,-100);//右旋回 #define SENKAIL OnFwdSync(OUT_BC,-50,100);//左旋回 #define TURNR Off(OUT_B);OnFwd(OUT_C,-50);//右カーブ #define TURNL Off(OUT_C);OnFwd(OUT_B,-50);//左カーブ #define TYOKUSIN OnFwdSync(OUT_BC,-50,0);//直進 SetSensorLight(S1); SetSensorLowspeed(S2); t0=CurrentTick();//交差点検知に使用 while(CurrentTick()-t0<=600){ if(SENSOR_1<45){ SENKAIL; //ラインの真ん中では左旋回 } else if(SENSOR_1<48){ TURNL; //ラインに少し入ったら左カーブ } else if(SENSOR_1<60){ TYOKUSIN; //ラインの境界線あたりで直進 t0=CurrentTick(); //タイマーをリセット } else if(SENSOR_1<65){ TURNR; //ラインから外れたら右カーブ t0=CurrentTick(); //タイマーをリセット } else if(SENSOR_1>=65){ SENKAIR; //ラインから大きく外れたら右旋回 t0=CurrentTick(); //タイマーをリセット }
ライントレースはラインの左側を通ることにした。これにより、ヘアピンカーブでの交差点認識がなくなる。光センサーの値はセンサーを床近くに取り付けたため、かなり簡単にこの範囲に落ち着いた。交差点の検知は黒を光センサーが検知している時間を測定し、一定時間以上になると交差点と判断する。しかし、一番問題となったのはタイマーの値で、電池残量によってその都度スピードが変わってくるので毎回のように値を調節する必要があった。調節の間に電池がさらに減っていくためイタチごっこになった。次回の課題までに解決策を見つける必要がある。
if(n==0){ //2回目の作動防止 if(SensorUS(S2)<9){ //超音波センサーでボールを認識 Off(OUT_BC); Wait(1000); RotateMotor(OUT_A,40,-60); //アームを下げる n=n+1; //2回目の作動防止 t0=CurrentTick(); //タイマーをリセット } }
上でも述べたようにボールの認識は超音波センサーで行った。タッチセンサーを使うことも考えたが、ボールが軽くてセンサーが反応しないので今回は超音波センサーを使うことにした。超音波センサーは初めて使ったので最初は苦戦したが、最終的にはかなり安定してボールを取れるようになった。取ったあとのボールに超音波センサーが反応する問題はif文を2つ繋げることで解決した。
上ではライントレースとボールを取るプログラムを別々に書いているが、実際には2つを繋げてさらに交差点で止まるプログラムを加えてサブルーチン「KIHON()」とした。
#define SENKAIR OnFwdSync(OUT_BC,-50,-100);//右旋回 #define SENKAIL OnFwdSync(OUT_BC,-50,100);//左旋回 #define TURNR Off(OUT_B);OnFwd(OUT_C,-50);//右カーブ #define TURNL Off(OUT_C);OnFwd(OUT_B,-50);//左カーブ #define TYOKUSIN OnFwdSync(OUT_BC,-50,0);//直進 sub KIHON() { SetSensorLight(S1); SetSensorLowspeed(S2); t0=CurrentTick(); while(CurrentTick()-t0<=600){ if(SENSOR_1<45){ SENKAIL; } else if(SENSOR_1<48){ TURNL; } else if(SENSOR_1<60){ TYOKUSIN; t0=CurrentTick(); } else if(SENSOR_1<65){ TURNR; t0=CurrentTick(); } else if(SENSOR_1>=65){ SENKAIR; t0=CurrentTick(); } if(n==0){ if(SensorUS(S2)<9){ Off(OUT_BC); Wait(1000); RotateMotor(OUT_A,40,-60); n=n+1; t0=CurrentTick(); } } } Off(OUT_BC); Wait(1000); //交差点で1秒止まる }
#define KOUSATEN_MAE TURNR;Wait(500); //交差点を直進 #define KOUSATEN_MIGI TURNR;Wait(2000);SENKAIR;Wait(1500); //交差点を右折
今回の課題で1番失敗したと思う部分。最初にライントレースが全部通しでできた時に時間制御だったので最後まで時間制御でやってしまった。しかし、電池残量の変化によるスピードの変化を考えれば角度制御にすべきだった。ここを変えておけば本番でも失敗することなくできていたかもしれない。
#define KOUSATEN_MAE TURNR;Wait(500); #define KOUSATEN_MIGI TURNR;Wait(2000);SENKAIR;Wait(1500); task main () { RotateMotor(OUT_A,40,60); n=0; KIHON(); KOUSATEN_MIGI;//P右折 KIHON(); KOUSATEN_MAE;//Q直進 KIHON(); KOUSATEN_MAE;//Q直進2回目 KIHON(); KOUSATEN_MIGI;//R右折 KIHON(); KOUSATEN_MAE;//P2直進 KIHON(); KOUSATEN_MIGI;//S右折 KIHON(); KOUSATEN_MAE; //ゴールにむきを合わせる Off(OUT_BC); Wait(1000); RotateMotor(OUT_A,40,60); //アームを上げる RotateMotorEx(OUT_BC,50,720,0,true,true); //後ろに下がる Wait(500); RotateMotor(OUT_A,40,-60); //アームを下げる RotateMotorEx(OUT_BC,-50,720,0,true,true);//前に進むことでアームでボールを押す Off(OUT_BC); }
成功回数1回。電圧の変化による交差点の誤検知は仕方ないとしても、交差点の通過を角度制御にしなかったのは手痛いミスだった。1回成功した時にもう一度やってみるべきだった。
今回のまとめとしては詰めが甘いだと思う。プログラム自体は一応走るレベルだったが、確実性の低いものだった。それだけでなく、そのことに気づかず本番を迎えたことも詰めが甘いと言える。次の課題ではこうならないように注意が必要である。