ロボティクス入門ゼミ  

課題 ライントレースロボット

黒い線をなぞって周回するロボットを製作する。
・交差点が2箇所以上。
・急なヘアピンカーブが1箇所以上。
・直角に曲がるコーナー(クランク)が1箇所以上。
・黒い線の幅は15〜20mm程度。

無題.png

上記の写真は私たちA5のコース。下半分はなだらかなコースでだが、上半分がヘアピンや、半径が小さいカーブが多いために少し難しいコースになってしまった。

製作過程

h24/6/1〜6/29 2012a/A5/ITY/M2/photo

CIMG1577.JPG

・アナログセンサ1個、タッチセンサ2個使用。

・ライントレースの仕組み

無題5.png

・黒と感知すると旋回、白と感知すると旋回して蛇行しながら進む。

無題2.png

・カーブも蛇行しながらトレースすることができる。

車体部分

CIMG1578.JPG

・前回は重心が高くて走行に支障が出たので今回は低重心、コンパクトを目指した。

CIMG1582.JPG

・センサの位置をできるだけ車体に近づけた。

工夫したところ

・低重心、コンパクト化

結果

プログラム

フローチャート

無題7.png

・白黒のしきい置調整用の関数と侵入時に90度回転する関数を使用し、メインルーチンでモータ制御した。

プログラム

/*		2012/6/22  ITY					*/
/*		2012a_robo		tore-su6		*/

/*-------------------------------------------------------------------
				別名定義
-------------------------------------------------------------------*/
#define PWM 		80							// PWM(力の大きさ)
#define PWM_D 		15							// PWM(力の大きさ)
#define DIF 		6							// 差
#define ON 		1							// オン
#define OFF		0							// オフ
#define TRUN_AC	320								// 90度の回転角度
#define DEFF_RC	180								// 超信地旋回までの時間
#define DEFF_LC	100								// 超信地旋回までの時間

/*-------------------------------------------------------------------
				関数宣言
-------------------------------------------------------------------*/
void TURN_R();									// 90度ターン
void TURN_L();									// 90度ターン
void MODULATE();								// しきい値調整用の関数

/*-------------------------------------------------------------------
				グローバル変数
-------------------------------------------------------------------*/
int s1_touch,s2_touch,br_light,wh_light;					// タッチセンサ、しきい値の変数宣言

/*-------------------------------------------------------------------
				メインルーチン
-------------------------------------------------------------------*/
task main()
{
    SetSensorLight(IN_4);							// アナログセンサの宣言
    SetSensorTouch(IN_2);							// タッチセンサの宣言
    SetSensorTouch(IN_1);							// タッチセンサの宣言
    int s_light,diff,abs_diff,aspect,s_avg,r_count,l_count,num_c;		// 変数宣言
    num_c=0,s_light=0,r_count=0,l_count=0;					// 変数の初期化

	MODULATE();								// しきい値調整用の関数
	s_avg = (br_light+wh_light)/2;						// 白と黒の平均値を取る
	OnFwd(OUT_AC,80);							// コースに入るために前進
	Wait(400);								// 0.4秒間前進
	TURN_R();								// 右に90度旋回
	while(true){								// ライントレース開始
	num_c++;								// クランク用のカウンタを回す
		s_light = Sensor(IN_4);						// アナログセンサの値を取得
		if((s_light < (s_avg + DIF)) && (s_light > (s_avg - DIF))){	// センサの値が平均値の差(DIF)に入っているとき
			OnFwd(OUT_AC,PWM);					// 両方のモータを正転させる
		}
		else{								// センサの値が平均値の差(DIF)に入っていないとき
			abs_diff = abs(s_light - s_avg);			// 今のセンサの値と平均値を比較する
			diff = PWM_D + (50 - abs_diff) + (abs(l_count-r_count)*0.1);// PWM=(初期速度)+(上で比較した値)+(センサが復帰するまでの時間*0.1) 
			if(diff > 100)diff = 100;				// PWMが100を超えないようにする
			if(s_light < s_avg){					// センサの値が平均値より小さい時(黒)
				OnFwd(OUT_C,diff);				// Cのモータを正転
				if(l_count > DEFF_RC) OnRev(OUT_A,diff/2);	// 復帰モードに入った時、Aのモータを後転(超信地旋回)
				else Off(OUT_A);				// 復帰モードに入るまで、Aのモータを停止
				l_count++;					// lのカウンタ開始
				r_count=0;					// rのカウンタのクリア
			}
			else if(s_light > s_avg){				// センサの値が平均値より小さい時(白)
				OnFwd(OUT_A,diff);				// Aのモータを正転
				if(r_count > DEFF_RC) OnRev(OUT_C,diff/2);	// 復帰モードに入った時、Cのモータを後転(超信地旋回)
				else Off(OUT_C);				// 復帰モードに入るまで、Cのモータを停止
				r_count++;					// rのカウンタ開始
				l_count=0;					// lのカウンタのクリア
			}
		}
		Wait(1);							// 1ms周期でメインルーチンを回す
		if(num_c > 20000){						// クランク前にトレースする向きの変更
			Off(OUT_AC);						// ACのモータの停止
			OnFwd(OUT_A,diff);					// ACのモータの正転
			Wait(400);						// 0.4秒待つ
		}
		while(num_c > 20000){						// 向きの変更後トレース開始
			s_light = Sensor(IN_4);					// 以下は上のプログラムの左右を変更したもの
			if((s_light < (s_avg + DIF)) && (s_light > (s_avg - DIF))){
				OnFwd(OUT_AC,PWM);
			}
			else{
				abs_diff = abs(s_light - s_avg);
				diff = PWM_D + (50 - abs_diff) + (abs(l_count-r_count)*0.2);
				if(diff > 100)diff = 100;

				if(s_light < s_avg){
					OnFwd(OUT_A,diff);
					if(l_count > DEFF_LC) OnRev(OUT_C,diff/2);
					else Off(OUT_C);
					l_count++;
					r_count=0;
				}	
				else if(s_light > s_avg){
					OnFwd(OUT_C,diff);
					if(r_count > DEFF_LC) OnRev(OUT_A,diff/2);
					else Off(OUT_A);
 					r_count++;
					l_count=0;
				}
			}
		}
	}
}

/*-------------------------------------------------------------------
				サブルーチン
-------------------------------------------------------------------*/
void TURN_R()									// 90度ターン
{
	int tako_a=0,tako_c=0;							// 変数宣言
	ResetScreen();								// LCDの初期化
	OnFwdSyncEx(OUT_AC,40,-100,RESET_NONE);					// 左右ACのモータを回す
	while((tako_a < TRUN_AC) && (tako_c < TRUN_AC)){			// 90度回転していないとき
		tako_a = abs(MotorTachoCount(OUT_A));				// タコメータからモータAの値を取得
		tako_c = abs(MotorTachoCount(OUT_C));				// タコメータからモータBの値を取得
		NumOut(10,48,tako_a,0);						// LCDにタコメータ(A)の値を表示
		NumOut(10,40,tako_c,0);						// LCDにタコメータ(A)の値を表示
	}
	Off(OUT_AC);								// モータの停止
}

void MODULATE()									// しきい値の調整用
{
    int t_count;								// 変数宣言
    s1_touch=0,s2_touch=0,t_count=0,						// 変数の初期化
     br_light=10,wh_light=60;

	while(s2_touch == OFF){
		s1_touch = Sensor(IN_2);					// タッチセンサの値を取得
		s2_touch = Sensor(IN_1);					// タッチセンサの値を取得
		NumOut(10,60,s1_touch,0);					// LCDにタッチセンサの値を表示
		NumOut(10,40,s2_touch,0);					// LCDにタッチセンサの値を表示
		NumOut(30,60,br_light,0);					// LCDに黒のしきい値を表示
		NumOut(30,40,wh_light,0);					// LCDに白のしきい値を表示
		if(s1_touch == OFF){						// スイッチ1が押されていないとき
			t_count = 0;						// カウンタの初期化
			Off(OUT_AC);						// モータの停止
		}
		else if(s1_touch == ON){					// スイッチ1が押されているとき
			if(t_count < 1000){					// 1秒間押されているか判定
				t_count++;					// カウンタをまわす
				br_light = Sensor(IN_4);			// 黒いラインの明るさを取得
			}
			else {							// 1以上押されているとき
				wh_light = Sensor(IN_4);			// 白い部分の明るさを取得
			}
		}
	}
}

工夫したところ

無題6.png

・クランクや、コースを出るところは、あらかじめ時間がたつと左右のトレースを反転するようにしておく。

無題3.png

・左右トレースを反転した後、クランクやコースを出るときに、曲がりやすいように超信地旋回に移る時間を変更した。

反省・感想

無題4.png

・写真の赤丸のところで良く脱線していた。クロスラインとRがきつい曲線は成功率が低かったので、ライン検出がうまくできていないと考えられる。また、コースの黒色に斑があり、それも影響していると考えられる。

無題1.png


・折りたたんだためコースに穴があいてしまい、誤検出が目立った。
・精度も悪く走行もぎこちなかったため、センサ1つで走行する難しさを知ったが、発想次第で、簡単にトレースする方法があったりと非常に驚いた。また、電地に影響されないようにするためには、回転数もしっかり計算してプログラムする必要があると感じた。


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2012-06-28 (木) 02:36:37 (2615d)