2018年11月
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30  

Amazonウィジェット

  • お気に入り
  • 書籍ランキング

AdSense

  • 広告
無料ブログはココログ

« 遺伝的アルゴリズムで育てる「お掃除ロボット」 その6 ~動かしてみた!!~ | トップページ | VisualStudioにncurses(pdcurses)を導入する。 »

2018年3月28日 (水)

遺伝的アルゴリズムで育てる「お掃除ロボット」 その7 ~ロボット動作の改良~

前回のソースを動かしてみた。
計算は合っているのだがなんだか思っていた動きと違っている。


詳細に調べてみると、やはり前回までのやり方ではお掃除ロボットの動きを再現できていなかった。

そもそもお掃除ロボットって後退なんかしただろうかと思う。



そこで、移動方向は後退を除く直進、左折、右折の3種類とした。

旋回方向と方角の管理方法についてももっと汎用的な方法に見直すことにした。

だいぶ前にyoutubeで1時間でテトリスを作るという動画を見たとき、 ブロックの回転に、座標変換に使う回転行列を使っているのをみた。

これは今回も使えるのではないかと思い、うろ覚えで回転行列を書いてみた。

回転行列を出すには、加法定理を使ったり、 座標系を回した絵をかいて、そこから方程式を立てて行列にしたり。 昔はいろいろやっていたのだが、このやり方を知っていれば一発で回転行列を出せる。

 

2次元マップで90度回転しかしないので、回転行列はこんな風になる。
単純に配列で要素を並べて、掛け算すればいいレベル。

Kaitengyoretsu90deg enumで移動方向の名前を定義して、その名前で受け取るようにした。
下記が完成したコード。

//移動の向き
typedef enum { left, forward, right }dir_t;

//旋回後の移動方向を計算
void rotRobot(indiv_t *ind, dir_t d) {
	const int dim[][4] = {
		{ 0,1,-1,0 }, //left
		{ 1,0,0,1 }, //forward
		{ 0,-1,1,0 }, //right
	};
	int x = dim[d][0] * ind->dx + dim[d][1] * ind->dy;
	int y = dim[d][2] * ind->dx + dim[d][3] * ind->dy;
	//printf("%2d*%2d + %2d*%2d = %2d\n", dim[d][0], ind->dx, dim[d][1], ind->dy, x);
	//printf("%2d*%2d + %2d*%2d = %2d\n", dim[d][2], ind->dx, dim[d][3], ind->dy, y);
	ind->dx = x;
	ind->dy = y;
}

再びロボット作成の関数から。

void makeRobot(indiv_t *ind, int ini_dx, int ini_dy){
	ind->pos.x = INI_X;
	ind->pos.y = INI_Y;

	//初期位置にagentをセット
	point_t p = { INI_X, INI_Y };
	map[getIndex(p)] = CH_Robot;

	ind->life = INI_LIFE;
	ind->item = 0;
	ind->scr = 0;
	
	for (int i = 0; i

gen[i] = search[i]; //printf("(%d,%d)", ind->gen[i].dir, ind->gen[i].num); } int gidx = SEARCH_LEN; for (int i = 0; i < HITTED_LEN; i++) { saikoro(&hitted[i]); ind->gen[gidx] = hitted[i]; gidx++; } //お掃除モードで始動 ind->work = searchMode; //最初の移動方向 ind->delta.x = ini_dx; ind->delta.y = ini_dy; //初期の移動方向をセット。 rotRobot(ind, forward); }



移動方向の計算 ロボットの移動方向がdx,dyで保持されていて、 これに回転行列をかけることで旋回後のdx,dyに変換されるようになっている。

genに固定値を入れて動かし、最後にロボットが辿り着く座標を見ることで、 動作検証を行った。

同じgenを入れていてもdxdyへの初期値として何を入れるかで、 その後の動きと最終地点はガラリと変わってしまう。


検証の時はそこまで考慮して作らないといけない。 初期状態は一個しかないのであればそれでもいいが、 気まぐれで変えたときに隠れていたバグが突然発症することもある。

makeRobot関数の中の、gen[]の中身を乱数で作るほうをコメントアウトし、 下記のような検証用コードを入れた。

	////---debug
	//dir_t dir[] = { right,right,right,right };
	dir_t dir[] = { right,left,right,left };
	//dir_t dir[] = { forward,forward,forward,forward };
	dir_t dir[] = { forward,left,forward,right };
	int nums[] = { 5,4,6,5 };
	for (int i = 0; i < SEARCH_LEN; i++) {
		search[i].dir = dir[i];
		search[i].num = nums[i];
	}
	hitted[0].dir = left;
	hitted[0].num = 2; //num>=1が条件
	hitted[1].dir = left;
	hitted[1].num = 2;
	for (int i = 0; i

gen[i] = search[i]; //printf("(%d,%d)", ind->gen[i].dir, ind->gen[i].num); } int ggidx = SEARCH_LEN; for (int i = 0; i < HITTED_LEN; i++) { ind->gen[ggidx] = hitted[i]; ggidx++; } ////---debug

このコードを少し書き換えて、壁に当たったときの動作も見た。 だいぶ雰囲気が出てきた。

動作時の動画

そろそろ表示方法の改良を考えても良いころ合いだろうか。
次回はncursesを使ったCUIの凝った使い方をやっていく。

続く


<余談>
数式エディタを使っいたかったのだが、もしかしたらと思いオンライン数式エディタで検索したらmathcha.ioというのが出てきた。 昔LaTeXでゴソゴソと書いていたのが嘘のように簡単に操作できる。 matrixが使いたくて、mと打ったらすぐに候補が表示され、そこから選ぶだけですごく使いやすい。

« 遺伝的アルゴリズムで育てる「お掃除ロボット」 その6 ~動かしてみた!!~ | トップページ | VisualStudioにncurses(pdcurses)を導入する。 »

C言語」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/518723/66386508

この記事へのトラックバック一覧です: 遺伝的アルゴリズムで育てる「お掃除ロボット」 その7 ~ロボット動作の改良~:

« 遺伝的アルゴリズムで育てる「お掃除ロボット」 その6 ~動かしてみた!!~ | トップページ | VisualStudioにncurses(pdcurses)を導入する。 »