2019a/Member

課題3

課題3は「ピンポン玉または青と赤のボールを運搬して、所定の容器の中に入れる。」という課題だった。
Map.png

戦略

どのボールを取るか

課題3はテストの時期と重なるため十分な時間をかけての試行錯誤は困難であると予想された。この課題は所定の容器に入れられたピンポン玉に応じてポイントが加点されるが

  • プラ容器内のピンポン玉
    • 1個運べば8点
    • 2つとも運べば20点
  • L地点とL'地点(いずれもプラ容器外)のピンポン玉
    • 1個運べば4点
    • 2つとも運べば12点

と加点されるポイントはプラ箱内のピンポン玉を運んだほうが多い。そこで今回はプラ箱外のピンポン玉は無視してプラ箱内のピンポン玉のみを運ぶロボットを作ることにした。

ボールの取り方

プラ容器の中のピンポン玉は以下の方法で取ることにした。

  1. プラ容器を下の図のように傾ける。
    TiltTheBox.png
  2. 下の図のように傾けたプラ容器から転がってきたピンポン玉を取る。
    CatchTheBall.png

作成したロボット

Robot.png
今回は上のようなロボットを作った。工夫した点は以下の4つである。

プラ箱を傾ける部分

Arm.png
図のようにプラ箱を傾けるためにはかなり長い腕が必要だった。
TipOfTheArm.png
また腕の先端の棒はプラ箱を傾けたときにプラ箱を安定させるという役割がある。

ピンポン玉を回収する部分

Hand.png
ピンポン玉を回収する部分は上のようになっている。プラ容器内のピンポン玉2つしか回収しないのでここにはピンポン玉2つ分のスペースしかないが、その分ピンポン玉を回収する部分をコンパクトにし、重心を後ろに下げることが出来た。

センサー部分

今回はライントレースにカラーセンサーを2つ使いライントレースの精度を高めた。
ColorSensors.png

重心

Tires.png
今回のロボットではモーターを多く使ったため重心が前に傾いてしまったがタイヤを4つ使い安定した動きができるようにした。

プログラムの準備

モジュールのインポート

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

インスタンスの作成

mR = LargeMotor('outC')
mL = LargeMotor('outA')
csR = ColorSensor('in1')
csL = ColorSensor('in2')
arm = LargeMotor('outD')
hand = MediumMotor('outB')

それぞれ以下のモーターやセンサーのインスタンスである。 Instances.png

関数の定義

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

  • ロボットを右/左に回転させる関数
  • ロボットを前進/後退させる関数
  • ライントレースをする関数

ロボットを右に回転させる関数

Right.png
ロボットを右に回転させる関数は回転の中心の違う2つの関数を定義した。

def right(time_sp):
    sleep(1)
    mR.run_timed(time_sp=time_sp, speed_sp=100, stop_action="brake")
def clockwise(time_sp):
    mR.run_timed(time_sp=time_sp, speed_sp=-100, stop_action="brake")
    mL.run_timed(time_sp=time_sp, speed_sp=100, stop_action="brake")

ロボットを左に回転させる関数

Left.png
ロボットを左に回転させる関数は回転の中心の違う2つの関数を定義した。

def left(time_sp):
    sleep(1)
    mL.run_timed(time_sp=time_sp, speed_sp=100, stop_action="brake")
def counter_clockwise(time_sp):
    mR.run_timed(time_sp=time_sp, speed_sp=100, stop_action="brake")
    mL.run_timed(time_sp=time_sp, speed_sp=-100, stop_action="brake")

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

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

  • 時間を指定して前進させるforward関数
  • 停止の命令をしない限り動き続けるforward_forever関数

の二種類を定義した。

def forward(time_sp):
    mR.run_timed(time_sp=time_sp, speed_sp=100, stop_action="brake")
    mL.run_timed(time_sp=time_sp, speed_sp=100, stop_action="brake")
    sleep(1)
def forward_forever(speed_sp):
    mR.run_forever(speed_sp=100, stop_action="brake")
    mL.run_forever(speed_sp=100, stop_action="brake")

ロボットを後退させる関数

前進のときとは違い、ロボットを後退させる関数は1種類のみを定義した。

def backward(time_sp):
    mR.run_timed(time_sp=time_sp, speed_sp=-100, stop_action="brake")
    mL.run_timed(time_sp=time_sp, speed_sp=-100, stop_action="brake")

ライントレースをする関数

LineTrace_1.png
LineTrace_2.png
ライントレースをするための関数。しかしこの関数はライントレースの為でなく、下のように「ロボットに対して直角な黒線があったらロボットを止める」といった役割でつかわれた。
LineTrace_3.png

def line_trace():
    
    black_line_reflection = 15
    
    if csR.value() >= black_line_reflection and csL.value() >= black_line_reflection:
        forward_forever(100)
        sleep(0.1)
    elif csR.value() >= black_line_reflection and csL.value() < black_line_reflection:
        counter_clockwise(100)
        sleep(0.1)
    elif csR.value() < black_line_reflection and csL.value() >= black_line_reflection:
        clockwise(100)
        sleep(0.1)
    else:
        mR.stop()
        mL.stop()
        sleep(0.1)
        break

プログラム

ブロック分け

次のようにプログラムを5つのブロックに分けて作った。
Blocks.png

ロボットを動かす

最初ロボットは赤い□の位置にMのほうを頭にしておいた。

プラ容器と縦軸を合わせる

FirstStep.png

# 前進してプラ容器と縦軸を合わせる。
line_trace()
sleep(0.1)
forward_forever()
sleep(4)
mL.stop()
mR.stop()
# ロボットを回転させてプラ容器のほうを向かせる。
counter_clockwise(1900)
sleep(2.1)

プラ容器まで接近する

SecondStep.png

# line_trace関数でロボットとプラ容器の間にある黒線までロボットを前進させる。
line_trace()
sleep(0.1)
# プラ容器を傾けやすいよう距離を詰めるために少し前にずらす。
forward_forever(100)
sleep(0.3)
mL.stop()
mR.stop()

プラ容器からピンポン玉を取る

# プラ容器から確実にピンポン玉を出すためにプラ容器を2回傾ける。
# プラ容器傾け1回目
# アームをさげる
arm.reset()
sleep(0.1)
arm.run_to_rel_pos(position_sp=160, speed_sp=250, stop_action="brake")
sleep(3)

# プラ容器傾け2回目
# アームを上げる
arm.reset()
arm.run_to_rel_pos(position_sp=-160, speed_sp=250, stop_action="brake")
hand.reset()
sleep(2)
# アームを下げる
arm.reset()
arm.run_to_rel_pos(position_sp=160, speed_sp=250, stop_action="brake")
sleep(2)

# ボールを回収する
hand.run_to_rel_pos(position_sp=80, speed_sp=300, stop_action="brake")
sleep(1)

# アームを上げる
arm.reset()
arm.run_to_rel_pos(position_sp=-160, speed_sp=100, stop_action="brake")
sleep(3)

ゴールまで移動する

ForthStep.png

counter_clockwise(2000)
sleep(3)
# 直線B'C'まで動かしたいが途中ある直線BCのせいでline_trace関数1回では直線B'C'に届かない。
# なので直線BCを超えた後にline_trace関数を使う。

# 直線BCを超えさせる
forward_forever(100)
sleep(3)
mR.stop()
mL.stop()
sleep(1)

# 直線B'C'までロボットを動かす。
line_trace()
sleep(1)

# プラ容器を傾けやすいよう距離をとるために少し後ろにずらす。
backward(800)
sleep(1)
backward(800)
sleep(1)

ボールをシュートする

# アームを下げてプラ容器を傾ける
arm.reset()
arm.run_to_rel_pos(position_sp=160, speed_sp=120, stop_action="brake")
sleep(2)

# ハンドを回転させてピンポン玉をシュートする。
# ピンポン玉確実にシュートするためにハンドは何回もまわす。
# ハンドを何回もまわすためにposition_spには大きい数字を入れる。
hand.reset()
hand.run_to_rel_pos(position_sp=-2000, speed_sp=1000, stop_action="brake")
sleep(5)

# アームを上げる
arm.reset()
arm.run_to_rel_pos(position_sp=-160, speed_sp=120, stop_action="brake")

結果

2回チャンスが与えられたが、2回ともボールをとることが出来なかった。

反省と感想

今回失敗した理由としてあげられるのは、テスト前で時間がなさ過ぎて試行錯誤する回数が減ってしまったことである。試行錯誤の回数が少ないのにブロック,sleep(2.1)などの手動で値を決める場所が多すぎて、それがボールを取る動作の精度の低下を招いたと思う。

また十分な時間がかけられず、プログラムがかなり荒くなってしまった。例えば

forward(4000)

と書くところを

forward_forever(100)
sleep(4)
mL.stop()
mR.stop()

と書くなど、プログラムが最適化されていないことも精度を低くした原因の1つだと思う。もっと時間をかけられればより良い結果を出せたと思う。




昨日の訪問者数: 3人
今日の訪問者数: 1人
合計訪問者数: &counter([total|today|yesterday]);人


添付ファイル: fileCatchTheBall.png 4件 [詳細] fileTiltTheBox.png 4件 [詳細] fileMap.png 3件 [詳細] fileForthStep.png 4件 [詳細] fileSecondStep.png 3件 [詳細] fileFirstStep.png 3件 [詳細] fileLineTrace_3.png 2件 [詳細] fileLineTrace_2.png 4件 [詳細] fileLineTrace_1.png 4件 [詳細] fileBlocks.png 4件 [詳細] fileRight.png 4件 [詳細] fileLeft.png 4件 [詳細] fileTires.png 2件 [詳細] fileHand.png 1件 [詳細] fileColorSensors.png 1件 [詳細] fileTipOfTheArm.png 2件 [詳細] fileArm.png 1件 [詳細] fileRobot.png 1件 [詳細] fileInstances.png 2件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-08-15 (木) 05:05:17