Skip to content

Commit d9472cc

Browse files
committed
Improved sensors:
- cropped image for visual sensor to improv speed - corrected calculation of depth and touch - game engine now has to be reset outside of step function, to improve compatibility with other libraries
1 parent 4c9f226 commit d9472cc

File tree

15 files changed

+305
-427
lines changed

15 files changed

+305
-427
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ and runs experiments very quickly.
1212

1313
# Installation
1414

15+
Before installing, you might have to install libsdl1.2-dev and pygame manually.
16+
17+
Once these dependencies are installed, you can install simple-playgrounds using pip.
1518
A pip package is available and regularly updated:
1619

1720
`pip3 install simple-playgrounds`

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
setup(
88
name='simple_playgrounds',
9-
version='0.9.16',
9+
version='0.9.17',
1010
description='Simulator for AGI and RL',
1111
author='Michael Garcia Ortiz',
1212
author_email='[email protected]',

simple_playgrounds/entities/agents/sensors/visual_sensors/collection/depth_sensor.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ def update_sensor(self, img):
2929

3030
mask = self.polar_view != 0
3131
sensor = np.min(np.where(mask.any(axis=1), mask.argmax(axis=1),
32-
self.polar_view.shape[1] - 1), axis=1)
32+
self.polar_view.shape[1] ), axis=1)
3333

34-
sensor_value = (self.polar_view.shape[1] - sensor)
34+
sensor_value = self._range*(self.polar_view.shape[1] - sensor)/self.polar_view.shape[1]
3535

3636
image = np.asarray(sensor_value)
3737
image = np.expand_dims(image, 0)

simple_playgrounds/entities/agents/sensors/visual_sensors/collection/touch_sensor.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def __init__(self, anchor, invisible_elements=None, normalize=True, **kwargs):
3535
"""
3636

3737
super(TouchSensor, self).__init__(anchor, invisible_elements, normalize=normalize,
38-
min_range=anchor.radius+1, **kwargs)
38+
min_range=anchor.radius, **kwargs)
3939

4040
self._range = self._min_range + self._range
4141

@@ -53,8 +53,7 @@ def update_sensor(self, img):
5353
sensor = np.min(np.where(mask.any(axis=1), mask.argmax(axis=1),
5454
self.polar_view.shape[1] ), axis=1)
5555

56-
sensor_value = (self.polar_view.shape[1] - sensor)
57-
56+
sensor_value = (self._range - self._min_range) * (self.polar_view.shape[1] - sensor )/self.polar_view.shape[1]
5857
image = np.asarray(sensor_value)
5958
image = np.expand_dims(image, 0)
6059

@@ -69,7 +68,7 @@ def update_sensor(self, img):
6968
def apply_normalization(self):
7069
if self.normalize:
7170

72-
self.sensor_value = self.sensor_value /(self._range - self._min_range)/(2*self._scale_ratio)
71+
self.sensor_value = self.sensor_value /(self._range - self._min_range)
7372

7473
@property
7574
def shape(self):

simple_playgrounds/entities/agents/sensors/visual_sensors/visual_sensor.py

+51-4
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,58 @@ def _crop_image(self, img):
9898
# # Position of the sensor
9999
sensor_x, sensor_y = self.anchor.pm_body.position
100100

101-
x_1 = int(max(0, (width - sensor_x) - self._range))
102-
x_2 = int(min(width, (width - sensor_x) + self._range))
101+
sensor_angle = (self.anchor.pm_body.angle + math.pi/2)%(2*math.pi)
103102

104-
y_1 = int(max(0, (height - sensor_y) - self._range))
105-
y_2 = int(min(height, (height - sensor_y) + self._range))
103+
theta_left = (sensor_angle + self._fov / 2.0)%(2*math.pi)
104+
theta_right = (sensor_angle - self._fov / 2.0)%(2*math.pi)
105+
106+
pos_left = ( self._range * math.cos(theta_left), self._range * math.sin(theta_left) )
107+
pos_right = ( self._range * math.cos(theta_right), self._range * math.sin(theta_right) )
108+
109+
pts_extrema = [pos_left, pos_right, (0,0)]
110+
111+
# angle 0
112+
angles = [0, math.pi/2, 2*math.pi/2, 3*math.pi/2]
113+
114+
for angle in angles:
115+
116+
pt = (self._range * math.cos(angle), self._range * math.sin(angle))
117+
118+
if self._fov == 2*math.pi:
119+
pts_extrema.append(pt)
120+
121+
elif angle == 0:
122+
123+
if theta_right > theta_left:
124+
pts_extrema.append(pt)
125+
126+
else:
127+
128+
if theta_left >= angle:
129+
130+
if theta_right <= angle or theta_left <= theta_right:
131+
pts_extrema.append(pt)
132+
133+
if theta_left < angle:
134+
135+
if theta_left <= theta_right <= angle:
136+
pts_extrema.append(pt)
137+
138+
# if theta_left <= theta_right <= 2*math.pi:
139+
# theta_right = theta_right - 2*math.pi
140+
141+
x_min = min([x for x,y in pts_extrema])
142+
x_max = max([x for x,y in pts_extrema])
143+
y_min = min([y for x,y in pts_extrema])
144+
y_max = max([y for x,y in pts_extrema])
145+
146+
# print(x_min, x_max, y_min, y_max)
147+
148+
y_1 = int(max(0, (height - sensor_y) + x_min))
149+
y_2 = int(min(height, (height - sensor_y) + x_max))
150+
151+
x_2 = width - int(max(0, sensor_x + y_min))
152+
x_1 = width - int(min(width, sensor_x + y_max))
106153

107154
self._center = (((height - sensor_y) - y_1), ((width - sensor_x) - x_1))
108155

simple_playgrounds/game_engine.py

+76-39
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ def __init__(self, playground, time_limit=None, replay=False, screen=False):
7070
self.surface_sensors = pygame.Surface((self.playground.width, self.playground.length))
7171

7272
self.game_on = True
73-
self.episode_elapsed_time = 0
74-
self.total_elapsed_time = 0
73+
self.elapsed_time = 0
7574

7675
def multiple_steps(self, actions, n_steps=1):
7776
"""
@@ -109,16 +108,32 @@ def multiple_steps(self, actions, n_steps=1):
109108
for agent_name in actions:
110109
cumulated_rewards[agent_name] = 0
111110

112-
for _ in range(n_steps-1):
113-
self.step(hold_actions)
111+
step = 0
112+
continue_actions = True
113+
114+
while step < n_steps and continue_actions:
115+
116+
if step < n_steps-1:
117+
action = hold_actions
118+
else:
119+
action = last_action
120+
121+
self._engine_step(action)
114122

115123
for agent in self.agents:
116124
cumulated_rewards[agent.name] += agent.reward
117125

118-
self.step(last_action)
126+
step += 1
127+
128+
reset, terminate = self._handle_terminations()
129+
130+
if reset or terminate:
131+
continue_actions = False
119132

120133
for agent in self.agents:
121-
agent.reward += cumulated_rewards[agent.name]
134+
agent.reward = cumulated_rewards[agent.name]
135+
136+
return reset, terminate
122137

123138
def step(self, actions):
124139
"""
@@ -129,37 +144,67 @@ def step(self, actions):
129144
130145
"""
131146

132-
for agent in self.agents:
133-
agent.apply_actions_to_body_parts(actions[agent.name])
134-
135-
self.playground.update(SIMULATION_STEPS)
147+
self._engine_step(actions)
136148

137149
# Termination
138-
game_reset, game_terminates = self.game_terminated()
150+
reset, terminate = self._handle_terminations()
151+
152+
return reset, terminate
153+
154+
def _handle_terminations(self):
155+
156+
reset = False
157+
terminate = False
158+
159+
playground_terminated = self.playground.done
160+
reached_time_limit = self._check_time()
161+
keyboard_reset, keyboard_quit = self._check_keyboard()
162+
163+
if keyboard_quit:
164+
terminate = True
165+
166+
elif keyboard_reset:
167+
reset = True
168+
169+
elif playground_terminated:
170+
171+
if self.replay_until_time_limit:
172+
reset = True
173+
174+
else:
175+
terminate = True
139176

140-
if game_reset:
141-
self.reset()
177+
elif reached_time_limit:
142178

143-
if game_terminates:
144-
self.game_on = False
145-
self.terminate()
179+
terminate = True
146180

147-
self.total_elapsed_time += 1
148-
self.episode_elapsed_time += 1
181+
return reset, terminate
182+
183+
def _engine_step(self, actions):
184+
185+
for agent in self.agents:
186+
agent.apply_actions_to_body_parts(actions[agent.name])
187+
188+
self.playground.update(SIMULATION_STEPS)
189+
190+
self.elapsed_time += 1
149191

150192
def reset(self):
151193
"""
152194
Resets the game to its initial state.
153195
154196
"""
155-
self.episode_elapsed_time = 0
156-
157197
self.playground.reset()
158-
159198
self.game_on = True
160199

200+
def _check_time(self):
201+
if self.elapsed_time >= self.time_limit:
202+
return True
203+
else:
204+
return False
205+
161206

162-
def game_terminated(self):
207+
def _check_keyboard(self):
163208
"""
164209
Tests whether the game came to an end, because of time limit or termination of playground.
165210
@@ -170,14 +215,6 @@ def game_terminated(self):
170215
reset_game = False
171216
terminate_game = False
172217

173-
if self.total_elapsed_time == self.time_limit or self.playground.done:
174-
175-
if self.replay_until_time_limit and self.total_elapsed_time < self.time_limit:
176-
reset_game = True
177-
else:
178-
terminate_game = True
179-
180-
181218
if self.screen is not None:
182219

183220
pygame.event.get()
@@ -198,10 +235,7 @@ def game_terminated(self):
198235
elif pygame.key.get_pressed()[K_r] and self.reset_key_ready is True:
199236
self.reset_key_ready = False
200237

201-
if self.replay_until_time_limit:
202-
reset_game = True
203-
else:
204-
terminate_game = True
238+
reset_game = True
205239

206240
return reset_game, terminate_game
207241

@@ -349,7 +383,7 @@ def run(self, steps=None, with_screen = False, print_rewards = False):
349383
for agent in self.agents:
350384
actions[agent.name] = agent.controller.generate_actions()
351385

352-
self.step(actions)
386+
reset, terminate = self.step(actions)
353387
self.update_observations()
354388

355389
if with_screen and self.game_on:
@@ -366,12 +400,15 @@ def run(self, steps=None, with_screen = False, print_rewards = False):
366400
if steps ==0:
367401
continue_for_n_steps = False
368402

403+
if reset:
404+
self.reset()
405+
406+
if terminate:
407+
continue_for_n_steps = False
408+
self.terminate()
369409

370-
# for agent in self.agents:
371-
# print(agent.position, agent.base_platform.pm_body.velocity, agent.base_platform.pm_body.kinetic_energy)
372-
# assert 0 < agent.position[0] < self.playground.size[0]
373-
# assert 0 < agent.position[1] < self.playground.size[1]
374410

375411
def terminate(self):
376412

413+
self.game_on = False
377414
pygame.quit()

simple_playgrounds/playgrounds/collection/rl/basic.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Endgoal9Rooms(ConnectedRooms2D):
3232

3333
def __init__(self):
3434

35-
super().__init__(size = (600, 600), n_rooms=(3,3),wall_type='colorful')
35+
super().__init__(size = (600, 600), n_rooms=(3,3), wall_type='colorful')
3636

3737
# Starting area of the agent
3838
area_start = PositionAreaSampler(center=(300, 300), area_shape='rectangle', width_length=(600, 600))
@@ -52,7 +52,7 @@ def __init__(self):
5252
super().__init__(size = (200, 100), n_rooms=2, wall_type='colorful')
5353

5454
# Starting area of the agent
55-
area_start = PositionAreaSampler(center=(100, 50), area_shape='rectangle', width_length=(200, 100))
55+
area_start = PositionAreaSampler(center=(50, 50), area_shape='rectangle', width_length=(100, 100))
5656
self.agent_starting_area = area_start
5757

5858
# invisible endzone at one corner of the game

simple_playgrounds/playgrounds/configs/playground_default.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ colorful :
2222
n_colors: 20
2323
delta_uniform: 10
2424
size_tiles : 10
25-
color_min : [ 0, 0, 0 ]
26-
color_max: [150, 150, 150 ]
25+
color_min : [ 100, 100, 100 ]
26+
color_max: [250, 250, 250 ]
2727

2828
wall:
2929
entity_type: basic

simple_playgrounds/playgrounds/playground.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,11 @@ def reset(self):
145145
entity.reset()
146146

147147
# reset agents
148-
#self._remove_agents()
149-
for agent in self.agents:
148+
# self._remove_agents()
149+
for agent in self.agents.copy():
150150
agent.reset()
151+
self.remove_agent(agent)
152+
self.add_agent(agent)
151153
#self.add_agent(agent)
152154

153155
self.done = False
@@ -368,7 +370,7 @@ def remove_scene_element(self, scene_element):
368370
self._disappeared_scene_elements.append(scene_element)
369371

370372
for elem in self.scene_elements:
371-
if elem.entity_type is SceneElementTypes.DISPENSER and scene_element in elem.produced_entities:
373+
if elem.entity_type == 'dispenser' and scene_element in elem.produced_entities:
372374
elem.produced_entities.remove(scene_element)
373375

374376
for field in self.fields:

tests/test_agents.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def test_base_agent_on_all_test_playgrounds():
3030

3131
print('Starting testing of ', pg_class.__name__)
3232

33-
engine = Engine(pg, time_limit=1000, replay=False)
33+
engine = Engine(pg, time_limit=1000, replay=True)
3434
engine.run()
3535

3636
assert 0 < agent.position[0] < pg.size[0]

0 commit comments

Comments
 (0)