Skip to content

Commit d166c4f

Browse files
committed
Added OpenAI gym environment for a planar crane with continuous inputs.
1 parent 95df230 commit d166c4f

4 files changed

+473
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#! /usr/bin/env python
2+
3+
###############################################################################
4+
# openAI_planarCrane_episodeDataProcessing.py
5+
#
6+
# script to process the episode data saved in the CRAWLAB planar_crane
7+
# OpenAI gym environment
8+
#
9+
# NOTE: Any plotting is set up for output, not viewing on screen.
10+
# So, it will likely be ugly on screen. The saved PDFs should look
11+
# better.
12+
#
13+
# Created: 07/13/17
14+
# - Joshua Vaughan
15+
16+
# - http://www.ucs.louisiana.edu/~jev9637
17+
#
18+
# Modified:
19+
# *
20+
#
21+
# TODO:
22+
# *
23+
###############################################################################
24+
25+
import numpy as np
26+
import matplotlib.pyplot as plt
27+
28+
FILENAME = 'example_data/EpisodeData_2017-07-13_132633.csv'
29+
CABLE_LENGTH = 2.0
30+
31+
# Files have data saved as:
32+
# Time (s), Angle (rad), Angle (rad/s), Trolley Pos (m), Trolly Vel (m/s), Trolley Accel (m/s^2), Reward
33+
#
34+
# We'll unpack that data inline with opening the data file
35+
t, theta, theta_dot, x, x_dot, x_ddot, reward = np.loadtxt(FILENAME, delimiter=',', unpack=True)
36+
37+
38+
# ---- Plot the payload angle -------------------------------------------------
39+
# Set the plot size - 3x2 aspect ratio is best
40+
fig = plt.figure(figsize=(6,4))
41+
ax = plt.gca()
42+
plt.subplots_adjust(bottom=0.17, left=0.17, top=0.96, right=0.96)
43+
44+
# Change the axis units font
45+
plt.setp(ax.get_ymajorticklabels(),fontsize=18)
46+
plt.setp(ax.get_xmajorticklabels(),fontsize=18)
47+
48+
ax.spines['right'].set_color('none')
49+
ax.spines['top'].set_color('none')
50+
51+
ax.xaxis.set_ticks_position('bottom')
52+
ax.yaxis.set_ticks_position('left')
53+
54+
# Turn on the plot grid and set appropriate linestyle and color
55+
ax.grid(True,linestyle=':', color='0.75')
56+
ax.set_axisbelow(True)
57+
58+
# Define the X and Y axis labels
59+
plt.xlabel('Time (s)', fontsize=22, weight='bold', labelpad=5)
60+
plt.ylabel('Angle (deg)', fontsize=22, weight='bold', labelpad=10)
61+
62+
plt.plot(t, theta*180/np.pi, linewidth=2, linestyle='-', label=r'Data 1')
63+
# plt.plot(t, y2, linewidth=2, linestyle='--', label=r'Data 2')
64+
65+
# uncomment below and set limits if needed
66+
# plt.xlim(0,5)
67+
# plt.ylim(0,10)
68+
69+
# Create the legend, then fix the fontsize
70+
# leg = plt.legend(loc='upper right', ncol = 1, fancybox=True)
71+
# ltext = leg.get_texts()
72+
# plt.setp(ltext,fontsize=18)
73+
74+
# Adjust the page layout filling the page using the new tight_layout command
75+
plt.tight_layout(pad=0.5)
76+
77+
# save the figure as a high-res pdf in the current folder
78+
# plt.savefig('OpenAI_planarCrane_angle.pdf')
79+
80+
81+
# ----- Plot the position of the payload --------------------------------------
82+
# Set the plot size - 3x2 aspect ratio is best
83+
fig = plt.figure(figsize=(6,4))
84+
ax = plt.gca()
85+
plt.subplots_adjust(bottom=0.17, left=0.17, top=0.96, right=0.96)
86+
87+
# Change the axis units font
88+
plt.setp(ax.get_ymajorticklabels(),fontsize=18)
89+
plt.setp(ax.get_xmajorticklabels(),fontsize=18)
90+
91+
ax.spines['right'].set_color('none')
92+
ax.spines['top'].set_color('none')
93+
94+
ax.xaxis.set_ticks_position('bottom')
95+
ax.yaxis.set_ticks_position('left')
96+
97+
# Turn on the plot grid and set appropriate linestyle and color
98+
ax.grid(True,linestyle=':', color='0.75')
99+
ax.set_axisbelow(True)
100+
101+
# Define the X and Y axis labels
102+
plt.xlabel('Time (s)', fontsize=22, weight='bold', labelpad=5)
103+
plt.ylabel('Position (m)', fontsize=22, weight='bold', labelpad=10)
104+
105+
plt.plot(t, x, linewidth=2, linestyle='--', label=r'Trolley')
106+
plt.plot(t, x - CABLE_LENGTH * np.sin(theta), linewidth=2, linestyle='-', label=r'Payload')
107+
108+
# uncomment below and set limits if needed
109+
# plt.xlim(0,5)
110+
# plt.ylim(0,10)
111+
112+
# Create the legend, then fix the fontsize
113+
leg = plt.legend(ncol = 1, fancybox=True) #, loc='upper right')
114+
ltext = leg.get_texts()
115+
plt.setp(ltext,fontsize=18)
116+
117+
# Adjust the page layout filling the page using the new tight_layout command
118+
plt.tight_layout(pad=0.5)
119+
120+
# save the figure as a high-res pdf in the current folder
121+
# plt.savefig('OpenAI_planarCrane_position.pdf')
122+
123+
124+
125+
126+
127+
# ----- Plot the acceleration input -------------------------------------------
128+
# Set the plot size - 3x2 aspect ratio is best
129+
fig = plt.figure(figsize=(6,4))
130+
ax = plt.gca()
131+
plt.subplots_adjust(bottom=0.17, left=0.17, top=0.96, right=0.96)
132+
133+
# Change the axis units font
134+
plt.setp(ax.get_ymajorticklabels(),fontsize=18)
135+
plt.setp(ax.get_xmajorticklabels(),fontsize=18)
136+
137+
ax.spines['right'].set_color('none')
138+
ax.spines['top'].set_color('none')
139+
140+
ax.xaxis.set_ticks_position('bottom')
141+
ax.yaxis.set_ticks_position('left')
142+
143+
# Turn on the plot grid and set appropriate linestyle and color
144+
ax.grid(True,linestyle=':', color='0.75')
145+
ax.set_axisbelow(True)
146+
147+
# Define the X and Y axis labels
148+
plt.xlabel('Time (s)', fontsize=22, weight='bold', labelpad=5)
149+
plt.ylabel('Accel. (m/s$^2$)', fontsize=22, weight='bold', labelpad=10)
150+
151+
plt.plot(t, x_ddot, linewidth=2, linestyle='-', label=r'Accel. Input')
152+
153+
# uncomment below and set limits if needed
154+
# plt.xlim(0,5)
155+
# plt.ylim(0,10)
156+
157+
# Create the legend, then fix the fontsize
158+
# leg = plt.legend(loc='upper right', ncol = 1, fancybox=True)
159+
# ltext = leg.get_texts()
160+
# plt.setp(ltext,fontsize=18)
161+
162+
# Adjust the page layout filling the page using the new tight_layout command
163+
plt.tight_layout(pad=0.5)
164+
165+
# save the figure as a high-res pdf in the current folder
166+
# plt.savefig('OpenAI_planarCrane_Accelcommand.pdf')
167+
168+
# show the figure
169+
plt.show()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#! /usr/bin/env python
2+
3+
###############################################################################
4+
# openAI_variableLengthPendulum.py
5+
#
6+
# script to run the variable lenght pendulum OpenAI environment
7+
#
8+
# NOTE: Any plotting is set up for output, not viewing on screen.
9+
# So, it will likely be ugly on screen. The saved PDFs should look
10+
# better.
11+
#
12+
# Created: 07/07/17
13+
# - Joshua Vaughan
14+
15+
# - http://www.ucs.louisiana.edu/~jev9637
16+
#
17+
# Modified:
18+
# *
19+
#
20+
# TODO:
21+
# *
22+
###############################################################################
23+
24+
import numpy as np
25+
import matplotlib.pyplot as plt
26+
27+
import gym
28+
import time
29+
import planar_crane_continuous
30+
31+
env = gym.make('planar_crane_continuous-v0')
32+
33+
# run 5 episodes of 1000 timesteps, taking random actions at each step
34+
for i_episode in range(5):
35+
observation = env.reset()
36+
for t in range(1000):
37+
env.render()
38+
39+
# just randomly choose an action
40+
action = env.action_space.sample()
41+
observation, reward, done, info = env.step(action)
42+
43+
# Finally, print the updated state of the system
44+
print("\033[2J\033[;H") # Clear the terminal each time
45+
j = 40 # padding
46+
d = '.' # what to fill with
47+
print("Theta (deg).:".ljust(j,d), '{:+8.3f}'.format(observation[0]*180/np.pi))
48+
print("Theta_dot (deg/s):".ljust(j,d), '{:+8.3f}'.format(observation[1]*180/np.pi))
49+
print("x (m):".ljust(j,d), '{:+8.3f}'.format(observation[2]))
50+
print("x_dot (m/s):".ljust(j,d), '{:+8.3f}'.format(observation[3]))
51+
print("x_ddot (m/s^2) Input:".ljust(j,d), '{:+8.3f}'.format(action[0]))
52+
print("Reward:".ljust(j,d), '{:+8.3f}'.format(reward))
53+
54+
# if episode finishes before full time range, notify
55+
if done:
56+
print("\r\nEpisode finished after {} timesteps".format(t+1))
57+
time.sleep(1)
58+
break
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#! /usr/bin/env python
2+
3+
###############################################################################
4+
# openAI_planarCrane_test.py
5+
#
6+
# File to test on the CRAWLAB custom OpenAI planar crane environment
7+
#
8+
# Requires:
9+
# * CRAWLAB planar_crane Open_AI environment folder to be in the same as this file
10+
# * keras, openAI gym, keras-rl packages (all are pip or conda installable)
11+
#
12+
# NOTE: Any plotting is set up for output, not viewing on screen.
13+
# So, it will likely be ugly on screen. The saved PDFs should look
14+
# better.
15+
#
16+
# Created: 07/09/17
17+
# - Joshua Vaughan
18+
19+
# - http://www.ucs.louisiana.edu/~jev9637
20+
#
21+
# Modified:
22+
# *
23+
#
24+
# TODO:
25+
# *
26+
###############################################################################
27+
28+
import numpy as np
29+
import datetime # used to generate unique filenames
30+
31+
import gym
32+
import planar_crane_continuous
33+
34+
from keras.models import Sequential, Model
35+
from keras.layers import Dense, Activation, Flatten, Input, merge
36+
from keras.optimizers import Adam
37+
38+
from rl.agents import DDPGAgent
39+
from rl.memory import SequentialMemory
40+
from rl.random import OrnsteinUhlenbeckProcess
41+
42+
43+
ENV_NAME = 'planar_crane_continuous-v0'
44+
45+
LAYER_SIZE = 2048
46+
NUM_HIDDEN_LAYERS = 3
47+
NUM_STEPS = 50000
48+
TRIAL_ID = datetime.datetime.now().strftime('%Y-%m-%d_%H%M%S')
49+
50+
# TODO: Add file picker GUI - For now, look for files with the format below
51+
# Remove the _actor or _critic from the filename. The load method automatically
52+
# appends these.
53+
FILENAME = 'weights/ddpg_planar_crane_continuous-v0_weights_2048_3_50000_2017-07-13_144811.h5f'
54+
55+
# Get the environment and extract the number of actions.
56+
env = gym.make(ENV_NAME)
57+
nb_actions = env.action_space.shape[0]
58+
59+
# Record episode data?
60+
env.SAVE_DATA = True
61+
62+
63+
64+
# Next, we build a very simple actor model.
65+
actor = Sequential()
66+
67+
# Input Layer
68+
actor.add(Flatten(input_shape=(1,) + env.observation_space.shape))
69+
70+
# Hidden layers
71+
for _ in range(NUM_HIDDEN_LAYERS):
72+
actor.add(Dense(LAYER_SIZE))
73+
actor.add(Activation('relu'))
74+
75+
# Output layer
76+
actor.add(Dense(nb_actions))
77+
actor.add(Activation('linear'))
78+
print(actor.summary())
79+
80+
81+
# critic model
82+
action_input = Input(shape=(nb_actions,), name='action_input')
83+
observation_input = Input(shape=(1,) + env.observation_space.shape, name='observation_input')
84+
flattened_observation = Flatten()(observation_input)
85+
x = merge([action_input, flattened_observation], mode='concat')
86+
87+
# Hidden layers
88+
for _ in range(NUM_HIDDEN_LAYERS):
89+
x = (Dense(LAYER_SIZE))(x)
90+
x = Activation('relu')(x)
91+
92+
# Output Layer
93+
x = Dense(1)(x)
94+
x = Activation('linear')(x)
95+
critic = Model(input=[action_input, observation_input], output=x)
96+
print(critic.summary())
97+
98+
# Finally, we configure and compile our agent. You can use every built-in Keras optimizer and
99+
# even the metrics!
100+
memory = SequentialMemory(limit=2*NUM_STEPS, window_length=1)
101+
random_process = OrnsteinUhlenbeckProcess(size=nb_actions, theta=.15, mu=0., sigma=.3)
102+
agent = DDPGAgent(nb_actions=nb_actions, actor=actor, critic=critic, critic_action_input=action_input,
103+
memory=memory, nb_steps_warmup_critic=100, nb_steps_warmup_actor=100,
104+
random_process=random_process, gamma=.99, target_model_update=1e-3)
105+
agent.compile(Adam(lr=.001, clipnorm=1.), metrics=['mae'])
106+
107+
# Load the model weights - this method will automatically load the weights for
108+
# both the actor and critic
109+
agent.load_weights(FILENAME)
110+
111+
112+
# Finally, evaluate our algorithm for 5 episodes.
113+
agent.test(env, nb_episodes=5, nb_max_episode_steps=500, visualize=True)

0 commit comments

Comments
 (0)