※コンパイルは通っていますが、実機で動かしたわけではありません。
うまく動く保証はどこにもありません。
michaegonのプログラムのほうがよほどいいです。
緑、青、赤の順にこなします。
#define sikiiti 50 #define BMAX 500 #define go_left OnFwd(OUT_C,30);OnFwd(OUT_B,-20); #define go_right OnFwd(OUT_C,-20);OnFwd(OUT_B,30); #define go_straight OnFwd(OUT_BC,15); #define turn_right OnFwd(OUT_C,-10);OnFwd(OUT_B,10); #define turn_left OnFwd(OUT_C,10);OnFwd(OUT_B,-10); #define back_left OnFwd(OUT_C,-30);OnFwd(OUT_B,20); #define back_right OnFwd(OUT_C,20);OnFwd(OUT_B,-30); #define back_straight OnFwd(OUT_BC,-15); #define STOP Off(OUT_BC);Wait(1000); #define P 10 #define MODOSHITIME 300 #define TEST 11 #define CONNx 5 #define CONNy 1 #define MODOSHITIME 300 #define KICK 12 #define FINISH 13 #define KANOKI 14
大量にdefineされていますけど、上半分程は僕がnxcプログラムを書くときにテンプレとして置いているものなので、使わなかったものも多いです。
いちいち定義を書かずとも、ある程度は指定できるのがいいです。
int count[3]={0,0,0};
今回はカウンターは配列形式にしています。
白ければcount[0]を+1、黒ければcount[1]を+1、交差点と判定されればcount[2]を+1します。
void TSUSHIN(int x){ int msg1=0; STOP; SendRemoteNumber(CONNx,MAILBOX1,x); while(msg1==0){ ReceiveRemoteNumber(MAILBOX1,true,msg1); Wait(1); } }
通信用のプログラムを別に置いています。
こうすることで、いちいちややこしい送信文、受信文を書かなくてもいいようにしました。
void START(){ TSUSHIN(TEST); while(SENSOR_1>sikiiti){ go_straight; } while(SENSOR_1<sikiiti){ turn_right; } }
スタート時の動作です。
通信テストを行い、ライントレースに行くまでの動作が書かれています。
int iscan(){ if(SENSOR_2<15){ return 1; }else{ return 0; } }
缶があれば1を、なければ0を返す関数です。
void kick(){ while(SENSOR_2>10){ go_straight; } TSUSHIN(KICK); }
もし缶があれば、近づいた上で、キックしろという命令を送ります。
void LAPfinish(){ back_straight; Wait(500); TSUSHIN(KANOKI); int msg1=0; while(msg1==0){ ReceiveRemoteNumber(MAILBOX1,true,msg1); Wait(1); } back_straight; Wait(2000); }
各LAPの終了行動、つまり缶を立てる時の動作が書かれています。
void line_trace(int t){ int MEIDO=SENSOR_1-sikiiti; if(t==3||t==4){ OnFwd(OUT_C,P+MEIDO);OnFwd(OUT_B,P-MEIDO); }else{ OnFwd(OUT_C,P-MEIDO);OnFwd(OUT_B,P+MEIDO); } if(0<MEIDO){ count[0]=0; count[1]++; }else{ count[0]++; count[1]=0; } if(count[0]>50){ count[0]=0; count[1]=0; count[2]++; if(t==1){ turn_left; Wait(MODOSHITIME); go_straight; Wait(2000); }else if(t==2){ turn_left; Wait(2000); } } }
ライントレースについて書かれています。
ここでは光センサーの値により、各モーターをどの速度で回すか指定しています。
課題1のような二段階、さらには6段階などより、格段に多くの段階になっています。
もしうまくいかなければ、課題1が終わったあとで書いた6段階、それでもうまく行かなければ課題1のときの二段階のライントレースに差し替えることもできます。
void LAP(int x){ if(x==1){ while(SENSOR_1<sikiiti){ turn_right; } count[2]=0; while(count[2]<7){ line_trace(1); if(iscan()==1){ kick(); } } do{ Wait(200); go_straight; }while(SENSOR_1>sikiiti); LAPfinish(); while(SENSOR_1>sikiiti){ go_left; } }else if(x==2){ count[2]=0; while(count[2]<3){ line_trace(0); if(iscan()==1){ kick(); } } while(count[2]<7){ line_trace(1); if(iscan()==1){ kick(); } } while(count[2]<9){ line_trace(0); if(iscan()==1){ kick(); } } LAPfinish(); while(SENSOR_1>sikiiti){ go_right; } } }
非常にめんどくさく書かれていますが、通過した交差点の数でいまどこにいるかを把握し、それに対応した行動を行っていくプログラムです。
もしこのプログラムを調整することがあるならば、最も調整が必要と思われる部分の一つです。
void LAST_ACTION(){ go_straight; Wait(5000); STOP; TSUSHIN(FINISH); }
最終行動が書かれています。
task main(){ SetSensorLight(S1); SetSensorLowspeed(S2); START(); LAP(1); LAP(2); LAST_ACTION(); }
メインは簡潔にかかれています。
たったこれだけです。
#define turn_left OnFwd(OUT_C,10);OnFwd(OUT_B,-10); #define back_left OnFwd(OUT_C,-30);OnFwd(OUT_B,20); #define back_right OnFwd(OUT_C,20);OnFwd(OUT_B,-30); #define back_straight OnFwd(OUT_CB,-15); #define STOP Off(OUT_BC);Wait(1000); #define P 10 #define MODOSHITIME 300 #define TEST 11 #define CONNx 5 #define CONNy 1 #define MODOSHITIME 300 #define KICK 12 #define FINISH 13 #define KANOKI 14
defineはメインと変わってません。
inline void SHIME(){ } inline void TATE(){ } inline void HANASU(){ }
この辺はまだ空白です。
SHIMEで「閉めて」、TATEで「立てて」、HANASUで「離し」ます。
最終的には消す予定ではありました、というのは同じようなものをmichaegonが書いていましたので。
inline void CANOKI(){ SHIME(); TATE(); HANASU(); }
わかりやすいようにこう書いてはいますが、michaegonのプログラムをそのまま持ってくる、うまく行かなければその場で合ったものを書く予定でした。
inline void OTO(){ } inline void KERI(){ }
最後の行動が終了した時の音をだすOTO「音」と、缶を叩き込むKERI「蹴り」をここで書く予定でした。
michaegonのプログラムをそのまま持ってくるなり、その場で書くなりする予定でした。
task main(){ while(true){ int msg1=0; while(msg1==0){ ReceiveRemoteNumber(MAILBOX1,true,msg1); Wait(1); } if(msg1==TEST){ SendRemoteNumber(CONNy,MAILBOX1,TEST); }else if(msg1==KICK){ KERI(); SendRemoteNumber(CONNy,MAILBOX1,KICK); }else if(msg1==FINISH){ OTO(); break; }else if(msg1==KANOKI){ CANOKI(); SendRemoteNumber(CONNy,MAILBOX1,KANOKI); } } }
メインのプログラムは、通信された時にどう返すかのみ書かれています。
それ以外は必要ありませんので。
結果的に使われることのなかったプログラムですが、メインの方はそこそこ上手く書けていると思います。
サブの方は空白も多く、実際に機体を見ながら、試しながら書く前提で書いたので、こんな感じになっています。
まだまだ直すべき点は多いと思います。
今後の課題にしたいです。