今回は、2台のロボットでコップを積み上げることを目的とした(後述)
自分は、コップを2本のアームで挟んで持ってくるロボット(ロボット1)を担当することになった
よって、このレポートの内容がほとんどロボット1についてのレポートになることをご容赦いただきたい
ロボットのベースとして、前回用いたライントレースロボットをベースとしている
ライントレースでそのままの形を使えるので、ハードと前回のプログラムの互換性が強いためである
前回の図
↓
今回の図
(前回のロボットに2本のアームを取り付けた)
アームにはMediumMotorを用いて、一個のモーターでアームの開閉をできるようにし、それによってモータの数を節約し
一個のマイコンでつかんでとってくるまでの動作を可能にした
ロボット2は、2本の無限軌道を用いてコップを上げ下げするのが主な役割である
前後移動を一つのモーターに頼っているので、正確に目の前にコップを置く必要がある
目の前にコップが置かれると、つかめる一定距離まで前進して無限軌道を回転させてコップを持ち上げる
自分の班では、2台のロボットを用いて課題3の達成を目指した
それぞれのロボットの役割は以下のとおりである
1:紙コップを一個づつ挟んで、所定の場所に引きずってくる 2:1のロボットが持ってきた紙コップを持ち上げて積み重ねる
これらの役割を2台のロボットに分担させることによって、課題3の達成を目指す
ロボット1に必要な動作を細かく分けると以下のとおりである
1:ライントレースをしてコップのところまでたどり着く 2:コップを認識する 3:コップをつかむ位置まで前進する 4:アームを閉じてコップをつかむ 5:ライントレースをして所定の位置までたどり着く 6:アームを開いてコップを離す
これらの繰り返しでコップを積み上げることが可能である
よってこれから1〜6の動作についてサブルーチンといった形で記述していく
サブルーチンの形で記述するのは、何か異常が起こった時に修正を一つのサブルーチンに限定して修正することが可能となるからである
ml = ev3.LargeMotor('outB') mr = ev3.LargeMotor('outA') mm = ev3.MediumMotor('outC') cs = ev3.ColorSensor('in1') de = ev3.InfraredSensor('in2')
ライントレースはほぼ課題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)
といったサブルーチンでまとめることができたのは前回からの大きな進歩だと思っている
これらによって、ライントレースのプログラムをより簡潔に表記することができた
コップを認識するためのサブルーチンであるが、この点が、本番でもうまくいかなかった点である
構想としては、ライントレースをして目的地にたどり着いたロボットが回転をはじめ、回転しながらコップを見つけ、その方向に直進してある距離になったらアームを閉じるというものだった
一応、うまくいかなかったがコップをサーチするプログラムを記述する
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以内にコップを見つけたら)前進してコップをつかむといったプログラムである
本番ではおそらく一番うまくいかなかったのがこのサブルーチンである
自分たちの使っていた赤外線センサーは本当にセンサーの一直線上にないと機能しないようなものだった
それによって、サーチする際にコップを見つけても、途中で少しでも軌道からずれてしまい、機能しなかったと思われる
コップをサーチしてつかむまでの動作は一連のサブルーチンであったほうが良いと途中で方針が変更されたので、先ほどの「catch」のサブルーチンにすべて含まれている
よって3,4については割愛させていただく
ライントレースをして元の場所に戻ってアームを開くだけなので割愛させていただく
#!/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に行ってコップをつかんでくる」といった意味である
#!/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のプログラムについては自分はほとんどかかわっていないので、プログラムだけ掲載する
#!/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)
課題3では今までの経験を活かし、サブルーチンづくりに尽力したが、その点微調整をうまく行うことができず、サブルーチンをスキップしてしまう失敗が多かった
一個のサブルーチンを作り上げる時間をもっととって、一個一個確実にその動作をクリアできるかどうか検証することが大切である
次回の機会があれば、リアルタイムでのセンサーの認識の検証などを用いて、センサーの特性を知ることが大切である
ロボットの連携においても、センサーを用いすぎたりすると、どこでミスが起こっているのかわかりにくくなる
できるだけ少ない機構で連携や目的の動作を達成できないかについて考えることが大切である
プログラムをできるだけ少なく書けるようにするためのサブルーチンの大切さを知ったよい授業だった