[[2018a/Member]] 今回は、空き缶を運ぶロボットを製作した &ref(2018a/Member/Kkun/Mission2/IMG_20180720_164413541.jpg,50%,空き缶ロボ); #contents *今回の工夫 [#w83df397] ・急カーブは内側を通ると曲がり切ることが難しい。しかし、外側を通るとギリギリだが、回ることができる。~ また、今回採用した右/左側を通る方式には利点がある。~ 右側を通っている時に左回転の回数に制限を設けないことにより、右側をトレースしつつ反時計周りに急カーブを通る時、ラインを外側に外れてしまっても、その場で回転を続け、最終的にラインの右側に到達できるようになっている。~ &ref(2018a/Member/Kkun/Mission2/print.jpg,50%,軌跡);~ 上の図の赤線は、急カーブにおいて自分のロボットの中心が通る軌跡である *右/左のライントレースの設定 [#fc06b3c8] 例として、線の右を通る時の説明をする。~ 線の外側を通っているときは、マジックの色により光度が上がるので、その時は左に方向を修正することで、線の境を通るようにする。~ また、線の内側を通っているときは、光度が低いので、右に方向を修正して、境を通るようにする。~ ~ 自分は、光度の認識を5段階に分けて動かした。~ これによって、よりスムーズなライントレースが可能になった これによって、よりスムーズなライントレースが可能になった~ ~ また、ロボットが来た道に対して真っ直ぐになるように、大きく回ったときと小さく回った時の回数を別々にカウントし、交差点の認識をしたとき、回った角度だけ逆方向に回転する。 *交差点の認識 [#de993522] 交差点は、ある回数以上黒が続いたら、という定義にした。~ また、連続して回った角度の分だけ逆に回転させ、通常の体制に戻すことで、次の行動へと結びつけ易くした。~ こうすることで、交差点を直進する時も、少し前進した後に、同じプログラムを繰り返すだけで済むようにした。 *缶を掴む [#n9f9068e] 缶の置き場所は既にきまっているので、タッチセンサー等で感知する必要はなく、それらしい場所で腕を閉じるだけでよいはずだった。~ しかし、ライントレースは性質上真っ直ぐ進むことができないので、缶を掴むために直進するも、缶を倒したり、外してしまうことが多々あった。 *考察 [#c1105f15] 光センサーは意外にも繊細なもので、電気の明るさ、紙の色、また、ロボットのガタによる光の当たり方の違いなどで動作不良を起こした~ なので、家でもロボットをいじったが、結局学校で微調整をすることとなった~ ~ また、まとまった行動の終了時にロボットを真っ直ぐに直すことにより、次への繋がりをやりやすくしたのは、メインプログラムを簡易化でき、とても良かった~ ~ 上の図を見てもらうと分かるが、急カーブをライントレースをする際に、線の外側を通ってしまっているので、これはライントレースといっていいのかと、疑問に思った。~ しかし、急カーブの存在を知っているからといって、急なカーブを「直進」するときにプログラムを替えてしまったのでは、汎用性のあるライントレースではないと思った。~ なので、自分は今回のような方法を取ることにした。~ ~ 本音としては、光センサーを2つ使うことが出来れば、より正確で、線をはみ出さないライントレースができたと思う *まとめ [#taba4da5] 今回のロボットは思ったように動かすことが出来ず、走らせることが出来なかった。~ しかし、今回のライントレースプログラムでわかったこと、工夫したところは、次回のロボットにも活かせると思う~ だが、もう少しで動きそうだったので、もっと時間があるとよかった *プログラム [#pfa677ed] #define PA 20 #define PB 20 #define PC 20 #define PBC 20 #define BLACK2 50 #define BLACK1 55 #define GLAY 65 #define WHITE1 70 #define WHITE2 75 アームを開く関数 void OPEN() { RotateMotor(OUT_A, PA, 90); } アームを閉じる関数 void CLOSE() { RotateMotor(OUT_A, -PA, 90); } 左に90°回転する関数 void TURN_L() { RotateMotorEx(OUT_BC, PBA, 235, 100, true, true); } 右に90°回転する関数 void TURN_R() { RotateMotorEx(OUT_BC, -PBA, 235, 100, true, true); } 左にTURN_L1()よりも大きく回る関数 void TURN_L2() { RotateMotor(OUT_B, PB, 30); } 左に少し回る関数 void TURN_L1() { RotateMotor(OUT_B, PB, 15); } 少しだけ前進する関数 void FWD() { RotateMotorEx(OUT_BC, PBC, 30, 0, true, true); } x mmだけ前進する関数 void FWDMM(int x) { RotateMotor(OUT_BC, PBC, (x /10) * (750 / 35)) } 右に少し回る関数 void TURN_R1() { RotateMotor(OUT_C, PC, 15); } 右にTURN_R1()よりも大きく回る関数 void TURN_R2() { RotateMotor(OUT_C, PC, 30); } 左側の縁を通る関数 void STRAIGHT_L() { int i, j; //i,jは、左に回転した回数のカウンタである i = 0; j = 0; while((i + j) < 3){ if (SENSOR_1 < BLACK2){ if (SENSOR_1 < BLACK2){//真っ暗い場合、左に大きく回転する TURN_L2(); i++; }else if (SENSOR_1 < BLACK1){ }else if (SENSOR_1 < BLACK1){//薄暗い場合、左に少し回転する TURN_L1(); j++; }else if (SENSOR_1 < GLAY){ }else if (SENSOR_1 < GLAY){//ちょうどいい場合、直進する FWD(); i = 0; j = 0; }else if (SENSOR_1 < WHITE1){ }else if (SENSOR_1 < WHITE1){//白い場合、右に少し回転する TURN_R1(); i = 0; j = 0; }else {TURN_R2(); }else {TURN_R2();//真っ白い場合、右に大きく回転する i = 0; j = 0; } } RotateMotor(OUT_B, -PB, (i * 30 + j * 10)); //ここでロボットの向きを真っ直ぐにする } 右側の縁を通る関数 void STRAIGHT_R() { int i, j; //i,jは、右に回転した回数のカウンタである i = 0; j = 0; while((i + j) < 3){ if (SENSOR_1 < BLACK2){ if (SENSOR_1 < BLACK2){//真っ暗い場合、右に大きく回転する TURN_R2(); i++; }else if (SENSOR_1 < BLACK1){ }else if (SENSOR_1 < BLACK1){//薄暗い場合、右に少し回転する TURN_R1(); j++; }else if (SENSOR_1 < GLAY){ }else if (SENSOR_1 < GLAY){//ちょうどいい場合、直進する FWD(); i = 0; j = 0; }else if (SENSOR_1 < WHITE1){ }else if (SENSOR_1 < WHITE1){//白い場合、左に少し回転する TURN_L1(); i = 0; j = 0; }else {TURN_L2(); }else {TURN_L2();//真っ白い場合、左に大きく回転する i = 0; j = 0; } } RotateMotor(OUT_C, -PC, (i * 30 + j * 10)); //ここでロボットの向きを真っ直ぐにする } 右側の縁から左側の縁へ移る関数 void MOVE_L() { RotateMotor(OUT_B, PB, 180); RotateMotor(OUT_C, PC, 180); } 左側の縁から右側の縁へ移る関数 void MOVE_R() { RotateMotor(OUT_C, PC, 180); RotateMotor(OUT_B, PB, 180); }