*はじめに [#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)
}}