目次
きたざわ
ユウジ
今回の課題は「ライントレーサー兼空き缶運びロボット」です。詳しい課題内容は課題2をご覧ください。
空き缶の移動のさせ方がそれぞれ違います。
・きたざわ→空き缶を次の交差点まで運んで行き、その交差点に空き缶を残してさらにコースに沿って進む。
・ユウジ→空き缶をコース上に戻して再びコースに戻って進む。
完成したロボットがこちらです。
前のパーツを簡単に取り外すことができないので、外す必要が無くなるようNQCのCPUをわざと反対向きに取り付けました。↑
CPU前部に、CPUにプログラムを送るためのセンサーがあるためです。
走行中、後述するタッチセンサーのバンパーに空き缶が当たると、左右のアームが閉じ、空き缶を掴みます。
光センサーを2つ付け、その間に線をはさんで走行します。また、公差点で道が途絶えているところにはT字路があり、そこで両方のセンサーが反応したら、線を無視して直進し、離れた線まで進みます。
3つだけしかモーターを使えないので、配分は、タイヤに2つ、ハサミ(空き缶を掴む部分)に1つ、ということになります。1つのモーターでハサミを動かすために、次の写真のような仕組みを考えました。
回す軸を左右に伸ばし、同じ仕組みのギアの仕組みを左右に付けることにより、同時に動き、なおかつそれぞれが逆に動くので、ハサミにぴったりな動きをさせることができました。
1つのタッチセンサーで広範囲をカバーするため、以下の写真の仕組みにしました。オレンジの方向に力が加わると、センサーが反応するようになっています。
空き缶がぶつかったことを感知するためにタッチセンサーを付けるのですが、ハサミの開閉に影響がでないよう、バンパーの位置をハサミの間にしています。
また、ちょうど真ん中の高さにバンパーがあるので、空き缶に当たったときに、しっかりと反応します。
ハサミパーツを作る上で、軸を縦方向にしたいために、レゴブロックを横向きに使う必要がありました。
このパーツを固定するために、始めは同じ向きで固定して使用する光センサーのブロックとだけ固定されていました。(赤丸内のところ)
しかし固定している部分が少なすぎたため、モーターを動かした瞬間にハサミパーツは外れました。
そこで本体上部とハサミパーツを連結させました。
走行するときに、ライントレースの特性上、発進→方向転換(ほぼ急ブレーキ)、を繰り返すため、ロボがつんのめってしまい、タッチセンサーの誤作動が起きてしまいました。
そこでロボ前方に支えを作ることにしました。光センサーと地面との隙間を無くし、安定して走るようにしたのが下の写真です。
先ほど述べたように、ライントレース走行の勢いにより、タッチセンサーのバーが大きく揺れ、その反動によりタッチセンサーが誤作動することがたびたび起きました。
そこで軸パーツを使い、バーが前方へ動くことを防ぐことで、大きな揺れが起こることを防ぎました。
図の流れで動かします。
#define go OnFwd(OUT_A+OUT_C); //まっすぐ進む #define back OnRev(OUT_A+OUT_C); //まっすぐ下がる #define stoping Off(OUT_A+OUT_C); //動きを止める #define spin_r OnFwd(OUT_C);OnRev(OUT_A); //右旋回 #define spin_l OnFwd(OUT_A);OnRev(OUT_C); //左旋回 #define open OnFwd(OUT_B);Wait(30);Off(OUT_B); //アームを開く #define close SetPower(OUT_B,0);OnRev(OUT_B); //アームを弱い力で閉じ続ける(空き缶を持って移動中、アームが開いてしまわないように) #define eye_r SENSOR_1 //SENSOR_1の名称をeye_rと定義 #define eye_l SENSOR_3 //SENSOR_2の名称をeye_lと定義 #define boundary_r 42 //右光センサーの黒白判断の境目の値(部屋の明るさで大きく左右されるので、すぐ訂正できるよう定義しておく) #define boundary_l 50 //左光センサーの黒白判断の境目の値(部屋の明るさで大きく左右されるので、すぐ訂正できるよう定義しておく) task line_run() { //ライントレース用のタスクです SetSensor(eye_r,SENSOR_LIGHT); //eye_rは光センサーと定義 SetSensor(eye_l,SENSOR_LIGHT); //eye_lも光センサーと定義 while(true) { go; //普段はライントレースしながら進む if(eye_r<boundary_r) { //もし右光センサーが線に当たったら spin_r; //右旋回 until((eye_r>boundary_r)||((eye_r<boundary_r)&&(eye_l<boundary_l))); //右光センサーが線を離れるか、両方のセンサーが反応するまで(T字路) } if(eye_l<boundary_l) { //もし左光センサーが当たったら spin_l; //左旋回 until((eye_l>boundary_l)||((eye_r<boundary_r)&&(eye_l<boundary_l))); //左光センサーが線を離れるか、両方のセンサーが反応するまで(T字路) } if((eye_r<boundary_r)&&(eye_l<boundary_l)) { //もし両方のセンサーが反応したら(T字路に到着) PlaySound(SOUND_DOUBLE_BEEP); //まず音を出す(わかりやすいように) stoping;Wait(200); //課題の通り2秒間停止 go;Wait(100); //まっすぐ進み向かい側の線へ } } } task main() { SetSensor(SENSOR_2,SENSOR_TOUCH); //SENSOR_2をタッチセンサーと定義 ClearTimer(0); //タイマーで時間を計り始める start line_run; //走る until(SENSOR_2==1); //タッチセンサーが反応するまで(1つめの空き缶と接触) stoping; //一度止まる stop line_run; close; //空き缶をつかむ start line_run; //再び走る until((eye_r<boundary_r)&&(eye_l<boundary_l)); //両方の光センサーが反応するまで(T字路到着) PlaySound(SOUND_DOUBLE_BEEP); //わかりやすいように音 stoping; //止まって stop line_run; //ライントレースのタスクを一度止めます go;Wait(180); //少し進んで spin_r;Wait(164); //180度回転 open; //空き缶を線の上に置きます back;Wait(60); //下がって spin_r;Wait(100); //方向を修正(ここで線の上に復帰) start line_run; //再び走る until(SENSOR_2==1); //タッチセンサーが反応するまで(2つめの空き缶と接触) stoping; //止まる stop line_run; close; //空き缶つかむ start line_run; //再び走る until((eye_r<boundary_r)&&(eye_l<boundary_l)); //両方の光センサーが反応するまで(T字路到着) PlaySound(SOUND_DOUBLE_BEEP); //わかりやすいように音 stoping; //止まって stop line_run; //ライントレースのタスクを一度止めます go;Wait(150); //少し進んで spin_r;Wait(164); //反転 open; //空き缶を置く back;Wait(60); //下がって spin_r;Wait(70); //方向修正 go;Wait(30); //少し進む(ここで線の上に復帰) stoping; while(FastTimer(0)<=5200) { //タイマーが52秒以上になるまで start line_run;Wait(100); //1秒間ライントレースを繰り返す stoping; stop line_run; } }
空き缶を置いた後に進む道2つがかなり異なっていたため、復帰するためのプログラムが別々なものになり、全体的にかなり長いプログラムになってしまい残念でした。
一周して止まるのに使った最後のプログラムでは、止まるべき時間から最大1秒近くの誤差ができてしまいます。センサーを使って停止するなど、もう少し正確に停止できればよかったと思います。
#define Turn_R OnRev(OUT_A); //右タイヤを後退 #define Turn_L OnRev(OUT_C); //左タイヤを後退 #define Light_R 40 //右の光センサーの閾値 #define Light_L 50 //左の光センサーの閾値 #define Tomare Off(OUT_A+OUT_C); //停止 #define go OnFwd(OUT_A+OUT_C); //前進 #define Eye_R SENSOR_1 //右の光センサ #define Eye_L SENSOR_3 //左の光センサ #define BUMPER SENSOR_2 //バンパーを定義 #define Get OnRev(OUT_B);Wait(30);Off(OUT_B); #define carry OnRev(OUT_A);OnFwd(OUT_C);Wait(190);OnFwd(OUT_A);Wait(20);Off(OUT_A+OUT_C); #define carry2 OnFwd(OUT_B);Wait(30);Off(OUT_B); #define fin OnRev(OUT_A+OUT_C);Wait(80);OnFwd(OUT_C);Wait(195);OnRev(OUT_C);Wait(80);Off(OUT_A+OUT_C); #define RUN_TIME 660 //時間を定義 task main() { //メインのタスク SetPriority(1); //優先順位を設定 SetSensor(BUMPER,SENSOR_TOUCH); //タッチセンサーを定義 SetSensor(Eye_R, SENSOR_LIGHT); //右の光センサーを定義 SetSensor(Eye_L, SENSOR_LIGHT); //左の光センサーを定義 ClearTimer(0); //タイマーをリセット while( Timer(0) <= RUN_TIME ) { //定義した時間を越えるまで続ける start follow_line; //もう一つのtaskを使用 until (BUMPER == 1); //タッチセンサが反応するまで acquire(ACQUIRE_OUT_A+ACQUIRE_OUT_C){ Get;Wait(35);carry;Wait(35);carry2;Wait(35);fin;Wait(35); //缶を運ぶ一連の動作 Tomare; } } Tomare; } task follow_line() //有線順位の低いtask(光センサー専用タスク) { SetPriority(2); //優先順位を設定 while ( Timer(0) <= RUN_TIME ) {acquire(ACQUIRE_OUT_A+ACQUIRE_OUT_C){ if ((Eye_R < Light_R)&&(Eye_L > Light_L)) //右の光センサが反応したら { Turn_R; Wait(15); Tomare; } else if ((Eye_L < Light_L)&&(Eye_R > Light_R)) //左の光センサが反応したら { Turn_L; Wait(15); Tomare; } else if ((Eye_R < Light_R)&&(Eye_L < Light_L)) //両方同時に反応したら { Tomare;Wait(50); go;Wait(100);Tomare; } else{ go;} Wait(1);} } Tomare;}
組み立てたロボットを実際に動かしてみて、初めて発覚する問題点がかなりありました。 ロボの問題点を克服させる作業が大変でしたが、楽しい部分でもありました。
最初taskを複数使いこなせず、大変苦労しました。また、ロボットを動かしている時に本体が揺れてしまい勝手にタッチセンサーが反応してうまく行かないときもありました。しかし自分たちで工夫して問題点をクリアすることができ、とてもやりがいのある課題でした。
このページについてコメントをよろしくお願いします。