課題内容

 課題3は、課題2で使用したコース上で、各場所に配置された缶を回収しゴールの円の中に積み上げる課題である。
 コースと缶の配置は下の画像の通りである。
 詳しいルールについては、2017a/Mission3を参照。

コース全体像と缶配置

機構説明

缶の回収方法と積み上げ

 まずロボットを作る上での方向性として、出来るだけライントレースをせずに缶をゴールに積み上げる機構にすることにした。
 缶を積み上げ、ゴールに配置するまでの動作としては、次の2つの動作によって行う。

.魁璽江紊貿枌屬気譴討い覺味靴帖蔽羶箸瞭っている缶を除く)をアームによって回収し、ゴール前に一直線に並べる。

缶回収イメージ

■隠牽亜訐回し、今度はハンド上の部分で缶を1個ずつ積み上げてゆき、ゴールに置く。

缶の積み上げイメージ

 ※ただし、プログラムの調整が間に合わなかったため、授業内の競技会では,瞭虻遒里澆猫△瞭虻遒蝋圓辰討い覆ぁ

アーム部分

 缶を回収するときに、あまりアームの駆動が速いと缶を倒してしまうのではないかと考えた。そこで、アームの駆動には、ウォームギアを使用し、出来るだけ機構で速度を落とせるように工夫をした。しかし、それでも動かしてみると缶を倒してしまうことが多々あったため、さらにプログラムでモーターのパワーを小さくして駆動させている。

缶動力部分

 また、缶を一度に全て回収するため、アームの長さは缶7個分を挟み込める長さにしようと考えていたが、それだけ長くするとアームがたわみコースに接地してしまった。補強しようにも部品も足りなかったため、諦めて缶5個分は挟める長さで作成した。
 下の動画はアームで缶を回収しているときの様子である。

缶回収の様子

ハンド部分

 ハンド部分の缶をつかむ機構には、クラッチギアを使用することで、ずっとモーターを回転させるだけで缶をつかめるようにした。これによって、缶を放す時に開く時間を設定するだけで済むので、シンプルなプログラムで済むようにもなっている。
 また、缶をつかむときにそのままブロックで缶をつかむと滑ってしまった。そこで、初めはアームにゴムを渡し、ゴムで缶を挟もうと考えたが、ゴムの弾力が強すぎてしまい、うまくつかむことが出来なかった。そこで、缶に触れる箇所にタイヤを取り付けタイヤの摩擦によって缶を保持することにした。

ハンド画像

 ハンドの上下機構にはウォームギアから1番大きなギアへ伝達し、そのギアとラックを組むことでハンドを上下させている。
 上下機構の制御には回転センサを用いている。

ハンド上下機構の様子

プログラム

アーム・駆動側

 アーム・駆動部分のプログラムに関しては、授業内で行った競技会では使用していないプログラムも、動作確認まで済ませてあるため載せてある。
 「定数・マクロ 定義」と「グローバル変数」の部分に関しては、コメント文で十分説明できていると思う。また、サブルーチン・メインタスクで使用している部分を見れば使用用途は理解できると思うので説明は省略する。

//------------------------------------------------------------//
//	缶回収ロボット プログラム			      //
//------------------------------------------------------------//

/*--------------------------------------*/
/*	    定数・マクロ 定義 		*/
/*--------------------------------------*/

/*---------- センサ値 ----------*/
#define LINE_BLACK 	35					// 黒線反応時の光センサ(ライン判定用)の値
#define CAN_SHORT 	46					// 缶に接近したときの 光センサ(缶用)の値

/*---------- 動作に関する時間 ----------*/ 

#define TURN_TIME	145					// 180°反転までの時間
#define APP_TIME	75					// 缶接近までの時間 
#define ARM_TIME	200					// アームが真横を向くまでの時間(アームの駆動時間はこれを基準に使用)

/*---------- タイヤ・アームの動作 ----------*/
#define FOWORD		OnFwd(OUT_AC);				// 直進
#define BACK 		OnRev(OUT_AC);				// 後退
#define STOP 		Off(OUT_AC);				// 停止
#define TURN_LEFT 	OnFwd(OUT_C); OnRev(OUT_A);		// 左旋回
#define TURN_RIGHT 	OnFwd(OUT_A); OnRev(OUT_C);		// 右旋回 

#define ARM_OPEN	OnFwd(OUT_B);				// アーム開
#define ARM_CLOSE	OnRev(OUT_B);				// アーム閉
#define ARM_STOP	Off(OUT_B);				// アーム停止 

/*---------- 通信 信号 ----------*/
#define ROGER 		1					// <受信・送信> 【了解】
#define GO_AHEAD	10					// <送信> 【行動開始】
#define MOTION_END	20					// <受信> 【動作完了】

/*--------------------------------------*/
/*	    グローバル変数 		*/
/*--------------------------------------*/
int trans_sign = 0;						// <通信> 送信信号 格納用

int can_cnt = 0;						// 缶 積み上げ本数カウント用

サブルーチン

 駆動側はアームの動作は1度しかせず、前進後退もサブルーチンとしてまとめる必要が無かったため、通信に使用する受信と送信のみをサブルーチンとしてまとめてある。
 受信側は、最後に受信した値を初期化した後、ハンド側から新たな信号が送られてくるまで待機するようになっている。
 送信側は、こちらも一度受信した値を初期化した後、ハンド側からの【了解】の信号を受信するまで送信を続けるようになっている。

/*--------------------------------------*/
/*	     <通信> 受信 		*/
/*--------------------------------------*/
sub Reception()
{
	ClearMessage();						// <通信> 初期化(最後に受信した値 → 0)
	until(Message() == MOTION_END);				// <通信> 『20【動作完了】』を受信するまで待機
	SendMessage(ROGER);					// <通信> 『1【了解】』を送信

}

/*--------------------------------------*/
/*	     <通信> 送信 		*/
/*--------------------------------------*/
sub Transmission()
{
	ClearMessage();						// <通信> 初期化(最後に受信した値 → 0)
	SendMessage(trans_sign);				// <通信> 『"trans_sign"の値』を送信
	until(Message() == ROGER);				// <通信> 『1【了解】』を受信するまで送信し続ける
}

メインタスク

 今までのところでも何回か書いているように、授業内で行った競技会までに動作の調整が終わりきらなかった。そのため、調整が終わらなかった部分から下は使用していない。しかし、使用していないプログラムも動作確認まで済んでいるため載せてある。
 使用しなかった部分については、またその部分だけ取り出して説明する。

/*--------------------------------------*/
/*	     メインタスク		*/
/*--------------------------------------*/
task main()
{
	/*---------- モータパワー・センサ 設定 ----------*/
	SetPower(OUT_AC , 3);
	SetSensor(SENSOR_3 , SENSOR_LIGHT);			// 黒線 認識用
	SetSensor(SENSOR_1 , SENSOR_LIGHT);			// 缶  認識用

	/*---------- アームを全開 ----------*/

	ARM_CLOSE;						// アーム閉
	Wait(ARM_TIME);						// アームが真横を向くまで閉じる
	ARM_STOP;
	Wait(100);

	/*---------- 缶 回収 ----------*/

	FOWORD;							// アーム側を前方向として
	until(SENSOR_3 < LINE_BLACK);				// 2つ目の黒線まで前進
	until(SENSOR_3 > LINE_BLACK);				//
	until(SENSOR_3 < LINE_BLACK);				//
	STOP;							// 停止
	Wait(100);

	ARM_CLOSE;						// アーム閉
	Wait(ARM_TIME + 50);					// アームが平行になるまで閉じる
	ARM_STOP;
	Wait(100);

	BACK;							// 缶を揃えるために
	Wait(50);						// 少し下がる
	STOP;

	ARM_CLOSE;						// アーム閉
	Wait(30);						// 缶を一列にするためにさらに少し閉じる
	ARM_STOP;

	ARM_OPEN;						// アームを開き、
	Wait(ARM_TIME*2 + 80);					// スタート時にあった場所まで戻す
	ARM_STOP;

	/*---------- 缶積み上げのための準備 ----------*/

	BACK;							// 後退して、
	until(SENSOR_3 > LINE_BLACK);				// 2つ目の黒線まで前進
	until(SENSOR_3 < LINE_BLACK);				//
	STOP;

 ここまでは、機構説明の『缶の回収方法と積み上げ』の,瞭虻遒任△襦
 動作の流れは下のフローチャートの様になっている。
 フローチャートの一番下は結合子の「○」になっているが、これは『缶積み上げの流れと様子』のフローチャートの「アーム・駆動側」の結合子につながっている。

缶回収の流れ

 授業での競技会では、この後”}”でメインタスクを閉じてしまい、缶をアームで閉じる動作のところまでで使用している。
 調整が間に合わなかったのは、下の4行で、ロボットが旋回し180°後ろを向くプログラムである。しかし、旋回を時間で制御しようとしたため、"TURN_TIME"の数値の設定が難しくなってしまった。そのため、きれいに真後ろを向くことが出来ず、正確に缶の手前まで走ることが出来なかった。

	SetPower(OUT_AC , 7);
	TURN_LEFT;						// 左旋回で
	Wait(TURN_TIME);					// 180°後ろを向く
	STOP;

 ここから下は、ハンド側と通信を行い、缶を積み上げるときのプログラムである。調整が終わらなかったのは上の部分のみで、ここからのプログラムのみでなら缶を積み上げることが出来る。
 実際に缶を積み上げている様子は、『缶積み上げの流れと様子』の動画を参照。

	SetPower(OUT_AC , 3);
	BACK;							// ハンド側を前方向として
	until(SENSOR_1 > CAN_SHORT);				// 缶の手前まで前進
	Wait(20);						//(ここから下は、ハンド方向を前方向とする)
	STOP;

	/*---------- 缶の積み上げ開始 (3回繰り返し、4段にする) ----------*/ 
	while(pile_up_cnt < 3){
		trans_sign = GO_AHEAD;				// <通信> 『10【行動開始】』
		Transmission();					// 送信

		/* - - - - - - - - - - - - - - - - -*/
		/*   ハンド側が缶の持ち上げを実行   */
		/* - - - - - - - - - - - - - - - - -*/

		Reception();					// <通信> 『20【動作完了】』が送られてくるまで待機

		BACK;						// 缶一つ分だけ(次の缶の手前まで)
		until(SENSOR_1 > CAN_SHORT);			// 前進する
		Wait(20);
		STOP;

		trans_sign = GO_AHEAD;				// <通信> 『10【行動開始】』
		Transmission();					// 送信

		/* - - - - - - - - - - - - - - - - - -*/
		/*  ハンドが缶を置き、初期位置に戻る  */
		/* - - - - - - - - - - - - - - - - - -*/

		Reception();					// <通信> 『20【動作完了】』が送られてくるまで待機

		can_cnt++;					// 缶の本数 +1
	}
}

 ハンド側との通信による全体の流れは、『プログラムの流れ』のフローチャートを参照。
 駆動側は、光センサで缶を検知し、缶をつかめる距離まで近づいたら停止を繰り返す。積み上げた缶の本数をカウントし、缶の積み上げを3回行ったらwhile文のループから抜けて停止するようになっている。

ハンド側

 ハンド側のプログラムは駆動側と通信を行い、缶を積み上げる動作を繰り返すだけである。
 缶の積み上げの様子は、アーム側のプログラムの説明でも書いたが『缶積み上げの流れと様子』で積み上げの動画のリンクを載せてある。
 また、ハンド側についても、『定数・マクロ 定義』と『グローバル変数』についてはコメント文で説明できていると思うので説明は省略する。

//------------------------------------------------------------//
//	缶積み上げロボットプログラム			      //
//------------------------------------------------------------//

/*----------------------------------------*/
/*	     定数・マクロ 定義 		  */
/*----------------------------------------*/

#define HAND_TIME		50				// ハンド開閉 時間

/*---------- ハンド・上下機構 動作 ----------*/
#define ELEVATE_UP		OnFwd(OUT_C);			// <ハンド昇降>上昇
#define ELEVATE_DOWN		OnRev(OUT_C);			// <ハンド昇降>降下
#define ELEVATE_STOP		Off(OUT_C);			// <ハンド昇降>停止
#define HAND_OPEN		OnRev(OUT_B);			// <ハンド開閉>開
#define HAND_CLOSE		OnFwd(OUT_B);			// <ハンド開閉>閉
#define HAND_STOP		Off(OUT_B);			// <ハンド開閉>停止

/*---------- 通信 信号 ----------*/
#define ROGER 			1				// <受信・送信> 【了解】
#define GO_AHEAD		10				// <受信> 【行動開始】
#define MOTION_END		20				// <送信> 【動作完了】

/*----------- グローバル変数 定義 ----------*/
int trans_sign = 0;						// 送信用 信号 格納変数

int hand_flag = 0;						// <ハンド>開閉 判断用
int elevate_flag = 0;						// <ハンド>昇降 判断用

int can_cnt = 0;						// 積み上げた缶の本数

サブルーチン

 ハンド側のサブルーチンは、通信に使用する受信と送信に加え、ハンドの上下を行うものとハンドの開閉を行うものもサブルーチンとして作成している。

《 ハンド昇降 》

/*---------------------------------*/
/*	     ハンド昇降 	   */
/*---------------------------------*/
sub Hand_Elevate()
{
	if(elevate_flag == 0){					// ハンド上昇
		ELEVATE_UP;
		until(SENSOR_1 > 385);
		ELEVATE_STOP;

		elevate_flag = 1;				// ハンド上昇終了 次:降下を実行
	}
	else if(elevate_flag == 1){				// ハンド降下(缶をのせる)
		ELEVATE_DOWN;
		until(SENSOR_1 < 360);
		ELEVATE_STOP;

		elevate_flag = 2;				// ハンド降下終了 次:下降を実行
	}
	else if(elevate_flag == 2){				// ハンド初期位置(一番下)へ移動
		ELEVATE_DOWN;
		until(SENSOR_1 < 3);
		ELEVATE_STOP;

		elevate_flag = 0;				// ハンド下降終了 次:上昇を実行
	}
}

 ハンドの昇降は回転センサの値で制御している。
 ハンドの昇降の動作は、《上昇 → 少し下降(缶を置くため)→ 下降(元の位置へ)》を繰り返す。そこで、if文を使い"elevate_flag"という変数の値(0,1,2)で動作を3パターンに分けた。そして、それぞれの動作の後で"elevate_flag"の値を次に行う動作の値に変更する。すると《0→1→2→0》と変わってゆくため、同じ"Hand_Elevate()"のサブルーチンを使用するだけで、3パターンの動作を順番に繰り返せるようになっている。

《 ハンド開閉 》

/*---------------------------------*/
/*	     ハンド開閉 	   */
/*---------------------------------*/
sub Hand_OC()
{
	if(hand_flag == 0){
		SetPower(OUT_C , 3);
		HAND_CLOSE;
		Wait(100);
		SetPower(OUT_C , 6);		
		hand_flag = 1;					// ハンド閉 次:ハンドを開く
	}
	else{
		HAND_OPEN;
		Wait(HAND_TIME);
		HAND_STOP;

		hand_flag = 0;					// ハンド開 次:ハンドを閉じる
	}
}

 ハンドの開閉は時間でハンドの開き具合を制御している。ハンドを開くか閉じるかの判断は、上の『ハンド昇降』のサブルーチンと同様に"hand_flag"という変数の値を変更することで、同じサブルーチン"Hand_OC()"を使用するだけで《開→閉》を繰り返す様になっている。

《 受信/送信 》
 受信と送信についてはアーム・駆動側のプログラムと全く同じものであり、そちらで説明しているため省略する。

/*---------------------------------*/
/*	    通信(受信側) 	   */
/*---------------------------------*/
sub Reception()
{
	ClearMessage();						// <通信> 初期化(最後に受信した値 → 0)
	until(Message() == GO_AHEAD);				// <通信> 『10【行動開始】』を受信するまで待機
	SendMessage(ROGER);					// <通信> 『1【了解】』を送信

}

/*---------------------------------*/
/*	     通信(送信側)	   */
/*---------------------------------*/
sub Transmission()
{
	ClearMessage();						// <通信> 初期化 (最後に受信した値 → 0)
	SendMessage(trans_sign);				// <通信> 『"trans_sign"の値』を送信
	until(Message() == ROGER);				// <通信> 『1【了解】』を受信するまで送信し続ける
}

メインタスク

 ハンド側のメインタスクはアーム・駆動側に比べてシンプルで、缶を積み上げるだけの動作である。
 具体的には、
  《缶を持ち上げる》→《缶を下の缶の上に乗せてハンドを開く》→《元の位置に戻る》
の3つの動作を駆動側からの【行動開始】の信号が送られてくる度に1つずつ順番に行い繰り返すだけである。
 アーム・駆動側との通信による連携と動作の流れは『缶積み上げの流れと様子』のフローチャートを参照。

/*---------------------------------*/
/*	    メインタスク 	   */
/*---------------------------------*/
task main()
{
	/*---------- モータパワー・センサ 設定 ----------*/
	SetSensor(SENSOR_1 , SENSOR_ROTATION);			// 回転センサ設定
	ClearSensor(SENSOR_1);					// 回転センサ初期化

	/*---------- 缶 積み上げ(3回繰り返し、4段にする)----------*/

	while(can_cnt < 3){
		Reception();					// <通信> 『10【行動開始】』を受信するまで待機

		Hand_OC();					// 缶をつかむ
		Hand_Elevate();					// ハンド上昇

		trans_sign = MOTION_END;			// <通信> 『20【動作完了】』
		Transmission();					// 送信

		/* - - - - - - - - - - - - - - - - - - -*/
		/*	駆動側が缶の手前まで移動	*/
		/* - - - - - - - - - - - - - - - - - - -*/

		Reception();					// <通信> 『10【行動開始】』を受信するまで待機

		Hand_Elevate();					// ハンド下降
		Hand_OC();					// 缶を放す

		Hand_Elevate();					// 一番下までハンドを下ろす

		trans_sign = MOTION_END;			// <信号>『20【動作完了】』
		Transmission();					// 送信

		can_cnt++;					// 缶の本数 +1
	}

	Reception();						// <通信> 『10【行動開始】』を受信するまで待機
}

缶積み上げの流れと様子

 缶積み上げの時の流れは下のフローチャートの様になっている。
 アーム・駆動側の1番上は「結合子」の「○」になっているが、これはアーム・駆動側のプログラムの『メインタスク』の説明で載せてある結合子とつながっている。

缶積み上げ時の流れ


 3段までだが、実際に缶を積み上げている様子をyoutubeに動画を上げてある。
 下の画像をクリックするとyoutubeの動画のページに飛ぶようになっている。 ここをクリックするとyoutubeの動画のページへ行きます

反省・感想

 ロボットのコンセプトとして、「敢えてほとんどライントレースをせずに缶を回収し、ゴールに積み上げる」ということを考えてロボットの製作を行ってきた。途中まではうまく動作し、缶の回収もゴールに向かって一直線に並べることも正確に出来たため、結果的に競技会でも一直線に並べることで9点を取ることが出来た。しかし、このやり方であれば、缶の積み上げまで成功させないとロボット製作が成功したとは言えないと思うため、缶の積み上げまで出来なかったことはとても残念に感じている。後1日あれば180°旋回も正確に制御し、缶の積み上げまで出来たように思うので、もっと計画的にロボット製作を進めてゆくことが大事だったと実感した。
 また、ロボット本体の製作に関しては、「ハンドやアームなどの部品の重みで組んだブロックが外れてしまい、補強としてまた部品を使用するため、より重みが増す」という悪循環になってしまい、予想よりも大きな形になってしまった。タイヤの動作もブロックが一部外れてしまっていたために左右でバランスが悪くなってしまうこともあった。そのため、もっとシンプルに部品同士を固定できるような工夫が出来れば良かったと思う。
 これまで3つの課題に取り組み、プログラムを作るときに必要な物事を論理的に考える力や、チームでロボットを製作するときの協調性や日程のスケジューリングなどの重要性を感じた。そして、それらの能力を少しずつでも身につけることが出来たと思う。これらの能力や経験はロボット製作だけでなく様々な場面で活用できるので、このゼミで学んだことや感じたことを今後に活かしてゆきたいと思う。


添付ファイル: fileフローチャート 缶積み上げ.png 116件 [詳細] fileフローチャート 缶回収.png 68件 [詳細] file積み上げ 動画.png 29件 [詳細] fileハンド上下機構.jpg 74件 [詳細] fileハンド画像.jpg 63件 [詳細] fileアーム動力画像.jpg 75件 [詳細] file缶回収様子.gif 68件 [詳細] fileアニメーション 缶回収.gif 57件 [詳細] fileアニメーション 缶積み上げ.gif 66件 [詳細] fileコース・缶配置.png 84件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-08-13 (日) 23:35:08