[[2013b/MemberOnly/進行状況]]

#contents

*メンバ紹介 [#n3ee21c5]

:pianoman|おのくんです。今回も主にプログラム担当です。遅刻魔&早退魔。

:Redcicudu(Redcicada)|ロボット制作の権威。彼のおかげでプログラミングの時間を十分に確保できた。時々面白い言葉を吐き出す。&br;[[課題2>http://yakushi.shinshu-u.ac.jp/robotics/?2013b%2FMember%2FRedcicudu%2FMission2]]

:chikuwa|主にプログラム、時々ロボットの改良。軽快にキーボードをぶっ叩く。今回の課題の肝であるアーム部のプログラムを中心にあらゆる作業を取りまとめた。&br;[[課題2>http://yakushi.shinshu-u.ac.jp/robotics/?2013b%2FMember%2Fchikuwa%2FMission2]]

*課題2の内容 [#h82c71f8]

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

#ref(robocon2013b.png)

**すとらてじぃ [#f79f3cc7]

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

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

#ref(robocon2013b2.png)

*マシンについて [#jc89a7e5]

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

ロボットの詳細な解説は[[こちら>http://yakushi.shinshu-u.ac.jp/robotics/?2013b%2FMember%2FRedcicudu%2FMission2#wa039a17]]をご覧ください。ここでは簡単に紹介します。

***全体像 [#z7e2fa08]

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

***後輪 [#bd18e886]

#ref(robot2.jpeg,left)

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

***歯車 [#b764b5b5]

|#ref(robot3.png)|#ref(robot4.png)|

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

*プログラムの概要 [#aa05aacd]

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

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

*pianomanが担当したプログラム [#aec6c64d]

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

**Bluetoothによる通信プログラム [#pf04a566]

***プログラムの概要 [#qecb6e52]

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

[master]   →  命令  →  [slave]

 ↓                ↓

待機               処理

 ↓                ↓

[master]   ←  応答  ←  [slave]

 ↓                ↓

次の処理へ            待機

***コード [#mdb67030]

 /* 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"で他のファイルから呼び出せます。

***問題点 [#v29002a3]

~基本的に上記にある3つの命令(sendmsg,receive,respond)を使うのですが、既に出来つつあった[[chikuwa氏のアーム操作のプログラム>http://yakushi.shinshu-u.ac.jp/robotics/?2013b%2FMember%2Fchikuwa%2FMission2#ib35f3c5]]に組み込む際に以下の問題点が浮上しました。

-スレーブが受け取ったメッセージに応じてプログラム条件分岐させることが出来ない。
~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){ ~ }
       ....
     }
 }
みたいな感じで使えばもっと汎用性が高まりました。&br;
今回は条件分岐がいるところではSendRemoteNumberとReceiveRemoteNumberを使って対処しました。ちゃんと考えていればもっと入力の手間が少なくなり通信関連の作業時間を小さくすることが出来たはずです。
結局今回は条件分岐がいるところではSendRemoteNumberとReceiveRemoteNumberを使って対処しました。ちゃんと考えていればもっと入力の手間が少なくなり通信関連の作業時間を小さくすることが出来たはずです。

***苦労した点 [#pf42e6d4]

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

#ref(bluetooth.png)

***実際の使用 [#a060b626]

[[chikuwa氏のプログラム>http://yakushi.shinshu-u.ac.jp/robotics/?2013b%2FMember%2Fchikuwa%2FMission2#m65b569f]]に組み込まれています。

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

といった具合です。

**缶の検知プログラム [#z5568099]

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

***以前のプログラム [#l73deeb0]

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

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

*まとめ [#a11d439a]

***感想 [#k2408ea6]

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

***反省点 [#p37e25c5]

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

*おまけ [#ud99fff8]

***現代音楽(?)演奏プログラム [#q210f997]

 #define p(a,b) PlayTone(a,b);
 
 task main()
 {
 
	while(true)
	{
		p(Random(800),Random(500));
		Wait(Random(500)); 
	}
 }

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

*コメント [#id734b2f]

何でもどうぞ。
- てすてす -- [[pianoman]] &new{2014-02-07 (金) 00:00:38};

#comment

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS