2011b

目次一覧

メンバー

t.s .... 工学部機械システム工学科。物作りはとても好きです。

ひろ.... 工学部情報工学科。プログラミングにも慣れてきた。

今回の課題

光センサーを用いてライントレースするロボットをつくる。 ただしコースの条件は以下のとおりである。

  • 通常の交差点が2箇所以上ある
  • ロータリー型の交差点が1箇所以上ある (ロータリーでは反時計まわりに進む)
  • 直角に曲がるコーナーおよびそのコーナーをショートカットするコース(点線)が存在する
  • 急なヘアピンカーブが1箇所以上ある
  • スタート地点に目印がある
  • 黒い線の幅は15〜20mm程度

ロボットの特徴

ギアを重ねたり、全体を重くしたりすることで、正確性に重点を置いた中型のロボット。また、片方のセンサーを動かせるようにしたことで、コース上のあらゆる条件を満た しやすくした。

全体の画像

通常の走行において、タイヤ1つにつきモーターを一つセットした。 しかし、単に軸を通しただけだとV字開脚となり、全体が地面に擦れてしまう可能性があったので、真ん中には丈夫なパーツを用いて、軸を固定するようにしてある。

車体

センサーは片方にだけ180度回転するようにしてある。ゆっくりと正確に動かすために、ギアをうまく噛み合わせたりウォームギアを用いて、ゆっくりと動かすようにした。この動くセンサーはプログラムによっては強引に押し込んでしまう可能性があるので、真ん中のギアは一定の力がかかると空回りする特殊なギアを使用。

前のギア

後ろ側は摩擦が大きいと進みにくくなるため、地面に触れる足を二本から一本に減らし、さらに先端になめらかな面を持つパーツを用いた。

後ろの足

このロボットは互いのセンサーが白である時に直進し、片方だけ黒が触れた場合は黒い線に沿って曲がる。そして両方が黒であった時前進か後退をして、そのあとに片方のセンサーが動き、前方の道をサーチする。

進み方

進み方2

反省点

  • 進んだ量を測る事が出来ない。一定量進むために、Waitを使わなければならなかった。対策として、回転センサーを動力部につけようとした。しかし、左右で、進む量が変わったので、失敗した。キャスターに取り付ければWaitを使わずに進めたと後悔した。

コース概要

コース全体

上の図のコースは左側に道が密集しており、センサーの幅を用いて動作するロボットにとっては厄介なコースである。赤い丸はロータリー・青い丸は鋭角・緑の丸は近道を含んだコース・紫の丸は交差点である。

  • ロータリーは反時計回りに進み、半周した後脱出できるようにする必要がある。 交差点と比べて、ロータリーは両方黒になった時、真中は黒が全くないので、そこを利用した。
  • 鋭角は非常に曲がりづらく、確率で鋭角の外側の黒い線に引っかかってしまう。鋭角を通り過ぎても、次の交差点に入る前に左側の黒い線に衝突してしまう。
  • 一周目は通常ルート、二周目は近道は通らなければならない。近道を判断できるようプログラムし、それぞれ2つのプログラムによってルートを決めるようにしている。
  • 交差点は黒い線の上をトレースするロボットの場合難しくはないが、白い上を2つのセンサーで走るロボットの場合、意外と厄介な障害物である。交差点は数センチ前に黒い線があるため、そこを利用した。

このほかにも、左からスタートの場合鋭角の地点でおおめに曲がらないと、黒い線同士の幅が狭く、両方黒になってしまう。交差点でないところで交差点と判断してしまったり、センサーの位置が少しずれたり、プログラムを少しでもミスしたりすると一周できなかったりと、かなり厄介なコースとなっている。

プログラム

t.s

このプログラムの特徴は、両方黒い線に触れたとき、大まかに前進して、その後止まる。 その時、交差点と近道の道の幅の特徴を用いて、両方が黒であったとき、近道と判断して近道専用のプログラムを開始。そうでなければ、またさらに少し前進して、奥の線の数を時間さで調べる。調べた後、黒の数が一本であったときは交差点、一本もなかったときはロータリー、(ただしこの時、どちらかのセンサーかが黒であったとき、鋭角)二本以上であったときはスタートと判断する。この様に、二段階に分けて、すべての障害物を判断している。

  
#define IKT 45//閾値(明るさ判断)
#define POW 20//両方が黒であるときに前進する量	
#define G_TIME 0//誤差修正
#defineRORTARY();Rot++;while(SENSOR_1>IKT)
{OnRev(OUT_C);OnFwd(OUT_A);}OnFwd(OUT_C);Off(OUT_A);Wait(60);
#define TIKAMITI_1();tika=1;
#define TIKAMITI_2();tika2=1;
sub MAE()//両方黒の時、一歩前に前進
{OnFwd(OUT_A+OUT_C);
Wait(POW);
Off(OUT_A+OUT_C);
}
sub IPOMAE()//近道でないときの前進
{OnFwd(OUT_A+OUT_C);
Wait(5);
Off(OUT_A+OUT_C);
}
sub SEAMAE()//サーチ前
{OnFwd(OUT_B);
Wait(100+33*G_TIME);
Off(OUT_B);
}
sub SEAEND()//サーチ終了
{OnRev(OUT_B);
Wait(860+33*G_TIME);
Off(OUT_B);
}
task main()
{
SetSensor (SENSOR_1,SENSOR_LIGHT);
SetSensor (SENSOR_3,SENSOR_LIGHT);
int sens=0;
int Rot=0;
int TKMT=0;
int kuro=0;
int count=0;
int tika=0;
int tika2=0;
OnRev(OUT_B);
Wait(30+G_TIME);
Float(OUT_B);
while(true){
SetPower(OUT_A,7);
SetPower(OUT_C,7);
OnFwd(OUT_A+OUT_C);//通常走行
Wait(2);
Float(OUT_A+OUT_C);
Wait(1);
if(sens==0&&SENSOR_3<=IKT&&Rot!=0){	//ロータリー
			sens++;
			OnFwd(OUT_C);
			Off(OUT_A);
			Wait(55+G_TIME);
			PlaySound(SOUND_CLICK);Wait(5+G_TIME);
					}
		if(Rot!=0&&SENSOR_1<=IKT&&SENSOR_3<=IKT){
			Rot=0;
			sens=0;
			OnFwd(OUT_A);
			Off(OUT_C);
			Wait(50+G_TIME);
			while(SENSOR_1>IKT){
				OnFwd(OUT_A);
				Off(OUT_C);
						}
								}
if(SENSOR_1<=IKT&&SENSOR_3<=IKT&&tika>=1&&tika<3){  //近道1
PlaySound(SOUND_CLICK);Off(OUT_A+OUT_C);
OnFwd(OUT_C);until(SENSOR_3>IKT);OnRev(OUT_A);Wait(20);tika++;}
if(SENSOR_1<=IKT&&SENSOR_3<=IKT&&tika>=3){
PlaySound(SOUND_CLICK);tika=0;}
if(SENSOR_1<=IKT&&SENSOR_3<=IKT&&tika2>=1&&tika2<3){ //近道2
PlaySound(SOUND_CLICK);Off(OUT_A+OUT_C);
OnFwd(OUT_A);until(SENSOR_1>IKT);OnRev(OUT_C);Wait(20);tika2++;}
if(SENSOR_1<=IKT&&SENSOR_3<=IKT&&tika2>=3){
PlaySound(SOUND_CLICK);tika2=0;}
while(SENSOR_1<=IKT&&SENSOR_3>IKT){//左に曲がるとき 
OnRev(OUT_A+OUT_C);  
}
while(SENSOR_3<=IKT&&SENSOR_1>IKT&&Rot==0){//右に曲がるとき
OnRev(OUT_C);                       	
} 
while(SENSOR_1<=IKT&&SENSOR_3<=IKT&&Rot==0&&tika==0&&tika2==0){	//黒い線が両方触れたとき
MAE();
if(SENSOR_1<=IKT&&SENSOR_3<=IKT){//サーチ前に両方黒い線に触れた(近道と判断)
PlaySound(SOUND_DOWN);
if(count==0){//一周目の時
TIKAMITI_1();
		
}
if(count>0){//二周目以降
TIKAMITI_2();
}
				}
else{	//サーチ前に両方黒い線に触れなかった(近道意外と判断)
IPOMAE();
ClearTimer(0);
kuro=0;
SEAMAE();
                               
while(FastTimer(0)<=750+33*G_TIME&&tika==0&&tika2==0){//サーチ中
OnFwd(OUT_B);

if(SENSOR_1<=IKT){
PlaySound(SOUND_LOW_BEEP);
kuro++;
Wait(500+33*G_TIME);
          }        
                                             }
SEAEND();
if(kuro==1){	//サーチしたときの黒い線の数が1本(交差点と判断)
PlaySound(SOUND_UP);
OnFwd(OUT_A+OUT_C);
Wait(30+G_TIME);
break;                                
 }
if(kuro>=2){//サーチしたときの黒い線の数が2本(スタートと判断)   
count++;
PlaySound(SOUND_UP);
OnFwd(OUT_A+OUT_C);
Wait(55+G_TIME);
break;
}                                            
if(kuro==0){//サーチしたときの黒い線の数が0本(ロータリーか鋭角)
PlaySound(SOUND_FAST_UP);
if(SENSOR_3<=IKT){	//もし鋭角であれば(右)
OnFwd(OUT_C);
until(SENSOR_3>IKT);
Wait(30+G_TIME);
Off(OUT_C);
OnRev(OUT_A);
Wait(70+G_TIME);
break;
		}
if(SENSOR_1<=IKT){//もし鋭角であれば(左)
OnFwd(OUT_A);
until(SENSOR_1>IKT);
Wait(30+G_TIME);
Off(OUT_A);
OnRev(OUT_C);
Wait(70+G_TIME);
break;
                    }
else {//もしロータリーであれば
RORTARY();
break;
      }
		}
}                                       
                             }                        	
              }
}

ひろ

#define IKT 45//閾値(明るさ判断)
#define t 780//bを巻戻す時間
sub turn_r(){	//右折
	OnFwd(OUT_A);
	Off(OUT_C);
}
sub turn_l(){	//左折
	OnFwd(OUT_C);
	Off(OUT_A);
}
sub turn_rb(){	//バックで右折
	OnRev(OUT_C);
	Off(OUT_A);
}
sub turn_lb(){	//バックで左折
	OnRev(OUT_A);
	Off(OUT_C);
}
task main()
{
	SetSensor (SENSOR_1,SENSOR_LIGHT);
	SetSensor (SENSOR_3,SENSOR_LIGHT);
	int go=1;	//0:ロータリー、1:十字
	int sens=0;	//ロータリーの右を1回飛ばす
	int Rot=0;	//ロータリーに入っているなら!=0
	int tika=0;	//近道に入っているなら!=0
	int count=0;	//何周したか
	int l=0;	//1なら最後に左折
	int r=0;	//1なら最後に右折
	int ex_turn=0;	//急カーブを曲がる調整をしたら1、急カーブをしたら0
	int time=0;	//巻き戻しの時間
	SetPower(OUT_A,7);SetPower(OUT_B,7);SetPower(OUT_C,7);	//出力調整
	OnRev(OUT_B);
	Wait(50);
	while(true){
		if(count==2){	//二周目が終わる
			Off(OUT_A+OUT_B+OUT_C);	//停止
			break;
		}
		OnFwd(OUT_A+OUT_C);	//左右のセンサーが白なら前進
		Wait(3);
		Float(OUT_A+OUT_C);
		Wait(1);
		Off(OUT_B);
		if(sens==0&&SENSOR_3<IKT&&Rot!=0){//ロータリーで右を1回飛ばす
			sens=1;
			while(SENSOR_3<IKT){
				turn_l();
			}
			Wait(20);
			PlaySound(SOUND_CLICK);Wait(5);
		}
		if(Rot!=0&&SENSOR_1<IKT&&SENSOR_3<IKT){	//ロータリーを出る
			Rot=0;
			sens=0;
			while(SENSOR_1<IKT){
				turn_r();
			}
			Wait(20);
			while(SENSOR_1>IKT){
				turn_r();
			}
		}
		if(tika!=0&&count!=0&&SENSOR_1<IKT&&SENSOR_3<IKT){//近道&2周目、両方黒で左の黒を無視
			turn_r();Wait(70);
			if(tika==2){
				tika=0;
			}
			if(tika==1){
				tika++;
			}
		}
		if(tika!=0&&count==0&&SENSOR_1<IKT&&SENSOR_3<IKT){	//近道&1周目、両方黒で右の黒を無視
			turn_l();Wait(70);
			if(tika==2){
				tika=0;
			}
			if(tika==1){
				tika++;
			}
		}
		ClearTimer(0);
		while(SENSOR_1<IKT&&SENSOR_3>IKT){	//左折
			if(FastTimer(0)>55){	//たくさん曲がると急カーブ
				ex_turn=0;
				turn_lb();
				PlaySound(SOUND_CLICK);
			}
			if(FastTimer(0)<17){
				turn_l();
				l=1;
				r=0;
			}
			else{
				turn_lb();
			}
		}
		ClearTimer(0);
		while(SENSOR_3<IKT&&SENSOR_1>IKT&&Rot==0){	//右折
			if(FastTimer(0)>55){	//たくさん曲がると急カーブ
				ex_turn=0;
				turn_rb();
				PlaySound(SOUND_CLICK);
			}
			if(FastTimer(0)<17){
				turn_r();
				r=1;
				l=0;
			}
			else{
				turn_rb();
			}
		}
		while(SENSOR_1<IKT&&SENSOR_3<IKT&&Rot==0&&tika==0){//両方黒でロータリー、近道をしてない時
			if(l==1&&ex_turn==0){//最後に左折した時、両方黒になったら
				OnRev(OUT_A+OUT_C);
				Wait(25);
				while(SENSOR_3>IKT&&SENSOR_1>IKT){//ラインがロボットの中心より右にある時、中心より左にすると急カーブできる
					turn_rb();
				}
				ex_turn=1;
				PlaySound(SOUND_CLICK);
				break;
			}
			if(r==1&&ex_turn==0){//最後に右折した時、両方黒になったら
				OnRev(OUT_A+OUT_C);
				Wait(25);
				while(SENSOR_1>IKT&&SENSOR_3>IKT){//ラインがロボットの中心より左にある時、中心より右にすると急カーブできる
					turn_lb();
				}
				ex_turn=1;
				PlaySound(SOUND_CLICK);
				break;
			}
			else{	//急カーブの調整をしても両方黒になった時
				ex_turn=0;
				OnRev(OUT_A+OUT_C);
				Wait(27);
				while(SENSOR_1<IKT||SENSOR_3<IKT){
					OnFwd(OUT_A+OUT_C);
				}
				Off(OUT_A+OUT_C);
				ClearTimer(0);
				while(FastTimer(0)<t&&tika==0){//近道の判定
					OnFwd(OUT_B);
					if(SENSOR_1<IKT&&FastTimer(0)<t&&tika==0){//黒線の長さを測る
						PlaySound(SOUND_CLICK);
						OnFwd(OUT_B);
						Wait(235);
						PlaySound(SOUND_UP);
						ClearTimer(1);
						while(SENSOR_1>IKT&&FastTimer(1)<120){//近道なら長い白
							OnFwd(OUT_B);
							Wait(12);
							if(SENSOR_1<IKT){
								tika=0;
								break;
							}
							tika=1;PlaySound(SOUND_DOWN);
						}
						if(SENSOR_1<IKT){//それ以外は黒
							break;
						}
					}
				}
				time=FastTimer(0);
				if(FastTimer(0)>12){//動かした量だけ巻き戻しをする
					OnRev(OUT_B);
					Wait(time-12);
				}
				OnFwd(OUT_A+OUT_C);
				Wait(22);
				Off(OUT_B);
				if(tika==0){//ロータリーか十字かスタートの判定
					go=1;
					Wait(38);
					Off(OUT_A+OUT_C);
					ClearTimer(0);
					while(SENSOR_1>IKT&&SENSOR_3>IKT&&FastTimer(0)<t){	//黒を探す
						OnFwd(OUT_B);
						if(FastTimer(0)>730){	//黒が無いなら、ロータリー
							go=0;
							Wait(5);
							break;
						}
					}
					time=FastTimer(0);
					if(FastTimer(0)<160&&SENSOR_1<IKT){//黒が左のセンサーと近いとスタート
						count++;
						PlaySound(SOUND_DOUBLE_BEEP);
						OnFwd(OUT_A+OUT_C);
						OnRev(OUT_B);
						Wait(27);
						Off(OUT_A+OUT_B+OUT_C);
						if(time>=27){
							Wait(time-27);//動かした量だけ巻き戻しをする
						}
						break;
					}
					if(FastTimer(0)>12){//動かした量だけ巻き戻しをする
						OnRev(OUT_B);
						Wait(time-12);
					}
					if(go==1){//十字の交差点
						PlaySound(SOUND_DOWN);
						OnRev(OUT_B);
						Wait(22);
						OnFwd(OUT_A+OUT_C);
						Off(OUT_B);
					}
					else {//ロータリーの時
						PlaySound(SOUND_DOUBLE_BEEP);
						Rot=1;
						go=1;
						OnRev(OUT_A+OUT_C);
						Wait(31);
						Off(OUT_B);
						while(SENSOR_1<IKT){
							turn_r();
						}
						Wait(20);
						while(SENSOR_1>IKT){
							turn_r();
						}
						while(SENSOR_3<IKT){
							turn_l();
						}
						turn_l();
						Wait(15);
					}
					Off(OUT_B);
				}
			}
		}
	}
}

難しかったところ、工夫したところ

t.s

  • 交差点、ロータリー、鋭角、近道、スタートを一度に判断するようにしたあまり、わずかな電力の消費でもうまく障害物を判断することができず苦労した。

  • 一つ一つ問題を解決していくと、今までうまくできた障害物ができなくなるケースが 多くあり、非常に苦労した。

  • すべてのコースを判断できるように、正確に動作するようにした。そのためにギヤを噛ませたり、全体を重くしてみたり、プログラムではFloatとOnFwdとOnRevをうまく用いてさらに遅くなるようにした。

ひろ

  • 鋭角を確実に曲るために、普通の曲がり方を急カーブ出来るようにFastTimerを用いて調整した。
  • 判定を簡単にするため、鋭角を曲る調整→近道かその他→ロータリーか交差点を判断。と3回の判定で、速さより正確さを重視することにした。
  • 前進、後退のWaitが電池の残量に影響されて、移動量が変化する。SetPowerで出力が重量に負けないように調整した。
  • ラインの黒の値が途中で大きくなっていて、気づくまでWaitを変えたり、分岐条件を変えたりしても、うまくいかなくて困った。

全体を通しての感想

t.s

  • ライントレースをするロボットを作ることは実際にやってみると非常に難しく、様々な困難にぶち当たってきた。~しかし実際に作ってみることで、どのようなロボットを製作すればいいのか・どのようなプログラムを作ればいいのかといろいろと悩むことで、新しい発見ができた。
  • あらゆるコースに対応するために機能を重視した。おかげでよい面がたくさんあり、障害物一つ一つが攻略できる度に達成感があった。ただ、電池の消費による移動量の増減を考えておらず、正確性を要求する場面ではかなり苦労したため、もっと工夫するべきだった。

ひろ

  • 移動量や光センサーの値は、電池の残量や重さ、高さ、重心などの様々な原因で変化するので、常にまったく同じ動きが出来るとは限らない。Waitを使うと重さや摩擦で移動量が変わるので、ライントレースをするならば、whileやifの方が、状況により判断できて、移動量に左右されないので、Waitの量を減らそう。と考えたが、細かい前進や後退はどうしてもWaitになってしまった。工夫したかった。
  • 相方が知らないうちにこのページの大半を完成させていた。イラストにはビックリした。

最後にコメントがありましたら、何でもどうぞ!



添付ファイル: file全体.jpg 407件 [詳細] file前.jpg 360件 [詳細] fileコース.png 273件 [詳細] file下.png 380件 [詳細] file後ろ.png 368件 [詳細] fileUGOKI2.png 330件 [詳細] fileUGOKI1.png 297件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2012-02-18 (土) 22:41:01 (2616d)