2013b/MemberOnly/進行状況

メンバ紹介

pianoman
おのくんです。今回も主にプログラム担当です。遅刻魔&早退魔。
Redcicudu(Redcicada)
ロボット制作の権威。彼のおかげでプログラミングの時間を十分に確保できた。時々面白い言葉を吐き出す。
課題2
chikuwa
主にプログラム、時々ロボットの改良。軽快にキーボードをぶっ叩く。今回の課題の肝であるアーム部のプログラムを中心にあらゆる作業を取りまとめた。
課題2

課題2の内容

以下のコース内に配置された缶をゴール内に積み上げる。スイッチを入れる以外はロボット・コース・缶をいじるのは原則禁止。

robocon2013b.png

すとらてじぃ

マシンに比べてコースの間隔や缶の配置間隔が小さい所があり、ライントレースだけに頼るのは難しいと考えました。ライン上に無い缶もあります。したがって配置間隔の狭くマシンが干渉しそうなところ(´↓とキΝА砲歪恐伺肇札鵐気鰺僂い憧未鮹戯此κ甞諭△修梁召魯薀ぅ鵐肇譟璽垢農橘未亡未来たら捕獲するようにしました。

以下のようにコース順を決めました。矢印の経路は超音波センサで位置を特定する部分です。

robocon2013b2.png

マシンについて

マシンは2〜3週間かけて制作しました。最初はおのくんとchikuwa氏が台車を、Redcicudu氏がアームを制作していましたが、結局はRedcicudu氏がほぼ全てを作ってしまいました。非常に強固でパワフルで比較的コンパクトなマシンに仕上がってます。4輪なのでとても安定な走行が可能です。

ロボットの詳細な解説はこちらをご覧ください。ここでは簡単に紹介します。

全体像

DVC00019 (2).JPG
缶をつかみながら移動するのでアームは縦に長くなっています。下の輪ゴムは滑り止めです。真ん中の支柱と合わせて三本の柱で缶が崩れないようにしています。

後輪

robot2.jpeg

後輪はRedcicudu氏がうまい具合に2つ付けてくれました。走行がとても安定しました。しかし流石に重いNXTの本体を二つ支えているので車体を回転する時につっかえます。後述のように角度指定で駆動輪を動かし車体を回転させても正確さに欠けてしまいます。

歯車

robot3.png
robot4.png

左の写真はアームの歯車です。Redcicudu氏の得意技(?)。これも安定動作の秘訣と言えるでしょう。

プログラムの概要

図の番号順に取っていきます。

robocon2013c.png
´◆ΝΝ超音波センサで探す→取る
robocon2013d.png
ぁΝキライントレース→缶に接近→取る

pianomanが担当したプログラム

課題2における自分の役割はつなぎ的なプログラムを組む事でした。仮に以下のプログラムを使わなくてもどうにか課題2を対処するのは可能ですが、あると奇麗に解決出来るようなものを目指しました。

Bluetoothによる通信プログラム

プログラムの概要

  1. マスター機がメッセージをスレーブ機へ送信し、スレーブ機の返信を受信するまでプログラムを進めません。
  2. スレーブ機はマスター機のメッセージを受信し、プログラムを実行します。
  3. スレーブ機はプログラムが終わったらマスター機へ返信し、次のメッセージが来るまで待機します。
  4. 返信を受け取ったマスター機はプログラムを再開させます。

[master]   →  命令  →  [slave]

 ↓                ↓

待機               処理

 ↓                ↓

[master]   ←  応答  ←  [slave]

 ↓                ↓

次の処理へ            待機

コード

/* bluetooth.nxc */
/* 送受信と接続確認 */

/* マスター用プログラム */
/* sendmsg(送信メッセージ,受信メッセージ) */
/****スレーブに送信メッセージを送信した後、受信メッセージを受け取るまで待機。 ****/

sub sendmsg(string msg,string rps)
{
	SendRemoteString(1,0,msg);

	string rmsg = "";
	while(rmsg == "")
	{
		ReceiveRemoteString(1,true,rmsg);
		TextOut(0,LCD_LINE1,"Wait until slave");
		TextOut(0,LCD_LINE2,"completes tasks...");
		Wait(1000);
	}
	
	ResetScreen();
}

 /* 共用プログラム */


/* btcheck(接続ポート番号) */
/* 接続の確認。失敗した場合"Something wrong"を表示。 */

sub btcheck(int conn)
{
	while(!BluetoothStatus(conn) == NO_ERR)
	{
		ResetScreen();
		TextOut(0,LCD_LINE1,"Something wrong");
		Wait(1000);
	}

	ResetScreen();
}
 
/*スレイブ用プログラム*/

/* receive("受信メッセージ") */
/* マスターからメッセージを受け取る。 */

sub receive(string rd)
{
	string msg;
	while(msg != rd)
	{
		ReceiveRemoteString(0,true,msg);
		ResetScreen();
		TextOut(0,LCD_LINE1,"Receiving...");
		Wait(1000);
	}
	
	ResetScreen();
	TextOut(0,LCD_LINE1,"I got it!!");
	Wait(1000);
	ResetScreen();
}

/* repond("送信メッセージ") */
/* 応答のメッセージをマスターに送信 */

sub respond(string reply)
{
	SendResponseString(1,reply);
	ResetScreen();
	TextOut(0,LCD_LINE1,"Responded");
	Wait(1000);
	ResetScreen();
}

/*(c) 2014 ONO*/

#include "bluetooth.nxc"で他のファイルから呼び出せます。

問題点

基本的に上記にある3つの命令(sendmsg,receive,respond)を使うのですが、既に出来つつあったchikuwa氏のアーム操作のプログラムに組み込む際に以下の問題点が浮上しました。

  • スレーブが受け取ったメッセージに応じてプログラム条件分岐させることが出来ない。

    receiveは単に目的のメッセージが来るまで待機する機能しかありません。

    string receive()
    {
           string msg;
    	while(msg == "")
    	{
    		ReceiveRemoteString(0,true,msg);
    		ResetScreen();
    		TextOut(0,LCD_LINE1,"Receiving...");
    		Wait(1000);
    	}
    return msg;
    }
    として
    task main()
    {
       while(true)
       {
          msg = receive();
          if(msg == catch){ ~ }
          if(msg == put){ ~ }
          ....
        }
    }
    みたいな感じで使えばもっと汎用性が高まりました。
    結局今回は条件分岐がいるところではSendRemoteNumberとReceiveRemoteNumberを使って対処しました。ちゃんと考えていればもっと入力の手間が少なくなり通信関連の作業時間を小さくすることが出来たはずです。

苦労した点

最初作成したとき、マスター側は送信は成功しましたがスレーブ側の応答に反応できませんでした。同じメールボックスに双方のメッセージを記録していたのですが、書き換えのタイミングが適切でなかったようです。マスターの送信とスレーブの応答の記録に別々のメールボックスを使用することで解決しました。

bluetooth.png

実際の使用

chikuwa氏のプログラムに組み込まれています。

缶を検知→スレーブへアームを降ろすように要請(sendmsg)→受信した後(receive)スレーブがアームを降ろしマスターへ応答(respond)→前進の後缶をつかんでアームを上昇させるよう要請(sendmsg)→缶をつかんでアームを上昇させた後応答(receive&respond)→次のステップへ

といった具合です。

缶の検知プログラム

sonic.png
今回の課題ではライン上から外れた場所にも缶が置いてあります。これを取らずして得点は稼げません。
このプログラムはまず右回転しながらロボットの正面方向の対象物までの距離を計測し、一番近いもの(=缶)に向きを調整します。超音波センサを用いて計測するのですが、これがなかなかくせ者の様で奇麗に決まりませんでした。そのため上記の写真にもあるようにロボットにガイドを設置することになりました。
/* find_direction.nxc */

#define tr OnFwdSync(OUT_AB,60,100); //右回転
#define tl OnFwdSync(OUT_AB,60,-100); //左回転
#define go OnFwdSync(OUT_AB,75,0) //直進
#define unko 60 //計測回数
#define distance 13 //缶までの接近距離
#define measure_time 10 //計測間隔

sub fd(void)
{
	int takatyan; //
	int zxc[unko]; //配列
	int min; //仮の最小値

/* 準備:左に少し回転。 */

	tl;
	Wait(1000);

/* マシンと缶との距離を測る。右回転しながら10ms間隔で60回計測。 */ 

	for(int i = 0;i <=unko-1;i ++) //iが1〜60に加算される間はzxc[i]に超音波センサの値を代入。
	{
		tr;
		Wait(measure_time);
		zxc[i] = SensorUS(S4);
	}

/*記録したデータの中から最小値(距離)を求める。*/

	min = 60; //仮の最小値
	for(int j = 0;j <=unko-1; j++) //j番地におけるzxcの値がminより小さい場合、minにzxcの値を代入。
	{
		if(min > zxc[j])
		{
			min = zxc[j];
			takatyan = j;
		}
	}

/***NXTはViewメニューにてそれぞれのセンサの値をリアルタイムで見ることができるのですが、**/
/***超音波センサは計測範囲外になると”?????”と表示します。この場合にメモリに何が書き**/
/***込まるのか分からないのですが、もし0でも代入されてしまうと困るので100を代入してい***/
/***ます。                                        **/

	for(int j = 0;j <= unko-1; j++)
	{
		if(zxc[j] == 0){zxc[j] = 100; }
	}
	
	Off(OUT_AB);
	TextOut(0,LCD_LINE1,"takatyan =");
	NumOut(0,LCD_LINE2,zxc[takatyan]);
	Wait(1000);

/* 最小値と一致するまで左回転。*/

	tl;
	until( SensorUS(S4) <= zxc[takatyan] );
	PlaySound(SOUND_UP);
	Off(OUT_AB);
	
	ResetScreen();
	Wait(1000);

/*缶に接近。*/
 
	go;
	until(SensorUS(S4) <= distance);
	Off(OUT_AB);

}
 
/* (c) 2014 ONO*/

以前のプログラム

最初にこのプログラムを作ったときは、ロボットの位置を調整するのに以下の式でモーターの回転量を計算してマシンの向きを変えていました。しかしロボットの重量が重く後輪が滑らかに追従しなかったため想定よりも位置修正にブレが生じたので上記のように変更しました。

  • 計測後のマシンの左回転量=
    (最初のマシンの回転量/計測回数)*(計測回数ー最短距離を検知するまでの計測回数)

まとめ

感想

  • チームの仲間と早い時期から議論と試行錯誤を重ねて本番でとても良い結果を残す事が出来てよかったと思います。
  • 割と仲間にアドヴァイス出来た点も良かったです。(まだまだ入門レベルではありますが...)
  • 自発的にプログラミングについて調べて実際に応用したことは、怠け癖のある自分にしてはだいぶ進歩したなと思います。

反省点

  • 永遠の自宅通の名に甘んじて作業に遅刻した事。
  • ロボット制作の重要な部分にあまり携わる事ができなかったこと。(Redcicudu氏の力量が凄すぎたからちょっと仕方が無いかもしれない)
  • 割と家でコードを書かずに、講義や集まった時にその場で書いてしまった怠け精神。
  • コードの記述量と記述に費やした時間の少なさ。多ければ良いとは一概には言えないが、他の二人の作業量と比較すると不満を言われても仕方ないかもしれない。

おまけ

現代音楽(?)演奏プログラム

#define p(a,b) PlayTone(a,b);

task main()
{

	while(true)
	{
		p(Random(800),Random(500));
		Wait(Random(500)); 
	}
}

ランダムな数字を周波数と音の継続時間、休止時間に放り込んでいます。Random関数の値をかえるとえらく印象が変わる点が面白いです(笑)これを鳴らすとあまり良い顔をされないので注意が必要です。

コメント

何でもどうぞ。

  • てすてす -- pianoman? 2014-02-07 (金) 00:00:38


添付ファイル: filerobocon2013c.png 169件 [詳細] filerobocon2013d.png 176件 [詳細] fileDVC00019 (2).JPG 189件 [詳細] filerobot4.png 182件 [詳細] filerobot3.png 216件 [詳細] filerobot2.jpeg 166件 [詳細] filerobot1.jpg 106件 [詳細] filebluetooth.png 188件 [詳細] filesonic.png 170件 [詳細] filerobocon2013b2.png 185件 [詳細] filerobocon2013b.png 196件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-02-07 (金) 23:50:37 (2020d)