LEGO MINDSTORMS EV3で強化学習する

| Topic path: Top / 強化学習 / LEGO MINDSTORMS EV3で強化学習する

*はじめに [#zb65e2c8]

LEGO MINDSTORMS EV3でライントレースを強化学習します。

まずは、EV3でPythonを動かせるようにします。
-[[LEGO MINDSTORMS EV3でPythonを使う>強化学習/LEGO MINDSTORMS EV3でPythonを使う]] - とうごろうぃき



*準備 [#oc34905c]

numpyをEV3にインストールします。
NumPyをEV3にインストールします。
#geshi(sh){{
robot@ev3dev:~$ sudo apt-get update
robot@ev3dev:~$ sudo apt-get install python3-numpy
}}



*クラス構造 [#u8541859]
-環境を表す Environment
--EV3のライントレースを表す EV3LineTrace
-強化学習エージェントを表す ReinformentLearningAgent
--Q学習エージェントを表す QLearningAgent

Environmentクラス、ReinformentLearningAgentクラス、QLearningAgentクラスは、「[[Pythonで強化学習する>強化学習/Pythonで強化学習する]]」で作成したものと同じです。


*EV3のライントレース EV3LineTrace [#ocfd5e7a]

EV3基本セットで作れるトレーニング・ロボットのカゴを外し、光センサーを左右に一つづつけたロボットを使用します。
(光センサーは別売りです。)

状態は、光センサーで読み取った値が40以上かどうかで状態を区別しています。
左右のセンサーがあるので4状態になります。

行動は、「左に曲がる」と「右に曲がる」の2種類としています。

報酬は、左右いずれかの光センサーの値が未満(黒)であれば [math]1.0[/math]、そうでなければ [math]-0.01[/math] としています。



#ref(./ev3lt.py)
#geshi(python){{
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# ev3lt.py
#
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
import ev3dev.ev3 as ev3
import environment as env
import numpy as np
import time


class EV3LineTrace(env.Environment):
    """EV3でライントレース問題。状態は (左光センサー観測値, 右光センサー観測値) で表される。"""

    states = 4 # 状態数
    actions = 2 # 行動数
    motor_l = ev3.LargeMotor('outB')    # 左モーター
    motor_r = ev3.LargeMotor('outC')    # 右モーター
    sensor_l = ev3.LightSensor('in2')   # 左光センサー
    sensor_r = ev3.LightSensor('in3')   # 右光センター
    sleep = 0.1 # スリープ時間

    @classmethod
    def init_state(cls):
        """初期状態として現在の状態を返す。"""
        state = cls.get_state()
        return state

    @classmethod
    def is_terminal(cls, state):
        """渡された状態が終端状態ならTrue, そうでないならFalseを返す。"""
        return False

    @classmethod
    def get_state(cls):
        """現在の状態(センサーの値)を返す。"""
        light_l = cls.sensor_l.reflected_light_intensity  # 左側光センサーの反射光の強さ
        light_r = cls.sensor_r.reflected_light_intensity  # 右側光センサーの反射光の強さ
        return (light_l, light_r)

    @classmethod
    def get_s(cls, state):
        """状態を状態番号に変換して返す。"""
        light_l, light_r = state[0], state[1]
        if light_l < 40 and light_r < 40:
            s = 0
        elif light_l < 40:
            s = 1
        elif light_r < 40:
            s = 2
        else:
            s = 3
        return s

    @classmethod
    def get_a(cls, action):
        """行動を行動番号に変して返す。"""
        return action

    @classmethod
    def get_reward(cls, state):
        """報酬を返す。"""
        light_l, light_r = state[0], state[1]
        if light_l < 40 or light_r < 40:  # どちらかの光センサーの値が40未満(黒)なら
            reward = 1.0
        else:
            reward = -0.01
        return reward

    @classmethod
    def take_action(cls, state, action):
        """行動を実行して状態を更新し、報酬と次の状態を返す。"""
        if action == 0:
            state_ = cls.turn_l()
        else:
            state_ = cls.turn_r()
        reward = cls.get_reward(state_)
        return reward, state_,

    @classmethod
    def str_state(cls, state):
        """状態を表す文字列を返す。"""
        light_l, light_r = state[0], state[1]
        return '(%.3f, %.3f)' % (light_l, light_r)

    @classmethod
    def str_action(cls, action):
        """行動を表す文字列を返す。"""
        if action == 0:
            str = 'turnL'
        else:
            str = 'turnR'
        return str

    @classmethod
    def turn_l(cls):
        """左に曲がる。"""
        cls.motor_l.run_forever(speed_sp=-25)   # 左のモーターを後ろに、
        cls.motor_r.run_forever(speed_sp=100)    # 右のモーターを前に回す
        time.sleep(cls.sleep)
        state_ = cls.get_state()
        return state_

    @classmethod
    def turn_r(cls):
        """右に曲がる。"""
        cls.motor_l.run_forever(speed_sp=100)    # 左のモーターを前に、
        cls.motor_r.run_forever(speed_sp=-25)   # 右のモーターを後ろに回す
        time.sleep(cls.sleep)
        state_ = cls.get_state()
        return state_

    @classmethod
    def stop(cls):
        """止まる。"""
        cls.motor_l.stop()
        cls.motor_r.stop()
    
    def __init__(self):
        super().__init__()
}}

*実行用ファイル [#va34d4ac]
#ref(./ev3ltql.py)
#geshi(python){{
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# ev3ltql.py
#
# Copyright 2017-2018 Tohgoroh Matsui All Rights Reserved.
#
import ev3lt
import qlagent


if __name__ == '__main__':
    ev3lt = ev3lt.EV3LineTrace()    # 環境
    agent = qlagent.QLearningAgent(environment=ev3lt, epsilon=0.1, max_steps=10000, evaluation=False, verbose_level=2)    # Q学習エージェント
    agent.learn()   # 学習する
}}

*実行 [#yf90b99f]
#geshi(sh){{
$ python3 ev3ltql.py 
# 0, (59.2, 65.5), turnR, -0.010000, (58.8, 65.1)
# 1, (58.8, 65.1), turnL, -0.010000, (58.8, 64.7)
# 2, (58.8, 64.7), turnR, -0.010000, (57.9, 64.3)
# 3, (57.9, 64.3), turnL, -0.010000, (58.4, 64.0)
# 4, (58.4, 64.0), turnL, 1.000000, (33.1, 63.7)
# 5, (33.1, 63.7), turnL, 1.000000, (58.4, 36.1)
# 6, (58.4, 36.1), turnR, -0.010000, (58.0, 56.1)
# 7, (58.0, 56.1), turnL, -0.010000, (58.1, 52.7)
# 8, (58.1, 52.7), turnL, -0.010000, (58.1, 63.7)
# 9, (58.1, 63.7), turnL, -0.010000, (58.3, 63.7)
}}
トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS