[[2018b/Member]]
#contents
*コース [#a5d84039]
&ref(2018b/Member/shaymin/Mission2/2018b-mission2.png,80%);
**ミッション [#e3ac83af]
次のいずれかのコースで黒い線に沿って動き、途中でボールをゴール付近に立てた350mlの空き缶(黄色で表示)に当てるロボットを製作せよ。 (相棒と違うコースを選ぶこと)

***第1コース [#xcec9f29]
ロボットを長方形X内におき、Aをスタート
Bを右折
Kで一時停止して左折
Jを直進
Iを直進
Hを左折
Gで一時停止して左折
Eで一時停止して右折
Lを経て正方形Y内に入って停止
(一時停止の指定がある場所は、1秒間停止すること)

ボールはロボットが弧KJIH上にある時にQ地点の空き缶に当てる

***第2コース [#ga25fcce]
ロボットを正方形X内におき、Lをスタート
Eを一時停止して直進
Iを一時停止して左折
Hを直進
Kを直進
Jを左折
Cを一時停止して右折
Eを一時停止して直進
Gを一時停止して直進
長方形X内に入って停止
(一時停止の指定がある場所は、1秒間停止すること)

ボールはロボットが弧IHKJ上にある時にQ地点の空き缶に当てる
*ロボットの説明 [#z113c707]
***ロボットのサイズ [#pc8d310e]
***ボールを射出する機構 [#x950cb45]
*** [#u91be52a]
高さ 31.5cm 幅 20.2cm
*** ライントレースの原理と工夫[#u91be52a]
&ref(2018b/Member/shaymin/Mission2/18-12-22-16-07-52-897_deco.jpg,20%);

私たちのグループはラインの境目をたどり、ラインを進んでいくプログラムを作りました。
カラーセンサーで紙の上を読み取り、値を5つの範囲に場合分けしました。(5段階)
ですが、これだけだと十字路などの交差点を思い通りの方向に進むことはできません。
思い通りの方向に進むためには交差点を認識しなければなりません。
交差点のの一般的な認識方法として挙げられたものにtime.time()関数を用いた方法があります。
一定の『秒数』以上黒側を認識し続けると交差点とみなす、といったものですが、私はこの方法は最初の調整が簡単な反面、プログラムが難しく、その後のプログラムを書く上でとても不便だと考え少し違う方法でEV3に交差点を認識させました。
私のとった方法は『b=0』という値を用意し、黒側の値を検知した場合、bに数値を足し、白側の値や直線の値を検知した場合、bを0に戻します。
そして、bの値が一定の数値を超えたとき、交差点と認識するようにしました。
この方式をとる主な利点は一定時間bの値を上昇させないという操作が可能な点にあります。
カラーセンサーが一つしかないので交差点ではないのに交差点と誤って判断してしまうケースが多々あります。
実際、発表時に交差点を正しく認識できなかった班もありました。
ですが、bの値を任意の時間固定しておけば誤って交差点を認知することはありません。
time.time()と比べ、こちらの方法のほうが簡単で理解しやすいと思います。

***ロボット本体の説明と工夫について [#ifbc1176]
&ref(2018b/Member/shaymin/Mission2/s_18-12-22-16-14-53-708_deco.jpg,100%);

赤の矢印:このロボットはEV3の向きを設計図とは逆向きに取り付けてあります。モーターと本体をつなぐコードの種類に限りがあり、モーターの位置とコードの長さの相性が悪かったため変更しました。さらにこのEV3の本体とレゴを繋げる部分には高低差があり、その高低差を埋めるため赤い矢印の部品を取り付けています。

黄色い矢印:この黄色の矢印のセンサーで地面に書かれた線を読み取っています。しかしこのセンサーは車輪との距離が離れすぎてしまうと機体が振れた時、センサーの値の変化が大きくなってしまいます。そこでこのセンサーを車輪になるべく近づけ、かつ安定した強度を保つため写真の黄色い矢印のような部品を使用しました

&ref(2018b/Member/shaymin/Mission2/s_18-12-22-16-21-01-069_deco.jpg,100%);

青い矢印:青い矢印の正面にはミディアムモーターが取り付けられています。ミディアムモーターが十字の棒を回して射出機を動かすために反対側はぼうにの場所だけを固定し、回転を妨げないようにしなければならないため、穴の丸い部品を使用しました。

水色の矢印:水色の矢印はボールのクッションのような役割を果たしています。ボールを持って移動しなければならないため機体や射出部分が揺れた時に振動が伝わらないように付けました。

緑の矢印:緑の矢印も水色の矢印と似たような役割を持っていて、機体や射出部分が揺れた時にボールが飛び出すのを防ぐための部分です。

&ref(2018b/Member/shaymin/Mission2/s_18-12-22-16-25-18-100_deco.jpg,100%);

黄緑の矢印:黄緑色の矢印に取り付けられている灰色の棒は、実は固定されてはおらず矢印の先についている黒い部品の出っ張っている部分に挟まれているだけの状態です。しかしこの棒は回転こそするものの、位置は固定されています。この部品によってレールは"内側"から幅が変わらないように固定されます。

茶色の矢印:この茶色の矢印はこの射出するレールを"外側"から抑え幅が広がらないようにする役割を持っています。棒もボールに当たらない位置に取り付けてあります。

&ref(2018b/Member/shaymin/Mission2/s_18-12-22-16-28-18-127_deco.jpg,100%);

桃色の矢印:青い矢印の裏側です。丸い穴の開いた長い白い部品の側面を使い、ミディアムモーターと繋がっている棒が飛び出さないように抑えています。

紫の矢印:この部品はとても重要な役割を果たしています。この小さな部品ひとつで3つの部品を繋いでいます。この部品がないと射出する機構が崩壊するしてしまうほど大切な部分です。

***ボールを射出する機構 [#t5b84b79]
&ref(2018b/Member/shaymin/Mission2/s_20181222_153103175.jpg,100%);
射出→
&ref(2018b/Member/shaymin/Mission2/s_20181222_153121600.jpg,100%);

*プログラムとプログラムの説明 [#ncfb5e9a]
**コース1 [#e34eb78d]
 #!/usr/bin/env python3
 from ev3dev.ev3 import *
 from time import sleep
 mL = LargeMotor('outA')
 mR = LargeMotor('outB')
 mi = MediumMotor('outD')
 s1 = TouchSensor('in3')
 s2 = ColorSensor('in4')
 U1 = UltrasonicSensor('in2')#部品の呼び名と出力先を指定
#ここから定義
 def laf(t):#やや左前に前進
        mL.run_timed(time_sp=30,speed_sp=120+20*t,stop_action='brake')
        mR.run_timed(time_sp=30,speed_sp=120-20*t,stop_action='brake')
 def raf(t):#やや右前に前進
        mL.run_timed(time_sp=30,speed_sp=120-20*t,stop_action='brake')
        mR.run_timed(time_sp=30,speed_sp=120+20*t,stop_action='brake')
 def tl(t):#左旋回
        mL.run_timed(time_sp=20,speed_sp=-150*t,stop_action='brake')
        mR.run_timed(time_sp=20,speed_sp=150*t,stop_action='brake')
 def tr(t):#右旋回
        mL.run_timed(time_sp=20,speed_sp=100*t,stop_action='brake')
        mR.run_timed(time_sp=20,speed_sp=-100*t,stop_action='brake')
 def fd():#前進
        mL.run_timed(time_sp=20,speed_sp=150,stop_action='brake')
        mR.run_timed(time_sp=20,speed_sp=150,stop_action='brake')
 def roll(t,s):#任意の方向に進む
        mL.run_to_rel_pos(position_sp=t,speed_sp=150,stop_action='brake')
        mR.run_to_rel_pos(position_sp=s,speed_sp=150,stop_action='brake')
 def throwing(s,t):#ミディアムモーターのボールの射出
        mi.run_timed(time_sp=s,speed_sp=t,stop_action='brake')
 def turn(s,t):#任意の方向に任意の速度で回転
        mL.run_timed(time_sp=s,speed_sp=t,stop_action='brake')
        mR.run_timed(time_sp=s,speed_sp=-t,stop_action='brake')

 roll(150,150)
 sleep(3)
 w = 0#白側を連続して観測した回数を保存する
 b = 0#黒側を連続して観測した回数を保存する
 i = 0#交差点の数をカウントする
 while i <= 1:#1個目の交差点まで
        t0 = time.time()
        if i==0:
                e=6
        else:
                e=9
        while s1.value() == 0:
                if time.time()-t0 <= e:
                        b=0
                if 65 < s2.value():
                        tl(1)
                        w=w+1
                        b=0
                if 55 < s2.value() <= 65:
                        laf(1)
                        w=w+1
                        b=0
                if 50 < s2.value() <= 55:
                        fd()
                        w=0
                        b=0
                if 40 < s2.value() <= 50:
                        raf(1)
                        b=b+0.6
                        w=0
                if s2.value() <= 40:
                        tr(1)
                        b=b+1
                        w=0
                elif b>35:
                        i=i+1
                        break
        if i == 1:
                roll(60,20)
                sleep(2)
                roll(60,-110)
                sleep(2)
                roll(0,-90)
        if i == 2:
                sleep(1)
                roll(-100,130)
                sleep(3)
                roll(20,20)
                sleep(3)
 while 2 <= i <= 8:#2個目から8個目の交差点の間
        t1 = time.time()
        if i==3:
                s=1.2
        elif i==6:
                s=8
                sleep(2)
        elif i==7:
                s=1.2
        elif i==8:
                s==0.3
        else:
                s=1.0
        while s1.value() == 0:
                if time.time()-t1 <= 7*s:
                        b=0
                if 65 < s2.value():
                        tl(-1)
                        w=w+1
                        b=0
                if 55 < s2.value() <=65:
                        laf(-1)
                        w=w+1
                        b=0
                if 50 <s2.value() <=55:
                        fd()
                        w=0
                        b=0
                if 40 <s2.value() <=50:
                        raf(-1)
                        w=0
                if s2.value()<=40:
                        tr(-1.2)
                        b=b+1
                        w=0
                elif b>35:
                        i=i+1
                        print(i)
                        break
        if i==3:
                roll(200,0)
                sleep(3)
        if i==4:
                roll(200,0)
                sleep(3)
                I=0
                while s1.value()==0:#超音波センサーの最小値を記録
                        u=100000
                        t0=time.time()
                        print(I)
                        turn(12000,70)
                        while time.time()-t0 <= 12:
                                if u >=U1.value():
                                        u=U1.value()
                                        t1= time.time()
                                        print(u)
                                else:
                                        continue
                        sleep(0.5)
                        t2=time.time()
                        sleep(1)
                        print(t1)
                        print(t2)
                        t3=t2-t1
                        print(t3)
                        turn(t3*(1050+5*i),-70)#最小値を記録した地点まで戻る
                        sleep(t3*1.2)
                        if u+25>U1.value():
                                throwing(1000,50)#投げる
                                sleep(3)
                                throwing(1000,-50)
                                break
                        elif I == 3:
                                throwing(1000,50)
                                sleep(3)
                                throwing(1000,-50)
                                break
                        else:
                                I=I+1#缶を発見できなかった場合再度索敵を行う
                roll(180,-180)
                sleep(3)
        if i==8:
                roll(-10,-10)
                sleep(2)
                roll(350,-20)
                sleep(5)
 roll(95,-95)
 sleep(2)
 roll(300,300)

**コース2 [#j88bd7c7]
 #!/usr/bin/env python3
 from ev3dev.ev3 import *
 from time import sleep
 mL = LargeMotor('outA')
 mR = LargeMotor('outB')
 mi = MediumMotor('outD')
 s1 = TouchSensor('in3')
 s2 = ColorSensor('in4')
 U1 = UltrasonicSensor('in2')#部品の呼び名と出力先を指定
#ここから定義
 def laf(t):#やや左前に前進
        mL.run_timed(time_sp=30,speed_sp=120+20*t,stop_action='brake')
        mR.run_timed(time_sp=30,speed_sp=120-20*t,stop_action='brake')
 def raf(t):#やや右前に前進
        mL.run_timed(time_sp=30,speed_sp=120-20*t,stop_action='brake')
        mR.run_timed(time_sp=30,speed_sp=120+20*t,stop_action='brake')
 def tl(t):#左旋回
        mL.run_timed(time_sp=20,speed_sp=-150*t,stop_action='brake')
        mR.run_timed(time_sp=20,speed_sp=150*t,stop_action='brake')
 def tr(t):#右旋回
        mL.run_timed(time_sp=20,speed_sp=100*t,stop_action='brake')
        mR.run_timed(time_sp=20,speed_sp=-100*t,stop_action='brake')
 def fd():#前進
        mL.run_timed(time_sp=20,speed_sp=150,stop_action='brake')
        mR.run_timed(time_sp=20,speed_sp=150,stop_action='brake')
 def roll(t,s):#任意の方向に進む
        mL.run_to_rel_pos(position_sp=t,speed_sp=150,stop_action='brake')
        mR.run_to_rel_pos(position_sp=s,speed_sp=150,stop_action='brake')
 def throwing(s,t):#ミディアムモーターのボールの射出
        mi.run_timed(time_sp=s,speed_sp=t,stop_action='brake')
 def turn(s,t):#任意の方向に任意の速度で回転
        mL.run_timed(time_sp=s,speed_sp=t,stop_action='brake')
        mR.run_timed(time_sp=s,speed_sp=-t,stop_action='brake')
 roll(150,150)
 sleep(3)
 w=0#白側を連続して観測した回数を保存する
 b=0#黒側を連続して観測した回数を保存する
 i=0#交差点の数をカウントする
 while s1.value() == 0:#コース1と違いすべて左側トレース
        t0 = time.time()
        if i == 0:
                s=0.2
        elif i == 3:
                s=1.0
        elif i == 6:
                s=3
        elif i == 7:
                s=1.1
        elif i == 8:
                s=6.5
        elif i == 9:
                s=0.7
        else:
                s=0.8
        while i <= 9:
                if time.time()-t0 <= 7*s:
                        b=0
                if 65 < s2.value():
                        tl(-1)
                        w=w+1
                        b=0
                if 55 < s2.value() <= 65:
                        laf(1)
                        w=w+1
                        b=0
                if 50 < s2.value() <= 55:
                        fd()
                        w=0
                        b=0
                if 40 < s2.value() <= 50:
                        raf(1)
                        b=b+0.6
                if s2.value() <= 40:
                        tr(-1)
                        b=b+1
                        w=0
                elif b>33:
                        i=i+1
                        print(i)
                        break
        if i == 1:
                sleep(2)
                roll(30,-30)
                sleep(1)
                roll(50,50)
                sleep(2)
        if i == 3:
                roll(200,0)
                sleep(2)
                I=0
                while s1.value()==0:#超音波センサーの最小値を記録
                        u = 100000
                        t0=time.time()
                        print(I)
                        turn(12000,70)
                        while time.time()-t0<= 12:
                                if u >=U1.value():
                                        u = U1.value()
                                        t1 = time.time()
                                        print(u)
                                else:
                                        continue
                        sleep(0.5)
                        t2=time.time()
                        sleep(1)
                        print(t1)
                        print(t2)
                        t3=t2-t1
                        print(t3)
                        turn(t3*(1040+10*i),-70)#最小値を記録した地点まで戻る
                        sleep(t3*1.2)
                        if u+20>U1.value():
                                throwing(1000,50)#投げる
                                sleep(3)
                                throwing(1000,-50)
                                break
                        elif I == 3:
                                throwing(1000,50)
                                sleep(3)
                                throwing(1000,-50)
                                break
                        else:
                                I=I+1#缶を発見できなかった場合再度索敵を行う
                sleep(2)
                roll(-30,-30)
                sleep(3)
        if i == 4:
                roll(200,0)
                sleep(2)
        if i == 6:
                roll(-10,-10)
                sleep(2)
                roll(420,-20)
                sleep(6)
        if 8 <= i <= 9:
                roll(30,-30)
                sleep(1)
                roll(70,70)
                sleep(2)
        if i == 10:
                roll(50,-50)
                sleep(1)
                roll(250,250)
                break

*感想、考察 [#r5bc3aeb]
今回初めてライントレースだったので、速さより正確さを重視したプログラムを組みました。前回の課題1の経験を活かしさらなるEV3の安定化を図りました。
ライントレースについて、交差点を認識して行動をするので曲がり角のある側の側面を沿って進まなければなりません。例えば、円の内側や、外周の外側をトレースするのは得策ではありませんでした。そのため、今回のコース1では外周の外側のトレースができないので右側トレースを使い、その後は円の内側をトレースしないよう左側トレースを使用しました。この使い分けを考えるのにとても苦労しました。
ロボット本体や充電の状態に左右されやすいので、動作をゆっくり行い、安定性を重視することはとても重要だと考える。


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS