cacher.nqc .... 主に箱をキャッチするためのプログラム。片方のRCXのため。
trace-cource.nqc ... 主にライントレースをするためのプログラム。もう一方のRCXのため。
turn.nqc ... trace-cource.nqcで使われているプログラム。[箱を取る/箱を置く]などの動作の直前・直後の処理が書かれている。
command.nqc ... trace-cource.nqcとcacher.nqcに使われているプログラム。赤外線通信を使い、二台のRCX間で通信するときのプロトコル(通信規則)を定義している。
command.h ... command.nqcに使われているヘッダファイル。通信時に通信開始・通信終了など常数を定義している。
command-proc.h ... trace-cource.nqcとcacher.nqcに使われているヘッダファイル。[箱を取る・箱を落とす・ライントレースする]などの動作を伝えるときに使う常数を定義している。
通信によって、二台のRCXは同期する。
箱を取ったり置いたりするRCXが、全体の動作を管理し、もう一台に動作一つ一つを開始するように指示を出している。
ライントレースをするRCXは、機械の移動を覚えるだけで精一杯の感があった。
最初に大雑把に全体をコーディングしたところ、サブルーチンの数がNQCの制限の8個を越えてしまっていたからだ。
ライントレースをするだけで片方は限界なので、もう一方のRCXに全体の進行や、箱を取ったり置いたりする動作を任せることとなった。
ロボコンのフィールドのそれぞれの区間に番号を割り当てる。
機械は、変数に自分のいる位置を覚えているのでそれをもとにライントレースをする。
問題点 : 最初の割り当て方の問題
黒い線で分けられた間の空間にそれぞれ一つずつ数字を割り当てたが、
それよりも、黒い線にそれぞれ数字を割り当てた方がプログラムしやすかったかもしれない。
小さな仕様 : 線の直後
ライントレースや、細かな移動の動作(箱を取る、置くなどの動作以外)の直後は黒い線の直後の位置に必ずくるようにしている。
この仕様通りにしていなかったのが、区間5の直後から区間4を超えて区間3に入る部分であった。
区間3に入った後は区切る線をずっと超えたところに来ていた。
これにより、区間3から箱を取る動作は、ほかの区間1や区間2とは違う動作となり、調整に苦心した。
最終的には、区間3で箱を取る動作をする前に、おかしな位置にいる機械を区間3の区切る線の直後に配置する動作を加えて対処した。
初期のcommand.nqcでは、通信が失敗することが多々あった。
ロボコン当日の早朝六時から、スクラッチから書き直した。
これにより、少しは通信が失敗する確立が減った。
しかし、前より通信が完了するまでの時間が遅くなった。
調整によりできるだけ短時間で通信が完了するように気を配った。
ロボコン前日まではライントレースはかなり安定していた。
しかし、すこし動作が遅いのが難点であった。
すると、当日にとても速いスピードで走っているチームを発見した。
そして、自分たちも負けていられないと、ギヤ比を変更しプログラムを変更し、とても速いロボットにした。
しかし、そう簡単に速くかつ安定なライントレースは実現せず、
スリップやコースアウトなどのトラブルを背負う機械になってしまった。
結局はロボコンで速いまま出場させたが、終わった後に遅い動作に戻したところ、ほぼ正確な動作を示した。
明らかにこちらの安定性を取るべきであった。
本当にブレークポイントを指定したかった。
debug用のprintもしたかった。
だが、NQCにはそんな機能はない。
ロボットはタイヤなど、物理的な要素が予期しない動作を招くのか、
一度発生しても、二度と再現しないバグが多々あった。
サブルーチンの数の制限や、ファンクションを用いるとコンパイル後に巨大になる、
サブルーチンからサブルーチンを呼べない、などのNQCの制限に開発は阻まれた。
最初は綺麗だったコードが、対策のため一気にtask main(){}に集中しもうゴチャゴチャになった。
長すぎる、冗長な、ひと続きのルーチンはどこに何があるのかさっぱりわからず、デバッグに苦労した。
10番教室にはMACがあり、チームで数台のMACを使える。
しかし、複数のMAC間でファイル共有の方法などのやり方がわからず、
結局は大体、一台のMACでのみ編集する羽目になった。
CVSなど同時に複数の人が編集できる環境があれば良いと感じた。
(CVSなど使ったことがないのにこんな事を言うのも変だ。)
(コードの編集履歴などを見れるようになっていれば、なお理想的であるし。)
個人のiBookでファイルを編集していたところ、
長いプログラムの入力に対する、画面の反応がだんだん鈍くなり、最後には使い物にならない程遅くなった。
MacNQCは使えない。
また、RCXの電池の電圧をどこで見たらいいかわからなかったのもきつい。
(コマンドラインのnqcコマンドはなかった。)
空腹の状態で、解決できない問題を直すように試み続けるのは得策でなかった。
食べ物を食べて血糖値を上げれば問題解決が5倍速になる。
NQCは制限が厳しく、自由にプログラムを組めないのを、これまでのゼミでの経験で少しはわかっていた。
不安の中、brickosというNQCより自由度が高い、クロスコンパイラをつかうNQC似の言語を発見し、個人的に、苦労して開発環境をインストールした。
ところが、なれたNQCが安心だろうということでbrickosは使わないことになった。
makeの苦労が水の泡。
今はまだコメント文が入っていない(2006/02/08現在)。
コードには、大量の要らないコメントアウトされた命令文がある。
見やすくするために、将来それらを消すかもしれない。
#define LINETRACE #define LIGHT_L SENSOR_3 #define LIGHT_C SENSOR_2 #define LIGHT_R SENSOR_1 #define L OUT_C #define R OUT_A #define LIGHT_THRESHOLD 40 #if 1 #define FWD OnFwd #define REV OnRev #else #define FWD OnRev #define REV OnFwd #endif int pcounter=0; int c_point1=1,c_point2=0,c_point3=0; int place=1; //put first position!!!!!!!! int tmp; int startplace; int endplace; #include "command-proc.h" #include "turn.nqc" #include "command.nqc" task main(){ ClearMessage(); SetSensor(LIGHT_L,SENSOR_LIGHT); SetSensor(LIGHT_R,SENSOR_LIGHT); SetSensor(LIGHT_C,SENSOR_LIGHT); while(1){ recive(); if(command==COMMAND_GO){ startplace=place; recive(); endplace=command; if(startplace<endplace){ //PlaySound(SOUND_CLICK); //PlaySound(SOUND_CLICK); while(place!=3 && place<endplace){ //gostrait(); linetrace(); find_bar(); place++; } if(place<endplace){ linetrace(); find_light(); place++; } if(place<endplace){ //godiffzone3to5(); //SetPower(L,4); //SetPower(R,4); Off(L); FWD(R); until(LIGHT_R<LIGHT_THRESHOLD); REV(L); //FWD(R); until(LIGHT_R>LIGHT_THRESHOLD); Off(R); REV(L); until(LIGHT_L>LIGHT_THRESHOLD); // REV(L); REV(R); until(LIGHT_R<LIGHT_THRESHOLD); REV(L); REV(R); until(LIGHT_R>LIGHT_THRESHOLD); REV(L); REV(R); until(LIGHT_L<LIGHT_THRESHOLD || LIGHT_R<LIGHT_THRESHOLD); REV(L); REV(R); until(LIGHT_R>LIGHT_THRESHOLD); /*REV(L+R); Wait(15); Off(L); FWD(R); until(LIGHT_C<LIGHT_THRESHOLD); REV(L+R); until(LIGHT_C>LIGHT_THRESHOLD); until(LIGHT_C>LIGHT_THRESHOLD); REV(R);FWD(L); until(LIGHT_R>LIGHT_THRESHOLD && LIGHT_L>LIGHT_THRESHOLD); */ Off(L+R); //SetPower(L,OUT_FULL); //SetPower(R,OUT_FULL); place++; } if(place<endplace){ //SetPower(L,3); //SetPower(R,3); linetrace(); find_bar(); //SetPower(L,OUT_FULL); //SetPower(R,OUT_FULL); place++; } while(place!=9 && place<endplace){ //gostrait(); linetrace(); find_bar(); place++; } //place--; }else if(endplace<startplace){ //PlaySound(SOUND_CLICK); while(place!=5 && place>=endplace){ //gostrait(); linetrace(); find_bar(); place--; } if(place>=endplace){ //SetPower(L,3); //SetPower(R,3); linetrace(); find_light(); FWD(L+R); until(LIGHT_L<LIGHT_THRESHOLD || LIGHT_R<LIGHT_THRESHOLD); Off(L+R); find_light(); //SetPower(L,OUT_FULL); //SetPower(R,OUT_FULL); place--; } if(place>=endplace){ //godiffzone5to3(); //SetPower(L,4); //SetPower(R,4); REV(L);Off(R); until(LIGHT_C<LIGHT_THRESHOLD); //REV(L);Off(R); //until(LIGHT_C>LIGHT_THRESHOLD); REV(L+R); until(LIGHT_L<LIGHT_THRESHOLD); REV(L+R); until(LIGHT_L>LIGHT_THRESHOLD); FWD(L);REV(R); //Wait(25); //Wait(88); until(LIGHT_C>LIGHT_THRESHOLD); until(LIGHT_C<LIGHT_THRESHOLD); until(LIGHT_C>LIGHT_THRESHOLD); //REV(L+R); //Wait(20); //until(LIGHT_C<LIGHT_THRESHOLD); Off(L+R); //SetPower(L,OUT_FULL); //SetPower(R,OUT_FULL); place--; } if(endplace==3){ //SetPower(L,OUT_HALF); //SetPower(R,OUT_HALF); linetrace(); FWD(L+R); //until(LIGHT_L>LIGHT_THRESHOLD && LIGHT_R>LIGHT_THRESHOLD); //until(LIGHT_L<LIGHT_THRESHOLD && LIGHT_R<LIGHT_THRESHOLD); until(LIGHT_L>LIGHT_THRESHOLD && LIGHT_R>LIGHT_THRESHOLD); until(LIGHT_L<LIGHT_THRESHOLD && LIGHT_R<LIGHT_THRESHOLD); REV(L+R); until(LIGHT_L>LIGHT_THRESHOLD && LIGHT_R>LIGHT_THRESHOLD); //SetPower(L,OUT_FULL); //SetPower(R,OUT_FULL); Off(L+R); } while(place!=0 && place>endplace){ //gostrait(); linetrace(); find_bar(); place--; } //place++; } place=endplace; }else if(command==COMMAND_GET_READY){ if(place==1){ c_point1++; }else if(place==2){ c_point2++; }else if(place==3){ c_point3++; } turn_back=0; turn(); }else if(command==COMMAND_TURN_LINE){ turn_back=1; turn(); } } } sub linetrace(){ //PlaySound(SOUND_DOUBLE_BEEP); REV(L+R); while(true){ if(LIGHT_R<LIGHT_THRESHOLD && LIGHT_L<LIGHT_THRESHOLD && LIGHT_C<LIGHT_THRESHOLD){ Off(L+R); //SetPower(L+R,OUT_FULL); break; } if(LIGHT_C<LIGHT_THRESHOLD && LIGHT_L<LIGHT_THRESHOLD){ Off(L); REV(R); }else if(LIGHT_C<LIGHT_THRESHOLD && LIGHT_R<LIGHT_THRESHOLD){ Off(R); REV(L); }else{ if(LIGHT_R<LIGHT_THRESHOLD){ Off(R); ////SetPower(L,OUT_HALF); }else{ ////SetPower(L,OUT_FULL); REV(R); } if(LIGHT_L<LIGHT_THRESHOLD){ Off(L); ////SetPower(R,OUT_HALF); }else{ REV(L); ////SetPower(R,OUT_FULL); } } } } /*sub linetrace(){ //PlaySound(SOUND_DOUBLE_BEEP); REV(L+R); while(true){ if(LIGHT_R<LIGHT_THRESHOLD && LIGHT_L<LIGHT_THRESHOLD && LIGHT_C<LIGHT_THRESHOLD){ Off(L+R); //SetPower(L+R,OUT_FULL); break; }else if(LIGHT_C<LIGHT_THRESHOLD && LIGHT_L>LIGHT_THRESHOLD &&LIGHT_R>LIGHT_THRESHOLD){ REV(L+R); }else if(LIGHT_C<LIGHT_THRESHOLD && LIGHT_L<LIGHT_THRESHOLD){ //Float(L); //FWD(L); Off(L); REV(R); }else if(LIGHT_C<LIGHT_THRESHOLD && LIGHT_R<LIGHT_THRESHOLD){ //Float(R); //FWD(R); Off(R); REV(L); }else if(LIGHT_C>LIGHT_THRESHOLD){ if(LIGHT_R<LIGHT_THRESHOLD && LIGHT_L>LIGHT_THRESHOLD){ FWD(R); REV(L); ////SetPower(L,OUT_HALF); }else if(LIGHT_R>LIGHT_THRESHOLD && LIGHT_L<LIGHT_THRESHOLD){ ////SetPower(L,OUT_FULL); REV(R); FWD(L); //Off(L); } }else{ // PlaySound(SOUND_DOWN); } } }*/ sub find_light(){ REV(L+R); until((LIGHT_R>LIGHT_THRESHOLD) && (LIGHT_L>LIGHT_THRESHOLD) && (LIGHT_C>LIGHT_THRESHOLD)); Off(L+R); } sub find_bar(){ REV(L+R); while((LIGHT_R<LIGHT_THRESHOLD) && (LIGHT_L<LIGHT_THRESHOLD) && (LIGHT_C<LIGHT_THRESHOLD)); Off(L+R); }
#define GO_STRAIGHT REV(OUT_A+OUT_C); #define TURN_LEFT FWD(OUT_C);REV(OUT_A); #define BACK_STRAIGHT FWD(OUT_A+OUT_C); #define TURN_RIGHT FWD(OUT_A);REV(OUT_C); #define BATT_POWER 8/12 // 8/13 int turn_back; sub turn() { int tmp=0,tmp2; if(place==1){ tmp2=c_point1; }else if(place==2){ tmp2=c_point2; }else if(place==3){ tmp2=c_point3; }else{ tmp2=0; } if(turn_back){ PlaySound(SOUND_DOWN); BACK_STRAIGHT if(tmp2==1){ tmp=5*BATT_POWER; }else if(tmp2==2){ tmp=60*BATT_POWER; }else{ tmp= 90*BATT_POWER; } Wait(tmp); if(place<4){ TURN_LEFT }else{ TURN_RIGHT } //Wait(95*BATT_POWER); until(LIGHT_C<LIGHT_THRESHOLD); Off(OUT_A+OUT_C); }else{ PlaySound(SOUND_UP); int sec_first; int sec_second; SetPower(L,2); SetPower(R,2); FWD(L+R); until(LIGHT_L<LIGHT_THRESHOLD || LIGHT_R<LIGHT_THRESHOLD); Off(L+R); if(LIGHT_L<LIGHT_THRESHOLD){ REV(L); until(LIGHT_L>LIGHT_THRESHOLD); Off(L); }else if(LIGHT_R<LIGHT_THRESHOLD){ REV(R); until(LIGHT_R>LIGHT_THRESHOLD); Off(R); } REV(L+R); until(LIGHT_L>LIGHT_THRESHOLD &&LIGHT_R>LIGHT_THRESHOLD); Off(L+R); SetPower(L,OUT_FULL); SetPower(R,OUT_FULL); if(place==2){ sec_first=250; sec_second=80; }else if(place==3){ sec_first=250; sec_second=80; }else if(place==1){ sec_first=250; sec_second=80; }else if(place>4){ sec_first=239; sec_second=109; } //if(place==3){ // //} GO_STRAIGHT Wait(sec_first*BATT_POWER); if(place<4){ TURN_LEFT }else{ TURN_RIGHT } Wait(140*BATT_POWER); if(tmp2==1){ tmp=sec_second*BATT_POWER*1/16; }else if(tmp2==2){ tmp=sec_second*BATT_POWER*7/10; }else{ tmp=sec_second*BATT_POWER; } GO_STRAIGHT Wait(tmp); Off (OUT_A+OUT_C); } }
/*#define GREEN 44 #define BLACK 30 #define WHITE 50 */ #include "command.nqc" #include "command-proc.h" #define LIGHT SENSOR_1 #define ARM OUT_A #define HAND OUT_B task main() { ClearMessage(); SetSensor(LIGHT,SENSOR_LIGHT); Wait(10); //SendMessage(COMMAND_TURN_LINE); //command=COMMAND_TURN_LINE; //send(); int i,dest,src,tmp; int c_place1=0,c_place2=0,c_place3=0; src=1;///// for(i=0;i<9;i++){ Wait(450); if(src==1){ c_place1++; tmp=c_place1; }else if(src==2){ c_place2++; tmp=c_place2; }else{ c_place3++; tmp=c_place3; } //tsukamu(); if(src==1 || src ==3){ //SetPower(ARM,OUT_FULL); OnFwd(ARM) ; Wait(30); OnRev(HAND); Wait(150); SetPower(ARM,OUT_FULL); OnRev(ARM); Wait(90); //SetPower(HAND,OUT_FULL); Off(ARM); //Off(HAND); }else{ OnFwd(ARM) ; //SetPower(ARM,OUT_FULL); Wait(50); Off(ARM); //SetPower(HAND,OUT_FULL); OnRev(HAND); Wait(150); SetPower(ARM,OUT_FULL); OnRev(ARM); Wait(90); Off(ARM); //Off(HAND); } // /* Wait(40); OnRev(HAND); Wait(80); OnRev(ARM); //SetPower(ARM,OUT_LOW); Wait(130); SetPower(HAND,OUT_HALF); OnRev(ARM); SetPower(ARM,OUT_FULL); Wait(50); Off(ARM);*/ //Off(B); // if(LIGHT>48){ //white dest=7; }else if(LIGHT>39){ //green dest=6; }else{ //brack dest=8; } PlaySound(SOUND_LOW_BEEP); command=COMMAND_TURN_LINE; send(); command=COMMAND_GO; send(); command=dest; send(); command=COMMAND_GET_READY; send(); Wait(450); //hanasu(); OnFwd(ARM) ; SetPower(ARM,OUT_HALF); Wait(30); OnRev(ARM); SetPower(ARM,OUT_LOW); OnFwd(HAND); SetPower(HAND,OUT_FULL); Wait(50); Off(HAND); OnRev(ARM); SetPower(ARM,OUT_FULL); Wait(40); Off(ARM); // command=COMMAND_TURN_LINE; send(); PlaySound(SOUND_CLICK); if(i==3-1){ src++; PlaySound(SOUND_FAST_UP); }else if(i==6-1){ src++; PlaySound(SOUND_FAST_UP); } command=COMMAND_GO; send(); command=src; send(); command=COMMAND_GET_READY; send(); } }
#define COMMAND_GO 110 #define COMMAND_GET_READY 111 #define COMMAND_TURN_LINE 112
#define COMMAND_START 201 #define COMMAND_END 202 #define COMMAND_RECIVED 203 #define COMMAND_READY 204 #define COMMAND_CONTENT 205 #define COMMAND_LISNING 206 #define COMMAND_NULL 255
#include "command.h" int command=0; #ifdef LINETRACE sub recive(){ int count,tmp; until(Message()==COMMAND_START || Message()==COMMAND_CONTENT); until(Message()==COMMAND_CONTENT){ Wait(10); SendMessage(COMMAND_LISNING); } while(1){ Wait(2); //PlaySound(SOUND_CLICK); tmp=Message(); if(tmp==COMMAND_CONTENT){ tmp=COMMAND_NULL; until(tmp!=COMMAND_CONTENT){ tmp=Message(); } command=tmp; Wait(3); SendMessage(command); Wait(13); }else if(tmp==COMMAND_END){ break; } } Wait(20); until(Message()==COMMAND_END){ SendMessage(COMMAND_RECIVED); Wait(7); } Wait(10); } #else sub send(){ int i; until(Message()==COMMAND_READY || Message()==COMMAND_LISNING){ SendMessage(COMMAND_START); Wait(15); } until(Message()==command){ Wait(23); SendMessage(COMMAND_CONTENT); Wait(5); SendMessage(command); } Wait(10); for(i=0;i<15;i++){ SendMessage(COMMAND_END); Wait(5); } } #endif
どうぞ。