2019a/Member

課題2

内容

「紙に書いた黒い線に沿ってロボットを動かしボールを運ぶ」という課題だった。

コース

今回は以下のようなコースでロボットを動かした。
Map.png
(赤い矢印の方向に進む。また青い丸では1秒止まる。)

戦略

ライントレース

今回の課題ではライントレースをどのように行うかでロボットの速度や交差点がある程度決まる。今回は交差点判断との相性を考えて、以下のような方法でライントレースをすることにした。
LineTrace.png
今回は黒い線と白い地面の境目をたどるような方法でライントレースをすることにした。例えば上の図のように黒い線の左側をたどるときは

  • もしカラーセンサーで地面の色を測定して黒色だったらラインの内側にいると判断してロボットを左前方に動かす。
  • もしカラーセンサーで地面の色を測定して白色だったらラインの左外側にいると判断してロボットを右前方に動かす。

という動作を繰り返して黒い線と白い地面の境目をたどるという方法をとった。

また、この方法で直線上をライントレースするとカラーセンサーは地面の色を

黒→白→黒→白→黒→白→黒→白→黒→白→黒→白→黒→白→黒

というように交互に判断する。またカーブ上でもよほどきついカーブでない限り

黒→黒→白→黒→黒→白→黒→黒→黒→白→黒→黒→黒→黒→白

といった感じに判断した地面の色が長時間連続して黒だけだったり白だけだったりということは起こらない。この特性を利用して交差点の判断をする。

交差点の判断

交差点を判断するのは単純に見えてとても難しい。今回はかなりきついカーブでも交差点と誤認せずコースの地点Jのような交差点も交差点と認識できるように以下のような方法で交差点を判別した。
DetermineTheIntersection.png
交差点の上で戦略,里茲Δ縫薀ぅ鵐肇譟璽垢鬚垢襪噺鮑硬世虜険Δ力咾里擦い妊蹈椒奪箸黒い線の上にいる時間が長くなる。そこで戦略,諒法でライントレースをしてもロボットがある一定時間連続して黒い線の上にいたらそこを交差点と判断するようにした。またこの方法では「ロボットがある一定時間連続して黒い線の上にいたら」という条件で交差点を判断するが、その間にもロボットは動いてしまうので交差点と判断して止まった場所と実際の交差点の位置が少しずれる。そこはその都度位置のずれを打ち消すような動きを直後にプログラムすることで対応した。

作成したロボット

Robot.png
今回は上のようなロボットを作成した。課題1の時とは違い今回使ったEV3のモーターはかなり正確だったのでギアは使っていない。今回は以下の二点を工夫した。

アーム

ボールを運ぶためのアームはこのようなものにした。
Arm.png

カラーセンサー

カラーセンサーは黒線の有無がしっかりわかるようなるべく地面に近づけるようにした。
ColorSensor.png

プログラムの準備

モジュールのインポート

#!/usr/bin/env python3
from ev3dev.ev3 import *
import time

インスタンスと定数の作成

mR = LargeMotor("outA")
mL = LargeMotor("outB")
mB = MediumMotor("outC")
cs = ColorSensor("in1")
cs.mode = "COL-REFLECT"
speed_sp = 100
black_line_reflection = 7

インスタンスの名前の由来は

  • 右側(Right)のモーター(motor)
  • 左側(Left)のモーター(motor)
  • ボール(Ball)を持つために使うモーター(motor)
  • カラーセンサー(colorsensor)

である。
今回カラーセンサーは反射光の強さを0〜100の値で返すCOL-REFLECTモードを使った。

また、定数の使い道は以下の通り。

  • speed_sp: モーターを動かす速度。今回はライントレースを正確にするために±100と遅めにした。
  • black_line_reflection: 黒い線上をカラーセンサーで明るさ測定したときの値。カラーセンサーで地面の明るさ測定をしたときこの値より低い値が出たら黒い線の上にいると判断する。

関数の定義

今回は以下の関数を定義した。

  • ロボットを前進させる関数
  • ロボットを時計回り/反時計回りに回転させる関数
  • 黒い線の右側/左側をライントレースさせる関数
  • ロボットにボールをキャッチ/シュートさせる関数

ロボットを前進させる関数

def forward(distance):
    mR.run_timed(time_sp=distance / speed_sp * 2000, speed_sp=speed_sp, stop_action="hold")
    mL.run_timed(time_sp=distance / speed_sp * 2000, speed_sp=speed_sp, stop_action="hold")
    time.sleep(distance / speed_sp * 2)

引数:

  • distance: 前進させる距離をmmで指定する。

この関数の説明:

  • time_spはtime_sp=1000,speed_sp=360のとき180mm進むので、そこから逆算した。

ロボットを時計回りに回転させる関数

def clockwise(angle):
    mR.run_timed(time_sp=angle / speed_sp * 2000, speed_sp=-speed_sp, stop_action="hold")
    mL.run_timed(time_sp=angle / speed_sp * 2000, speed_sp=speed_sp, stop_action="hold")
    time.sleep(angle / speed_sp * 2)

引数:

  • angle: 時計回りに回転させる角度を度数法で指定する。

この関数の説明:

  • 二つのタイヤの真ん中を中心として時計回りに回転させる。
  • time_spはtime_sp=1000,speed_sp=360の時ロボットが180度回転したのでそこから逆算した。

ロボットを反時計回りに回転させる関数

def counter_clockwise(angle):
    mR.run_timed(time_sp=angle / speed_sp * 2000, speed_sp=speed_sp, stop_action="hold")
    mL.run_timed(time_sp=angle / speed_sp * 2000, speed_sp=-speed_sp, stop_action="hold")
    time.sleep(angle / speed_sp * 2)

引数:

  • angle: 反時計回りに回転させる角度を度数法で指定する。

この関数の説明:

  • 二つのタイヤの真ん中を中心として反時計回りに回転させる。
  • time_spはtime_sp=1000,speed_sp=360の時ロボットが180度回転したのでそこから逆算した。

黒い線の右側をライントレースさせる関数

RightSideLineTrace.png

def right_side_line_trace():
    reflection_log = [False for _ in range(30)]
    while True:
        del reflection_log[0]

        if cs.value() <= black_line_reflection:
            # black
            mR.stop(stop_action="hold")
            mL.run_timed(time_sp=1000, speed_sp=speed_sp, stop_action="hold")
            reflection_log.append(True)
        else:
            # white
            mL.stop(stop_action="hold")
            mR.run_timed(time_sp=1000, speed_sp=speed_sp, stop_action="hold")
            reflection_log.append(False)

        if all(reflection_log):
            mR.stop(stop_action="hold")
            mL.stop(stop_action="hold")
            break

この関数の説明:

  • 黒い線の右側をライントレースする関数。
  • 具体的には
    • もし地面の明るさがblack_line_reflectionを下回っていたら黒い線の上だと判断して右前方に進む。
    • もし地面の明るさがblack_line_reflectionを上回っていたら黒い線の上ではないと判断して左前方に進む。
    • 一定時間黒い線の上いたら(30回連続して地面の明るさがblack_line_reflectionを下回っていたら)交差点だと判断して止まる。

という動作をすることによってライントレースをする。

黒い線の左側をライントレースさせる関数

LeftSideLineTrace.png

def left_side_line_trace():
    reflection_log = [False for _ in range(30)]
    while True:
        del reflection_log[0]

        if cs.value() <= black_line_reflection:
            # black
            mL.stop(stop_action="hold")
            mR.run_timed(time_sp=1000, speed_sp=speed_sp, stop_action="hold")
            reflection_log.append(True)
        else:
            # white
            mR.stop(stop_action="hold")
            mL.run_timed(time_sp=1000, speed_sp=speed_sp, stop_action="hold")
            reflection_log.append(False)

        if all(reflection_log):
            mR.stop(stop_action="hold")
            mL.stop(stop_action="hold")
            break

この関数の説明:

  • 黒い線の左側をライントレースする関数。right_side_line_trace関数とほとんど同じ。
  • 具体的には
    • もし地面の明るさがblack_line_reflectionを下回っていたら黒い線の上だと判断して左前方に進む。
    • もし地面の明るさがblack_line_reflectionを上回っていたら黒い線の上ではないと判断して右前方に進む。
    • 一定時間黒い線の上いたら(30回連続して地面の明るさがblack_line_reflectionを下回っていたら)交差点だと判断して止まる。

という動作をすることによってライントレースをする。

ロボットにボールをキャッチさせる関数

def catch():
    mB.run_to_rel_pos(position_sp=-60, speed_sp=speed_sp, stop_action="hold")
    time.sleep(1)

この関数の説明:

  • speed_spはモーターの向きの関係で負になっている。
  • スリープさせる時間が1秒なのは、この関数が実行される前のアームの位置がわからないため。1秒あればペンを動かすには問題ないと判断した。

ロボットにボールをシュートさせる関数

def shot():
    # Release the ball from the arm.
    mB.run_to_rel_pos(position_sp=60, speed_sp=speed_sp, stop_action="hold")
    time.sleep(1)

    # Move backward.
    mR.run_timed(time_sp=500, speed_sp=-1000, stop_action="hold")
    mL.run_timed(time_sp=500, speed_sp=-1000, stop_action="hold")
    time.sleep(0.5)

    # Move forward
    mR.run_timed(time_sp=700, speed_sp=1000, stop_action="hold")
    mL.run_timed(time_sp=700, speed_sp=1000, stop_action="hold")
    time.sleep(0.7)

この関数の説明:

  • ボールをシュートさせる関数。
    .◆璽爐らボールを外す。
    後ろに下がる。
    ボールに体当たりしてボールを蹴る。

という動作によってボールをシュートする。

ロボットを動かす

MからKまで

RobotAtM.png

# from M to K
left_side_line_trace() #

ボールをキャッチする

RobotAtK_1.png

# from K to L
clockwise(35) #
forward(180) #
catch()
# from L to K
counter_clockwise(180) #
left_side_line_trace() #

KからJまで

RobotAtK_2.png
ロボットのカラーセンサーがJを確実に判別できるよう、ロボットをいったんJより右側に移してからライントレースをさせた。

# from K to J
counter_clockwise(45) #
forward(100) #
clockwise(115) #
left_side_line_trace() #
time.sleep(1)

JからIまで

RobotAtJ.png

# from J to I
counter_clockwise(30) #
left_side_line_trace() #

IからHまで

RobotAtI.png

# from I to H
forward(30) #
left_side_line_trace() #

HからGまで

RobotAtH.png

# from H to G
forward(20) #
left_side_line_trace() #

GからDまで

RobotAtG.png

# from G to D
forward(20) #
left_side_line_trace() #
time.sleep(1)

DからBまで動かしてシュートさせる

RobotAtD.png

# from D to G
forward(20) #
right_side_line_trace() #
shot()

反省

ライントレースと交差点判断はとても精度が高かったがその分速度がかなり遅かった。speed_spの値を高くするなど速度を上げる工夫をしてみたが、そうすると交差点判断の精度がかなり落ちてしまい結局速度を上げることが出来なかった。またボールをシュートする方法が体当たりだったが、体当たりするときにボールをアームから外すとボールが動いてしまい変な方向にボールをシュートしてしまうといったことが多発した。もう少しアームの形を工夫すればシュートの精度が上がったと思う。




昨日の訪問者数: 0人
今日の訪問者数: 1人
合計訪問者数: 4人


添付ファイル: fileRightSideLineTrace.png [詳細] fileLeftSideLineTrace.png [詳細] fileRobot.png [詳細] fileArm.png [詳細] fileColorSensor.png [詳細] fileRobotAtK_2.png [詳細] fileRobotAtM.png [詳細] fileRobotAtK_1.png [詳細] fileRobotAtJ.png [詳細] fileRobotAtI.png [詳細] fileRobotAtH.png [詳細] fileRobotAtG.png [詳細] fileRobotAtD.png [詳細] fileDetermineTheIntersection.png 1件 [詳細] fileLineTrace.png [詳細] fileMap.png [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-08-14 (水) 01:11:55 (4d)