[[2018a/Member]]
#contents
**更新履歴 [#fa12d98f]
8月10日ー「関数の説明」において、交差点判断の解説を追加
8月20日ー缶捕獲部分の説明、交差点判断をさらに詳細に、関数の説明を追記。
8月20日ーコメントへの返答を追記
**再評価のコメントへの返答 [#n3501ca7]
 課題1を再評価しました。課題2の time1やtime2というのは何のための変数? time2-time1は  
 何を計算している? 明るさが50の場合は? -- 松本 2018-08-15 (水) 20:53:56

返答
time1、time2の解説
まず、nを引数として、0.1*n秒より多くの時間黒線上にいたら、交差点に差し掛かったと判断するということにします。
関数の最初に、time1 = time.time(), time2 = 0と初期化しますが、この値はwhile文の実行条件である、time2 - time1 < 0.1 * nを満たしていればなんでも良いです。
そして、黒線上にいるとき、モータを動かした後にtime2 = time.time()と代入され、
黒線上にいないときに、モータを動かした後にtime1 = time.time(), time2 = 0と代入されます。
ここでのtime2に代入する値はtime2 - time1 < 0.1*nを満たしていれば何でも良いです。
これにより、黒線上でないところから黒線上に移ったときに、time2-tim1の値は、黒線上にいる時間を表すことになります。故に、time2 - time1 > 0.1*nとなれば交差点であると判断できます。

明るさが50の場合については、cs.value()の値は9,90などのかなり極端な値を取ることが分かっていたので、あまり考えていませんでしたし、考える必要もないと思っていました。しかし、環境によってはcs.value()=50となることがあるかもしれないですし、その場合while文が永遠に終わらないので、どちらか一方に等号をつけるのが無難だと思います。 

**課題内容 [#b2c3e8d9]
コースは下図
#ref(2018a/Member/mochi/Mission2/s_2018a-mission2.png,100%, )
第一コースを選択。
 1.Aをスタート
 2.Bを直進
 3.Cで一時停止の後、直進
 4.Dで一時停止の後、Xの空き缶をキャッチしてD地点に戻る
 5.DからEに向かい、Eを直進
 6.Fを左折
 7.Gで一時停止の後、左折
 8.Hで一時停止の後、右折
 9.Iで一時停止の後、右折
 10.Lを直進
 11.Kを直進
 12.Jで一時停止の後、空き缶をYに置きてJに戻りBに向かう
 13.Bで一時停止の後、左折
 14.Aで停止
 (一時停止の指定がある場所は、1秒間停止すること)

*ロボット概要 [#g0a02d36]
**ロボット全体 [#m01ca068]
#ref(2018a/Member/mochi/Mission2/s_DSC_0226.JPG,100%, )
**缶捕獲部分 [#lfa7edca]
#ref(2018a/Member/mochi/Mission2/s_DSC_0230.JPG,100%, )
解説
缶の上からかご状の部品を被せることで缶をつかむ。
**カラーセンサー [#e9efc455]
線のトレースに使用
#ref(2018a/Member/mochi/Mission2/s_DSC_0227.JPG,100%, )
**超音波センサー [#r73bd426]
缶の場所検知に使用
#ref(2018a/Member/mochi/Mission2/s_DSC_0230.JPG,100%, )
*プログラム概要 [#m8e6ac56]
**モジュールのインポート [#x23979d4]
 #!/usr/bin/env python3
 from ev3dev.ev3 import *
 import time
 from time import sleep
time関数をインポート

**デバイスの名前付け [#bc709dc7]
 mL = LargeMotor("outA")
 mR = LargeMotor("outD")
 m = MediumMotor("outC")
 cs = ColorSensor("in3")
 us = UltrasonicSensor("in4")

**種々の関数を定義 [#me76c574]
 def kousaten_L(n): #黒線の左側を進み、交差点で止まる. 
 	time1 = time.time()		#判断の時間をnを変えることで変更可能
 	time2 = 0
 	while time2 - time1 < 0.1*n:
 		if cs.value() < 50:
 			mL.run_timed(time_sp = 30, speed_sp = -50, stop_action = 'brake')
 			mR.run_timed(time_sp = 30, speed_sp = 200, stop_action = 'brake')
 			time2 = time.time()
 
 		elif cs.value() > 50:
 			mL.run_timed(time_sp = 30, speed_sp = 300, stop_action = 'brake')
 			mR.run_timed(time_sp = 30, speed_sp = -50, stop_action = 'brake')
 			time1 = time.time()
 			time2 = 0
 
 def kousaten_R(n): #黒線の左側を進み、交差点で止まる。
  	time1 = time.time()		#判断の時間をnを変えることで変更可能
 	time2 = 0
 	while time2 - time1 < 0.1*n:
 		if cs.value() < 50:
 			mL.run_timed(time_sp = 20, speed_sp = 200, stop_action = 'brake')
 			mR.run_timed(time_sp = 20, speed_sp = -100, stop_action = 'brake')
 			time2 = time.time()
 
 		elif cs.value() > 50:
 			mL.run_timed(time_sp = 20, speed_sp = -100, stop_action = 'brake')
 			mR.run_timed(time_sp = 20, speed_sp = 200, stop_action = 'brake')
 			time1 = time.time()
 			time2 = 0
 
 def tyokusin_kousaten_L(): #kousaten_L(n)を使用後に使用可能。交差点を直進する
 	while cs.value() < 50:
 			mL.run_timed(time_sp = 20, speed_sp = 300, stop_action = 'brake')
 			mR.run_timed(time_sp = 20, speed_sp = 100, stop_action = 'brake')
 	while cs.value() > 50:
 			mL.run_timed(time_sp = 20, speed_sp = 300, stop_action = 'brake')
 			mR.run_timed(time_sp = 20, speed_sp = -100, stop_action = 'brake')
 
 def tyokusin_kousaten_R(): #kousaten_R(n)を使用後に使用可能。交差点を直進する
  	while cs.value() < 50:
 			mL.run_timed(time_sp = 20, speed_sp = 50, stop_action = 'brake')
 			mR.run_timed(time_sp = 20, speed_sp = 100, stop_action = 'brake')
 	while cs.value() > 50:
 			mL.run_timed(time_sp = 20, speed_sp = 50, stop_action = 'brake')
 			mR.run_timed(time_sp = 20, speed_sp = 100, stop_action = 'brake')
 
 def sasetu_kousaten_L():#kousaten_L(n)を使用後に使用可能。交差点を左折する
 	while cs.value() <50:
 		mL.run_timed(time_sp = 20, speed_sp = -50, stop_action = 'brake')
 		mR.run_timed(time_sp = 20, speed_sp = 300, stop_action = 'brake')
 
 def move_left():#直線の黒線の右側を進行中に使用可能。黒線の左側に移動する。
  	if cs.value() < 50:
 		while cs.value() < 50:
 			mL.run_timed(time_sp = 20, speed_sp = 100, stop_action = 'brake')
 			mR.run_timed(time_sp = 20, speed_sp = 100, stop_action = 'brake')
 	elif cs.value() > 50:
 		while cs.value() > 50:
 			mL.run_timed(time_sp = 20, speed_sp = 200, stop_action = 'brake')
 			mR.run_timed(time_sp = 20, speed_sp = -100, stop_action = 'brake')
 		while cs.value() < 50:
 			mL.run_timed(time_sp = 20, speed_sp = 100, stop_action = 'brake')
 			mR.run_timed(time_sp = 20, speed_sp = 100, stop_action = 'brake')
 
 def move_right():#直線の黒線の左側を進行中に使用可能。黒線の右側に移動する。
 	if cs.value() < 50:
 		while cs.value() < 50:
 			mL.run_timed(time_sp = 20, speed_sp = 150, stop_action = 'brake')
 			mR.run_timed(time_sp = 20, speed_sp = -50, stop_action = 'brake')
 	elif cs.value() > 50:
 		while cs.value() > 50:
 			mL.run_timed(time_sp = 20, speed_sp = 200, stop_action = 'brake')
 			mR.run_timed(time_sp = 20, speed_sp = -50, stop_action = 'brake')
 		while cs.value() < 50:
 			mL.run_timed(time_sp = 20, speed_sp = 150, stop_action = 'brake')
 			mR.run_timed(time_sp = 20, speed_sp = -50, stop_action = 'brake')
 
 def trace_L(n): #n秒間黒線の左側を進む。
 	time1 = time.time()
 	time2 = 0
 	while time2 - time1 < n:
 		if cs.value() < 50:
 			mL.run_timed(time_sp = 15, speed_sp = -50, stop_action = 'brake')
 			mR.run_timed(time_sp = 15, speed_sp = 300, stop_action = 'brake')
 		elif cs.value() > 50:
 			mL.run_timed(time_sp = 15, speed_sp = 300, stop_action = 'brake')
 			mR.run_timed(time_sp = 15, speed_sp = -50, stop_action = 'brake')
 		time2 = time.time()
 def trace_R(n): #n秒間黒線の右側を進む。
        time1 = time.time()
        time2 = 0
         while time2 - time1 < n:
                 if cs.value() < 50:
                          mL.run_timed(time_sp = 20, speed_sp = 300, stop_action = "brake")
                         mR.run_timed(time_sp = 20, speed_sp = -50, stop_action = "brake")
                 elif cs.value() > 50:
                         mL.run_timed(time_sp = 20, speed_sp = -50, stop_action = "brake")
                         mR.run_timed(time_sp = 20, speed_sp = 300, stop_action = "brake")
                 time2 = time.time() 
 
 def can_detection(): #黒線の左側を進み、缶を超音波センサーで缶を感知したら停止する。
 	while True:
 		if cs.value() < 50:
 			mL.run_timed(time_sp = 30, speed_sp = -150, stop_action = "brake")
 			mR.run_timed(time_sp = 30, speed_sp = 200, stop_action = "brake")
 		elif cs.value() > 50:
 			mL.run_timed(time_sp = 30, speed_sp = 200, stop_action = "brake")
 			mR.run_timed(time_sp = 30, speed_sp = -150, stop_action = "brake")
 		if us.value() < 45:
 			break
***関数の説明 [#mb647efe]
cs.value()の値は極端な数字を取ることが検証によりわかっていたので、
cs.value()<50のときは黒、cs.vakue()>50のときは白を検知しているとした。

黒線の左側をトレース時に左折と黒線の右側のトレース時に右折の動作は対称的であるため、
左折と右折の動作を別々に考える手間を省けた。

****関数の用途の説明 [#i40a1dbd]
kousaten_L(n) :黒線の左側をトレース時に交差点判断に使用
kousaten_R(n) :黒線の右側をトレース時に交差点判断に使用
tyokusin_kousaten_L() :Kousaten_L(n)実行後に交差点を直進
tyokusin_kousaten_R() :Kousaten_R(n)実行後に交差点を直進
sasetu_kousaten_L() :Kousaten_L(n)実行後に交差点を左折
move_left() :黒線の右側から左側に移動するときに使用
move_right() :黒線の左側から右側に移動するときに使用
trace_L(n) :黒線の左側をn秒進みたいときに使用
trace_R(n) :黒線の右側をn秒進みたいときに使用
can_detection() :黒線の左側をトレースし、超音波センサーで缶を感知したら停止
***関数の用途の説明 [#f109178f]
 kousaten_L(n) :黒線の左側をトレース時に交差点判断に使用
 kousaten_R(n) :黒線の右側をトレース時に交差点判断に使用
 tyokusin_kousaten_L() :Kousaten_L(n)実行後に交差点を直進
 tyokusin_kousaten_R() :Kousaten_R(n)実行後に交差点を直進
 sasetu_kousaten_L() :Kousaten_L(n)実行後に交差点を左折
 move_left() :黒線の右側から左側に移動するときに使用
 move_right() :黒線の左側から右側に移動するときに使用
 trace_L(n) :黒線の左側をn秒進みたいときに使用
 trace_R(n) :黒線の右側をn秒進みたいときに使用
 can_detection() :黒線の左側をトレースし、超音波センサーで缶を感知したら停止

****交差点判断の仕方の詳細 [#w36da433]
***交差点判断の仕方の詳細 [#p8172cb7]
交差点判断プログラムは授業中に紹介された一つのアイディアがもととなっているので、
ここでは黒線の左側をトレースし、交差点で停止する関数を例に挙げて説明する。
プログラムは以下である。

 def kousaten_L(n): #黒線の左側を進み、交差点で止まる. 
 	time1 = time.time()		#判断の時間をnを変えることで変更可能
 	time2 = 0
 	while time2 - time1 < 0.1*n:
 		if cs.value() < 50:
 			mL.run_timed(time_sp = 30, speed_sp = -50, stop_action = 'brake')
 			mR.run_timed(time_sp = 30, speed_sp = 200, stop_action = 'brake')
 			time2 = time.time()
 
 		elif cs.value() > 50:
 			mL.run_timed(time_sp = 30, speed_sp = 300, stop_action = 'brake')
 			mR.run_timed(time_sp = 30, speed_sp = -50, stop_action = 'brake')
 			time1 = time.time()
 			time2 = 0

解説
変数について
time1:実行時と地面が白色(cs.value()>50)の時にtime.time()が代入される
time2:実行時と地面が白色(cs.vakue()>50)の時に0が代入。地面が黒色(cs.value()<50)の時にtime.time()が代入される
この関数は、黒線の左側をトレースするが、その方法は、地面が白色のとき、右斜め前にゆるくカーブしながらすすみ、
地面が黒色のとき、左斜め前にゆるくカーブしながら進むことにより、ジグザグにトレースしている。
そこで、交差点に差し掛かると、黒線に沿ってロボットは左側へ導かれるが、その時に黒線上にいる時間が増えるため、
time1はそのままで、time2 =time.time()が新たに代入され、time2 - time1 > 0.1*nとなり、ロボットは停止する。
なお、このようなnは試行錯誤により見つける。

**プログラム本体 [#qc2ad313]
 mL.run_timed(time_sp = 1500, speed_sp = -125,  stop_action = "brake"); #地点Yに缶を置くためにに移動
 mR.run_timed(time_sp = 1500, speed_sp = 300, stop_action = "brake") 
 
 sleep(2)
 
 mL.run_timed(time_sp = 400, speed_sp = 300,  stop_action = "brake");
 mR.run_timed(time_sp = 400, speed_sp = -125, stop_action = "brake") #地点Yに移動終了
 
 
 sleep(2)
 
 m.run_timed(time_sp = 500, speed_sp = -100) #アーム上げ
 
 sleep(1)
 
 mL.run_timed(time_sp = 1000, speed_sp = -200,  stop_action = "brake");#地点Jへ移動開始
 mR.run_timed(time_sp = 1000, speed_sp = -200, stop_action = "brake")
 
 sleep(1)
 
 mL.run_timed(time_sp = 1200, speed_sp = 300,  stop_action = "brake");
 mR.run_timed(time_sp = 1200, speed_sp = -125, stop_action = "brake") #地点Jへ移動終了
 
 sleep(1)
 
 while cs.value() >  50:
         mL.run_timed(time_sp = 50, speed_sp = -200, stop_action = 'brake')
         mR.run_timed(time_sp = 50, speed_sp = -200, stop_action = 'brake')
 
 trace_L(5)
 
 kousaten_L(4.5) #Bで止まる
 
 sleep(1)
 
 while cs.value() < 50:
         mL.run_timed(time_sp = 10, speed_sp = -125,  stop_action = "brake");
         mR.run_timed(time_sp = 10, speed_sp = 300, stop_action = "brake")
 
 kousaten_L(4.5)
 
 while cs.value() < 50:
 	mL.run_timed(time_sp = 20, speed_sp = 300, stop_action = 'brake')
 	mR.run_timed(time_sp = 20, speed_sp = -100, stop_action = 'brake')
 
 mL.run_timed(time_sp = 2000, speed_sp = 100,  stop_action = "brake"); #Aまで進む
 mR.run_timed(time_sp = 2000, speed_sp = 100, stop_action = "brake")

*反省 [#l470be37]
・交差点判断の精度が悪い。
・地盤の材質によって調整が必要(どうしようもない)

*改善策 [#i920fa75]
・交差点の判断
 他の人の発表を拝見したところ、モーターのスピードを緩めて、振れ幅を大きくすれば精度が上がりそう。

・地盤の材質によってーー
 どうしようもない

*感想 [#d29e6eab]
ロボットの作成よりプログラムのトライアルアンドエラーの試行がとても長かった。
だが、時間をかければ結果が帰ってくるのでたのしかった。

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