目次
ブラン・・・繊維学部応用生物学系
二宮・・・同、創造工学・根暗で目を見て話せない系
セレン・・・同、応用生物学系。実はブラインドタッチができない
課題2:黒い線上を動くロボット
ルール
次のような周回コース(黒い線)を動くロボットを作成せよ。
センサー、モーターはいくつ使ってもよい。プログラムは次の2つ(または3つ)を作成すること。
1.直角のコーナーを通る
2.直角のコーナーを通らない(近道する)
3.(3人チームの場合) 1周目は近道を選択せず、2周目は近道を選択するロボットを作る
ただし、
シンプルに条件を満たすコースにした。鋭角のカーブが特徴的なところ。
task_mainの中をなるべくごちゃごちゃさせないために、サブルーチンや関数を多く使った。
パーツごとに交差点カウントをcross = 0;でリセットすることで、同じ行動を使い回したり周回をリピートで処理できるように工夫した。
また、難しい鋭角カーブはそこに差し掛かったときだけ片方のセンサーをOFFにして、線をたどりながら角を探すことで解決した。
#define BORDER 40 //センサーの閾値 #define RUN_TIME 1000 int cross = 0; sub go() //前進 {OnFwd(OUT_A+OUT_C);} sub back() //後退 {OnRev(OUT_A+OUT_C);} sub turn_L() //左旋回 {OnFwd(OUT_C);OnRev(OUT_A);} sub turn_R() //右旋回 {OnFwd(OUT_A);OnRev(OUT_C);} sub turn_l() //左に進む {OnFwd(OUT_C);Off(OUT_A);} sub turn_r() //右に進む {OnFwd(OUT_A);Off(OUT_C);} sub count() //交差点カウント {cross++;PlaySound(SOUND_CLICK);} sub end() //停止 {Off(OUT_A+OUT_C);PlaySound(SOUND_DOWN);} void edge() //鋭角カーブ { cross = 0; while(cross!=1) { if(SENSOR_1 < BORDER) {turn_L();} if(SENSOR_3 < BORDER) {turn_R();} if(SENSOR_1 < BORDER && SENSOR_3 < BORDER){go();count();} if(SENSOR_1 > BORDER && SENSOR_3 > BORDER){go();} } ClearTimer(0); while(FastTimer(0) <= 500) { if(SENSOR_3 < BORDER) {turn_r();} if(SENSOR_3 > BORDER) {turn_L();} } PlaySound(SOUND_CLICK); while(SENSOR_3 > BORDER) { turn_L(); } } void normal(int t) //基本のライントレース { cross = 0; while(cross!=t) { if(SENSOR_1 < BORDER) {turn_L();} if(SENSOR_3 < BORDER) {turn_R();} if(SENSOR_1 < BORDER && SENSOR_3 < BORDER){go();Wait(30);count();} if(SENSOR_1 > BORDER && SENSOR_3 > BORDER){go();} } PlaySound(SOUND_UP); } void rotary() //ロータリーの動き { cross = 0; while(cross!=1) { if(SENSOR_1 < BORDER) {turn_L();} if(SENSOR_3 < BORDER) {turn_R();} if(SENSOR_1 < BORDER && SENSOR_3 < BORDER){go();Wait(20);turn_R();Wait(40);go();Wait(30);count();} if(SENSOR_1 > BORDER && SENSOR_3 > BORDER){go();} } while(cross!=2) { if(SENSOR_1 < BORDER) {turn_L();} if(SENSOR_3 < BORDER) {turn_R();} if(SENSOR_1 < BORDER && SENSOR_3 < BORDER){go();Wait(20);turn_L();;Wait(30);go();Wait(30);count();} if(SENSOR_1 > BORDER && SENSOR_3 > BORDER){go();} } while(cross!=3) { if(SENSOR_1 < BORDER) {turn_L();} if(SENSOR_3 < BORDER) {turn_R();} if(SENSOR_1 < BORDER && SENSOR_3 < BORDER){go();Wait(20);turn_R();;Wait(40);go();Wait(30);count();} if(SENSOR_1 > BORDER && SENSOR_3 > BORDER){go();} } PlaySound(SOUND_UP); } void hat() //帽子の部分 { ClearTimer(0); while(FastTimer(0) <= RUN_TIME) { if(SENSOR_1 < BORDER) {turn_l();} if(SENSOR_3 < BORDER) {turn_r();} if(SENSOR_1 > BORDER && SENSOR_3 > BORDER){go();} } PlaySound(SOUND_UP); } task main() { int L; SetSensor(SENSOR_1, SENSOR_LIGHT); SetSensor(SENSOR_3, SENSOR_LIGHT); for (L=1; L<=2; L++) //周回数 { normal(1); edge(); normal(2); rotary(); hat(); rotary(); normal(2); edge(); normal(1); } end(); }
何故一番冴えない私が両方の道を通らねばならぬのか(一周目通常、二周目近道)・・・早くからいろんな作例を参考に試行錯誤。何回も試すウチに、センサの条件付けを色々と簡略したり出来る事に気がついた。成るべく細部にプログラムを分けて、試験走行も部分的に行えた。なのでタスクメインもすっきり見やすくなった!それにエディタ?の自動字下げをオンにしてなすがままにインデントしてもらったら、それっぽい画面が仕上がった。その過程で気づいた事の一つに「elseの使い辛さ」がある。多分下手に使うよりはif多用した方が簡単で、字数も少ないと思う。また、こだわりとしては最初のバック走行。鋭角なんだからやってみたいと、最初期から考えていたので満足成。結構長くなってしまったが、前回と比べて自分のプログラムに進歩が見えた・・・?のは良かったかな、と。
#define T 40 #define W OUT_A+OUT_C #define R OnFwd(OUT_A);OnRev(OUT_C); #define L OnFwd(OUT_C);OnRev(OUT_A); #define BK OnRev(W); #define OFF Off(W); int X = 0; int CC = 0; void go(){OnFwd(W);} void COUNT(){CC++;PlayTone(210,20);} task main() { SetSensor(SENSOR_1, SENSOR_LIGHT); SetSensor(SENSOR_3, SENSOR_LIGHT); Wait(7*T); ASHI(); RUN(2); roll();//◆◆◆有頂天 PlayTone(1310,20); ClearTimer(0); while(FastTimer(0) <= 400 ) { if(SENSOR_1 < T) {OnFwd(OUT_C);Off(OUT_A);Wait(40);} if(SENSOR_3 < T) {OnFwd(OUT_A);Off(OUT_C);Wait(40);} if(SENSOR_1 > T && SENSOR_3 > T) {go();} if(SENSOR_1 < T && SENSOR_3 < T ) { L; Wait(30); go(); Wait(30); } } PlayTone(1310,20); while(FastTimer(0) >= 401 && FastTimer(0) <= 630 ) { go(); if(SENSOR_1 < T) {OnFwd(OUT_C);Off(OUT_A);} if(SENSOR_3 < T) {OnFwd(OUT_A);Off(OUT_C);} if(SENSOR_1 < T && SENSOR_3 < T ) { R; Wait(45); go(); Wait(170); } } PlayTone(1320,10); roll();//◆◆◆有頂天脱出 RUN(2); hajikko(); RUN(2); hajikko(); RUN(2); roll(); ClearTimer(0); while(FastTimer(0) <=1000 ) { if(SENSOR_1 < T) {OnFwd(OUT_C);Off(OUT_A);} if(SENSOR_3 < T) {OnFwd(OUT_A);Off(OUT_C);} if(SENSOR_1 < T && SENSOR_3 < T) { PlayTone(910,10);PlayTone(910,10); go();Wait(26);R;Wait(51);go();Wait(259);COUNT(); R;Wait(80); } if(SENSOR_1 > T && SENSOR_3 > T) {go();} } PlayTone(910,10); roll(); RUN(2); hajikko(); end(); } void roll() //ちはやロータリング { CC = 0; while(CC!=1) { if(SENSOR_1 < T) {L;} if(SENSOR_3 < T) {R;} if(SENSOR_1 < T && SENSOR_3 < T) { go(); Wait(20); R; Wait(40); go(); Wait(30); COUNT(); } if(SENSOR_1 > T && SENSOR_3 > T) {go();} } while(CC!=2) { go(); if(SENSOR_1 < T) {L;Wait(14);} if(SENSOR_3 < T) {R;} if(SENSOR_1 < T && SENSOR_3 < T) {go(); Wait(20); L; Wait(30); go(); Wait(30); COUNT(); } } while(CC!=3) { if(SENSOR_1 < T) {L;} if(SENSOR_3 < T) {R;} if(SENSOR_1 < T && SENSOR_3 < T) {go(); Wait(20); R; Wait(40); go(); Wait(30); COUNT(); } if(SENSOR_1 > T && SENSOR_3 > T) {go();} } PlayTone(540,15); } void ASHI()//アシ { ClearTimer(0); while ( Timer(0) <= 19 ) { if((SENSOR_1>T) && (SENSOR_3>T)) {BK;} if( (SENSOR_1>T) && (SENSOR_3<T) ) {R;} if( (SENSOR_1<T) && (SENSOR_3>T) ) {L;} if( (SENSOR_1<T) && (SENSOR_3<T) ) {BK;} } while ( (Timer(0) >= 19) && ( X <= 0 ) ) { if((SENSOR_1>T) && (SENSOR_3>T)) {BK;} if( (SENSOR_1>T) && (SENSOR_3<T) ) { BK; Wait(0); R; Wait(39); go(); Wait(34); X++; PlayTone(700,80); } if( (SENSOR_1<T) && (SENSOR_3>T) ) {L;} } } void hajikko() //つまさきmove'n on { CC = 0; while(CC!=1) { if(SENSOR_1 < T) {L;} if(SENSOR_3 < T) {R;} if(SENSOR_1 < T && SENSOR_3 < T) { go(); Wait(82); L; Wait(254); go(); Wait(47); COUNT(); } if(SENSOR_1 > T && SENSOR_3 > T) {go();} } } void RUN(int t) //トレース、、、オン { CC = 0; while(CC!=t) { if(SENSOR_1 < T) {L;} if(SENSOR_3 < T) {R;} if(SENSOR_1 < T && SENSOR_3 < T) {go();Wait(50);COUNT();} if(SENSOR_1 > T && SENSOR_3 > T) {go();} } PlaySound(SOUND_UP); } void end() ////Pushed Rice! { CC = 0; while(CC!=1) { if(SENSOR_1 < T) {L;} if(SENSOR_3 < T) {R;} if(SENSOR_1 < T && SENSOR_3 < T) {COUNT();} if(SENSOR_1 > T && SENSOR_3 > T) {go();} } OFF; PlayTone(240,15); PlaySound(SOUND_DOWN); PlayTone(840,15); }
■反省
「タイマーを多用しない方がいい」というのは電池の減りを目の当たりにして痛感。次回ではできるだけ避けたい。大分挙動が異なるので調整が頻繁に必要になったり。皮肉にもここで「プログラムを細かく分けておく」のが活躍。後になるほど恩恵を得た。もしまたライントレースをするなら、床と机など走らせる場所で結果が違わないものにしたい。ーーーこの辺りは講評でも指摘された点だし、練習課題のバンパーで学んだ事。wait実効中に他のプログラムが入らないため終わってみればズレてる、対アクシデントのプログラムは利用されることすらない、というもの。分かってはいる(つもりだ)が・・・これが難しかった。成程、戦車などが無人にならないのはやはりこういう融通が効かない・・・から?
ポイントごとにカウントを1つずつ増やしていくプログラムなので、左右対称のコースにもかかわらずヘアピンやロータリーの部分が1回目と2回目で別々のプログラムで汎用性はあまりないかも。しかもプログラムが長くなってしまった。
スピードを上げるために、右左折は全てお互いの車輪を逆方向に回して曲がる方法を採用。
工夫としてはポイントごとに「ド、レ、ミ、…、シ、ド、シ、…、レ、ド」と鳴るようにしてどのプログラムが作動しているかわかりやすいようにしたつもり。
#define BLACK 40 //閾値 #define SHORTCUT_TIME 300 //近道手前の移動時間 #define STRAIGHT_TIME 600 //2週目に入る前の軌道修正の時間 #define SE(t) PlayTone(t,20); //ポイントで音を鳴らす #define c 523 //ド #define d 587 //レ #define e 659 //ミ #define f 698 //ファ #define g 784 //ソ #define a 880 //ラ #define b 988 //シ #define C 1047 //高いド int count; //カウント sub go_ahead() //前進 {OnFwd(OUT_A+OUT_C);} sub go_back() //後退 {OnRev(OUT_A+OUT_C);} sub spin_right() //右折 {OnFwd(OUT_A); OnRev(OUT_C);} sub spin_left() //左折 {OnFwd(OUT_C); OnRev(OUT_A);} void switchback() //スタート〜鋭角 { while(count==0){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_back();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left(); Wait(30); go_ahead(); Wait(80); count++; SE(c);} } } void hairpin1() //ヘアピン(1) { while(count==1){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {spin_right();} if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK) {go_ahead(); Wait(30); count++; SE(d);} //Waitで線を通り過ぎないとカウント回数が増えてしまう } while(count==2){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {spin_right();} if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK) {go_ahead(); Wait(30); count++; SE(e);} } } void enter_rotary() //ロータリー進入 { while(count==3){ go_ahead(); if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK) {SE(f); go_ahead(); Wait(50); spin_right(); Wait(50); go_ahead(); Wait(10); count++;} } } void rotary1() //ロータリー(1) { while(count==4){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {go_ahead(); Wait(20); count++; SE(g);} } while(count==5){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {go_ahead(); Wait(50); spin_right(); Wait(45); count++; SE(a);} } } void corner1() //直角前 { ClearTimer(0); while(count==6 && FastTimer(0)<=SHORTCUT_TIME){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {spin_right();} } while(count==6 && FastTimer(0)>SHORTCUT_TIME){ //近道進入 if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {go_ahead(); Wait(60); spin_left(); Wait(50); go_ahead(); Wait(50); count++; SE(b);} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {spin_right();} } } void shortcut() //近道 { while(count==7){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead(); Wait(20);} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {spin_right();} if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK) {go_ahead(); Wait(50); spin_left(); Wait(50); go_ahead(); Wait(10); count++; SE(C);} } } void corner2() //直角後 { while(count==8){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {spin_right();} if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK) {go_ahead(); Wait(50); spin_right(); Wait(50); go_ahead(); Wait(10); count++; SE(b);} } } void rotary2() //ロータリー(2) { while(count==9){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {go_ahead(); Wait(20); count++; SE(a);} } while(count==10){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {go_ahead(); Wait(50); spin_right(); Wait(60); count++; SE(g);} } } void hairpin2() //ヘアピン(2) { while(count==11){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {spin_right();} if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK) {go_ahead(); Wait(50); count++; SE(f);} } while(count==12){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {spin_right();} if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK) {go_ahead(); Wait(30); count++; SE(e);} } while(count==13){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {go_ahead(); Wait(120); spin_right(); Wait(100); count++; SE(d);} if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK) {go_ahead();} } } void straight() //1周目〜2週目 { ClearTimer(0); while(count==14 && FastTimer(0)<=STRAIGHT_TIME){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {spin_right();} if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK) {go_ahead();} } while(count==14 && FastTimer(0)>STRAIGHT_TIME){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {go_ahead(); Wait(100); spin_right(); Wait(120); go_ahead(); Wait(70); count=count-13; SE(c);} if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK) {go_ahead();} } } void goal() //ゴール { while(count==14){ if(SENSOR_1 > BLACK && SENSOR_3 > BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK) {spin_left();} if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK) {go_ahead();} if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK) {Off(OUT_A+OUT_C); SE(c);} } } task main() { SetSensor(SENSOR_1,SENSOR_LIGHT); SetSensor(SENSOR_3,SENSOR_LIGHT); count = 0; switchback(); //スタート hairpin1(); enter_rotary(); rotary1(); corner1(); shortcut(); corner2(); rotary2(); hairpin2(); straight(); //1週目〜2週目 hairpin1(); enter_rotary(); rotary1(); corner1(); shortcut(); corner2(); rotary2(); hairpin2(); goal(); //ゴール }
最後に、コメントがありましたら何でもどうぞ!