課題2

黒い線に沿って決められたコースを進みピンポン球を途中でつかみゴールにシュートせよと言う課題であった。

コース

A地点から出発 → B → C(直進) → D(一時停止の後、直進) → E → F → G(一時停止の後、右折) → H → I → J(右折) → K(左折) → L(ピンポン玉をつかむ) → K(直進) → M(一時停止) → シュート→ A地点に入る(ゴール) のコースにした。

コース

ロボット

robo

なるべくカラーセンサーが2つのタイヤの真ん中にくるようにし、回転の中心をカラーセンサーの位置になるようにした。 robo4

球を拾うアームをカラーセンサーの前に設置した。このアームを上下させることで球を拾い、運び、シュートする。 robo2

ライントレース

ライントレースの基本的な方針は以下の通りである。カラーセンサーの範囲の一部にコースが入るようにセッティングし、ある明るさの時は直進、それより暗くなったら右回転(Rturn)、明るくなったら左回転(Lturn)する。

暗い

セッティングする位置をコースにあまりかぶらないようにする。そうすることで交差点に入ったときはカーブに比べ急激に暗くなる。これで交差点を認識する。

暗くなる

それぞれの明るさの値は下図の通りである。実際に走らせる時にコードの中にprint(cs.value())を入れると明るさの値を知ることが出来る。それを元に明るさの値の境界を決めた。(なおラインの無い真っ白のときは80以上の値になる。)

明るさの値

この下写真でカラーセンサーは50を返す。

robo5

プログラム

始めに

  • ev3dev用に書かれたpythonライブラリやsleep関数などを導入する。
    #!/usr/bin/env python3
    from ev3dev.ev3 import *
    from time import *
    m = LargeMotor('outA')
    n = LargeMotor('outB')
    l = MidiumMoter('outC')
    cs = ColorSensor('in2')
    cs.mode = 'COL-REFLECT'

mは左側の車輪を動かすモーター、nは右側の車輪を動かすモーター、lはアームを上げ下げさせるモーターを表している。csはカラーセンサーのことで今回は色の明るさが明るくなるほど値が大きくなるように0〜100までの値を返す。 d_sp=150)

    n.run_timed(time_sp=100, speed_sp=150)
def back():
    m.run_timed(time_sp=100, speed_sp=-150)
    n.run_timed(time_sp=100, speed_sp=-150)

前回の「機体を動かすスピードが速すぎる(speed_sp=500)と動作が全く安定しない」という反省も活かし、今回はスピードを150で統一した。

def Rturn(x):
    m.run_to_rel_pos(position_sp=10+x, speed_sp=100, stop_action='brake')
    n.run_to_rel_pos(position_sp=0, speed_sp=100, stop_action='brake')
def Lturn(x):
    m.run_to_rel_pos(position_sp=0, speed_sp=100, stop_action='brake')
    n.run_to_rel_pos(position_sp=10+x, speed_sp=100, stop_action='brake')

Lturnで右タイヤを軸に左回転、Rturnで左タイヤを軸に右回転する。基本的にはxに0を代入し少しずつ回転するようにするが、一度にたくさん回転させたいときはxに大きな値を入れるようにする。

def RRturn(x):
    m.run_to_rel_pos(position_sp=10+x, speed_sp=100, stop_action='brake')
    n.run_to_rel_pos(position_sp=-10-x, speed_sp=100, stop_action='brake')
def LLturn(x):
    m.run_to_rel_pos(position_sp=-10-x, speed_sp=100, stop_action='brake')
    n.run_to_rel_pos(position_sp=10+x, speed_sp=100, stop_action='brake')

RRturnで機体を中心に右回転、LLturnで機体を中心に左回転する。上と同様に基本的にはxに0を代入し必要に応じて大きな値を代入する。

def armup():
    l.run_to_abs_pos(position_sp=100,speed_sp=100,stop_action="hold")
    sleep(0.1)
def armdown():
    l.run_to_abs_pos(position_sp=-100,speed_sp=100,stop_action="hold")
    sleep(0.1)

armup()でアームを上げ、armdown()で下げる。大きい角度上げたり、速いスピードで上げると球が吹っ飛んでいくので気をつける。

コース分け

コースを下図のようにいくつかのブロックに分けてプログラムの説明をする。

コースブロック

第1ブロック(赤)

第1ブロックではCとDに交差点があり、そこを直進する必要がある。そこでtyoku関数を定義する。tyoku関数は明るさの値が15以上(交差点を越える)まで直進をし続ける関数である。

def tyoku():
    a=cs.value()
    while(a<15):
        run()
        sleep(0.1)
        a=cs.value()

1つめの交差点でtyoku関数を使い、2つめの交差点で1秒sleepさせtyoku関数を使えば第1ブロックは通過…と上手くはいかない。1つめの交差点を越した後直進しすぎてしまい、カーブであるのに交差点と認識してしまう暗さの所まで進んでしまい、2つめの交差点と認識してしまう。 ちょく

これを防ぐために「1つめの交差点を認識してからしばらくは2つめの交差点はは来ない」といった風にする必要がある。今回は「40回以上ループしないと次の交差点は来ない」とした。こうすることで本来交差点と認識する暗さであっても右回転し続けカーブのライントレースが出来る。

c=0 #交差点の数
d=40 #ループした数(1つめの交差点からループした回数を数えたいので始めは40からスタート)
while True:
    d=d+1
    start=cs.value()
    if (start>=15 and start<=50) or (start<15 and d<=40): #右回転
        Rturn(0)
    elif start>=65: #左回転
        Lturn(0)
    elif start<15 and d>40: #交差点 40回ループするまでは交差点と認識させない
        c=c+1
        if c==1: #1つめの交差点
            d=0 #0回目としループした回数を数える
        if c==2: #2つめの交差点
            sleep(1) #1秒間停止
        tyoku()
    else: #直進
        run()
        sleep(0.1)

これで第1ブロックを通過出来る。

第2ブロック(橙)

E,Fの90°回転で、右タイヤを軸とする右回転をすると上手くいかない。下図のように回転している途中にラインを飛び越えてしまうからだ。

飛び越える 飛び越えない

よって、機体を中心とした回転にする必要がある。新しい関数Rmagaを定義する。

def Rmaga():
    a=cs.value()
    while(a<50):
        sleep(0.1)
        RRturn(0)
        sleep(0.1)
        run()
        a=cs.value()

この関数がしている事はtyoku関数とほとんど同じである。Rmagaでは直進するほどの明るさになるまで機体を右回転させている。 E,F以外の道のりでしていることは第1ブロックと同じであるので先ほどのコードに3,4番目の交差点ではRmagaをするというコードを加える。さらに4つめの交差点でこのWhile文を抜ける。

while True:
    d=d+1
    start=cs.value()
    if (start>=15 and start<=50) or (start<15 and d<=40): #右回転
        Rturn(0)
    elif start>=65: #左回転
        Lturn(0)
    elif start<15 and d>40: #交差点 40回ループするまでは交差点と認識させない
        c=c+1
        if c==1: #1つめの交差点
            d=0 #0回目としループした回数を数える
            tyoku()
        if c==2: #2つめの交差点
            sleep(1) #1秒間停止
            tyoku()
        if c==3 or c==4:
            sleep(1)
            Rmaga()
            if c==4: #4つめの交差点でこのWhile文を抜ける
                break   
    else: #直進
        run()
        sleep(0.1)

第3ブロック(黄)

交差点GはRmaga関数、H,Iはtyoku関数で通過できる。 交差点JからKに行くまでに機体を直線KLに対して垂直にしたい。前回の課題1の実験から機体中心に360°回転するには744と入力すればよいと分かっている。つまり10°回転するには約20と入力すればよい。下図より回転させるべき角度は約60°と分かるのでだいたい120と入力すればよいと見当が立つ。何回も繰り返し試したところ、160と入力すると上手くいくと分かった。よって次のコードを加える。

60

for n_1 in range(15):
    sleep(0.1)
    RRturn(0)
    sleep(0.1)
    run()

第3ブロックの円は第1ブロックのカーブに比べ曲率が大きく第1ブロックの時よりも一度に大きくカーブさせる必要がある。よって第1ブロックではLturn(0)だった所を第3ブロックはLturn(70)にしている。だから、一度While文を抜ける必要があったんですね。

第3ブロックのプログラムは以下の通りになる。

start=cs.value()
while True:
    start=cs.value()
    if start>=15 and start<=50:
        Rturn(0)
    elif start>=65:
        Lturn(70)
   elif start<15:
        c=c+1
        if c==1:
           sleep(1) #Gで一時停止
           Rmaga()
        if c==2 or c==3:
            tyoku()
        if c==4:
            for n_1 in range(15):
                sleep(0.1)
                RRturn(0)
                sleep(0.1)
                run()
            break
    else:
        run()
        sleep(0.1)

第4ブロック(緑)

第4ブロックでは球を拾う動作が入る。

  • 機体を球の方に向くように90°回転。…
  • 少しバックする。(アームが長くこのままアームを下ろすと球にぶつかってしまうため。)…
  • アームを下げる。…
  • Lまで進む。(明るくなるまで進む)…
  • アームを上げる。…
  • 機体を180°回転…

この6つの動作で球を拾い第4ブロックは通過できる。ポイントはこの一連の動作はラインのど真ん中で行われていることである。(ライントレースという本来の課題が達成できておらず、反省点である。)

第4ブロックのプログラムは以下の通りになる。

for n_1 in range(18): #
    sleep(0.1)
    LLturn(0)
    sleep(0.1)
    run()
for n_2 in range(10): #
    back()
    sleep(0.1)
armdown() #
while True: #
    start=cs.value()
    if start>80:
        break
    run()
    sleep(0.1)
armup() #
for n_3 in range(36): #
    sleep(0.1)
    RRturn(0)
    sleep(0.1)

第5ブロック(青)

第4ブロックのポイントとして述べたように第4ブロックの動作は全てラインのど真ん中で行っている。つまり第4ブロックの動作の終わりは下図のようになる。

60

理論上機体は直線KLに対して平行になっているはずである。しかし実際には少しの誤差が重なり上図のように右側に傾いたようになってしまった。今回は逆にこの傾きを利用して第5ブロックを攻略する。

第5ブロックの開始時ではラインのど真ん中にあり、機体が右側に傾いているためtyoku関数を用いると、機体がラインの右側に出る。こうすれば、今までのライントレースの仕方で進むことができる。交差点と認識するのは第5ブロックの開始時、地点K、そしてゴールの地点Mである。よって一つ目と二つ目の交差点ではtyoku関数を使い、最後の交差点であるゴールでは機体を停止しアームを下ろせば第5ブロックを通過、つまり課題2達成である。

ラスト

第5ブロックのプログラムは以下の通りになる。

while True:
    start=cs.value()
    if start>=15 and start<=50:
        Rturn(0)
    elif start>=65:
        Lturn(0)
    elif start<15:
        c=c+1
        if c==1 or c==2:
           sleep(0.1)
           tyoku()
        if c==3:
           sleep(1)
           break
    else:
        run()
        sleep(0.1)
armdown()

実装プログラム

最後に課題2を達成するためにこれまで載せてきたプログラムをまとめて、実装プログラムとしてここに載せる。

#!/usr/bin/env python3
from ev3dev.ev3 import *
from time import *
m = LargeMotor('outA')
n = LargeMotor('outB')
l = MediumMotor('outC')
cs = ColorSensor('in2')
cs.mode = 'COL-REFLECT'

def run():
    m.run_timed(time_sp=100, speed_sp=150)
    n.run_timed(time_sp=100, speed_sp=150)
def back():
   m.run_timed(time_sp=100, speed_sp=-150)
   n.run_timed(time_sp=100, speed_sp=-150)

def Rturn(x):
    m.run_to_rel_pos(position_sp=10+x, speed_sp=100, stop_action='brake')
    n.run_to_rel_pos(position_sp=0, speed_sp=100, stop_action='brake')
def Lturn(x):
    m.run_to_rel_pos(position_sp=0, speed_sp=100, stop_action='brake')
    n.run_to_rel_pos(position_sp=10+x, speed_sp=100, stop_action='brake')

def RRturn(x):
    m.run_to_rel_pos(position_sp=10+x, speed_sp=100, stop_action='brake')
    n.run_to_rel_pos(position_sp=-10-x, speed_sp=100, stop_action='brake')
def LLturn(x):
    m.run_to_rel_pos(position_sp=-10-x, speed_sp=100, stop_action='brake')
    n.run_to_rel_pos(position_sp=10+x, speed_sp=100, stop_action='brake')

def armup():
    l.run_to_abs_pos(position_sp=100,speed_sp=100,stop_action="hold")
    sleep(0.1)
def armdown():
    l.run_to_abs_pos(position_sp=-100,speed_sp=100,stop_action="hold")
    sleep(0.1)

def tyoku():
    a=cs.value()
    while(a<15):
        run()
        sleep(0.1)
        a=cs.value()

def Rmaga():
    a=cs.value()
    while(a<50):
        sleep(0.1)
        RRturn(0)
        sleep(0.1)
        run()
        a=cs.value()

c=0
d=0
while True:
    d=d+1
    start=cs.value()
    if (start>=15 and start<=50) or (start<15 and d<=40):
        Rturn(0)
    elif start>=65:
        Lturn(0)
    elif start<15 and d>40:
        c=c+1
        if c==1:
            d=0
            tyoku()
        if c==2:
            sleep(1)
            tyoku()
        if c==3 or c==4:
            sleep(1)
            Rmaga()
            if c==4:
                break
    else:
        run()
        sleep(0.1)
c=0
start=cs.value()
while True:
    start=cs.value()
    if start>=15 and start<=50:
        Rturn(0)
    elif start>=65:
        Lturn(70)
   elif start<15:
        c=c+1
        if c==1:
           sleep(1)
           Rmaga()
        if c==2 or c==3:
            tyoku()
        if c==4:
            for n_1 in range(15):
                sleep(0.1)
                RRturn(0)
                sleep(0.1)
                run()
            break
    else:
        run()
        sleep(0.1)

for n_1 in range(18):
    sleep(0.1)
    LLturn(0)
    sleep(0.1)
    run()
for n_2 in range(10):
    back()
    sleep(0.1)
armdown()
while True:
    start=cs.value()
    if start>80:
        break
    run()
    sleep(0.1)
armup()
for n_3 in range(36):
    sleep(0.1)
    RRturn(0)
    sleep(0.1)

c=0
while True:
    start=cs.value()
    if start>=15 and start<=50:
        Rturn(0)
    elif start>=65:
        Lturn(0)
    elif start<15:
        c=c+1
        if c==1 or c==2:
           sleep(0.1)
           tyoku()
        if c==3:
           sleep(1)
           break
    else:
        run()
        sleep(0.1)
 armdown()

反省

  • 今回はコースをブロックで分けることによりブロックでの難所が見えやすくなり課題攻略のめども立てやすくすることができた。全てのブロックで思った通りの動作を実行することができた。
  • ブロックに分けることで良い点もあったが悪い点もあった。ブロック内での動作はできたが、第2ブロックから第3ブロックへ移行する時、第2ブロックの終わり時の位置のズレを第3ブロックのプログラムは加味できていないので、ズレてしまい正しく第3ブロックが動かなくなってしまった。上の実行プログラムでは第2ブロックの終わり時に人の手で少し位置を正しくズラしてあげないといけない。その位置のずれを修正するコードを付け加えたかったが時間が無く間に合わなかった。ブロックごとに分けることによって、ブロック内の動作を達成することに精一杯になってしまい、ブロック間の移行時についての考慮が欠けてしまった。これを改善する為に今後は、あるブロックが通過できたらその位置を記録しておき、その位置から次のブロックを動かすプログラムを考えるようにする。
  • 第4ブロックなど、コースありきのプログラムになってしまい汎用性が低くなってしまった。原因の一つに球を拾うアームが少しズレるとアームの隙間に球が入らず拾えなくなってしまい、その調整をライントレースではなく直接角度を操作するしか無くなったというのがある。アームの形をさらに広げたり、他のグループがしていたように球にかぶせるようにアームを下ろし球を持ち上げずに運ぶなどの工夫をして球を拾うと言う動作の許容範囲を広げるべきだった。

今日の訪問者数2人

昨日の訪問者数0人

合計訪問者数&counter([total|today|yesterday]);人


添付ファイル: fileラスト.jpg 4件 [詳細] file地点L.jpg 8件 [詳細] file60.jpg 7件 [詳細] file飛び越えない.jpg 7件 [詳細] file飛び越える.jpg 7件 [詳細] filerobo5.jpg 9件 [詳細] filerobo4.jpg 6件 [詳細] filerobo2.jpg 7件 [詳細] filerobo1.jpg 7件 [詳細] filerobo.jpg 5件 [詳細] fileちょく.jpg 8件 [詳細] fileコースブロック.jpg 7件 [詳細] file明るさの値.jpg 7件 [詳細] file暗くなる.jpg 7件 [詳細] file暗い1.jpg 8件 [詳細] file暗い.jpg 6件 [詳細] file2019a-mission2.png 8件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-08-14 (水) 23:14:11