#contents

*メンバー紹介 [#w90589e8]

[[michaegon>2013b/Member/michaegon/Mission1]]
 我が班最強のプログラマー。奇想天外なプログラムを書く。いきなり「ここの微分とシンクロ率が云々」言い始めた時はこいつ頭大丈夫か?と本気で心配した。

[[pepo>2013b/Member/pepo/Mission1]]
 言わずと知れたプロ。こちらの要望道理のロボットを組み立ててくれる。職人。

dyuma 自分です。
 下請け。


*課題の条件 [#l4666a6f]

[[2013b/Mission1]]
#ref(2013b/Member/dyuma/Mission1/7330920413472.gif);
1〜6は交差点番号です。~
このように番号を振り、1と6では曲がる、2〜5では直進するように組みました。~
青丸の位置に缶です。

*プログラム概要 [#h51d7538]

**イントロダクション [#n2511cbd]

このプログラムは「honban2.nxc」というファイル名で作りました。~
本番用のプログラムをつくろうと思い名前をhonbanに、そしてその直前に作っていた「honkaku1.nxc」と字が似ていて紛らわしいので、2をつけました。~
もともと作りかけていて不具合が全体的にあった「tekitou」シリーズの改良版です。~
よって、このページでは、僕の作ったこのプログラムをhonbanと表記させていただきます。


**honban [#v8a0ab38]

まずはうまく行ったプログラムソースを。
 #define sikiiti 40  //黒と白のしきい値
 #define WMAX  50000 //線を外れたとき、どれだけ戻るか。
 #define BMAX  10   //交差点の判定
 #define go_right OnFwd(OUT_C,50);OnFwd(OUT_B,-30);
 #define go_left OnFwd(OUT_C,-30);OnFwd(OUT_B,50);
 #define go_straight OnFwd(OUT_BC,20);
 #define back_right OnFwd(OUT_C,-50);OnFwd(OUT_B,30);
 #define back_left OnFwd(OUT_C,30);OnFwd(OUT_B,-50);
 #define back_straight OnFwd(OUT_BC,-40);
 #define STOP Off(OUT_BC);Wait(1000);
 #define senkai OnFwd(OUT_B,-30);OnFwd(OUT_C,30);Wait(2100);
 #define tukamu OnFwd(OUT_A,20);Wait(1100);Off(OUT_A);
 #define hanasu OnFwd(OUT_A,-20);Wait(900);Off(OUT_A);
 #define SPEEDy 18
 #define importantnumber 4000 //弄ってピッタリの数値を探せ。
 
 int count1=1,count2=0/*黒カウンタ*/,count3=0/*白カウンタ*/,count4=0,count5=0; //カウンタ用意
 
 inline void turn_right(){
 		count3++;
 		count2=0;
 		go_right;
 	}
 
 inline void turn_left(){
 		count2++;
 		count3=0;
 		go_left;
 	}
 
 inline void come_right(){
 		STOP;
 		while(count3>0){
 			back_right;
 			count3--;
 			Wait(1);
 		}
 		STOP;
 	}
 
 inline void kousa_ten(){
  	STOP;
 	back_left;
 	Wait(250);
 	STOP;
 	go_straight;
 	Wait(1200);
 	STOP;
 	
 	}
 
 inline void yukku_ri(){
 	if(SENSOR_1>sikiiti+10){//白いとき
 		OnFwd(OUT_C,SPEEDy*2);OnFwd(OUT_B,SPEEDy*-2);
 	}else if(SENSOR_1>sikiiti){
 		OnFwd(OUT_C,SPEEDy*2);OnFwd(OUT_B,SPEEDy);
 	}else if(SENSOR_1>sikiiti-10){//黒いとき
 		OnFwd(OUT_C,SPEEDy);OnFwd(OUT_B,SPEEDy*2);
 	}else{
 		OnFwd(OUT_C,SPEEDy*-1);OnFwd(OUT_B,SPEEDy*2);
 	}
  	}
 
 inline void WARNING_KAN(){
	STOP;
	while(SensorUS(S2)>10){
		yukku_ri();
	}
	STOP;
	tukamu;
	STOP;
	while(count5<=importantnumber){
		yukku_ri();
		Wait(1);
		count5++;
	}
	STOP;
	senkai;
	STOP;
	hanasu;
	back_straight;
	Wait(1000);
	STOP;
	senkai;
	while(SENSOR_1<=sikiiti){
		go_right;
	}
	}
 
 inline void Last_action(){
	;/*ここに最終行動を書く*/
	}
 
 task main(){
	SetSensorLight(S1);
	SetSensorLowspeed(S2);
	OnFwd(OUT_A,-5);
	while(count1<7){
		if(SENSOR_1>sikiiti){//白いとき
			if(count3<=WMAX){
				turn_right();
			}else{
				come_right(); //行き過ぎたら戻る
			}
		}else if(SENSOR_1<=sikiiti){//黒いとき
			if(count2<=BMAX){
				turn_left();
			}else{
				PlayTone(440,20);
				if(count1<=5&&count1>=2){//二回目から五回目は交差点を直進する。
					kousa_ten();
				}
				while(SENSOR_1<=sikiiti){
					go_left;
				}
				count1++;
			}
		}
		if(SensorUS(S2)<=15&&count4==0){
				WARNING_KAN();//ここに缶に当たった時の動作
				count4++;
		}
		Wait(1);
	}
	Last_action();
 	}
 }



**honbanの解説 [#t942cb59]

***設定した変数などの解説 [#r432a29b]
 #define sikiiti 40  //黒と白のしきい値
白と黒の境の値です。環境によって値を変えないといけないのですが、汎用性を持たせるために、学校での値と自宅での昼と夜の値を測定し、全てで使える値を使用してます。

 #define WMAX  50000 //線を外れたとき、どれだけ戻るか。
[[補足>#p9384b02]]に書きました。

 #define BMAX  10   //交差点の判定
黒がどれだけ続けば交差点かどうか判断します。電池が無くなってくれば、この値を上げないと普通のカーブでも交差点判定してしまいます。

 #define go_right OnFwd(OUT_C,50);OnFwd(OUT_B,-30);
 #define go_left OnFwd(OUT_C,-30);OnFwd(OUT_B,50); 
 #define go_straight OnFwd(OUT_BC,20);
 #define back_right OnFwd(OUT_C,-50);OnFwd(OUT_B,30);
 #define back_left OnFwd(OUT_C,30);OnFwd(OUT_B,-50);
 #define back_straight OnFwd(OUT_BC,-40);
 #define STOP Off(OUT_BC);Wait(1000);
前へ進む、右へ進む、左へ進む、それぞれのバック、それから止まるを定義しています。

 #define senkai OnFwd(OUT_B,-30);OnFwd(OUT_C,30);Wait(2100);
 #define tukamu OnFwd(OUT_A,20);Wait(1100);Off(OUT_A);
 #define hanasu OnFwd(OUT_A,-20);Wait(900);Off(OUT_A);
缶を掴んだ時に必要な、旋回と掴む動作と離す動作を定義しています。

 #define SPEEDy 18
[[缶を掴んでどかす>#lc3f8fd1]]に書きました。

 #define importantnumber 4000 //弄ってピッタリの数値を探せ。
缶を掴んでからどのくらい進むかを定義しています。電池が無くなってくれば値をあげます。
 
 int count1=1,count2=0/*黒カウンタ*/,count3=0/*白カウンタ*/,count4=0,count5=0; //カウンタ用意
カウントの解説。(数字はカウンターを作った順番です。)~
count1:交差点の回数をカウントしています。~
count2:黒がどれだけ続いているかカウントしています。~
count3:白がどれだけ続いているかカウントしています。~
count4:缶に近づいた回数をカウントしています~
count5:缶を掴んだあと、どのくらい進んだかカウントしています。~

***作ったinline関数の解説。 [#v9c8cc9f]

 inline void turn_right(){
 		count3++;
 		count2=0;
 		go_right;
 	}

光センサーの値が白を示せば、白のカウンターを1増やして黒のカウンターをリセットします。
 
 inline void turn_left(){
 		count2++;
 		count3=0;
 		go_left;
 	}

逆に黒であれば、黒のカウンターを1増やして白のカウンターをリセットします。

 inline void come_right(){
 		STOP;
 		while(count3>0){
 			back_right;
 			count3--;
 			Wait(1);
 		}
 		STOP;
 	}

[[補足>#p9384b02]]に書いているWMAXの話で、本来の道に戻るために書いたものです。

 inline void yukku_ri(){
 	if(SENSOR_1>sikiiti+10){//白いとき
 		OnFwd(OUT_C,SPEEDy*2);OnFwd(OUT_B,SPEEDy*-2);
 	}else if(SENSOR_1>sikiiti){
 		OnFwd(OUT_C,SPEEDy*2);OnFwd(OUT_B,SPEEDy);
 	}else if(SENSOR_1>sikiiti-10){//黒いとき
 		OnFwd(OUT_C,SPEEDy);OnFwd(OUT_B,SPEEDy*2);
 	}else{
 		OnFwd(OUT_C,SPEEDy*-1);OnFwd(OUT_B,SPEEDy*2);
 	}
  	}


缶に近づいて運ぶ動作です。これがあるため、このプログラムでは直線上に置いてある缶しか掴めません。しかし、利点としてはまっすぐに缶に近づけるので、ミス自体は非常に少ないです。

 inline void WARNING_KAN(){
	STOP;
	while(SensorUS(S2)>10){
		yukku_ri();
	}
	STOP;
	tukamu;
	STOP;
	while(count5<=importantnumber){
		yukku_ri();
		Wait(1);
		count5++;
	}
	STOP;
	senkai;
	STOP;
	hanasu;
	back_straight;
	Wait(1000);
	STOP;
	senkai;
	while(SENSOR_1<=sikiiti){
		go_right;
	}
	}

缶に近づいて、掴んで、動かして、缶を元の場所に戻して、離して、離れるまでの動作が書かれています。ここまでこの関数が長ければ、sub関数を使ったほうが良かったかもしれません。連続して缶を動かすこともありませんし。参照→[[缶を掴んでどかす>#lc3f8fd1]]

 inline void Last_action(){
	;/*ここに最終行動を書く*/
	}

[[補足>#p9384b02]]に書きました。


12/13 授業中~
更新:12/13 授業中~
[[授業中にうまく行ったプログラムをここに残しておきます。>2013b/Member/dyuma/Mission1/program]]

***ライントレース [#x03f134b]
基本は普通のライントレースです。~
それに、交差点判定(黒がいくつか続けば交差点だろう)を入れました。~
これだけではスタートとゴールでも交差点判定されちゃうので、一回目の交差点と六回目の交差点は
例外処理(無視)するようにしました。~
あとは白と黒のしきい値、速度調節、交差点判定の限界値、などを求めてプログラムに組み込めば、基本的なライントレースはできました。

***缶を掴んでどかす [#lc3f8fd1]
光センサーである程度近づくと、WARNING_KANというinline関数に入ります。~
ここに缶に近づいた時の動作が書かれています。~
まずは適切な距離までゆっくり近づき、まっすぐ腕を下ろすことで、缶を枠に入れて掴みます。~
この時の動作で、缶にまっすぐ近づかないと缶をうまく掴んでくれないので、このプログラムは直線上のみ缶をつかむことのできるinline関数です。~
もし、カーブ上にもう一つの缶を置きそれも適切にどかす、なんて課題もやろうと思えば、それ用のプログラムを別に書かなければなりません。~
(そのために、count4では二回目以降は缶が近づいても反応しないようにするフラグになっていますが、2つ目の缶を置いた時、反応時の動作にも対応できるようになっております。)~
そして、慎重に缶を運び(わずかに遅くなっています。元々はもっと遅くするつもりでしたが、この速度でも缶は安定していたため、本当にわずかにしか速度は落とさないようにしました。この速度はSPEEDyで制御できます。yが小文字なのは単なる趣味です。)、反転して缶を置き、少しだけバックして反転、そして普通のライントレースに戻ります。~
この時のすべての変数の値は、ちょうど隅の位置で最適化されていますので、仮に缶を他の場所に移すと、また変数を適切な値に直さなければなりません。~

***補足 [#p9384b02]

-ライントレースは、本来は白と黒のしきい値に段階を設けて、6段階くらいでやろうと思っていたのですが、時間不足で二段階になっております~
6段階に分けてしまうと、この方法の交差点判定が非常にややこしくなるためです。~
大きく蛇行しているときと、比較的まっすぐ進んでいる時では、値が大きく変わってしまいます。~
その辺りも解決の手段もあるのでしょうが、とりあえずはうまくいくプログラムを作ることが目標でしたので、完成度は二の次になっております。~

-WMAXというのを作ってますが、実質意味はないです。~
本来の使い方をするならば、線から外れすぎた時に戻すようにするためにプログラム上には書いていたのですが、思いの外大きく線から外れることもなく、むしろ下手な値を入れてしまうとうまく行っている時に干渉してしまう可能性もあったため、実際ほぼ起こりえない値で設定しています。~
もし将来的にこのプログラムをいじっていって、線からはみ出して迷走するようであれば、適切な値を入れようと思います。

-countがここまで増えると予めわかっていたなら、配列を使うべきだったかもしれません。

-コース上の他の場所に缶を置くことも考えたのですが、ここが一番安定して動作します。~
角ですからやりやすいのですが、角も交差点に入るなら他の場所を考え、その場所にあった値を設定せねばなりません。~
ロボットの大きさとコースの狭さ的に干渉しないところとなると、他の場所はかなり難しいです。

-最終行動はとりあえずは空白です。~
先にも述べました通り、完成度は二の次ですので。~
でも、将来的には、きちんとゴール出来たことを喜ぶような動作を入れたいと思っています。

-逆回りは班員のmichaegonがどちらでも対応できるプログラムを作ってくれているので、片方周りに特化しました。~
モーターの線のBとCを入れ替えて、値を弄ってしてやればできないことはないとは思いますが。

**honbanの実機動画 [#q0504ba4]

youtube http://www.youtube.com/watch?v=37fDI1v68Mo

自分の声が入ってますが、気にしないでください。~
補足でも書いたように二段階になっておりますので、ロボットはかなり揺れています。~
段階を増やせば、揺れ自体は減少させることができますが、成功確率はおそらく一時的に下がります。~
しかし、このプログラムならライントレースはほぼ100%、缶を掴む動作も90%以上の確率で成功します。(たまに失敗します。原因の大半は電池の問題です。次の章で説明します。)~
これでも課題の条件は満たしているので、いいと思います。~
完成度を更に求めるなら、段階を増やして何回もデバッグして、確率を上げるべきです。

**honbanの作成過程の話。 [#u405b9cf]

まあすべてのプログラムで言えることですけど、実機で動かして、「この値はもっと大きいほうがいい」、「ここはこうした方がいいだろう」を繰り返しました。~
「honban2.nxc」を調整していた矢先、「なんか速度が遅くなっているな〜」と思い、とりあえずはうまくいくように値を弄ってうまく動くようにしました。~
その時に撮った映像。

youtube http://www.youtube.com/watch?v=pD-EBmUX8SA

で、何周かさせてうまくいくことを確認しました。~
翌日朝、もう一度動かしてみると、なぜかうまくいきません。~
原因はどうも電池では?と思い、替えてみたところ、同じプログラムなのに速度がものすごく速くなりました。~
値も全部弄り直し・・・~
電池の残量に依存しない方法(モーターが回った角度を測る、予め電池容量をロボに判断させ適切な値に自動で入れるなど)を取ったほうがいいかもしれません。

プログラム自体、かなり無駄が多く作ってあります。~
もっと短くつくろうと思えば、変数の数を減らしたり、構文を複雑なものに変えたり、やりようはあると思いますが、わかりやすいプログラムを目指してみました。~
作っている時、どこをどういじればいいかわかりやすかったです。

逆に、task mainは短く簡潔につくってあります。~
ここで全体の流れが分かるかと思います。~
inline関数名も分かりやすく作りました。~
とくにWARNING_KANは気に入っています。~

*ロボット概要 [#o0092d58]

**缶を掴む。 [#md894f0c]
#ref(2013b/Member/dyuma/Mission1/2013-11-23 12.33.46.jpg,360x480);

最初はこのように、横から缶を掴む感じでした。~
しかし、力が弱く腕も短く、なんともしようがなかったので、最終的に上から下ろす形になりました。~
(写真がこれしか残ってなかったので使ったのですが、マイクとタッチセンサーは全く意味がありません。ただかっこいいからとつけてみて、記念にとった写真しか残っていませんでした(笑))

#ref(2013b/Member/dyuma/Mission1/2013-12-06 17.58.27.jpg,360x480);
#ref(2013b/Member/dyuma/Mission1/2013-12-06 17.58.30.jpg,360x480);
#ref(2013b/Member/dyuma/Mission1/2013-12-06 17.58.35.jpg,360x480);
#ref(2013b/Member/dyuma/Mission1/2013-11-29 22.00.43.jpg,360x480);

上から下ろしてくる形にして安定しました。~

**その他の改良点 [#ee43e8d8]
[[他の班員のページを参照してください。>#w90589e8]]

*Mission2に向けて [#va69ef21]

さらなるプログラミング力の向上と共に、よみやすいわかりやすいプログラムを目指します。~
できなかった六段階もやりたいです。~

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