指定の道をあらかじめ模造紙に描き、第1コース・第2コースそれぞれの道順に沿って製作したロボットを動かす。また、その途中に、350mlの空き缶を指定の位置から、指定の位置に運ぶ。
第2コース
1Aをスタート 2Bを右折 3Jで一時停止の後、Yの空き缶をキャッチしてJに戻る 4JからKに向かい、Kを直進 5Lを直進 6Iを左折 7Hで一時停止の後、左折 8Gで一時停止の後、右折 9Fで一時停止の後、右折 10Eを直進 11Dで一時停止の後、空き缶をXに置いてDに戻り、Cに向かう 12Cで一時停止の後、直進 13Bを直進 14Aで停止 (一時停止の指定がある場所は、1秒間停止すること)
課題1と同様、シンプルな3輪構造で、前輪が2輪、後輪が1輪となっている。前輪の2輪が駆動し、後輪の2輪が自由に回転する。
2つの車輪ほぼ真ん中前方に、確実に明るさを読み取れるような高さに設置した。
モータBに歯車を直接取り付け、 アームの動作は缶をつかむ動作、缶の方向を変える動作、缶を離す動作の3段階に分かれている。
モータBを稼働させるだけでは先にアームの方向が変わってしまうので、図のようにある程度固定し、缶をつかむ動作のみが稼働するようにした。
缶をつかむ動作を終えると缶をつかむ動きが固定され、缶の方向をかえる力が大きくなる。すると、上の図の部品が外れ、缶の方向が左に変わる。
缶の方向が変わると赤で囲まれた部分が回転し、それとともに黄で囲まれた部分が上昇し、回転部分にひっかかる。すると、缶の方向を変える部分が固定され、モータBを回すと、缶を離す。
今回、私は関数DAI(DAIに深い意味はない)を使って交差点を感知する方法として採用した。関数DAIは4つの範囲で図に示した数値を足されることになっている。
#define LEFT_LINE if(DEEPWHITE){RIGHT DAI -= 3;} else if(WHITE){BIT_RIGHT DAI -= 1;} else if(DEEPBLACK){LEFT DAI += 3;} else if(BLACK){BIT_LEFT DAI += 1;} else {STRAGHT DAI *= 0;} #define RIGHT_LINE if(DEEPWHITE){LEFT DAI -= 3;} else if(WHITE){BIT_LEFT DAI -= 1;} else if(DEEPBACK){RIGHT DAI += 3;} else if(BLACK){BIT_RIGHT DAI += 1;} else {STRAGHT DAI *= 0;}
プログラムのようにその時位置している範囲に従ってそれ相応の数値を足され、指定の方向へ移動する。どの範囲にも属さない時(丁度白と黒の境界にある時)は直進する。
右[#gabb9e62] #define RIGHT OnFwd(OUT_A,30);OnRev(OUT_C,30);Wait(1);Off(OUT_AC); 少し右[#f2a3eb93] #define BIT_RIGHT OnFwd(OUT_A,30);OnRev(OUT_C,10);Wait(1);Off(OUT_AC); 左[#yf200910] #define LEFT OnFwd(OUT_C,30);OnRev(OUT_A,30);Wait(1);Off(OUT_AC); 少し左[#m9a0ad8a] #define BIT_LEFT OnFwd(OUT_C,30);OnRev(OUT_A,10);Wait(1);Off(OUT_AC); 直線方向[#d825c59f] #define STRAGHT OnFwd(OUT_AC,30);Wait(1);Off(OUT_AC);
各方向に1000分の1秒進み、その時間毎に今存在している範囲を感知することで正確にライントレースできるようにした。
#define KANSU DAI < 150
ライントレース中は4つの範囲を行き来するのでほぼ±0に保たれ、交差点にさしかかるとDEEPBLACKの範囲上に比較的長時間存在するので関数DAIが増加し、関数DAIが150を超えると次の動作へうつる。 また、関数DAIを正確に測るためにライントレース前には"DAI *= 0"(関数DAIに0をかけて0にする)をする。
(例)右折
交差点を感知し、停止する。(図A) 85°くらい回転する。(図B)
while(BLACK){OnFwd(OUT_AC,20);}
地面がBLACKになるまで直進する。(図C) ライントレースする。
白 #define DEEPWHITE SENSOR_1 > 48 少し白 [#g54731d9] #define WHITE SENSOR_1 > 44 少し黒ece9d1] #define BLACK SENSOR_1 < 40 黒 [#hdece4ff] #define DEEPBLACK SENSOR_1 < 36 右[#gabb9e62] #define RIGHT OnFwd(OUT_A,30);OnRev(OUT_C,30);Wait(1);Off(OUT_AC); 少し右[#f2a3eb93] #define BIT_RIGHT OnFwd(OUT_A,30);OnRev(OUT_C,10);Wait(1);Off(OUT_AC); 左[#yf200910] #define LEFT OnFwd(OUT_C,30);OnRev(OUT_A,30);Wait(1);Off(OUT_AC); 少し左[#m9a0ad8a] #define BIT_LEFT OnFwd(OUT_C,30);OnRev(OUT_A,10);Wait(1);Off(OUT_AC); 直線方向[#d825c59f] #define STRAGHT OnFwd(OUT_AC,30);Wait(1);Off(OUT_AC);
※上のプログラムを組み合わせて図のように動作するようにした。
#define LEFT_LINE if(DEEPWHITE){RIGHT DAI -= 3;} else if(WHITE){BIT_RIGHT DAI -= 1;} else if(DEEPBLACK){LEFT DAI += 3;} else if(BLACK){BIT_LEFT DAI += 1;} else {STRAGHT DAI *= 0;} #define RIGHT_LINE if(DEEPWHITE){LEFT DAI -= 3;} else if(WHITE){BIT_LEFT DAI -= 1;} else if(DEEPBACK){RIGHT DAI += 3;} else if(BLACK){BIT_RIGHT DAI += 1;} else {STRAGHT DAI *= 0;} #define KANSU DAI < 150
それぞれ左・右のライントレース時に使うプログラム
#define OFF Off(OUT_AC);
#define WAIT Wait(1000);
車輪を止めるプログラムと停止するプログラム
#define CATCH OnFwd(OUT_AC,20);Wait(300);OFF OnFwd(OUT_B,30);Wait(300);Off(OUT_B);OnRev(OUT_AC,20);Wait(300);OFF
#define RELEASE OnFwd(OUT_B,30);Wait(1000);Off(OUT_B);Wait(500);OnRev(OUT_B,30);Wait(500);Off(OUT_B);
それぞれアームを閉開するプログラム
#define SIMPLE_RIGHT OnFwd(OUT_A,40);OnRev(OUT_C,40);
#define SIMPLE_LEFT OnFwd(OUT_C,40);OnRev(OUT_A,40);
それぞれ右・左にその場で旋回するプログラム
#define GO_STRAIGHT OnFwd(OUT_A,40);OnFwd(OUT_C,40);Wait(190);OFF #define MOVE_RIGHT SIMPLE_RIGHT Wait(750); OFF
#define GO_STRAIGHT OnFwd(OUT_A,40);OnFwd(OUT_C,40);Wait(190);OFF #define MOVE_LEFT SIMPLE_LEFT Wait(750); OFF
それぞれ交差点で右・左に曲がるプログラム
task main()
{ SetSensorLight(S1); int DAI=0; while(KANSU){ RIGHT_LINE } OFF DAI *= 0; //右ライントレース PlaySound(SOUND_DOWN); //音を鳴らす GO_STRAIGHT //少し直進 MOVE_RIGHT //右に85°曲がる while(KANSU){ RIGHT_LINE } OFF DAI *= 0; //右ライントレース PlaySound(SOUND_UP); //音を鳴らす WAIT //停止 CATCH //掴む OnFwd(OUT_B,10); //掴み続ける GO_STRAIGHT //少し直進 MOVE_LEFT //左に85°曲がる while(BLACK){ OnFwd(OUT_AC,20); } OFF //黒になるまで直進 repeat(2){ while(KANSU){ LEFT_LINE } OFF DAI *= 0; //左ライントレース SIMPLE_RIGHT Wait(50); OFF //微調整 while(BLACK){ OnFwd(OUT_AC,30); } OFF //黒になるまで直進 } while(KANSU){ LEFT_LINE } OFF //左ライントレース PlaySound(SOUND_UP); //音を鳴らす WAIT //停止 DAI *= 0; OnFwd(OUT_AC,30); Wait(50); OFF SIMPLE_LEFT Wait(450); OFF //微調整 while(KANSU){ LEFT_LINE } OFF DAI *= 0; //左ライントレース while(BLACK){ OnFwd(OUT_A,30);OnFwd(OUT_C,30); } OFF //黒になるまで直進 while(KANSU){ RIGHT_LINE } OFF DAI *= 0; //右ライントレース while(BLACK){ OnFwd(OUT_A,30);OnFwd(OUT_C,30); } OFF //黒になるまで直進 while(KANSU){ LEFT_LINE } OFF DAI *= 0; //左ライントレース GO_STRAIGHT //少し直進 MOVE_LEFT //左に85°曲がる while(KANSU){ LEFT_LINE } OFF DAI *= 0; //左ライントレース WAIT //停止 GO_STRAIGHT //少し直進 MOVE_RIGHT //右に85°曲がる while(BLACK){ OnFwd(OUT_A,30);OnFwd(OUT_C,30); } OFF //黒になるまで直進 while(KANSU){ RIGHT_LINE } OFF DAI *= 0; //右ライントレース WAIT //停止 PlaySound(SOUND_UP); //音を鳴らす GO_STRAIGHT //少し直進 MOVE_RIGHT //右に85°曲がる while(KANSU){ RIGHT_LINE } OFF //右ライントレース SIMPLE_RIGHT Wait(50); OFF //微調整 while(BLACK){ OnFwd(OUT_AC,30); } OFF //黒になるまで直進 while(KANSU){ RIGHT_LINE } OFF //右ライントレース Off(OUT_B); //掴み続けることをやめる WAIT //停止 RELEASE //離す OnFwd(OUT_AC,30); Wait(80); OFF SIMPLE_RIGHT Wait(500); OFF //微調整 while(KANSU){ RIGHT_LINE } OFF DAI *= 0; //右ライントレース GO_STRAIGHT //少し直進 MOVE_RIGHT //右に85°曲がる while(KANSU){ RIGHT_LINE } OFF DAI *= 0; //右ライントレース WAIT //停止 PlaySound(SOUND_UP); //音を鳴らす while(BLACK){ OnFwd(OUT_A,30);OnFwd(OUT_C,29); } OFF //黒になるまで直進 while(KANSU){ RIGHT_LINE } OFF DAI *= 0; //右ライントレース PlaySound(SOUND_FAST_UP); //音を鳴らす }
作成の過程では、センサーライトやアームを所定の位置に設置しつつ、全体のバランスを保つことが難しかった。また、アーム部分を1つのモータで2段階動かすことにこだわり過ぎて、時間と労力を使い過ぎた。プログラミングの過程では、交差点などを正常に通過させる確率を上げることが大変だった。
上では苦労したと書いたが、やはり、あらゆる工夫を取り込んで、1つのモータで2段階動かすことができたことがよかった。また、ライントレースに関数を使用することで安定して交差点を認識できるようにした。