目次

課題

課題説明ページ:2017b/Mission2

自分は第2コースを選択。

「EV3 Tracer」設計について

使用機:LEGO MINDSTORMS EV3

設計思想

今回のロボットは、思い通りに走って曲がるのは大前提であり、紙コップを移動させる機構が必要とされていた。
残念ながら今回は紙を動かすことはできない。
基本はEV3のデフォルト設計で良いが、ライントレースに最適なカラーセンサの取り付け、紙コップを掴む機構の取り付けが求められた。
前回ほど設計に自由度はなく、奇抜なデザインをする余裕も必要もない。
よって本機は高い安定性を重視し設計を行った。

EV3 Tracer-1

Tracer1

EV3デフォルトを基に、カラーセンサ、アームの取り付けを行った。
カラーセンサの固定位置は入念なライントレース試験を行い決定。
また、カラーセンサの精度を少しでも高めるため、ブルドーザーの如くコース整地用ブレードを取り付けた。
事故が起こった際もセンサーを保護するバンパーとして活躍するかもしれない。

コップを掴むアームは前回のX軸制御機構を流用。
この機構は前回成功を収めて信頼性も高いため、そのまま採用した。
右に固定して伸ばしたビームと、駆動する左のビームでコップを挟み込む。
左右に広く腕を広げられるため、多少誤差があってもコップを掴むことが可能。
前回のコードを流用する狙いもある。

問題点

  • アームによって全幅が大きくなった結果、コース走行時に掴む前のコップを弾いてしまい、うまくコップを掴めない。
  • ミリ単位で調整を行える元X軸制御機構の能力が無用の長物と化している。

EV3 Tracer-2

Tracer2

コップを掴むアームの機構は、掴む・離すのオンオフ制御だけできれば良かったと気づいた。
無駄に大きい前のアームは廃止し、縦置きモータにビームを直結した単純な構造に変えた。
結果、全幅も気にならない程度になり、掴む前にコップに当たって弾くことも無くなった。
こちらも左右に広く腕を開き、多少の誤差を気にせず掴むことができる。

プログラム

Tracer_ver.1.7.3

今回の課題のプログラムの最終形態。
ここでは関数群を記述している。

#!/usr/bin/env python3
import ev3dev.ev3 as ev3
import time
mr = ev3.LargeMotor('outC')
assert mr.connected, "Connect right large motor to port C"
ml = ev3.LargeMotor('outA')
assert ml.connected, "Connect left large motor to port A"
arm = ev3.MediumMotor('outB')
assert arm.connected, "Connect arm medium motor to port B"
cs = ev3.ColorSensor()
assert cs.connected, "Connect a color sensor to any sensor port"
cs.mode = 'COL-REFLECT'
angle = 17/9          #モータのposition_spに与えて角度に変換するための定数
target_val = 50       #トレース時のカラーセンサの目標値
std_speed = 40        #トレーサーの標準スピード
kp = std_speed*0.04   #線の境界へ戻る強さ
cm = 20.05            #移動をcmに変換するための定数
intersection_time = 0.23          #交差点検知時間
angle_stabilization_time = 0.3    #走行する境界を変更する際の移動時間
def line_following(dev_which_edge):   #ライントレース用
   if dev_which_edge == 'left_edge':  #後述のrun_until_intersectionに組み込む
       p = (cs.value()-target_val)*kp
   elif dev_which_edge == 'right_edge':
       p = (target_val-cs.value())*kp
   else:
       print('invalid edge')
   if p > 0:
       mr.duty_cycle_sp = std_speed-p
       ml.duty_cycle_sp = std_speed
   elif p <= 0:
       mr.duty_cycle_sp = std_speed
       ml.duty_cycle_sp = std_speed+p
def run_until_intersection(_which_edge):   #交差点を検知するまでライントレースを行う
   global which_edge                       #引数に"left_edge"か"right_edge"で左右どちらをトレースするか与えて使用
   which_edge = _which_edge
   start_time = time.time()
   for motor in mr, ml:
       motor.run_direct()
   while True:
       line_following(_which_edge)
       if 10 < cs.value() < 100:
           start_time = time.time()
       if time.time()-start_time > intersection_time:
           ev3.Sound.beep()
           while abs(cs.value()-target_val) > 10:
               line_following(_which_edge)
           for motor in mr, ml:
               motor.stop(stop_action='brake')
           break
def change_following_edge():   #トレースする境界を変更する際に交差点で使用
   for motor in mr, ml:
           motor.run_direct()
   start_time = time.time()
   if which_edge == 'right_edge':
       while time.time()-start_time < angle_stabilization_time:
           line_following('right_edge')
       for motor in mr, ml:
           motor.stop(stop_action='brake')
       circle(90)
       move(2)
       circle(-90)
   elif which_edge == 'left_edge':
       while time.time()-start_time < angle_stabilization_time:
           line_following('left_edge')
       for motor in mr, ml:
           motor.stop(stop_action='brake')
       circle(-90)
       move(2)
       circle(90)
def move(distance):   #前進、後退
   for motor in mr, ml:
       motor.run_to_rel_pos(position_sp=distance*cm, speed_sp=std_speed*5, stop_action='brake')
   for motor in mr, ml:
       motor.wait_while('running')
def circle(r):   #超信地旋回 時計回りが正
   if r < 0:
           signs = [-1, 1]
   elif r >= 0:
           signs = [1, -1]
   for motor, sign in zip([mr, ml], signs):
       motor.run_to_rel_pos(position_sp=sign*abs(r)*angle, speed_sp=std_speed*5, stop_action='brake')
   for motor in mr, ml:
       motor.wait_while('running')
def intersection_go_straight():   #交差点直進
   if which_edge == 'left_edge':
       circle(-60)
       move(3)
       for motor in mr, ml:
           motor.run_direct()
       while abs(cs.value()-target_val) > 10:
           line_following('left_edge')
   elif which_edge == 'right_edge':
       circle(60)
       move(3)
       for motor in mr, ml:
           motor.run_direct()
       while abs(cs.value()-target_val) > 10:
           line_following('right_edge')
   for motor in mr, ml:
       motor.stop(stop_action='brake')
def intersection_turn_right():   #交差点右折
   if which_edge == 'left_edge':
       circle(-155)
       move(2)
def intersection_turn_left():   #交差点左折
   if which_edge == 'right_edge':
       circle(155)
       move(2)
def catch():   #コップキャッチ
   arm.reset()
   #pos_positive: to inside, pos_negative: to outside
   arm.run_to_abs_pos(position_sp=-80, speed_sp=60, stop_action="brake")
   arm.wait_while("running")
   move(10)
   arm.run_to_abs_pos(position_sp=0, speed_sp=60, stop_action="brake")
   arm.wait_while("running")
   move(-10)
def release():   #コップリリース
   arm.run_to_abs_pos(position_sp=-80, speed_sp=60, stop_action="brake")
   arm.wait_while("running")
   move(5)
   move(-10)
   arm.run_to_abs_pos(position_sp=0, speed_sp=60, stop_action="brake")
   arm.wait_while("running")
   move(5)

TracerGyro

カラーセンサを使った交差点検知に一時期挫折し、ジャイロセンサを使って検知を試みたもの。
結局カラーセンサのほうがうまく検知できたため使われることはなくなった。

def dev_run(): #ライントレース、後述のrun_while_not_inersectionに組み込む
   #run on left edge of a line
   p = (cs.value()-target_val)*kp
   if p > 0:
       bgs = gs.value() #白を検知したら角度をリセット
       mr.duty_cycle_sp = std_speed-p
       ml.duty_cycle_sp = std_speed
   elif p <= 0:
       mr.duty_cycle_sp = std_speed
       ml.duty_cycle_sp = std_speed+p
def run_while_not_intersection(): #交差点検知までライントレース
   for motor in motors:
       motor.run_direct()
   bgs = gs.value()
   while True:
       dev_run()
       if gs.value()-bgs <= -83: #83度以上の回転を検知したら交差点
           # play intersection sound
           print('debug\tintersection gs.value()-bgs', gs.value()-bgs)

(Tracerと共通の部分は省略し、交差点検知の部分だけ記述。)

今見直すと、変数bgsをグローバル変数の宣言をしていなかった。 そのため白を検知した時点で正しく値をリセットできていなかったのかもしれない。

第2コース走行プログラム

上記のTraccer_ver1.7.3をインポートして動作する。

#!/usr/bin/env python3
from tracer_v173 import *

#Dをスタート
#C直進
run_until_intersection("left_edge")
intersection_go_straight()
run_until_intersection("left_edge")
#B左折
intersection_turn_left()
run_until_intersection("left_edge")
#P一時停止、左折
time.sleep(1)
intersection_turn_left()
run_until_intersection("left_edge")
#Q直進
intersection_go_straight()
run_until_intersection("left_edge")
#R左折
intersection_turn_left()
run_until_intersection("left_edge")
#E左折
intersection_turn_left()
# avoid misdetection of sharp turn as intersection
for motor in mr, ml:
   motor.run_direct()
start_time = time.time()
while time.time()-start_time < 12:
   line_following('left_edge')
for motor in mr, ml:
   motor.stop(stop_action='brake')
run_until_intersection('left_edge')
#F左折
intersection_turn_left()
run_until_intersection("left_edge")
#S一時停止、直進
# intersection_go_straight()
#Yコップキャッチ
circle(-120)
catch()
circle(50)
move(6)
run_until_intersection("left_edge")
#S一時停止、直進
intersection_go_straight()
run_until_intersection("left_edge")
#Q一時停止、左折
intersection_turn_left()
run_until_intersection("left_edge")
#R直進,コップリリース
intersection_go_straight()
circle(-90)
release()
circle(90)
move(1)
run_until_intersection("left_edge")
#P左折
intersection_turn_left()
run_until_intersection("left_edge")
#B一時停止、左折
time.sleep(1)
intersection_turn_left()
run_until_intersection("left_edge")
#Aゴール

結果

ライントレースは9割ほど成功するまでに洗練されてきたが、コップキャッチ周辺でミスが起こることがまだ多い。次回のロボコンに向けて、より高い精度を目指したい。


来客数カウンター 588


意見や感想などあればどうぞ。



添付ファイル: filereTracer2.jpg 82件 [詳細] filereTracer1.jpg 65件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-01-18 (木) 16:47:24 (576d)