青と赤のボールを運搬して、それぞれ所定の350ml缶の上に乗せる。
本体
前回のロボットを改良して、カラーセンサーと超音波センサーが真ん中に来るようにした。 超音波センサーを挟むように取り付けてある2本の灰色の棒は、缶に近づくとき少しずれていても、缶を無理やり超音波センサーの正面に来るように取り付けてある。
ボールを掴むのではなくベルトコンベアを使って掬い上げるようにした。こうすることによって、ボールを2つ保持することができるので、s字カーブを通らなくて済むようになった。
ベルトコンベアをさらに回すと、ボールは車体上部にあるスロープに導かれそのまま缶に向かって転がっていく
缶に着地するとき、何も手を加えないとボールの水平方向の運動エネルギーが強すぎて、ボールが缶から飛び出してしまうため、スロープの出口に暖簾のようなものを設けた。これを設けることによって、ボールのエネルギーを殺し、飛び出すことを防いでいる。
今回はジャイロセンサーを利用していて、車体の回転した角度を測っている。
最初はUFOキャッチャーのようにボールを掴むロボットを考えていたが、課題一の反省からモーターによってモーターを動かすと車体のバランスが悪くなったり、ケーブルに引っ張る力が加わって正確に動かないと思ったので、ベルトコンベア式にした。
球を2つ保持できるため、赤玉を入手したらそのまま青玉へ進む。青玉を入手したら、次にベルトコンベアを回したとき出てくる球は赤玉なので、赤玉を乗せる缶のもとへ向かう。
地図上の扇形の図形は缶を見つけるときに使う超音波センサーで調べる範囲。角度だけでなく調べる距離も設定することで、万が一缶が見つからなくても暴走しないような逃げ道を作った。
赤玉を乗せるゾーンの缶は間隔が広いため、ダミーをありにした。青玉を乗せるゾーンは車体の大きさの関係上、缶をずらしてしまう恐れがあるため、ダミーなしで行う。
基本的に課題2と変化は無い。課題2: http://yakushi.shinshu-u.ac.jp/robotics/?2018b%2FMember%2FKisuke%2FMission2
def linetrace_rin(): c1=cs.value() while c1>13: c1=cs.value() x=(abs(c1-10)/70)*100 if x>100: x=100 l=(x/100)*210-30 r=150-l ml.run_forever(speed_sp=l,stop_action='brake') mr.run_forever(speed_sp=r,stop_action='brake') stop() def linetrace_lin(): c1=cs.value() while c1>13: c1=cs.value() x=abs((c1-10)/70)*100 if x>100: x=100 r=(x/100)*210-30 l=150-r ml.run_forever(speed_sp=l,stop_action='brake') mr.run_forever(speed_sp=r,stop_action='brake') stop() def linetrace_rout(): c1=cs.value() while c1<40: c1=cs.value() x=(abs(c1-10)/70)*100 if x>100: x=100 l=(x/100)*120-40 r=40-l ml.run_forever(speed_sp=l,stop_action='brake') mr.run_forever(speed_sp=r,stop_action='brake') stop() def linetrace_lout(): c1=cs.value() while c1<40: c1=cs.value() x=(abs(c1-10)/70)*100 if x>100: x=100 r=(x/100)*120-40 l=40-r ml.run_forever(speed_sp=l,stop_action='brake') mr.run_forever(speed_sp=r,stop_action='brake') stop()
赤ボールを缶5,6に乗せるときのために、設定した時間で終了するライントレースを作成した。
def linetrace_ltime(j): c1=cs.value() t1=time.time() #プログラムがスタートした時刻を定義 t2=time.time() #プログラムの経過時間を定義 while t2-t1<j: #j秒経った時に止まる。 c1=cs.value() t2=time.time() x=abs((c1-10)/70)*100 if x>100: x=100 r=(x/100)*210-30 l=150-r ml.run_forever(speed_sp=l,stop_action='brake') mr.run_forever(speed_sp=r,stop_action='brake') stop()
def roll(s): ma.run_to_rel_pos(position_sp=s,speed_sp=80,stop_action='hold') time.sleep(3)
モーターを回すだけのシンプルなプログラムになっている。基本的に220度ずつ回している。
課題2ではタイヤの回転角度で車体の角度を測っていたが、それだと車体のバッテリー残量で回転角度が変わっていたので、ジャイロセンサーを利用して改善した。
def discover_l(s,t): #左回りの場合 u1=us.value() #超音波センサーの値を先に定義する g1=gs.value() #プログラムスタート時の角度を定義 g2=gs.value() #プログラムの途中経過の角度をあらかじめ定義 while g1-g2<s: #g1-g2は回った角度を表していて、それがs度に達した時プログラムが終了する ちなみにジャイロセンサーは右回転するとその値が増加するため、左回転していた場合、g1>g2となるので引く順番に気をつける u2=us.value() #プログラムの進行中に逐次超音波センサーの値を保存する ml.run_forever(speed_sp=-70,stop_action='hold') mr.run_forever(speed_sp=70,stop_action='hold') #車体を左回転させる g2=gs.value() #ジャイロセンサーの値を逐次更新する if u2<u1: #超音波センサーを更新した時、その値が最小値だった場合はその値をu1に保存しておく u1=u2 g3=gs.value() #その時の角度もg3に保存しておく g4=gs.value() #缶発見後に右回転する時のスタート地点の角度を定義 g5=gs.value() #右回転している時の角度を定義 if u1<=t: #指定した範囲内に缶が存在していた場合 while g5-g4<g3-g2-6: #缶の位置に到達するまで右回りする -6がついているのは、ジャイロセンサーの誤差分を埋めるためにある。 mr.run_forever(speed_sp=-70,stop_action='hold') ml.run_forever(speed_sp=70,stop_action='hold') g5=gs.value() stop() u3=us.value() #超音波センサーの値をあらかじめ定義 t1=time.time() #この時の時間を保存 while u3<2550: #※1 ml.run_forever(speed_sp=100,stop_action='hold') mr.run_forever(speed_sp=100,stop_action='hold') #缶に近づくために進む u3=us.value() #超音波センサーの値を更新していく t2=time.time() #進んだ経過時間を測定する stop() roll(220) #ベルトコンベアを回してボールを射出する ml.run_timed(speed_sp=-100,time_sp=(t2-t1)*1000,stop_action='hold') mr.run_timed(speed_sp=-100,time_sp=(t2-t1)*1000,stop_action='hold') #缶に近づくために進んだ分だけ後退する time.sleep(t2-t1) #後退している間プログラムを一時停止する g6=gs.value() #初期位置に戻るためのスタートの時間を定義 g7=gs.value() #初期位置に戻る時の経過時間をあらかじめ定義 while g7-g6<=g1-g3-6: #初期位置に戻るまでループする mr.run_forever(speed_sp=-70,stop_action='hold') ml.run_forever(speed_sp=70,stop_action='hold') #右回転 g7=gs.value() stop() else: #測定した範囲内で缶が見つからなかった場合 while g5-g4<g1-g2: #測り始めた位置まで戻る mr.run_forever(speed_sp=-70,stop_action='hold') ml.run_forever(speed_sp=70,stop_action='hold') g5=gs.value() stop() def discover_r(s,t): #右回転の場合 左回転の時とさほど変わらないので細かいところは省略 u1=us.value() g1=gs.value() g2=gs.value() while g2-g1<s: #今回は右回転となるためg2>g1となる u2=us.value() ml.run_forever(speed_sp=70,stop_action='hold') mr.run_forever(speed_sp=-70,stop_action='hold') g2=gs.value() if u2<u1: u1=u2 g3=gs.value() g4=gs.value() g5=gs.value() if u1<=t: while g4-g5<g2-g3-6: mr.run_forever(speed_sp=70,stop_action='hold') ml.run_forever(speed_sp=-70,stop_action='hold') g5=gs.value() stop() u3=us.value() t1=time.time() while u3<2550: ml.run_forever(speed_sp=100,stop_action='hold') mr.run_forever(speed_sp=100,stop_action='hold') u3=us.value() t2=time.time() stop() roll(220) ml.run_timed(speed_sp=-100,time_sp=(t2-t1)*1000,stop_action='hold') mr.run_timed(speed_sp=-100,time_sp=(t2-t1)*1000,stop_action='hold') time.sleep(t2-t1) g6=gs.value() g7=gs.value() while g6-g7<=g3-g1-6: mr.run_forever(speed_sp=70,stop_action='hold') ml.run_forever(speed_sp=-70,stop_action='hold') g7=gs.value() stop() else: while g4-g5<90: mr.run_forever(speed_sp=70,stop_action='hold') ml.run_forever(speed_sp=-70,stop_action='hold') g5=gs.value() stop()
※1 超音波センサーの値が2550を示した時にwhile関数を抜ける。ここで言う2550というのは2550だけの距離があるということではなく、超音波センサーと缶の距離が限りなく近いことを表している。超音波センサーは2つのスピーカーから発せられた超音波の干渉縞を計測しているのではないかと思う。なので超音波センサーに缶を限りなく近づけた時、干渉縞が形成されずセンサーが自身の測れる距離の限界である2550ではないかと勘違いをする。それを利用して超音波センサーが缶に限りなく近づいた(センサーの値が2550)時、whileのループを抜けるようにした。
分かりづらいので画像を載せておく。
#!/usr/bin/env python3 from ev3dev.ev3 import * import time ml=LargeMotor('outA') mr=LargeMotor('outD') ma=LargeMotor('outB') cs=ColorSensor('in3') us=UltrasonicSensor('in4') gs=GyroSensor('in1') def stop(): 車輪を止める ml.stop() mr.stop() def linetrace_rin(): #説明済みのため省略 c1=cs.value() while c1>13: c1=cs.value() x=(abs(c1-10)/70)*100 if x>100: x=100 l=(x/100)*210-30 r=150-l ml.run_forever(speed_sp=l,stop_action='brake') mr.run_forever(speed_sp=r,stop_action='brake') stop() def linetrace_lin(): c1=cs.value() while c1>13: c1=cs.value() x=abs((c1-10)/70)*100 if x>100: x=100 r=(x/100)*210-30 l=150-r ml.run_forever(speed_sp=l,stop_action='brake') mr.run_forever(speed_sp=r,stop_action='brake') stop() def linetrace_rout(): c1=cs.value() while c1<40: c1=cs.value() x=(abs(c1-10)/70)*100 if x>100: x=100 l=(x/100)*120-40 r=40-l ml.run_forever(speed_sp=l,stop_action='brake') mr.run_forever(speed_sp=r,stop_action='brake') stop() def linetrace_lout(): c1=cs.value() while c1<40: c1=cs.value() x=(abs(c1-10)/70)*100 if x>100: x=100 r=(x/100)*120-40 l=40-r ml.run_forever(speed_sp=l,stop_action='brake') mr.run_forever(speed_sp=r,stop_action='brake') stop() def linetrace_ltime(j): #説明済みのため省略 c1=cs.value() t1=time.time() t2=time.time() while t2-t1<j: c1=cs.value() t2=time.time() x=abs((c1-10)/70)*100 if x>100: x=100 r=(x/100)*210-30 l=150-r ml.run_forever(speed_sp=l,stop_action='brake') mr.run_forever(speed_sp=r,stop_action='brake') stop() def runtime(l,r): #指定した時間分タイヤを動かす ml.run_timed(time_sp=l*1000,speed_sp=70,stop_action='brake') mr.run_timed(time_sp=r*1000,speed_sp=70,stop_action='brake') time.sleep((l+r)/2) def angle(l,r,t): #指定した角度分タイヤを動かす lは左タイヤの角度、rは右タイヤの角度、tはスリープする時間 ml.run_to_rel_pos(position_sp=l,speed_sp=115,stop_action='hold') mr.run_to_rel_pos(position_sp=r,speed_sp=115,stop_action='hold') time.sleep(t) def kaiten_r(s,t): 右回りに回転 g1=gs.value() #ジャイロセンサーの値をあらかじめ定義 g2=gs.value() #ジャイロセンサーの値をあらかじめ別の変数に定義 while g2-g1<s: #g2とg1を比較してg2-g1が指定した角度になったら止まる ml.run_forever(speed_sp=t,stop_action='hold') mr.run_forever(speed_sp=-t,stop_action='hold') #指定した速度で右回転する g2=gs.value() #ループする度にg2の値を更新していく stop() #止まる def kaiten_l(s,t): 左回りに回転 g1=gs.value() g2=gs.value() while g1-g2<s: #ジャイロセンサーは時計回りだと値が増加していくため、左回りの場合g1-g2にしなければならない ml.run_forever(speed_sp=-t,stop_action='hold') mr.run_forever(speed_sp=t,stop_action='hold') #指定した速度で左回転する g2=gs.value() #ループする度にg2の値を更新していく stop() #止まる def roll(s): ベルトコンベアを動かすプログラム ma.run_to_rel_pos(position_sp=s,speed_sp=80,stop_action='hold') time.sleep(3) def discover_l(s,t): #上で説明済みのため省略 u1=us.value() g1=gs.value() g2=gs.value() while g1-g2<s: u2=us.value() ml.run_forever(speed_sp=-70,stop_action='hold') mr.run_forever(speed_sp=70,stop_action='hold') g2=gs.value() if u2<u1: u1=u2 g3=gs.value() g4=gs.value() g5=gs.value() if u1<=t: while g5-g4<g3-g2-6: mr.run_forever(speed_sp=-70,stop_action='hold') ml.run_forever(speed_sp=70,stop_action='hold') g5=gs.value() stop() u3=us.value() t1=time.time() while u3<2550: ml.run_forever(speed_sp=100,stop_action='hold') mr.run_forever(speed_sp=100,stop_action='hold') u3=us.value() t2=time.time() stop() roll(220) ml.run_timed(speed_sp=-100,time_sp=(t2-t1)*1000,stop_action='hold') mr.run_timed(speed_sp=-100,time_sp=(t2-t1)*1000,stop_action='hold') time.sleep(t2-t1) g6=gs.value() g7=gs.value() while g7-g6<=g1-g3-6: mr.run_forever(speed_sp=-70,stop_action='hold') ml.run_forever(speed_sp=70,stop_action='hold') g7=gs.value() stop() else: while g5-g4<90: mr.run_forever(speed_sp=-70,stop_action='hold') ml.run_forever(speed_sp=70,stop_action='hold') g5=gs.value() stop() def discover_r(s,t): u1=us.value() g1=gs.value() g2=gs.value() while g2-g1<s: u2=us.value() ml.run_forever(speed_sp=70,stop_action='hold') mr.run_forever(speed_sp=-70,stop_action='hold') g2=gs.value() if u2<u1: u1=u2 g3=gs.value() g4=gs.value() g5=gs.value() if u1<=t: while g4-g5<g2-g3-6: mr.run_forever(speed_sp=70,stop_action='hold') ml.run_forever(speed_sp=-70,stop_action='hold') g5=gs.value() stop() u3=us.value() t1=time.time() while u3<2550: ml.run_forever(speed_sp=100,stop_action='hold') mr.run_forever(speed_sp=100,stop_action='hold') u3=us.value() t2=time.time() stop() roll(220) ml.run_timed(speed_sp=-100,time_sp=(t2-t1)*1000,stop_action='hold') mr.run_timed(speed_sp=-100,time_sp=(t2-t1)*1000,stop_action='hold') time.sleep(t2-t1) g6=gs.value() g7=gs.value() while g6-g7<=g3-g1-6: mr.run_forever(speed_sp=70,stop_action='hold') ml.run_forever(speed_sp=-70,stop_action='hold') g7=gs.value() stop() else: while g4-g5<90: mr.run_forever(speed_sp=70,stop_action='hold') ml.run_forever(speed_sp=-70,stop_action='hold') g5=gs.value() def Redball(): #スタートから赤ボールを取りに行くプログラム angle(250,250,3) #赤ボールの位置まで進む kaiten_r(180,110) #ボールを掬う部分は車体の後ろにあるので180度回転する roll(220) #ボールを掬う kaiten_r(195,110) #車体の向きを戻す ライントレースの条件に引っかからないようにすこし余分に回っておく linetrace_lin() #G地点まで線の右側をライントレースする def Blueball(): 青ボールを取りに行くまでのプログラム angle(-20,160,2) #Gの交差点をまたぐために位置を調整する linetrace_lin() #GからHまで線の右側をライントレースする angle(-35,-35,1.5) #Hの交差点を認識したら車体を回転した際、ボールとぶつからないように少し下がる kaiten_r(175,110) #車体を180度回転させる roll(220) #ボールを掬う def move(): 青ボールを拾った後、Eの交差点に行くまでのプログラム kaiten_r(190,110) #車体の向きを元に戻す angle(-50,-50,1) #ライントレースが安定するように少し下がる linetrace_lin() #Hまで線の右側をライントレースする linetrace_lout() #Hを認識後、linetrace_lin()では右に曲がりきれないため、よりゆっくり進むこちらに切り替える linetrace_lin() #HからI間の線の境界線上まで来たら、こちらに切り替え linetrace_lout() #Iを認識後、こちらに先ほどと同じ理由でこちらに切り替え linetrace_lin() #Eを認識するまでライントレース def BlueZone(): #赤ボールを缶に乗せて分岐から帰ってきた後、青ボールを乗せに行くプログラム linetrace_rin() #EからI間の線の左側をライントレースする linetrace_rout() #Iを認識後、linetrace_rin()では左に曲がりきれないため、よりゆっくり進むこちらに切り替える linetrace_rin() #IからH間の線の境界線上まで来たら、こちらに切り替え、このままHまで進む angle(70,0,1) #交差点を跨ぐ linetrace_rin() #HからKまでライントレースする def discover2(): #青ボールを射出するプログラム kaiten_l(60,100) #角度を調整しておく discover_r(90,500) #缶に乗せるプログラム 上で説明済みなので省略 def start(): r=int(input("insert numbera")) #赤は番号の場合分けが容易だったため、赤のみダミーを避けるために分岐を設けた。その際に缶に番号を入力する。 Redball() Blueball() move() if r<=2: #缶1缶2に置く時 Eの位置で缶を探し始める kaiten_l(90,110) #E地点で上の方向を向く discover_l(90,250) #缶を乗せるプログラムを作動 範囲は地図のピンク色の部分 kaiten_l(95,100) #E地点で左側を向く if r==3: #缶3に置く時 Dまで進んで缶3がある範囲のみ探す angle(-40,180,2) #Eの左下から右上に車体を移す linetrace_lin() #EからD間の線の右側をライントレースする discover_r(60,250) #D地点で缶を乗せるプログラムを作動 範囲は地図の青色の部分 angle(-150,-150,2) #後に車体を180度回転させた時、車体が缶3にぶつからないように少し下がる kaiten_l(195,110) #195度左回転をする linetrace_rin() #DからEの間を線の左側をライントレースする angle(230,-40,2) #Eの右上から左下に移動 if r==4: #缶4に置く時 Dまで進んで缶4がある範囲のみ探す angle(-40,180,2) #Eの左下から右上に車体を移す linetrace_lin() #EからD間の線の右側をライントレースする discover_l(60,250) #D地点で缶に乗せるプログラムを作動 範囲は地図の紫色の部分 kaiten_l(195,110) #195度左回転する linetrace_rin() #DからEの間を線の左側をライントレースする angle(230,-40,2) #Eの右上から左下に移動 if 5<=r: #缶5缶6に置く時 Uターンの手前まで進み、缶がある範囲を探す angle(-40,180,2) #Eの左下から右上に車体を移す linetrace_lin() #EからD間の線の右側をライントレースする linetrace_lout() #Dの交差点を認識後、linetrace_lin()のままだと右に曲がりきれないのでこちらに切り替える linetrace_ltime(3) #Dから急カーブ前の間で線の境界線上を認識後、3秒だけライントレースをする discover_l(60,190) #缶に乗せるプログラムを作動 範囲は地図の緑色の部分 angle(-130,-130,3) #後に車体を180度回転する時に、車体が缶5にぶつからないように少し下がる kaiten_l(180,110) #車体を左に180度回転する linetrace_rin() #D地点までライントレース linetrace_rout() #D地点を認識後、角を曲がり切れるようにこちらに切り替える linetrace_rin() #E地点までライントレース angle(230,-40,2) #Eの右上から左下に移動 BlueZone() discover2() start() #起動
ロボコンでは無事に優勝することができた。しかし、青ボールを缶に乗せることが出来なかった。本番で失敗したところの1つは赤いボールを掬う時である。これはジャイロセンサーの調子がEV3を起動した時に少しだけ変化するため、180度回転したつもりが、行き過ぎたり足りなかったりするのが原因だ。2つ目は赤ボールを乗せた後、交差点Iに侵入する時にライントレースがうまく作動しなかったことだ。これはロボットを作動した時の外部の環境(蛍光灯の明るさなど)によってカラーセンサーの値が少し変化したのではないかと思われる。
課題3では課題1や課題2の反省点を生かしたロボットができたのではないかと思った。このゼミを受ける前はロボットを動かすために、いかに良いプログラムを作れるかが課題だと思っていたが、実際に取り組んでみるとロボット自体のハードの大切さに気づかされた。与えられた課題に適したロボットを作り、それに合ったプログラムを作ることが大事である。
総計:1013