黒線に沿い、コースを進み途中の地点でピンポン球を掴みゴールにシュートする課題
大まかなコースの説明をする。
A→B→C→D(一時停止あり)→E→F→G(一時停止あり)→H→I→J→K→L(ピンポン玉)→K→M(一時停止あり)→シュート→Aである。
機体は動かしやすいようにシンプルな機構
ボールを捉えやすいようにアームを真ん中へ
差が減るようにセンサーも真ん中へ
ev3devのpythonライブラリ、sleep関数諸々を導入するところから始める。カラーセンサーmode = 'COL-REFLECT'では明るいほど高い値を出す。0〜100までの値である。mLは左のラージモーター、mRは右のラージモーターに対応する。mmはミディアムモーターで今回はボールを回収、放出の役割を果たす。
#!/usr/bin/env python3 from ev3dev.ev3 import * from time import sleep mL = LargeMotor('outA') mR = LargeMotor('outB') mm = MediumMotor('outC') cs = ColorSensor('in2') cs.mode = 'COL-REFLECT'
ロボットを動かす定義をしていく、l()は左前に進み、r()は右前に進む。time_spを小さくすることでなるべく脱線しないように配慮。f(a)は前進、b()は後退。こちらはtime_spを少し大きくしspeed_spを小さくすることでラインの値を変に読まないように配慮。
def r(): mL.run_timed(time_sp=1,speed_sp=550,stop_action='brake') mR.run_timed(time_sp=1,speed_sp=60,stop_action='brake') def l(): mL.run_timed(time_sp=1,speed_sp=60,stop_action='brake') mR.run_timed(time_sp=1,speed_sp=550,stop_action='brake') def f(a): mL.run_timed(time_sp=10+a,speed_sp=150,stop_action='brake') mR.run_timed(time_sp=10+a,speed_sp=150,stop_action='brake') def b(): mL.run_timed(time_sp=20,speed_sp=-50,stop_action='brake') mR.run_timed(time_sp=20,speed_sp=-50,stop_action='brake')
magaru(m,n,o,p)は90度回転して元の位置に戻る、というものである。magaru(1,0,0,1)で右回転、magaru(0,1,1,0)で左回転する。ziyuu(x,y,X,Y)を定義しとくことにより後々のプログラムを簡潔にする。armage()はアームをあげてボールを回収、armsage()ではアームをさげてボールを射出。
def magaru(m,n,o,p): mL.run_timed(time_sp=400,speed_sp=1000*m,stop_action='brake') mR.run_timed(time_sp=400,speed_sp=1000*n,stop_action='brake') sleep(1) mL.run_timed(time_sp=350+o*100,speed_sp=-350,stop_action='brake') mR.run_timed(time_sp=350+p*100,speed_sp=-350,stop_action='brake') sleep(1) def ziyuu(x,y,X,Y): mL.run_timed(time_sp=x,speed_sp=y,stop_action='brake') mR.run_timed(time_sp=X,speed_sp=Y,stop_action='brake') def armage(): mm.run_to_abs_pos(position_sp=80,speed_sp=100,stop_action="hold") sleep(0.1) def armsage(): mm.run_to_abs_pos(position_sp=-80,speed_sp=100,stop_action="hold") sleep(0.1)
print (cs.value())でカラーセンサーの値を調べたところ赤丸1では70以上、赤丸2では50ほど、赤丸3では10以下であることが分かった。図1ではcs.value()の値が50ほどで前進させ、図2はcs.value()の値が20以下の時右前に進ませて、図3では60以上の時左前に進ませる。図4ではcs.value()の値が70以上で後退させる。なおこの基準ではかなりの範囲でかぶっているので、elifを使うことでその問題を解決した。これによりおおまかな値で定義し、より正確にラインをたどれるようにした。
なお最初にst=cs.value()と書き、whileの中にne=cs.value()を入れ、whileの最後にst=neと書くことで前回計測したcs.value()を保持することが出来た。これにより図5では連続的、つまり2回黒を計測するとL字や十字路と判断するようにした。この2回計測させる、ということが1番の工夫である、1度ではカーブ時などに勘違いしてL字や十字路だと思い誤作動を起こすが二回黒のかなり低い値、st<10 and ne<10にしておくことで誤作動が激減した。
ganbaru()関数は最初にs=0を置き、黒二回計測、つまり交差点or”「 ” この形の時にsに1を加える、if,elif,elseを使い、ライントレースを制御、sが2以上になればwhileから抜けだし動作終了。細かいライントレースに用いる。(主にゴール前)
ganbare()関数は基本的にはganbaru()関数と同じで、BからIに移動させるためtの限界値はaと設定し、長めにライントレース、つまり交差点or”「 ” の形を何度も計測し動作し続けるものとなっている。これを実現するために siraberu()関数を定義し組み込んである、これは後述する。
def ganbaru(): s=0 st=cs.value() while s <= 1: ne=cs.value() if st>70 or ne>70: b() elif st<10 and ne<10: s=s+1 sleep(1) elif ne>60: l() elif ne<20: r() else: f(0) st=ne def ganbare(a): t=0 st=cs.value() while t <= a: ne=cs.value() if st>70 or ne>70: b() elif st<10 and ne<10: siraberu() sleep(3) t=t+1 elif ne>60: l() elif ne<20: r() else: f(0) st=ne
siraberu()関数を説明する。
図のように黒を二度観測、つまり交差点or”「 ” の形、Tにあたれば、まず右前に移動し左右に首を揺らし、二つ目の赤の地点と矢印の地点、左、右のcs.value()を観測する、それぞれ順番にss0、ss1、ss2と定義する。そして一旦元の位置に戻り、ss0、ss1、ss2の値によって行動を分岐させる。
図のように交差点であれば左は黒を観測し右は何も観測しない、この場合はD地点でおこる、すなわち前進させる必要がある。elseで対応させ、 f(300)前進。簡単に説明したのが下図である。
なお出っ張りがない部分は円のところもあり、誤作動がないようこまかく調整した。if ss0 > 65 and ss1 > 70 and ss2 > 65;においてmagaru(1,0,0,1)、つまり90度旋回する様になっている。
これらによって交差点or”「 ” の形、Tに完全に対応させた。
def siraberu(): mR.run_timed(time_sp=400,speed_sp=200,stop_action='brake') mL.run_timed(time_sp=400,speed_sp=100,stop_action='brake') sleep(0.4) ss0=cs.value() sleep(0.5) mR.run_timed(time_sp=400,speed_sp=120,stop_action='brake') mL.run_timed(time_sp=400,speed_sp=-120,stop_action='brake') sleep(0.4) ss1=cs.value() sleep(0.5) mR.run_timed(time_sp=400,speed_sp=-120,stop_action='brake') mL.run_timed(time_sp=400,speed_sp=120,stop_action='brake') sleep(0.4) mR.run_timed(time_sp=400,speed_sp=-120,stop_action='brake') mL.run_timed(time_sp=400,speed_sp=120,stop_action='brake') sleep(0.4) ss2=cs.value() sleep(0.5) mR.run_timed(time_sp=400,speed_sp=120,stop_action='brake') mL.run_timed(time_sp=400,speed_sp=-120,stop_action='brake') sleep(0.4) mR.run_timed(time_sp=400,speed_sp=-200,stop_action='brake') mL.run_timed(time_sp=400,speed_sp=-100,stop_action='brake') sleep(1) while True: if ss0 > 65 and ss1 > 70 and ss2 > 65: sleep(1) magaru(1,0,0,1) break else: f(300) break
プログラム全文は以下に記載する。
#!/usr/bin/env python3 from ev3dev.ev3 import * from time import sleep mL = LargeMotor('outA') mR = LargeMotor('outB') mm = MediumMotor('outC') cs = ColorSensor('in2') cs.mode = 'COL-REFLECT' def r(): mL.run_timed(time_sp=1,speed_sp=550,stop_action='brake') mR.run_timed(time_sp=1,speed_sp=60,stop_action='brake') def l(): mL.run_timed(time_sp=1,speed_sp=60,stop_action='brake') mR.run_timed(time_sp=1,speed_sp=550,stop_action='brake') def f(a): mL.run_timed(time_sp=10+a,speed_sp=150,stop_action='brake') mR.run_timed(time_sp=10+a,speed_sp=150,stop_action='brake') def b(): mL.run_timed(time_sp=20,speed_sp=-50,stop_action='brake') mR.run_timed(time_sp=20,speed_sp=-50,stop_action='brake') def magaru(m,n,o,p): mL.run_timed(time_sp=400,speed_sp=1000*m,stop_action='brake') mR.run_timed(time_sp=400,speed_sp=1000*n,stop_action='brake') sleep(1) mL.run_timed(time_sp=350+o*100,speed_sp=-350,stop_action='brake') mR.run_timed(time_sp=350+p*100,speed_sp=-350,stop_action='brake') sleep(1) def ziyuu(x,y,X,Y): mL.run_timed(time_sp=x,speed_sp=y,stop_action='brake') mR.run_timed(time_sp=X,speed_sp=Y,stop_action='brake') def armage(): mm.run_to_abs_pos(position_sp=80,speed_sp=100,stop_action="hold") sleep(0.1) def armsage(): mm.run_to_abs_pos(position_sp=-80,speed_sp=100,stop_action="hold") sleep(0.1) def siraberu(): mR.run_timed(time_sp=400,speed_sp=200,stop_action='brake') mL.run_timed(time_sp=400,speed_sp=100,stop_action='brake') sleep(0.4) ss0=cs.value() sleep(0.5) mR.run_timed(time_sp=400,speed_sp=120,stop_action='brake') mL.run_timed(time_sp=400,speed_sp=-120,stop_action='brake') sleep(0.4) ss1=cs.value() sleep(0.5) mR.run_timed(time_sp=400,speed_sp=-120,stop_action='brake') mL.run_timed(time_sp=400,speed_sp=120,stop_action='brake') sleep(0.4) mR.run_timed(time_sp=400,speed_sp=-120,stop_action='brake') mL.run_timed(time_sp=400,speed_sp=120,stop_action='brake') sleep(0.4) ss2=cs.value() sleep(0.5) mR.run_timed(time_sp=400,speed_sp=120,stop_action='brake') mL.run_timed(time_sp=400,speed_sp=-120,stop_action='brake') sleep(0.4) mR.run_timed(time_sp=400,speed_sp=-200,stop_action='brake') mL.run_timed(time_sp=400,speed_sp=-100,stop_action='brake') sleep(1) while True: if ss0 > 65 and ss1 > 70 and ss2 > 65: sleep(1) magaru(1,0,0,1) break else: f(300) break def ganbaru(): s=0 st=cs.value() while s <= 1: ne=cs.value() if st>70 or ne>70: b() elif st<10 and ne<10: s=s+1 sleep(1) elif ne>60: l() elif ne<20: r() else: f(0) st=ne def ganbare(a): t=0 st=cs.value() while t <= a: ne=cs.value() if st>70 or ne>70: b() elif st<10 and ne<10: siraberu() sleep(3) t=t+1 elif ne>60: l() elif ne<20: r() else: f(0) st=ne
導入と先ほど説明した定義である。
ganbare(6) sleep(1)
BからHに移動、ここが最も難所で成功率は高くない。
ganbaru() sleep(1)
HからJに移動
magaru(1,0,0,1) sleep(1)
90度回転
ganbaru() sleep(1)
JからKに移動
magaru(0,1,1,0) sleep(1)
90度回転
f(50) sleep(1) armage()
玉を回収する、この部分も誤差が大きい時は回収出来ない。
ganbare(1) sleep(1) armsage()
ゴールまで行き、アームを下ろした。
課題達成に必死、自己流の工夫が余りできていない。ロボットの形は機構だったが、プログラムが全く機能しないなどの苦労が多かった。ライントレースが正確になるまでの調整が特に大変。難所の円部分で誤作動する可能性が高いことを解決出来なかった