2016-08-24 23:10:58 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
|
|
@author: Olivier Sigaud
|
|
|
|
|
|
|
|
A merge between two sources:
|
|
|
|
|
|
|
|
* Adaptation of the MountainCar Environment from the "FAReinforcement" library
|
|
|
|
of Jose Antonio Martin H. (version 1.0), adapted by 'Tom Schaul, tom@idsia.ch'
|
|
|
|
and then modified by Arnaud de Broissia
|
|
|
|
|
|
|
|
* the OpenAI/gym MountainCar environment
|
2018-11-29 02:27:27 +01:00
|
|
|
itself from
|
2017-06-14 16:27:42 -04:00
|
|
|
http://incompleteideas.net/sutton/MountainCar/MountainCar1.cp
|
|
|
|
permalink: https://perma.cc/6Z2N-PFWC
|
2016-08-24 23:10:58 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
import math
|
2018-11-29 02:27:27 +01:00
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
2016-08-24 23:10:58 +02:00
|
|
|
import gym
|
|
|
|
from gym import spaces
|
|
|
|
from gym.utils import seeding
|
|
|
|
|
2020-04-11 00:25:01 +02:00
|
|
|
|
2016-08-24 23:10:58 +02:00
|
|
|
class Continuous_MountainCarEnv(gym.Env):
|
2021-07-27 00:21:29 +04:30
|
|
|
"""
|
|
|
|
Description:
|
|
|
|
The agent (a car) is started at the bottom of a valley. For any given
|
|
|
|
state the agent may choose to accelerate to the left, right or cease
|
|
|
|
any acceleration.
|
|
|
|
Observation:
|
|
|
|
Type: Box(2)
|
|
|
|
Num Observation Min Max
|
|
|
|
0 Car Position -1.2 0.6
|
|
|
|
1 Car Velocity -0.07 0.07
|
|
|
|
Actions:
|
|
|
|
Type: Box(1)
|
|
|
|
Num Action Min Max
|
|
|
|
0 the power coef -1.0 1.0
|
|
|
|
Note: actual driving force is calculated by multipling the power coef by power (0.0015)
|
|
|
|
|
|
|
|
Reward:
|
|
|
|
Reward of 100 is awarded if the agent reached the flag (position = 0.45) on top of the mountain.
|
|
|
|
Reward is decrease based on amount of energy consumed each step.
|
|
|
|
|
|
|
|
Starting State:
|
|
|
|
The position of the car is assigned a uniform random value in
|
|
|
|
[-0.6 , -0.4].
|
|
|
|
The starting velocity of the car is always assigned to 0.
|
|
|
|
|
|
|
|
Episode Termination:
|
|
|
|
The car position is more than 0.45
|
|
|
|
Episode length is greater than 200
|
|
|
|
"""
|
2016-08-24 23:10:58 +02:00
|
|
|
metadata = {
|
|
|
|
'render.modes': ['human', 'rgb_array'],
|
|
|
|
'video.frames_per_second': 30
|
|
|
|
}
|
|
|
|
|
2020-04-11 00:25:01 +02:00
|
|
|
def __init__(self, goal_velocity=0):
|
2016-08-24 23:10:58 +02:00
|
|
|
self.min_action = -1.0
|
|
|
|
self.max_action = 1.0
|
|
|
|
self.min_position = -1.2
|
|
|
|
self.max_position = 0.6
|
|
|
|
self.max_speed = 0.07
|
|
|
|
self.goal_position = 0.45 # was 0.5 in gym, 0.45 in Arnaud de Broissia's version
|
2019-07-15 01:09:19 +05:30
|
|
|
self.goal_velocity = goal_velocity
|
2016-08-24 23:10:58 +02:00
|
|
|
self.power = 0.0015
|
|
|
|
|
2020-04-11 00:25:01 +02:00
|
|
|
self.low_state = np.array(
|
|
|
|
[self.min_position, -self.max_speed], dtype=np.float32
|
|
|
|
)
|
|
|
|
self.high_state = np.array(
|
|
|
|
[self.max_position, self.max_speed], dtype=np.float32
|
|
|
|
)
|
2016-08-24 23:10:58 +02:00
|
|
|
|
|
|
|
self.viewer = None
|
|
|
|
|
2020-04-11 00:25:01 +02:00
|
|
|
self.action_space = spaces.Box(
|
|
|
|
low=self.min_action,
|
|
|
|
high=self.max_action,
|
|
|
|
shape=(1,),
|
|
|
|
dtype=np.float32
|
|
|
|
)
|
|
|
|
self.observation_space = spaces.Box(
|
|
|
|
low=self.low_state,
|
|
|
|
high=self.high_state,
|
|
|
|
dtype=np.float32
|
|
|
|
)
|
2016-08-24 23:10:58 +02:00
|
|
|
|
Cleanup, removal of unmaintained code (#836)
* add dtype to Box
* remove board_game, debugging, safety, parameter_tuning environments
* massive set of breaking changes
- remove python logging module
- _step, _reset, _seed, _close => non underscored method
- remove benchmark and scoring folder
* Improve render("human"), now resizable, closable window.
* get rid of default step and reset in wrappers, so it doesn’t silently fail for people with underscore methods
* CubeCrash unit test environment
* followup fixes
* MemorizeDigits unit test envrionment
* refactored spaces a bit
fixed indentation
disabled test_env_semantics
* fix unit tests
* fixes
* CubeCrash, MemorizeDigits tested
* gym backwards compatibility patch
* gym backwards compatibility, followup fixes
* changelist, add spaces to main namespaces
* undo_logger_setup for backwards compat
* remove configuration.py
2018-01-25 18:20:14 -08:00
|
|
|
self.seed()
|
2016-08-24 23:10:58 +02:00
|
|
|
self.reset()
|
|
|
|
|
Cleanup, removal of unmaintained code (#836)
* add dtype to Box
* remove board_game, debugging, safety, parameter_tuning environments
* massive set of breaking changes
- remove python logging module
- _step, _reset, _seed, _close => non underscored method
- remove benchmark and scoring folder
* Improve render("human"), now resizable, closable window.
* get rid of default step and reset in wrappers, so it doesn’t silently fail for people with underscore methods
* CubeCrash unit test environment
* followup fixes
* MemorizeDigits unit test envrionment
* refactored spaces a bit
fixed indentation
disabled test_env_semantics
* fix unit tests
* fixes
* CubeCrash, MemorizeDigits tested
* gym backwards compatibility patch
* gym backwards compatibility, followup fixes
* changelist, add spaces to main namespaces
* undo_logger_setup for backwards compat
* remove configuration.py
2018-01-25 18:20:14 -08:00
|
|
|
def seed(self, seed=None):
|
2016-08-24 23:10:58 +02:00
|
|
|
self.np_random, seed = seeding.np_random(seed)
|
|
|
|
return [seed]
|
|
|
|
|
Cleanup, removal of unmaintained code (#836)
* add dtype to Box
* remove board_game, debugging, safety, parameter_tuning environments
* massive set of breaking changes
- remove python logging module
- _step, _reset, _seed, _close => non underscored method
- remove benchmark and scoring folder
* Improve render("human"), now resizable, closable window.
* get rid of default step and reset in wrappers, so it doesn’t silently fail for people with underscore methods
* CubeCrash unit test environment
* followup fixes
* MemorizeDigits unit test envrionment
* refactored spaces a bit
fixed indentation
disabled test_env_semantics
* fix unit tests
* fixes
* CubeCrash, MemorizeDigits tested
* gym backwards compatibility patch
* gym backwards compatibility, followup fixes
* changelist, add spaces to main namespaces
* undo_logger_setup for backwards compat
* remove configuration.py
2018-01-25 18:20:14 -08:00
|
|
|
def step(self, action):
|
2016-08-24 23:10:58 +02:00
|
|
|
|
|
|
|
position = self.state[0]
|
|
|
|
velocity = self.state[1]
|
2020-04-11 00:27:28 +02:00
|
|
|
force = min(max(action[0], self.min_action), self.max_action)
|
2016-08-24 23:10:58 +02:00
|
|
|
|
2020-04-11 00:25:01 +02:00
|
|
|
velocity += force * self.power - 0.0025 * math.cos(3 * position)
|
2016-08-24 23:10:58 +02:00
|
|
|
if (velocity > self.max_speed): velocity = self.max_speed
|
|
|
|
if (velocity < -self.max_speed): velocity = -self.max_speed
|
|
|
|
position += velocity
|
|
|
|
if (position > self.max_position): position = self.max_position
|
|
|
|
if (position < self.min_position): position = self.min_position
|
2020-04-11 00:25:01 +02:00
|
|
|
if (position == self.min_position and velocity < 0): velocity = 0
|
2016-08-24 23:10:58 +02:00
|
|
|
|
2020-04-11 00:25:01 +02:00
|
|
|
# Convert a possible numpy bool to a Python bool.
|
|
|
|
done = bool(
|
|
|
|
position >= self.goal_position and velocity >= self.goal_velocity
|
|
|
|
)
|
2016-08-24 23:10:58 +02:00
|
|
|
|
|
|
|
reward = 0
|
|
|
|
if done:
|
|
|
|
reward = 100.0
|
2020-04-11 00:25:01 +02:00
|
|
|
reward -= math.pow(action[0], 2) * 0.1
|
2016-08-24 23:10:58 +02:00
|
|
|
|
|
|
|
self.state = np.array([position, velocity])
|
|
|
|
return self.state, reward, done, {}
|
|
|
|
|
Cleanup, removal of unmaintained code (#836)
* add dtype to Box
* remove board_game, debugging, safety, parameter_tuning environments
* massive set of breaking changes
- remove python logging module
- _step, _reset, _seed, _close => non underscored method
- remove benchmark and scoring folder
* Improve render("human"), now resizable, closable window.
* get rid of default step and reset in wrappers, so it doesn’t silently fail for people with underscore methods
* CubeCrash unit test environment
* followup fixes
* MemorizeDigits unit test envrionment
* refactored spaces a bit
fixed indentation
disabled test_env_semantics
* fix unit tests
* fixes
* CubeCrash, MemorizeDigits tested
* gym backwards compatibility patch
* gym backwards compatibility, followup fixes
* changelist, add spaces to main namespaces
* undo_logger_setup for backwards compat
* remove configuration.py
2018-01-25 18:20:14 -08:00
|
|
|
def reset(self):
|
2016-08-24 23:10:58 +02:00
|
|
|
self.state = np.array([self.np_random.uniform(low=-0.6, high=-0.4), 0])
|
|
|
|
return np.array(self.state)
|
|
|
|
|
|
|
|
def _height(self, xs):
|
|
|
|
return np.sin(3 * xs)*.45+.55
|
|
|
|
|
Cleanup, removal of unmaintained code (#836)
* add dtype to Box
* remove board_game, debugging, safety, parameter_tuning environments
* massive set of breaking changes
- remove python logging module
- _step, _reset, _seed, _close => non underscored method
- remove benchmark and scoring folder
* Improve render("human"), now resizable, closable window.
* get rid of default step and reset in wrappers, so it doesn’t silently fail for people with underscore methods
* CubeCrash unit test environment
* followup fixes
* MemorizeDigits unit test envrionment
* refactored spaces a bit
fixed indentation
disabled test_env_semantics
* fix unit tests
* fixes
* CubeCrash, MemorizeDigits tested
* gym backwards compatibility patch
* gym backwards compatibility, followup fixes
* changelist, add spaces to main namespaces
* undo_logger_setup for backwards compat
* remove configuration.py
2018-01-25 18:20:14 -08:00
|
|
|
def render(self, mode='human'):
|
2016-08-24 23:10:58 +02:00
|
|
|
screen_width = 600
|
|
|
|
screen_height = 400
|
|
|
|
|
|
|
|
world_width = self.max_position - self.min_position
|
|
|
|
scale = screen_width/world_width
|
2020-04-11 00:25:01 +02:00
|
|
|
carwidth = 40
|
|
|
|
carheight = 20
|
2016-08-24 23:10:58 +02:00
|
|
|
|
|
|
|
if self.viewer is None:
|
|
|
|
from gym.envs.classic_control import rendering
|
|
|
|
self.viewer = rendering.Viewer(screen_width, screen_height)
|
|
|
|
xs = np.linspace(self.min_position, self.max_position, 100)
|
|
|
|
ys = self._height(xs)
|
|
|
|
xys = list(zip((xs-self.min_position)*scale, ys*scale))
|
|
|
|
|
|
|
|
self.track = rendering.make_polyline(xys)
|
|
|
|
self.track.set_linewidth(4)
|
|
|
|
self.viewer.add_geom(self.track)
|
|
|
|
|
|
|
|
clearance = 10
|
|
|
|
|
2020-04-11 00:25:01 +02:00
|
|
|
l, r, t, b = -carwidth / 2, carwidth / 2, carheight, 0
|
|
|
|
car = rendering.FilledPolygon([(l, b), (l, t), (r, t), (r, b)])
|
2016-08-24 23:10:58 +02:00
|
|
|
car.add_attr(rendering.Transform(translation=(0, clearance)))
|
|
|
|
self.cartrans = rendering.Transform()
|
|
|
|
car.add_attr(self.cartrans)
|
|
|
|
self.viewer.add_geom(car)
|
2020-04-11 00:25:01 +02:00
|
|
|
frontwheel = rendering.make_circle(carheight / 2.5)
|
2016-08-24 23:10:58 +02:00
|
|
|
frontwheel.set_color(.5, .5, .5)
|
2020-04-11 00:25:01 +02:00
|
|
|
frontwheel.add_attr(
|
|
|
|
rendering.Transform(translation=(carwidth / 4, clearance))
|
|
|
|
)
|
2016-08-24 23:10:58 +02:00
|
|
|
frontwheel.add_attr(self.cartrans)
|
|
|
|
self.viewer.add_geom(frontwheel)
|
2020-04-11 00:25:01 +02:00
|
|
|
backwheel = rendering.make_circle(carheight / 2.5)
|
|
|
|
backwheel.add_attr(
|
|
|
|
rendering.Transform(translation=(-carwidth / 4, clearance))
|
|
|
|
)
|
2016-08-24 23:10:58 +02:00
|
|
|
backwheel.add_attr(self.cartrans)
|
|
|
|
backwheel.set_color(.5, .5, .5)
|
|
|
|
self.viewer.add_geom(backwheel)
|
|
|
|
flagx = (self.goal_position-self.min_position)*scale
|
|
|
|
flagy1 = self._height(self.goal_position)*scale
|
|
|
|
flagy2 = flagy1 + 50
|
|
|
|
flagpole = rendering.Line((flagx, flagy1), (flagx, flagy2))
|
|
|
|
self.viewer.add_geom(flagpole)
|
2020-04-11 00:25:01 +02:00
|
|
|
flag = rendering.FilledPolygon(
|
|
|
|
[(flagx, flagy2), (flagx, flagy2 - 10), (flagx + 25, flagy2 - 5)]
|
|
|
|
)
|
|
|
|
flag.set_color(.8, .8, 0)
|
2016-08-24 23:10:58 +02:00
|
|
|
self.viewer.add_geom(flag)
|
|
|
|
|
|
|
|
pos = self.state[0]
|
2020-04-11 00:25:01 +02:00
|
|
|
self.cartrans.set_translation(
|
|
|
|
(pos-self.min_position) * scale, self._height(pos) * scale
|
|
|
|
)
|
2016-08-24 23:10:58 +02:00
|
|
|
self.cartrans.set_rotation(math.cos(3 * pos))
|
|
|
|
|
2020-04-11 00:25:01 +02:00
|
|
|
return self.viewer.render(return_rgb_array=mode == 'rgb_array')
|
Cleanup, removal of unmaintained code (#836)
* add dtype to Box
* remove board_game, debugging, safety, parameter_tuning environments
* massive set of breaking changes
- remove python logging module
- _step, _reset, _seed, _close => non underscored method
- remove benchmark and scoring folder
* Improve render("human"), now resizable, closable window.
* get rid of default step and reset in wrappers, so it doesn’t silently fail for people with underscore methods
* CubeCrash unit test environment
* followup fixes
* MemorizeDigits unit test envrionment
* refactored spaces a bit
fixed indentation
disabled test_env_semantics
* fix unit tests
* fixes
* CubeCrash, MemorizeDigits tested
* gym backwards compatibility patch
* gym backwards compatibility, followup fixes
* changelist, add spaces to main namespaces
* undo_logger_setup for backwards compat
* remove configuration.py
2018-01-25 18:20:14 -08:00
|
|
|
|
|
|
|
def close(self):
|
2018-09-14 13:36:57 -07:00
|
|
|
if self.viewer:
|
|
|
|
self.viewer.close()
|
|
|
|
self.viewer = None
|