ロボコン C4 |
350ml の中身の入ったアルミ缶を所定の場所から所定の場所まで移動させる。
☆詳しいこと★(ルール等)
1台が缶をスタート地点まで運び、スタート地点で缶の受け渡しをし、もう1台がスタート地点からゴールまで運ぶ。
真ん中の缶は前から捕らえ、両側の缶は障害物や角材を避けて斜め前から捕らえる。
障害物の排除はせず、障害物を避けるようにする。
ロボットの誘導ではライントレースを一部で行う。
最初に考えた方法もこの方法である。
ロボットの幅を小さくすることに成功し、1台が缶を運搬しもう1台が障害物を一時的に移動させるという構想に途中で変更したが、
フィールドの外側を板で囲うことが分かり、障害物を移動させるロボットを待機させる場所がなくなったため結局最初の構想に戻した。
ロボ制作日記を読む
1号機☆
スタートから缶を受け渡す所までを担当します。
2号機★
缶を受け渡されてから、ゴールに入れるまでを担当します。
1台で缶を運ぶという構想で途中まで製作していたため1号機のほうが幅が少し小さくなっているが、基本的な構造は同じ。
缶を転がす部分が前であるかのように見えるが実は後ろである。
どちらも後輪駆動で前輪はキャスタ。モータと後輪の間のギアは減速比3。
ロボコン前の課題でキャスタを用いたところ回転やコーナーリングがスムーズにできたので、今回も前輪にキャスタを用いた。
前輪付近には2つの光センサが、後部には缶を認識するタッチセンサと缶を転がす腕がある。
2号機には、缶が角材を乗り上げるようにタッチセンサの腕に階段状の部品が取り付けてある。
缶を捕らえる腕の動きは単純だが、1号機は捕らえる部分を大きくすることで、単純な動きで缶をしっかりと斜めからでも捕らえるようにした。
そこを大きくすると運搬中に缶の向きが変わってしまい受け渡し時にうまく転がらないことがあるが、
内側の2つのローラーにより缶の長手方向とロボットの直進方向が平行にならないようにしている。
2号機は受け取るだけなので、小さく構造も簡単になっている。
ロボットの構造がほぼ同じなので、プログラムも似ている。細かい動きではラインに頼らず、動く時間を指定している。
#define THRESHOLD 42 //閾値 #define thrtime 45 //黒線通過時間 #define offac Off(OUT_A+OUT_C); //停止 #define fwd OnFwd(OUT_A+OUT_C); //前進 #define rev OnRev(OUT_A+OUT_C); //後退 #define fwdright Off(OUT_A);OnFwd(OUT_C); //右前方へ #define fwdleft Off(OUT_C);OnFwd(OUT_A); //左前方へ #define revright Off(OUT_A);OnRev(OUT_C); //右後方へ #define revleft Off(OUT_C);OnRev(OUT_A); //左後方へ #define tracecond ((SENSOR_3>THRESHOLD)||(SENSOR_1>THRESHOLD)) //ライントレース条件 #define wht1 (SENSOR_1>THRESHOLD) //センサ1が白を認識 #define blk1 (SENSOR_1<=THRESHOLD) //センサ1が黒を認識 #define wht3 (SENSOR_3>THRESHOLD) //センサ3が白を認識 #define blk3 (SENSOR_3<=THRESHOLD) //センサ3が黒を認識 #define blk1a3 ((SENSOR_1<=THRESHOLD)&&(SENSOR_3<=THRESHOLD)) //センサ1,3両方がが黒を認識 #define snd PlaySound(SOUND_DOUBLE_BEEP); //音を鳴らす sub trace() //ライントレース { if(wht1&&wht3){fwd} if(blk1&&wht3){fwdright} if(wht1&&blk3){fwdleft} } sub turnleft() //左折 {fwd;Wait(25); OnRev(OUT_C);OnFwd(OUT_A);Wait(30);until(blk3);} sub turnright() //右折 {fwd;Wait(25); OnRev(OUT_A);OnFwd(OUT_C);Wait(30);until(blk1);} task message() //通信 {ClearMessage();while(Message()!=255){SendMessage(128);Wait(25);}} task main() //以下メインタスク { int i=1,time=0; SetSensor(SENSOR_1,SENSOR_LIGHT); //センサ1: 右光センサ SetSensor(SENSOR_2,SENSOR_TOUCH); //センサ2: タッチセンサ SetSensor(SENSOR_3,SENSOR_LIGHT); //センサ3: 左光センサ SetPower(OUT_A,7);SetPower(OUT_C,6);SetPower(OUT_B,7); //出力調整 OnRev(OUT_B);Wait(50); //腕をあげる。 repeat(3) //以下3回繰り返し。 { fwd;Wait(100);fwdright;Wait(60);fwdleft;Wait(60); //右によって、線を認識するまで直進し右折。 fwd;until(blk1a3);snd;turnright(); while(tracecond){trace();}snd;fwd;Wait(thrtime); //2つ目の交点に達するまでライントレースし、右折。 while(tracecond){trace();}snd;turnright(); while(tracecond){trace();}rev;Wait(50); //交点に達するまでライントレースし、0.5秒後退。 OnRev(OUT_A);OnFwd(OUT_C);Wait(40);until(blk1); //センサ1が線を認識するまで右回転。 if(i==1) //1回目の動作 { OnRev(OUT_C);OnFwd(OUT_A);Wait(5); //0.05秒左回転(位置調整)。 rev;until(SENSOR_2==1);offac;OnFwd(OUT_B);Wait(120);Off(OUT_B); //センサ2が押されるまで後退し、押されたら停止後腕を下ろし、一旦力を抜く。 fwd;Wait(50);OnFwd(OUT_B); //0.5秒前進し、腕に力をかける。 } if(i==2) //2回目の動作 { revleft;Wait(8);ClearTimer(0);rev;until(SENSOR_2==1);time=FastTimer(0); //左後方へ0.08秒動き、センサ2が押されるまで後退。後退時間を変数timeに記録。 offac;OnFwd(OUT_B);Wait(120);fwd;Wait(time);fwdleft;until(blk1); //停止して腕を下ろした後、time*10^-3秒間前進し、センサ1が線を認識するまで左前方へ。 } if(i==3) //3回目の動作 { rev;Wait(50);revright;Wait(20); ClearTimer(0);rev;until(SENSOR_2==1);time=FastTimer(0); //0.5秒後退し右後方へ0.2秒動いた後、センサ2が押されるまで後退。後退時間記録。 offac;OnFwd(OUT_B);Wait(120);fwd;Wait(time);fwdright;until(blk3); //停止して腕を下ろした後、time*10^-3秒間前進し、センサ3が線を認識するまで右前方へ。 } fwdleft;Wait(25);fwd;until(blk1a3);snd;turnleft(); //左に向きを変え、線を認識するまで直進し、左折。 while(tracecond){trace();}snd;fwd;Wait(thrtime); //2つ目の交点に達するまでライントレースし、左折。 while(tracecond){trace();}snd;turnleft(); while(tracecond){trace();}snd;start message; //交点に達するまでライントレースし、通信を開始。 turnleft();Wait(20);until(blk3);Wait(11); //左折を開始し、センサ3が2回線を認識するまで動く。 rev;Wait(90);stop message; //0.9秒間後退し、通信を終了。 OnRev(OUT_B);Wait(20);offac;Wait(80);i=i+1; //腕をあげ、停止。iに1を足す。 } offac; }
1つ目の缶を捕らえるときに一旦腕の力を抜いているが、これは腕の枠が両側の缶に当たっても車体が持ち上がってしまうのを防ぐためである。
車体が持ち上がると後輪が空転してしまい、動けなくなる。
#define THRESHOLD 42 //閾値 #define thrtime 45 //黒線通過時間 #define offac Off(OUT_A+OUT_C); //停止 #define fwd OnFwd(OUT_A+OUT_C); //前進 #define rev OnRev(OUT_A+OUT_C); //後退 #define fwdright Off(OUT_A);OnFwd(OUT_C); //右前方へ #define fwdleft Off(OUT_C);OnFwd(OUT_A); //左前方へ #define revright Off(OUT_A);OnRev(OUT_C); //右後方へ #define revleft Off(OUT_C);OnRev(OUT_A); //左後方へ #define tracecond ((SENSOR_3>THRESHOLD)||(SENSOR_1>THRESHOLD)) //ライントレース条件 #define wht1 (SENSOR_1>THRESHOLD) //センサ1が白を認識 #define blk1 (SENSOR_1<=THRESHOLD) //センサ1が黒を認識 #define wht3 (SENSOR_3>THRESHOLD) //センサ3が白を認識 #define blk3 (SENSOR_3<=THRESHOLD) //センサ3が黒を認識 #define blk1a3 ((SENSOR_1<=THRESHOLD)&&(SENSOR_3<=THRESHOLD)) //センサ1,3両方がが黒を認識 #define snd PlaySound(SOUND_DOUBLE_BEEP); //音を鳴らす sub trace() //ライントレース { if(wht1&&wht3){fwd} if(blk1&&wht3){fwdright} if(wht1&&blk3){fwdleft} } sub turnleft() //左折 {fwd;Wait(27); OnRev(OUT_C);OnFwd(OUT_A);Wait(30);until(blk3);} sub turnright() //右折 {fwd;Wait(27); OnRev(OUT_A);OnFwd(OUT_C);Wait(30);until(blk1);} task message() //通信 {ClearMessage();until(Message()==128);repeat(12){SendMessage(255);Wait(25);}} task main() { SetSensor(SENSOR_1,SENSOR_LIGHT); //センサ1: 右光センサ SetSensor(SENSOR_2,SENSOR_TOUCH); //センサ2: タッチセンサ SetSensor(SENSOR_3,SENSOR_LIGHT); //センサ3: 左光センサ SetPower(OUT_A,5);SetPower(OUT_C,7);SetPower(OUT_B,7); //出力調整 Wait(50); while(true) //以下繰り返し。 { start message;OnFwd(OUT_B);Wait(10);Float(OUT_B);until(Message()==128); //出力を1号機からの通信を待つ。 OnRev(OUT_B);until(SENSOR_2==1);stop message; //通信ができたら腕を上げ、センサ2が押されるまで待つ。 OnFwd(OUT_B);Wait(100); //センサ2が押されたら腕を下ろす。 fwdleft;Wait(62);fwdright;Wait(44); //左によって、線を2本横断するまで直進し、左折。 fwd;until(blk1a3);snd;Wait(thrtime);until(blk1a3);snd;turnleft(); while(tracecond){trace();}snd;fwd;Wait(thrtime); //2つ目の交点までライントレースし、右折。 while(tracecond){trace();}snd;turnright();Wait(3);offac; OnRev(OUT_B);Wait(100);rev;Wait(400); //腕を上げ、4秒後退。ゴールっ…。 fwdright;Wait(79); //右前方に0.79秒動き、線を2本横断するまで直進。 fwd;until(blk1a3);snd;Wait(thrtime);until(blk1a3);snd; turnleft();Wait(2);rev;Wait(150);offac; //左折し、1.5秒直進して停止。 } offac;Off(OUT_B); }
2号機は同じ動きを繰り返すだけのものであり、またゴール時に角材に向かって直進することで向きを確実に決め直すことができるため調整が簡単で、
ライントレースは缶をゴールに運ぶ時に少し行うだけで済んだ。
本番では受け渡しに失敗したため、結局1つも運べず2号機が活躍する前に終わった。
このような結果になった最も大きな原因は、欲張り過ぎて基本がおろそかになっていたことであると考えられる。
最初の時点でいきなり欲張り3つすべてを素早く運ぶことを目標とし、速度を上げて不安定さに気付かないままキャスタを用いたため、
基本的なことである「正確な動き」ができなくなってしまった。この不正確さがプログラムの改良で補えないほどのもので、
さらにこの問題に気づいたのが調整段階に入ってからでロボットの改良が間に合わず、あのような結果となった。練習でも3つすべては運べなかった。
まず簡単なことを目標にし、基本的なことができるようになってから上を目指すようにすべきだった。
コメントをどうぞ。