- 追加された行はこの色です。
- 削除された行はこの色です。
*ロボットの全体像 [#p94c337a]
#contents
*全体の流れ [#p94c337a]
今回は、2台のロボットでコップを積み上げることを目的とした(後述)
自分は、コップを2本のアームで挟んで持ってくるロボットを担当することになった
自分は、コップを2本のアームで挟んで持ってくるロボット(ロボット1)を担当することになった
よって、このレポートの内容がほとんどロボット1についてのレポートになることをご容赦いただきたい
*課題3の内容 [#ibdf65f8]
#ref(課題.png)
-紙コップは上下どちらにおいてもかまわない
-2台のロボットの場合はA地点とB地点からスタート、一体型の場合はA地点とB地点のいずれかからスタートする
-最終的に黒線で囲まれた輪の中にC地点からの紙コップとD地点からの紙コップを交互に重ねる (下側から数えて奇数番目はC地点からのコップ、偶数番目はD地点からのコップになるようにする)
-紙コップを重ねる場所は、必ずしも目的地点の輪の中でなくてもかまわない
-最終的に紙コップが自力で立っていること、またロボットが紙コップに触れていないこと、ただしスタート時と上下逆になっていてもかまわない
-競技時間はすべてのコップを重ね終わるまで、あるいは審判が続行不能と判断するまで。
-審判の合図の後、5秒以内にロボットをスタートさせ、それ以降はロボットや紙コップに触ってはいけない
-EV3のチームはA,B,Cにそれぞれマークした紙コップをそれぞれ3個置く
-EV3のチームはA,B,C,Dのどこからスタートしてもよいが、別の地点にある合計9個の紙コップを運ぶこと
-紙コップに色を塗ったり文字や絵をかいてもよいが、穴を開けたり故意に変形させてはいけない
-光センサは2セット合わせて2つまで使って良い、その他のセンサや部品はキットに含まれているものだけを使用すること
*ロボットの全体像 [#k7581335]
-ロボット1の全体像
まず、ロボット1について記述する
ロボットのベースとして、前回用いたライントレースロボットをベースとしている
ライントレースはそのままの形を使えるので、ハード面と前回のプログラムの互換性が強いためである
ライントレースでそのままの形を使えるので、ハードと前回のプログラムの互換性が強いためである
前回の図
#ref(1.jpg)
↓
今回の図
#ref(ロボット1.jpg)
~
#ref(ロボット12.jpg)
(前回のロボットに2本のアームを取り付けた)
アームにはMediumMotorを用いて、一個のモーターでアームの開閉をできるようにし、それによってモータの数を節約し
一個のマイコンでつかんでとってくるまでの動作を可能にした
~
~
-ロボット2の全体像
次に、ロボット2について記述する
#ref(ロボット2.jpg)
#ref(ロボット21.jpg)
ロボット2は、2本の無限軌道を用いてコップを上げ下げするのが主な役割である
前後移動を一つのモーターに頼っているので、正確に目の前にコップを置く必要がある
目の前にコップが置かれると、つかめる一定距離まで前進して無限軌道を回転させてコップを持ち上げる
*課題3の達成をするために必要なロボットの動き [#a901cf25]
自分の班では、2台のロボットを用いて課題3の達成を目指した
それぞれのロボットの役割は以下のとおりである
1:紙コップを一個づつ挟んで、所定の場所に引きずってくる
2:1のロボットが持ってきた紙コップを持ち上げて積み重ねる
これらの役割を2台のロボットに分担させることによって、課題3の達成を目指す
*ロボット1が目的の動作をするためのプログラム [#e0332dcf]
ロボット1に必要な動作を細かく分けると以下のとおりである
1:ライントレースをしてコップのところまでたどり着く
2:コップを認識する
3:コップをつかむ位置まで前進する
4:アームを閉じてコップをつかむ
5:ライントレースをして所定の位置までたどり着く
6:アームを開いてコップを離す
これらの繰り返しでコップを積み上げることが可能である
よってこれから1〜6の動作についてサブルーチンといった形で記述していく
サブルーチンの形で記述するのは、何か異常が起こった時に修正を一つのサブルーチンに限定して修正することが可能となるからである
~
~
*サブルーチンについて記述していくにあたって、本プログラムの最低限の定義を記述する [#efa5ff8e]
ml = ev3.LargeMotor('outB')
mr = ev3.LargeMotor('outA')
mm = ev3.MediumMotor('outC')
cs = ev3.ColorSensor('in1')
de = ev3.InfraredSensor('in2')
*1のサブルーチンについて [#e4336f12]
ライントレースはほぼ課題2をベースとして、行きつく先が少し変わっただけである
その際、前回の課題からの改善点として、
黒い線の右側の境界をトレースしていく「lineright」
def lineright():
t0 = time.time()
while time.time() - t0 < 0.4:
if cs.value () > 50 :
mr.run_forever(duty_cycle_sp=60)
ml.run_forever(duty_cycle_sp=-30)
t0 = time.time()
else:
mr.run_forever(duty_cycle_sp=-30)
ml.run_forever(duty_cycle_sp=60)
黒い線の左側の境界をトレースしていく「lineleft」
def lineleft():
t0 = time.time()
while time.time() - t0 < 0.4:
if cs.value () > 50 :
mr.run_forever(duty_cycle_sp=-30)
ml.run_forever(duty_cycle_sp=60)
t0 = time.time()
else:
mr.run_forever(duty_cycle_sp=60)
ml.run_forever(duty_cycle_sp=-30)
といったサブルーチンを作成した
交差点に差し掛かった時、右に曲がって止まるのか、左に曲がって止まるのか、というのは前回の大きな課題だった
そのとき、いちいちどちらに曲がって止まったかを記録して修正していたのが前回の私たちだったが
今回、「lineright」「lineleft」のサブルーチンを作成したことで、交差点での方向修正が格段に容易になった
また、「lineright」「lineleft」の派生として、交差点で曲がりすぎたのを修正するサブルーチンとして
「lineright」で右に曲がりすぎたのを正面に修正する「rreset」
def rreset():
ml.run_forever(duty_cycle_sp=-18)
mr.run_forever(duty_cycle_sp=18)
time.sleep(1)
「lineleft」で左に曲がりすぎたのを正面に修正する「lreset」
def lreset():
ml.run_forever(duty_cycle_sp=18)
mr.run_forever(duty_cycle_sp=-18)
time.sleep(1)
といったサブルーチンでまとめることができたのは前回からの大きな進歩だと思っている
これらによって、ライントレースのプログラムをより簡潔に表記することができた
*2のサブルーチンについて [#h0d6bf11]
コップを認識するためのサブルーチンであるが、この点が、本番でもうまくいかなかった点である
構想としては、ライントレースをして目的地にたどり着いたロボットが回転をはじめ、回転しながらコップを見つけ、その方向に直進してある距離になったらアームを閉じるというものだった
一応、うまくいかなかったがコップをサーチするプログラムを記述する
def catch():
while de.value() > 500:
if de.value() < 200:
ml.run_forever(duty_cycle_sp=40)
mr.run_forever(duty_cycle_sp=40)
time.sleep(1)
ml.run_forever(duty_cycle_sp=0)
mr.run_forever(duty_cycle_sp=0)
mm.run_forever(duty_cycle_sp=50)
time.sleep(3)
else:
ml.run_forever(duty_cycle_sp=-15)
mr.run_forever(duty_cycle_sp=15)
プログラムの説明として、elseでコップを見つけていない状態を表し、その間はゆっくりと左旋回を続ける
もし、de.value() < 200になったら(20cm以内にコップを見つけたら)前進してコップをつかむといったプログラムである
本番ではおそらく一番うまくいかなかったのがこのサブルーチンである
自分たちの使っていた赤外線センサーは本当にセンサーの一直線上にないと機能しないようなものだった
それによって、サーチする際にコップを見つけても、途中で少しでも軌道からずれてしまい、機能しなかったと思われる
*3のサブルーチンについて、4のサブルーチンについて [#j5a070ac]
コップをサーチしてつかむまでの動作は一連のサブルーチンであったほうが良いと途中で方針が変更されたので、先ほどの「catch」のサブルーチンにすべて含まれている
よって3,4については割愛させていただく
*5のサブルーチン、6のサブルーチンについて [#xf6c3deb]
ライントレースをして元の場所に戻ってアームを開くだけなので割愛させていただく
*本番で用いたプログラム本体 [#bf05b8e8]
#!/usr/bin/python
import ev3dev.ev3 as ev3
import time
ml = ev3.LargeMotor('outB')
mr = ev3.LargeMotor('outA')
mm = ev3.MediumMotor('outC')
cs = ev3.ColorSensor('in1')
de = ev3.InfraredSensor('in2')
def catch():
while de.value() < 50:
if de.value() < 10:
ml.run_forever(duty_cycle_sp=0)
mr.run_forever(duty_cycle_sp=0)
mm.run_forever(duty_cycle_sp=50)
time.sleep(4)
mm.run_forever(duty_cycle_sp=0)
ml.run_forever(duty_cycle_sp=-20)
mr.run_forever(duty_cycle_sp=-20)
time.sleep(1.5)
ml.run_forever(duty_cycle_sp=0)
mr.run_forever(duty_cycle_sp=0)
ml.run_forever(duty_cycle_sp=-50)
mr.run_forever(duty_cycle_sp=50)
time.sleep(1.6)
ml.run_forever(duty_cycle_sp=0)
mr.run_forever(duty_cycle_sp=0)
else:
ml.run_forever(duty_cycle_sp=15)
mr.run_forever(duty_cycle_sp=15)
def lineleft():
t0 = time.time()
while time.time() - t0 < 0.35:
if cs.value () > 50 :
mr.run_forever(duty_cycle_sp=-30)
ml.run_forever(duty_cycle_sp=60)
t0 = time.time()
else:
mr.run_forever(duty_cycle_sp=60)
ml.run_forever(duty_cycle_sp=-30)
def cross(t,dl,dr):
mr.run_forever(duty_cycle_sp=dr)
ml.run_forever(duty_cycle_sp=dl)
time.sleep(t/1000)
ml.stop()
mr.stop()
def toa():
lineright()
cross(1000,-20,20)
cross(1000,13,13)
lineright()
cross(1000,0,0)
cross(1000,-18,18)
cross(1000,0,0)
catch()
cross(1400,30,-30)
lineright()
cross(1000,0,0)
cross(1000,-20,20)
cross(1000,10,10)
lineright()
cross(1000,0,0)
cross(1000,-25,25)
mm.run_forever(duty_cycle_sp=-50)
time.sleep(3)
mm.run_forever(duty_cycle_sp=0)
cross(1000,-30,-30)
cross(2000,-40,40)
def tob():
lineleft()
cross(1000,-10,10)
lineright()
cross(1000,-20,20)
cross(1000,13,13)
lineright()
cross(1000,-20,20)
cross(1000,13,13)
lineright()
cross(1000,0,0)
cross(1000,-17,17)
cross(1000,0,0)
catch()
lineleft()
cross(1000,20,-20)
cross(1000,13,13)
lineleft()
cross(1000,20,-20)
cross(1000,40,13)
lineright()
cross(1000,0,0)
cross(1000,36,-36)
lineright()
cross(1000,0,0)
cross(1000,-20,20)
mm.run_forever(duty_cycle_sp=-50)
time.sleep(3)
mm.run_forever(duty_cycle_sp=0)
cross(1000,-30,-30)
def toc():
lineright()
cross(1000,-17,17)
cross(1000,30,-30)
cross(1000,10,10)
lineright()
cross(1000,-20,20)
cross(1000,13,13)
lineright()
cross(1000,-20,20)
cross(1000,13,13)
catch()
lineright()
cross(1000,0,0)
cross(1000,17,-17)
cross(1000,13,13)
lineright()
cross(1000,0,0)
cross(1000,-22,22)
cross(1000,0,0)
lineright()
cross(1000,0,0)
cross(1000,-25,25)
mm.run_forever(duty_cycle_sp=-50)
time.sleep(3)
mm.run_forever(duty_cycle_sp=0)
cross(1000,-30,-30)
cross(1500,-50,50)
mm.run_forever(duty_cycle_sp=-50)
time.sleep(3.5)
mm.run_forever(duty_cycle_sp=0)
tob()
cross(1000,-13,13)
tob()
これは、同じチームの者が制作したものである
先ほどのサブルーチンを用いず、「cross」というモーターをパワーと秒数で定義するサブルーチンを何度も使っている
こちらを本番で用いたのは、前日にこちらのほうがよく動いたからである
「toa」「tob」「toc」などのサブルーチンはそれぞれ「Aにいってコップをつかんでくる」「Bに行ってコップをつかんでくる」「Cに行ってコップをつかんでくる」といった意味である
*自分なりに書き直したプログラム [#b72eea4a]
#!/usr/bin/python
import ev3dev.ev3 as ev3
import time
ml = ev3.LargeMotor('outB')
mr = ev3.LargeMotor('outA')
mm = ev3.MediumMotor('outC')
cs = ev3.ColorSensor('in1')
de = ev3.InfraredSensor('in2')
def catch():
while de.value() > 500:
if de.value() < 200:
ml.run_forever(duty_cycle_sp=40)
mr.run_forever(duty_cycle_sp=40)
time.sleep(1)
ml.run_forever(duty_cycle_sp=0)
mr.run_forever(duty_cycle_sp=0)
mm.run_forever(duty_cycle_sp=50)
time.sleep(3)
else:
ml.run_forever(duty_cycle_sp=-15)
mr.run_forever(duty_cycle_sp=15)
def lineright():
t0 = time.time()
while time.time() - t0 < 0.4:
if cs.value () > 50 :
mr.run_forever(duty_cycle_sp=60)
ml.run_forever(duty_cycle_sp=-30)
t0 = time.time()
else:
mr.run_forever(duty_cycle_sp=-30)
ml.run_forever(duty_cycle_sp=60)
def lineleft():
t0 = time.time()
while time.time() - t0 < 0.4:
if cs.value () > 50 :
mr.run_forever(duty_cycle_sp=-30)
ml.run_forever(duty_cycle_sp=60)
t0 = time.time()
else:
mr.run_forever(duty_cycle_sp=60)
ml.run_forever(duty_cycle_sp=-30)
def cross(t,dl,dr):
mr.run_forever(duty_cycle_sp=dr)
ml.run_forever(duty_cycle_sp=dl)
time.sleep(t/1000)
ml.stop()
mr.stop()
def turnright():
mr.run_forever(duty_cycle_sp=-20)
ml.run_forever(duty_cycle_sp=20)
time.sleep(2)
mr.run_forever(duty_cycle_sp=15)
ml.run_forever(duty_cycle_sp=15)
time.sleep(1)
def turnleft():
mr.run_forever(duty_cycle_sp=20)
ml.run_forever(duty_cycle_sp=-20)
time.sleep(2)
mr.run_forever(duty_cycle_sp=15)
ml.run_forever(duty_cycle_sp=15)
time.sleep(1)
def rreset():
ml.run_forever(duty_cycle_sp=-18)
mr.run_forever(duty_cycle_sp=18)
time.sleep(1)
def lreset():
ml.run_forever(duty_cycle_sp=18)
mr.run_forever(duty_cycle_sp=-18)
time.sleep(1)
def toa():
lineright()
lreset()
turnleft()
lineright()
rrest()
turnright()
lineright()
catch()
cross(1400,30,-30)
lineright()
rreset()
lineright()
rreset()
mm.run_forever(duty_cycle_sp=-50)
time.sleep(3)
mm.run_forever(duty_cycle_sp=0)
cross(1000,-30,-30)
cross(2000,-40,40)
def tob():
lineleft()
lreset()
lineright()
rreset()
lineright()
rreset()
lineright()
rreset()
cross(1000,17,17)
catch()
lineleft()
lreset()
lineleft()
lreset()
lineright()
rreset()
lineright()
rreset()
mm.run_forever(duty_cycle_sp=-50)
time.sleep(3)
mm.run_forever(duty_cycle_sp=0)
cross(1000,-30,-30)
def toc():
lineright()
rreset()
lineright()
rreset()
lineright()
rreset()
cross(1000,13,13)
catch()
lineright()
rreset()
lineright()
rreset()
lineright()
rreset()
mm.run_forever(duty_cycle_sp=-50)
time.sleep(3)
mm.run_forever(duty_cycle_sp=0)
cross(1000,-30,-30)
cross(1500,-50,50)
mm.run_forever(duty_cycle_sp=-50)
time.sleep(3.5)
mm.run_forever(duty_cycle_sp=0)
tob()
cross(1000,-13,13)
tob()
このように先ほどのプログラムを書き直したのだが、うまくいかなかった
サブルーチンでひとくくりにするより一回ごとの調整のほうがうまくいったというのが悔しいというのはある
また、チームメイトの「catch」は、探索を含まないのに対し、自分の「catch」は探索を含めてしまったのが失敗の要因かもしれない
*ロボット2のプログラム [#gf9ffe04]
ロボット2のプログラムについては自分はほとんどかかわっていないので、プログラムだけ掲載する
#!/usr/bin/python
import ev3dev.ev3 as ev3
import time
m1 = ev3.LargeMotor('outA')
m2 = ev3.MediumMotor('outB')
m3 = ev3.MediumMotor('outC')
m4 = ev3.LargeMotor('outD')
us = ev3.UltrasonicSensor('in1')
def search(p):
t0 = time.time()
while time.time() - t0 < 0.001:
if us.value() > p:
m4.run_forever(duty_cycle_sp=50)
t0 = time.time()
else:
m4.stop()
def bring(x,y):
m4.run_forever(duty_cycle_sp=x)
time.sleep(y)
m4.stop()
def close():
m1.run_forever(duty_cycle_sp=-37.5)
time.sleep(0.32)
m1.stop()
def up():
m3.run_forever(duty_cycle_sp=-50)
m2.run_forever(duty_cycle_sp=50)
time.sleep(2.25)
m2.stop()
m3.stop()
def down():
m3.run_forever(duty_cycle_sp=50)
m2.run_forever(duty_cycle_sp=-50)
time.sleep(1.5)
m2.stop()
m3.stop()
def open(a,b):
m1.run_forever(duty_cycle_sp=a)
time.sleep(b)
m1.stop()
search(60)
bring(45,0.2)
close()
up()
search(60)
open(20,0.275)
bring(45,0.2)
down()
open(27.5,0.325)
bring(-40,7.5)
*まとめ [#p6db7b4f]
課題3では今までの経験を活かし、サブルーチンづくりに尽力したが、その点微調整をうまく行うことができず、サブルーチンをスキップしてしまう失敗が多かった
一個のサブルーチンを作り上げる時間をもっととって、一個一個確実にその動作をクリアできるかどうか検証することが大切である
次回の機会があれば、リアルタイムでのセンサーの認識の検証などを用いて、センサーの特性を知ることが大切である
ロボットの連携においても、センサーを用いすぎたりすると、どこでミスが起こっているのかわかりにくくなる
できるだけ少ない機構で連携や目的の動作を達成できないかについて考えることが大切である
プログラムをできるだけ少なく書けるようにするためのサブルーチンの大切さを知ったよい授業だった