From e1617c34a67bb904f5eee5ef9777021b31a49619 Mon Sep 17 00:00:00 2001 From: Onur Date: Thu, 27 Jan 2022 15:38:37 +0100 Subject: [PATCH 001/104] started working on contextual bp --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b5aa424..6122e90 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setup( 'gym', 'PyQt5', 'matplotlib', - 'mp_env_api @ git+https://github.com/ALRhub/motion_primitive_env_api.git', + #'mp_env_api @ git+https://github.com/ALRhub/motion_primitive_env_api.git', # 'mp_env_api @ git+ssh://git@github.com/ALRhub/motion_primitive_env_api.git', 'mujoco-py<2.1,>=2.0', 'dm_control', From be5b287ae19d8803c2e6c9bb7adc67ad095de90d Mon Sep 17 00:00:00 2001 From: Onur Date: Fri, 28 Jan 2022 19:24:34 +0100 Subject: [PATCH 002/104] randomized cup --- alr_envs/alr/__init__.py | 24 +++++++--- alr_envs/alr/mujoco/beerpong/beerpong.py | 56 ++++++++++------------ alr_envs/alr/mujoco/beerpong/mp_wrapper.py | 4 +- 3 files changed, 44 insertions(+), 40 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 90ec78c..67031f1 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -213,16 +213,26 @@ register(id='TableTennis4DCtxt-v0', kwargs={'ctxt_dim': 4}) ## BeerPong -difficulties = ["simple", "intermediate", "hard", "hardest"] - -for v, difficulty in enumerate(difficulties): - register( - id='ALRBeerPong-v{}'.format(v), +# fixed goal cup position +register( + id='ALRBeerPong-v0', entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', max_episode_steps=600, kwargs={ - "difficulty": difficulty, - "reward_type": "staged", + "rndm_goal": False, + "cup_goal_pos": [-0.3, -1.2] + } + ) + + +# random goal cup position +register( + id='ALRBeerPong-v1', + entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', + max_episode_steps=600, + kwargs={ + "rndm_goal": True, + "cup_goal_pos": [-0.3, -1.2] } ) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 755710a..2fb435f 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -4,11 +4,16 @@ import os import numpy as np from gym import utils from gym.envs.mujoco import MujocoEnv +from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward + + +CUP_POS_MIN = np.array([-0.32, -2.2]) +CUP_POS_MAX = np.array([0.32, -1.2]) class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): - def __init__(self, frame_skip=1, apply_gravity_comp=True, reward_type: str = "staged", noisy=False, - context: np.ndarray = None, difficulty='simple'): + def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, + rndm_goal=False, cup_goal_pos=[-0.3, -1.2]): self._steps = 0 self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", @@ -17,7 +22,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.j_min = np.array([-2.6, -1.985, -2.8, -0.9, -4.55, -1.5707, -2.7]) self.j_max = np.array([2.6, 1.985, 2.8, 3.14159, 1.25, 1.5707, 2.7]) - self.context = context + self.rndm_goal = rndm_goal self.apply_gravity_comp = apply_gravity_comp self.add_noise = noisy @@ -38,23 +43,8 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): else: self.noise_std = 0 - if difficulty == 'simple': - self.cup_goal_pos = np.array([0, -1.7, 0.840]) - elif difficulty == 'intermediate': - self.cup_goal_pos = np.array([0.3, -1.5, 0.840]) - elif difficulty == 'hard': - self.cup_goal_pos = np.array([-0.3, -2.2, 0.840]) - elif difficulty == 'hardest': - self.cup_goal_pos = np.array([-0.3, -1.2, 0.840]) - - if reward_type == "no_context": - from alr_envs.alr.mujoco.beerpong.beerpong_reward import BeerPongReward - reward_function = BeerPongReward - elif reward_type == "staged": - from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward - reward_function = BeerPongReward - else: - raise ValueError("Unknown reward type: {}".format(reward_type)) + self.cup_goal_pos = np.array(cup_goal_pos.append(0.840)) + reward_function = BeerPongReward self.reward_function = reward_function() MujocoEnv.__init__(self, self.xml_path, frame_skip) @@ -94,6 +84,12 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.sim.model.body_pos[self.cup_table_id] = self.cup_goal_pos start_pos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() self.set_state(start_pos, init_vel) + if self.rndm_goal: + xy = np.random.uniform(CUP_POS_MIN, CUP_POS_MAX) + xyz = np.zeros(3) + xyz[:2] = xy + xyz[-1] = 0.840 + self.sim.model.body_pos[self.cup_table_id] = xyz return self._get_obs() def step(self, a): @@ -153,13 +149,12 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def check_traj_in_joint_limits(self): return any(self.current_pos > self.j_max) or any(self.current_pos < self.j_min) - # TODO: extend observation space def _get_obs(self): theta = self.sim.data.qpos.flat[:7] return np.concatenate([ np.cos(theta), np.sin(theta), - # self.get_body_com("target"), # only return target to make problem harder + self.sim.model.body_pos[self.cup_table_id][:2].copy(), [self._steps], ]) @@ -169,25 +164,26 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): return np.hstack([ [False] * 7, # cos [False] * 7, # sin - # [True] * 2, # x-y coordinates of target distance + [True] * 2, # xy position of cup [False] # env steps ]) if __name__ == "__main__": - env = ALRBeerBongEnv(reward_type="staged", difficulty='hardest') - - # env.configure(ctxt) + env = ALRBeerBongEnv(rndm_goal=True) + import time env.reset() env.render("human") - for i in range(800): - ac = 10 * env.action_space.sample()[0:7] + for i in range(1500): + # ac = 10 * env.action_space.sample()[0:7] + ac = np.zeros(7) obs, rew, d, info = env.step(ac) env.render("human") print(rew) if d: - break - + print('RESETTING') + env.reset() + time.sleep(1) env.close() diff --git a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py index 87c6b7e..11af9a5 100644 --- a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py @@ -9,11 +9,10 @@ class MPWrapper(MPEnvWrapper): @property def active_obs(self): - # TODO: @Max Filter observations correctly return np.hstack([ [False] * 7, # cos [False] * 7, # sin - # [True] * 2, # x-y coordinates of target distance + [True] * 2, # xy position of cup [False] # env steps ]) @@ -31,7 +30,6 @@ class MPWrapper(MPEnvWrapper): @property def goal_pos(self): - # TODO: @Max I think the default value of returning to the start is reasonable here raise ValueError("Goal position is not available and has to be learnt based on the environment.") @property From bcebf1077c2aa82e850a96185f63c8e0fbe03806 Mon Sep 17 00:00:00 2001 From: Onur Date: Mon, 31 Jan 2022 17:03:49 +0100 Subject: [PATCH 003/104] contextual bp working --- alr_envs/alr/__init__.py | 2 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 67031f1..0181f62 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -375,7 +375,7 @@ for _v in _versions: ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) ## Beerpong -_versions = ["v0", "v1", "v2", "v3"] +_versions = ["v0", "v1"] for _v in _versions: _env_id = f'BeerpongProMP-{_v}' register( diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 2fb435f..9092ef1 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -13,9 +13,15 @@ CUP_POS_MAX = np.array([0.32, -1.2]) class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, - rndm_goal=False, cup_goal_pos=[-0.3, -1.2]): - self._steps = 0 + rndm_goal=False, cup_goal_pos=None): + if cup_goal_pos is None: + cup_goal_pos = [-0.3, -1.2, 0.840] + elif len(cup_goal_pos)==2: + cup_goal_pos = np.array(cup_goal_pos) + cup_goal_pos = np.insert(cup_goal_pos, 2, 0.80) + self.cup_goal_pos = np.array(cup_goal_pos) + self._steps = 0 self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", "beerpong_wo_cup" + ".xml") @@ -43,7 +49,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): else: self.noise_std = 0 - self.cup_goal_pos = np.array(cup_goal_pos.append(0.840)) + reward_function = BeerPongReward self.reward_function = reward_function() From 66be0b1e02a8741b945b5eba488ed50e03d4eb8d Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 1 Feb 2022 16:02:33 +0100 Subject: [PATCH 004/104] adjusted reward function --- alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index e94b470..40b181b 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -97,14 +97,14 @@ class BeerPongReward: # encourage bounce before falling into cup if not ball_in_cup: if not self.ball_table_contact: - reward = 0.2 * (1 - np.tanh(min_dist ** 2)) + 0.1 * (1 - np.tanh(final_dist ** 2)) + reward = 0.2 * (1 - np.tanh(0.5*min_dist)) + 0.1 * (1 - np.tanh(0.5*final_dist)) else: - reward = (1 - np.tanh(min_dist ** 2)) + 0.5 * (1 - np.tanh(final_dist ** 2)) + reward = (1 - np.tanh(0.5*min_dist)) + 0.5 * (1 - np.tanh(0.5*final_dist)) else: if not self.ball_table_contact: - reward = 2 * (1 - np.tanh(final_dist ** 2)) + 1 * (1 - np.tanh(min_dist ** 2)) + 1 + reward = 2 * (1 - np.tanh(0.5*final_dist)) + 1 * (1 - np.tanh(0.5*min_dist)) + 1 else: - reward = 2 * (1 - np.tanh(final_dist ** 2)) + 1 * (1 - np.tanh(min_dist ** 2)) + 3 + reward = 2 * (1 - np.tanh(0.5*final_dist)) + 1 * (1 - np.tanh(0.5*min_dist)) + 3 # reward = - 1 * cost - self.collision_penalty * int(self._is_collided) success = ball_in_cup From 2a27f59e506893bd8ac657fbbfba3bb9f3505d41 Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 8 Feb 2022 09:50:01 +0100 Subject: [PATCH 005/104] fix tt issues -> context + traj.length --- alr_envs/alr/__init__.py | 39 ++++++++++++++++++- .../beerpong/assets/beerpong_wo_cup.xml | 11 +++--- alr_envs/alr/mujoco/beerpong/beerpong.py | 7 +++- .../alr/mujoco/table_tennis/mp_wrapper.py | 6 +-- alr_envs/alr/mujoco/table_tennis/tt_gym.py | 8 ++-- setup.py | 2 +- 6 files changed, 58 insertions(+), 15 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 0181f62..026f1a7 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -236,6 +236,17 @@ register( } ) +# Beerpong devel big table +register( + id='ALRBeerPong-v3', + entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', + max_episode_steps=600, + kwargs={ + "rndm_goal": True, + "cup_goal_pos": [-0.3, -1.2] + } + ) + # Motion Primitive Environments ## Simple Reacher @@ -402,6 +413,32 @@ for _v in _versions: ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) +## Beerpong- Big table devel + +register( + id='BeerpongProMP-v3', + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": f"alr_envs:ALRBeerPong-v3", + "wrappers": [mujoco.beerpong.MPWrapper], + "mp_kwargs": { + "num_dof": 7, + "num_basis": 5, + "duration": 1, + "post_traj_time": 2, + "policy_type": "motor", + "weights_scale": 1, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.array([ 1.5, 5, 2.55, 3, 2., 2, 1.25]), + "d_gains": np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) + } + } + } + ) +ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('BeerpongProMP-v3') + ## Table Tennis ctxt_dim = [2, 4] for _v, cd in enumerate(ctxt_dim): @@ -416,7 +453,7 @@ for _v, cd in enumerate(ctxt_dim): "num_dof": 7, "num_basis": 2, "duration": 1.25, - "post_traj_time": 4.5, + "post_traj_time": 1.5, "policy_type": "motor", "weights_scale": 1.0, "zero_start": True, diff --git a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml index e96d2bc..436b36c 100644 --- a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml +++ b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml @@ -132,18 +132,19 @@ - - + - - - + + diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 9092ef1..99d1a23 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -7,8 +7,11 @@ from gym.envs.mujoco import MujocoEnv from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward -CUP_POS_MIN = np.array([-0.32, -2.2]) -CUP_POS_MAX = np.array([0.32, -1.2]) +# CUP_POS_MIN = np.array([-0.32, -2.2]) +# CUP_POS_MAX = np.array([0.32, -1.2]) + +CUP_POS_MIN = np.array([-1.42, -4.05]) +CUP_POS_MAX = np.array([1.42, -1.25]) class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): diff --git a/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py b/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py index 86d5a00..473583f 100644 --- a/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py +++ b/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py @@ -11,9 +11,9 @@ class MPWrapper(MPEnvWrapper): def active_obs(self): # TODO: @Max Filter observations correctly return np.hstack([ - [True] * 7, # Joint Pos - [True] * 3, # Ball pos - [True] * 3 # goal pos + [False] * 7, # Joint Pos + [True] * 2, # Ball pos + [True] * 2 # goal pos ]) @property diff --git a/alr_envs/alr/mujoco/table_tennis/tt_gym.py b/alr_envs/alr/mujoco/table_tennis/tt_gym.py index d1c2dc3..e88bbc5 100644 --- a/alr_envs/alr/mujoco/table_tennis/tt_gym.py +++ b/alr_envs/alr/mujoco/table_tennis/tt_gym.py @@ -10,7 +10,8 @@ from alr_envs.alr.mujoco.table_tennis.tt_reward import TT_Reward #TODO: Check for simulation stability. Make sure the code runs even for sim crash -MAX_EPISODE_STEPS = 1750 +# MAX_EPISODE_STEPS = 1750 +MAX_EPISODE_STEPS = 1375 BALL_NAME_CONTACT = "target_ball_contact" BALL_NAME = "target_ball" TABLE_NAME = 'table_tennis_table' @@ -76,10 +77,11 @@ class TTEnvGym(MujocoEnv, utils.EzPickle): self._ids_set = True def _get_obs(self): - ball_pos = self.sim.data.body_xpos[self.ball_id] + ball_pos = self.sim.data.body_xpos[self.ball_id][:2].copy() + goal_pos = self.goal[:2].copy() obs = np.concatenate([self.sim.data.qpos[:7].copy(), # 7 joint positions ball_pos, - self.goal.copy()]) + goal_pos]) return obs def sample_context(self): diff --git a/setup.py b/setup.py index 6122e90..796c569 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup( install_requires=[ 'gym', 'PyQt5', - 'matplotlib', + #'matplotlib', #'mp_env_api @ git+https://github.com/ALRhub/motion_primitive_env_api.git', # 'mp_env_api @ git+ssh://git@github.com/ALRhub/motion_primitive_env_api.git', 'mujoco-py<2.1,>=2.0', From 209eac352c724f0181705b0cd333f881ee80f4be Mon Sep 17 00:00:00 2001 From: Onur Date: Thu, 10 Feb 2022 19:22:34 +0100 Subject: [PATCH 006/104] big table xml --- .../beerpong/assets/beerpong_wo_cup.xml | 13 +- .../assets/beerpong_wo_cup_big_table.xml | 188 ++++++++++++++++++ 2 files changed, 194 insertions(+), 7 deletions(-) create mode 100644 alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml diff --git a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml index 436b36c..d89e03c 100644 --- a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml +++ b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml @@ -132,19 +132,18 @@ - - + - - - - + @@ -185,4 +184,4 @@ - + \ No newline at end of file diff --git a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml new file mode 100644 index 0000000..436b36c --- /dev/null +++ b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml @@ -0,0 +1,188 @@ + + + From 855f0f1c7bbc869cb0a6d6625ac8516cdf5ed12e Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 5 Apr 2022 10:47:01 +0200 Subject: [PATCH 007/104] fix tt issues -> context + traj.length --- alr_envs/alr/__init__.py | 88 +++++++--------------- alr_envs/alr/mujoco/table_tennis/tt_gym.py | 3 +- 2 files changed, 28 insertions(+), 63 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 026f1a7..917e102 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -236,16 +236,6 @@ register( } ) -# Beerpong devel big table -register( - id='ALRBeerPong-v3', - entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', - max_episode_steps=600, - kwargs={ - "rndm_goal": True, - "cup_goal_pos": [-0.3, -1.2] - } - ) # Motion Primitive Environments @@ -413,32 +403,6 @@ for _v in _versions: ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) -## Beerpong- Big table devel - -register( - id='BeerpongProMP-v3', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": f"alr_envs:ALRBeerPong-v3", - "wrappers": [mujoco.beerpong.MPWrapper], - "mp_kwargs": { - "num_dof": 7, - "num_basis": 5, - "duration": 1, - "post_traj_time": 2, - "policy_type": "motor", - "weights_scale": 1, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.array([ 1.5, 5, 2.55, 3, 2., 2, 1.25]), - "d_gains": np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) - } - } - } - ) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('BeerpongProMP-v3') - ## Table Tennis ctxt_dim = [2, 4] for _v, cd in enumerate(ctxt_dim): @@ -453,7 +417,7 @@ for _v, cd in enumerate(ctxt_dim): "num_dof": 7, "num_basis": 2, "duration": 1.25, - "post_traj_time": 1.5, + "post_traj_time": 4.5, "policy_type": "motor", "weights_scale": 1.0, "zero_start": True, @@ -467,28 +431,28 @@ for _v, cd in enumerate(ctxt_dim): ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) -register( - id='TableTennisProMP-v2', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": "alr_envs:TableTennis2DCtxt-v1", - "wrappers": [mujoco.table_tennis.MPWrapper], - "mp_kwargs": { - "num_dof": 7, - "num_basis": 2, - "duration": 1., - "post_traj_time": 2.5, - "policy_type": "motor", - "weights_scale": 1, - "off": -0.05, - "bandwidth_factor": 3.5, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": 0.5*np.array([1.0, 4.0, 2.0, 4.0, 1.0, 4.0, 1.0]), - "d_gains": 0.5*np.array([0.1, 0.4, 0.2, 0.4, 0.1, 0.4, 0.1]) - } - } - } -) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("TableTennisProMP-v2") +# register( +# id='TableTennisProMP-v2', +# entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', +# kwargs={ +# "name": "alr_envs:TableTennis2DCtxt-v1", +# "wrappers": [mujoco.table_tennis.MPWrapper], +# "mp_kwargs": { +# "num_dof": 7, +# "num_basis": 2, +# "duration": 1.25, +# "post_traj_time": 4.5, +# #"width": 0.01, +# #"off": 0.01, +# "policy_type": "motor", +# "weights_scale": 1.0, +# "zero_start": True, +# "zero_goal": False, +# "policy_kwargs": { +# "p_gains": 0.5*np.array([1.0, 4.0, 2.0, 4.0, 1.0, 4.0, 1.0]), +# "d_gains": 0.5*np.array([0.1, 0.4, 0.2, 0.4, 0.1, 0.4, 0.1]) +# } +# } +# } +# ) +# ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("TableTennisProMP-v2") diff --git a/alr_envs/alr/mujoco/table_tennis/tt_gym.py b/alr_envs/alr/mujoco/table_tennis/tt_gym.py index e88bbc5..c93cd26 100644 --- a/alr_envs/alr/mujoco/table_tennis/tt_gym.py +++ b/alr_envs/alr/mujoco/table_tennis/tt_gym.py @@ -11,7 +11,8 @@ from alr_envs.alr.mujoco.table_tennis.tt_reward import TT_Reward #TODO: Check for simulation stability. Make sure the code runs even for sim crash # MAX_EPISODE_STEPS = 1750 -MAX_EPISODE_STEPS = 1375 +# MAX_EPISODE_STEPS = 1375 +MAX_EPISODE_STEPS = 2875 BALL_NAME_CONTACT = "target_ball_contact" BALL_NAME = "target_ball" TABLE_NAME = 'table_tennis_table' From 8ef00f73432d64ca600263b5ad2840ff454433d6 Mon Sep 17 00:00:00 2001 From: Onur Date: Thu, 7 Apr 2022 10:20:10 +0200 Subject: [PATCH 008/104] shorter TT simulation time --- alr_envs/alr/__init__.py | 2 +- alr_envs/alr/mujoco/table_tennis/tt_gym.py | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 917e102..931e3bb 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -417,7 +417,7 @@ for _v, cd in enumerate(ctxt_dim): "num_dof": 7, "num_basis": 2, "duration": 1.25, - "post_traj_time": 4.5, + "post_traj_time": 1.5, "policy_type": "motor", "weights_scale": 1.0, "zero_start": True, diff --git a/alr_envs/alr/mujoco/table_tennis/tt_gym.py b/alr_envs/alr/mujoco/table_tennis/tt_gym.py index c93cd26..7079a1b 100644 --- a/alr_envs/alr/mujoco/table_tennis/tt_gym.py +++ b/alr_envs/alr/mujoco/table_tennis/tt_gym.py @@ -10,9 +10,7 @@ from alr_envs.alr.mujoco.table_tennis.tt_reward import TT_Reward #TODO: Check for simulation stability. Make sure the code runs even for sim crash -# MAX_EPISODE_STEPS = 1750 -# MAX_EPISODE_STEPS = 1375 -MAX_EPISODE_STEPS = 2875 +MAX_EPISODE_STEPS = 1375 # (1.25 + 1.5)/0.002 BALL_NAME_CONTACT = "target_ball_contact" BALL_NAME = "target_ball" TABLE_NAME = 'table_tennis_table' @@ -58,6 +56,7 @@ class TTEnvGym(MujocoEnv, utils.EzPickle): self.hit_ball = False self.ball_contact_after_hit = False self._ids_set = False + self.n_step = 0 super(TTEnvGym, self).__init__(model_path=model_path, frame_skip=1) self.ball_id = self.sim.model._body_name2id[BALL_NAME] # find the proper -> not protected func. self.ball_contact_id = self.sim.model._geom_name2id[BALL_NAME_CONTACT] @@ -67,6 +66,7 @@ class TTEnvGym(MujocoEnv, utils.EzPickle): self.paddle_contact_id_2 = self.sim.model._geom_name2id[PADDLE_CONTACT_2_NAME] # check if we need both or only this self.racket_id = self.sim.model._geom_name2id[RACKET_NAME] + def _set_ids(self): self.ball_id = self.sim.model._body_name2id[BALL_NAME] # find the proper -> not protected func. self.table_contact_id = self.sim.model._geom_name2id[TABLE_NAME] @@ -119,6 +119,7 @@ class TTEnvGym(MujocoEnv, utils.EzPickle): self.sim.forward() self.reward_func.reset(self.goal) # reset the reward function + self.n_step = 0 return self._get_obs() def _contact_checker(self, id_1, id_2): @@ -166,6 +167,8 @@ class TTEnvGym(MujocoEnv, utils.EzPickle): info = {"hit_ball": self.hit_ball, "q_pos": np.copy(self.sim.data.qpos[:7]), "ball_pos": np.copy(self.sim.data.qpos[7:])} + self.n_step += 1 + print(self.n_step) return ob, reward, done, info # might add some information here .... def set_context(self, context): From 33c79f31d2262afbce8328111e557eebe5b156ff Mon Sep 17 00:00:00 2001 From: Onur Date: Thu, 7 Apr 2022 10:24:47 +0200 Subject: [PATCH 009/104] remove unnecessary print --- alr_envs/alr/mujoco/table_tennis/tt_gym.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/alr_envs/alr/mujoco/table_tennis/tt_gym.py b/alr_envs/alr/mujoco/table_tennis/tt_gym.py index 7079a1b..33db936 100644 --- a/alr_envs/alr/mujoco/table_tennis/tt_gym.py +++ b/alr_envs/alr/mujoco/table_tennis/tt_gym.py @@ -10,7 +10,7 @@ from alr_envs.alr.mujoco.table_tennis.tt_reward import TT_Reward #TODO: Check for simulation stability. Make sure the code runs even for sim crash -MAX_EPISODE_STEPS = 1375 # (1.25 + 1.5)/0.002 +MAX_EPISODE_STEPS = 1375 # (1.25 + 1.5) /0.002 BALL_NAME_CONTACT = "target_ball_contact" BALL_NAME = "target_ball" TABLE_NAME = 'table_tennis_table' @@ -56,7 +56,6 @@ class TTEnvGym(MujocoEnv, utils.EzPickle): self.hit_ball = False self.ball_contact_after_hit = False self._ids_set = False - self.n_step = 0 super(TTEnvGym, self).__init__(model_path=model_path, frame_skip=1) self.ball_id = self.sim.model._body_name2id[BALL_NAME] # find the proper -> not protected func. self.ball_contact_id = self.sim.model._geom_name2id[BALL_NAME_CONTACT] @@ -168,7 +167,6 @@ class TTEnvGym(MujocoEnv, utils.EzPickle): "q_pos": np.copy(self.sim.data.qpos[:7]), "ball_pos": np.copy(self.sim.data.qpos[7:])} self.n_step += 1 - print(self.n_step) return ob, reward, done, info # might add some information here .... def set_context(self, context): From 04b6b314cf6d8930daf2d0cff247e9cd4e4e0716 Mon Sep 17 00:00:00 2001 From: ottofabian Date: Thu, 7 Apr 2022 14:57:53 +0200 Subject: [PATCH 010/104] Update beerpong_wo_cup.xml --- alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml index d89e03c..e96d2bc 100644 --- a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml +++ b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml @@ -132,7 +132,7 @@ - + - \ No newline at end of file + From eb7dd3a18fc98f8007cfb22bc07f7ace0193031f Mon Sep 17 00:00:00 2001 From: Onur Date: Thu, 7 Apr 2022 18:49:44 +0200 Subject: [PATCH 011/104] fixing beerpong rewards --- alr_envs/alr/__init__.py | 28 +---- alr_envs/alr/mujoco/beerpong/beerpong.py | 18 +-- .../mujoco/beerpong/beerpong_reward_staged.py | 104 +++++++++++++++--- 3 files changed, 94 insertions(+), 56 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 931e3bb..7e7bca1 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -429,30 +429,4 @@ for _v, cd in enumerate(ctxt_dim): } } ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -# register( -# id='TableTennisProMP-v2', -# entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', -# kwargs={ -# "name": "alr_envs:TableTennis2DCtxt-v1", -# "wrappers": [mujoco.table_tennis.MPWrapper], -# "mp_kwargs": { -# "num_dof": 7, -# "num_basis": 2, -# "duration": 1.25, -# "post_traj_time": 4.5, -# #"width": 0.01, -# #"off": 0.01, -# "policy_type": "motor", -# "weights_scale": 1.0, -# "zero_start": True, -# "zero_goal": False, -# "policy_kwargs": { -# "p_gains": 0.5*np.array([1.0, 4.0, 2.0, 4.0, 1.0, 4.0, 1.0]), -# "d_gains": 0.5*np.array([0.1, 0.4, 0.2, 0.4, 0.1, 0.4, 0.1]) -# } -# } -# } -# ) -# ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("TableTennisProMP-v2") + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) \ No newline at end of file diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 99d1a23..886b924 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -7,21 +7,16 @@ from gym.envs.mujoco import MujocoEnv from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward -# CUP_POS_MIN = np.array([-0.32, -2.2]) -# CUP_POS_MAX = np.array([0.32, -1.2]) - -CUP_POS_MIN = np.array([-1.42, -4.05]) -CUP_POS_MAX = np.array([1.42, -1.25]) +CUP_POS_MIN = np.array([-0.32, -2.2]) +CUP_POS_MAX = np.array([0.32, -1.2]) class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): - if cup_goal_pos is None: - cup_goal_pos = [-0.3, -1.2, 0.840] - elif len(cup_goal_pos)==2: - cup_goal_pos = np.array(cup_goal_pos) - cup_goal_pos = np.insert(cup_goal_pos, 2, 0.80) + cup_goal_pos = np.array(cup_goal_pos if cup_goal_pos is not None else [-0.3, -1.2, 0.840]) + if cup_goal_pos.shape[0]==2: + cup_goal_pos = np.insert(cup_goal_pos, 2, 0.840) self.cup_goal_pos = np.array(cup_goal_pos) self._steps = 0 @@ -52,7 +47,6 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): else: self.noise_std = 0 - reward_function = BeerPongReward self.reward_function = reward_function() @@ -94,7 +88,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): start_pos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() self.set_state(start_pos, init_vel) if self.rndm_goal: - xy = np.random.uniform(CUP_POS_MIN, CUP_POS_MAX) + xy = self.np_random.uniform(CUP_POS_MIN, CUP_POS_MAX) xyz = np.zeros(3) xyz[:2] = xy xyz[-1] = 0.840 diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index 40b181b..6edc7ee 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -54,6 +54,7 @@ class BeerPongReward: self.ball_table_contact = False self.ball_wall_contact = False self.ball_cup_contact = False + self.ball_in_cup = False self.noisy_bp = noisy self._t_min_final_dist = -1 @@ -80,39 +81,94 @@ class BeerPongReward: action_cost = np.sum(np.square(action)) self.action_costs.append(action_cost) + # ##################### Reward function which forces to bounce once on the table (tanh) ######################## + # if not self.ball_table_contact: + # self.ball_table_contact = self._check_collision_single_objects(env.sim, self.ball_collision_id, + # self.table_collision_id) - if not self.ball_table_contact: - self.ball_table_contact = self._check_collision_single_objects(env.sim, self.ball_collision_id, - self.table_collision_id) + # self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) + # if env._steps == env.ep_length - 1 or self._is_collided: + # min_dist = np.min(self.dists) + # final_dist = self.dists_final[-1] + # + # ball_in_cup = self._check_collision_single_objects(env.sim, self.ball_collision_id, + # self.cup_table_collision_id) + # + # # encourage bounce before falling into cup + # if not ball_in_cup: + # if not self.ball_table_contact: + # reward = 0.2 * (1 - np.tanh(0.5*min_dist)) + 0.1 * (1 - np.tanh(0.5*final_dist)) + # else: + # reward = (1 - np.tanh(0.5*min_dist)) + 0.5 * (1 - np.tanh(0.5*final_dist)) + # else: + # if not self.ball_table_contact: + # reward = 2 * (1 - np.tanh(0.5*final_dist)) + 1 * (1 - np.tanh(0.5*min_dist)) + 1 + # else: + # reward = 2 * (1 - np.tanh(0.5*final_dist)) + 1 * (1 - np.tanh(0.5*min_dist)) + 3 + # + # # reward = - 1 * cost - self.collision_penalty * int(self._is_collided) + # success = ball_in_cup + # crash = self._is_collided + # else: + # reward = - 1e-2 * action_cost + # success = False + # crash = False + # ################################################################################################################ + # ##################### Reward function which does not force to bounce once on the table (tanh) ################ + # self._check_contacts(env.sim) + # self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) + # if env._steps == env.ep_length - 1 or self._is_collided: + # min_dist = np.min(self.dists) + # final_dist = self.dists_final[-1] + # + # # encourage bounce before falling into cup + # if not self.ball_in_cup: + # if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact: + # min_dist_coeff, final_dist_coeff, rew_offset = 0.2, 0.1, 0 + # # reward = 0.2 * (1 - np.tanh(0.5*min_dist)) + 0.1 * (1 - np.tanh(0.5*final_dist)) + # else: + # min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, 0 + # # reward = (1 - np.tanh(0.5*min_dist)) + 0.5 * (1 - np.tanh(0.5*final_dist)) + # else: + # min_dist_coeff, final_dist_coeff, rew_offset = 1, 2, 3 + # # reward = 2 * (1 - np.tanh(0.5*final_dist)) + 1 * (1 - np.tanh(0.5*min_dist)) + 3 + # + # reward = final_dist_coeff * (1 - np.tanh(0.5 * final_dist)) + min_dist_coeff * (1 - np.tanh(0.5 * min_dist)) \ + # + rew_offset + # success = self.ball_in_cup + # crash = self._is_collided + # else: + # reward = - 1e-2 * action_cost + # success = False + # crash = False + # ################################################################################################################ + + # ##################### Reward function which does not force to bounce once on the table (quad dist) ############ + self._check_contacts(env.sim) self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) if env._steps == env.ep_length - 1 or self._is_collided: - min_dist = np.min(self.dists) final_dist = self.dists_final[-1] - ball_in_cup = self._check_collision_single_objects(env.sim, self.ball_collision_id, - self.cup_table_collision_id) - # encourage bounce before falling into cup - if not ball_in_cup: - if not self.ball_table_contact: - reward = 0.2 * (1 - np.tanh(0.5*min_dist)) + 0.1 * (1 - np.tanh(0.5*final_dist)) + if not self.ball_in_cup: + if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact: + min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -4 else: - reward = (1 - np.tanh(0.5*min_dist)) + 0.5 * (1 - np.tanh(0.5*final_dist)) + min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -2 else: - if not self.ball_table_contact: - reward = 2 * (1 - np.tanh(0.5*final_dist)) + 1 * (1 - np.tanh(0.5*min_dist)) + 1 - else: - reward = 2 * (1 - np.tanh(0.5*final_dist)) + 1 * (1 - np.tanh(0.5*min_dist)) + 3 + min_dist_coeff, final_dist_coeff, rew_offset = 0, 1, 0 - # reward = - 1 * cost - self.collision_penalty * int(self._is_collided) - success = ball_in_cup + reward = rew_offset - min_dist_coeff * min_dist**2 - final_dist_coeff * final_dist**2 - \ + 1e-4*np.mean(action_cost) + success = self.ball_in_cup crash = self._is_collided else: reward = - 1e-2 * action_cost success = False crash = False + # ################################################################################################################ infos = {} infos["success"] = success @@ -124,6 +180,20 @@ class BeerPongReward: return reward, infos + def _check_contacts(self, sim): + if not self.ball_table_contact: + self.ball_table_contact = self._check_collision_single_objects(sim, self.ball_collision_id, + self.table_collision_id) + if not self.ball_cup_contact: + self.ball_cup_contact = self._check_collision_with_set_of_objects(sim, self.ball_collision_id, + self.cup_collision_ids) + if not self.ball_wall_contact: + self.ball_wall_contact = self._check_collision_single_objects(sim, self.ball_collision_id, + self.wall_collision_id) + if not self.ball_in_cup: + self.ball_in_cup = self._check_collision_single_objects(sim, self.ball_collision_id, + self.cup_table_collision_id) + def _check_collision_single_objects(self, sim, id_1, id_2): for coni in range(0, sim.data.ncon): con = sim.data.contact[coni] From 7ffe94dcfd68d420a5af1da449cb82e0116e1dbd Mon Sep 17 00:00:00 2001 From: Onur Date: Fri, 8 Apr 2022 17:32:53 +0200 Subject: [PATCH 012/104] working bp version, tested with CMORE on a smaller context with 1 seed --- alr_envs/alr/__init__.py | 1 + alr_envs/alr/mujoco/beerpong/beerpong.py | 7 ++++++- .../alr/mujoco/beerpong/beerpong_reward_staged.py | 14 +++++++------- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 7e7bca1..38abbf1 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -391,6 +391,7 @@ for _v in _versions: "duration": 1, "post_traj_time": 2, "policy_type": "motor", + # "weights_scale": 0.15, "weights_scale": 1, "zero_start": True, "zero_goal": False, diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 886b924..d885e78 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -10,6 +10,10 @@ from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward CUP_POS_MIN = np.array([-0.32, -2.2]) CUP_POS_MAX = np.array([0.32, -1.2]) +# smaller context space -> Easier task +# CUP_POS_MIN = np.array([-0.16, -2.2]) +# CUP_POS_MAX = np.array([0.16, -1.7]) + class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, @@ -36,7 +40,8 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.ball_site_id = 0 self.ball_id = 11 - self._release_step = 175 # time step of ball release + # self._release_step = 175 # time step of ball release + self._release_step = 130 # time step of ball release self.sim_time = 3 # seconds self.ep_length = 600 # based on 3 seconds with dt = 0.005 int(self.sim_time / self.dt) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index 6edc7ee..c9ed451 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -85,7 +85,7 @@ class BeerPongReward: # if not self.ball_table_contact: # self.ball_table_contact = self._check_collision_single_objects(env.sim, self.ball_collision_id, # self.table_collision_id) - + # # self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) # if env._steps == env.ep_length - 1 or self._is_collided: # min_dist = np.min(self.dists) @@ -115,7 +115,7 @@ class BeerPongReward: # crash = False # ################################################################################################################ - # ##################### Reward function which does not force to bounce once on the table (tanh) ################ + ##################### Reward function which does not force to bounce once on the table (tanh) ################ # self._check_contacts(env.sim) # self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) # if env._steps == env.ep_length - 1 or self._is_collided: @@ -142,9 +142,9 @@ class BeerPongReward: # reward = - 1e-2 * action_cost # success = False # crash = False - # ################################################################################################################ + ################################################################################################################ - # ##################### Reward function which does not force to bounce once on the table (quad dist) ############ + # # ##################### Reward function which does not force to bounce once on the table (quad dist) ############ self._check_contacts(env.sim) self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) if env._steps == env.ep_length - 1 or self._is_collided: @@ -162,12 +162,12 @@ class BeerPongReward: reward = rew_offset - min_dist_coeff * min_dist**2 - final_dist_coeff * final_dist**2 - \ 1e-4*np.mean(action_cost) + # 1e-7*np.mean(action_cost) success = self.ball_in_cup - crash = self._is_collided else: - reward = - 1e-2 * action_cost + # reward = - 1e-2 * action_cost + reward = - 1e-4 * action_cost success = False - crash = False # ################################################################################################################ infos = {} From 092525889be79c43350b3e37e729a4348aab71ac Mon Sep 17 00:00:00 2001 From: Onur Date: Wed, 13 Apr 2022 17:28:25 +0200 Subject: [PATCH 013/104] Added environments from Paul + Marc --- alr_envs/alr/__init__.py | 273 +++++++++++++++++- alr_envs/alr/mujoco/__init__.py | 9 +- alr_envs/alr/mujoco/ant_jump/__init__.py | 1 + alr_envs/alr/mujoco/ant_jump/ant_jump.py | 117 ++++++++ alr_envs/alr/mujoco/ant_jump/assets/ant.xml | 81 ++++++ alr_envs/alr/mujoco/ant_jump/mp_wrapper.py | 31 ++ .../alr/mujoco/half_cheetah_jump/__init__.py | 1 + .../half_cheetah_jump/assets/cheetah.xml | 62 ++++ .../half_cheetah_jump/half_cheetah_jump.py | 100 +++++++ .../mujoco/half_cheetah_jump/mp_wrapper.py | 30 ++ alr_envs/alr/mujoco/hopper_jump/__init__.py | 1 + .../alr/mujoco/hopper_jump/assets/hopper.xml | 48 +++ .../hopper_jump/assets/hopper_jump_on_box.xml | 51 ++++ .../alr/mujoco/hopper_jump/hopper_jump.py | 110 +++++++ .../mujoco/hopper_jump/hopper_jump_on_box.py | 170 +++++++++++ alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py | 31 ++ alr_envs/alr/mujoco/hopper_throw/__init__.py | 1 + .../hopper_throw/assets/hopper_throw.xml | 56 ++++ .../assets/hopper_throw_in_basket.xml | 132 +++++++++ .../alr/mujoco/hopper_throw/hopper_throw.py | 113 ++++++++ .../hopper_throw/hopper_throw_in_basket.py | 143 +++++++++ .../alr/mujoco/hopper_throw/mp_wrapper.py | 30 ++ .../alr/mujoco/walker_2d_jump/__init__.py | 1 + .../mujoco/walker_2d_jump/assets/walker2d.xml | 62 ++++ .../alr/mujoco/walker_2d_jump/mp_wrapper.py | 30 ++ .../mujoco/walker_2d_jump/walker_2d_jump.py | 113 ++++++++ 26 files changed, 1795 insertions(+), 2 deletions(-) create mode 100644 alr_envs/alr/mujoco/ant_jump/__init__.py create mode 100644 alr_envs/alr/mujoco/ant_jump/ant_jump.py create mode 100644 alr_envs/alr/mujoco/ant_jump/assets/ant.xml create mode 100644 alr_envs/alr/mujoco/ant_jump/mp_wrapper.py create mode 100644 alr_envs/alr/mujoco/half_cheetah_jump/__init__.py create mode 100644 alr_envs/alr/mujoco/half_cheetah_jump/assets/cheetah.xml create mode 100644 alr_envs/alr/mujoco/half_cheetah_jump/half_cheetah_jump.py create mode 100644 alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py create mode 100644 alr_envs/alr/mujoco/hopper_jump/__init__.py create mode 100644 alr_envs/alr/mujoco/hopper_jump/assets/hopper.xml create mode 100644 alr_envs/alr/mujoco/hopper_jump/assets/hopper_jump_on_box.xml create mode 100644 alr_envs/alr/mujoco/hopper_jump/hopper_jump.py create mode 100644 alr_envs/alr/mujoco/hopper_jump/hopper_jump_on_box.py create mode 100644 alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py create mode 100644 alr_envs/alr/mujoco/hopper_throw/__init__.py create mode 100644 alr_envs/alr/mujoco/hopper_throw/assets/hopper_throw.xml create mode 100644 alr_envs/alr/mujoco/hopper_throw/assets/hopper_throw_in_basket.xml create mode 100644 alr_envs/alr/mujoco/hopper_throw/hopper_throw.py create mode 100644 alr_envs/alr/mujoco/hopper_throw/hopper_throw_in_basket.py create mode 100644 alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py create mode 100644 alr_envs/alr/mujoco/walker_2d_jump/__init__.py create mode 100644 alr_envs/alr/mujoco/walker_2d_jump/assets/walker2d.xml create mode 100644 alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py create mode 100644 alr_envs/alr/mujoco/walker_2d_jump/walker_2d_jump.py diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 38abbf1..e435fa6 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -11,6 +11,13 @@ from .mujoco.reacher.alr_reacher import ALRReacherEnv from .mujoco.reacher.balancing import BalancingEnv from alr_envs.alr.mujoco.table_tennis.tt_gym import MAX_EPISODE_STEPS +from .mujoco.ant_jump.ant_jump import MAX_EPISODE_STEPS_ANTJUMP +from .mujoco.half_cheetah_jump.half_cheetah_jump import MAX_EPISODE_STEPS_HALFCHEETAHJUMP +from .mujoco.hopper_jump.hopper_jump import MAX_EPISODE_STEPS_HOPPERJUMP +from .mujoco.hopper_jump.hopper_jump_on_box import MAX_EPISODE_STEPS_HOPPERJUMPONBOX +from .mujoco.hopper_throw.hopper_throw import MAX_EPISODE_STEPS_HOPPERTHROW +from .mujoco.hopper_throw.hopper_throw_in_basket import MAX_EPISODE_STEPS_HOPPERTHROWINBASKET +from .mujoco.walker_2d_jump.walker_2d_jump import MAX_EPISODE_STEPS_WALKERJUMP ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": []} @@ -185,6 +192,69 @@ register( } ) + +register( + id='ALRAntJump-v0', + entry_point='alr_envs.alr.mujoco:ALRAntJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_ANTJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_ANTJUMP + } +) + +register( + id='ALRHalfCheetahJump-v0', + entry_point='alr_envs.alr.mujoco:ALRHalfCheetahJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_HALFCHEETAHJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HALFCHEETAHJUMP + } +) + +register( + id='ALRHopperJump-v0', + entry_point='alr_envs.alr.mujoco:ALRHopperJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP + } +) + +register( + id='ALRHopperJumpOnBox-v0', + entry_point='alr_envs.alr.mujoco:ALRHopperJumpOnBoxEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMPONBOX, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMPONBOX + } +) + +register( + id='ALRHopperThrow-v0', + entry_point='alr_envs.alr.mujoco:ALRHopperThrowEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROW, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROW + } +) + +register( + id='ALRHopperThrowInBasket-v0', + entry_point='alr_envs.alr.mujoco:ALRHopperThrowInBasketEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROWINBASKET + } +) + +register( + id='ALRWalker2DJump-v0', + entry_point='alr_envs.alr.mujoco:ALRWalker2dJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_WALKERJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_WALKERJUMP + } +) ## Balancing Reacher register( @@ -430,4 +500,205 @@ for _v, cd in enumerate(ctxt_dim): } } ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) \ No newline at end of file + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + + +## AntJump +for _v, cd in enumerate(ctxt_dim): + _env_id = f'TableTennisProMP-v{_v}' + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": "alr_envs:TableTennis{}DCtxt-v0".format(cd), + "wrappers": [mujoco.table_tennis.MPWrapper], + "mp_kwargs": { + "num_dof": 7, + "num_basis": 2, + "duration": 1.25, + "post_traj_time": 1.5, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": 0.5*np.array([1.0, 4.0, 2.0, 4.0, 1.0, 4.0, 1.0]), + "d_gains": 0.5*np.array([0.1, 0.4, 0.2, 0.4, 0.1, 0.4, 0.1]) + } + } + } + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + + +register( + id='ALRAntJumpProMP-v0', + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": "alr_envs:ALRAntJump-v0", + "wrappers": [mujoco.ant_jump.MPWrapper], + "mp_kwargs": { + "num_dof": 8, + "num_basis": 5, + "duration": 10, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(8), + "d_gains": 0.1*np.ones(8) + } + } + } +) +ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRAntJumpProMP-v0') + +register( + id='ALRHalfCheetahJumpProMP-v0', + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": "alr_envs:ALRHalfCheetahJump-v0", + "wrappers": [mujoco.half_cheetah_jump.MPWrapper], + "mp_kwargs": { + "num_dof": 6, + "num_basis": 5, + "duration": 5, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(6), + "d_gains": 0.1*np.ones(6) + } + } + } +) +ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRHalfCheetahJumpProMP-v0') + + +register( + id='ALRHopperJumpProMP-v0', + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": "alr_envs:ALRHopperJump-v0", + "wrappers": [mujoco.hopper_jump.MPWrapper], + "mp_kwargs": { + "num_dof": 3, + "num_basis": 5, + "duration": 2, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(3), + "d_gains": 0.1*np.ones(3) + } + } + } +) +ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRHopperJumpProMP-v0') + +register( + id='ALRHopperJumpOnBoxProMP-v0', + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": "alr_envs:ALRHopperJumpOnBox-v0", + "wrappers": [mujoco.hopper_jump.MPWrapper], + "mp_kwargs": { + "num_dof": 3, + "num_basis": 5, + "duration": 2, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(3), + "d_gains": 0.1*np.ones(3) + } + } + } +) +ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRHopperJumpOnBoxProMP-v0') + + +register( + id='ALRHopperThrowProMP-v0', + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": "alr_envs:ALRHopperThrow-v0", + "wrappers": [mujoco.hopper_throw.MPWrapper], + "mp_kwargs": { + "num_dof": 3, + "num_basis": 5, + "duration": 2, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(3), + "d_gains": 0.1*np.ones(3) + } + } + } +) +ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRHopperThrowProMP-v0') + + +register( + id='ALRHopperThrowInBasketProMP-v0', + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": "alr_envs:ALRHopperThrowInBasket-v0", + "wrappers": [mujoco.hopper_throw.MPWrapper], + "mp_kwargs": { + "num_dof": 3, + "num_basis": 5, + "duration": 2, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(3), + "d_gains": 0.1*np.ones(3) + } + } + } +) +ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRHopperThrowInBasketProMP-v0') + + +register( + id='ALRWalker2DJumpProMP-v0', + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": "alr_envs:ALRWalker2DJump-v0", + "wrappers": [mujoco.walker_2d_jump.MPWrapper], + "mp_kwargs": { + "num_dof": 6, + "num_basis": 5, + "duration": 2.4, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(6), + "d_gains": 0.1*np.ones(6) + } + } + } +) +ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRWalker2DJumpProMP-v0') diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index cdb3cde..8935db4 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -3,4 +3,11 @@ from .reacher.balancing import BalancingEnv from .ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv from .ball_in_a_cup.biac_pd import ALRBallInACupPDEnv from .table_tennis.tt_gym import TTEnvGym -from .beerpong.beerpong import ALRBeerBongEnv \ No newline at end of file +from .beerpong.beerpong import ALRBeerBongEnv +from .ant_jump.ant_jump import ALRAntJumpEnv +from .half_cheetah_jump.half_cheetah_jump import ALRHalfCheetahJumpEnv +from .hopper_jump.hopper_jump import ALRHopperJumpEnv +from .hopper_jump.hopper_jump_on_box import ALRHopperJumpOnBoxEnv +from .hopper_throw.hopper_throw import ALRHopperThrowEnv +from .hopper_throw.hopper_throw_in_basket import ALRHopperThrowInBasketEnv +from .walker_2d_jump.walker_2d_jump import ALRWalker2dJumpEnv \ No newline at end of file diff --git a/alr_envs/alr/mujoco/ant_jump/__init__.py b/alr_envs/alr/mujoco/ant_jump/__init__.py new file mode 100644 index 0000000..c5e6d2f --- /dev/null +++ b/alr_envs/alr/mujoco/ant_jump/__init__.py @@ -0,0 +1 @@ +from .mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/ant_jump/ant_jump.py b/alr_envs/alr/mujoco/ant_jump/ant_jump.py new file mode 100644 index 0000000..09c623d --- /dev/null +++ b/alr_envs/alr/mujoco/ant_jump/ant_jump.py @@ -0,0 +1,117 @@ +import numpy as np +from gym.envs.mujoco.ant_v3 import AntEnv + +MAX_EPISODE_STEPS_ANTJUMP = 200 + + +class ALRAntJumpEnv(AntEnv): + """ + Initialization changes to normal Ant: + - healthy_reward: 1.0 -> 0.01 -> 0.0 no healthy reward needed - Paul and Marc + - ctrl_cost_weight 0.5 -> 0.0 + - contact_cost_weight: 5e-4 -> 0.0 + - healthy_z_range: (0.2, 1.0) -> (0.3, float('inf')) !!!!! Does that make sense, limiting height? + """ + + def __init__(self, + xml_file='ant.xml', + ctrl_cost_weight=0.0, + contact_cost_weight=0.0, + healthy_reward=0.0, + terminate_when_unhealthy=True, + healthy_z_range=(0.3, float('inf')), + contact_force_range=(-1.0, 1.0), + reset_noise_scale=0.1, + context=True, # variable to decide if context is used or not + exclude_current_positions_from_observation=True, + max_episode_steps=200): + self.current_step = 0 + self.max_height = 0 + self.context = context + self.max_episode_steps = max_episode_steps + self.goal = 0 # goal when training with context + super().__init__(xml_file, ctrl_cost_weight, contact_cost_weight, healthy_reward, terminate_when_unhealthy, + healthy_z_range, contact_force_range, reset_noise_scale, + exclude_current_positions_from_observation) + + def step(self, action): + + self.current_step += 1 + self.do_simulation(action, self.frame_skip) + + height = self.get_body_com("torso")[2].copy() + + self.max_height = max(height, self.max_height) + + rewards = 0 + + ctrl_cost = self.control_cost(action) + contact_cost = self.contact_cost + + costs = ctrl_cost + contact_cost + + done = height < 0.3 # fall over -> is the 0.3 value from healthy_z_range? TODO change 0.3 to the value of healthy z angle + + if self.current_step == self.max_episode_steps or done: + if self.context: + # -10 for scaling the value of the distance between the max_height and the goal height; only used when context is enabled + # height_reward = -10 * (np.linalg.norm(self.max_height - self.goal)) + height_reward = -10*np.linalg.norm(self.max_height - self.goal) + # no healthy reward when using context, because we optimize a negative value + healthy_reward = 0 + else: + height_reward = self.max_height - 0.7 + healthy_reward = self.healthy_reward * self.current_step + + rewards = height_reward + healthy_reward + + obs = self._get_obs() + reward = rewards - costs + + info = { + 'height': height, + 'max_height': self.max_height, + 'goal': self.goal + } + + return obs, reward, done, info + + def _get_obs(self): + return np.append(super()._get_obs(), self.goal) + + def reset(self): + self.current_step = 0 + self.max_height = 0 + self.goal = np.random.uniform(1.0, 2.5, + 1) # goal heights from 1.0 to 2.5; can be increased, but didnt work well with CMORE + return super().reset() + + # reset_model had to be implemented in every env to make it deterministic + def reset_model(self): + noise_low = -self._reset_noise_scale + noise_high = self._reset_noise_scale + + qpos = self.init_qpos # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + qvel = self.init_qvel # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) + + self.set_state(qpos, qvel) + + observation = self._get_obs() + return observation + +if __name__ == '__main__': + render_mode = "human" # "human" or "partial" or "final" + env = ALRAntJumpEnv() + obs = env.reset() + + for i in range(2000): + # objective.load_result("/tmp/cma") + # test with random actions + ac = env.action_space.sample() + obs, rew, d, info = env.step(ac) + if i % 10 == 0: + env.render(mode=render_mode) + if d: + env.reset() + + env.close() \ No newline at end of file diff --git a/alr_envs/alr/mujoco/ant_jump/assets/ant.xml b/alr_envs/alr/mujoco/ant_jump/assets/ant.xml new file mode 100644 index 0000000..ee4d679 --- /dev/null +++ b/alr_envs/alr/mujoco/ant_jump/assets/ant.xml @@ -0,0 +1,81 @@ + + + diff --git a/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py b/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py new file mode 100644 index 0000000..4967b64 --- /dev/null +++ b/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py @@ -0,0 +1,31 @@ +from typing import Tuple, Union + +import numpy as np + +from mp_env_api import MPEnvWrapper + + +class MPWrapper(MPEnvWrapper): + + @property + def active_obs(self): + return np.hstack([ + [False] * 111, # ant has 111 dimensional observation space !! + [True] # goal height + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray]: + return self.env.sim.data.qpos[7:15].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[6:14].copy() + + @property + def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: + raise ValueError("Goal position is not available and has to be learnt based on the environment.") + + @property + def dt(self) -> Union[float, int]: + return self.env.dt diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/__init__.py b/alr_envs/alr/mujoco/half_cheetah_jump/__init__.py new file mode 100644 index 0000000..c5e6d2f --- /dev/null +++ b/alr_envs/alr/mujoco/half_cheetah_jump/__init__.py @@ -0,0 +1 @@ +from .mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/assets/cheetah.xml b/alr_envs/alr/mujoco/half_cheetah_jump/assets/cheetah.xml new file mode 100644 index 0000000..41daadf --- /dev/null +++ b/alr_envs/alr/mujoco/half_cheetah_jump/assets/cheetah.xml @@ -0,0 +1,62 @@ + + + + + + + + + diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/half_cheetah_jump.py b/alr_envs/alr/mujoco/half_cheetah_jump/half_cheetah_jump.py new file mode 100644 index 0000000..4b53a5d --- /dev/null +++ b/alr_envs/alr/mujoco/half_cheetah_jump/half_cheetah_jump.py @@ -0,0 +1,100 @@ +import os +from gym.envs.mujoco.half_cheetah_v3 import HalfCheetahEnv +import numpy as np + +MAX_EPISODE_STEPS_HALFCHEETAHJUMP = 100 + + +class ALRHalfCheetahJumpEnv(HalfCheetahEnv): + """ + ctrl_cost_weight 0.1 -> 0.0 + """ + + def __init__(self, + xml_file='cheetah.xml', + forward_reward_weight=1.0, + ctrl_cost_weight=0.0, + reset_noise_scale=0.1, + context=True, + exclude_current_positions_from_observation=True, + max_episode_steps=100): + self.current_step = 0 + self.max_height = 0 + self.max_episode_steps = max_episode_steps + self.goal = 0 + self.context = context + xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) + super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, reset_noise_scale, + exclude_current_positions_from_observation) + + def step(self, action): + + self.current_step += 1 + self.do_simulation(action, self.frame_skip) + + height_after = self.get_body_com("torso")[2] + self.max_height = max(height_after, self.max_height) + + ## Didnt use fell_over, because base env also has no done condition - Paul and Marc + # fell_over = abs(self.sim.data.qpos[2]) > 2.5 # how to figure out if the cheetah fell over? -> 2.5 oke? + # TODO: Should a fall over be checked herE? + done = False + + ctrl_cost = self.control_cost(action) + costs = ctrl_cost + + if self.current_step == self.max_episode_steps: + height_goal_distance = -10*np.linalg.norm(self.max_height - self.goal) + 1e-8 if self.context \ + else self.max_height + rewards = self._forward_reward_weight * height_goal_distance + else: + rewards = 0 + + observation = self._get_obs() + reward = rewards - costs + info = { + 'height': height_after, + 'max_height': self.max_height + } + + return observation, reward, done, info + + def _get_obs(self): + return np.append(super()._get_obs(), self.goal) + + def reset(self): + self.max_height = 0 + self.current_step = 0 + self.goal = np.random.uniform(1.1, 1.6, 1) # 1.1 1.6 + return super().reset() + + # overwrite reset_model to make it deterministic + def reset_model(self): + noise_low = -self._reset_noise_scale + noise_high = self._reset_noise_scale + + qpos = self.init_qpos # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + qvel = self.init_qvel # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) + + self.set_state(qpos, qvel) + + observation = self._get_obs() + return observation + +if __name__ == '__main__': + render_mode = "human" # "human" or "partial" or "final" + env = ALRHalfCheetahJumpEnv() + obs = env.reset() + + for i in range(2000): + # objective.load_result("/tmp/cma") + # test with random actions + ac = env.action_space.sample() + obs, rew, d, info = env.step(ac) + if i % 10 == 0: + env.render(mode=render_mode) + if d: + print('After ', i, ' steps, done: ', d) + env.reset() + + env.close() \ No newline at end of file diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py b/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py new file mode 100644 index 0000000..6179b07 --- /dev/null +++ b/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py @@ -0,0 +1,30 @@ +from typing import Tuple, Union + +import numpy as np + +from mp_env_api import MPEnvWrapper + + +class MPWrapper(MPEnvWrapper): + @property + def active_obs(self): + return np.hstack([ + [False] * 17, + [True] # goal height + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray]: + return self.env.sim.data.qpos[3:9].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[3:9].copy() + + @property + def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: + raise ValueError("Goal position is not available and has to be learnt based on the environment.") + + @property + def dt(self) -> Union[float, int]: + return self.env.dt diff --git a/alr_envs/alr/mujoco/hopper_jump/__init__.py b/alr_envs/alr/mujoco/hopper_jump/__init__.py new file mode 100644 index 0000000..c5e6d2f --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_jump/__init__.py @@ -0,0 +1 @@ +from .mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/hopper_jump/assets/hopper.xml b/alr_envs/alr/mujoco/hopper_jump/assets/hopper.xml new file mode 100644 index 0000000..f18bc46 --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_jump/assets/hopper.xml @@ -0,0 +1,48 @@ + + + + + + + + diff --git a/alr_envs/alr/mujoco/hopper_jump/assets/hopper_jump_on_box.xml b/alr_envs/alr/mujoco/hopper_jump/assets/hopper_jump_on_box.xml new file mode 100644 index 0000000..69d78ff --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_jump/assets/hopper_jump_on_box.xml @@ -0,0 +1,51 @@ + + + + + + + + \ No newline at end of file diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py new file mode 100644 index 0000000..7ce8196 --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -0,0 +1,110 @@ +from gym.envs.mujoco.hopper_v3 import HopperEnv +import numpy as np + +MAX_EPISODE_STEPS_HOPPERJUMP = 250 + + +class ALRHopperJumpEnv(HopperEnv): + """ + Initialization changes to normal Hopper: + - healthy_reward: 1.0 -> 0.1 -> 0 + - healthy_angle_range: (-0.2, 0.2) -> (-float('inf'), float('inf')) + - healthy_z_range: (0.7, float('inf')) -> (0.5, float('inf')) + + """ + + def __init__(self, + xml_file='hopper.xml', + forward_reward_weight=1.0, + ctrl_cost_weight=1e-3, + healthy_reward=0.0, + penalty=0.0, + context=True, + terminate_when_unhealthy=True, + healthy_state_range=(-100.0, 100.0), + healthy_z_range=(0.5, float('inf')), + healthy_angle_range=(-float('inf'), float('inf')), + reset_noise_scale=5e-3, + exclude_current_positions_from_observation=True, + max_episode_steps=250): + self.current_step = 0 + self.max_height = 0 + self.max_episode_steps = max_episode_steps + self.penalty = penalty + self.goal = 0 + self.context = context + self.exclude_current_positions_from_observation = exclude_current_positions_from_observation + super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, + healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, + exclude_current_positions_from_observation) + + def step(self, action): + + self.current_step += 1 + self.do_simulation(action, self.frame_skip) + height_after = self.get_body_com("torso")[2] + self.max_height = max(height_after, self.max_height) + + ctrl_cost = self.control_cost(action) + costs = ctrl_cost + done = False + + if self.current_step >= self.max_episode_steps: + hight_goal_distance = -10*np.linalg.norm(self.max_height - self.goal) if self.context else self.max_height + healthy_reward = 0 if self.context else self.healthy_reward * self.current_step + height_reward = self._forward_reward_weight * hight_goal_distance # maybe move reward calculation into if structure and define two different _forward_reward_weight variables for context and episodic seperatley + rewards = height_reward + healthy_reward + + else: + # penalty for wrong start direction of first two joints; not needed, could be removed + rewards = ((action[:2] > 0) * self.penalty).sum() if self.current_step < 10 else 0 + + observation = self._get_obs() + reward = rewards - costs + info = { + 'height' : height_after, + 'max_height': self.max_height, + 'goal' : self.goal + } + + return observation, reward, done, info + + def _get_obs(self): + return np.append(super()._get_obs(), self.goal) + + def reset(self): + self.goal = np.random.uniform(1.4, 2.3, 1) # 1.3 2.3 + self.max_height = 0 + self.current_step = 0 + return super().reset() + + # overwrite reset_model to make it deterministic + def reset_model(self): + noise_low = -self._reset_noise_scale + noise_high = self._reset_noise_scale + + qpos = self.init_qpos # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + qvel = self.init_qvel # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) + + self.set_state(qpos, qvel) + + observation = self._get_obs() + return observation + +if __name__ == '__main__': + render_mode = "human" # "human" or "partial" or "final" + env = ALRHopperJumpEnv() + obs = env.reset() + + for i in range(2000): + # objective.load_result("/tmp/cma") + # test with random actions + ac = env.action_space.sample() + obs, rew, d, info = env.step(ac) + if i % 10 == 0: + env.render(mode=render_mode) + if d: + print('After ', i, ' steps, done: ', d) + env.reset() + + env.close() \ No newline at end of file diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump_on_box.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump_on_box.py new file mode 100644 index 0000000..e5e363e --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump_on_box.py @@ -0,0 +1,170 @@ +from gym.envs.mujoco.hopper_v3 import HopperEnv + +import numpy as np +import os + +MAX_EPISODE_STEPS_HOPPERJUMPONBOX = 250 + + +class ALRHopperJumpOnBoxEnv(HopperEnv): + """ + Initialization changes to normal Hopper: + - healthy_reward: 1.0 -> 0.01 -> 0.001 + - healthy_angle_range: (-0.2, 0.2) -> (-float('inf'), float('inf')) + """ + + def __init__(self, + xml_file='hopper_jump_on_box.xml', + forward_reward_weight=1.0, + ctrl_cost_weight=1e-3, + healthy_reward=0.001, + terminate_when_unhealthy=True, + healthy_state_range=(-100.0, 100.0), + healthy_z_range=(0.7, float('inf')), + healthy_angle_range=(-float('inf'), float('inf')), + reset_noise_scale=5e-3, + context=True, + exclude_current_positions_from_observation=True, + max_episode_steps=250): + self.current_step = 0 + self.max_height = 0 + self.max_episode_steps = max_episode_steps + self.min_distance = 5000 # what value? + self.hopper_on_box = False + self.context = context + self.box_x = 1 + xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) + super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, + healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, + exclude_current_positions_from_observation) + + def step(self, action): + + self.current_step += 1 + self.do_simulation(action, self.frame_skip) + height_after = self.get_body_com("torso")[2] + foot_pos = self.get_body_com("foot") + self.max_height = max(height_after, self.max_height) + + vx, vz, vangle = self.sim.data.qvel[0:3] + + s = self.state_vector() + fell_over = not (np.isfinite(s).all() and (np.abs(s[2:]) < 100).all() and (height_after > .7)) + + box_pos = self.get_body_com("box") + box_size = 0.3 + box_height = 0.3 + box_center = (box_pos[0] + (box_size / 2), box_pos[1], box_height) + foot_length = 0.3 + foot_center = foot_pos[0] - (foot_length / 2) + + dist = np.linalg.norm(foot_pos - box_center) + + self.min_distance = min(dist, self.min_distance) + + # check if foot is on box + is_on_box_x = box_pos[0] <= foot_center <= box_pos[0] + box_size + is_on_box_y = True # is y always true because he can only move in x and z direction? + is_on_box_z = box_height - 0.02 <= foot_pos[2] <= box_height + 0.02 + is_on_box = is_on_box_x and is_on_box_y and is_on_box_z + if is_on_box: self.hopper_on_box = True + + ctrl_cost = self.control_cost(action) + + costs = ctrl_cost + + done = fell_over or self.hopper_on_box + + if self.current_step >= self.max_episode_steps or done: + done = False + + max_height = self.max_height.copy() + min_distance = self.min_distance.copy() + + alive_bonus = self._healthy_reward * self.current_step + box_bonus = 0 + rewards = 0 + + # TODO explain what we did here for the calculation of the reward + if is_on_box: + if self.context: + rewards -= 100 * vx ** 2 if 100 * vx ** 2 < 1 else 1 + else: + box_bonus = 10 + rewards += box_bonus + # rewards -= dist * dist ???? why when already on box? + # reward -= 90 - abs(angle) + rewards -= 100 * vx ** 2 if 100 * vx ** 2 < 1 else 1 + rewards += max_height * 3 + rewards += alive_bonus + + else: + if self.context: + rewards = -10 - min_distance + rewards += max_height * 3 + else: + # reward -= (dist*dist) + rewards -= min_distance * min_distance + # rewards -= dist / self.max_distance + rewards += max_height + rewards += alive_bonus + + else: + rewards = 0 + + observation = self._get_obs() + reward = rewards - costs + info = { + 'height': height_after, + 'max_height': self.max_height.copy(), + 'min_distance': self.min_distance, + 'goal': self.box_x, + } + + return observation, reward, done, info + + def _get_obs(self): + return np.append(super()._get_obs(), self.box_x) + + def reset(self): + + self.max_height = 0 + self.min_distance = 5000 + self.current_step = 0 + self.hopper_on_box = False + if self.context: + box_id = self.sim.model.body_name2id("box") + self.box_x = np.random.uniform(1, 3, 1) + self.sim.model.body_pos[box_id] = [self.box_x, 0, 0] + return super().reset() + + # overwrite reset_model to make it deterministic + def reset_model(self): + noise_low = -self._reset_noise_scale + noise_high = self._reset_noise_scale + + qpos = self.init_qpos # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + qvel = self.init_qvel # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) + + self.set_state(qpos, qvel) + + observation = self._get_obs() + return observation + +if __name__ == '__main__': + render_mode = "human" # "human" or "partial" or "final" + env = ALRHopperJumpOnBoxEnv() + obs = env.reset() + + for i in range(2000): + # objective.load_result("/tmp/cma") + # test with random actions + ac = env.action_space.sample() + obs, rew, d, info = env.step(ac) + if i % 10 == 0: + env.render(mode=render_mode) + if d: + print('After ', i, ' steps, done: ', d) + env.reset() + + env.close() \ No newline at end of file diff --git a/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py b/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py new file mode 100644 index 0000000..0d6768c --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py @@ -0,0 +1,31 @@ +from typing import Tuple, Union + +import numpy as np + +from mp_env_api import MPEnvWrapper + + +class MPWrapper(MPEnvWrapper): + @property + def active_obs(self): + return np.hstack([ + [False] * (5 + int(not self.exclude_current_positions_from_observation)), # position + [False] * 6, # velocity + [True] + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray]: + return self.env.sim.data.qpos[3:6].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[3:6].copy() + + @property + def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: + raise ValueError("Goal position is not available and has to be learnt based on the environment.") + + @property + def dt(self) -> Union[float, int]: + return self.env.dt diff --git a/alr_envs/alr/mujoco/hopper_throw/__init__.py b/alr_envs/alr/mujoco/hopper_throw/__init__.py new file mode 100644 index 0000000..989b5a9 --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_throw/__init__.py @@ -0,0 +1 @@ +from .mp_wrapper import MPWrapper \ No newline at end of file diff --git a/alr_envs/alr/mujoco/hopper_throw/assets/hopper_throw.xml b/alr_envs/alr/mujoco/hopper_throw/assets/hopper_throw.xml new file mode 100644 index 0000000..1c39602 --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_throw/assets/hopper_throw.xml @@ -0,0 +1,56 @@ + + + + + + + + diff --git a/alr_envs/alr/mujoco/hopper_throw/assets/hopper_throw_in_basket.xml b/alr_envs/alr/mujoco/hopper_throw/assets/hopper_throw_in_basket.xml new file mode 100644 index 0000000..b4f0342 --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_throw/assets/hopper_throw_in_basket.xml @@ -0,0 +1,132 @@ + + + + + + + + \ No newline at end of file diff --git a/alr_envs/alr/mujoco/hopper_throw/hopper_throw.py b/alr_envs/alr/mujoco/hopper_throw/hopper_throw.py new file mode 100644 index 0000000..03553f2 --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_throw/hopper_throw.py @@ -0,0 +1,113 @@ +import os + +from gym.envs.mujoco.hopper_v3 import HopperEnv +import numpy as np + +MAX_EPISODE_STEPS_HOPPERTHROW = 250 + + +class ALRHopperThrowEnv(HopperEnv): + """ + Initialization changes to normal Hopper: + - healthy_reward: 1.0 -> 0.0 -> 0.1 + - forward_reward_weight -> 5.0 + - healthy_angle_range: (-0.2, 0.2) -> (-float('inf'), float('inf')) + + Reward changes to normal Hopper: + - velocity: (x_position_after - x_position_before) -> self.get_body_com("ball")[0] + """ + + def __init__(self, + xml_file='hopper_throw.xml', + forward_reward_weight=5.0, + ctrl_cost_weight=1e-3, + healthy_reward=0.1, + terminate_when_unhealthy=True, + healthy_state_range=(-100.0, 100.0), + healthy_z_range=(0.7, float('inf')), + healthy_angle_range=(-float('inf'), float('inf')), + reset_noise_scale=5e-3, + context = True, + exclude_current_positions_from_observation=True, + max_episode_steps=250): + xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) + self.current_step = 0 + self.max_episode_steps = max_episode_steps + self.context = context + self.goal = 0 + super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, + healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, + exclude_current_positions_from_observation) + + def step(self, action): + + self.current_step += 1 + self.do_simulation(action, self.frame_skip) + ball_pos_after = self.get_body_com("ball")[0] #abs(self.get_body_com("ball")[0]) # use x and y to get point and use euclid distance as reward? + ball_pos_after_y = self.get_body_com("ball")[2] + + # done = self.done TODO We should use this, not sure why there is no other termination; ball_landed should be enough, because we only look at the throw itself? - Paul and Marc + ball_landed = self.get_body_com("ball")[2] <= 0.05 + done = ball_landed + + ctrl_cost = self.control_cost(action) + costs = ctrl_cost + + rewards = 0 + + if self.current_step >= self.max_episode_steps or done: + distance_reward = -np.linalg.norm(ball_pos_after - self.goal) if self.context else \ + self._forward_reward_weight * ball_pos_after + healthy_reward = 0 if self.context else self.healthy_reward * self.current_step + + rewards = distance_reward + healthy_reward + + observation = self._get_obs() + reward = rewards - costs + info = { + 'ball_pos': ball_pos_after, + 'ball_pos_y': ball_pos_after_y, + 'current_step' : self.current_step, + 'goal' : self.goal, + } + + return observation, reward, done, info + + def _get_obs(self): + return np.append(super()._get_obs(), self.goal) + + def reset(self): + self.current_step = 0 + self.goal = self.goal = np.random.uniform(2.0, 6.0, 1) # 0.5 8.0 + return super().reset() + + # overwrite reset_model to make it deterministic + def reset_model(self): + noise_low = -self._reset_noise_scale + noise_high = self._reset_noise_scale + + qpos = self.init_qpos # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + qvel = self.init_qvel # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) + + self.set_state(qpos, qvel) + + observation = self._get_obs() + return observation + +if __name__ == '__main__': + render_mode = "human" # "human" or "partial" or "final" + env = ALRHopperThrowEnv() + obs = env.reset() + + for i in range(2000): + # objective.load_result("/tmp/cma") + # test with random actions + ac = env.action_space.sample() + obs, rew, d, info = env.step(ac) + if i % 10 == 0: + env.render(mode=render_mode) + if d: + print('After ', i, ' steps, done: ', d) + env.reset() + + env.close() \ No newline at end of file diff --git a/alr_envs/alr/mujoco/hopper_throw/hopper_throw_in_basket.py b/alr_envs/alr/mujoco/hopper_throw/hopper_throw_in_basket.py new file mode 100644 index 0000000..74a5b21 --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_throw/hopper_throw_in_basket.py @@ -0,0 +1,143 @@ +import os +from gym.envs.mujoco.hopper_v3 import HopperEnv + +import numpy as np + + +MAX_EPISODE_STEPS_HOPPERTHROWINBASKET = 250 + + +class ALRHopperThrowInBasketEnv(HopperEnv): + """ + Initialization changes to normal Hopper: + - healthy_reward: 1.0 -> 0.0 + - healthy_angle_range: (-0.2, 0.2) -> (-float('inf'), float('inf')) + - hit_basket_reward: - -> 10 + + Reward changes to normal Hopper: + - velocity: (x_position_after - x_position_before) -> (ball_position_after - ball_position_before) + """ + + def __init__(self, + xml_file='hopper_throw_in_basket.xml', + forward_reward_weight=1.0, + ctrl_cost_weight=1e-3, + healthy_reward=0.0, + hit_basket_reward=10, + basket_size=0.3, + terminate_when_unhealthy=True, + healthy_state_range=(-100.0, 100.0), + healthy_z_range=(0.7, float('inf')), + healthy_angle_range=(-float('inf'), float('inf')), + reset_noise_scale=5e-3, + context=True, + penalty=0.0, + exclude_current_positions_from_observation=True, + max_episode_steps = 250): + self.hit_basket_reward = hit_basket_reward + self.current_step = 0 + self.max_episode_steps = max_episode_steps + self.ball_in_basket = False + self.basket_size = basket_size + self.context = context + self.penalty = penalty + self.basket_x = 5 + xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) + super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, + healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, + exclude_current_positions_from_observation) + + def step(self, action): + + self.current_step += 1 + self.do_simulation(action, self.frame_skip) + ball_pos = self.get_body_com("ball") + + basket_pos = self.get_body_com("basket_ground") + basket_center = (basket_pos[0] + 0.5, basket_pos[1], basket_pos[2]) + + is_in_basket_x = ball_pos[0] >= basket_pos[0] and ball_pos[0] <= basket_pos[0] + self.basket_size + is_in_basket_y = ball_pos[1] >= basket_pos[1] - (self.basket_size/2) and ball_pos[1] <= basket_pos[1] + (self.basket_size/2) + is_in_basket_z = ball_pos[2] < 0.1 + is_in_basket = is_in_basket_x and is_in_basket_y and is_in_basket_z + if is_in_basket: self.ball_in_basket = True + + ball_landed = self.get_body_com("ball")[2] <= 0.05 + done = ball_landed or is_in_basket + + rewards = 0 + + ctrl_cost = self.control_cost(action) + + costs = ctrl_cost + + if self.current_step >= self.max_episode_steps or done: + + if is_in_basket: + if not self.context: + rewards += self.hit_basket_reward + else: + dist = np.linalg.norm(ball_pos-basket_center) + if self.context: + rewards = -10 * dist + else: + rewards -= (dist*dist) + else: + # penalty not needed + rewards += ((action[:2] > 0) * self.penalty).sum() if self.current_step < 10 else 0 #too much of a penalty? + + observation = self._get_obs() + reward = rewards - costs + info = { + 'ball_pos': ball_pos[0], + } + + return observation, reward, done, info + + def _get_obs(self): + return np.append(super()._get_obs(), self.basket_x) + + def reset(self): + if self.max_episode_steps == 10: + # We have to initialize this here, because the spec is only added after creating the env. + self.max_episode_steps = self.spec.max_episode_steps + + self.current_step = 0 + self.ball_in_basket = False + if self.context: + basket_id = self.sim.model.body_name2id("basket_ground") + self.basket_x = np.random.uniform(3, 7, 1) + self.sim.model.body_pos[basket_id] = [self.basket_x, 0, 0] + return super().reset() + + # overwrite reset_model to make it deterministic + def reset_model(self): + noise_low = -self._reset_noise_scale + noise_high = self._reset_noise_scale + + qpos = self.init_qpos # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + qvel = self.init_qvel # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) + + self.set_state(qpos, qvel) + + observation = self._get_obs() + return observation + + +if __name__ == '__main__': + render_mode = "human" # "human" or "partial" or "final" + env = ALRHopperThrowInBasketEnv() + obs = env.reset() + + for i in range(2000): + # objective.load_result("/tmp/cma") + # test with random actions + ac = env.action_space.sample() + obs, rew, d, info = env.step(ac) + if i % 10 == 0: + env.render(mode=render_mode) + if d: + print('After ', i, ' steps, done: ', d) + env.reset() + + env.close() \ No newline at end of file diff --git a/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py b/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py new file mode 100644 index 0000000..e5e9486 --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py @@ -0,0 +1,30 @@ +from typing import Tuple, Union + +import numpy as np + +from mp_env_api import MPEnvWrapper + + +class MPWrapper(MPEnvWrapper): + @property + def active_obs(self): + return np.hstack([ + [False] * 17, + [True] # goal pos + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray]: + return self.env.sim.data.qpos[3:6].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[3:6].copy() + + @property + def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: + raise ValueError("Goal position is not available and has to be learnt based on the environment.") + + @property + def dt(self) -> Union[float, int]: + return self.env.dt diff --git a/alr_envs/alr/mujoco/walker_2d_jump/__init__.py b/alr_envs/alr/mujoco/walker_2d_jump/__init__.py new file mode 100644 index 0000000..989b5a9 --- /dev/null +++ b/alr_envs/alr/mujoco/walker_2d_jump/__init__.py @@ -0,0 +1 @@ +from .mp_wrapper import MPWrapper \ No newline at end of file diff --git a/alr_envs/alr/mujoco/walker_2d_jump/assets/walker2d.xml b/alr_envs/alr/mujoco/walker_2d_jump/assets/walker2d.xml new file mode 100644 index 0000000..1b48e36 --- /dev/null +++ b/alr_envs/alr/mujoco/walker_2d_jump/assets/walker2d.xml @@ -0,0 +1,62 @@ + + + + + + + \ No newline at end of file diff --git a/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py b/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py new file mode 100644 index 0000000..445fa40 --- /dev/null +++ b/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py @@ -0,0 +1,30 @@ +from typing import Tuple, Union + +import numpy as np + +from mp_env_api import MPEnvWrapper + + +class MPWrapper(MPEnvWrapper): + @property + def active_obs(self): + return np.hstack([ + [False] * 17, + [True] # goal pos + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray]: + return self.env.sim.data.qpos[3:9].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[3:9].copy() + + @property + def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: + raise ValueError("Goal position is not available and has to be learnt based on the environment.") + + @property + def dt(self) -> Union[float, int]: + return self.env.dt diff --git a/alr_envs/alr/mujoco/walker_2d_jump/walker_2d_jump.py b/alr_envs/alr/mujoco/walker_2d_jump/walker_2d_jump.py new file mode 100644 index 0000000..009dd9d --- /dev/null +++ b/alr_envs/alr/mujoco/walker_2d_jump/walker_2d_jump.py @@ -0,0 +1,113 @@ +import os +from gym.envs.mujoco.walker2d_v3 import Walker2dEnv +import numpy as np + +MAX_EPISODE_STEPS_WALKERJUMP = 300 + + +class ALRWalker2dJumpEnv(Walker2dEnv): + """ + healthy reward 1.0 -> 0.005 -> 0.0025 not from alex + penalty 10 -> 0 not from alex + """ + + def __init__(self, + xml_file='walker2d.xml', + forward_reward_weight=1.0, + ctrl_cost_weight=1e-3, + healthy_reward=0.0025, + terminate_when_unhealthy=True, + healthy_z_range=(0.8, 2.0), + healthy_angle_range=(-1.0, 1.0), + reset_noise_scale=5e-3, + penalty=0, + context=True, + exclude_current_positions_from_observation=True, + max_episode_steps=300): + self.current_step = 0 + self.max_episode_steps = max_episode_steps + self.max_height = 0 + self._penalty = penalty + self.context = context + self.goal = 0 + xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) + super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, + healthy_z_range, healthy_angle_range, reset_noise_scale, + exclude_current_positions_from_observation) + + def step(self, action): + self.current_step += 1 + self.do_simulation(action, self.frame_skip) + #pos_after = self.get_body_com("torso")[0] + height = self.get_body_com("torso")[2] + + self.max_height = max(height, self.max_height) + + fell_over = height < 0.2 + done = fell_over + + ctrl_cost = self.control_cost(action) + costs = ctrl_cost + + if self.current_step >= self.max_episode_steps or done: + done = True + height_goal_distance = -10 * (np.linalg.norm(self.max_height - self.goal)) if self.context else self.max_height + healthy_reward = self.healthy_reward * self.current_step + + rewards = height_goal_distance + healthy_reward + else: + # penalty not needed + rewards = 0 + rewards += ((action[:2] > 0) * self._penalty).sum() if self.current_step < 4 else 0 + rewards += ((action[3:5] > 0) * self._penalty).sum() if self.current_step < 4 else 0 + + + observation = self._get_obs() + reward = rewards - costs + info = { + 'height': height, + 'max_height': self.max_height, + 'goal' : self.goal, + } + + return observation, reward, done, info + + def _get_obs(self): + return np.append(super()._get_obs(), self.goal) + + def reset(self): + self.current_step = 0 + self.max_height = 0 + self.goal = np.random.uniform(1.5, 2.5, 1) # 1.5 3.0 + return super().reset() + + # overwrite reset_model to make it deterministic + def reset_model(self): + noise_low = -self._reset_noise_scale + noise_high = self._reset_noise_scale + + qpos = self.init_qpos # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + qvel = self.init_qvel # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) + + self.set_state(qpos, qvel) + + observation = self._get_obs() + return observation + +if __name__ == '__main__': + render_mode = "human" # "human" or "partial" or "final" + env = ALRWalker2dJumpEnv() + obs = env.reset() + + for i in range(2000): + # objective.load_result("/tmp/cma") + # test with random actions + ac = env.action_space.sample() + obs, rew, d, info = env.step(ac) + if i % 10 == 0: + env.render(mode=render_mode) + if d: + print('After ', i, ' steps, done: ', d) + env.reset() + + env.close() \ No newline at end of file From 1c9019ab083622e200732711faba94b5da9f2be3 Mon Sep 17 00:00:00 2001 From: Onur Date: Wed, 20 Apr 2022 10:50:41 +0200 Subject: [PATCH 014/104] added non-contextual envs --- alr_envs/alr/__init__.py | 430 +++++++++++++++++++++++---------------- 1 file changed, 253 insertions(+), 177 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index e435fa6..1b3f118 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -192,69 +192,150 @@ register( } ) - +# CtxtFree are v0, Contextual are v1 register( id='ALRAntJump-v0', entry_point='alr_envs.alr.mujoco:ALRAntJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_ANTJUMP, kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_ANTJUMP + "max_episode_steps": MAX_EPISODE_STEPS_ANTJUMP, + "context": False } ) +# CtxtFree are v0, Contextual are v1 +register( + id='ALRAntJump-v1', + entry_point='alr_envs.alr.mujoco:ALRAntJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_ANTJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_ANTJUMP, + "context": True + } +) + +# CtxtFree are v0, Contextual are v1 register( id='ALRHalfCheetahJump-v0', entry_point='alr_envs.alr.mujoco:ALRHalfCheetahJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HALFCHEETAHJUMP, kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HALFCHEETAHJUMP + "max_episode_steps": MAX_EPISODE_STEPS_HALFCHEETAHJUMP, + "context": False } ) - +# CtxtFree are v0, Contextual are v1 +register( + id='ALRHalfCheetahJump-v1', + entry_point='alr_envs.alr.mujoco:ALRHalfCheetahJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_HALFCHEETAHJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HALFCHEETAHJUMP, + "context": True + } +) +# CtxtFree are v0, Contextual are v1 register( id='ALRHopperJump-v0', entry_point='alr_envs.alr.mujoco:ALRHopperJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, + "context": False } ) - +register( + id='ALRHopperJump-v1', + entry_point='alr_envs.alr.mujoco:ALRHopperJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, + "context": True + } +) +# CtxtFree are v0, Contextual are v1 register( id='ALRHopperJumpOnBox-v0', entry_point='alr_envs.alr.mujoco:ALRHopperJumpOnBoxEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMPONBOX, kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMPONBOX + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMPONBOX, + "context": False } ) +# CtxtFree are v0, Contextual are v1 +register( + id='ALRHopperJumpOnBox-v1', + entry_point='alr_envs.alr.mujoco:ALRHopperJumpOnBoxEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMPONBOX, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMPONBOX, + "context": True + } +) +# CtxtFree are v0, Contextual are v1 register( id='ALRHopperThrow-v0', entry_point='alr_envs.alr.mujoco:ALRHopperThrowEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROW, kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROW + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROW, + "context": False } ) +# CtxtFree are v0, Contextual are v1 +register( + id='ALRHopperThrow-v1', + entry_point='alr_envs.alr.mujoco:ALRHopperThrowEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROW, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROW, + "context": True + } +) +# CtxtFree are v0, Contextual are v1 register( id='ALRHopperThrowInBasket-v0', entry_point='alr_envs.alr.mujoco:ALRHopperThrowInBasketEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROWINBASKET + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, + "context": False } ) - +# CtxtFree are v0, Contextual are v1 +register( + id='ALRHopperThrowInBasket-v1', + entry_point='alr_envs.alr.mujoco:ALRHopperThrowInBasketEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, + "context": True + } +) +# CtxtFree are v0, Contextual are v1 register( id='ALRWalker2DJump-v0', entry_point='alr_envs.alr.mujoco:ALRWalker2dJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_WALKERJUMP, kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_WALKERJUMP + "max_episode_steps": MAX_EPISODE_STEPS_WALKERJUMP, + "context": False } ) +# CtxtFree are v0, Contextual are v1 +register( + id='ALRWalker2DJump-v1', + entry_point='alr_envs.alr.mujoco:ALRWalker2dJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_WALKERJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_WALKERJUMP, + "context": True + } +) + ## Balancing Reacher register( @@ -502,203 +583,198 @@ for _v, cd in enumerate(ctxt_dim): ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - ## AntJump -for _v, cd in enumerate(ctxt_dim): - _env_id = f'TableTennisProMP-v{_v}' +_versions = ["v0", "v1"] +for _v in _versions: + _env_id = f'ALRAntJumpProMP-{_v}' register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', kwargs={ - "name": "alr_envs:TableTennis{}DCtxt-v0".format(cd), - "wrappers": [mujoco.table_tennis.MPWrapper], + "name": f"alr_envs:ALRAntJump-{_v}", + "wrappers": [mujoco.ant_jump.MPWrapper], "mp_kwargs": { - "num_dof": 7, - "num_basis": 2, - "duration": 1.25, - "post_traj_time": 1.5, + "num_dof": 8, + "num_basis": 5, + "duration": 10, + "post_traj_time": 0, "policy_type": "motor", "weights_scale": 1.0, "zero_start": True, "zero_goal": False, "policy_kwargs": { - "p_gains": 0.5*np.array([1.0, 4.0, 2.0, 4.0, 1.0, 4.0, 1.0]), - "d_gains": 0.5*np.array([0.1, 0.4, 0.2, 0.4, 0.1, 0.4, 0.1]) + "p_gains": np.ones(8), + "d_gains": 0.1*np.ones(8) } } } ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -register( - id='ALRAntJumpProMP-v0', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": "alr_envs:ALRAntJump-v0", - "wrappers": [mujoco.ant_jump.MPWrapper], - "mp_kwargs": { - "num_dof": 8, - "num_basis": 5, - "duration": 10, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(8), - "d_gains": 0.1*np.ones(8) +## HalfCheetahJump +_versions = ["v0", "v1"] +for _v in _versions: + _env_id = f'ALRHalfCheetahJumpProMP-{_v}' + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": f"alr_envs:ALRHalfCheetahJump-{_v}", + "wrappers": [mujoco.half_cheetah_jump.MPWrapper], + "mp_kwargs": { + "num_dof": 6, + "num_basis": 5, + "duration": 5, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(6), + "d_gains": 0.1*np.ones(6) + } } } - } -) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRAntJumpProMP-v0') + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) -register( - id='ALRHalfCheetahJumpProMP-v0', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": "alr_envs:ALRHalfCheetahJump-v0", - "wrappers": [mujoco.half_cheetah_jump.MPWrapper], - "mp_kwargs": { - "num_dof": 6, - "num_basis": 5, - "duration": 5, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(6), - "d_gains": 0.1*np.ones(6) +## HopperJump +_versions = ["v0", "v1"] +for _v in _versions: + _env_id = f'ALRHopperJumpProMP-{_v}' + register( + id= _env_id, + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": f"alr_envs:ALRHopperJump-{_v}", + "wrappers": [mujoco.hopper_jump.MPWrapper], + "mp_kwargs": { + "num_dof": 3, + "num_basis": 5, + "duration": 2, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(3), + "d_gains": 0.1*np.ones(3) + } } } - } -) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRHalfCheetahJumpProMP-v0') + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -register( - id='ALRHopperJumpProMP-v0', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": "alr_envs:ALRHopperJump-v0", - "wrappers": [mujoco.hopper_jump.MPWrapper], - "mp_kwargs": { - "num_dof": 3, - "num_basis": 5, - "duration": 2, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3) +## HopperJumpOnBox +_versions = ["v0", "v1"] +for _v in _versions: + _env_id = f'ALRHopperJumpOnBoxProMP-{_v}' + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": f"alr_envs:ALRHopperJumpOnBox-{_v}", + "wrappers": [mujoco.hopper_jump.MPWrapper], + "mp_kwargs": { + "num_dof": 3, + "num_basis": 5, + "duration": 2, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(3), + "d_gains": 0.1*np.ones(3) + } } } - } -) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRHopperJumpProMP-v0') + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) -register( - id='ALRHopperJumpOnBoxProMP-v0', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": "alr_envs:ALRHopperJumpOnBox-v0", - "wrappers": [mujoco.hopper_jump.MPWrapper], - "mp_kwargs": { - "num_dof": 3, - "num_basis": 5, - "duration": 2, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3) +#HopperThrow +_versions = ["v0", "v1"] +for _v in _versions: + _env_id = f'ALRHopperThrowProMP-{_v}' + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": f"alr_envs:ALRHopperThrow-{_v}", + "wrappers": [mujoco.hopper_throw.MPWrapper], + "mp_kwargs": { + "num_dof": 3, + "num_basis": 5, + "duration": 2, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(3), + "d_gains": 0.1*np.ones(3) + } } } - } -) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRHopperJumpOnBoxProMP-v0') + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -register( - id='ALRHopperThrowProMP-v0', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": "alr_envs:ALRHopperThrow-v0", - "wrappers": [mujoco.hopper_throw.MPWrapper], - "mp_kwargs": { - "num_dof": 3, - "num_basis": 5, - "duration": 2, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3) +## HopperThrowInBasket +_versions = ["v0", "v1"] +for _v in _versions: + _env_id = f'ALRHopperThrowInBasketProMP-{_v}' + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": f"alr_envs:ALRHopperThrowInBasket-{_v}", + "wrappers": [mujoco.hopper_throw.MPWrapper], + "mp_kwargs": { + "num_dof": 3, + "num_basis": 5, + "duration": 2, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(3), + "d_gains": 0.1*np.ones(3) + } } } - } -) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRHopperThrowProMP-v0') + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -register( - id='ALRHopperThrowInBasketProMP-v0', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": "alr_envs:ALRHopperThrowInBasket-v0", - "wrappers": [mujoco.hopper_throw.MPWrapper], - "mp_kwargs": { - "num_dof": 3, - "num_basis": 5, - "duration": 2, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3) +## Walker2DJump +_versions = ["v0", "v1"] +for _v in _versions: + _env_id = f'ALRWalker2DJumpProMP-{_v}' + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": f"alr_envs:ALRWalker2DJump-{_v}", + "wrappers": [mujoco.walker_2d_jump.MPWrapper], + "mp_kwargs": { + "num_dof": 6, + "num_basis": 5, + "duration": 2.4, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(6), + "d_gains": 0.1*np.ones(6) + } } } - } -) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRHopperThrowInBasketProMP-v0') - - -register( - id='ALRWalker2DJumpProMP-v0', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": "alr_envs:ALRWalker2DJump-v0", - "wrappers": [mujoco.walker_2d_jump.MPWrapper], - "mp_kwargs": { - "num_dof": 6, - "num_basis": 5, - "duration": 2.4, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(6), - "d_gains": 0.1*np.ones(6) - } - } - } -) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append('ALRWalker2DJumpProMP-v0') + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) From 855ddcee4b119c25f43a657a50d547f86018e3a0 Mon Sep 17 00:00:00 2001 From: Onur Date: Wed, 20 Apr 2022 14:50:02 +0200 Subject: [PATCH 015/104] hopperjump-v2 -> init pos randomized --- alr_envs/alr/__init__.py | 34 +++++++++++++ alr_envs/alr/mujoco/__init__.py | 2 +- alr_envs/alr/mujoco/hopper_jump/__init__.py | 2 +- .../alr/mujoco/hopper_jump/hopper_jump.py | 48 +++++++++++++++++++ alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py | 26 ++++++++++ 5 files changed, 110 insertions(+), 2 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 1b3f118..91881f0 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -253,6 +253,15 @@ register( "context": True } ) + +register( + id='ALRHopperJump-v2', + entry_point='alr_envs.alr.mujoco:ALRHopperJumpRndmPosEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP + } +) # CtxtFree are v0, Contextual are v1 register( id='ALRHopperJumpOnBox-v0', @@ -667,6 +676,31 @@ for _v in _versions: ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) +## HopperJump +register( + id= "ALRHopperJumpProMP-v2", + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": f"alr_envs:ALRHopperJump-v2", + "wrappers": [mujoco.hopper_jump.HighCtxtMPWrapper], + "mp_kwargs": { + "num_dof": 3, + "num_basis": 5, + "duration": 2, + "post_traj_time": 0, + "policy_type": "motor", + "weights_scale": 1.0, + "zero_start": True, + "zero_goal": False, + "policy_kwargs": { + "p_gains": np.ones(3), + "d_gains": 0.1*np.ones(3) + } + } + } +) +ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ALRHopperJumpProMP-v2") + ## HopperJumpOnBox _versions = ["v0", "v1"] for _v in _versions: diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index 8935db4..df71924 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -6,7 +6,7 @@ from .table_tennis.tt_gym import TTEnvGym from .beerpong.beerpong import ALRBeerBongEnv from .ant_jump.ant_jump import ALRAntJumpEnv from .half_cheetah_jump.half_cheetah_jump import ALRHalfCheetahJumpEnv -from .hopper_jump.hopper_jump import ALRHopperJumpEnv +from .hopper_jump.hopper_jump import ALRHopperJumpEnv, ALRHopperJumpRndmPosEnv from .hopper_jump.hopper_jump_on_box import ALRHopperJumpOnBoxEnv from .hopper_throw.hopper_throw import ALRHopperThrowEnv from .hopper_throw.hopper_throw_in_basket import ALRHopperThrowInBasketEnv diff --git a/alr_envs/alr/mujoco/hopper_jump/__init__.py b/alr_envs/alr/mujoco/hopper_jump/__init__.py index c5e6d2f..c6db9c2 100644 --- a/alr_envs/alr/mujoco/hopper_jump/__init__.py +++ b/alr_envs/alr/mujoco/hopper_jump/__init__.py @@ -1 +1 @@ -from .mp_wrapper import MPWrapper +from .mp_wrapper import MPWrapper, HighCtxtMPWrapper diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index 7ce8196..4047d04 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -91,6 +91,54 @@ class ALRHopperJumpEnv(HopperEnv): observation = self._get_obs() return observation + +class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): + def __init__(self, max_episode_steps=250): + super(ALRHopperJumpRndmPosEnv, self).__init__(exclude_current_positions_from_observation=False, + reset_noise_scale=5e-1, + max_episode_steps=max_episode_steps) + def reset_model(self): + noise_low = -self._reset_noise_scale + noise_high = self._reset_noise_scale + + qpos = self.init_qpos + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + qvel = self.init_qvel #+ self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) + + self.set_state(qpos, qvel) + + observation = self._get_obs() + return observation + + def step(self, action): + + self.current_step += 1 + self.do_simulation(action, self.frame_skip) + height_after = self.get_body_com("torso")[2] + self.max_height = max(height_after, self.max_height) + + ctrl_cost = self.control_cost(action) + costs = ctrl_cost + done = False + + if self.current_step >= self.max_episode_steps: + healthy_reward = 0 + height_reward = self._forward_reward_weight * self.max_height # maybe move reward calculation into if structure and define two different _forward_reward_weight variables for context and episodic seperatley + rewards = height_reward + healthy_reward + + else: + # penalty for wrong start direction of first two joints; not needed, could be removed + rewards = ((action[:2] > 0) * self.penalty).sum() if self.current_step < 10 else 0 + + observation = self._get_obs() + reward = rewards - costs + info = { + 'height': height_after, + 'max_height': self.max_height, + 'goal': self.goal + } + + return observation, reward, done, info + if __name__ == '__main__': render_mode = "human" # "human" or "partial" or "final" env = ALRHopperJumpEnv() diff --git a/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py b/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py index 0d6768c..36b7158 100644 --- a/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py @@ -29,3 +29,29 @@ class MPWrapper(MPEnvWrapper): @property def dt(self) -> Union[float, int]: return self.env.dt + + +class HighCtxtMPWrapper(MPWrapper): + @property + def active_obs(self): + return np.hstack([ + [True] * (5 + int(not self.exclude_current_positions_from_observation)), # position + [False] * 6, # velocity + [False] + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray]: + return self.env.sim.data.qpos[3:6].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[3:6].copy() + + @property + def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: + raise ValueError("Goal position is not available and has to be learnt based on the environment.") + + @property + def dt(self) -> Union[float, int]: + return self.env.dt From 77927e91573a9e517acbaf1c1c4a1459787116b0 Mon Sep 17 00:00:00 2001 From: Onur Date: Wed, 20 Apr 2022 17:51:43 +0200 Subject: [PATCH 016/104] improve randomization hopperjump-v2 --- alr_envs/alr/mujoco/hopper_jump/hopper_jump.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index 4047d04..a1e8990 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -100,8 +100,11 @@ class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): def reset_model(self): noise_low = -self._reset_noise_scale noise_high = self._reset_noise_scale - - qpos = self.init_qpos + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + rnd_vec = self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + rnd_vec[2] *= 0.05 # the angle around the y axis shouldn't be too high as the agent then falls down quickly and + # can not recover + rnd_vec[1] = np.clip(rnd_vec[1], 0, 0.3) + qpos = self.init_qpos + rnd_vec qvel = self.init_qvel #+ self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) self.set_state(qpos, qvel) From c0502cf1d4b2f37e7adcc27ab1607681be45f426 Mon Sep 17 00:00:00 2001 From: Onur Date: Thu, 21 Apr 2022 08:44:13 +0200 Subject: [PATCH 017/104] corrected reward for hopperjumprndminit + ALRReacher for iLQR --- alr_envs/alr/__init__.py | 11 +++++++ alr_envs/alr/mujoco/__init__.py | 2 +- .../alr/mujoco/hopper_jump/hopper_jump.py | 29 ++++++++++++++++--- alr_envs/alr/mujoco/reacher/alr_reacher.py | 21 ++++++++++++++ 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 91881f0..8f37f78 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -148,6 +148,17 @@ register( } ) +register( + id='ALRReacherSparseOptCtrl-v0', + entry_point='alr_envs.alr.mujoco:ALRReacherOptCtrlEnv', + max_episode_steps=200, + kwargs={ + "steps_before_reward": 200, + "n_links": 5, + "balance": False, + } +) + register( id='ALRReacherSparseBalanced-v0', entry_point='alr_envs.alr.mujoco:ALRReacherEnv', diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index df71924..9c7eecf 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -1,4 +1,4 @@ -from .reacher.alr_reacher import ALRReacherEnv +from .reacher.alr_reacher import ALRReacherEnv, ALRReacherOptCtrlEnv from .reacher.balancing import BalancingEnv from .ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv from .ball_in_a_cup.biac_pd import ALRBallInACupPDEnv diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index a1e8990..e76cf4f 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -94,10 +94,16 @@ class ALRHopperJumpEnv(HopperEnv): class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): def __init__(self, max_episode_steps=250): + self.contact_with_floor = False + self._floor_geom_id = None + self._foot_geom_id = None super(ALRHopperJumpRndmPosEnv, self).__init__(exclude_current_positions_from_observation=False, reset_noise_scale=5e-1, max_episode_steps=max_episode_steps) + def reset_model(self): + self._floor_geom_id = self.model.geom_name2id('floor') + self._foot_geom_id = self.model.geom_name2id('foot_geom') noise_low = -self._reset_noise_scale noise_high = self._reset_noise_scale rnd_vec = self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) @@ -116,8 +122,12 @@ class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): self.current_step += 1 self.do_simulation(action, self.frame_skip) + + self.contact_with_floor = self._contact_checker(self._floor_geom_id, self._foot_geom_id) if not \ + self.contact_with_floor else True + height_after = self.get_body_com("torso")[2] - self.max_height = max(height_after, self.max_height) + self.max_height = max(height_after, self.max_height) if self.contact_with_floor else 0 ctrl_cost = self.control_cost(action) costs = ctrl_cost @@ -142,9 +152,19 @@ class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): return observation, reward, done, info + def _contact_checker(self, id_1, id_2): + for coni in range(0, self.sim.data.ncon): + con = self.sim.data.contact[coni] + collision = con.geom1 == id_1 and con.geom2 == id_2 + collision_trans = con.geom1 == id_2 and con.geom2 == id_1 + if collision or collision_trans: + return True + return False + if __name__ == '__main__': render_mode = "human" # "human" or "partial" or "final" - env = ALRHopperJumpEnv() + # env = ALRHopperJumpEnv() + env = ALRHopperJumpRndmPosEnv() obs = env.reset() for i in range(2000): @@ -152,8 +172,9 @@ if __name__ == '__main__': # test with random actions ac = env.action_space.sample() obs, rew, d, info = env.step(ac) - if i % 10 == 0: - env.render(mode=render_mode) + # if i % 10 == 0: + # env.render(mode=render_mode) + env.render(mode=render_mode) if d: print('After ', i, ' steps, done: ', d) env.reset() diff --git a/alr_envs/alr/mujoco/reacher/alr_reacher.py b/alr_envs/alr/mujoco/reacher/alr_reacher.py index 2d122d2..42fe5a7 100644 --- a/alr_envs/alr/mujoco/reacher/alr_reacher.py +++ b/alr_envs/alr/mujoco/reacher/alr_reacher.py @@ -87,6 +87,27 @@ class ALRReacherEnv(MujocoEnv, utils.EzPickle): [self._steps], ]) +class ALRReacherOptCtrlEnv(ALRReacherEnv): + def __init__(self, steps_before_reward=200, n_links=5, balance=False): + super(ALRReacherOptCtrlEnv, self).__init__(steps_before_reward, n_links, balance) + self.goal = np.array([0.1, 0.1]) + + def _get_obs(self): + theta = self.sim.data.qpos.flat[:self.n_links] + return np.concatenate([ + theta, + self.sim.data.qvel.flat[:self.n_links], # this is angular velocity + ]) + + def reset_model(self): + qpos = self.init_qpos + qpos[-2:] = self.goal + qvel = self.init_qvel + qvel[-2:] = 0 + self.set_state(qpos, qvel) + self._steps = 0 + + return self._get_obs() if __name__ == '__main__': nl = 5 From a9460f15fd7737eb7649e5f6710a78d3cc63c4ec Mon Sep 17 00:00:00 2001 From: Onur Date: Fri, 22 Apr 2022 15:36:19 +0200 Subject: [PATCH 018/104] fix small reacher issues for optimal control --- alr_envs/alr/mujoco/reacher/alr_reacher.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/alr_envs/alr/mujoco/reacher/alr_reacher.py b/alr_envs/alr/mujoco/reacher/alr_reacher.py index 42fe5a7..74cff4d 100644 --- a/alr_envs/alr/mujoco/reacher/alr_reacher.py +++ b/alr_envs/alr/mujoco/reacher/alr_reacher.py @@ -89,12 +89,14 @@ class ALRReacherEnv(MujocoEnv, utils.EzPickle): class ALRReacherOptCtrlEnv(ALRReacherEnv): def __init__(self, steps_before_reward=200, n_links=5, balance=False): - super(ALRReacherOptCtrlEnv, self).__init__(steps_before_reward, n_links, balance) self.goal = np.array([0.1, 0.1]) + super(ALRReacherOptCtrlEnv, self).__init__(steps_before_reward, n_links, balance) def _get_obs(self): theta = self.sim.data.qpos.flat[:self.n_links] + tip_pos = self.get_body_com("fingertip") return np.concatenate([ + tip_pos[:2], theta, self.sim.data.qvel.flat[:self.n_links], # this is angular velocity ]) From 7f64c975cd061159db1b1c365b3b513bf0ac8db3 Mon Sep 17 00:00:00 2001 From: Onur Date: Wed, 27 Apr 2022 16:15:17 +0200 Subject: [PATCH 019/104] shorter number of release steps for beerpong --- alr_envs/alr/__init__.py | 10 ++-- alr_envs/alr/mujoco/beerpong/beerpong.py | 7 ++- .../mujoco/beerpong/beerpong_reward_staged.py | 53 +++++++++++++++---- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 8f37f78..ac885fa 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -559,11 +559,13 @@ for _v in _versions: "mp_kwargs": { "num_dof": 7, "num_basis": 2, - "duration": 1, - "post_traj_time": 2, + # "duration": 1, + "duration": 0.5, + # "post_traj_time": 2, + "post_traj_time": 2.5, "policy_type": "motor", - # "weights_scale": 0.15, - "weights_scale": 1, + "weights_scale": 0.14, + # "weights_scale": 1, "zero_start": True, "zero_goal": False, "policy_kwargs": { diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index d885e78..f5d2bd8 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -41,9 +41,9 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.ball_id = 11 # self._release_step = 175 # time step of ball release - self._release_step = 130 # time step of ball release + # self._release_step = 130 # time step of ball release + self._release_step = 100 # time step of ball release - self.sim_time = 3 # seconds self.ep_length = 600 # based on 3 seconds with dt = 0.005 int(self.sim_time / self.dt) self.cup_table_id = 10 @@ -54,6 +54,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): reward_function = BeerPongReward self.reward_function = reward_function() + self.n_table_bounces_first = 0 MujocoEnv.__init__(self, self.xml_path, frame_skip) utils.EzPickle.__init__(self) @@ -75,6 +76,8 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): return self.sim.data.qvel[0:7].copy() def reset(self): + print(not self.reward_function.ball_ground_contact_first) + self.n_table_bounces_first += int(not self.reward_function.ball_ground_contact_first) self.reward_function.reset(self.add_noise) return super().reset() diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index c9ed451..24c48be 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -50,7 +50,7 @@ class BeerPongReward: self.angle_rewards = [] self.cup_angles = [] self.cup_z_axes = [] - self.ball_ground_contact = False + self.ball_ground_contact_first = False self.ball_table_contact = False self.ball_wall_contact = False self.ball_cup_contact = False @@ -150,8 +150,9 @@ class BeerPongReward: if env._steps == env.ep_length - 1 or self._is_collided: min_dist = np.min(self.dists) final_dist = self.dists_final[-1] - - # encourage bounce before falling into cup + # if self.ball_ground_contact_first: + # min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -6 + # else: if not self.ball_in_cup: if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact: min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -4 @@ -159,17 +160,47 @@ class BeerPongReward: min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -2 else: min_dist_coeff, final_dist_coeff, rew_offset = 0, 1, 0 - - reward = rew_offset - min_dist_coeff * min_dist**2 - final_dist_coeff * final_dist**2 - \ - 1e-4*np.mean(action_cost) - # 1e-7*np.mean(action_cost) + reward = rew_offset - min_dist_coeff * min_dist ** 2 - final_dist_coeff * final_dist ** 2 - \ + 1e-4 * np.mean(action_cost) + # 1e-7*np.mean(action_cost) success = self.ball_in_cup else: - # reward = - 1e-2 * action_cost - reward = - 1e-4 * action_cost + reward = - 1e-2 * action_cost + # reward = - 1e-4 * action_cost + # reward = 0 success = False # ################################################################################################################ + # # # ##################### Reward function which does not force to bounce once on the table (quad dist) ############ + # self._check_contacts(env.sim) + # self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) + # if env._steps == env.ep_length - 1 or self._is_collided: + # min_dist = np.min(self.dists) + # final_dist = self.dists_final[-1] + # + # if not self.ball_in_cup: + # if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact: + # min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -6 + # else: + # if self.ball_ground_contact_first: + # min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -4 + # else: + # min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -2 + # else: + # if self.ball_ground_contact_first: + # min_dist_coeff, final_dist_coeff, rew_offset = 0, 1, -1 + # else: + # min_dist_coeff, final_dist_coeff, rew_offset = 0, 1, 0 + # reward = rew_offset - min_dist_coeff * min_dist ** 2 - final_dist_coeff * final_dist ** 2 - \ + # 1e-7 * np.mean(action_cost) + # # 1e-4*np.mean(action_cost) + # success = self.ball_in_cup + # else: + # # reward = - 1e-2 * action_cost + # # reward = - 1e-4 * action_cost + # reward = 0 + # success = False + # ################################################################################################################ infos = {} infos["success"] = success infos["is_collided"] = self._is_collided @@ -193,6 +224,10 @@ class BeerPongReward: if not self.ball_in_cup: self.ball_in_cup = self._check_collision_single_objects(sim, self.ball_collision_id, self.cup_table_collision_id) + if not self.ball_ground_contact_first: + if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact and not self.ball_in_cup: + self.ball_ground_contact_first = self._check_collision_single_objects(sim, self.ball_collision_id, + self.ground_collision_id) def _check_collision_single_objects(self, sim, id_1, id_2): for coni in range(0, sim.data.ncon): From cd33e82d3c78f86950324c19c005f837e2ec6503 Mon Sep 17 00:00:00 2001 From: Onur Date: Thu, 28 Apr 2022 09:05:28 +0200 Subject: [PATCH 020/104] start integrating mp_pytorch lib --- alr_envs/alr/__init__.py | 7 + .../alr/mujoco/beerpong/new_mp_wrapper.py | 20 +++ alr_envs/alr/mujoco/reacher/new_mp_wrapper.py | 24 +++ mp_wrapper.py | 170 ++++++++++++++++++ policies.py | 129 +++++++++++++ 5 files changed, 350 insertions(+) create mode 100644 alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py create mode 100644 alr_envs/alr/mujoco/reacher/new_mp_wrapper.py create mode 100644 mp_wrapper.py create mode 100644 policies.py diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index ac885fa..3182b72 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -825,3 +825,10 @@ for _v in _versions: } ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + + +# --------------------- Testing new mp wrapper ----------------------------------------------------- + +# register( +# id='ALRReacherProMP-v0' +# ) \ No newline at end of file diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py new file mode 100644 index 0000000..ca2e17e --- /dev/null +++ b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py @@ -0,0 +1,20 @@ +from mp_wrapper import BaseMPWrapper +from typing import Union, Tuple +import numpy as np + + +class MPWrapper(BaseMPWrapper): + + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qpos[0:7].copy() + + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[0:7].copy() + + def set_active_obs(self): + return np.hstack([ + [False] * 7, # cos + [False] * 7, # sin + [True] * 2, # xy position of cup + [False] # env steps + ]) diff --git a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py new file mode 100644 index 0000000..43c8a51 --- /dev/null +++ b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py @@ -0,0 +1,24 @@ +from mp_wrapper import BaseMPWrapper +from typing import Union, Tuple +import numpy as np + + +class MPWrapper(BaseMPWrapper): + + @property + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qpos.flat[:self.env.n_links] + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel.flat[:self.env.n_links] + + def set_active_obs(self): + return np.concatenate([ + [False] * self.env.n_links, # cos + [False] * self.env.n_links, # sin + [True] * 2, # goal position + [False] * self.env.n_links, # angular velocity + [False] * 3, # goal distance + # self.get_body_com("target"), # only return target to make problem harder + [False], # step + ]) diff --git a/mp_wrapper.py b/mp_wrapper.py new file mode 100644 index 0000000..202082a --- /dev/null +++ b/mp_wrapper.py @@ -0,0 +1,170 @@ +from abc import ABC, abstractmethod +from typing import Union, Tuple + +import gym +import numpy as np + +from gym import spaces +from gym.envs.mujoco import MujocoEnv +from policies import get_policy_class, BaseController +from mp_pytorch.mp.mp_interfaces import MPInterface + + +class BaseMPWrapper(gym.Env, ABC): + """ + Base class for movement primitive based gym.Wrapper implementations. + + Args: + env: The (wrapped) environment this wrapper is applied on + num_dof: Dimension of the action space of the wrapped env + num_basis: Number of basis functions per dof + duration: Length of the trajectory of the movement primitive in seconds + post_traj_time: Time for which the last position of the trajectory is fed to the environment to continue + simulation in seconds + policy_type: Type or object defining the policy that is used to generate action based on the trajectory + weight_scale: Scaling parameter for the actions given to this wrapper + render_mode: Equivalent to gym render mode + + """ + + def __init__(self, + env: MujocoEnv, + mp: MPInterface, + duration: float, + policy_type: Union[str, BaseController] = None, + render_mode: str = None, + **mp_kwargs + ): + super().__init__() + + assert env.dt is not None + self.env = env + self.dt = env.dt + self.duration = duration + self.traj_steps = int(duration / self.dt) + self.post_traj_steps = self.env.spec.max_episode_steps - self.traj_steps + + if isinstance(policy_type, str): + # pop policy kwargs here such that they are not passed to the initialize_mp method + self.policy = get_policy_class(policy_type, self, **mp_kwargs.pop('policy_kwargs', {})) + else: + self.policy = policy_type + + self.mp = mp + self.env = env + + # rendering + self.render_mode = render_mode + self.render_kwargs = {} + self.time_steps = np.linspace(0, self.duration, self.traj_steps + 1) + self.mp.set_mp_times(self.time_steps) + + # TODO: put action bounds in mp wrapper (e.g. time bound for traj. length ...), otherwis learning the durations + # might not work + # action_bounds = np.inf * np.ones((np.prod(self.mp.num_params))) + min_action_bounds, max_action_bounds = mp.get_param_bounds() + self.action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), + dtype=np.float32) + + self.active_obs = self.set_active_obs() + self.observation_space = spaces.Box(low=self.env.observation_space.low[self.active_obs], + high=self.env.observation_space.high[self.active_obs], + dtype=self.env.observation_space.dtype) + + def get_trajectory(self, action: np.ndarray) -> Tuple: + self.mp.set_params(action) + traj_dict = self.mp.get_mp_trajs(get_pos = True, get_vel = True) + trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] + + trajectory = trajectory_tensor.numpy() + velocity = velocity_tensor.numpy() + if self.post_traj_steps > 0: + trajectory = np.vstack([trajectory, np.tile(trajectory[-1, :], [self.post_traj_steps, 1])]) + velocity = np.vstack([velocity, np.zeros(shape=(self.post_traj_steps, self.mp.num_dof))]) + + return trajectory, velocity + + @abstractmethod + def set_active_obs(self): + pass + + @property + @abstractmethod + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + """ + Returns the current position of the action/control dimension. + The dimensionality has to match the action/control dimension. + This is not required when exclusively using velocity control, + it should, however, be implemented regardless. + E.g. The joint positions that are directly or indirectly controlled by the action. + """ + raise NotImplementedError() + + @property + @abstractmethod + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + """ + Returns the current velocity of the action/control dimension. + The dimensionality has to match the action/control dimension. + This is not required when exclusively using position control, + it should, however, be implemented regardless. + E.g. The joint velocities that are directly or indirectly controlled by the action. + """ + raise NotImplementedError() + + def step(self, action: np.ndarray): + """ This function generates a trajectory based on a MP and then does the usual loop over reset and step""" + + + trajectory, velocity = self.get_trajectory(action) + + trajectory_length = len(trajectory) + actions = np.zeros(shape=(trajectory_length,) + self.env.action_space.shape) + if isinstance(self.env.observation_space, spaces.Dict): # For goal environments + observations = np.zeros(shape=(trajectory_length,) + self.env.observation_space["observation"].shape, + dtype=self.env.observation_space.dtype) + else: + observations = np.zeros(shape=(trajectory_length,) + self.env.observation_space.shape, + dtype=self.env.observation_space.dtype) + rewards = np.zeros(shape=(trajectory_length,)) + trajectory_return = 0 + + infos = dict() + + for t, pos_vel in enumerate(zip(trajectory, velocity)): + ac = self.policy.get_action(pos_vel[0], pos_vel[1]) + actions[t, :] = np.clip(ac, self.env.action_space.low, self.env.action_space.high) + obs, rewards[t], done, info = self.env.step(actions[t, :]) + observations[t, :] = obs["observation"] if isinstance(self.env.observation_space, spaces.Dict) else obs + trajectory_return += rewards[t] + for k, v in info.items(): + elems = infos.get(k, [None] * trajectory_length) + elems[t] = v + infos[k] = elems + # infos['step_infos'].append(info) + if self.render_mode: + self.render(mode=self.render_mode, **self.render_kwargs) + if done: + break + infos.update({k: v[:t + 1] for k, v in infos.items()}) + infos['trajectory'] = trajectory + infos['step_actions'] = actions[:t + 1] + infos['step_observations'] = observations[:t + 1] + infos['step_rewards'] = rewards[:t + 1] + infos['trajectory_length'] = t + 1 + done = True + return self.get_observation_from_step(observations[t]), trajectory_return, done, infos + + def reset(self): + return self.get_observation_from_step(self.env.reset()) + + def render(self, mode='human', **kwargs): + """Only set render options here, such that they can be used during the rollout. + This only needs to be called once""" + self.render_mode = mode + self.render_kwargs = kwargs + # self.env.render(mode=self.render_mode, **self.render_kwargs) + self.env.render(mode=self.render_mode) + + def get_observation_from_step(self, observation: np.ndarray) -> np.ndarray: + return observation[self.active_obs] diff --git a/policies.py b/policies.py new file mode 100644 index 0000000..fd89f9e --- /dev/null +++ b/policies.py @@ -0,0 +1,129 @@ +from typing import Tuple, Union + +import numpy as np + + + +class BaseController: + def __init__(self, env, **kwargs): + self.env = env + + def get_action(self, des_pos, des_vel): + raise NotImplementedError + + +class PosController(BaseController): + """ + A Position Controller. The controller calculates a response only based on the desired position. + """ + def get_action(self, des_pos, des_vel): + return des_pos + + +class VelController(BaseController): + """ + A Velocity Controller. The controller calculates a response only based on the desired velocity. + """ + def get_action(self, des_pos, des_vel): + return des_vel + + +class PDController(BaseController): + """ + A PD-Controller. Using position and velocity information from a provided environment, + the controller calculates a response based on the desired position and velocity + + :param env: A position environment + :param p_gains: Factors for the proportional gains + :param d_gains: Factors for the differential gains + """ + + def __init__(self, + env, + p_gains: Union[float, Tuple], + d_gains: Union[float, Tuple]): + self.p_gains = p_gains + self.d_gains = d_gains + super(PDController, self).__init__(env) + + def get_action(self, des_pos, des_vel): + cur_pos = self.env.current_pos + cur_vel = self.env.current_vel + assert des_pos.shape == cur_pos.shape, \ + f"Mismatch in dimension between desired position {des_pos.shape} and current position {cur_pos.shape}" + assert des_vel.shape == cur_vel.shape, \ + f"Mismatch in dimension between desired velocity {des_vel.shape} and current velocity {cur_vel.shape}" + trq = self.p_gains * (des_pos - cur_pos) + self.d_gains * (des_vel - cur_vel) + return trq + + +class MetaWorldController(BaseController): + """ + A Metaworld Controller. Using position and velocity information from a provided environment, + the controller calculates a response based on the desired position and velocity. + Unlike the other Controllers, this is a special controller for MetaWorld environments. + They use a position delta for the xyz coordinates and a raw position for the gripper opening. + + :param env: A position environment + """ + + def __init__(self, + env + ): + super(MetaWorldController, self).__init__(env) + + def get_action(self, des_pos, des_vel): + gripper_pos = des_pos[-1] + + cur_pos = self.env.current_pos[:-1] + xyz_pos = des_pos[:-1] + + assert xyz_pos.shape == cur_pos.shape, \ + f"Mismatch in dimension between desired position {xyz_pos.shape} and current position {cur_pos.shape}" + trq = np.hstack([(xyz_pos - cur_pos), gripper_pos]) + return trq + + +#TODO: Do we need this class? +class PDControllerExtend(BaseController): + """ + A PD-Controller. Using position and velocity information from a provided positional environment, + the controller calculates a response based on the desired position and velocity + + :param env: A position environment + :param p_gains: Factors for the proportional gains + :param d_gains: Factors for the differential gains + """ + + def __init__(self, + env, + p_gains: Union[float, Tuple], + d_gains: Union[float, Tuple]): + + self.p_gains = p_gains + self.d_gains = d_gains + super(PDControllerExtend, self).__init__(env) + + def get_action(self, des_pos, des_vel): + cur_pos = self.env.current_pos + cur_vel = self.env.current_vel + if len(des_pos) != len(cur_pos): + des_pos = self.env.extend_des_pos(des_pos) + if len(des_vel) != len(cur_vel): + des_vel = self.env.extend_des_vel(des_vel) + trq = self.p_gains * (des_pos - cur_pos) + self.d_gains * (des_vel - cur_vel) + return trq + + +def get_policy_class(policy_type, env, **kwargs): + if policy_type == "motor": + return PDController(env, **kwargs) + elif policy_type == "velocity": + return VelController(env) + elif policy_type == "position": + return PosController(env) + elif policy_type == "metaworld": + return MetaWorldController(env) + else: + raise ValueError(f"Invalid controller type {policy_type} provided. Only 'motor', 'velocity', 'position' " + f"and 'metaworld are currently supported controllers.") From 137eb726eb4f2924eed8bd867cd83588c7e90f76 Mon Sep 17 00:00:00 2001 From: Onur Date: Fri, 29 Apr 2022 18:46:09 +0200 Subject: [PATCH 021/104] mp_pytorch now running with zero start/goal promp, but delay is not working --- alr_envs/alr/mujoco/reacher/alr_reacher.py | 9 +++-- alr_envs/alr/mujoco/reacher/new_mp_wrapper.py | 3 ++ mp_wrapper.py | 38 ++++++++++++++++--- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/alr_envs/alr/mujoco/reacher/alr_reacher.py b/alr_envs/alr/mujoco/reacher/alr_reacher.py index 74cff4d..4477a66 100644 --- a/alr_envs/alr/mujoco/reacher/alr_reacher.py +++ b/alr_envs/alr/mujoco/reacher/alr_reacher.py @@ -56,19 +56,22 @@ class ALRReacherEnv(MujocoEnv, utils.EzPickle): return ob, reward, done, dict(reward_dist=reward_dist, reward_ctrl=reward_ctrl, velocity=angular_vel, reward_balance=reward_balance, end_effector=self.get_body_com("fingertip").copy(), - goal=self.goal if hasattr(self, "goal") else None) + goal=self.goal if hasattr(self, "goal") else None, + joint_pos = self.sim.data.qpos.flat[:self.n_links].copy(), + joint_vel = self.sim.data.qvel.flat[:self.n_links].copy()) def viewer_setup(self): self.viewer.cam.trackbodyid = 0 def reset_model(self): - qpos = self.np_random.uniform(low=-0.1, high=0.1, size=self.model.nq) + self.init_qpos + # qpos = self.np_random.uniform(low=-0.1, high=0.1, size=self.model.nq) + self.init_qpos + qpos = self.init_qpos while True: self.goal = self.np_random.uniform(low=-self.n_links / 10, high=self.n_links / 10, size=2) if np.linalg.norm(self.goal) < self.n_links / 10: break qpos[-2:] = self.goal - qvel = self.init_qvel + self.np_random.uniform(low=-.005, high=.005, size=self.model.nv) + qvel = self.init_qvel# + self.np_random.uniform(low=-.005, high=.005, size=self.model.nv) qvel[-2:] = 0 self.set_state(qpos, qvel) self._steps = 0 diff --git a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py index 43c8a51..37499e6 100644 --- a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py @@ -22,3 +22,6 @@ class MPWrapper(BaseMPWrapper): # self.get_body_com("target"), # only return target to make problem harder [False], # step ]) + + def _step_callback(self, action): + pass \ No newline at end of file diff --git a/mp_wrapper.py b/mp_wrapper.py index 202082a..82b23bd 100644 --- a/mp_wrapper.py +++ b/mp_wrapper.py @@ -6,6 +6,7 @@ import numpy as np from gym import spaces from gym.envs.mujoco import MujocoEnv + from policies import get_policy_class, BaseController from mp_pytorch.mp.mp_interfaces import MPInterface @@ -24,7 +25,6 @@ class BaseMPWrapper(gym.Env, ABC): policy_type: Type or object defining the policy that is used to generate action based on the trajectory weight_scale: Scaling parameter for the actions given to this wrapper render_mode: Equivalent to gym render mode - """ def __init__(self, @@ -44,6 +44,7 @@ class BaseMPWrapper(gym.Env, ABC): self.traj_steps = int(duration / self.dt) self.post_traj_steps = self.env.spec.max_episode_steps - self.traj_steps + # TODO: move to constructer, use policy factory instead what Fabian already coded if isinstance(policy_type, str): # pop policy kwargs here such that they are not passed to the initialize_mp method self.policy = get_policy_class(policy_type, self, **mp_kwargs.pop('policy_kwargs', {})) @@ -56,11 +57,10 @@ class BaseMPWrapper(gym.Env, ABC): # rendering self.render_mode = render_mode self.render_kwargs = {} - self.time_steps = np.linspace(0, self.duration, self.traj_steps + 1) + # self.time_steps = np.linspace(0, self.duration, self.traj_steps + 1) + self.time_steps = np.linspace(0, self.duration, self.traj_steps) self.mp.set_mp_times(self.time_steps) - # TODO: put action bounds in mp wrapper (e.g. time bound for traj. length ...), otherwis learning the durations - # might not work # action_bounds = np.inf * np.ones((np.prod(self.mp.num_params))) min_action_bounds, max_action_bounds = mp.get_param_bounds() self.action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), @@ -73,11 +73,13 @@ class BaseMPWrapper(gym.Env, ABC): def get_trajectory(self, action: np.ndarray) -> Tuple: self.mp.set_params(action) + self.mp.set_boundary_conditions(bc_time=self.time_steps[:1], bc_pos=self.current_pos, bc_vel=self.current_vel) traj_dict = self.mp.get_mp_trajs(get_pos = True, get_vel = True) trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] trajectory = trajectory_tensor.numpy() velocity = velocity_tensor.numpy() + if self.post_traj_steps > 0: trajectory = np.vstack([trajectory, np.tile(trajectory[-1, :], [self.post_traj_steps, 1])]) velocity = np.vstack([velocity, np.zeros(shape=(self.post_traj_steps, self.mp.num_dof))]) @@ -112,10 +114,16 @@ class BaseMPWrapper(gym.Env, ABC): """ raise NotImplementedError() + @abstractmethod + def _step_callback(self, action): + pass + def step(self, action: np.ndarray): """ This function generates a trajectory based on a MP and then does the usual loop over reset and step""" - - + # TODO: Think about sequencing + # TODO: put in a callback function here which every environment can implement. Important for e.g. BP to allow the + # TODO: Reward Function rather here? + # agent to learn when to release the ball trajectory, velocity = self.get_trajectory(action) trajectory_length = len(trajectory) @@ -148,6 +156,7 @@ class BaseMPWrapper(gym.Env, ABC): break infos.update({k: v[:t + 1] for k, v in infos.items()}) infos['trajectory'] = trajectory + # TODO: remove step information? Might be relevant for debugging -> return only in debug mode (verbose)? infos['step_actions'] = actions[:t + 1] infos['step_observations'] = observations[:t + 1] infos['step_rewards'] = rewards[:t + 1] @@ -168,3 +177,20 @@ class BaseMPWrapper(gym.Env, ABC): def get_observation_from_step(self, observation: np.ndarray) -> np.ndarray: return observation[self.active_obs] + + def plot_trajs(self, des_trajs, des_vels): + import matplotlib.pyplot as plt + import matplotlib + matplotlib.use('TkAgg') + pos_fig = plt.figure('positions') + vel_fig = plt.figure('velocities') + for i in range(des_trajs.shape[1]): + plt.figure(pos_fig.number) + plt.subplot(des_trajs.shape[1], 1, i + 1) + plt.plot(np.ones(des_trajs.shape[0])*self.current_pos[i]) + plt.plot(des_trajs[:, i]) + + plt.figure(vel_fig.number) + plt.subplot(des_vels.shape[1], 1, i + 1) + plt.plot(np.ones(des_trajs.shape[0])*self.current_vel[i]) + plt.plot(des_vels[:, i]) From f33996c27afcb5592b6ce325c58c9f7373864c1b Mon Sep 17 00:00:00 2001 From: Onur Date: Mon, 2 May 2022 15:06:21 +0200 Subject: [PATCH 022/104] include callback in step --- alr_envs/alr/mujoco/reacher/new_mp_wrapper.py | 5 +---- mp_wrapper.py | 21 +++++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py index 37499e6..5475366 100644 --- a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py @@ -21,7 +21,4 @@ class MPWrapper(BaseMPWrapper): [False] * 3, # goal distance # self.get_body_com("target"), # only return target to make problem harder [False], # step - ]) - - def _step_callback(self, action): - pass \ No newline at end of file + ]) \ No newline at end of file diff --git a/mp_wrapper.py b/mp_wrapper.py index 82b23bd..3defe07 100644 --- a/mp_wrapper.py +++ b/mp_wrapper.py @@ -33,6 +33,7 @@ class BaseMPWrapper(gym.Env, ABC): duration: float, policy_type: Union[str, BaseController] = None, render_mode: str = None, + verbose=2, **mp_kwargs ): super().__init__() @@ -44,7 +45,7 @@ class BaseMPWrapper(gym.Env, ABC): self.traj_steps = int(duration / self.dt) self.post_traj_steps = self.env.spec.max_episode_steps - self.traj_steps - # TODO: move to constructer, use policy factory instead what Fabian already coded + # TODO: move to constructor, use policy factory instead what Fabian already coded if isinstance(policy_type, str): # pop policy kwargs here such that they are not passed to the initialize_mp method self.policy = get_policy_class(policy_type, self, **mp_kwargs.pop('policy_kwargs', {})) @@ -53,6 +54,7 @@ class BaseMPWrapper(gym.Env, ABC): self.mp = mp self.env = env + self.verbose = verbose # rendering self.render_mode = render_mode @@ -114,14 +116,12 @@ class BaseMPWrapper(gym.Env, ABC): """ raise NotImplementedError() - @abstractmethod - def _step_callback(self, action): + def _step_callback(self, t, action): pass def step(self, action: np.ndarray): """ This function generates a trajectory based on a MP and then does the usual loop over reset and step""" # TODO: Think about sequencing - # TODO: put in a callback function here which every environment can implement. Important for e.g. BP to allow the # TODO: Reward Function rather here? # agent to learn when to release the ball trajectory, velocity = self.get_trajectory(action) @@ -141,6 +141,9 @@ class BaseMPWrapper(gym.Env, ABC): for t, pos_vel in enumerate(zip(trajectory, velocity)): ac = self.policy.get_action(pos_vel[0], pos_vel[1]) + callback_action = self._step_callback(t, action) + if callback_action is not None: + ac = np.concatenate((callback_action, ac)) # include callback action at first pos of vector actions[t, :] = np.clip(ac, self.env.action_space.low, self.env.action_space.high) obs, rewards[t], done, info = self.env.step(actions[t, :]) observations[t, :] = obs["observation"] if isinstance(self.env.observation_space, spaces.Dict) else obs @@ -156,11 +159,11 @@ class BaseMPWrapper(gym.Env, ABC): break infos.update({k: v[:t + 1] for k, v in infos.items()}) infos['trajectory'] = trajectory - # TODO: remove step information? Might be relevant for debugging -> return only in debug mode (verbose)? - infos['step_actions'] = actions[:t + 1] - infos['step_observations'] = observations[:t + 1] - infos['step_rewards'] = rewards[:t + 1] - infos['trajectory_length'] = t + 1 + if self.verbose == 2: + infos['step_actions'] = actions[:t + 1] + infos['step_observations'] = observations[:t + 1] + infos['step_rewards'] = rewards[:t + 1] + infos['trajectory_length'] = t + 1 done = True return self.get_observation_from_step(observations[t]), trajectory_return, done, infos From 2fbde9fbb1e618e6734c81dd76dffc03c6226196 Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 3 May 2022 19:51:54 +0200 Subject: [PATCH 023/104] working bp version --- alr_envs/alr/__init__.py | 80 +++++++--- alr_envs/alr/mujoco/beerpong/__init__.py | 3 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 28 ++-- .../mujoco/beerpong/beerpong_reward_staged.py | 4 + .../alr/mujoco/beerpong/new_mp_wrapper.py | 30 +++- alr_envs/alr/mujoco/reacher/new_mp_wrapper.py | 4 +- alr_envs/examples/pd_control_gain_tuning.py | 2 +- alr_envs/mp/__init__.py | 0 alr_envs/mp/basis_generator_factory.py | 17 +++ alr_envs/mp/controllers/__init__.py | 0 alr_envs/mp/controllers/base_controller.py | 4 + alr_envs/mp/controllers/controller_factory.py | 21 +++ .../mp/controllers/meta_world_controller.py | 25 ++++ alr_envs/mp/controllers/pd_controller.py | 28 ++++ alr_envs/mp/controllers/pos_controller.py | 9 ++ alr_envs/mp/controllers/vel_controller.py | 9 ++ .../mp/episodic_wrapper.py | 137 +++++++++++------- alr_envs/mp/mp_factory.py | 22 +++ alr_envs/mp/phase_generator_factory.py | 20 +++ alr_envs/utils/make_env_helpers.py | 112 +++++++++++++- policies.py | 129 ----------------- 21 files changed, 460 insertions(+), 224 deletions(-) create mode 100644 alr_envs/mp/__init__.py create mode 100644 alr_envs/mp/basis_generator_factory.py create mode 100644 alr_envs/mp/controllers/__init__.py create mode 100644 alr_envs/mp/controllers/base_controller.py create mode 100644 alr_envs/mp/controllers/controller_factory.py create mode 100644 alr_envs/mp/controllers/meta_world_controller.py create mode 100644 alr_envs/mp/controllers/pd_controller.py create mode 100644 alr_envs/mp/controllers/pos_controller.py create mode 100644 alr_envs/mp/controllers/vel_controller.py rename mp_wrapper.py => alr_envs/mp/episodic_wrapper.py (57%) create mode 100644 alr_envs/mp/mp_factory.py create mode 100644 alr_envs/mp/phase_generator_factory.py delete mode 100644 policies.py diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 3182b72..f91e004 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -391,7 +391,8 @@ register( max_episode_steps=600, kwargs={ "rndm_goal": False, - "cup_goal_pos": [-0.3, -1.2] + "cup_goal_pos": [0.1, -2.0], + "learn_release_step": True } ) @@ -403,7 +404,8 @@ register( max_episode_steps=600, kwargs={ "rndm_goal": True, - "cup_goal_pos": [-0.3, -1.2] + "cup_goal_pos": [-0.3, -1.2], + "learn_release_step": True } ) @@ -546,34 +548,72 @@ for _v in _versions: ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) +# ## Beerpong +# _versions = ["v0", "v1"] +# for _v in _versions: +# _env_id = f'BeerpongProMP-{_v}' +# register( +# id=_env_id, +# entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', +# kwargs={ +# "name": f"alr_envs:ALRBeerPong-{_v}", +# "wrappers": [mujoco.beerpong.MPWrapper], +# "mp_kwargs": { +# "num_dof": 7, +# "num_basis": 2, +# # "duration": 1, +# "duration": 0.5, +# # "post_traj_time": 2, +# "post_traj_time": 2.5, +# "policy_type": "motor", +# "weights_scale": 0.14, +# # "weights_scale": 1, +# "zero_start": True, +# "zero_goal": False, +# "policy_kwargs": { +# "p_gains": np.array([ 1.5, 5, 2.55, 3, 2., 2, 1.25]), +# "d_gains": np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) +# } +# } +# } +# ) +# ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + ## Beerpong _versions = ["v0", "v1"] for _v in _versions: _env_id = f'BeerpongProMP-{_v}' register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', kwargs={ "name": f"alr_envs:ALRBeerPong-{_v}", - "wrappers": [mujoco.beerpong.MPWrapper], - "mp_kwargs": { - "num_dof": 7, - "num_basis": 2, - # "duration": 1, - "duration": 0.5, - # "post_traj_time": 2, - "post_traj_time": 2.5, - "policy_type": "motor", - "weights_scale": 0.14, - # "weights_scale": 1, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.array([ 1.5, 5, 2.55, 3, 2., 2, 1.25]), - "d_gains": np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) + "wrappers": [mujoco.beerpong.NewMPWrapper], + "ep_wrapper_kwargs": { + "weight_scale": 1 + }, + "movement_primitives_kwargs": { + 'movement_primitives_type': 'promp', + 'num_dof': 7 + }, + "phase_generator_kwargs": { + 'phase_generator_type': 'linear', + 'delay': 0, + 'tau': 0.8, # initial value + 'learn_tau': True, + 'learn_delay': False + }, + "controller_kwargs": { + 'controller_type': 'motor', + "p_gains": np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]), + "d_gains": np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]), + }, + "basis_generator_kwargs": { + 'basis_generator_type': 'zero_rbf', + 'num_basis': 2, + 'num_basis_zero_start': 2 } } - } ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) diff --git a/alr_envs/alr/mujoco/beerpong/__init__.py b/alr_envs/alr/mujoco/beerpong/__init__.py index 989b5a9..18e33ce 100644 --- a/alr_envs/alr/mujoco/beerpong/__init__.py +++ b/alr_envs/alr/mujoco/beerpong/__init__.py @@ -1 +1,2 @@ -from .mp_wrapper import MPWrapper \ No newline at end of file +from .mp_wrapper import MPWrapper +from .new_mp_wrapper import NewMPWrapper \ No newline at end of file diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index f5d2bd8..661d10c 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -3,6 +3,7 @@ import os import numpy as np from gym import utils +from gym import spaces from gym.envs.mujoco import MujocoEnv from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward @@ -17,7 +18,7 @@ CUP_POS_MAX = np.array([0.32, -1.2]) class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, - rndm_goal=False, cup_goal_pos=None): + rndm_goal=False, learn_release_step=True, cup_goal_pos=None): cup_goal_pos = np.array(cup_goal_pos if cup_goal_pos is not None else [-0.3, -1.2, 0.840]) if cup_goal_pos.shape[0]==2: cup_goal_pos = np.insert(cup_goal_pos, 2, 0.840) @@ -51,10 +52,9 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.noise_std = 0.01 else: self.noise_std = 0 - + self.learn_release_step = learn_release_step reward_function = BeerPongReward self.reward_function = reward_function() - self.n_table_bounces_first = 0 MujocoEnv.__init__(self, self.xml_path, frame_skip) utils.EzPickle.__init__(self) @@ -63,6 +63,13 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def start_pos(self): return self._start_pos + def _set_action_space(self): + bounds = self.model.actuator_ctrlrange.copy().astype(np.float32) + bounds = np.concatenate((bounds, [[50, self.ep_length*0.333]]), axis=0) + low, high = bounds.T + self.action_space = spaces.Box(low=low, high=high, dtype=np.float32) + return self.action_space + @property def start_vel(self): return self._start_vel @@ -76,8 +83,6 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): return self.sim.data.qvel[0:7].copy() def reset(self): - print(not self.reward_function.ball_ground_contact_first) - self.n_table_bounces_first += int(not self.reward_function.ball_ground_contact_first) self.reward_function.reset(self.add_noise) return super().reset() @@ -104,14 +109,17 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): return self._get_obs() def step(self, a): + self._release_step = a[-1] if self.learn_release_step else self._release_step + self._release_step = np.clip(self._release_step, self.action_space.low[-1], self.action_space.high[-1]) \ + if self.learn_release_step else self._release_step reward_dist = 0.0 angular_vel = 0.0 - reward_ctrl = - np.square(a).sum() - + applied_action = a[:a.shape[0]-int(self.learn_release_step)] + reward_ctrl = - np.square(applied_action).sum() if self.apply_gravity_comp: - a = a + self.sim.data.qfrc_bias[:len(a)].copy() / self.model.actuator_gear[:, 0] + applied_action += self.sim.data.qfrc_bias[:len(applied_action)].copy() / self.model.actuator_gear[:, 0] try: - self.do_simulation(a, self.frame_skip) + self.do_simulation(applied_action, self.frame_skip) if self._steps < self._release_step: self.sim.data.qpos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() self.sim.data.qvel[7::] = self.sim.data.site_xvelp[self.ball_site_id, :].copy() @@ -125,7 +133,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): ob = self._get_obs() if not crash: - reward, reward_infos = self.reward_function.compute_reward(self, a) + reward, reward_infos = self.reward_function.compute_reward(self, applied_action) success = reward_infos['success'] is_collided = reward_infos['is_collided'] ball_pos = reward_infos['ball_pos'] diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index 24c48be..910763a 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -162,6 +162,10 @@ class BeerPongReward: min_dist_coeff, final_dist_coeff, rew_offset = 0, 1, 0 reward = rew_offset - min_dist_coeff * min_dist ** 2 - final_dist_coeff * final_dist ** 2 - \ 1e-4 * np.mean(action_cost) + if env.learn_release_step and not self.ball_in_cup: + too_small = (env._release_step<50)*(env._release_step-50)**2 + too_big = (env._release_step>200)*0.2*(env._release_step-200)**2 + reward = reward - too_small -too_big # 1e-7*np.mean(action_cost) success = self.ball_in_cup else: diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py index ca2e17e..9cd6374 100644 --- a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py @@ -1,13 +1,15 @@ -from mp_wrapper import BaseMPWrapper +from alr_envs.mp.episodic_wrapper import EpisodicWrapper from typing import Union, Tuple import numpy as np +import gym -class MPWrapper(BaseMPWrapper): - +class NewMPWrapper(EpisodicWrapper): + @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qpos[0:7].copy() + @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qvel[0:7].copy() @@ -18,3 +20,25 @@ class MPWrapper(BaseMPWrapper): [True] * 2, # xy position of cup [False] # env steps ]) + + def _step_callback(self, t: int, env_spec_params: Union[np.ndarray, None], step_action: np.ndarray) -> Union[np.ndarray]: + if self.env.learn_release_step: + return np.concatenate((step_action, np.atleast_1d(env_spec_params))) + else: + return step_action + + def _episode_callback(self, action: np.ndarray) -> Tuple[np.ndarray, Union[np.ndarray, None]]: + if self.env.learn_release_step: + return action[:-1], action[-1] # mp_params, release step + else: + return action, None + + def set_action_space(self): + if self.env.learn_release_step: + min_action_bounds, max_action_bounds = self.mp.get_param_bounds() + min_action_bounds = np.concatenate((min_action_bounds.numpy(), [self.env.action_space.low[-1]])) + max_action_bounds = np.concatenate((max_action_bounds.numpy(), [self.env.action_space.high[-1]])) + self.mp_action_space = gym.spaces.Box(low=min_action_bounds, high=max_action_bounds, dtype=np.float32) + return self.mp_action_space + else: + return super(NewMPWrapper, self).set_action_space() diff --git a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py index 5475366..02dc1d8 100644 --- a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py @@ -1,9 +1,9 @@ -from mp_wrapper import BaseMPWrapper +from alr_envs.mp.episodic_wrapper import EpisodicWrapper from typing import Union, Tuple import numpy as np -class MPWrapper(BaseMPWrapper): +class MPWrapper(EpisodicWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: diff --git a/alr_envs/examples/pd_control_gain_tuning.py b/alr_envs/examples/pd_control_gain_tuning.py index 90aac11..465042c 100644 --- a/alr_envs/examples/pd_control_gain_tuning.py +++ b/alr_envs/examples/pd_control_gain_tuning.py @@ -39,7 +39,7 @@ actual_vel = np.zeros((len(pos), *base_shape)) act = np.zeros((len(pos), *base_shape)) for t, pos_vel in enumerate(zip(pos, vel)): - actions = env.policy.get_action(pos_vel[0], pos_vel[1]) + actions = env.policy.get_action(pos_vel[0], pos_vel[1],, self.current_vel, self.current_pos actions = np.clip(actions, env.full_action_space.low, env.full_action_space.high) _, _, _, _ = env.env.step(actions) act[t, :] = actions diff --git a/alr_envs/mp/__init__.py b/alr_envs/mp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/alr_envs/mp/basis_generator_factory.py b/alr_envs/mp/basis_generator_factory.py new file mode 100644 index 0000000..610ad20 --- /dev/null +++ b/alr_envs/mp/basis_generator_factory.py @@ -0,0 +1,17 @@ +from mp_pytorch import PhaseGenerator, NormalizedRBFBasisGenerator, ZeroStartNormalizedRBFBasisGenerator +from mp_pytorch.basis_gn.rhytmic_basis import RhythmicBasisGenerator + +ALL_TYPES = ["rbf", "zero_rbf", "rhythmic"] + + +def get_basis_generator(basis_generator_type: str, phase_generator: PhaseGenerator, **kwargs): + basis_generator_type = basis_generator_type.lower() + if basis_generator_type == "rbf": + return NormalizedRBFBasisGenerator(phase_generator, **kwargs) + elif basis_generator_type == "zero_rbf": + return ZeroStartNormalizedRBFBasisGenerator(phase_generator, **kwargs) + elif basis_generator_type == "rhythmic": + return RhythmicBasisGenerator(phase_generator, **kwargs) + else: + raise ValueError(f"Specified basis generator type {basis_generator_type} not supported, " + f"please choose one of {ALL_TYPES}.") diff --git a/alr_envs/mp/controllers/__init__.py b/alr_envs/mp/controllers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/alr_envs/mp/controllers/base_controller.py b/alr_envs/mp/controllers/base_controller.py new file mode 100644 index 0000000..1ac1522 --- /dev/null +++ b/alr_envs/mp/controllers/base_controller.py @@ -0,0 +1,4 @@ +class BaseController: + + def get_action(self, des_pos, des_vel, c_pos, c_vel): + raise NotImplementedError diff --git a/alr_envs/mp/controllers/controller_factory.py b/alr_envs/mp/controllers/controller_factory.py new file mode 100644 index 0000000..1c1cfec --- /dev/null +++ b/alr_envs/mp/controllers/controller_factory.py @@ -0,0 +1,21 @@ +from alr_envs.mp.controllers.meta_world_controller import MetaWorldController +from alr_envs.mp.controllers.pd_controller import PDController +from alr_envs.mp.controllers.vel_controller import VelController +from alr_envs.mp.controllers.pos_controller import PosController + +ALL_TYPES = ["motor", "velocity", "position", "metaworld"] + + +def get_controller(controller_type: str, **kwargs): + controller_type = controller_type.lower() + if controller_type == "motor": + return PDController(**kwargs) + elif controller_type == "velocity": + return VelController() + elif controller_type == "position": + return PosController() + elif controller_type == "metaworld": + return MetaWorldController() + else: + raise ValueError(f"Specified controller type {controller_type} not supported, " + f"please choose one of {ALL_TYPES}.") \ No newline at end of file diff --git a/alr_envs/mp/controllers/meta_world_controller.py b/alr_envs/mp/controllers/meta_world_controller.py new file mode 100644 index 0000000..07988e5 --- /dev/null +++ b/alr_envs/mp/controllers/meta_world_controller.py @@ -0,0 +1,25 @@ +import numpy as np + +from alr_envs.mp.controllers.base_controller import BaseController + + +class MetaWorldController(BaseController): + """ + A Metaworld Controller. Using position and velocity information from a provided environment, + the controller calculates a response based on the desired position and velocity. + Unlike the other Controllers, this is a special controller for MetaWorld environments. + They use a position delta for the xyz coordinates and a raw position for the gripper opening. + + :param env: A position environment + """ + + def get_action(self, des_pos, des_vel, c_pos, c_vel): + gripper_pos = des_pos[-1] + + cur_pos = env.current_pos[:-1] + xyz_pos = des_pos[:-1] + + assert xyz_pos.shape == cur_pos.shape, \ + f"Mismatch in dimension between desired position {xyz_pos.shape} and current position {cur_pos.shape}" + trq = np.hstack([(xyz_pos - cur_pos), gripper_pos]) + return trq diff --git a/alr_envs/mp/controllers/pd_controller.py b/alr_envs/mp/controllers/pd_controller.py new file mode 100644 index 0000000..d22f6b4 --- /dev/null +++ b/alr_envs/mp/controllers/pd_controller.py @@ -0,0 +1,28 @@ +from typing import Union, Tuple + +from alr_envs.mp.controllers.base_controller import BaseController + + +class PDController(BaseController): + """ + A PD-Controller. Using position and velocity information from a provided environment, + the controller calculates a response based on the desired position and velocity + + :param env: A position environment + :param p_gains: Factors for the proportional gains + :param d_gains: Factors for the differential gains + """ + + def __init__(self, + p_gains: Union[float, Tuple] = 1, + d_gains: Union[float, Tuple] = 0.5): + self.p_gains = p_gains + self.d_gains = d_gains + + def get_action(self, des_pos, des_vel, c_pos, c_vel): + assert des_pos.shape == c_pos.shape, \ + f"Mismatch in dimension between desired position {des_pos.shape} and current position {c_pos.shape}" + assert des_vel.shape == c_vel.shape, \ + f"Mismatch in dimension between desired velocity {des_vel.shape} and current velocity {c_vel.shape}" + trq = self.p_gains * (des_pos - c_pos) + self.d_gains * (des_vel - c_vel) + return trq diff --git a/alr_envs/mp/controllers/pos_controller.py b/alr_envs/mp/controllers/pos_controller.py new file mode 100644 index 0000000..bec3c68 --- /dev/null +++ b/alr_envs/mp/controllers/pos_controller.py @@ -0,0 +1,9 @@ +from alr_envs.mp.controllers.base_controller import BaseController + + +class PosController(BaseController): + """ + A Position Controller. The controller calculates a response only based on the desired position. + """ + def get_action(self, des_pos, des_vel, c_pos, c_vel): + return des_pos diff --git a/alr_envs/mp/controllers/vel_controller.py b/alr_envs/mp/controllers/vel_controller.py new file mode 100644 index 0000000..38128be --- /dev/null +++ b/alr_envs/mp/controllers/vel_controller.py @@ -0,0 +1,9 @@ +from alr_envs.mp.controllers.base_controller import BaseController + + +class VelController(BaseController): + """ + A Velocity Controller. The controller calculates a response only based on the desired velocity. + """ + def get_action(self, des_pos, des_vel, c_pos, c_vel): + return des_vel diff --git a/mp_wrapper.py b/alr_envs/mp/episodic_wrapper.py similarity index 57% rename from mp_wrapper.py rename to alr_envs/mp/episodic_wrapper.py index 3defe07..ef0723e 100644 --- a/mp_wrapper.py +++ b/alr_envs/mp/episodic_wrapper.py @@ -3,15 +3,13 @@ from typing import Union, Tuple import gym import numpy as np - from gym import spaces -from gym.envs.mujoco import MujocoEnv - -from policies import get_policy_class, BaseController from mp_pytorch.mp.mp_interfaces import MPInterface +from alr_envs.mp.controllers.base_controller import BaseController -class BaseMPWrapper(gym.Env, ABC): + +class EpisodicWrapper(gym.Env, ABC): """ Base class for movement primitive based gym.Wrapper implementations. @@ -20,41 +18,34 @@ class BaseMPWrapper(gym.Env, ABC): num_dof: Dimension of the action space of the wrapped env num_basis: Number of basis functions per dof duration: Length of the trajectory of the movement primitive in seconds - post_traj_time: Time for which the last position of the trajectory is fed to the environment to continue - simulation in seconds - policy_type: Type or object defining the policy that is used to generate action based on the trajectory + controller: Type or object defining the policy that is used to generate action based on the trajectory weight_scale: Scaling parameter for the actions given to this wrapper render_mode: Equivalent to gym render mode """ - def __init__(self, - env: MujocoEnv, + env: gym.Env, mp: MPInterface, + controller: BaseController, duration: float, - policy_type: Union[str, BaseController] = None, render_mode: str = None, - verbose=2, - **mp_kwargs - ): + verbose: int = 1, + weight_scale: float = 1): super().__init__() - assert env.dt is not None self.env = env - self.dt = env.dt + try: + self.dt = env.dt + except AttributeError: + raise AttributeError("step based environment needs to have a function 'dt' ") self.duration = duration self.traj_steps = int(duration / self.dt) self.post_traj_steps = self.env.spec.max_episode_steps - self.traj_steps - # TODO: move to constructor, use policy factory instead what Fabian already coded - if isinstance(policy_type, str): - # pop policy kwargs here such that they are not passed to the initialize_mp method - self.policy = get_policy_class(policy_type, self, **mp_kwargs.pop('policy_kwargs', {})) - else: - self.policy = policy_type - + self.controller = controller self.mp = mp self.env = env self.verbose = verbose + self.weight_scale = weight_scale # rendering self.render_mode = render_mode @@ -62,19 +53,24 @@ class BaseMPWrapper(gym.Env, ABC): # self.time_steps = np.linspace(0, self.duration, self.traj_steps + 1) self.time_steps = np.linspace(0, self.duration, self.traj_steps) self.mp.set_mp_times(self.time_steps) - # action_bounds = np.inf * np.ones((np.prod(self.mp.num_params))) min_action_bounds, max_action_bounds = mp.get_param_bounds() - self.action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), + self.mp_action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), dtype=np.float32) + self.action_space = self.set_action_space() self.active_obs = self.set_active_obs() self.observation_space = spaces.Box(low=self.env.observation_space.low[self.active_obs], high=self.env.observation_space.high[self.active_obs], dtype=self.env.observation_space.dtype) def get_trajectory(self, action: np.ndarray) -> Tuple: - self.mp.set_params(action) + # TODO: this follows the implementation of the mp_pytorch library which includes the paramters tau and delay at + # the beginning of the array. + ignore_indices = int(self.mp.learn_tau) + int(self.mp.learn_delay) + scaled_mp_params = action.copy() + scaled_mp_params[ignore_indices:] *= self.weight_scale + self.mp.set_params(scaled_mp_params) self.mp.set_boundary_conditions(bc_time=self.time_steps[:1], bc_pos=self.current_pos, bc_vel=self.current_vel) traj_dict = self.mp.get_mp_trajs(get_pos = True, get_vel = True) trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] @@ -88,9 +84,54 @@ class BaseMPWrapper(gym.Env, ABC): return trajectory, velocity + def set_action_space(self): + """ + This function can be used to modify the action space for considering actions which are not learned via motion + primitives. E.g. ball releasing time for the beer pong task. By default, it is the parameter space of the + motion primitive. + Only needs to be overwritten if the action space needs to be modified. + """ + return self.mp_action_space + + def _episode_callback(self, action: np.ndarray) -> Tuple[np.ndarray, Union[np.ndarray, None]]: + """ + Used to extract the parameters for the motion primitive and other parameters from an action array which might + include other actions like ball releasing time for the beer pong environment. + This only needs to be overwritten if the action space is modified. + Args: + action: a vector instance of the whole action space, includes mp parameters and additional parameters if + specified, else only mp parameters + + Returns: + Tuple: mp_arguments and other arguments + """ + return action, None + + def _step_callback(self, t: int, env_spec_params: Union[np.ndarray, None], step_action: np.ndarray) -> Union[np.ndarray]: + """ + This function can be used to modify the step_action with additional parameters e.g. releasing the ball in the + Beerpong env. The parameters used should not be part of the motion primitive parameters. + Returns step_action by default, can be overwritten in individual mp_wrappers. + Args: + t: the current time step of the episode + env_spec_params: the environment specific parameter, as defined in fucntion _episode_callback + (e.g. ball release time in Beer Pong) + step_action: the current step-based action + + Returns: + modified step action + """ + return step_action + @abstractmethod - def set_active_obs(self): - pass + def set_active_obs(self) -> np.ndarray: + """ + This function defines the contexts. The contexts are defined as specific observations. + Returns: + boolearn array representing the indices of the observations + + """ + return np.ones(self.env.observation_space.shape[0], dtype=bool) @property @abstractmethod @@ -116,38 +157,34 @@ class BaseMPWrapper(gym.Env, ABC): """ raise NotImplementedError() - def _step_callback(self, t, action): - pass - def step(self, action: np.ndarray): """ This function generates a trajectory based on a MP and then does the usual loop over reset and step""" # TODO: Think about sequencing # TODO: Reward Function rather here? # agent to learn when to release the ball - trajectory, velocity = self.get_trajectory(action) + mp_params, env_spec_params = self._episode_callback(action) + trajectory, velocity = self.get_trajectory(mp_params) trajectory_length = len(trajectory) - actions = np.zeros(shape=(trajectory_length,) + self.env.action_space.shape) - if isinstance(self.env.observation_space, spaces.Dict): # For goal environments - observations = np.zeros(shape=(trajectory_length,) + self.env.observation_space["observation"].shape, - dtype=self.env.observation_space.dtype) - else: + if self.verbose >=2 : + actions = np.zeros(shape=(trajectory_length,) + self.env.action_space.shape) observations = np.zeros(shape=(trajectory_length,) + self.env.observation_space.shape, - dtype=self.env.observation_space.dtype) - rewards = np.zeros(shape=(trajectory_length,)) + dtype=self.env.observation_space.dtype) + rewards = np.zeros(shape=(trajectory_length,)) trajectory_return = 0 infos = dict() for t, pos_vel in enumerate(zip(trajectory, velocity)): - ac = self.policy.get_action(pos_vel[0], pos_vel[1]) - callback_action = self._step_callback(t, action) - if callback_action is not None: - ac = np.concatenate((callback_action, ac)) # include callback action at first pos of vector - actions[t, :] = np.clip(ac, self.env.action_space.low, self.env.action_space.high) - obs, rewards[t], done, info = self.env.step(actions[t, :]) - observations[t, :] = obs["observation"] if isinstance(self.env.observation_space, spaces.Dict) else obs - trajectory_return += rewards[t] + step_action = self.controller.get_action(pos_vel[0], pos_vel[1], self.current_pos, self.current_vel) + step_action = self._step_callback(t, env_spec_params, step_action) # include possible callback info + c_action = np.clip(step_action, self.env.action_space.low, self.env.action_space.high) + obs, c_reward, done, info = self.env.step(c_action) + if self.verbose >= 2: + actions[t, :] = c_action + rewards[t] = c_reward + observations[t, :] = obs + trajectory_return += c_reward for k, v in info.items(): elems = infos.get(k, [None] * trajectory_length) elems[t] = v @@ -158,14 +195,14 @@ class BaseMPWrapper(gym.Env, ABC): if done: break infos.update({k: v[:t + 1] for k, v in infos.items()}) - infos['trajectory'] = trajectory - if self.verbose == 2: + if self.verbose >= 2: + infos['trajectory'] = trajectory infos['step_actions'] = actions[:t + 1] infos['step_observations'] = observations[:t + 1] infos['step_rewards'] = rewards[:t + 1] infos['trajectory_length'] = t + 1 done = True - return self.get_observation_from_step(observations[t]), trajectory_return, done, infos + return self.get_observation_from_step(obs), trajectory_return, done, infos def reset(self): return self.get_observation_from_step(self.env.reset()) diff --git a/alr_envs/mp/mp_factory.py b/alr_envs/mp/mp_factory.py new file mode 100644 index 0000000..5cf7231 --- /dev/null +++ b/alr_envs/mp/mp_factory.py @@ -0,0 +1,22 @@ +from mp_pytorch.mp.dmp import DMP +from mp_pytorch.mp.promp import ProMP +from mp_pytorch.mp.idmp import IDMP + +from mp_pytorch.basis_gn.basis_generator import BasisGenerator + +ALL_TYPES = ["promp", "dmp", "idmp"] + + +def get_movement_primitive( + movement_primitives_type: str, action_dim: int, basis_generator: BasisGenerator, **kwargs + ): + movement_primitives_type = movement_primitives_type.lower() + if movement_primitives_type == "promp": + return ProMP(basis_generator, action_dim, **kwargs) + elif movement_primitives_type == "dmp": + return DMP(basis_generator, action_dim, **kwargs) + elif movement_primitives_type == 'idmp': + return IDMP(basis_generator, action_dim, **kwargs) + else: + raise ValueError(f"Specified movement primitive type {movement_primitives_type} not supported, " + f"please choose one of {ALL_TYPES}.") \ No newline at end of file diff --git a/alr_envs/mp/phase_generator_factory.py b/alr_envs/mp/phase_generator_factory.py new file mode 100644 index 0000000..45cfdc1 --- /dev/null +++ b/alr_envs/mp/phase_generator_factory.py @@ -0,0 +1,20 @@ +from mp_pytorch import LinearPhaseGenerator, ExpDecayPhaseGenerator +from mp_pytorch.phase_gn.rhythmic_phase_generator import RhythmicPhaseGenerator +from mp_pytorch.phase_gn.smooth_phase_generator import SmoothPhaseGenerator + +ALL_TYPES = ["linear", "exp", "rhythmic", "smooth"] + + +def get_phase_generator(phase_generator_type, **kwargs): + phase_generator_type = phase_generator_type.lower() + if phase_generator_type == "linear": + return LinearPhaseGenerator(**kwargs) + elif phase_generator_type == "exp": + return ExpDecayPhaseGenerator(**kwargs) + elif phase_generator_type == "rhythmic": + return RhythmicPhaseGenerator(**kwargs) + elif phase_generator_type == "smooth": + return SmoothPhaseGenerator(**kwargs) + else: + raise ValueError(f"Specified phase generator type {phase_generator_type} not supported, " + f"please choose one of {ALL_TYPES}.") \ No newline at end of file diff --git a/alr_envs/utils/make_env_helpers.py b/alr_envs/utils/make_env_helpers.py index 4300439..0c06906 100644 --- a/alr_envs/utils/make_env_helpers.py +++ b/alr_envs/utils/make_env_helpers.py @@ -1,13 +1,20 @@ import warnings -from typing import Iterable, Type, Union +from typing import Iterable, Type, Union, Mapping, MutableMapping import gym import numpy as np from gym.envs.registration import EnvSpec -from mp_env_api import MPEnvWrapper from mp_env_api.mp_wrappers.dmp_wrapper import DmpWrapper from mp_env_api.mp_wrappers.promp_wrapper import ProMPWrapper +from mp_pytorch import MPInterface + +from alr_envs.mp.basis_generator_factory import get_basis_generator +from alr_envs.mp.controllers.base_controller import BaseController +from alr_envs.mp.controllers.controller_factory import get_controller +from alr_envs.mp.mp_factory import get_movement_primitive +from alr_envs.mp.episodic_wrapper import EpisodicWrapper +from alr_envs.mp.phase_generator_factory import get_phase_generator def make_rank(env_id: str, seed: int, rank: int = 0, return_callable=True, **kwargs): @@ -92,7 +99,8 @@ def make(env_id: str, seed, **kwargs): return env -def _make_wrapped_env(env_id: str, wrappers: Iterable[Type[gym.Wrapper]], seed=1, **kwargs): +def _make_wrapped_env(env_id: str, wrappers: Iterable[Type[gym.Wrapper]], mp: MPInterface, controller: BaseController, + ep_wrapper_kwargs: Mapping, seed=1, **kwargs): """ Helper function for creating a wrapped gym environment using MPs. It adds all provided wrappers to the specified environment and verifies at least one MPEnvWrapper is @@ -108,14 +116,102 @@ def _make_wrapped_env(env_id: str, wrappers: Iterable[Type[gym.Wrapper]], seed=1 """ # _env = gym.make(env_id) _env = make(env_id, seed, **kwargs) - - assert any(issubclass(w, MPEnvWrapper) for w in wrappers), \ - "At least one MPEnvWrapper is required in order to leverage motion primitive environments." + has_episodic_wrapper = False for w in wrappers: - _env = w(_env) - + # only wrap the environment if not EpisodicWrapper, e.g. for vision + if not issubclass(w, EpisodicWrapper): + _env = w(_env) + else: # if EpisodicWrapper, use specific constructor + has_episodic_wrapper = True + _env = w(env=_env, mp=mp, controller=controller, **ep_wrapper_kwargs) + assert has_episodic_wrapper, \ + "At least one MPEnvWrapper is required in order to leverage motion primitive environments." return _env +def make_mp_from_kwargs( + env_id: str, wrappers: Iterable, ep_wrapper_kwargs: MutableMapping, mp_kwargs: MutableMapping, + controller_kwargs: MutableMapping, phase_kwargs: MutableMapping, basis_kwargs: MutableMapping, seed=1, + sequenced=False, **kwargs + ): + """ + This can also be used standalone for manually building a custom DMP environment. + Args: + ep_wrapper_kwargs: + basis_kwargs: + phase_kwargs: + controller_kwargs: + env_id: base_env_name, + wrappers: list of wrappers (at least an EpisodicWrapper), + seed: seed of environment + sequenced: When true, this allows to sequence multiple ProMPs by specifying the duration of each sub-trajectory, + this behavior is much closer to step based learning. + mp_kwargs: dict of at least {num_dof: int, num_basis: int} for DMP + + Returns: DMP wrapped gym env + + """ + _verify_time_limit(mp_kwargs.get("duration", None), kwargs.get("time_limit", None)) + dummy_env = make(env_id, seed) + if ep_wrapper_kwargs.get('duration', None) is None: + ep_wrapper_kwargs['duration'] = dummy_env.spec.max_episode_steps*dummy_env.dt + if phase_kwargs.get('tau', None) is None: + phase_kwargs['tau'] = ep_wrapper_kwargs['duration'] + action_dim = mp_kwargs.pop('num_dof', None) + action_dim = action_dim if action_dim is not None else np.prod(dummy_env.action_space.shape).item() + phase_gen = get_phase_generator(**phase_kwargs) + basis_gen = get_basis_generator(phase_generator=phase_gen, **basis_kwargs) + controller = get_controller(**controller_kwargs) + mp = get_movement_primitive(action_dim=action_dim, basis_generator=basis_gen, **mp_kwargs) + _env = _make_wrapped_env(env_id=env_id, wrappers=wrappers, mp=mp, controller=controller, + ep_wrapper_kwargs=ep_wrapper_kwargs, seed=seed, **kwargs) + return _env + + +def make_mp_env_helper(**kwargs): + """ + Helper function for registering a DMP gym environments. + Args: + **kwargs: expects at least the following: + { + "name": base environment name. + "wrappers": list of wrappers (at least an EpisodicWrapper is required), + "movement_primitives_kwargs": { + "movement_primitives_type": type_of_your_movement_primitive, + non default arguments for the movement primitive instance + ... + } + "controller_kwargs": { + "controller_type": type_of_your_controller, + non default arguments for the controller instance + ... + }, + "basis_generator_kwargs": { + "basis_generator_type": type_of_your_basis_generator, + non default arguments for the basis generator instance + ... + }, + "phase_generator_kwargs": { + "phase_generator_type": type_of_your_phase_generator, + non default arguments for the phase generator instance + ... + }, + } + + Returns: MP wrapped gym env + + """ + seed = kwargs.pop("seed", None) + wrappers = kwargs.pop("wrappers") + + mp_kwargs = kwargs.pop("movement_primitives_kwargs") + ep_wrapper_kwargs = kwargs.pop('ep_wrapper_kwargs') + contr_kwargs = kwargs.pop("controller_kwargs") + phase_kwargs = kwargs.pop("phase_generator_kwargs") + basis_kwargs = kwargs.pop("basis_generator_kwargs") + + return make_mp_from_kwargs(env_id=kwargs.pop("name"), wrappers=wrappers, ep_wrapper_kwargs=ep_wrapper_kwargs, + mp_kwargs=mp_kwargs, controller_kwargs=contr_kwargs, phase_kwargs=phase_kwargs, + basis_kwargs=basis_kwargs, **kwargs, seed=seed) def make_dmp_env(env_id: str, wrappers: Iterable, seed=1, mp_kwargs={}, **kwargs): """ diff --git a/policies.py b/policies.py deleted file mode 100644 index fd89f9e..0000000 --- a/policies.py +++ /dev/null @@ -1,129 +0,0 @@ -from typing import Tuple, Union - -import numpy as np - - - -class BaseController: - def __init__(self, env, **kwargs): - self.env = env - - def get_action(self, des_pos, des_vel): - raise NotImplementedError - - -class PosController(BaseController): - """ - A Position Controller. The controller calculates a response only based on the desired position. - """ - def get_action(self, des_pos, des_vel): - return des_pos - - -class VelController(BaseController): - """ - A Velocity Controller. The controller calculates a response only based on the desired velocity. - """ - def get_action(self, des_pos, des_vel): - return des_vel - - -class PDController(BaseController): - """ - A PD-Controller. Using position and velocity information from a provided environment, - the controller calculates a response based on the desired position and velocity - - :param env: A position environment - :param p_gains: Factors for the proportional gains - :param d_gains: Factors for the differential gains - """ - - def __init__(self, - env, - p_gains: Union[float, Tuple], - d_gains: Union[float, Tuple]): - self.p_gains = p_gains - self.d_gains = d_gains - super(PDController, self).__init__(env) - - def get_action(self, des_pos, des_vel): - cur_pos = self.env.current_pos - cur_vel = self.env.current_vel - assert des_pos.shape == cur_pos.shape, \ - f"Mismatch in dimension between desired position {des_pos.shape} and current position {cur_pos.shape}" - assert des_vel.shape == cur_vel.shape, \ - f"Mismatch in dimension between desired velocity {des_vel.shape} and current velocity {cur_vel.shape}" - trq = self.p_gains * (des_pos - cur_pos) + self.d_gains * (des_vel - cur_vel) - return trq - - -class MetaWorldController(BaseController): - """ - A Metaworld Controller. Using position and velocity information from a provided environment, - the controller calculates a response based on the desired position and velocity. - Unlike the other Controllers, this is a special controller for MetaWorld environments. - They use a position delta for the xyz coordinates and a raw position for the gripper opening. - - :param env: A position environment - """ - - def __init__(self, - env - ): - super(MetaWorldController, self).__init__(env) - - def get_action(self, des_pos, des_vel): - gripper_pos = des_pos[-1] - - cur_pos = self.env.current_pos[:-1] - xyz_pos = des_pos[:-1] - - assert xyz_pos.shape == cur_pos.shape, \ - f"Mismatch in dimension between desired position {xyz_pos.shape} and current position {cur_pos.shape}" - trq = np.hstack([(xyz_pos - cur_pos), gripper_pos]) - return trq - - -#TODO: Do we need this class? -class PDControllerExtend(BaseController): - """ - A PD-Controller. Using position and velocity information from a provided positional environment, - the controller calculates a response based on the desired position and velocity - - :param env: A position environment - :param p_gains: Factors for the proportional gains - :param d_gains: Factors for the differential gains - """ - - def __init__(self, - env, - p_gains: Union[float, Tuple], - d_gains: Union[float, Tuple]): - - self.p_gains = p_gains - self.d_gains = d_gains - super(PDControllerExtend, self).__init__(env) - - def get_action(self, des_pos, des_vel): - cur_pos = self.env.current_pos - cur_vel = self.env.current_vel - if len(des_pos) != len(cur_pos): - des_pos = self.env.extend_des_pos(des_pos) - if len(des_vel) != len(cur_vel): - des_vel = self.env.extend_des_vel(des_vel) - trq = self.p_gains * (des_pos - cur_pos) + self.d_gains * (des_vel - cur_vel) - return trq - - -def get_policy_class(policy_type, env, **kwargs): - if policy_type == "motor": - return PDController(env, **kwargs) - elif policy_type == "velocity": - return VelController(env) - elif policy_type == "position": - return PosController(env) - elif policy_type == "metaworld": - return MetaWorldController(env) - else: - raise ValueError(f"Invalid controller type {policy_type} provided. Only 'motor', 'velocity', 'position' " - f"and 'metaworld are currently supported controllers.") From 640f3b2d909656325a213e1a24592bbedf3c922c Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 3 May 2022 21:34:39 +0200 Subject: [PATCH 024/104] fix action space bugs for bp --- alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py | 4 ++-- alr_envs/mp/episodic_wrapper.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py index 9cd6374..267e76e 100644 --- a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py @@ -38,7 +38,7 @@ class NewMPWrapper(EpisodicWrapper): min_action_bounds, max_action_bounds = self.mp.get_param_bounds() min_action_bounds = np.concatenate((min_action_bounds.numpy(), [self.env.action_space.low[-1]])) max_action_bounds = np.concatenate((max_action_bounds.numpy(), [self.env.action_space.high[-1]])) - self.mp_action_space = gym.spaces.Box(low=min_action_bounds, high=max_action_bounds, dtype=np.float32) - return self.mp_action_space + self.action_space = gym.spaces.Box(low=min_action_bounds, high=max_action_bounds, dtype=np.float32) + return self.action_space else: return super(NewMPWrapper, self).set_action_space() diff --git a/alr_envs/mp/episodic_wrapper.py b/alr_envs/mp/episodic_wrapper.py index ef0723e..092f1bc 100644 --- a/alr_envs/mp/episodic_wrapper.py +++ b/alr_envs/mp/episodic_wrapper.py @@ -70,7 +70,7 @@ class EpisodicWrapper(gym.Env, ABC): ignore_indices = int(self.mp.learn_tau) + int(self.mp.learn_delay) scaled_mp_params = action.copy() scaled_mp_params[ignore_indices:] *= self.weight_scale - self.mp.set_params(scaled_mp_params) + self.mp.set_params(np.clip(scaled_mp_params, self.mp_action_space.low, self.mp_action_space.high)) self.mp.set_boundary_conditions(bc_time=self.time_steps[:1], bc_pos=self.current_pos, bc_vel=self.current_vel) traj_dict = self.mp.get_mp_trajs(get_pos = True, get_vel = True) trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] From 1881c14a48b74b142f939a7a9edd1c47832614ac Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 5 May 2022 16:48:59 +0200 Subject: [PATCH 025/104] reacher adjustments --- alr_envs/alr/__init__.py | 5 +++-- alr_envs/alr/mujoco/reacher/alr_reacher.py | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 8a7140d..2e23d44 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -97,6 +97,7 @@ register( "hole_depth": 1, "hole_x": None, "collision_penalty": 100, + "rew_fct": "unbounded" } ) @@ -354,7 +355,7 @@ for _v in _versions: "wrappers": [classic_control.hole_reacher.MPWrapper], "mp_kwargs": { "num_dof": 5, - "num_basis": 5, + "num_basis": 3, "duration": 2, "policy_type": "velocity", "weights_scale": 5, @@ -402,7 +403,7 @@ for _v in _versions: "wrappers": [mujoco.reacher.MPWrapper], "mp_kwargs": { "num_dof": 5 if "long" not in _v.lower() else 7, - "num_basis": 1, + "num_basis": 2, "duration": 4, "policy_type": "motor", "weights_scale": 5, diff --git a/alr_envs/alr/mujoco/reacher/alr_reacher.py b/alr_envs/alr/mujoco/reacher/alr_reacher.py index c2b5f18..b436fdd 100644 --- a/alr_envs/alr/mujoco/reacher/alr_reacher.py +++ b/alr_envs/alr/mujoco/reacher/alr_reacher.py @@ -39,14 +39,18 @@ class ALRReacherEnv(MujocoEnv, utils.EzPickle): reward_dist = 0.0 angular_vel = 0.0 reward_balance = 0.0 + is_delayed = self.steps_before_reward > 0 + reward_ctrl = - np.square(a).sum() if self._steps >= self.steps_before_reward: vec = self.get_body_com("fingertip") - self.get_body_com("target") reward_dist -= self.reward_weight * np.linalg.norm(vec) - if self.steps_before_reward > 0: + if is_delayed: # avoid giving this penalty for normal step based case # angular_vel -= 10 * np.linalg.norm(self.sim.data.qvel.flat[:self.n_links]) angular_vel -= 10 * np.square(self.sim.data.qvel.flat[:self.n_links]).sum() - reward_ctrl = - 10 * np.square(a).sum() + if is_delayed: + # Higher control penalty for sparse reward per timestep + reward_ctrl *= 10 if self.balance: reward_balance -= self.balance_weight * np.abs( From ad30e732c84f4fb29263a68443f6ba74a6b00730 Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 5 May 2022 16:53:56 +0200 Subject: [PATCH 026/104] reacher adjustments --- alr_envs/alr/mujoco/reacher/alr_reacher.py | 82 ++++++++++++---------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/alr_envs/alr/mujoco/reacher/alr_reacher.py b/alr_envs/alr/mujoco/reacher/alr_reacher.py index 4477a66..b436fdd 100644 --- a/alr_envs/alr/mujoco/reacher/alr_reacher.py +++ b/alr_envs/alr/mujoco/reacher/alr_reacher.py @@ -39,11 +39,18 @@ class ALRReacherEnv(MujocoEnv, utils.EzPickle): reward_dist = 0.0 angular_vel = 0.0 reward_balance = 0.0 + is_delayed = self.steps_before_reward > 0 + reward_ctrl = - np.square(a).sum() if self._steps >= self.steps_before_reward: vec = self.get_body_com("fingertip") - self.get_body_com("target") reward_dist -= self.reward_weight * np.linalg.norm(vec) - angular_vel -= np.linalg.norm(self.sim.data.qvel.flat[:self.n_links]) - reward_ctrl = - np.square(a).sum() + if is_delayed: + # avoid giving this penalty for normal step based case + # angular_vel -= 10 * np.linalg.norm(self.sim.data.qvel.flat[:self.n_links]) + angular_vel -= 10 * np.square(self.sim.data.qvel.flat[:self.n_links]).sum() + if is_delayed: + # Higher control penalty for sparse reward per timestep + reward_ctrl *= 10 if self.balance: reward_balance -= self.balance_weight * np.abs( @@ -56,63 +63,66 @@ class ALRReacherEnv(MujocoEnv, utils.EzPickle): return ob, reward, done, dict(reward_dist=reward_dist, reward_ctrl=reward_ctrl, velocity=angular_vel, reward_balance=reward_balance, end_effector=self.get_body_com("fingertip").copy(), - goal=self.goal if hasattr(self, "goal") else None, - joint_pos = self.sim.data.qpos.flat[:self.n_links].copy(), - joint_vel = self.sim.data.qvel.flat[:self.n_links].copy()) + goal=self.goal if hasattr(self, "goal") else None) def viewer_setup(self): self.viewer.cam.trackbodyid = 0 + # def reset_model(self): + # qpos = self.init_qpos + # if not hasattr(self, "goal"): + # self.goal = np.array([-0.25, 0.25]) + # # self.goal = self.init_qpos.copy()[:2] + 0.05 + # qpos[-2:] = self.goal + # qvel = self.init_qvel + # qvel[-2:] = 0 + # self.set_state(qpos, qvel) + # self._steps = 0 + # + # return self._get_obs() + def reset_model(self): - # qpos = self.np_random.uniform(low=-0.1, high=0.1, size=self.model.nq) + self.init_qpos - qpos = self.init_qpos + qpos = self.init_qpos.copy() while True: self.goal = self.np_random.uniform(low=-self.n_links / 10, high=self.n_links / 10, size=2) + # self.goal = self.np_random.uniform(low=0, high=self.n_links / 10, size=2) + # self.goal = np.random.uniform(low=[-self.n_links / 10, 0], high=[0, self.n_links / 10], size=2) if np.linalg.norm(self.goal) < self.n_links / 10: break qpos[-2:] = self.goal - qvel = self.init_qvel# + self.np_random.uniform(low=-.005, high=.005, size=self.model.nv) + qvel = self.init_qvel.copy() qvel[-2:] = 0 self.set_state(qpos, qvel) self._steps = 0 return self._get_obs() + # def reset_model(self): + # qpos = self.np_random.uniform(low=-0.1, high=0.1, size=self.model.nq) + self.init_qpos + # while True: + # self.goal = self.np_random.uniform(low=-self.n_links / 10, high=self.n_links / 10, size=2) + # if np.linalg.norm(self.goal) < self.n_links / 10: + # break + # qpos[-2:] = self.goal + # qvel = self.init_qvel + self.np_random.uniform(low=-.005, high=.005, size=self.model.nv) + # qvel[-2:] = 0 + # self.set_state(qpos, qvel) + # self._steps = 0 + # + # return self._get_obs() + def _get_obs(self): theta = self.sim.data.qpos.flat[:self.n_links] + target = self.get_body_com("target") return np.concatenate([ np.cos(theta), np.sin(theta), - self.sim.data.qpos.flat[self.n_links:], # this is goal position - self.sim.data.qvel.flat[:self.n_links], # this is angular velocity - self.get_body_com("fingertip") - self.get_body_com("target"), - # self.get_body_com("target"), # only return target to make problem harder + target[:2], # x-y of goal position + self.sim.data.qvel.flat[:self.n_links], # angular velocity + self.get_body_com("fingertip") - target, # goal distance [self._steps], ]) -class ALRReacherOptCtrlEnv(ALRReacherEnv): - def __init__(self, steps_before_reward=200, n_links=5, balance=False): - self.goal = np.array([0.1, 0.1]) - super(ALRReacherOptCtrlEnv, self).__init__(steps_before_reward, n_links, balance) - - def _get_obs(self): - theta = self.sim.data.qpos.flat[:self.n_links] - tip_pos = self.get_body_com("fingertip") - return np.concatenate([ - tip_pos[:2], - theta, - self.sim.data.qvel.flat[:self.n_links], # this is angular velocity - ]) - - def reset_model(self): - qpos = self.init_qpos - qpos[-2:] = self.goal - qvel = self.init_qvel - qvel[-2:] = 0 - self.set_state(qpos, qvel) - self._steps = 0 - - return self._get_obs() if __name__ == '__main__': nl = 5 @@ -130,4 +140,4 @@ if __name__ == '__main__': if d: env.reset() - env.close() \ No newline at end of file + env.close() From bd4632af8431faa19e698f2f572f6ea87ee0c54e Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 5 May 2022 16:54:39 +0200 Subject: [PATCH 027/104] hole_reacher update --- .../hole_reacher/hole_reacher.py | 3 + .../hole_reacher/hr_unbounded_reward.py | 60 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 alr_envs/alr/classic_control/hole_reacher/hr_unbounded_reward.py diff --git a/alr_envs/alr/classic_control/hole_reacher/hole_reacher.py b/alr_envs/alr/classic_control/hole_reacher/hole_reacher.py index 208f005..883be8c 100644 --- a/alr_envs/alr/classic_control/hole_reacher/hole_reacher.py +++ b/alr_envs/alr/classic_control/hole_reacher/hole_reacher.py @@ -45,6 +45,9 @@ class HoleReacherEnv(BaseReacherDirectEnv): elif rew_fct == "vel_acc": from alr_envs.alr.classic_control.hole_reacher.hr_dist_vel_acc_reward import HolereacherReward self.reward_function = HolereacherReward(allow_self_collision, allow_wall_collision, collision_penalty) + elif rew_fct == "unbounded": + from alr_envs.alr.classic_control.hole_reacher.hr_unbounded_reward import HolereacherReward + self.reward_function = HolereacherReward(allow_self_collision, allow_wall_collision) else: raise ValueError("Unknown reward function {}".format(rew_fct)) diff --git a/alr_envs/alr/classic_control/hole_reacher/hr_unbounded_reward.py b/alr_envs/alr/classic_control/hole_reacher/hr_unbounded_reward.py new file mode 100644 index 0000000..7ed13a1 --- /dev/null +++ b/alr_envs/alr/classic_control/hole_reacher/hr_unbounded_reward.py @@ -0,0 +1,60 @@ +import numpy as np + + +class HolereacherReward: + def __init__(self, allow_self_collision, allow_wall_collision): + + # collision + self.allow_self_collision = allow_self_collision + self.allow_wall_collision = allow_wall_collision + self._is_collided = False + + self.reward_factors = np.array((1, -5e-6)) + + def reset(self): + self._is_collided = False + + def get_reward(self, env): + dist_reward = 0 + success = False + + self_collision = False + wall_collision = False + + if not self.allow_self_collision: + self_collision = env._check_self_collision() + + if not self.allow_wall_collision: + wall_collision = env.check_wall_collision() + + self._is_collided = self_collision or wall_collision + + if env._steps == 180 or self._is_collided: + self.end_eff_pos = np.copy(env.end_effector) + + if env._steps == 199 or self._is_collided: + # return reward only in last time step + # Episode also terminates when colliding, hence return reward + dist = np.linalg.norm(self.end_eff_pos - env._goal) + + if self._is_collided: + dist_reward = 0.25 * np.exp(- dist) + else: + if env.end_effector[1] > 0: + dist_reward = np.exp(- dist) + else: + dist_reward = 1 - self.end_eff_pos[1] + + success = not self._is_collided + + info = {"is_success": success, + "is_collided": self._is_collided, + "end_effector": np.copy(env.end_effector), + "joints": np.copy(env.current_pos)} + + acc_cost = np.sum(env._acc ** 2) + + reward_features = np.array((dist_reward, acc_cost)) + reward = np.dot(reward_features, self.reward_factors) + + return reward, info \ No newline at end of file From 2cc1ab759c25f5068a5fdebbac4c8092a877c105 Mon Sep 17 00:00:00 2001 From: Onur Date: Thu, 5 May 2022 18:50:20 +0200 Subject: [PATCH 028/104] commit last version of --- alr_envs/alr/__init__.py | 150 +++++++++++++----- alr_envs/alr/mujoco/__init__.py | 4 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 29 ++-- .../mujoco/beerpong/beerpong_reward_staged.py | 12 +- .../alr/mujoco/beerpong/new_mp_wrapper.py | 43 +++-- alr_envs/alr/mujoco/hopper_jump/__init__.py | 1 + .../alr/mujoco/hopper_jump/hopper_jump.py | 49 +++--- .../alr/mujoco/hopper_jump/new_mp_wrapper.py | 29 ++++ alr_envs/alr/mujoco/reacher/alr_reacher.py | 42 ++--- alr_envs/mp/episodic_wrapper.py | 15 +- alr_envs/utils/make_env_helpers.py | 5 +- 11 files changed, 250 insertions(+), 129 deletions(-) create mode 100644 alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 552adfa..fa9b71b 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -391,8 +391,7 @@ register( max_episode_steps=600, kwargs={ "rndm_goal": False, - "cup_goal_pos": [0.1, -2.0], - "learn_release_step": True + "cup_goal_pos": [0.1, -2.0] } ) @@ -404,8 +403,7 @@ register( max_episode_steps=600, kwargs={ "rndm_goal": True, - "cup_goal_pos": [-0.3, -1.2], - "learn_release_step": True + "cup_goal_pos": [-0.3, -1.2] } ) @@ -646,7 +644,7 @@ for _v in _versions: }, "movement_primitives_kwargs": { 'movement_primitives_type': 'promp', - 'num_dof': 7 + 'action_dim': 7 }, "phase_generator_kwargs": { 'phase_generator_type': 'linear', @@ -658,7 +656,9 @@ for _v in _versions: "controller_kwargs": { 'controller_type': 'motor', "p_gains": np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]), + # "p_gains": 0.125*np.array([200, 300, 100, 100, 10, 10, 2.5]), "d_gains": np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]), + # "d_gains": 0.025*np.array([7, 15, 5, 2.5, 0.3, 0.3, 0.05]), }, "basis_generator_kwargs": { 'basis_generator_type': 'zero_rbf', @@ -753,29 +753,92 @@ for _v in _versions: ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) +# ## HopperJump +# _versions = ["v0", "v1"] +# for _v in _versions: +# _env_id = f'ALRHopperJumpProMP-{_v}' +# register( +# id= _env_id, +# entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', +# kwargs={ +# "name": f"alr_envs:ALRHopperJump-{_v}", +# "wrappers": [mujoco.hopper_jump.MPWrapper], +# "mp_kwargs": { +# "num_dof": 3, +# "num_basis": 5, +# "duration": 2, +# "post_traj_time": 0, +# "policy_type": "motor", +# "weights_scale": 1.0, +# "zero_start": True, +# "zero_goal": False, +# "policy_kwargs": { +# "p_gains": np.ones(3), +# "d_gains": 0.1*np.ones(3) +# } +# } +# } +# ) +# ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + +# ## HopperJump +# register( +# id= "ALRHopperJumpProMP-v2", +# entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', +# kwargs={ +# "name": f"alr_envs:ALRHopperJump-v2", +# "wrappers": [mujoco.hopper_jump.HighCtxtMPWrapper], +# "mp_kwargs": { +# "num_dof": 3, +# "num_basis": 5, +# "duration": 2, +# "post_traj_time": 0, +# "policy_type": "motor", +# "weights_scale": 1.0, +# "zero_start": True, +# "zero_goal": False, +# "policy_kwargs": { +# "p_gains": np.ones(3), +# "d_gains": 0.1*np.ones(3) +# } +# } +# } +# ) +# ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ALRHopperJumpProMP-v2") + ## HopperJump _versions = ["v0", "v1"] for _v in _versions: _env_id = f'ALRHopperJumpProMP-{_v}' register( id= _env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', kwargs={ "name": f"alr_envs:ALRHopperJump-{_v}", - "wrappers": [mujoco.hopper_jump.MPWrapper], - "mp_kwargs": { - "num_dof": 3, - "num_basis": 5, - "duration": 2, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3) - } + "wrappers": [mujoco.hopper_jump.NewMPWrapper], + "ep_wrapper_kwargs": { + "weight_scale": 1 + }, + "movement_primitives_kwargs": { + 'movement_primitives_type': 'promp', + 'action_dim': 3 + }, + "phase_generator_kwargs": { + 'phase_generator_type': 'linear', + 'delay': 0, + 'tau': 2, # initial value + 'learn_tau': False, + 'learn_delay': False + }, + "controller_kwargs": { + 'controller_type': 'motor', + "p_gains": np.ones(3), + "d_gains": 0.1*np.ones(3), + }, + "basis_generator_kwargs": { + 'basis_generator_type': 'zero_rbf', + 'num_basis': 5, + 'num_basis_zero_start': 2 } } ) @@ -784,25 +847,35 @@ for _v in _versions: ## HopperJump register( id= "ALRHopperJumpProMP-v2", - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', kwargs={ "name": f"alr_envs:ALRHopperJump-v2", - "wrappers": [mujoco.hopper_jump.HighCtxtMPWrapper], - "mp_kwargs": { - "num_dof": 3, - "num_basis": 5, - "duration": 2, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { + "wrappers": [mujoco.hopper_jump.NewHighCtxtMPWrapper], + "ep_wrapper_kwargs": { + "weight_scale": 1 + }, + "movement_primitives_kwargs": { + 'movement_primitives_type': 'promp', + 'action_dim': 3 + }, + "phase_generator_kwargs": { + 'phase_generator_type': 'linear', + 'delay': 0, + 'tau': 2, # initial value + 'learn_tau': False, + 'learn_delay': False + }, + "controller_kwargs": { + 'controller_type': 'motor', "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3) + "d_gains": 0.1*np.ones(3), + }, + "basis_generator_kwargs": { + 'basis_generator_type': 'zero_rbf', + 'num_basis': 5, + 'num_basis_zero_start': 2 } } - } ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ALRHopperJumpProMP-v2") @@ -916,11 +989,4 @@ for _v in _versions: } } ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - - -# --------------------- Testing new mp wrapper ----------------------------------------------------- - -# register( -# id='ALRReacherProMP-v0' -# ) \ No newline at end of file + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) \ No newline at end of file diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index 9c7eecf..fb86186 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -1,4 +1,3 @@ -from .reacher.alr_reacher import ALRReacherEnv, ALRReacherOptCtrlEnv from .reacher.balancing import BalancingEnv from .ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv from .ball_in_a_cup.biac_pd import ALRBallInACupPDEnv @@ -10,4 +9,5 @@ from .hopper_jump.hopper_jump import ALRHopperJumpEnv, ALRHopperJumpRndmPosEnv from .hopper_jump.hopper_jump_on_box import ALRHopperJumpOnBoxEnv from .hopper_throw.hopper_throw import ALRHopperThrowEnv from .hopper_throw.hopper_throw_in_basket import ALRHopperThrowInBasketEnv -from .walker_2d_jump.walker_2d_jump import ALRWalker2dJumpEnv \ No newline at end of file +from .walker_2d_jump.walker_2d_jump import ALRWalker2dJumpEnv +from .reacher.alr_reacher import ALRReacherEnv \ No newline at end of file diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 661d10c..36998b9 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -3,7 +3,6 @@ import os import numpy as np from gym import utils -from gym import spaces from gym.envs.mujoco import MujocoEnv from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward @@ -18,7 +17,7 @@ CUP_POS_MAX = np.array([0.32, -1.2]) class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, - rndm_goal=False, learn_release_step=True, cup_goal_pos=None): + rndm_goal=False, cup_goal_pos=None): cup_goal_pos = np.array(cup_goal_pos if cup_goal_pos is not None else [-0.3, -1.2, 0.840]) if cup_goal_pos.shape[0]==2: cup_goal_pos = np.insert(cup_goal_pos, 2, 0.840) @@ -43,7 +42,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): # self._release_step = 175 # time step of ball release # self._release_step = 130 # time step of ball release - self._release_step = 100 # time step of ball release + self.release_step = 100 # time step of ball release self.ep_length = 600 # based on 3 seconds with dt = 0.005 int(self.sim_time / self.dt) self.cup_table_id = 10 @@ -52,7 +51,6 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.noise_std = 0.01 else: self.noise_std = 0 - self.learn_release_step = learn_release_step reward_function = BeerPongReward self.reward_function = reward_function() @@ -63,13 +61,6 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def start_pos(self): return self._start_pos - def _set_action_space(self): - bounds = self.model.actuator_ctrlrange.copy().astype(np.float32) - bounds = np.concatenate((bounds, [[50, self.ep_length*0.333]]), axis=0) - low, high = bounds.T - self.action_space = spaces.Box(low=low, high=high, dtype=np.float32) - return self.action_space - @property def start_vel(self): return self._start_vel @@ -109,21 +100,22 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): return self._get_obs() def step(self, a): - self._release_step = a[-1] if self.learn_release_step else self._release_step - self._release_step = np.clip(self._release_step, self.action_space.low[-1], self.action_space.high[-1]) \ - if self.learn_release_step else self._release_step + # if a.shape[0] == 8: # we learn also when to release the ball + # self._release_step = a[-1] + # self._release_step = np.clip(self._release_step, 50, 250) + # self.release_step = 0.5/self.dt reward_dist = 0.0 angular_vel = 0.0 - applied_action = a[:a.shape[0]-int(self.learn_release_step)] + applied_action = a reward_ctrl = - np.square(applied_action).sum() if self.apply_gravity_comp: applied_action += self.sim.data.qfrc_bias[:len(applied_action)].copy() / self.model.actuator_gear[:, 0] try: self.do_simulation(applied_action, self.frame_skip) - if self._steps < self._release_step: + if self._steps < self.release_step: self.sim.data.qpos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() self.sim.data.qvel[7::] = self.sim.data.site_xvelp[self.ball_site_id, :].copy() - elif self._steps == self._release_step and self.add_noise: + elif self._steps == self.release_step and self.add_noise: self.sim.data.qvel[7::] += self.noise_std * np.random.randn(3) crash = False except mujoco_py.builder.MujocoException: @@ -160,7 +152,8 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): ball_pos=ball_pos, ball_vel=ball_vel, success=success, - is_collided=is_collided, sim_crash=crash) + is_collided=is_collided, sim_crash=crash, + table_contact_first=int(not self.reward_function.ball_ground_contact_first)) infos.update(reward_infos) return ob, reward, done, infos diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index 910763a..bb5dd3f 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -162,12 +162,16 @@ class BeerPongReward: min_dist_coeff, final_dist_coeff, rew_offset = 0, 1, 0 reward = rew_offset - min_dist_coeff * min_dist ** 2 - final_dist_coeff * final_dist ** 2 - \ 1e-4 * np.mean(action_cost) - if env.learn_release_step and not self.ball_in_cup: - too_small = (env._release_step<50)*(env._release_step-50)**2 - too_big = (env._release_step>200)*0.2*(env._release_step-200)**2 - reward = reward - too_small -too_big # 1e-7*np.mean(action_cost) + # release step punishment + min_time_bound = 0.1 + max_time_bound = 1.0 + release_time = env.release_step*env.dt + release_time_rew = int(release_timemax_time_bound)*(-30-10*(release_time-max_time_bound)**2) + reward += release_time_rew success = self.ball_in_cup + # print('release time :', release_time) else: reward = - 1e-2 * action_cost # reward = - 1e-4 * action_cost diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py index 267e76e..7c4ee9d 100644 --- a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py @@ -21,24 +21,35 @@ class NewMPWrapper(EpisodicWrapper): [False] # env steps ]) - def _step_callback(self, t: int, env_spec_params: Union[np.ndarray, None], step_action: np.ndarray) -> Union[np.ndarray]: - if self.env.learn_release_step: - return np.concatenate((step_action, np.atleast_1d(env_spec_params))) - else: - return step_action + # def set_mp_action_space(self): + # min_action_bounds, max_action_bounds = self.mp.get_param_bounds() + # if self.mp.learn_tau: + # min_action_bounds[0] = 20*self.env.dt + # max_action_bounds[0] = 260*self.env.dt + # mp_action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), + # dtype=np.float32) + # return mp_action_space + + # def _step_callback(self, t: int, env_spec_params: Union[np.ndarray, None], step_action: np.ndarray) -> Union[np.ndarray]: + # if self.mp.learn_tau: + # return np.concatenate((step_action, np.atleast_1d(env_spec_params))) + # else: + # return step_action def _episode_callback(self, action: np.ndarray) -> Tuple[np.ndarray, Union[np.ndarray, None]]: - if self.env.learn_release_step: - return action[:-1], action[-1] # mp_params, release step + if self.mp.learn_tau: + self.env.env.release_step = action[0]/self.env.dt # Tau value + # self.env.env.release_step = np.clip(action[0]/self.env.dt, 20, 260) # Tau value + return action, None else: return action, None - def set_action_space(self): - if self.env.learn_release_step: - min_action_bounds, max_action_bounds = self.mp.get_param_bounds() - min_action_bounds = np.concatenate((min_action_bounds.numpy(), [self.env.action_space.low[-1]])) - max_action_bounds = np.concatenate((max_action_bounds.numpy(), [self.env.action_space.high[-1]])) - self.action_space = gym.spaces.Box(low=min_action_bounds, high=max_action_bounds, dtype=np.float32) - return self.action_space - else: - return super(NewMPWrapper, self).set_action_space() + # def set_action_space(self): + # if self.mp.learn_tau: + # min_action_bounds, max_action_bounds = self.mp.get_param_bounds() + # min_action_bounds = np.concatenate((min_action_bounds.numpy(), [self.env.action_space.low[-1]])) + # max_action_bounds = np.concatenate((max_action_bounds.numpy(), [self.env.action_space.high[-1]])) + # self.action_space = gym.spaces.Box(low=min_action_bounds, high=max_action_bounds, dtype=np.float32) + # return self.action_space + # else: + # return super(NewMPWrapper, self).set_action_space() diff --git a/alr_envs/alr/mujoco/hopper_jump/__init__.py b/alr_envs/alr/mujoco/hopper_jump/__init__.py index c6db9c2..fbffe48 100644 --- a/alr_envs/alr/mujoco/hopper_jump/__init__.py +++ b/alr_envs/alr/mujoco/hopper_jump/__init__.py @@ -1 +1,2 @@ from .mp_wrapper import MPWrapper, HighCtxtMPWrapper +from .new_mp_wrapper import NewMPWrapper, NewHighCtxtMPWrapper diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index e76cf4f..9a74bb0 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -80,8 +80,6 @@ class ALRHopperJumpEnv(HopperEnv): # overwrite reset_model to make it deterministic def reset_model(self): - noise_low = -self._reset_noise_scale - noise_high = self._reset_noise_scale qpos = self.init_qpos # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) qvel = self.init_qvel # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) @@ -104,14 +102,26 @@ class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): def reset_model(self): self._floor_geom_id = self.model.geom_name2id('floor') self._foot_geom_id = self.model.geom_name2id('foot_geom') - noise_low = -self._reset_noise_scale - noise_high = self._reset_noise_scale + noise_low = -np.ones(self.model.nq)*self._reset_noise_scale + noise_low[1] = 0 + noise_low[2] = -0.3 + noise_low[3] = -0.1 + noise_low[4] = -1.1 + noise_low[5] = -0.785 + + noise_high = np.ones(self.model.nq)*self._reset_noise_scale + noise_high[1] = 0 + noise_high[2] = 0.3 + noise_high[3] = 0 + noise_high[4] = 0 + noise_high[5] = 0.785 + rnd_vec = self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) - rnd_vec[2] *= 0.05 # the angle around the y axis shouldn't be too high as the agent then falls down quickly and + # rnd_vec[2] *= 0.05 # the angle around the y axis shouldn't be too high as the agent then falls down quickly and # can not recover - rnd_vec[1] = np.clip(rnd_vec[1], 0, 0.3) + # rnd_vec[1] = np.clip(rnd_vec[1], 0, 0.3) qpos = self.init_qpos + rnd_vec - qvel = self.init_qvel #+ self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) + qvel = self.init_qvel self.set_state(qpos, qvel) @@ -167,16 +177,19 @@ if __name__ == '__main__': env = ALRHopperJumpRndmPosEnv() obs = env.reset() - for i in range(2000): - # objective.load_result("/tmp/cma") - # test with random actions - ac = env.action_space.sample() - obs, rew, d, info = env.step(ac) - # if i % 10 == 0: - # env.render(mode=render_mode) - env.render(mode=render_mode) - if d: - print('After ', i, ' steps, done: ', d) - env.reset() + for k in range(10): + obs = env.reset() + print('observation :', obs[:6]) + for i in range(200): + # objective.load_result("/tmp/cma") + # test with random actions + ac = env.action_space.sample() + obs, rew, d, info = env.step(ac) + # if i % 10 == 0: + # env.render(mode=render_mode) + env.render(mode=render_mode) + if d: + print('After ', i, ' steps, done: ', d) + env.reset() env.close() \ No newline at end of file diff --git a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py new file mode 100644 index 0000000..9932403 --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py @@ -0,0 +1,29 @@ +from alr_envs.mp.episodic_wrapper import EpisodicWrapper +from typing import Union, Tuple +import numpy as np + + +class NewMPWrapper(EpisodicWrapper): + @property + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qpos[3:6].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[3:6].copy() + + def set_active_obs(self): + return np.hstack([ + [False] * (5 + int(not self.env.exclude_current_positions_from_observation)), # position + [False] * 6, # velocity + [True] + ]) + + +class NewHighCtxtMPWrapper(NewMPWrapper): + def set_active_obs(self): + return np.hstack([ + [True] * (5 + int(not self.env.exclude_current_positions_from_observation)), # position + [False] * 6, # velocity + [False] + ]) \ No newline at end of file diff --git a/alr_envs/alr/mujoco/reacher/alr_reacher.py b/alr_envs/alr/mujoco/reacher/alr_reacher.py index b436fdd..6b36407 100644 --- a/alr_envs/alr/mujoco/reacher/alr_reacher.py +++ b/alr_envs/alr/mujoco/reacher/alr_reacher.py @@ -68,35 +68,35 @@ class ALRReacherEnv(MujocoEnv, utils.EzPickle): def viewer_setup(self): self.viewer.cam.trackbodyid = 0 - # def reset_model(self): - # qpos = self.init_qpos - # if not hasattr(self, "goal"): - # self.goal = np.array([-0.25, 0.25]) - # # self.goal = self.init_qpos.copy()[:2] + 0.05 - # qpos[-2:] = self.goal - # qvel = self.init_qvel - # qvel[-2:] = 0 - # self.set_state(qpos, qvel) - # self._steps = 0 - # - # return self._get_obs() - def reset_model(self): - qpos = self.init_qpos.copy() - while True: - self.goal = self.np_random.uniform(low=-self.n_links / 10, high=self.n_links / 10, size=2) - # self.goal = self.np_random.uniform(low=0, high=self.n_links / 10, size=2) - # self.goal = np.random.uniform(low=[-self.n_links / 10, 0], high=[0, self.n_links / 10], size=2) - if np.linalg.norm(self.goal) < self.n_links / 10: - break + qpos = self.init_qpos + if not hasattr(self, "goal"): + self.goal = np.array([-0.25, 0.25]) + # self.goal = self.init_qpos.copy()[:2] + 0.05 qpos[-2:] = self.goal - qvel = self.init_qvel.copy() + qvel = self.init_qvel qvel[-2:] = 0 self.set_state(qpos, qvel) self._steps = 0 return self._get_obs() + # def reset_model(self): + # qpos = self.init_qpos.copy() + # while True: + # self.goal = self.np_random.uniform(low=-self.n_links / 10, high=self.n_links / 10, size=2) + # # self.goal = self.np_random.uniform(low=0, high=self.n_links / 10, size=2) + # # self.goal = np.random.uniform(low=[-self.n_links / 10, 0], high=[0, self.n_links / 10], size=2) + # if np.linalg.norm(self.goal) < self.n_links / 10: + # break + # qpos[-2:] = self.goal + # qvel = self.init_qvel.copy() + # qvel[-2:] = 0 + # self.set_state(qpos, qvel) + # self._steps = 0 + # + # return self._get_obs() + # def reset_model(self): # qpos = self.np_random.uniform(low=-0.1, high=0.1, size=self.model.nq) + self.init_qpos # while True: diff --git a/alr_envs/mp/episodic_wrapper.py b/alr_envs/mp/episodic_wrapper.py index 092f1bc..7426c15 100644 --- a/alr_envs/mp/episodic_wrapper.py +++ b/alr_envs/mp/episodic_wrapper.py @@ -50,13 +50,10 @@ class EpisodicWrapper(gym.Env, ABC): # rendering self.render_mode = render_mode self.render_kwargs = {} - # self.time_steps = np.linspace(0, self.duration, self.traj_steps + 1) self.time_steps = np.linspace(0, self.duration, self.traj_steps) self.mp.set_mp_times(self.time_steps) # action_bounds = np.inf * np.ones((np.prod(self.mp.num_params))) - min_action_bounds, max_action_bounds = mp.get_param_bounds() - self.mp_action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), - dtype=np.float32) + self.mp_action_space = self.set_mp_action_space() self.action_space = self.set_action_space() self.active_obs = self.set_active_obs() @@ -65,7 +62,7 @@ class EpisodicWrapper(gym.Env, ABC): dtype=self.env.observation_space.dtype) def get_trajectory(self, action: np.ndarray) -> Tuple: - # TODO: this follows the implementation of the mp_pytorch library which includes the paramters tau and delay at + # TODO: this follows the implementation of the mp_pytorch library which includes the parameters tau and delay at # the beginning of the array. ignore_indices = int(self.mp.learn_tau) + int(self.mp.learn_delay) scaled_mp_params = action.copy() @@ -84,6 +81,13 @@ class EpisodicWrapper(gym.Env, ABC): return trajectory, velocity + def set_mp_action_space(self): + """This function can be used to set up an individual space for the parameters of the mp.""" + min_action_bounds, max_action_bounds = self.mp.get_param_bounds() + mp_action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), + dtype=np.float32) + return mp_action_space + def set_action_space(self): """ This function can be used to modify the action space for considering actions which are not learned via motion @@ -179,6 +183,7 @@ class EpisodicWrapper(gym.Env, ABC): step_action = self.controller.get_action(pos_vel[0], pos_vel[1], self.current_pos, self.current_vel) step_action = self._step_callback(t, env_spec_params, step_action) # include possible callback info c_action = np.clip(step_action, self.env.action_space.low, self.env.action_space.high) + # print('step/clipped action ratio: ', step_action/c_action) obs, c_reward, done, info = self.env.step(c_action) if self.verbose >= 2: actions[t, :] = c_action diff --git a/alr_envs/utils/make_env_helpers.py b/alr_envs/utils/make_env_helpers.py index 0c06906..f22e0d7 100644 --- a/alr_envs/utils/make_env_helpers.py +++ b/alr_envs/utils/make_env_helpers.py @@ -156,12 +156,11 @@ def make_mp_from_kwargs( ep_wrapper_kwargs['duration'] = dummy_env.spec.max_episode_steps*dummy_env.dt if phase_kwargs.get('tau', None) is None: phase_kwargs['tau'] = ep_wrapper_kwargs['duration'] - action_dim = mp_kwargs.pop('num_dof', None) - action_dim = action_dim if action_dim is not None else np.prod(dummy_env.action_space.shape).item() + mp_kwargs['action_dim'] = mp_kwargs.get('action_dim', np.prod(dummy_env.action_space.shape).item()) phase_gen = get_phase_generator(**phase_kwargs) basis_gen = get_basis_generator(phase_generator=phase_gen, **basis_kwargs) controller = get_controller(**controller_kwargs) - mp = get_movement_primitive(action_dim=action_dim, basis_generator=basis_gen, **mp_kwargs) + mp = get_movement_primitive(basis_generator=basis_gen, **mp_kwargs) _env = _make_wrapped_env(env_id=env_id, wrappers=wrappers, mp=mp, controller=controller, ep_wrapper_kwargs=ep_wrapper_kwargs, seed=seed, **kwargs) return _env From 647f086a8d3545a96f5018ebeed489625a08f01c Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 17 May 2022 10:31:47 +0200 Subject: [PATCH 029/104] remove unnecessary code lines --- alr_envs/alr/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index fa9b71b..1101020 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -656,9 +656,7 @@ for _v in _versions: "controller_kwargs": { 'controller_type': 'motor', "p_gains": np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]), - # "p_gains": 0.125*np.array([200, 300, 100, 100, 10, 10, 2.5]), "d_gains": np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]), - # "d_gains": 0.025*np.array([7, 15, 5, 2.5, 0.3, 0.3, 0.05]), }, "basis_generator_kwargs": { 'basis_generator_type': 'zero_rbf', From f1a96c055b7787831f494cbd41933a221dd46c97 Mon Sep 17 00:00:00 2001 From: Onur Date: Sun, 29 May 2022 11:58:01 +0200 Subject: [PATCH 030/104] safety --- alr_envs/alr/__init__.py | 90 ++++++++- alr_envs/alr/mujoco/__init__.py | 2 +- alr_envs/alr/mujoco/ant_jump/__init__.py | 1 + .../alr/mujoco/ant_jump/new_mp_wrapper.py | 21 +++ .../assets/beerpong_wo_cup_big_table.xml | 2 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 29 ++- .../mujoco/beerpong/beerpong_reward_staged.py | 154 ++++----------- .../alr/mujoco/beerpong/new_mp_wrapper.py | 6 + .../assets/{hopper.xml => hopper_jump.xml} | 4 + .../alr/mujoco/hopper_jump/hopper_jump.py | 178 +++++++++++++++--- .../alr/mujoco/hopper_jump/new_mp_wrapper.py | 12 +- alr_envs/mp/episodic_wrapper.py | 2 +- 12 files changed, 333 insertions(+), 168 deletions(-) create mode 100644 alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py rename alr_envs/alr/mujoco/hopper_jump/assets/{hopper.xml => hopper_jump.xml} (92%) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 1101020..9dc31ae 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -252,7 +252,8 @@ register( max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, - "context": False + "context": False, + "healthy_rewasrd": 1.0 } ) register( @@ -273,6 +274,17 @@ register( "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP } ) + +register( + id='ALRHopperJump-v3', + entry_point='alr_envs.alr.mujoco:ALRHopperXYJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, + "context": True, + "healthy_reward": 1.0 + } +) # CtxtFree are v0, Contextual are v1 register( id='ALRHopperJumpOnBox-v0', @@ -723,6 +735,46 @@ for _v in _versions: ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) +## AntJump +_versions = ["v0", "v1"] +for _v in _versions: + _env_id = f'ALRAntJumpProMP-{_v}' + register( + id= _env_id, + entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + kwargs={ + "name": f"alr_envs:ALRAntJump-{_v}", + "wrappers": [mujoco.ant_jump.NewMPWrapper], + "ep_wrapper_kwargs": { + "weight_scale": 1 + }, + "movement_primitives_kwargs": { + 'movement_primitives_type': 'promp', + 'action_dim': 8 + }, + "phase_generator_kwargs": { + 'phase_generator_type': 'linear', + 'delay': 0, + 'tau': 10, # initial value + 'learn_tau': False, + 'learn_delay': False + }, + "controller_kwargs": { + 'controller_type': 'motor', + "p_gains": np.ones(8), + "d_gains": 0.1*np.ones(8), + }, + "basis_generator_kwargs": { + 'basis_generator_type': 'zero_rbf', + 'num_basis': 5, + 'num_basis_zero_start': 2 + } + } + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + + + ## HalfCheetahJump _versions = ["v0", "v1"] for _v in _versions: @@ -877,6 +929,42 @@ register( ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ALRHopperJumpProMP-v2") + +## HopperJump +register( + id= "ALRHopperJumpProMP-v3", + entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + kwargs={ + "name": f"alr_envs:ALRHopperJump-v3", + "wrappers": [mujoco.hopper_jump.NewMPWrapper], + "ep_wrapper_kwargs": { + "weight_scale": 1 + }, + "movement_primitives_kwargs": { + 'movement_primitives_type': 'promp', + 'action_dim': 3 + }, + "phase_generator_kwargs": { + 'phase_generator_type': 'linear', + 'delay': 0, + 'tau': 2, # initial value + 'learn_tau': False, + 'learn_delay': False + }, + "controller_kwargs": { + 'controller_type': 'motor', + "p_gains": np.ones(3), + "d_gains": 0.1*np.ones(3), + }, + "basis_generator_kwargs": { + 'basis_generator_type': 'zero_rbf', + 'num_basis': 5, + 'num_basis_zero_start': 2 + } + } +) +ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ALRHopperJumpProMP-v3") + ## HopperJumpOnBox _versions = ["v0", "v1"] for _v in _versions: diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index fb86186..5c04b03 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -5,7 +5,7 @@ from .table_tennis.tt_gym import TTEnvGym from .beerpong.beerpong import ALRBeerBongEnv from .ant_jump.ant_jump import ALRAntJumpEnv from .half_cheetah_jump.half_cheetah_jump import ALRHalfCheetahJumpEnv -from .hopper_jump.hopper_jump import ALRHopperJumpEnv, ALRHopperJumpRndmPosEnv +from .hopper_jump.hopper_jump import ALRHopperJumpEnv, ALRHopperJumpRndmPosEnv, ALRHopperXYJumpEnv from .hopper_jump.hopper_jump_on_box import ALRHopperJumpOnBoxEnv from .hopper_throw.hopper_throw import ALRHopperThrowEnv from .hopper_throw.hopper_throw_in_basket import ALRHopperThrowInBasketEnv diff --git a/alr_envs/alr/mujoco/ant_jump/__init__.py b/alr_envs/alr/mujoco/ant_jump/__init__.py index c5e6d2f..5d15867 100644 --- a/alr_envs/alr/mujoco/ant_jump/__init__.py +++ b/alr_envs/alr/mujoco/ant_jump/__init__.py @@ -1 +1,2 @@ from .mp_wrapper import MPWrapper +from .new_mp_wrapper import NewMPWrapper diff --git a/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py new file mode 100644 index 0000000..c33048f --- /dev/null +++ b/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py @@ -0,0 +1,21 @@ +from alr_envs.mp.episodic_wrapper import EpisodicWrapper +from typing import Union, Tuple +import numpy as np + + + +class NewMPWrapper(EpisodicWrapper): + + def set_active_obs(self): + return np.hstack([ + [False] * 111, # ant has 111 dimensional observation space !! + [True] # goal height + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray]: + return self.env.sim.data.qpos[7:15].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[6:14].copy() diff --git a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml index 436b36c..78e2c32 100644 --- a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml +++ b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml @@ -144,7 +144,7 @@ solref="-10000 -100"/> - + diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 36998b9..017bfcd 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -7,8 +7,12 @@ from gym.envs.mujoco import MujocoEnv from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward -CUP_POS_MIN = np.array([-0.32, -2.2]) -CUP_POS_MAX = np.array([0.32, -1.2]) +CUP_POS_MIN = np.array([-1.42, -4.05]) +CUP_POS_MAX = np.array([1.42, -1.25]) + + +# CUP_POS_MIN = np.array([-0.32, -2.2]) +# CUP_POS_MAX = np.array([0.32, -1.2]) # smaller context space -> Easier task # CUP_POS_MIN = np.array([-0.16, -2.2]) @@ -24,8 +28,10 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.cup_goal_pos = np.array(cup_goal_pos) self._steps = 0 + # self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", + # "beerpong_wo_cup" + ".xml") self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", - "beerpong_wo_cup" + ".xml") + "beerpong_wo_cup_big_table" + ".xml") self.j_min = np.array([-2.6, -1.985, -2.8, -0.9, -4.55, -1.5707, -2.7]) self.j_max = np.array([2.6, 1.985, 2.8, 3.14159, 1.25, 1.5707, 2.7]) @@ -100,10 +106,6 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): return self._get_obs() def step(self, a): - # if a.shape[0] == 8: # we learn also when to release the ball - # self._release_step = a[-1] - # self._release_step = np.clip(self._release_step, 50, 250) - # self.release_step = 0.5/self.dt reward_dist = 0.0 angular_vel = 0.0 applied_action = a @@ -170,16 +172,11 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): [self._steps], ]) - # TODO - @property - def active_obs(self): - return np.hstack([ - [False] * 7, # cos - [False] * 7, # sin - [True] * 2, # xy position of cup - [False] # env steps - ]) +class ALRBeerPongStepEnv(ALRBeerBongEnv): + def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, + rndm_goal=False, cup_goal_pos=None): + super(ALRBeerPongStepEnv, self).__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) if __name__ == "__main__": env = ALRBeerBongEnv(rndm_goal=True) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index bb5dd3f..cb75127 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -40,6 +40,7 @@ class BeerPongReward: self.cup_z_axes = None self.collision_penalty = 500 self.reset(None) + self.is_initialized = False def reset(self, noisy): self.ball_traj = [] @@ -55,113 +56,60 @@ class BeerPongReward: self.ball_wall_contact = False self.ball_cup_contact = False self.ball_in_cup = False + self.dist_ground_cup = -1 # distance floor to cup if first floor contact self.noisy_bp = noisy self._t_min_final_dist = -1 def compute_reward(self, env, action): - self.ball_id = env.sim.model._body_name2id["ball"] - self.ball_collision_id = env.sim.model._geom_name2id["ball_geom"] - self.goal_id = env.sim.model._site_name2id["cup_goal_table"] - self.goal_final_id = env.sim.model._site_name2id["cup_goal_final_table"] - self.cup_collision_ids = [env.sim.model._geom_name2id[name] for name in self.cup_collision_objects] - self.cup_table_id = env.sim.model._body_name2id["cup_table"] - self.table_collision_id = env.sim.model._geom_name2id["table_contact_geom"] - self.wall_collision_id = env.sim.model._geom_name2id["wall"] - self.cup_table_collision_id = env.sim.model._geom_name2id["cup_base_table_contact"] - self.init_ball_pos_site_id = env.sim.model._site_name2id["init_ball_pos_site"] - self.ground_collision_id = env.sim.model._geom_name2id["ground"] - self.robot_collision_ids = [env.sim.model._geom_name2id[name] for name in self.robot_collision_objects] + + if not self.is_initialized: + self.is_initialized = True + self.ball_id = env.sim.model._body_name2id["ball"] + self.ball_collision_id = env.sim.model._geom_name2id["ball_geom"] + self.goal_id = env.sim.model._site_name2id["cup_goal_table"] + self.goal_final_id = env.sim.model._site_name2id["cup_goal_final_table"] + self.cup_collision_ids = [env.sim.model._geom_name2id[name] for name in self.cup_collision_objects] + self.cup_table_id = env.sim.model._body_name2id["cup_table"] + self.table_collision_id = env.sim.model._geom_name2id["table_contact_geom"] + self.wall_collision_id = env.sim.model._geom_name2id["wall"] + self.cup_table_collision_id = env.sim.model._geom_name2id["cup_base_table_contact"] + self.init_ball_pos_site_id = env.sim.model._site_name2id["init_ball_pos_site"] + self.ground_collision_id = env.sim.model._geom_name2id["ground"] + self.robot_collision_ids = [env.sim.model._geom_name2id[name] for name in self.robot_collision_objects] goal_pos = env.sim.data.site_xpos[self.goal_id] ball_pos = env.sim.data.body_xpos[self.ball_id] ball_vel = env.sim.data.body_xvelp[self.ball_id] goal_final_pos = env.sim.data.site_xpos[self.goal_final_id] + + self._check_contacts(env.sim) self.dists.append(np.linalg.norm(goal_pos - ball_pos)) self.dists_final.append(np.linalg.norm(goal_final_pos - ball_pos)) - + self.dist_ground_cup = np.linalg.norm(ball_pos-goal_pos) \ + if self.ball_ground_contact_first and self.dist_ground_cup == -1 else self.dist_ground_cup action_cost = np.sum(np.square(action)) self.action_costs.append(action_cost) - # ##################### Reward function which forces to bounce once on the table (tanh) ######################## - # if not self.ball_table_contact: - # self.ball_table_contact = self._check_collision_single_objects(env.sim, self.ball_collision_id, - # self.table_collision_id) - # - # self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) - # if env._steps == env.ep_length - 1 or self._is_collided: - # min_dist = np.min(self.dists) - # final_dist = self.dists_final[-1] - # - # ball_in_cup = self._check_collision_single_objects(env.sim, self.ball_collision_id, - # self.cup_table_collision_id) - # - # # encourage bounce before falling into cup - # if not ball_in_cup: - # if not self.ball_table_contact: - # reward = 0.2 * (1 - np.tanh(0.5*min_dist)) + 0.1 * (1 - np.tanh(0.5*final_dist)) - # else: - # reward = (1 - np.tanh(0.5*min_dist)) + 0.5 * (1 - np.tanh(0.5*final_dist)) - # else: - # if not self.ball_table_contact: - # reward = 2 * (1 - np.tanh(0.5*final_dist)) + 1 * (1 - np.tanh(0.5*min_dist)) + 1 - # else: - # reward = 2 * (1 - np.tanh(0.5*final_dist)) + 1 * (1 - np.tanh(0.5*min_dist)) + 3 - # - # # reward = - 1 * cost - self.collision_penalty * int(self._is_collided) - # success = ball_in_cup - # crash = self._is_collided - # else: - # reward = - 1e-2 * action_cost - # success = False - # crash = False - # ################################################################################################################ - - ##################### Reward function which does not force to bounce once on the table (tanh) ################ - # self._check_contacts(env.sim) - # self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) - # if env._steps == env.ep_length - 1 or self._is_collided: - # min_dist = np.min(self.dists) - # final_dist = self.dists_final[-1] - # - # # encourage bounce before falling into cup - # if not self.ball_in_cup: - # if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact: - # min_dist_coeff, final_dist_coeff, rew_offset = 0.2, 0.1, 0 - # # reward = 0.2 * (1 - np.tanh(0.5*min_dist)) + 0.1 * (1 - np.tanh(0.5*final_dist)) - # else: - # min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, 0 - # # reward = (1 - np.tanh(0.5*min_dist)) + 0.5 * (1 - np.tanh(0.5*final_dist)) - # else: - # min_dist_coeff, final_dist_coeff, rew_offset = 1, 2, 3 - # # reward = 2 * (1 - np.tanh(0.5*final_dist)) + 1 * (1 - np.tanh(0.5*min_dist)) + 3 - # - # reward = final_dist_coeff * (1 - np.tanh(0.5 * final_dist)) + min_dist_coeff * (1 - np.tanh(0.5 * min_dist)) \ - # + rew_offset - # success = self.ball_in_cup - # crash = self._is_collided - # else: - # reward = - 1e-2 * action_cost - # success = False - # crash = False - ################################################################################################################ - # # ##################### Reward function which does not force to bounce once on the table (quad dist) ############ - self._check_contacts(env.sim) + self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) + if env._steps == env.ep_length - 1 or self._is_collided: min_dist = np.min(self.dists) final_dist = self.dists_final[-1] - # if self.ball_ground_contact_first: - # min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -6 - # else: - if not self.ball_in_cup: - if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact: - min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -4 - else: - min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -2 + if self.ball_ground_contact_first: + min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 2, -4 # relative rew offset when first bounding on ground + # min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 0, -6 # absolute rew offset when first bouncing on ground else: - min_dist_coeff, final_dist_coeff, rew_offset = 0, 1, 0 + if not self.ball_in_cup: + if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact: + min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 0, -4 + else: + min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 0, -2 + else: + min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 0, 1, 0 ,0 + # dist_ground_cup = 1 * self.dist_ground_cup reward = rew_offset - min_dist_coeff * min_dist ** 2 - final_dist_coeff * final_dist ** 2 - \ - 1e-4 * np.mean(action_cost) + 1e-4 * np.mean(action_cost) - ground_contact_dist_coeff*self.dist_ground_cup ** 2 # 1e-7*np.mean(action_cost) # release step punishment min_time_bound = 0.1 @@ -172,43 +120,13 @@ class BeerPongReward: reward += release_time_rew success = self.ball_in_cup # print('release time :', release_time) + # print('dist_ground_cup :', dist_ground_cup) else: reward = - 1e-2 * action_cost # reward = - 1e-4 * action_cost # reward = 0 success = False # ################################################################################################################ - - # # # ##################### Reward function which does not force to bounce once on the table (quad dist) ############ - # self._check_contacts(env.sim) - # self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) - # if env._steps == env.ep_length - 1 or self._is_collided: - # min_dist = np.min(self.dists) - # final_dist = self.dists_final[-1] - # - # if not self.ball_in_cup: - # if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact: - # min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -6 - # else: - # if self.ball_ground_contact_first: - # min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -4 - # else: - # min_dist_coeff, final_dist_coeff, rew_offset = 1, 0.5, -2 - # else: - # if self.ball_ground_contact_first: - # min_dist_coeff, final_dist_coeff, rew_offset = 0, 1, -1 - # else: - # min_dist_coeff, final_dist_coeff, rew_offset = 0, 1, 0 - # reward = rew_offset - min_dist_coeff * min_dist ** 2 - final_dist_coeff * final_dist ** 2 - \ - # 1e-7 * np.mean(action_cost) - # # 1e-4*np.mean(action_cost) - # success = self.ball_in_cup - # else: - # # reward = - 1e-2 * action_cost - # # reward = - 1e-4 * action_cost - # reward = 0 - # success = False - # ################################################################################################################ infos = {} infos["success"] = success infos["is_collided"] = self._is_collided diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py index 7c4ee9d..9683687 100644 --- a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py @@ -44,6 +44,12 @@ class NewMPWrapper(EpisodicWrapper): else: return action, None + def set_context(self, context): + xyz = np.zeros(3) + xyz[:2] = context + xyz[-1] = 0.840 + self.env.env.model.body_pos[self.env.env.cup_table_id] = xyz + return self.get_observation_from_step(self.env.env._get_obs()) # def set_action_space(self): # if self.mp.learn_tau: # min_action_bounds, max_action_bounds = self.mp.get_param_bounds() diff --git a/alr_envs/alr/mujoco/hopper_jump/assets/hopper.xml b/alr_envs/alr/mujoco/hopper_jump/assets/hopper_jump.xml similarity index 92% rename from alr_envs/alr/mujoco/hopper_jump/assets/hopper.xml rename to alr_envs/alr/mujoco/hopper_jump/assets/hopper_jump.xml index f18bc46..3348bab 100644 --- a/alr_envs/alr/mujoco/hopper_jump/assets/hopper.xml +++ b/alr_envs/alr/mujoco/hopper_jump/assets/hopper_jump.xml @@ -25,12 +25,16 @@ + + + + diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index 9a74bb0..979e224 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -1,5 +1,6 @@ from gym.envs.mujoco.hopper_v3 import HopperEnv import numpy as np +import os MAX_EPISODE_STEPS_HOPPERJUMP = 250 @@ -14,13 +15,13 @@ class ALRHopperJumpEnv(HopperEnv): """ def __init__(self, - xml_file='hopper.xml', + xml_file='hopper_jump.xml', forward_reward_weight=1.0, ctrl_cost_weight=1e-3, healthy_reward=0.0, penalty=0.0, context=True, - terminate_when_unhealthy=True, + terminate_when_unhealthy=False, healthy_state_range=(-100.0, 100.0), healthy_z_range=(0.5, float('inf')), healthy_angle_range=(-float('inf'), float('inf')), @@ -34,6 +35,13 @@ class ALRHopperJumpEnv(HopperEnv): self.goal = 0 self.context = context self.exclude_current_positions_from_observation = exclude_current_positions_from_observation + self._floor_geom_id = None + self._foot_geom_id = None + self.contact_with_floor = False + self.init_floor_contact = False + self.has_left_floor = False + self.contact_dist = None + xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, exclude_current_positions_from_observation) @@ -43,28 +51,36 @@ class ALRHopperJumpEnv(HopperEnv): self.current_step += 1 self.do_simulation(action, self.frame_skip) height_after = self.get_body_com("torso")[2] + site_pos_after = self.sim.data.site_xpos[self.model.site_name2id('foot_site')].copy() self.max_height = max(height_after, self.max_height) ctrl_cost = self.control_cost(action) costs = ctrl_cost done = False - + rewards = 0 if self.current_step >= self.max_episode_steps: hight_goal_distance = -10*np.linalg.norm(self.max_height - self.goal) if self.context else self.max_height - healthy_reward = 0 if self.context else self.healthy_reward * self.current_step + healthy_reward = 0 if self.context else self.healthy_reward * 2 # self.current_step height_reward = self._forward_reward_weight * hight_goal_distance # maybe move reward calculation into if structure and define two different _forward_reward_weight variables for context and episodic seperatley rewards = height_reward + healthy_reward - else: - # penalty for wrong start direction of first two joints; not needed, could be removed - rewards = ((action[:2] > 0) * self.penalty).sum() if self.current_step < 10 else 0 + # else: + # # penalty for wrong start direction of first two joints; not needed, could be removed + # rewards = ((action[:2] > 0) * self.penalty).sum() if self.current_step < 10 else 0 observation = self._get_obs() reward = rewards - costs + # info = { + # 'height' : height_after, + # 'max_height': self.max_height, + # 'goal' : self.goal + # } info = { - 'height' : height_after, + 'height': height_after, + 'x_pos': site_pos_after, 'max_height': self.max_height, - 'goal' : self.goal + 'height_rew': self.max_height, + 'healthy_reward': self.healthy_reward * 2 } return observation, reward, done, info @@ -73,7 +89,7 @@ class ALRHopperJumpEnv(HopperEnv): return np.append(super()._get_obs(), self.goal) def reset(self): - self.goal = np.random.uniform(1.4, 2.3, 1) # 1.3 2.3 + self.goal = np.random.uniform(1.4, 2.16, 1) # 1.3 2.3 self.max_height = 0 self.current_step = 0 return super().reset() @@ -87,14 +103,124 @@ class ALRHopperJumpEnv(HopperEnv): self.set_state(qpos, qvel) observation = self._get_obs() + self.has_left_floor = False + self.contact_with_floor = False + self.init_floor_contact = False + self.contact_dist = None return observation + def _contact_checker(self, id_1, id_2): + for coni in range(0, self.sim.data.ncon): + con = self.sim.data.contact[coni] + collision = con.geom1 == id_1 and con.geom2 == id_2 + collision_trans = con.geom1 == id_2 and con.geom2 == id_1 + if collision or collision_trans: + return True + return False + + +class ALRHopperXYJumpEnv(ALRHopperJumpEnv): + # The goal here is the desired x-Position of the Torso + + def step(self, action): + + self._floor_geom_id = self.model.geom_name2id('floor') + self._foot_geom_id = self.model.geom_name2id('foot_geom') + + self.current_step += 1 + self.do_simulation(action, self.frame_skip) + height_after = self.get_body_com("torso")[2] + site_pos_after = self.sim.data.site_xpos[self.model.site_name2id('foot_site')].copy() + self.max_height = max(height_after, self.max_height) + + # floor_contact = self._contact_checker(self._floor_geom_id, self._foot_geom_id) if not self.contact_with_floor else False + # self.init_floor_contact = floor_contact if not self.init_floor_contact else self.init_floor_contact + # self.has_left_floor = not floor_contact if self.init_floor_contact and not self.has_left_floor else self.has_left_floor + # self.contact_with_floor = floor_contact if not self.contact_with_floor and self.has_left_floor else self.contact_with_floor + + floor_contact = self._contact_checker(self._floor_geom_id, + self._foot_geom_id) if not self.contact_with_floor else False + if not self.init_floor_contact: + self.init_floor_contact = floor_contact + if self.init_floor_contact and not self.has_left_floor: + self.has_left_floor = not floor_contact + if not self.contact_with_floor and self.has_left_floor: + self.contact_with_floor = floor_contact + + if self.contact_dist is None and self.contact_with_floor: + self.contact_dist = np.linalg.norm(self.sim.data.site_xpos[self.model.site_name2id('foot_site')] + - np.array([self.goal, 0, 0], dtype=object))[0] + + ctrl_cost = self.control_cost(action) + costs = ctrl_cost + done = False + goal_dist = 0 + rewards = 0 + if self.current_step >= self.max_episode_steps: + # healthy_reward = 0 if self.context else self.healthy_reward * self.current_step + healthy_reward = self.healthy_reward * 2 #* self.current_step + goal_dist = np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0], dtype=object))[0] + contact_dist = self.contact_dist if self.contact_dist is not None else 5 + dist_reward = self._forward_reward_weight * (-3*goal_dist + 10*self.max_height - 2*contact_dist) + rewards = dist_reward + healthy_reward + + # else: + ## penalty for wrong start direction of first two joints; not needed, could be removed + # rewards = ((action[:2] > 0) * self.penalty).sum() if self.current_step < 10 else 0 + + observation = self._get_obs() + reward = rewards - costs + info = { + 'height': height_after, + 'x_pos': site_pos_after, + 'max_height': self.max_height, + 'goal': self.goal, + 'dist_rew': goal_dist, + 'height_rew': self.max_height, + 'healthy_reward': self.healthy_reward * 2 + } + + return observation, reward, done, info + + def reset_model(self): + self.init_qpos[1] = 1.5 + self._floor_geom_id = self.model.geom_name2id('floor') + self._foot_geom_id = self.model.geom_name2id('foot_geom') + noise_low = -np.zeros(self.model.nq) + noise_low[3] = -0.5 + noise_low[4] = -0.2 + noise_low[5] = 0 + + noise_high = np.zeros(self.model.nq) + noise_high[3] = 0 + noise_high[4] = 0 + noise_high[5] = 0.785 + + rnd_vec = self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + qpos = self.init_qpos + rnd_vec + qvel = self.init_qvel + + self.set_state(qpos, qvel) + + observation = self._get_obs() + self.has_left_floor = False + self.contact_with_floor = False + self.init_floor_contact = False + self.contact_dist = None + + return observation + + def reset(self): + super().reset() + # self.goal = np.random.uniform(-1.5, 1.5, 1) + self.goal = np.random.uniform(0, 1.5, 1) + # self.goal = np.array([1.5]) + self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = np.array([self.goal, 0, 0], dtype=object) + return self.reset_model() + class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): def __init__(self, max_episode_steps=250): - self.contact_with_floor = False - self._floor_geom_id = None - self._foot_geom_id = None super(ALRHopperJumpRndmPosEnv, self).__init__(exclude_current_positions_from_observation=False, reset_noise_scale=5e-1, max_episode_steps=max_episode_steps) @@ -104,17 +230,17 @@ class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): self._foot_geom_id = self.model.geom_name2id('foot_geom') noise_low = -np.ones(self.model.nq)*self._reset_noise_scale noise_low[1] = 0 - noise_low[2] = -0.3 - noise_low[3] = -0.1 - noise_low[4] = -1.1 - noise_low[5] = -0.785 + noise_low[2] = 0 + noise_low[3] = -0.2 + noise_low[4] = -0.2 + noise_low[5] = -0.1 noise_high = np.ones(self.model.nq)*self._reset_noise_scale noise_high[1] = 0 - noise_high[2] = 0.3 + noise_high[2] = 0 noise_high[3] = 0 noise_high[4] = 0 - noise_high[5] = 0.785 + noise_high[5] = 0.1 rnd_vec = self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) # rnd_vec[2] *= 0.05 # the angle around the y axis shouldn't be too high as the agent then falls down quickly and @@ -162,24 +288,18 @@ class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): return observation, reward, done, info - def _contact_checker(self, id_1, id_2): - for coni in range(0, self.sim.data.ncon): - con = self.sim.data.contact[coni] - collision = con.geom1 == id_1 and con.geom2 == id_2 - collision_trans = con.geom1 == id_2 and con.geom2 == id_1 - if collision or collision_trans: - return True - return False + if __name__ == '__main__': render_mode = "human" # "human" or "partial" or "final" # env = ALRHopperJumpEnv() - env = ALRHopperJumpRndmPosEnv() + env = ALRHopperXYJumpEnv() + # env = ALRHopperJumpRndmPosEnv() obs = env.reset() for k in range(10): obs = env.reset() - print('observation :', obs[:6]) + print('observation :', obs[:]) for i in range(200): # objective.load_result("/tmp/cma") # test with random actions diff --git a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py index 9932403..31be6be 100644 --- a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py @@ -12,9 +12,19 @@ class NewMPWrapper(EpisodicWrapper): def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qvel[3:6].copy() + # # random goal + # def set_active_obs(self): + # return np.hstack([ + # [False] * (5 + int(not self.env.exclude_current_positions_from_observation)), # position + # [False] * 6, # velocity + # [True] + # ]) + + # Random x goal + random init pos def set_active_obs(self): return np.hstack([ - [False] * (5 + int(not self.env.exclude_current_positions_from_observation)), # position + [False] * (2 + int(not self.env.exclude_current_positions_from_observation)), # position + [True] * 3, # set to true if randomize initial pos [False] * 6, # velocity [True] ]) diff --git a/alr_envs/mp/episodic_wrapper.py b/alr_envs/mp/episodic_wrapper.py index 7426c15..21fb035 100644 --- a/alr_envs/mp/episodic_wrapper.py +++ b/alr_envs/mp/episodic_wrapper.py @@ -205,7 +205,7 @@ class EpisodicWrapper(gym.Env, ABC): infos['step_actions'] = actions[:t + 1] infos['step_observations'] = observations[:t + 1] infos['step_rewards'] = rewards[:t + 1] - infos['trajectory_length'] = t + 1 + infos['trajectory_length'] = t + 1 done = True return self.get_observation_from_step(obs), trajectory_return, done, infos From 863ef77e5ee178cdc9975c151d05d38fe53cd88e Mon Sep 17 00:00:00 2001 From: Onur Date: Sun, 29 May 2022 11:59:02 +0200 Subject: [PATCH 031/104] safety --- alr_envs/alr/mujoco/beerpong/beerpong.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 017bfcd..6790523 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -106,6 +106,10 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): return self._get_obs() def step(self, a): + # if a.shape[0] == 8: # we learn also when to release the ball + # self._release_step = a[-1] + # self._release_step = np.clip(self._release_step, 50, 250) + # self.release_step = 0.5/self.dt reward_dist = 0.0 angular_vel = 0.0 applied_action = a @@ -172,11 +176,16 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): [self._steps], ]) + # TODO + @property + def active_obs(self): + return np.hstack([ + [False] * 7, # cos + [False] * 7, # sin + [True] * 2, # xy position of cup + [False] # env steps + ]) -class ALRBeerPongStepEnv(ALRBeerBongEnv): - def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, - rndm_goal=False, cup_goal_pos=None): - super(ALRBeerPongStepEnv, self).__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) if __name__ == "__main__": env = ALRBeerBongEnv(rndm_goal=True) From 3cc1cd1456ad927d1f1838f83766dad466fd9a3c Mon Sep 17 00:00:00 2001 From: Onur Date: Sun, 29 May 2022 12:15:04 +0200 Subject: [PATCH 032/104] bp frameskip version --- alr_envs/alr/__init__.py | 10 ++-- alr_envs/alr/mujoco/beerpong/beerpong.py | 57 +++++++++---------- .../mujoco/beerpong/beerpong_reward_staged.py | 8 ++- 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 9dc31ae..3d42b9c 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -400,10 +400,11 @@ register(id='TableTennis4DCtxt-v0', register( id='ALRBeerPong-v0', entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', - max_episode_steps=600, + max_episode_steps=150, kwargs={ "rndm_goal": False, - "cup_goal_pos": [0.1, -2.0] + "cup_goal_pos": [0.1, -2.0], + "frameskip": 4 } ) @@ -412,10 +413,11 @@ register( register( id='ALRBeerPong-v1', entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', - max_episode_steps=600, + max_episode_steps=150, kwargs={ "rndm_goal": True, - "cup_goal_pos": [-0.3, -1.2] + "cup_goal_pos": [-0.3, -1.2], + "frameskip": 4 } ) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 6790523..4f7b85f 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -50,7 +50,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): # self._release_step = 130 # time step of ball release self.release_step = 100 # time step of ball release - self.ep_length = 600 # based on 3 seconds with dt = 0.005 int(self.sim_time / self.dt) + self.ep_length = 600//frame_skip self.cup_table_id = 10 if noisy: @@ -59,8 +59,8 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.noise_std = 0 reward_function = BeerPongReward self.reward_function = reward_function() - - MujocoEnv.__init__(self, self.xml_path, frame_skip) + self.repeat_action = frame_skip + MujocoEnv.__init__(self, self.xml_path, frame_skip=1) utils.EzPickle.__init__(self) @property @@ -106,26 +106,26 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): return self._get_obs() def step(self, a): - # if a.shape[0] == 8: # we learn also when to release the ball - # self._release_step = a[-1] - # self._release_step = np.clip(self._release_step, 50, 250) - # self.release_step = 0.5/self.dt reward_dist = 0.0 angular_vel = 0.0 - applied_action = a - reward_ctrl = - np.square(applied_action).sum() - if self.apply_gravity_comp: - applied_action += self.sim.data.qfrc_bias[:len(applied_action)].copy() / self.model.actuator_gear[:, 0] - try: - self.do_simulation(applied_action, self.frame_skip) - if self._steps < self.release_step: - self.sim.data.qpos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() - self.sim.data.qvel[7::] = self.sim.data.site_xvelp[self.ball_site_id, :].copy() - elif self._steps == self.release_step and self.add_noise: - self.sim.data.qvel[7::] += self.noise_std * np.random.randn(3) - crash = False - except mujoco_py.builder.MujocoException: - crash = True + + for _ in range(self.repeat_action): + if self.apply_gravity_comp: + applied_action = a + self.sim.data.qfrc_bias[:len(a)].copy() / self.model.actuator_gear[:, 0] + else: + applied_action = a + try: + self.do_simulation(applied_action, self.frame_skip) + self.reward_function.initialize(self) + self.reward_function.check_contacts(self.sim) + if self._steps < self.release_step: + self.sim.data.qpos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() + self.sim.data.qvel[7::] = self.sim.data.site_xvelp[self.ball_site_id, :].copy() + elif self._steps == self.release_step and self.add_noise: + self.sim.data.qvel[7::] += self.noise_std * np.random.randn(3) + crash = False + except mujoco_py.builder.MujocoException: + crash = True # joint_cons_viol = self.check_traj_in_joint_limits() ob = self._get_obs() @@ -148,7 +148,6 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): ball_vel = np.zeros(3) infos = dict(reward_dist=reward_dist, - reward_ctrl=reward_ctrl, reward=reward, velocity=angular_vel, # traj=self._q_pos, @@ -176,16 +175,14 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): [self._steps], ]) - # TODO @property - def active_obs(self): - return np.hstack([ - [False] * 7, # cos - [False] * 7, # sin - [True] * 2, # xy position of cup - [False] # env steps - ]) + def dt(self): + return super(ALRBeerBongEnv, self).dt()*self.repeat_action +class ALRBeerPongStepEnv(ALRBeerBongEnv): + def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, + rndm_goal=False, cup_goal_pos=None): + super(ALRBeerPongStepEnv, self).__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) if __name__ == "__main__": env = ALRBeerBongEnv(rndm_goal=True) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index cb75127..3ef8b7b 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -60,7 +60,7 @@ class BeerPongReward: self.noisy_bp = noisy self._t_min_final_dist = -1 - def compute_reward(self, env, action): + def initialize(self, env): if not self.is_initialized: self.is_initialized = True @@ -77,12 +77,14 @@ class BeerPongReward: self.ground_collision_id = env.sim.model._geom_name2id["ground"] self.robot_collision_ids = [env.sim.model._geom_name2id[name] for name in self.robot_collision_objects] + def compute_reward(self, env, action): + goal_pos = env.sim.data.site_xpos[self.goal_id] ball_pos = env.sim.data.body_xpos[self.ball_id] ball_vel = env.sim.data.body_xvelp[self.ball_id] goal_final_pos = env.sim.data.site_xpos[self.goal_final_id] - self._check_contacts(env.sim) + self.check_contacts(env.sim) self.dists.append(np.linalg.norm(goal_pos - ball_pos)) self.dists_final.append(np.linalg.norm(goal_final_pos - ball_pos)) self.dist_ground_cup = np.linalg.norm(ball_pos-goal_pos) \ @@ -137,7 +139,7 @@ class BeerPongReward: return reward, infos - def _check_contacts(self, sim): + def check_contacts(self, sim): if not self.ball_table_contact: self.ball_table_contact = self._check_collision_single_objects(sim, self.ball_collision_id, self.table_collision_id) From 9b4a0f89b6dd9ff7fa5a16679cabf146a8994af6 Mon Sep 17 00:00:00 2001 From: Onur Date: Sun, 29 May 2022 13:32:45 +0200 Subject: [PATCH 033/104] bp frameskip sanity check --- alr_envs/alr/__init__.py | 8 ++++---- alr_envs/alr/mujoco/beerpong/beerpong.py | 7 +------ alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py | 1 - 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 3d42b9c..9b0fb2f 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -400,11 +400,11 @@ register(id='TableTennis4DCtxt-v0', register( id='ALRBeerPong-v0', entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', - max_episode_steps=150, + max_episode_steps=600, kwargs={ "rndm_goal": False, "cup_goal_pos": [0.1, -2.0], - "frameskip": 4 + "frame_skip": 1 } ) @@ -413,11 +413,11 @@ register( register( id='ALRBeerPong-v1', entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', - max_episode_steps=150, + max_episode_steps=600, kwargs={ "rndm_goal": True, "cup_goal_pos": [-0.3, -1.2], - "frameskip": 4 + "frame_skip": 1 } ) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 4f7b85f..508cfba 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -177,12 +177,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): @property def dt(self): - return super(ALRBeerBongEnv, self).dt()*self.repeat_action - -class ALRBeerPongStepEnv(ALRBeerBongEnv): - def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, - rndm_goal=False, cup_goal_pos=None): - super(ALRBeerPongStepEnv, self).__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) + return super(ALRBeerBongEnv, self).dt*self.repeat_action if __name__ == "__main__": env = ALRBeerBongEnv(rndm_goal=True) diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py index 9683687..2bdc11a 100644 --- a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py @@ -39,7 +39,6 @@ class NewMPWrapper(EpisodicWrapper): def _episode_callback(self, action: np.ndarray) -> Tuple[np.ndarray, Union[np.ndarray, None]]: if self.mp.learn_tau: self.env.env.release_step = action[0]/self.env.dt # Tau value - # self.env.env.release_step = np.clip(action[0]/self.env.dt, 20, 260) # Tau value return action, None else: return action, None From 2ea7f6a2eda76160b7f283eb539e2dbbd04cddd4 Mon Sep 17 00:00:00 2001 From: Onur Date: Sun, 29 May 2022 13:57:33 +0200 Subject: [PATCH 034/104] bp_frameskip_dev --- alr_envs/alr/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 9b0fb2f..dd45698 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -400,11 +400,11 @@ register(id='TableTennis4DCtxt-v0', register( id='ALRBeerPong-v0', entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', - max_episode_steps=600, + max_episode_steps=300, kwargs={ "rndm_goal": False, "cup_goal_pos": [0.1, -2.0], - "frame_skip": 1 + "frame_skip": 2 } ) @@ -413,11 +413,11 @@ register( register( id='ALRBeerPong-v1', entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', - max_episode_steps=600, + max_episode_steps=300, kwargs={ "rndm_goal": True, "cup_goal_pos": [-0.3, -1.2], - "frame_skip": 1 + "frame_skip": 2 } ) From 59b15e82eaac6113586755808a20af965ecd0a68 Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 31 May 2022 19:41:08 +0200 Subject: [PATCH 035/104] bp 2fs seems to work --- alr_envs/alr/__init__.py | 54 ++++++++++++++++++- alr_envs/alr/mujoco/__init__.py | 2 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 2 +- .../alr/mujoco/hopper_jump/hopper_jump.py | 52 ++++++++++++++---- alr_envs/mp/episodic_wrapper.py | 3 ++ 5 files changed, 98 insertions(+), 15 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index dd45698..8315a09 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -285,6 +285,20 @@ register( "healthy_reward": 1.0 } ) + +##### Hopper Jump step based reward +register( + id='ALRHopperJump-v4', + entry_point='alr_envs.alr.mujoco:ALRHopperXYJumpEnvStepBased', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, + "context": True, + "healthy_reward": 1.0 + } +) + + # CtxtFree are v0, Contextual are v1 register( id='ALRHopperJumpOnBox-v0', @@ -925,7 +939,7 @@ register( "basis_generator_kwargs": { 'basis_generator_type': 'zero_rbf', 'num_basis': 5, - 'num_basis_zero_start': 2 + 'num_basis_zero_start': 1 } } ) @@ -961,12 +975,48 @@ register( "basis_generator_kwargs": { 'basis_generator_type': 'zero_rbf', 'num_basis': 5, - 'num_basis_zero_start': 2 + 'num_basis_zero_start': 1 } } ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ALRHopperJumpProMP-v3") + +## HopperJump +register( + id= "ALRHopperJumpProMP-v4", + entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + kwargs={ + "name": f"alr_envs:ALRHopperJump-v4", + "wrappers": [mujoco.hopper_jump.NewMPWrapper], + "ep_wrapper_kwargs": { + "weight_scale": 1 + }, + "movement_primitives_kwargs": { + 'movement_primitives_type': 'promp', + 'action_dim': 3 + }, + "phase_generator_kwargs": { + 'phase_generator_type': 'linear', + 'delay': 0, + 'tau': 2, # initial value + 'learn_tau': False, + 'learn_delay': False + }, + "controller_kwargs": { + 'controller_type': 'motor', + "p_gains": np.ones(3), + "d_gains": 0.1*np.ones(3), + }, + "basis_generator_kwargs": { + 'basis_generator_type': 'zero_rbf', + 'num_basis': 5, + 'num_basis_zero_start': 1 + } + } +) +ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ALRHopperJumpProMP-v4") + ## HopperJumpOnBox _versions = ["v0", "v1"] for _v in _versions: diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index 5c04b03..c02a70f 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -5,7 +5,7 @@ from .table_tennis.tt_gym import TTEnvGym from .beerpong.beerpong import ALRBeerBongEnv from .ant_jump.ant_jump import ALRAntJumpEnv from .half_cheetah_jump.half_cheetah_jump import ALRHalfCheetahJumpEnv -from .hopper_jump.hopper_jump import ALRHopperJumpEnv, ALRHopperJumpRndmPosEnv, ALRHopperXYJumpEnv +from .hopper_jump.hopper_jump import ALRHopperJumpEnv, ALRHopperJumpRndmPosEnv, ALRHopperXYJumpEnv, ALRHopperXYJumpEnvStepBased from .hopper_jump.hopper_jump_on_box import ALRHopperJumpOnBoxEnv from .hopper_throw.hopper_throw import ALRHopperThrowEnv from .hopper_throw.hopper_throw_in_basket import ALRHopperThrowInBasketEnv diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 508cfba..8846643 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -189,7 +189,7 @@ if __name__ == "__main__": ac = np.zeros(7) obs, rew, d, info = env.step(ac) env.render("human") - + print(env.dt) print(rew) if d: diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index 979e224..6bbbb5b 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -120,7 +120,6 @@ class ALRHopperJumpEnv(HopperEnv): class ALRHopperXYJumpEnv(ALRHopperJumpEnv): - # The goal here is the desired x-Position of the Torso def step(self, action): @@ -154,20 +153,15 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): ctrl_cost = self.control_cost(action) costs = ctrl_cost done = False - goal_dist = 0 + goal_dist = np.atleast_1d(np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0], dtype=object)))[0] rewards = 0 if self.current_step >= self.max_episode_steps: # healthy_reward = 0 if self.context else self.healthy_reward * self.current_step healthy_reward = self.healthy_reward * 2 #* self.current_step - goal_dist = np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0], dtype=object))[0] contact_dist = self.contact_dist if self.contact_dist is not None else 5 dist_reward = self._forward_reward_weight * (-3*goal_dist + 10*self.max_height - 2*contact_dist) rewards = dist_reward + healthy_reward - # else: - ## penalty for wrong start direction of first two joints; not needed, could be removed - # rewards = ((action[:2] > 0) * self.penalty).sum() if self.current_step < 10 else 0 - observation = self._get_obs() reward = rewards - costs info = { @@ -175,11 +169,10 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): 'x_pos': site_pos_after, 'max_height': self.max_height, 'goal': self.goal, - 'dist_rew': goal_dist, + 'goal_dist': goal_dist, 'height_rew': self.max_height, 'healthy_reward': self.healthy_reward * 2 } - return observation, reward, done, info def reset_model(self): @@ -213,12 +206,48 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): def reset(self): super().reset() # self.goal = np.random.uniform(-1.5, 1.5, 1) - self.goal = np.random.uniform(0, 1.5, 1) + # self.goal = np.random.uniform(0, 1.5, 1) + self.goal = self.np_random.uniform(0, 1.5, 1) # self.goal = np.array([1.5]) self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = np.array([self.goal, 0, 0], dtype=object) return self.reset_model() +class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): + def step(self, action): + + self._floor_geom_id = self.model.geom_name2id('floor') + self._foot_geom_id = self.model.geom_name2id('foot_geom') + + self.current_step += 1 + self.do_simulation(action, self.frame_skip) + height_after = self.get_body_com("torso")[2] + site_pos_after = self.sim.data.site_xpos[self.model.site_name2id('foot_site')].copy() + self.max_height = max(height_after, self.max_height) + ctrl_cost = self.control_cost(action) + + healthy_reward = self.healthy_reward * 2 + height_reward = 10*height_after + goal_dist = np.atleast_1d(np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0], dtype=object)))[0] + goal_dist_reward = -3*goal_dist + dist_reward = self._forward_reward_weight * (goal_dist_reward + height_reward) + reward = -ctrl_cost + healthy_reward + dist_reward + done = False + observation = self._get_obs() + info = { + 'height': height_after, + 'x_pos': site_pos_after, + 'max_height': self.max_height, + 'goal': self.goal, + 'goal_dist': goal_dist, + 'dist_rew': dist_reward, + 'height_rew': height_reward, + 'healthy_reward': healthy_reward, + 'ctrl_reward': -ctrl_cost + } + + return observation, reward, done, info + class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): def __init__(self, max_episode_steps=250): super(ALRHopperJumpRndmPosEnv, self).__init__(exclude_current_positions_from_observation=False, @@ -293,7 +322,8 @@ class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): if __name__ == '__main__': render_mode = "human" # "human" or "partial" or "final" # env = ALRHopperJumpEnv() - env = ALRHopperXYJumpEnv() + # env = ALRHopperXYJumpEnv() + env = ALRHopperXYJumpEnvStepBased() # env = ALRHopperJumpRndmPosEnv() obs = env.reset() diff --git a/alr_envs/mp/episodic_wrapper.py b/alr_envs/mp/episodic_wrapper.py index 21fb035..456c0c9 100644 --- a/alr_envs/mp/episodic_wrapper.py +++ b/alr_envs/mp/episodic_wrapper.py @@ -223,6 +223,9 @@ class EpisodicWrapper(gym.Env, ABC): def get_observation_from_step(self, observation: np.ndarray) -> np.ndarray: return observation[self.active_obs] + def seed(self, seed=None): + self.env.seed(seed) + def plot_trajs(self, des_trajs, des_vels): import matplotlib.pyplot as plt import matplotlib From 24604e60be365e38304961c0626b8ad8651f85e7 Mon Sep 17 00:00:00 2001 From: Onur Date: Thu, 2 Jun 2022 09:05:38 +0200 Subject: [PATCH 036/104] bp step based -> release time for PPO --- alr_envs/alr/__init__.py | 11 ++++++ alr_envs/alr/mujoco/__init__.py | 2 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 37 +++++++++++++++++-- alr_envs/alr/mujoco/beerpong/mp_wrapper.py | 3 ++ .../alr/mujoco/beerpong/new_mp_wrapper.py | 3 ++ 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 8315a09..978e85c 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -435,6 +435,17 @@ register( } ) +# random goal cup position +register( + id='ALRBeerPong-v2', + entry_point='alr_envs.alr.mujoco:ALRBeerBongEnvStepBased', + max_episode_steps=300, + kwargs={ + "rndm_goal": True, + "cup_goal_pos": [-0.3, -1.2], + "frame_skip": 2 + } + ) # Motion Primitive Environments diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index c02a70f..1cde867 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -2,7 +2,7 @@ from .reacher.balancing import BalancingEnv from .ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv from .ball_in_a_cup.biac_pd import ALRBallInACupPDEnv from .table_tennis.tt_gym import TTEnvGym -from .beerpong.beerpong import ALRBeerBongEnv +from .beerpong.beerpong import ALRBeerBongEnv, ALRBeerBongEnvStepBased from .ant_jump.ant_jump import ALRAntJumpEnv from .half_cheetah_jump.half_cheetah_jump import ALRHalfCheetahJumpEnv from .hopper_jump.hopper_jump import ALRHopperJumpEnv, ALRHopperJumpRndmPosEnv, ALRHopperXYJumpEnv, ALRHopperXYJumpEnvStepBased diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 8846643..0678da6 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -2,7 +2,7 @@ import mujoco_py.builder import os import numpy as np -from gym import utils +from gym import utils, spaces from gym.envs.mujoco import MujocoEnv from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward @@ -160,7 +160,6 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): is_collided=is_collided, sim_crash=crash, table_contact_first=int(not self.reward_function.ball_ground_contact_first)) infos.update(reward_infos) - return ob, reward, done, infos def check_traj_in_joint_limits(self): @@ -168,9 +167,16 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def _get_obs(self): theta = self.sim.data.qpos.flat[:7] + theta_dot = self.sim.data.qvel.flat[:7] + ball_pos = self.sim.data.body_xpos[self.sim.model._body_name2id["ball"]].copy() + cup_goal_diff_final = ball_pos - self.sim.data.site_xpos[self.sim.model._site_name2id["cup_goal_final_table"]].copy() + cup_goal_diff_top = ball_pos - self.sim.data.site_xpos[self.sim.model._site_name2id["cup_goal_table"]].copy() return np.concatenate([ np.cos(theta), np.sin(theta), + theta_dot, + cup_goal_diff_final, + cup_goal_diff_top, self.sim.model.body_pos[self.cup_table_id][:2].copy(), [self._steps], ]) @@ -179,14 +185,37 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def dt(self): return super(ALRBeerBongEnv, self).dt*self.repeat_action + +class ALRBeerBongEnvStepBased(ALRBeerBongEnv): + + def _set_action_space(self): + bounds = super(ALRBeerBongEnvStepBased, self)._set_action_space() + min_bound = np.concatenate(([-1], bounds.low), dtype=bounds.dtype) + max_bound = np.concatenate(([1], bounds.high), dtype=bounds.dtype) + self.action_space = spaces.Box(low=min_bound, high=max_bound, dtype=bounds.dtype) + return self.action_space + + def step(self, a): + self.release_step = self._steps if a[0]>=0 and self.release_step >= self._steps else self.release_step + return super(ALRBeerBongEnvStepBased, self).step(a[1:]) + + def reset(self): + ob = super(ALRBeerBongEnvStepBased, self).reset() + self.release_step = self.ep_length + 1 + return ob + if __name__ == "__main__": - env = ALRBeerBongEnv(rndm_goal=True) + # env = ALRBeerBongEnv(rndm_goal=True) + env = ALRBeerBongEnvStepBased(rndm_goal=True) import time env.reset() env.render("human") for i in range(1500): # ac = 10 * env.action_space.sample()[0:7] - ac = np.zeros(7) + ac = np.zeros(8) + ac[0] = -1 + if env._steps > 150: + ac[0] = 1 obs, rew, d, info = env.step(ac) env.render("human") print(env.dt) diff --git a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py index 11af9a5..022490c 100644 --- a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py @@ -12,6 +12,9 @@ class MPWrapper(MPEnvWrapper): return np.hstack([ [False] * 7, # cos [False] * 7, # sin + [False] * 7, # joint velocities + [False] * 3, # cup_goal_diff_final + [False] * 3, # cup_goal_diff_top [True] * 2, # xy position of cup [False] # env steps ]) diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py index 2bdc11a..2a2d4f9 100644 --- a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py @@ -17,6 +17,9 @@ class NewMPWrapper(EpisodicWrapper): return np.hstack([ [False] * 7, # cos [False] * 7, # sin + [False] * 7, # joint velocities + [False] * 3, # cup_goal_diff_final + [False] * 3, # cup_goal_diff_top [True] * 2, # xy position of cup [False] # env steps ]) From 8b8be4b5826c3c59434b76f55ce63c8b79cc07eb Mon Sep 17 00:00:00 2001 From: Onur Date: Sat, 4 Jun 2022 15:27:20 +0200 Subject: [PATCH 037/104] smaller ctxt range hopper jump + step-based rew for bp --- alr_envs/alr/__init__.py | 6 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 66 ++++++++++++++----- .../mujoco/beerpong/beerpong_reward_staged.py | 8 ++- .../alr/mujoco/hopper_jump/hopper_jump.py | 49 ++++++++++---- 4 files changed, 93 insertions(+), 36 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 978e85c..bf2ae74 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -253,7 +253,7 @@ register( kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, "context": False, - "healthy_rewasrd": 1.0 + "healthy_reward": 1.0 } ) register( @@ -405,7 +405,7 @@ register(id='TableTennis2DCtxt-v1', kwargs={'ctxt_dim': 2, 'fixed_goal': True}) register(id='TableTennis4DCtxt-v0', - entry_point='alr_envs.alr.mujoco:TTEnvGym', + entry_point='alr_envs.alr.mujocco:TTEnvGym', max_episode_steps=MAX_EPISODE_STEPS, kwargs={'ctxt_dim': 4}) @@ -915,7 +915,7 @@ for _v in _versions: "basis_generator_kwargs": { 'basis_generator_type': 'zero_rbf', 'num_basis': 5, - 'num_basis_zero_start': 2 + 'num_basis_zero_start': 1 } } ) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 0678da6..c72220b 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -187,35 +187,65 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): class ALRBeerBongEnvStepBased(ALRBeerBongEnv): + def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): + super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) + self.release_step = 62 # empirically evaluated for frame_skip=2! - def _set_action_space(self): - bounds = super(ALRBeerBongEnvStepBased, self)._set_action_space() - min_bound = np.concatenate(([-1], bounds.low), dtype=bounds.dtype) - max_bound = np.concatenate(([1], bounds.high), dtype=bounds.dtype) - self.action_space = spaces.Box(low=min_bound, high=max_bound, dtype=bounds.dtype) - return self.action_space + # def _set_action_space(self): + # bounds = super(ALRBeerBongEnvStepBased, self)._set_action_space() + # min_bound = np.concatenate(([-1], bounds.low), dtype=bounds.dtype) + # max_bound = np.concatenate(([1], bounds.high), dtype=bounds.dtype) + # self.action_space = spaces.Box(low=min_bound, high=max_bound, dtype=bounds.dtype) + # return self.action_space + + # def step(self, a): + # self.release_step = self._steps if a[0]>=0 and self.release_step >= self._steps else self.release_step + # return super(ALRBeerBongEnvStepBased, self).step(a[1:]) + # + # def reset(self): + # ob = super(ALRBeerBongEnvStepBased, self).reset() + # self.release_step = self.ep_length + 1 + # return ob def step(self, a): - self.release_step = self._steps if a[0]>=0 and self.release_step >= self._steps else self.release_step - return super(ALRBeerBongEnvStepBased, self).step(a[1:]) + if self._steps < self.release_step: + return super(ALRBeerBongEnvStepBased, self).step(a) + else: + reward = 0 + done = False + while not done: + sub_ob, sub_reward, done, sub_infos = super(ALRBeerBongEnvStepBased, self).step(np.zeros(a.shape)) + if not done or sub_infos['sim_crash']: + reward += sub_reward + else: + ball_pos = self.sim.data.body_xpos[self.sim.model._body_name2id["ball"]].copy() + cup_goal_dist_final = np.linalg.norm(ball_pos - self.sim.data.site_xpos[ + self.sim.model._site_name2id["cup_goal_final_table"]].copy()) + cup_goal_dist_top = np.linalg.norm(ball_pos - self.sim.data.site_xpos[ + self.sim.model._site_name2id["cup_goal_table"]].copy()) + if sub_infos['success']: + dist_rew = -cup_goal_dist_final**2 + else: + dist_rew = -0.5*cup_goal_dist_final**2 - cup_goal_dist_top**2 + reward = reward - sub_infos['action_cost'] + dist_rew + infos = sub_infos + ob = sub_ob + return ob, reward, done, infos + - def reset(self): - ob = super(ALRBeerBongEnvStepBased, self).reset() - self.release_step = self.ep_length + 1 - return ob if __name__ == "__main__": # env = ALRBeerBongEnv(rndm_goal=True) - env = ALRBeerBongEnvStepBased(rndm_goal=True) + env = ALRBeerBongEnvStepBased(frame_skip=2, rndm_goal=True) import time env.reset() env.render("human") for i in range(1500): - # ac = 10 * env.action_space.sample()[0:7] - ac = np.zeros(8) - ac[0] = -1 - if env._steps > 150: - ac[0] = 1 + ac = 10 * env.action_space.sample() + # ac = np.zeros(7) + # ac[0] = -1 + # if env._steps > 150: + # ac[0] = 1 obs, rew, d, info = env.step(ac) env.render("human") print(env.dt) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index 3ef8b7b..4629461 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -90,7 +90,7 @@ class BeerPongReward: self.dist_ground_cup = np.linalg.norm(ball_pos-goal_pos) \ if self.ball_ground_contact_first and self.dist_ground_cup == -1 else self.dist_ground_cup action_cost = np.sum(np.square(action)) - self.action_costs.append(action_cost) + self.action_costs.append(np.copy(action_cost)) # # ##################### Reward function which does not force to bounce once on the table (quad dist) ############ self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) @@ -110,8 +110,9 @@ class BeerPongReward: else: min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 0, 1, 0 ,0 # dist_ground_cup = 1 * self.dist_ground_cup + action_cost = 1e-4 * np.mean(action_cost) reward = rew_offset - min_dist_coeff * min_dist ** 2 - final_dist_coeff * final_dist ** 2 - \ - 1e-4 * np.mean(action_cost) - ground_contact_dist_coeff*self.dist_ground_cup ** 2 + action_cost - ground_contact_dist_coeff*self.dist_ground_cup ** 2 # 1e-7*np.mean(action_cost) # release step punishment min_time_bound = 0.1 @@ -124,7 +125,8 @@ class BeerPongReward: # print('release time :', release_time) # print('dist_ground_cup :', dist_ground_cup) else: - reward = - 1e-2 * action_cost + action_cost = 1e-2 * action_cost + reward = - action_cost # reward = - 1e-4 * action_cost # reward = 0 success = False diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index 6bbbb5b..afedf4e 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -80,7 +80,8 @@ class ALRHopperJumpEnv(HopperEnv): 'x_pos': site_pos_after, 'max_height': self.max_height, 'height_rew': self.max_height, - 'healthy_reward': self.healthy_reward * 2 + 'healthy_reward': self.healthy_reward * 2, + 'healthy': self.is_healthy } return observation, reward, done, info @@ -171,7 +172,8 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): 'goal': self.goal, 'goal_dist': goal_dist, 'height_rew': self.max_height, - 'healthy_reward': self.healthy_reward * 2 + 'healthy_reward': self.healthy_reward * 2, + 'healthy': self.is_healthy } return observation, reward, done, info @@ -207,13 +209,38 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): super().reset() # self.goal = np.random.uniform(-1.5, 1.5, 1) # self.goal = np.random.uniform(0, 1.5, 1) - self.goal = self.np_random.uniform(0, 1.5, 1) - # self.goal = np.array([1.5]) + # self.goal = self.np_random.uniform(0, 1.5, 1) + self.goal = self.np_random.uniform(0.3, 1.35, 1) self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = np.array([self.goal, 0, 0], dtype=object) return self.reset_model() class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): + + def __init__(self, + xml_file='hopper_jump.xml', + forward_reward_weight=1.0, + ctrl_cost_weight=1e-3, + healthy_reward=0.0, + penalty=0.0, + context=True, + terminate_when_unhealthy=False, + healthy_state_range=(-100.0, 100.0), + healthy_z_range=(0.5, float('inf')), + healthy_angle_range=(-float('inf'), float('inf')), + reset_noise_scale=5e-3, + exclude_current_positions_from_observation=True, + max_episode_steps=250, + height_scale = 10, + dist_scale = 3, + healthy_scale = 2): + self.height_scale = height_scale + self.dist_scale = dist_scale + self.healthy_scale = healthy_scale + super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, penalty, context, + terminate_when_unhealthy, healthy_state_range, healthy_z_range, healthy_angle_range, + reset_noise_scale, exclude_current_positions_from_observation, max_episode_steps) + def step(self, action): self._floor_geom_id = self.model.geom_name2id('floor') @@ -226,10 +253,10 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): self.max_height = max(height_after, self.max_height) ctrl_cost = self.control_cost(action) - healthy_reward = self.healthy_reward * 2 - height_reward = 10*height_after + healthy_reward = self.healthy_reward * self.healthy_scale + height_reward = self.height_scale*height_after goal_dist = np.atleast_1d(np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0], dtype=object)))[0] - goal_dist_reward = -3*goal_dist + goal_dist_reward = -self.dist_scale*goal_dist dist_reward = self._forward_reward_weight * (goal_dist_reward + height_reward) reward = -ctrl_cost + healthy_reward + dist_reward done = False @@ -240,12 +267,10 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): 'max_height': self.max_height, 'goal': self.goal, 'goal_dist': goal_dist, - 'dist_rew': dist_reward, - 'height_rew': height_reward, - 'healthy_reward': healthy_reward, - 'ctrl_reward': -ctrl_cost + 'height_rew': self.max_height, + 'healthy_reward': self.healthy_reward * 2, + 'healthy': self.is_healthy } - return observation, reward, done, info class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): From 719b40c4e48d92dbdd965e7ea4e17b299c12f9f4 Mon Sep 17 00:00:00 2001 From: Onur Date: Sat, 4 Jun 2022 17:43:35 +0200 Subject: [PATCH 038/104] update bp step based env --- alr_envs/alr/__init__.py | 11 +++++++++++ alr_envs/alr/mujoco/__init__.py | 2 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 25 +++++++++++++++++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index bf2ae74..cc9768a 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -446,6 +446,17 @@ register( "frame_skip": 2 } ) +# Beerpong with episodic reward, but fixed release time step +register( + id='ALRBeerPong-v3', + entry_point='alr_envs.alr.mujoco:ALRBeerBongEnvStepBasedEpisodicReward', + max_episode_steps=300, + kwargs={ + "rndm_goal": True, + "cup_goal_pos": [-0.3, -1.2], + "frame_skip": 2 + } + ) # Motion Primitive Environments diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index 1cde867..2b19331 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -2,7 +2,7 @@ from .reacher.balancing import BalancingEnv from .ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv from .ball_in_a_cup.biac_pd import ALRBallInACupPDEnv from .table_tennis.tt_gym import TTEnvGym -from .beerpong.beerpong import ALRBeerBongEnv, ALRBeerBongEnvStepBased +from .beerpong.beerpong import ALRBeerBongEnv, ALRBeerBongEnvStepBased, ALRBeerBongEnvStepBasedEpisodicReward from .ant_jump.ant_jump import ALRAntJumpEnv from .half_cheetah_jump.half_cheetah_jump import ALRHalfCheetahJumpEnv from .hopper_jump.hopper_jump import ALRHopperJumpEnv, ALRHopperJumpRndmPosEnv, ALRHopperXYJumpEnv, ALRHopperXYJumpEnvStepBased diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index c72220b..9028bd0 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -186,6 +186,26 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): return super(ALRBeerBongEnv, self).dt*self.repeat_action +class ALRBeerBongEnvStepBasedEpisodicReward(ALRBeerBongEnv): + def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): + super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) + self.release_step = 62 # empirically evaluated for frame_skip=2! + + def step(self, a): + if self._steps < self.release_step: + return super(ALRBeerBongEnvStepBasedEpisodicReward, self).step(a) + else: + reward = 0 + done = False + while not done: + sub_ob, sub_reward, done, sub_infos = super(ALRBeerBongEnvStepBasedEpisodicReward, self).step(np.zeros(a.shape)) + reward += sub_reward + infos = sub_infos + ob = sub_ob + ob[-1] = self.release_step + 1 # Since we simulate until the end of the episode, PPO does not see the + # internal steps and thus, the observation also needs to be set correctly + return ob, reward, done, infos + class ALRBeerBongEnvStepBased(ALRBeerBongEnv): def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) @@ -230,13 +250,16 @@ class ALRBeerBongEnvStepBased(ALRBeerBongEnv): reward = reward - sub_infos['action_cost'] + dist_rew infos = sub_infos ob = sub_ob + ob[-1] = self.release_step + 1 # Since we simulate until the end of the episode, PPO does not see the + # internal steps and thus, the observation also needs to be set correctly return ob, reward, done, infos if __name__ == "__main__": # env = ALRBeerBongEnv(rndm_goal=True) - env = ALRBeerBongEnvStepBased(frame_skip=2, rndm_goal=True) + # env = ALRBeerBongEnvStepBased(frame_skip=2, rndm_goal=True) + env = ALRBeerBongEnvStepBasedEpisodicReward(frame_skip=2, rndm_goal=True) import time env.reset() env.render("human") From c47845c0dd0bbf2592a4b54156adae61a193a08c Mon Sep 17 00:00:00 2001 From: Onur Date: Sun, 5 Jun 2022 15:11:07 +0200 Subject: [PATCH 039/104] prepare HJ for PPO --- alr_envs/alr/__init__.py | 4 +-- .../alr/mujoco/hopper_jump/hopper_jump.py | 27 ++++++++++++------- .../alr/mujoco/hopper_jump/new_mp_wrapper.py | 16 ++++++----- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index cc9768a..d3e976c 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -974,7 +974,7 @@ register( entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', kwargs={ "name": f"alr_envs:ALRHopperJump-v3", - "wrappers": [mujoco.hopper_jump.NewMPWrapper], + "wrappers": [mujoco.hopper_jump.NewHighCtxtMPWrapper], "ep_wrapper_kwargs": { "weight_scale": 1 }, @@ -1010,7 +1010,7 @@ register( entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', kwargs={ "name": f"alr_envs:ALRHopperJump-v4", - "wrappers": [mujoco.hopper_jump.NewMPWrapper], + "wrappers": [mujoco.hopper_jump.NewHighCtxtMPWrapper], "ep_wrapper_kwargs": { "weight_scale": 1 }, diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index afedf4e..2759fd4 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -11,7 +11,7 @@ class ALRHopperJumpEnv(HopperEnv): - healthy_reward: 1.0 -> 0.1 -> 0 - healthy_angle_range: (-0.2, 0.2) -> (-float('inf'), float('inf')) - healthy_z_range: (0.7, float('inf')) -> (0.5, float('inf')) - + - exclude current positions from observatiosn is set to False """ def __init__(self, @@ -26,7 +26,7 @@ class ALRHopperJumpEnv(HopperEnv): healthy_z_range=(0.5, float('inf')), healthy_angle_range=(-float('inf'), float('inf')), reset_noise_scale=5e-3, - exclude_current_positions_from_observation=True, + exclude_current_positions_from_observation=False, max_episode_steps=250): self.current_step = 0 self.max_height = 0 @@ -90,7 +90,7 @@ class ALRHopperJumpEnv(HopperEnv): return np.append(super()._get_obs(), self.goal) def reset(self): - self.goal = np.random.uniform(1.4, 2.16, 1) # 1.3 2.3 + self.goal = self.np_random.uniform(1.4, 2.16, 1)[0] # 1.3 2.3 self.max_height = 0 self.current_step = 0 return super().reset() @@ -149,12 +149,12 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): if self.contact_dist is None and self.contact_with_floor: self.contact_dist = np.linalg.norm(self.sim.data.site_xpos[self.model.site_name2id('foot_site')] - - np.array([self.goal, 0, 0], dtype=object))[0] + - np.array([self.goal, 0, 0])) ctrl_cost = self.control_cost(action) costs = ctrl_cost done = False - goal_dist = np.atleast_1d(np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0], dtype=object)))[0] + goal_dist = np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0])) rewards = 0 if self.current_step >= self.max_episode_steps: # healthy_reward = 0 if self.context else self.healthy_reward * self.current_step @@ -210,10 +210,14 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): # self.goal = np.random.uniform(-1.5, 1.5, 1) # self.goal = np.random.uniform(0, 1.5, 1) # self.goal = self.np_random.uniform(0, 1.5, 1) - self.goal = self.np_random.uniform(0.3, 1.35, 1) - self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = np.array([self.goal, 0, 0], dtype=object) + self.goal = self.np_random.uniform(0.3, 1.35, 1)[0] + self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = np.array([self.goal, 0, 0]) return self.reset_model() + def _get_obs(self): + goal_diff = self.sim.data.site_xpos[self.model.site_name2id('foot_site')].copy() \ + - np.array([self.goal, 0, 0]) + return np.concatenate((super(ALRHopperXYJumpEnv, self)._get_obs(), goal_diff)) class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): @@ -229,7 +233,7 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): healthy_z_range=(0.5, float('inf')), healthy_angle_range=(-float('inf'), float('inf')), reset_noise_scale=5e-3, - exclude_current_positions_from_observation=True, + exclude_current_positions_from_observation=False, max_episode_steps=250, height_scale = 10, dist_scale = 3, @@ -242,7 +246,10 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): reset_noise_scale, exclude_current_positions_from_observation, max_episode_steps) def step(self, action): - + print("") + print('height_scale: ', self.height_scale) + print('healthy_scale: ', self.healthy_scale) + print('dist_scale: ', self.dist_scale) self._floor_geom_id = self.model.geom_name2id('floor') self._foot_geom_id = self.model.geom_name2id('foot_geom') @@ -348,7 +355,9 @@ if __name__ == '__main__': render_mode = "human" # "human" or "partial" or "final" # env = ALRHopperJumpEnv() # env = ALRHopperXYJumpEnv() + np.random.seed(0) env = ALRHopperXYJumpEnvStepBased() + env.seed(0) # env = ALRHopperJumpRndmPosEnv() obs = env.reset() diff --git a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py index 31be6be..7a26d62 100644 --- a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py @@ -23,17 +23,19 @@ class NewMPWrapper(EpisodicWrapper): # Random x goal + random init pos def set_active_obs(self): return np.hstack([ - [False] * (2 + int(not self.env.exclude_current_positions_from_observation)), # position - [True] * 3, # set to true if randomize initial pos - [False] * 6, # velocity - [True] - ]) + [False] * (2 + int(not self.env.exclude_current_positions_from_observation)), # position + [True] * 3, # set to true if randomize initial pos + [False] * 6, # velocity + [True] + ]) class NewHighCtxtMPWrapper(NewMPWrapper): def set_active_obs(self): return np.hstack([ - [True] * (5 + int(not self.env.exclude_current_positions_from_observation)), # position + [False] * (2 + int(not self.env.exclude_current_positions_from_observation)), # position + [True] * 3, # set to true if randomize initial pos [False] * 6, # velocity - [False] + [True], # goal + [False] * 3 # goal diff ]) \ No newline at end of file From 7bd9848c31f1e377aab54a7ba8cf72bede900d0b Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 21 Jun 2022 17:15:01 +0200 Subject: [PATCH 040/104] after deadline --- alr_envs/alr/__init__.py | 126 ++++++++++++++++++ alr_envs/alr/mujoco/__init__.py | 2 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 26 +++- .../alr/mujoco/hopper_jump/hopper_jump.py | 46 +++++-- .../alr/mujoco/hopper_jump/new_mp_wrapper.py | 6 +- alr_envs/alr/mujoco/reacher/alr_reacher.py | 63 +++++---- alr_envs/alr/mujoco/reacher/mp_wrapper.py | 2 +- alr_envs/utils/make_env_helpers.py | 1 - 8 files changed, 227 insertions(+), 45 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index d3e976c..09f533a 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -203,6 +203,34 @@ register( } ) +_vs = np.arange(101).tolist() + [1e-5, 5e-5, 1e-4, 5e-4, 1e-3, 5e-3, 1e-2, 5e-2, 1e-1, 5e-1] +for i in _vs: + _env_id = f'ALRReacher{i}-v0' + register( + id=_env_id, + entry_point='alr_envs.alr.mujoco:ALRReacherEnv', + max_episode_steps=200, + kwargs={ + "steps_before_reward": 0, + "n_links": 5, + "balance": False, + 'ctrl_cost_weight': i + } + ) + + _env_id = f'ALRReacherSparse{i}-v0' + register( + id=_env_id, + entry_point='alr_envs.alr.mujoco:ALRReacherEnv', + max_episode_steps=200, + kwargs={ + "steps_before_reward": 200, + "n_links": 5, + "balance": False, + 'ctrl_cost_weight': i + } + ) + # CtxtFree are v0, Contextual are v1 register( id='ALRAntJump-v0', @@ -458,6 +486,18 @@ register( } ) +# Beerpong with episodic reward, but fixed release time step +register( + id='ALRBeerPong-v4', + entry_point='alr_envs.alr.mujoco:ALRBeerBongEnvFixedReleaseStep', + max_episode_steps=300, + kwargs={ + "rndm_goal": True, + "cup_goal_pos": [-0.3, -1.2], + "frame_skip": 2 + } + ) + # Motion Primitive Environments ## Simple Reacher @@ -648,6 +688,56 @@ for _v in _versions: ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + +_vs = np.arange(101).tolist() + [1e-5, 5e-5, 1e-4, 5e-4, 1e-3, 5e-3, 1e-2, 5e-2, 1e-1, 5e-1] +for i in _vs: + _env_id = f'ALRReacher{i}ProMP-v0' + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": f"alr_envs:{_env_id.replace('ProMP', '')}", + "wrappers": [mujoco.reacher.MPWrapper], + "mp_kwargs": { + "num_dof": 5, + "num_basis": 5, + "duration": 4, + "policy_type": "motor", + # "weights_scale": 5, + "n_zero_basis": 1, + "zero_start": True, + "policy_kwargs": { + "p_gains": 1, + "d_gains": 0.1 + } + } + } + ) + + _env_id = f'ALRReacherSparse{i}ProMP-v0' + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs={ + "name": f"alr_envs:{_env_id.replace('ProMP', '')}", + "wrappers": [mujoco.reacher.MPWrapper], + "mp_kwargs": { + "num_dof": 5, + "num_basis": 5, + "duration": 4, + "policy_type": "motor", + # "weights_scale": 5, + "n_zero_basis": 1, + "zero_start": True, + "policy_kwargs": { + "p_gains": 1, + "d_gains": 0.1 + } + } + } + ) + + # ## Beerpong # _versions = ["v0", "v1"] # for _v in _versions: @@ -717,6 +807,42 @@ for _v in _versions: ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) +## Beerpong ProMP fixed release +_env_id = 'BeerpongProMP-v2' +register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + kwargs={ + "name": "alr_envs:ALRBeerPong-v4", + "wrappers": [mujoco.beerpong.NewMPWrapper], + "ep_wrapper_kwargs": { + "weight_scale": 1 + }, + "movement_primitives_kwargs": { + 'movement_primitives_type': 'promp', + 'action_dim': 7 + }, + "phase_generator_kwargs": { + 'phase_generator_type': 'linear', + 'delay': 0, + 'tau': 0.62, # initial value + 'learn_tau': False, + 'learn_delay': False + }, + "controller_kwargs": { + 'controller_type': 'motor', + "p_gains": np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]), + "d_gains": np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]), + }, + "basis_generator_kwargs": { + 'basis_generator_type': 'zero_rbf', + 'num_basis': 2, + 'num_basis_zero_start': 2 + } + } +) +ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + ## Table Tennis ctxt_dim = [2, 4] for _v, cd in enumerate(ctxt_dim): diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index 2b19331..2885321 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -2,7 +2,7 @@ from .reacher.balancing import BalancingEnv from .ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv from .ball_in_a_cup.biac_pd import ALRBallInACupPDEnv from .table_tennis.tt_gym import TTEnvGym -from .beerpong.beerpong import ALRBeerBongEnv, ALRBeerBongEnvStepBased, ALRBeerBongEnvStepBasedEpisodicReward +from .beerpong.beerpong import ALRBeerBongEnv, ALRBeerBongEnvStepBased, ALRBeerBongEnvStepBasedEpisodicReward, ALRBeerBongEnvFixedReleaseStep from .ant_jump.ant_jump import ALRAntJumpEnv from .half_cheetah_jump.half_cheetah_jump import ALRHalfCheetahJumpEnv from .hopper_jump.hopper_jump import ALRHopperJumpEnv, ALRHopperJumpRndmPosEnv, ALRHopperXYJumpEnv, ALRHopperXYJumpEnvStepBased diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 9028bd0..5040ec7 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -185,6 +185,10 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def dt(self): return super(ALRBeerBongEnv, self).dt*self.repeat_action +class ALRBeerBongEnvFixedReleaseStep(ALRBeerBongEnv): + def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): + super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) + self.release_step = 62 # empirically evaluated for frame_skip=2! class ALRBeerBongEnvStepBasedEpisodicReward(ALRBeerBongEnv): def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): @@ -206,6 +210,25 @@ class ALRBeerBongEnvStepBasedEpisodicReward(ALRBeerBongEnv): # internal steps and thus, the observation also needs to be set correctly return ob, reward, done, infos + +# class ALRBeerBongEnvStepBasedEpisodicReward(ALRBeerBongEnv): +# def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): +# super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) +# self.release_step = 62 # empirically evaluated for frame_skip=2! +# +# def step(self, a): +# if self._steps < self.release_step: +# return super(ALRBeerBongEnvStepBasedEpisodicReward, self).step(a) +# else: +# sub_ob, sub_reward, done, sub_infos = super(ALRBeerBongEnvStepBasedEpisodicReward, self).step(np.zeros(a.shape)) +# reward = sub_reward +# infos = sub_infos +# ob = sub_ob +# ob[-1] = self.release_step + 1 # Since we simulate until the end of the episode, PPO does not see the +# # internal steps and thus, the observation also needs to be set correctly +# return ob, reward, done, infos + + class ALRBeerBongEnvStepBased(ALRBeerBongEnv): def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) @@ -259,7 +282,8 @@ class ALRBeerBongEnvStepBased(ALRBeerBongEnv): if __name__ == "__main__": # env = ALRBeerBongEnv(rndm_goal=True) # env = ALRBeerBongEnvStepBased(frame_skip=2, rndm_goal=True) - env = ALRBeerBongEnvStepBasedEpisodicReward(frame_skip=2, rndm_goal=True) + # env = ALRBeerBongEnvStepBasedEpisodicReward(frame_skip=2, rndm_goal=True) + env = ALRBeerBongEnvFixedReleaseStep(frame_skip=2, rndm_goal=True) import time env.reset() env.render("human") diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index 2759fd4..20ede40 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -123,7 +123,6 @@ class ALRHopperJumpEnv(HopperEnv): class ALRHopperXYJumpEnv(ALRHopperJumpEnv): def step(self, action): - self._floor_geom_id = self.model.geom_name2id('floor') self._foot_geom_id = self.model.geom_name2id('foot_geom') @@ -173,7 +172,8 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): 'goal_dist': goal_dist, 'height_rew': self.max_height, 'healthy_reward': self.healthy_reward * 2, - 'healthy': self.is_healthy + 'healthy': self.is_healthy, + 'contact_dist': self.contact_dist if self.contact_dist is not None else 0 } return observation, reward, done, info @@ -194,7 +194,6 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): rnd_vec = self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) qpos = self.init_qpos + rnd_vec qvel = self.init_qvel - self.set_state(qpos, qvel) observation = self._get_obs() @@ -207,9 +206,6 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): def reset(self): super().reset() - # self.goal = np.random.uniform(-1.5, 1.5, 1) - # self.goal = np.random.uniform(0, 1.5, 1) - # self.goal = self.np_random.uniform(0, 1.5, 1) self.goal = self.np_random.uniform(0.3, 1.35, 1)[0] self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = np.array([self.goal, 0, 0]) return self.reset_model() @@ -219,6 +215,16 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): - np.array([self.goal, 0, 0]) return np.concatenate((super(ALRHopperXYJumpEnv, self)._get_obs(), goal_diff)) + def set_context(self, context): + # context is 4 dimensional + qpos = self.init_qpos + qvel = self.init_qvel + qpos[-3:] = context[:3] + self.goal = context[-1] + self.set_state(qpos, qvel) + self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = np.array([self.goal, 0, 0]) + return self._get_obs() + class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): def __init__(self, @@ -246,10 +252,6 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): reset_noise_scale, exclude_current_positions_from_observation, max_episode_steps) def step(self, action): - print("") - print('height_scale: ', self.height_scale) - print('healthy_scale: ', self.healthy_scale) - print('dist_scale: ', self.dist_scale) self._floor_geom_id = self.model.geom_name2id('floor') self._foot_geom_id = self.model.geom_name2id('foot_geom') @@ -268,6 +270,23 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): reward = -ctrl_cost + healthy_reward + dist_reward done = False observation = self._get_obs() + + + ########################################################### + # This is only for logging the distance to goal when first having the contact + ########################################################## + floor_contact = self._contact_checker(self._floor_geom_id, + self._foot_geom_id) if not self.contact_with_floor else False + if not self.init_floor_contact: + self.init_floor_contact = floor_contact + if self.init_floor_contact and not self.has_left_floor: + self.has_left_floor = not floor_contact + if not self.contact_with_floor and self.has_left_floor: + self.contact_with_floor = floor_contact + + if self.contact_dist is None and self.contact_with_floor: + self.contact_dist = np.linalg.norm(self.sim.data.site_xpos[self.model.site_name2id('foot_site')] + - np.array([self.goal, 0, 0])) info = { 'height': height_after, 'x_pos': site_pos_after, @@ -275,8 +294,9 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): 'goal': self.goal, 'goal_dist': goal_dist, 'height_rew': self.max_height, - 'healthy_reward': self.healthy_reward * 2, - 'healthy': self.is_healthy + 'healthy_reward': self.healthy_reward * self.healthy_reward, + 'healthy': self.is_healthy, + 'contact_dist': self.contact_dist if self.contact_dist is not None else 0 } return observation, reward, done, info @@ -361,7 +381,7 @@ if __name__ == '__main__': # env = ALRHopperJumpRndmPosEnv() obs = env.reset() - for k in range(10): + for k in range(1000): obs = env.reset() print('observation :', obs[:]) for i in range(200): diff --git a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py index 7a26d62..77a1bf6 100644 --- a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py @@ -38,4 +38,8 @@ class NewHighCtxtMPWrapper(NewMPWrapper): [False] * 6, # velocity [True], # goal [False] * 3 # goal diff - ]) \ No newline at end of file + ]) + + def set_context(self, context): + return self.get_observation_from_step(self.env.env.set_context(context)) + diff --git a/alr_envs/alr/mujoco/reacher/alr_reacher.py b/alr_envs/alr/mujoco/reacher/alr_reacher.py index 6b36407..c12352a 100644 --- a/alr_envs/alr/mujoco/reacher/alr_reacher.py +++ b/alr_envs/alr/mujoco/reacher/alr_reacher.py @@ -8,7 +8,8 @@ import alr_envs.utils.utils as alr_utils class ALRReacherEnv(MujocoEnv, utils.EzPickle): - def __init__(self, steps_before_reward=200, n_links=5, balance=False): + def __init__(self, steps_before_reward: int = 200, n_links: int = 5, ctrl_cost_weight: int = 1, + balance: bool = False): utils.EzPickle.__init__(**locals()) self._steps = 0 @@ -17,6 +18,7 @@ class ALRReacherEnv(MujocoEnv, utils.EzPickle): self.balance = balance self.balance_weight = 1.0 + self.ctrl_cost_weight = ctrl_cost_weight self.reward_weight = 1 if steps_before_reward == 200: @@ -40,7 +42,7 @@ class ALRReacherEnv(MujocoEnv, utils.EzPickle): angular_vel = 0.0 reward_balance = 0.0 is_delayed = self.steps_before_reward > 0 - reward_ctrl = - np.square(a).sum() + reward_ctrl = - np.square(a).sum() * self.ctrl_cost_weight if self._steps >= self.steps_before_reward: vec = self.get_body_com("fingertip") - self.get_body_com("target") reward_dist -= self.reward_weight * np.linalg.norm(vec) @@ -48,9 +50,9 @@ class ALRReacherEnv(MujocoEnv, utils.EzPickle): # avoid giving this penalty for normal step based case # angular_vel -= 10 * np.linalg.norm(self.sim.data.qvel.flat[:self.n_links]) angular_vel -= 10 * np.square(self.sim.data.qvel.flat[:self.n_links]).sum() - if is_delayed: - # Higher control penalty for sparse reward per timestep - reward_ctrl *= 10 + # if is_delayed: + # # Higher control penalty for sparse reward per timestep + # reward_ctrl *= 10 if self.balance: reward_balance -= self.balance_weight * np.abs( @@ -68,35 +70,42 @@ class ALRReacherEnv(MujocoEnv, utils.EzPickle): def viewer_setup(self): self.viewer.cam.trackbodyid = 0 - def reset_model(self): - qpos = self.init_qpos - if not hasattr(self, "goal"): - self.goal = np.array([-0.25, 0.25]) - # self.goal = self.init_qpos.copy()[:2] + 0.05 - qpos[-2:] = self.goal - qvel = self.init_qvel - qvel[-2:] = 0 - self.set_state(qpos, qvel) - self._steps = 0 - - return self._get_obs() - # def reset_model(self): - # qpos = self.init_qpos.copy() - # while True: - # self.goal = self.np_random.uniform(low=-self.n_links / 10, high=self.n_links / 10, size=2) - # # self.goal = self.np_random.uniform(low=0, high=self.n_links / 10, size=2) - # # self.goal = np.random.uniform(low=[-self.n_links / 10, 0], high=[0, self.n_links / 10], size=2) - # if np.linalg.norm(self.goal) < self.n_links / 10: - # break + # qpos = self.init_qpos + # if not hasattr(self, "goal"): + # self.goal = np.array([-0.25, 0.25]) + # # self.goal = self.init_qpos.copy()[:2] + 0.05 # qpos[-2:] = self.goal - # qvel = self.init_qvel.copy() + # qvel = self.init_qvel # qvel[-2:] = 0 # self.set_state(qpos, qvel) # self._steps = 0 # # return self._get_obs() + def reset_model(self): + qpos = self.init_qpos.copy() + while True: + # full space + # self.goal = self.np_random.uniform(low=-self.n_links / 10, high=self.n_links / 10, size=2) + # I Quadrant + # self.goal = self.np_random.uniform(low=0, high=self.n_links / 10, size=2) + # II Quadrant + # self.goal = np.random.uniform(low=[-self.n_links / 10, 0], high=[0, self.n_links / 10], size=2) + # II + III Quadrant + # self.goal = np.random.uniform(low=-self.n_links / 10, high=[0, self.n_links / 10], size=2) + # I + II Quadrant + self.goal = np.random.uniform(low=[-self.n_links / 10, 0], high=self.n_links, size=2) + if np.linalg.norm(self.goal) < self.n_links / 10: + break + qpos[-2:] = self.goal + qvel = self.init_qvel.copy() + qvel[-2:] = 0 + self.set_state(qpos, qvel) + self._steps = 0 + + return self._get_obs() + # def reset_model(self): # qpos = self.np_random.uniform(low=-0.1, high=0.1, size=self.model.nq) + self.init_qpos # while True: @@ -140,4 +149,4 @@ if __name__ == '__main__': if d: env.reset() - env.close() + env.close() \ No newline at end of file diff --git a/alr_envs/alr/mujoco/reacher/mp_wrapper.py b/alr_envs/alr/mujoco/reacher/mp_wrapper.py index abcdc50..3b655d4 100644 --- a/alr_envs/alr/mujoco/reacher/mp_wrapper.py +++ b/alr_envs/alr/mujoco/reacher/mp_wrapper.py @@ -40,4 +40,4 @@ class MPWrapper(MPEnvWrapper): @property def dt(self) -> Union[float, int]: - return self.env.dt + return self.env.dt \ No newline at end of file diff --git a/alr_envs/utils/make_env_helpers.py b/alr_envs/utils/make_env_helpers.py index f22e0d7..301a5aa 100644 --- a/alr_envs/utils/make_env_helpers.py +++ b/alr_envs/utils/make_env_helpers.py @@ -98,7 +98,6 @@ def make(env_id: str, seed, **kwargs): return env - def _make_wrapped_env(env_id: str, wrappers: Iterable[Type[gym.Wrapper]], mp: MPInterface, controller: BaseController, ep_wrapper_kwargs: Mapping, seed=1, **kwargs): """ From 9ad6fbe712e66e4815adc22357132aeb3d4c28e5 Mon Sep 17 00:00:00 2001 From: Fabian Otto Date: Tue, 28 Jun 2022 16:05:09 +0200 Subject: [PATCH 041/104] first clean up and some non working ideas sketched --- README.md | 38 +++--- .../alr/mujoco/ball_in_a_cup/ball_in_a_cup.py | 15 +-- .../ball_in_a_cup_reward_simple.py | 2 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 114 ++++++---------- .../mujoco/beerpong/beerpong_reward_staged.py | 48 +++---- .../alr/mujoco/beerpong/new_mp_wrapper.py | 42 ++---- .../alr/mujoco/hopper_jump/hopper_jump.py | 123 +++++++++--------- alr_envs/mp/episodic_wrapper.py | 67 ++++++---- alr_envs/utils/__init__.py | 9 +- alr_envs/utils/make_env_helpers.py | 27 ++-- 10 files changed, 225 insertions(+), 260 deletions(-) diff --git a/README.md b/README.md index edd1aac..c08a1d4 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,32 @@ ## ALR Robotics Control Environments This project offers a large variety of reinforcement learning environments under the unifying interface of [OpenAI gym](https://gym.openai.com/). -Besides, we also provide support (under the OpenAI interface) for the benchmark suites +We provide support (under the OpenAI interface) for the benchmark suites [DeepMind Control](https://deepmind.com/research/publications/2020/dm-control-Software-and-Tasks-for-Continuous-Control) -(DMC) and [Metaworld](https://meta-world.github.io/). Custom (Mujoco) gym environments can be created according -to [this guide](https://github.com/openai/gym/blob/master/docs/creating-environments.md). Unlike existing libraries, we -additionally support to control agents with Dynamic Movement Primitives (DMPs) and Probabilistic Movement Primitives (ProMP, -we only consider the mean usually). +(DMC) and [Metaworld](https://meta-world.github.io/). +Custom (Mujoco) gym environments can be created according +to [this guide](https://www.gymlibrary.ml/content/environment_creation/). +Unlike existing libraries, we additionally support to control agents with movement primitives, such as +Dynamic Movement Primitives (DMPs) and Probabilistic Movement Primitives (ProMP, we only consider the mean usually). -## Motion Primitive Environments (Episodic environments) +## Movement Primitive Environments (Episode-Based/Black-Box Environments) -Unlike step-based environments, motion primitive (MP) environments are closer related to stochastic search, black box -optimization, and methods that are often used in robotics. MP environments are trajectory-based and always execute a full -trajectory, which is generated by a Dynamic Motion Primitive (DMP) or a Probabilistic Motion Primitive (ProMP). The -generated trajectory is translated into individual step-wise actions by a controller. The exact choice of controller is, -however, dependent on the type of environment. We currently support position, velocity, and PD-Controllers for position, -velocity, and torque control, respectively. The goal of all MP environments is still to learn a policy. Yet, an action +Unlike step-based environments, movement primitive (MP) environments are closer related to stochastic search, black-box +optimization, and methods that are often used in traditional robotics and control. +MP environments are episode-based and always execute a full trajectory, which is generated by a trajectory generator, +such as a Dynamic Movement Primitive (DMP) or a Probabilistic Movement Primitive (ProMP). +The generated trajectory is translated into individual step-wise actions by a trajectory tracking controller. +The exact choice of controller is, however, dependent on the type of environment. +We currently support position, velocity, and PD-Controllers for position, velocity, and torque control, respectively +as well as a special controller for the MetaWorld control suite. +The goal of all MP environments is still to learn a optimal policy. Yet, an action represents the parametrization of the motion primitives to generate a suitable trajectory. Additionally, in this -framework we support all of this also for the contextual setting, for which we expose all changing substates of the -task as a single observation in the beginning. This requires to predict a new action/MP parametrization for each -trajectory. All environments provide next to the cumulative episode reward all collected information from each -step as part of the info dictionary. This information should, however, mainly be used for debugging and logging. +framework we support all of this also for the contextual setting, i.e. we expose a subset of the observation space +as a single context in the beginning of the episode. This requires to predict a new action/MP parametrization for each +context. +All environments provide next to the cumulative episode reward all collected information from each +step as part of the info dictionary. This information is, however, mainly meant for debugging as well as logging +and not for training. |Key| Description| |---|---| diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup.py b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup.py index 7cff670..7b286bc 100644 --- a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup.py +++ b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup.py @@ -4,10 +4,11 @@ import numpy as np from gym.envs.mujoco import MujocoEnv - class ALRBallInACupEnv(MujocoEnv, utils.EzPickle): - def __init__(self, n_substeps=4, apply_gravity_comp=True, simplified: bool = False, - reward_type: str = None, context: np.ndarray = None): + def __init__( + self, n_substeps=4, apply_gravity_comp=True, simplified: bool = False, + reward_type: str = None, context: np.ndarray = None + ): utils.EzPickle.__init__(**locals()) self._steps = 0 @@ -23,9 +24,7 @@ class ALRBallInACupEnv(MujocoEnv, utils.EzPickle): self.context = context - alr_mujoco_env.AlrMujocoEnv.__init__(self, - self.xml_path, - apply_gravity_comp=apply_gravity_comp, + alr_mujoco_env.AlrMujocoEnv.__init__(self, self.xml_path, apply_gravity_comp=apply_gravity_comp, n_substeps=n_substeps) self._start_pos = np.array([0.0, 0.58760536, 0.0, 1.36004913, 0.0, -0.32072943, -1.57]) self._start_vel = np.zeros(7) @@ -129,7 +128,7 @@ class ALRBallInACupEnv(MujocoEnv, utils.EzPickle): np.sin(theta), # self.get_body_com("target"), # only return target to make problem harder [self._steps], - ]) + ]) # TODO @property @@ -139,7 +138,7 @@ class ALRBallInACupEnv(MujocoEnv, utils.EzPickle): [False] * 7, # sin # [True] * 2, # x-y coordinates of target distance [False] # env steps - ]) + ]) # These functions are for the task with 3 joint actuations def extend_des_pos(self, des_pos): diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward_simple.py b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward_simple.py index a147d89..0762e22 100644 --- a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward_simple.py +++ b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward_simple.py @@ -67,7 +67,7 @@ class BallInACupReward(alr_reward_fct.AlrReward): action_cost = np.sum(np.square(action)) self.action_costs.append(action_cost) - self._is_collided = self.check_collision(self.env.sim) or self.env.check_traj_in_joint_limits() + self._is_collided = self.check_collision(self.env.sim) or self.env._check_traj_in_joint_limits() if self.env._steps == self.env.ep_length - 1 or self._is_collided: t_min_dist = np.argmin(self.dists) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 5040ec7..b7d376e 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -1,11 +1,11 @@ -import mujoco_py.builder import os +import mujoco_py.builder import numpy as np -from gym import utils, spaces +from gym import utils from gym.envs.mujoco import MujocoEnv -from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward +from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward CUP_POS_MIN = np.array([-1.42, -4.05]) CUP_POS_MAX = np.array([1.42, -1.25]) @@ -18,12 +18,14 @@ CUP_POS_MAX = np.array([1.42, -1.25]) # CUP_POS_MIN = np.array([-0.16, -2.2]) # CUP_POS_MAX = np.array([0.16, -1.7]) - class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): - def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, - rndm_goal=False, cup_goal_pos=None): + def __init__( + self, frame_skip=1, apply_gravity_comp=True, noisy=False, + rndm_goal=False, cup_goal_pos=None + ): + cup_goal_pos = np.array(cup_goal_pos if cup_goal_pos is not None else [-0.3, -1.2, 0.840]) - if cup_goal_pos.shape[0]==2: + if cup_goal_pos.shape[0] == 2: cup_goal_pos = np.insert(cup_goal_pos, 2, 0.840) self.cup_goal_pos = np.array(cup_goal_pos) @@ -50,7 +52,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): # self._release_step = 130 # time step of ball release self.release_step = 100 # time step of ball release - self.ep_length = 600//frame_skip + self.ep_length = 600 // frame_skip self.cup_table_id = 10 if noisy: @@ -71,14 +73,6 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def start_vel(self): return self._start_vel - @property - def current_pos(self): - return self.sim.data.qpos[0:7].copy() - - @property - def current_vel(self): - return self.sim.data.qvel[0:7].copy() - def reset(self): self.reward_function.reset(self.add_noise) return super().reset() @@ -122,7 +116,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.sim.data.qpos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() self.sim.data.qvel[7::] = self.sim.data.site_xvelp[self.ball_site_id, :].copy() elif self._steps == self.release_step and self.add_noise: - self.sim.data.qvel[7::] += self.noise_std * np.random.randn(3) + self.sim.data.qvel[7::] += self.noise_std * np.random.randn(3) crash = False except mujoco_py.builder.MujocoException: crash = True @@ -147,29 +141,32 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): ball_pos = np.zeros(3) ball_vel = np.zeros(3) - infos = dict(reward_dist=reward_dist, - reward=reward, - velocity=angular_vel, - # traj=self._q_pos, - action=a, - q_pos=self.sim.data.qpos[0:7].ravel().copy(), - q_vel=self.sim.data.qvel[0:7].ravel().copy(), - ball_pos=ball_pos, - ball_vel=ball_vel, - success=success, - is_collided=is_collided, sim_crash=crash, - table_contact_first=int(not self.reward_function.ball_ground_contact_first)) + infos = dict( + reward_dist=reward_dist, + reward=reward, + velocity=angular_vel, + # traj=self._q_pos, + action=a, + q_pos=self.sim.data.qpos[0:7].ravel().copy(), + q_vel=self.sim.data.qvel[0:7].ravel().copy(), + ball_pos=ball_pos, + ball_vel=ball_vel, + success=success, + is_collided=is_collided, sim_crash=crash, + table_contact_first=int(not self.reward_function.ball_ground_contact_first) + ) infos.update(reward_infos) return ob, reward, done, infos - def check_traj_in_joint_limits(self): + def _check_traj_in_joint_limits(self): return any(self.current_pos > self.j_max) or any(self.current_pos < self.j_min) def _get_obs(self): theta = self.sim.data.qpos.flat[:7] theta_dot = self.sim.data.qvel.flat[:7] ball_pos = self.sim.data.body_xpos[self.sim.model._body_name2id["ball"]].copy() - cup_goal_diff_final = ball_pos - self.sim.data.site_xpos[self.sim.model._site_name2id["cup_goal_final_table"]].copy() + cup_goal_diff_final = ball_pos - self.sim.data.site_xpos[ + self.sim.model._site_name2id["cup_goal_final_table"]].copy() cup_goal_diff_top = ball_pos - self.sim.data.site_xpos[self.sim.model._site_name2id["cup_goal_table"]].copy() return np.concatenate([ np.cos(theta), @@ -179,17 +176,21 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): cup_goal_diff_top, self.sim.model.body_pos[self.cup_table_id][:2].copy(), [self._steps], - ]) + ]) + + def compute_reward(self): @property def dt(self): - return super(ALRBeerBongEnv, self).dt*self.repeat_action + return super(ALRBeerBongEnv, self).dt * self.repeat_action + class ALRBeerBongEnvFixedReleaseStep(ALRBeerBongEnv): def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) self.release_step = 62 # empirically evaluated for frame_skip=2! + class ALRBeerBongEnvStepBasedEpisodicReward(ALRBeerBongEnv): def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) @@ -202,54 +203,21 @@ class ALRBeerBongEnvStepBasedEpisodicReward(ALRBeerBongEnv): reward = 0 done = False while not done: - sub_ob, sub_reward, done, sub_infos = super(ALRBeerBongEnvStepBasedEpisodicReward, self).step(np.zeros(a.shape)) + sub_ob, sub_reward, done, sub_infos = super(ALRBeerBongEnvStepBasedEpisodicReward, self).step( + np.zeros(a.shape)) reward += sub_reward infos = sub_infos ob = sub_ob - ob[-1] = self.release_step + 1 # Since we simulate until the end of the episode, PPO does not see the - # internal steps and thus, the observation also needs to be set correctly + ob[-1] = self.release_step + 1 # Since we simulate until the end of the episode, PPO does not see the + # internal steps and thus, the observation also needs to be set correctly return ob, reward, done, infos -# class ALRBeerBongEnvStepBasedEpisodicReward(ALRBeerBongEnv): -# def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): -# super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) -# self.release_step = 62 # empirically evaluated for frame_skip=2! -# -# def step(self, a): -# if self._steps < self.release_step: -# return super(ALRBeerBongEnvStepBasedEpisodicReward, self).step(a) -# else: -# sub_ob, sub_reward, done, sub_infos = super(ALRBeerBongEnvStepBasedEpisodicReward, self).step(np.zeros(a.shape)) -# reward = sub_reward -# infos = sub_infos -# ob = sub_ob -# ob[-1] = self.release_step + 1 # Since we simulate until the end of the episode, PPO does not see the -# # internal steps and thus, the observation also needs to be set correctly -# return ob, reward, done, infos - - class ALRBeerBongEnvStepBased(ALRBeerBongEnv): def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) self.release_step = 62 # empirically evaluated for frame_skip=2! - # def _set_action_space(self): - # bounds = super(ALRBeerBongEnvStepBased, self)._set_action_space() - # min_bound = np.concatenate(([-1], bounds.low), dtype=bounds.dtype) - # max_bound = np.concatenate(([1], bounds.high), dtype=bounds.dtype) - # self.action_space = spaces.Box(low=min_bound, high=max_bound, dtype=bounds.dtype) - # return self.action_space - - # def step(self, a): - # self.release_step = self._steps if a[0]>=0 and self.release_step >= self._steps else self.release_step - # return super(ALRBeerBongEnvStepBased, self).step(a[1:]) - # - # def reset(self): - # ob = super(ALRBeerBongEnvStepBased, self).reset() - # self.release_step = self.ep_length + 1 - # return ob - def step(self, a): if self._steps < self.release_step: return super(ALRBeerBongEnvStepBased, self).step(a) @@ -267,9 +235,9 @@ class ALRBeerBongEnvStepBased(ALRBeerBongEnv): cup_goal_dist_top = np.linalg.norm(ball_pos - self.sim.data.site_xpos[ self.sim.model._site_name2id["cup_goal_table"]].copy()) if sub_infos['success']: - dist_rew = -cup_goal_dist_final**2 + dist_rew = -cup_goal_dist_final ** 2 else: - dist_rew = -0.5*cup_goal_dist_final**2 - cup_goal_dist_top**2 + dist_rew = -0.5 * cup_goal_dist_final ** 2 - cup_goal_dist_top ** 2 reward = reward - sub_infos['action_cost'] + dist_rew infos = sub_infos ob = sub_ob @@ -278,13 +246,13 @@ class ALRBeerBongEnvStepBased(ALRBeerBongEnv): return ob, reward, done, infos - if __name__ == "__main__": # env = ALRBeerBongEnv(rndm_goal=True) # env = ALRBeerBongEnvStepBased(frame_skip=2, rndm_goal=True) # env = ALRBeerBongEnvStepBasedEpisodicReward(frame_skip=2, rndm_goal=True) env = ALRBeerBongEnvFixedReleaseStep(frame_skip=2, rndm_goal=True) import time + env.reset() env.render("human") for i in range(1500): diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index 4629461..7e5fda6 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -29,52 +29,38 @@ class BeerPongReward: # "cup_base_table" ] - - self.ball_traj = None self.dists = None self.dists_final = None - self.costs = None self.action_costs = None - self.angle_rewards = None - self.cup_angles = None - self.cup_z_axes = None - self.collision_penalty = 500 - self.reset(None) + self.reset() self.is_initialized = False - def reset(self, noisy): - self.ball_traj = [] + def reset(self): self.dists = [] self.dists_final = [] - self.costs = [] self.action_costs = [] - self.angle_rewards = [] - self.cup_angles = [] - self.cup_z_axes = [] self.ball_ground_contact_first = False self.ball_table_contact = False self.ball_wall_contact = False self.ball_cup_contact = False self.ball_in_cup = False - self.dist_ground_cup = -1 # distance floor to cup if first floor contact - self.noisy_bp = noisy - self._t_min_final_dist = -1 + self.dist_ground_cup = -1 # distance floor to cup if first floor contact def initialize(self, env): if not self.is_initialized: self.is_initialized = True self.ball_id = env.sim.model._body_name2id["ball"] - self.ball_collision_id = env.sim.model._geom_name2id["ball_geom"] self.goal_id = env.sim.model._site_name2id["cup_goal_table"] self.goal_final_id = env.sim.model._site_name2id["cup_goal_final_table"] - self.cup_collision_ids = [env.sim.model._geom_name2id[name] for name in self.cup_collision_objects] self.cup_table_id = env.sim.model._body_name2id["cup_table"] + + self.ball_collision_id = env.sim.model._geom_name2id["ball_geom"] self.table_collision_id = env.sim.model._geom_name2id["table_contact_geom"] self.wall_collision_id = env.sim.model._geom_name2id["wall"] self.cup_table_collision_id = env.sim.model._geom_name2id["cup_base_table_contact"] - self.init_ball_pos_site_id = env.sim.model._site_name2id["init_ball_pos_site"] self.ground_collision_id = env.sim.model._geom_name2id["ground"] + self.cup_collision_ids = [env.sim.model._geom_name2id[name] for name in self.cup_collision_objects] self.robot_collision_ids = [env.sim.model._geom_name2id[name] for name in self.robot_collision_objects] def compute_reward(self, env, action): @@ -87,7 +73,7 @@ class BeerPongReward: self.check_contacts(env.sim) self.dists.append(np.linalg.norm(goal_pos - ball_pos)) self.dists_final.append(np.linalg.norm(goal_final_pos - ball_pos)) - self.dist_ground_cup = np.linalg.norm(ball_pos-goal_pos) \ + self.dist_ground_cup = np.linalg.norm(ball_pos - goal_pos) \ if self.ball_ground_contact_first and self.dist_ground_cup == -1 else self.dist_ground_cup action_cost = np.sum(np.square(action)) self.action_costs.append(np.copy(action_cost)) @@ -99,7 +85,7 @@ class BeerPongReward: min_dist = np.min(self.dists) final_dist = self.dists_final[-1] if self.ball_ground_contact_first: - min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 2, -4 # relative rew offset when first bounding on ground + min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 2, -4 # relative rew offset when first bounding on ground # min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 0, -6 # absolute rew offset when first bouncing on ground else: if not self.ball_in_cup: @@ -108,18 +94,18 @@ class BeerPongReward: else: min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 0, -2 else: - min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 0, 1, 0 ,0 + min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 0, 1, 0, 0 # dist_ground_cup = 1 * self.dist_ground_cup action_cost = 1e-4 * np.mean(action_cost) reward = rew_offset - min_dist_coeff * min_dist ** 2 - final_dist_coeff * final_dist ** 2 - \ - action_cost - ground_contact_dist_coeff*self.dist_ground_cup ** 2 + action_cost - ground_contact_dist_coeff * self.dist_ground_cup ** 2 # 1e-7*np.mean(action_cost) # release step punishment min_time_bound = 0.1 max_time_bound = 1.0 - release_time = env.release_step*env.dt - release_time_rew = int(release_timemax_time_bound)*(-30-10*(release_time-max_time_bound)**2) + release_time = env.release_step * env.dt + release_time_rew = int(release_time < min_time_bound) * (-30 - 10 * (release_time - min_time_bound) ** 2) \ + + int(release_time > max_time_bound) * (-30 - 10 * (release_time - max_time_bound) ** 2) reward += release_time_rew success = self.ball_in_cup # print('release time :', release_time) @@ -147,17 +133,17 @@ class BeerPongReward: self.table_collision_id) if not self.ball_cup_contact: self.ball_cup_contact = self._check_collision_with_set_of_objects(sim, self.ball_collision_id, - self.cup_collision_ids) + self.cup_collision_ids) if not self.ball_wall_contact: self.ball_wall_contact = self._check_collision_single_objects(sim, self.ball_collision_id, - self.wall_collision_id) + self.wall_collision_id) if not self.ball_in_cup: self.ball_in_cup = self._check_collision_single_objects(sim, self.ball_collision_id, self.cup_table_collision_id) if not self.ball_ground_contact_first: if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact and not self.ball_in_cup: self.ball_ground_contact_first = self._check_collision_single_objects(sim, self.ball_collision_id, - self.ground_collision_id) + self.ground_collision_id) def _check_collision_single_objects(self, sim, id_1, id_2): for coni in range(0, sim.data.ncon): @@ -190,4 +176,4 @@ class BeerPongReward: if collision or collision_trans: return True - return False \ No newline at end of file + return False diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py index 2a2d4f9..53d7a1a 100644 --- a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py @@ -1,10 +1,15 @@ -from alr_envs.mp.episodic_wrapper import EpisodicWrapper -from typing import Union, Tuple +from typing import Tuple, Union + import numpy as np -import gym + +from alr_envs.mp.episodic_wrapper import EpisodicWrapper class NewMPWrapper(EpisodicWrapper): + + # def __init__(self, replanning_model): + # self.replanning_model = replanning_model + @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qpos[0:7].copy() @@ -22,26 +27,16 @@ class NewMPWrapper(EpisodicWrapper): [False] * 3, # cup_goal_diff_top [True] * 2, # xy position of cup [False] # env steps - ]) + ]) - # def set_mp_action_space(self): - # min_action_bounds, max_action_bounds = self.mp.get_param_bounds() - # if self.mp.learn_tau: - # min_action_bounds[0] = 20*self.env.dt - # max_action_bounds[0] = 260*self.env.dt - # mp_action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), - # dtype=np.float32) - # return mp_action_space - - # def _step_callback(self, t: int, env_spec_params: Union[np.ndarray, None], step_action: np.ndarray) -> Union[np.ndarray]: - # if self.mp.learn_tau: - # return np.concatenate((step_action, np.atleast_1d(env_spec_params))) - # else: - # return step_action + def do_replanning(self, pos, vel, s, a, t, last_replan_step): + return False + # const = np.arange(0, 1000, 10) + # return bool(self.replanning_model(s)) def _episode_callback(self, action: np.ndarray) -> Tuple[np.ndarray, Union[np.ndarray, None]]: if self.mp.learn_tau: - self.env.env.release_step = action[0]/self.env.dt # Tau value + self.env.env.release_step = action[0] / self.env.dt # Tau value return action, None else: return action, None @@ -52,12 +47,3 @@ class NewMPWrapper(EpisodicWrapper): xyz[-1] = 0.840 self.env.env.model.body_pos[self.env.env.cup_table_id] = xyz return self.get_observation_from_step(self.env.env._get_obs()) - # def set_action_space(self): - # if self.mp.learn_tau: - # min_action_bounds, max_action_bounds = self.mp.get_param_bounds() - # min_action_bounds = np.concatenate((min_action_bounds.numpy(), [self.env.action_space.low[-1]])) - # max_action_bounds = np.concatenate((max_action_bounds.numpy(), [self.env.action_space.high[-1]])) - # self.action_space = gym.spaces.Box(low=min_action_bounds, high=max_action_bounds, dtype=np.float32) - # return self.action_space - # else: - # return super(NewMPWrapper, self).set_action_space() diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index 20ede40..146b039 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -14,20 +14,23 @@ class ALRHopperJumpEnv(HopperEnv): - exclude current positions from observatiosn is set to False """ - def __init__(self, - xml_file='hopper_jump.xml', - forward_reward_weight=1.0, - ctrl_cost_weight=1e-3, - healthy_reward=0.0, - penalty=0.0, - context=True, - terminate_when_unhealthy=False, - healthy_state_range=(-100.0, 100.0), - healthy_z_range=(0.5, float('inf')), - healthy_angle_range=(-float('inf'), float('inf')), - reset_noise_scale=5e-3, - exclude_current_positions_from_observation=False, - max_episode_steps=250): + def __init__( + self, + xml_file='hopper_jump.xml', + forward_reward_weight=1.0, + ctrl_cost_weight=1e-3, + healthy_reward=0.0, + penalty=0.0, + context=True, + terminate_when_unhealthy=False, + healthy_state_range=(-100.0, 100.0), + healthy_z_range=(0.5, float('inf')), + healthy_angle_range=(-float('inf'), float('inf')), + reset_noise_scale=5e-3, + exclude_current_positions_from_observation=False, + max_episode_steps=250 + ): + self.current_step = 0 self.max_height = 0 self.max_episode_steps = max_episode_steps @@ -47,7 +50,7 @@ class ALRHopperJumpEnv(HopperEnv): exclude_current_positions_from_observation) def step(self, action): - + self.current_step += 1 self.do_simulation(action, self.frame_skip) height_after = self.get_body_com("torso")[2] @@ -59,22 +62,14 @@ class ALRHopperJumpEnv(HopperEnv): done = False rewards = 0 if self.current_step >= self.max_episode_steps: - hight_goal_distance = -10*np.linalg.norm(self.max_height - self.goal) if self.context else self.max_height - healthy_reward = 0 if self.context else self.healthy_reward * 2 # self.current_step - height_reward = self._forward_reward_weight * hight_goal_distance # maybe move reward calculation into if structure and define two different _forward_reward_weight variables for context and episodic seperatley + hight_goal_distance = -10 * np.linalg.norm(self.max_height - self.goal) if self.context else self.max_height + healthy_reward = 0 if self.context else self.healthy_reward * 2 # self.current_step + height_reward = self._forward_reward_weight * hight_goal_distance # maybe move reward calculation into if structure and define two different _forward_reward_weight variables for context and episodic seperatley rewards = height_reward + healthy_reward - # else: - # # penalty for wrong start direction of first two joints; not needed, could be removed - # rewards = ((action[:2] > 0) * self.penalty).sum() if self.current_step < 10 else 0 - observation = self._get_obs() reward = rewards - costs - # info = { - # 'height' : height_after, - # 'max_height': self.max_height, - # 'goal' : self.goal - # } + info = { 'height': height_after, 'x_pos': site_pos_after, @@ -82,7 +77,7 @@ class ALRHopperJumpEnv(HopperEnv): 'height_rew': self.max_height, 'healthy_reward': self.healthy_reward * 2, 'healthy': self.is_healthy - } + } return observation, reward, done, info @@ -90,7 +85,7 @@ class ALRHopperJumpEnv(HopperEnv): return np.append(super()._get_obs(), self.goal) def reset(self): - self.goal = self.np_random.uniform(1.4, 2.16, 1)[0] # 1.3 2.3 + self.goal = self.np_random.uniform(1.4, 2.16, 1)[0] # 1.3 2.3 self.max_height = 0 self.current_step = 0 return super().reset() @@ -98,8 +93,8 @@ class ALRHopperJumpEnv(HopperEnv): # overwrite reset_model to make it deterministic def reset_model(self): - qpos = self.init_qpos # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) - qvel = self.init_qvel # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) + qpos = self.init_qpos # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + qvel = self.init_qvel # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) self.set_state(qpos, qvel) @@ -147,7 +142,7 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): self.contact_with_floor = floor_contact if self.contact_dist is None and self.contact_with_floor: - self.contact_dist = np.linalg.norm(self.sim.data.site_xpos[self.model.site_name2id('foot_site')] + self.contact_dist = np.linalg.norm(self.sim.data.site_xpos[self.model.site_name2id('foot_site')] - np.array([self.goal, 0, 0])) ctrl_cost = self.control_cost(action) @@ -157,9 +152,9 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): rewards = 0 if self.current_step >= self.max_episode_steps: # healthy_reward = 0 if self.context else self.healthy_reward * self.current_step - healthy_reward = self.healthy_reward * 2 #* self.current_step + healthy_reward = self.healthy_reward * 2 # * self.current_step contact_dist = self.contact_dist if self.contact_dist is not None else 5 - dist_reward = self._forward_reward_weight * (-3*goal_dist + 10*self.max_height - 2*contact_dist) + dist_reward = self._forward_reward_weight * (-3 * goal_dist + 10 * self.max_height - 2 * contact_dist) rewards = dist_reward + healthy_reward observation = self._get_obs() @@ -174,7 +169,7 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): 'healthy_reward': self.healthy_reward * 2, 'healthy': self.is_healthy, 'contact_dist': self.contact_dist if self.contact_dist is not None else 0 - } + } return observation, reward, done, info def reset_model(self): @@ -225,25 +220,28 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = np.array([self.goal, 0, 0]) return self._get_obs() + class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): - def __init__(self, - xml_file='hopper_jump.xml', - forward_reward_weight=1.0, - ctrl_cost_weight=1e-3, - healthy_reward=0.0, - penalty=0.0, - context=True, - terminate_when_unhealthy=False, - healthy_state_range=(-100.0, 100.0), - healthy_z_range=(0.5, float('inf')), - healthy_angle_range=(-float('inf'), float('inf')), - reset_noise_scale=5e-3, - exclude_current_positions_from_observation=False, - max_episode_steps=250, - height_scale = 10, - dist_scale = 3, - healthy_scale = 2): + def __init__( + self, + xml_file='hopper_jump.xml', + forward_reward_weight=1.0, + ctrl_cost_weight=1e-3, + healthy_reward=0.0, + penalty=0.0, + context=True, + terminate_when_unhealthy=False, + healthy_state_range=(-100.0, 100.0), + healthy_z_range=(0.5, float('inf')), + healthy_angle_range=(-float('inf'), float('inf')), + reset_noise_scale=5e-3, + exclude_current_positions_from_observation=False, + max_episode_steps=250, + height_scale=10, + dist_scale=3, + healthy_scale=2 + ): self.height_scale = height_scale self.dist_scale = dist_scale self.healthy_scale = healthy_scale @@ -263,15 +261,14 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): ctrl_cost = self.control_cost(action) healthy_reward = self.healthy_reward * self.healthy_scale - height_reward = self.height_scale*height_after + height_reward = self.height_scale * height_after goal_dist = np.atleast_1d(np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0], dtype=object)))[0] - goal_dist_reward = -self.dist_scale*goal_dist + goal_dist_reward = -self.dist_scale * goal_dist dist_reward = self._forward_reward_weight * (goal_dist_reward + height_reward) reward = -ctrl_cost + healthy_reward + dist_reward done = False observation = self._get_obs() - ########################################################### # This is only for logging the distance to goal when first having the contact ########################################################## @@ -297,9 +294,10 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): 'healthy_reward': self.healthy_reward * self.healthy_reward, 'healthy': self.is_healthy, 'contact_dist': self.contact_dist if self.contact_dist is not None else 0 - } + } return observation, reward, done, info + class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): def __init__(self, max_episode_steps=250): super(ALRHopperJumpRndmPosEnv, self).__init__(exclude_current_positions_from_observation=False, @@ -309,14 +307,14 @@ class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): def reset_model(self): self._floor_geom_id = self.model.geom_name2id('floor') self._foot_geom_id = self.model.geom_name2id('foot_geom') - noise_low = -np.ones(self.model.nq)*self._reset_noise_scale + noise_low = -np.ones(self.model.nq) * self._reset_noise_scale noise_low[1] = 0 noise_low[2] = 0 noise_low[3] = -0.2 noise_low[4] = -0.2 noise_low[5] = -0.1 - noise_high = np.ones(self.model.nq)*self._reset_noise_scale + noise_high = np.ones(self.model.nq) * self._reset_noise_scale noise_high[1] = 0 noise_high[2] = 0 noise_high[3] = 0 @@ -325,7 +323,7 @@ class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): rnd_vec = self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) # rnd_vec[2] *= 0.05 # the angle around the y axis shouldn't be too high as the agent then falls down quickly and - # can not recover + # can not recover # rnd_vec[1] = np.clip(rnd_vec[1], 0, 0.3) qpos = self.init_qpos + rnd_vec qvel = self.init_qvel @@ -341,7 +339,7 @@ class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): self.do_simulation(action, self.frame_skip) self.contact_with_floor = self._contact_checker(self._floor_geom_id, self._foot_geom_id) if not \ - self.contact_with_floor else True + self.contact_with_floor else True height_after = self.get_body_com("torso")[2] self.max_height = max(height_after, self.max_height) if self.contact_with_floor else 0 @@ -365,12 +363,11 @@ class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): 'height': height_after, 'max_height': self.max_height, 'goal': self.goal - } + } return observation, reward, done, info - if __name__ == '__main__': render_mode = "human" # "human" or "partial" or "final" # env = ALRHopperJumpEnv() @@ -396,4 +393,4 @@ if __name__ == '__main__': print('After ', i, ' steps, done: ', d) env.reset() - env.close() \ No newline at end of file + env.close() diff --git a/alr_envs/mp/episodic_wrapper.py b/alr_envs/mp/episodic_wrapper.py index 456c0c9..b2eb391 100644 --- a/alr_envs/mp/episodic_wrapper.py +++ b/alr_envs/mp/episodic_wrapper.py @@ -9,7 +9,7 @@ from mp_pytorch.mp.mp_interfaces import MPInterface from alr_envs.mp.controllers.base_controller import BaseController -class EpisodicWrapper(gym.Env, ABC): +class EpisodicWrapper(gym.Env, gym.wrappers.TransformReward, ABC): """ Base class for movement primitive based gym.Wrapper implementations. @@ -22,14 +22,19 @@ class EpisodicWrapper(gym.Env, ABC): weight_scale: Scaling parameter for the actions given to this wrapper render_mode: Equivalent to gym render mode """ - def __init__(self, - env: gym.Env, - mp: MPInterface, - controller: BaseController, - duration: float, - render_mode: str = None, - verbose: int = 1, - weight_scale: float = 1): + + def __init__( + self, + env: gym.Env, + mp: MPInterface, + controller: BaseController, + duration: float, + render_mode: str = None, + verbose: int = 1, + weight_scale: float = 1, + sequencing=True, + reward_aggregation=np.mean, + ): super().__init__() self.env = env @@ -40,11 +45,11 @@ class EpisodicWrapper(gym.Env, ABC): self.duration = duration self.traj_steps = int(duration / self.dt) self.post_traj_steps = self.env.spec.max_episode_steps - self.traj_steps + # duration = self.env.max_episode_steps * self.dt - self.controller = controller self.mp = mp self.env = env - self.verbose = verbose + self.controller = controller self.weight_scale = weight_scale # rendering @@ -52,15 +57,18 @@ class EpisodicWrapper(gym.Env, ABC): self.render_kwargs = {} self.time_steps = np.linspace(0, self.duration, self.traj_steps) self.mp.set_mp_times(self.time_steps) + # self.mp.set_mp_duration(self.time_steps, dt) # action_bounds = np.inf * np.ones((np.prod(self.mp.num_params))) - self.mp_action_space = self.set_mp_action_space() + self.mp_action_space = self.get_mp_action_space() - self.action_space = self.set_action_space() + self.action_space = self.get_action_space() self.active_obs = self.set_active_obs() self.observation_space = spaces.Box(low=self.env.observation_space.low[self.active_obs], high=self.env.observation_space.high[self.active_obs], dtype=self.env.observation_space.dtype) + self.verbose = verbose + def get_trajectory(self, action: np.ndarray) -> Tuple: # TODO: this follows the implementation of the mp_pytorch library which includes the parameters tau and delay at # the beginning of the array. @@ -69,33 +77,37 @@ class EpisodicWrapper(gym.Env, ABC): scaled_mp_params[ignore_indices:] *= self.weight_scale self.mp.set_params(np.clip(scaled_mp_params, self.mp_action_space.low, self.mp_action_space.high)) self.mp.set_boundary_conditions(bc_time=self.time_steps[:1], bc_pos=self.current_pos, bc_vel=self.current_vel) - traj_dict = self.mp.get_mp_trajs(get_pos = True, get_vel = True) + traj_dict = self.mp.get_mp_trajs(get_pos=True, get_vel=True) trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] trajectory = trajectory_tensor.numpy() velocity = velocity_tensor.numpy() + # TODO: Do we need this or does mp_pytorch have this? if self.post_traj_steps > 0: trajectory = np.vstack([trajectory, np.tile(trajectory[-1, :], [self.post_traj_steps, 1])]) velocity = np.vstack([velocity, np.zeros(shape=(self.post_traj_steps, self.mp.num_dof))]) return trajectory, velocity - def set_mp_action_space(self): + def get_mp_action_space(self): """This function can be used to set up an individual space for the parameters of the mp.""" min_action_bounds, max_action_bounds = self.mp.get_param_bounds() mp_action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), - dtype=np.float32) + dtype=np.float32) return mp_action_space - def set_action_space(self): + def get_action_space(self): """ This function can be used to modify the action space for considering actions which are not learned via motion primitives. E.g. ball releasing time for the beer pong task. By default, it is the parameter space of the motion primitive. Only needs to be overwritten if the action space needs to be modified. """ - return self.mp_action_space + try: + return self.mp_action_space + except AttributeError: + return self.get_mp_action_space() def _episode_callback(self, action: np.ndarray) -> Tuple[np.ndarray, Union[np.ndarray, None]]: """ @@ -111,7 +123,8 @@ class EpisodicWrapper(gym.Env, ABC): """ return action, None - def _step_callback(self, t: int, env_spec_params: Union[np.ndarray, None], step_action: np.ndarray) -> Union[np.ndarray]: + def _step_callback(self, t: int, env_spec_params: Union[np.ndarray, None], step_action: np.ndarray) -> Union[ + np.ndarray]: """ This function can be used to modify the step_action with additional parameters e.g. releasing the ball in the Beerpong env. The parameters used should not be part of the motion primitive parameters. @@ -169,11 +182,15 @@ class EpisodicWrapper(gym.Env, ABC): mp_params, env_spec_params = self._episode_callback(action) trajectory, velocity = self.get_trajectory(mp_params) + # TODO + # self.time_steps = np.linspace(0, learned_duration, self.traj_steps) + # self.mp.set_mp_times(self.time_steps) + trajectory_length = len(trajectory) - if self.verbose >=2 : + if self.verbose >= 2: actions = np.zeros(shape=(trajectory_length,) + self.env.action_space.shape) observations = np.zeros(shape=(trajectory_length,) + self.env.observation_space.shape, - dtype=self.env.observation_space.dtype) + dtype=self.env.observation_space.dtype) rewards = np.zeros(shape=(trajectory_length,)) trajectory_return = 0 @@ -181,7 +198,7 @@ class EpisodicWrapper(gym.Env, ABC): for t, pos_vel in enumerate(zip(trajectory, velocity)): step_action = self.controller.get_action(pos_vel[0], pos_vel[1], self.current_pos, self.current_vel) - step_action = self._step_callback(t, env_spec_params, step_action) # include possible callback info + step_action = self._step_callback(t, env_spec_params, step_action) # include possible callback info c_action = np.clip(step_action, self.env.action_space.low, self.env.action_space.high) # print('step/clipped action ratio: ', step_action/c_action) obs, c_reward, done, info = self.env.step(c_action) @@ -197,7 +214,7 @@ class EpisodicWrapper(gym.Env, ABC): # infos['step_infos'].append(info) if self.render_mode: self.render(mode=self.render_mode, **self.render_kwargs) - if done: + if done or do_replanning(kwargs): break infos.update({k: v[:t + 1] for k, v in infos.items()}) if self.verbose >= 2: @@ -235,10 +252,10 @@ class EpisodicWrapper(gym.Env, ABC): for i in range(des_trajs.shape[1]): plt.figure(pos_fig.number) plt.subplot(des_trajs.shape[1], 1, i + 1) - plt.plot(np.ones(des_trajs.shape[0])*self.current_pos[i]) + plt.plot(np.ones(des_trajs.shape[0]) * self.current_pos[i]) plt.plot(des_trajs[:, i]) plt.figure(vel_fig.number) plt.subplot(des_vels.shape[1], 1, i + 1) - plt.plot(np.ones(des_trajs.shape[0])*self.current_vel[i]) + plt.plot(np.ones(des_trajs.shape[0]) * self.current_vel[i]) plt.plot(des_vels[:, i]) diff --git a/alr_envs/utils/__init__.py b/alr_envs/utils/__init__.py index bb4b0bc..a96d882 100644 --- a/alr_envs/utils/__init__.py +++ b/alr_envs/utils/__init__.py @@ -20,12 +20,13 @@ def make_dmc( environment_kwargs: dict = {}, time_limit: Union[None, float] = None, channels_first: bool = True -): + ): # Adopted from: https://github.com/denisyarats/dmc2gym/blob/master/dmc2gym/__init__.py # License: MIT # Copyright (c) 2020 Denis Yarats - assert re.match(r"\w+-\w+", id), "env_id does not have the following structure: 'domain_name-task_name'" + if not re.match(r"\w+-\w+", id): + raise ValueError("env_id does not have the following structure: 'domain_name-task_name'") domain_name, task_name = id.split("-") env_id = f'dmc_{domain_name}_{task_name}_{seed}-v1' @@ -60,7 +61,7 @@ def make_dmc( camera_id=camera_id, frame_skip=frame_skip, channels_first=channels_first, - ), + ), max_episode_steps=max_episode_steps, - ) + ) return gym.make(env_id) diff --git a/alr_envs/utils/make_env_helpers.py b/alr_envs/utils/make_env_helpers.py index 301a5aa..dbefeee 100644 --- a/alr_envs/utils/make_env_helpers.py +++ b/alr_envs/utils/make_env_helpers.py @@ -55,7 +55,7 @@ def make(env_id: str, seed, **kwargs): Returns: Gym environment """ - if any([det_pmp in env_id for det_pmp in ["DetPMP", "detpmp"]]): + if any(deprec in env_id for deprec in ["DetPMP", "detpmp"]): warnings.warn("DetPMP is deprecated and converted to ProMP") env_id = env_id.replace("DetPMP", "ProMP") env_id = env_id.replace("detpmp", "promp") @@ -92,14 +92,17 @@ def make(env_id: str, seed, **kwargs): from alr_envs import make_dmc env = make_dmc(env_id, seed=seed, **kwargs) - assert env.base_step_limit == env.spec.max_episode_steps, \ - f"The specified 'episode_length' of {env.spec.max_episode_steps} steps for gym is different from " \ - f"the DMC environment specification of {env.base_step_limit} steps." + if not env.base_step_limit == env.spec.max_episode_steps: + raise ValueError(f"The specified 'episode_length' of {env.spec.max_episode_steps} steps for gym " + f"is different from the DMC environment specification of {env.base_step_limit} steps.") return env -def _make_wrapped_env(env_id: str, wrappers: Iterable[Type[gym.Wrapper]], mp: MPInterface, controller: BaseController, - ep_wrapper_kwargs: Mapping, seed=1, **kwargs): + +def _make_wrapped_env( + env_id: str, wrappers: Iterable[Type[gym.Wrapper]], mp: MPInterface, controller: BaseController, + ep_wrapper_kwargs: Mapping, seed=1, **kwargs + ): """ Helper function for creating a wrapped gym environment using MPs. It adds all provided wrappers to the specified environment and verifies at least one MPEnvWrapper is @@ -120,13 +123,14 @@ def _make_wrapped_env(env_id: str, wrappers: Iterable[Type[gym.Wrapper]], mp: MP # only wrap the environment if not EpisodicWrapper, e.g. for vision if not issubclass(w, EpisodicWrapper): _env = w(_env) - else: # if EpisodicWrapper, use specific constructor + else: # if EpisodicWrapper, use specific constructor has_episodic_wrapper = True _env = w(env=_env, mp=mp, controller=controller, **ep_wrapper_kwargs) - assert has_episodic_wrapper, \ - "At least one MPEnvWrapper is required in order to leverage motion primitive environments." + if not has_episodic_wrapper: + raise ValueError("An EpisodicWrapper is required in order to leverage movement primitive environments.") return _env + def make_mp_from_kwargs( env_id: str, wrappers: Iterable, ep_wrapper_kwargs: MutableMapping, mp_kwargs: MutableMapping, controller_kwargs: MutableMapping, phase_kwargs: MutableMapping, basis_kwargs: MutableMapping, seed=1, @@ -152,7 +156,7 @@ def make_mp_from_kwargs( _verify_time_limit(mp_kwargs.get("duration", None), kwargs.get("time_limit", None)) dummy_env = make(env_id, seed) if ep_wrapper_kwargs.get('duration', None) is None: - ep_wrapper_kwargs['duration'] = dummy_env.spec.max_episode_steps*dummy_env.dt + ep_wrapper_kwargs['duration'] = dummy_env.spec.max_episode_steps * dummy_env.dt if phase_kwargs.get('tau', None) is None: phase_kwargs['tau'] = ep_wrapper_kwargs['duration'] mp_kwargs['action_dim'] = mp_kwargs.get('action_dim', np.prod(dummy_env.action_space.shape).item()) @@ -207,10 +211,11 @@ def make_mp_env_helper(**kwargs): phase_kwargs = kwargs.pop("phase_generator_kwargs") basis_kwargs = kwargs.pop("basis_generator_kwargs") - return make_mp_from_kwargs(env_id=kwargs.pop("name"), wrappers=wrappers, ep_wrapper_kwargs=ep_wrapper_kwargs, + return make_mp_from_kwargs(env_id=kwargs.pop("name"), wrappers=wrappers, ep_wrapper_kwargs=ep_wrapper_kwargs, mp_kwargs=mp_kwargs, controller_kwargs=contr_kwargs, phase_kwargs=phase_kwargs, basis_kwargs=basis_kwargs, **kwargs, seed=seed) + def make_dmp_env(env_id: str, wrappers: Iterable, seed=1, mp_kwargs={}, **kwargs): """ This can also be used standalone for manually building a custom DMP environment. From 8fe6a83271e015c41710cd55861f5344695da982 Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 28 Jun 2022 20:33:19 +0200 Subject: [PATCH 042/104] started cleaning up init. DMP envs are still not transferred. Wrappers for various environments still missing --- alr_envs/alr/__init__.py | 1204 ++++++----------- alr_envs/alr/mujoco/beerpong/beerpong.py | 64 +- .../alr/mujoco/hopper_jump/hopper_jump.py | 70 - 3 files changed, 418 insertions(+), 920 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 09f533a..ec539db 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -21,6 +21,35 @@ from .mujoco.walker_2d_jump.walker_2d_jump import MAX_EPISODE_STEPS_WALKERJUMP ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": []} +DEFAULT_MP_ENV_DICT = { + "name": 'EnvName', + "wrappers": [], + "ep_wrapper_kwargs": { + "weight_scale": 1 + }, + "movement_primitives_kwargs": { + 'movement_primitives_type': 'promp', + 'action_dim': 7 + }, + "phase_generator_kwargs": { + 'phase_generator_type': 'linear', + 'delay': 0, + 'tau': 1.5, # initial value + 'learn_tau': False, + 'learn_delay': False + }, + "controller_kwargs": { + 'controller_type': 'motor', + "p_gains": np.ones(7), + "d_gains": np.ones(7) * 0.1, + }, + "basis_generator_kwargs": { + 'basis_generator_type': 'zero_rbf', + 'num_basis': 5, + 'num_basis_zero_start': 2 + } +} + # Classic Control ## Simple Reacher register( @@ -32,16 +61,6 @@ register( } ) -register( - id='SimpleReacher-v1', - entry_point='alr_envs.alr.classic_control:SimpleReacherEnv', - max_episode_steps=200, - kwargs={ - "n_links": 2, - "random_start": False - } -) - register( id='LongSimpleReacher-v0', entry_point='alr_envs.alr.classic_control:SimpleReacherEnv', @@ -51,16 +70,6 @@ register( } ) -register( - id='LongSimpleReacher-v1', - entry_point='alr_envs.alr.classic_control:SimpleReacherEnv', - max_episode_steps=200, - kwargs={ - "n_links": 5, - "random_start": False - } -) - ## Viapoint Reacher register( @@ -91,38 +100,6 @@ register( } ) -register( - id='HoleReacher-v1', - entry_point='alr_envs.alr.classic_control:HoleReacherEnv', - max_episode_steps=200, - kwargs={ - "n_links": 5, - "random_start": False, - "allow_self_collision": False, - "allow_wall_collision": False, - "hole_width": 0.25, - "hole_depth": 1, - "hole_x": None, - "collision_penalty": 100, - } -) - -register( - id='HoleReacher-v2', - entry_point='alr_envs.alr.classic_control:HoleReacherEnv', - max_episode_steps=200, - kwargs={ - "n_links": 5, - "random_start": False, - "allow_self_collision": False, - "allow_wall_collision": False, - "hole_width": 0.25, - "hole_depth": 1, - "hole_x": 2, - "collision_penalty": 1, - } -) - # Mujoco ## Reacher @@ -203,108 +180,39 @@ register( } ) -_vs = np.arange(101).tolist() + [1e-5, 5e-5, 1e-4, 5e-4, 1e-3, 5e-3, 1e-2, 5e-2, 1e-1, 5e-1] -for i in _vs: - _env_id = f'ALRReacher{i}-v0' - register( - id=_env_id, - entry_point='alr_envs.alr.mujoco:ALRReacherEnv', - max_episode_steps=200, - kwargs={ - "steps_before_reward": 0, - "n_links": 5, - "balance": False, - 'ctrl_cost_weight': i - } - ) - - _env_id = f'ALRReacherSparse{i}-v0' - register( - id=_env_id, - entry_point='alr_envs.alr.mujoco:ALRReacherEnv', - max_episode_steps=200, - kwargs={ - "steps_before_reward": 200, - "n_links": 5, - "balance": False, - 'ctrl_cost_weight': i - } - ) - -# CtxtFree are v0, Contextual are v1 register( id='ALRAntJump-v0', entry_point='alr_envs.alr.mujoco:ALRAntJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_ANTJUMP, - kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_ANTJUMP, - "context": False - } -) - -# CtxtFree are v0, Contextual are v1 -register( - id='ALRAntJump-v1', - entry_point='alr_envs.alr.mujoco:ALRAntJumpEnv', - max_episode_steps=MAX_EPISODE_STEPS_ANTJUMP, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_ANTJUMP, "context": True } ) -# CtxtFree are v0, Contextual are v1 register( id='ALRHalfCheetahJump-v0', entry_point='alr_envs.alr.mujoco:ALRHalfCheetahJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HALFCHEETAHJUMP, - kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HALFCHEETAHJUMP, - "context": False - } -) -# CtxtFree are v0, Contextual are v1 -register( - id='ALRHalfCheetahJump-v1', - entry_point='alr_envs.alr.mujoco:ALRHalfCheetahJumpEnv', - max_episode_steps=MAX_EPISODE_STEPS_HALFCHEETAHJUMP, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HALFCHEETAHJUMP, "context": True } ) -# CtxtFree are v0, Contextual are v1 + register( id='ALRHopperJump-v0', entry_point='alr_envs.alr.mujoco:ALRHopperJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, - kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, - "context": False, - "healthy_reward": 1.0 - } -) -register( - id='ALRHopperJump-v1', - entry_point='alr_envs.alr.mujoco:ALRHopperJumpEnv', - max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, "context": True } ) +#### Hopper Jump random joints and des position register( - id='ALRHopperJump-v2', - entry_point='alr_envs.alr.mujoco:ALRHopperJumpRndmPosEnv', - max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, - kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP - } -) - -register( - id='ALRHopperJump-v3', + id='ALRHopperJumpRndmJointsDesPos-v0', entry_point='alr_envs.alr.mujoco:ALRHopperXYJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ @@ -314,9 +222,9 @@ register( } ) -##### Hopper Jump step based reward +##### Hopper Jump random joints and des position step based reward register( - id='ALRHopperJump-v4', + id='ALRHopperJumpRndmJointsDesPosStepBased-v0', entry_point='alr_envs.alr.mujoco:ALRHopperXYJumpEnvStepBased', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ @@ -326,84 +234,40 @@ register( } ) - -# CtxtFree are v0, Contextual are v1 register( id='ALRHopperJumpOnBox-v0', entry_point='alr_envs.alr.mujoco:ALRHopperJumpOnBoxEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMPONBOX, - kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMPONBOX, - "context": False - } -) -# CtxtFree are v0, Contextual are v1 -register( - id='ALRHopperJumpOnBox-v1', - entry_point='alr_envs.alr.mujoco:ALRHopperJumpOnBoxEnv', - max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMPONBOX, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMPONBOX, "context": True } ) -# CtxtFree are v0, Contextual are v1 register( id='ALRHopperThrow-v0', entry_point='alr_envs.alr.mujoco:ALRHopperThrowEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROW, - kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROW, - "context": False - } -) -# CtxtFree are v0, Contextual are v1 -register( - id='ALRHopperThrow-v1', - entry_point='alr_envs.alr.mujoco:ALRHopperThrowEnv', - max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROW, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROW, "context": True } ) -# CtxtFree are v0, Contextual are v1 register( id='ALRHopperThrowInBasket-v0', entry_point='alr_envs.alr.mujoco:ALRHopperThrowInBasketEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, - kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, - "context": False - } -) -# CtxtFree are v0, Contextual are v1 -register( - id='ALRHopperThrowInBasket-v1', - entry_point='alr_envs.alr.mujoco:ALRHopperThrowInBasketEnv', - max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, "context": True } ) -# CtxtFree are v0, Contextual are v1 + register( id='ALRWalker2DJump-v0', entry_point='alr_envs.alr.mujoco:ALRWalker2dJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_WALKERJUMP, - kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_WALKERJUMP, - "context": False - } -) -# CtxtFree are v0, Contextual are v1 -register( - id='ALRWalker2DJump-v1', - entry_point='alr_envs.alr.mujoco:ALRWalker2dJumpEnv', - max_episode_steps=MAX_EPISODE_STEPS_WALKERJUMP, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_WALKERJUMP, "context": True @@ -427,76 +291,46 @@ register(id='TableTennis2DCtxt-v0', max_episode_steps=MAX_EPISODE_STEPS, kwargs={'ctxt_dim': 2}) -register(id='TableTennis2DCtxt-v1', - entry_point='alr_envs.alr.mujoco:TTEnvGym', - max_episode_steps=MAX_EPISODE_STEPS, - kwargs={'ctxt_dim': 2, 'fixed_goal': True}) - register(id='TableTennis4DCtxt-v0', entry_point='alr_envs.alr.mujocco:TTEnvGym', max_episode_steps=MAX_EPISODE_STEPS, kwargs={'ctxt_dim': 4}) -## BeerPong -# fixed goal cup position register( - id='ALRBeerPong-v0', - entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', - max_episode_steps=300, - kwargs={ - "rndm_goal": False, - "cup_goal_pos": [0.1, -2.0], - "frame_skip": 2 - } - ) + id='ALRBeerPong-v0', + entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', + max_episode_steps=300, + kwargs={ + "rndm_goal": True, + "cup_goal_pos": [-0.3, -1.2], + "frame_skip": 2 + } +) - -# random goal cup position +# Here we use the same reward as in ALRBeerPong-v0, but now consider after the release, +# only one time step, i.e. we simulate until the end of th episode register( - id='ALRBeerPong-v1', - entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', - max_episode_steps=300, - kwargs={ - "rndm_goal": True, - "cup_goal_pos": [-0.3, -1.2], - "frame_skip": 2 - } - ) - -# random goal cup position -register( - id='ALRBeerPong-v2', - entry_point='alr_envs.alr.mujoco:ALRBeerBongEnvStepBased', - max_episode_steps=300, - kwargs={ - "rndm_goal": True, - "cup_goal_pos": [-0.3, -1.2], - "frame_skip": 2 - } - ) -# Beerpong with episodic reward, but fixed release time step -register( - id='ALRBeerPong-v3', - entry_point='alr_envs.alr.mujoco:ALRBeerBongEnvStepBasedEpisodicReward', - max_episode_steps=300, - kwargs={ - "rndm_goal": True, - "cup_goal_pos": [-0.3, -1.2], - "frame_skip": 2 - } - ) + id='ALRBeerPongStepBased-v0', + entry_point='alr_envs.alr.mujoco:ALRBeerBongEnvStepBased', + max_episode_steps=300, + kwargs={ + "rndm_goal": True, + "cup_goal_pos": [-0.3, -1.2], + "frame_skip": 2 + } +) # Beerpong with episodic reward, but fixed release time step register( - id='ALRBeerPong-v4', - entry_point='alr_envs.alr.mujoco:ALRBeerBongEnvFixedReleaseStep', - max_episode_steps=300, - kwargs={ - "rndm_goal": True, - "cup_goal_pos": [-0.3, -1.2], - "frame_skip": 2 - } - ) + id='ALRBeerPongFixedRelease-v0', + entry_point='alr_envs.alr.mujoco:ALRBeerBongEnvFixedReleaseStep', + max_episode_steps=300, + kwargs={ + "rndm_goal": True, + "cup_goal_pos": [-0.3, -1.2], + "frame_skip": 2 + } +) # Motion Primitive Environments @@ -530,25 +364,17 @@ for _v in _versions: ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' + kwargs_dict_simple_reacher_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_simple_reacher_promp['wrappers'].append('TODO') # TODO + kwargs_dict_simple_reacher_promp['movement_primitives_kwargs']['action_dim'] = 2 if "long" not in _v.lower() else 5 + kwargs_dict_simple_reacher_promp['phase_generator_kwargs']['tau'] = 2 + kwargs_dict_simple_reacher_promp['controller_kwargs']['p_gains'] = 0.6 + kwargs_dict_simple_reacher_promp['controller_kwargs']['d_gains'] = 0.075 + kwargs_dict_simple_reacher_promp['name'] = _env_id register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": f"alr_envs:{_v}", - "wrappers": [classic_control.simple_reacher.MPWrapper], - "mp_kwargs": { - "num_dof": 2 if "long" not in _v.lower() else 5, - "num_basis": 5, - "duration": 2, - "policy_type": "motor", - "weights_scale": 1, - "zero_start": True, - "policy_kwargs": { - "p_gains": .6, - "d_gains": .075 - } - } - } + kwargs=kwargs_dict_simple_reacher_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -573,28 +399,24 @@ register( ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append("ViaPointReacherDMP-v0") +kwargs_dict_via_point_reacher_promp = dict(DEFAULT_MP_ENV_DICT) +kwargs_dict_via_point_reacher_promp['wrappers'].append('TODO') # TODO +kwargs_dict_via_point_reacher_promp['movement_primitives_kwargs']['action_dim'] = 5 +kwargs_dict_via_point_reacher_promp['phase_generator_kwargs']['tau'] = 2 +kwargs_dict_via_point_reacher_promp['controller_kwargs']['controller_type'] = 'velocity' +kwargs_dict_via_point_reacher_promp['name'] = "ViaPointReacherProMP-v0" register( id="ViaPointReacherProMP-v0", entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": f"alr_envs:ViaPointReacher-v0", - "wrappers": [classic_control.viapoint_reacher.MPWrapper], - "mp_kwargs": { - "num_dof": 5, - "num_basis": 5, - "duration": 2, - "policy_type": "velocity", - "weights_scale": 1, - "zero_start": True - } - } + kwargs=kwargs_dict_via_point_reacher_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ViaPointReacherProMP-v0") ## Hole Reacher -_versions = ["v0", "v1", "v2"] +_versions = ["HoleReacher-v0"] for _v in _versions: - _env_id = f'HoleReacherDMP-{_v}' + _name = _v.split("-") + _env_id = f'{_name[0]}DMP-{_name[1]}' register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_dmp_env_helper', @@ -617,22 +439,19 @@ for _v in _versions: ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) - _env_id = f'HoleReacherProMP-{_v}' + _env_id = f'{_name[0]}ProMP-{_name[1]}' + kwargs_dict_hole_reacher_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_hole_reacher_promp['wrappers'].append('TODO') # TODO + kwargs_dict_hole_reacher_promp['ep_wrapper_kwargs']['weight_scale'] = 2 + kwargs_dict_hole_reacher_promp['movement_primitives_kwargs']['action_dim'] = 5 + kwargs_dict_hole_reacher_promp['phase_generator_kwargs']['tau'] = 2 + kwargs_dict_hole_reacher_promp['controller_kwargs']['controller_type'] = 'velocity' + kwargs_dict_hole_reacher_promp['basis_generator_kwargs']['num_basis'] = 5 + kwargs_dict_hole_reacher_promp['name'] = f"alr_envs:{_v}" register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": f"alr_envs:HoleReacher-{_v}", - "wrappers": [classic_control.hole_reacher.MPWrapper], - "mp_kwargs": { - "num_dof": 5, - "num_basis": 3, - "duration": 2, - "policy_type": "velocity", - "weights_scale": 5, - "zero_start": True - } - } + kwargs=kwargs_dict_hole_reacher_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -666,30 +485,268 @@ for _v in _versions: ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' + kwargs_dict_alr_reacher_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_alr_reacher_promp['wrappers'].append('TODO') # TODO + kwargs_dict_alr_reacher_promp['movement_primitives_kwargs']['action_dim'] = 5 if "long" not in _v.lower() else 7 + kwargs_dict_alr_reacher_promp['phase_generator_kwargs']['tau'] = 4 + kwargs_dict_alr_reacher_promp['controller_kwargs']['p_gains'] = 1 + kwargs_dict_alr_reacher_promp['controller_kwargs']['d_gains'] = 0.1 + kwargs_dict_alr_reacher_promp['name'] = f"alr_envs:{_v}" register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": f"alr_envs:{_v}", - "wrappers": [mujoco.reacher.MPWrapper], - "mp_kwargs": { - "num_dof": 5 if "long" not in _v.lower() else 7, - "num_basis": 2, - "duration": 4, - "policy_type": "motor", - "weights_scale": 5, - "zero_start": True, - "policy_kwargs": { - "p_gains": 1, - "d_gains": 0.1 - } - } - } + kwargs=kwargs_dict_alr_reacher_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) +######################################################################################################################## +## Beerpong ProMP +_versions = ['ALRBeerPong-v0'] +for _v in _versions: + _name = _v.split("-") + _env_id = f'{_name[0]}ProMP-{_name[1]}' + kwargs_dict_bp_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.NewMPWrapper) + kwargs_dict_bp_promp['movement_primitives_kwargs']['action_dim'] = 7 + kwargs_dict_bp_promp['phase_generator_kwargs']['tau'] = 0.8 + kwargs_dict_bp_promp['phase_generator_kwargs']['learn_tau'] = True + kwargs_dict_bp_promp['controller_kwargs']['p_gains'] = np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]) + kwargs_dict_bp_promp['controller_kwargs']['d_gains'] = np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) + kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis'] = 2 + kwargs_dict_bp_promp['name'] = f"alr_envs:{_v}" + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + kwargs=kwargs_dict_bp_promp + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) +### BP with Fixed release +_versions = ["ALRBeerPongStepBased-v0", "ALRBeerPongFixedRelease-v0"] +for _v in _versions: + _name = _v.split("-") + _env_id = f'{_name[0]}ProMP-{_name[1]}' + kwargs_dict_bp_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.NewMPWrapper) + kwargs_dict_bp_promp['movement_primitives_kwargs']['action_dim'] = 7 + kwargs_dict_bp_promp['phase_generator_kwargs']['tau'] = 0.62 + kwargs_dict_bp_promp['controller_kwargs']['p_gains'] = np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]) + kwargs_dict_bp_promp['controller_kwargs']['d_gains'] = np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) + kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis'] = 2 + kwargs_dict_bp_promp['name'] = f"alr_envs:{_v}" + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + kwargs=kwargs_dict_bp_promp_fixed_release + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) +######################################################################################################################## + +## Table Tennis needs to be fixed according to Zhou's implementation + +######################################################################################################################## + +## AntJump +_versions = ['ALRAntJump-v0'] +for _v in _versions: + _name = _v.split("-") + _env_id = f'{_name[0]}ProMP-{_name[1]}' + kwargs_dict_ant_jump_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_ant_jump_promp['wrappers'].append(mujoco.ant_jump.NewMPWrapper) + kwargs_dict_ant_jump_promp['movement_primitives_kwargs']['action_dim'] = 8 + kwargs_dict_ant_jump_promp['phase_generator_kwargs']['tau'] = 10 + kwargs_dict_ant_jump_promp['controller_kwargs']['p_gains'] = np.ones(8) + kwargs_dict_ant_jump_promp['controller_kwargs']['d_gains'] = 0.1 * np.ones(8) + kwargs_dict_ant_jump_promp['name'] = f"alr_envs:{_v}" + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + kwargs=kwargs_dict_ant_jump_promp + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + +######################################################################################################################## + +## HalfCheetahJump +_versions = ['ALRHalfCheetahJump-v0'] +for _v in _versions: + _name = _v.split("-") + _env_id = f'{_name[0]}ProMP-{_name[1]}' + kwargs_dict_halfcheetah_jump_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_halfcheetah_jump_promp['wrappers'].append(mujoco.ant_jump.NewMPWrapper) + kwargs_dict_halfcheetah_jump_promp['movement_primitives_kwargs']['action_dim'] = 6 + kwargs_dict_halfcheetah_jump_promp['phase_generator_kwargs']['tau'] = 5 + kwargs_dict_halfcheetah_jump_promp['controller_kwargs']['p_gains'] = np.ones(6) + kwargs_dict_halfcheetah_jump_promp['controller_kwargs']['d_gains'] = 0.1 * np.ones(6) + kwargs_dict_halfcheetah_jump_promp['name'] = f"alr_envs:{_v}" + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs=kwargs_dict_halfcheetah_jump_promp + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + +######################################################################################################################## + + +## HopperJump +_versions = ['ALRHopperJump-v0', 'ALRHopperJumpRndmJointsDesPos-v0', 'ALRHopperJumpRndmJointsDesPosStepBased-v0', + 'ALRHopperJumpOnBox-v0', 'ALRHopperThrow-v0', 'ALRHopperThrowInBasket-v0'] + +for _v in _versions: + _name = _v.split("-") + _env_id = f'{_name[0]}ProMP-{_name[1]}' + kwargs_dict_hopper_jump_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_hopper_jump_promp['wrappers'].append('TODO') # TODO + kwargs_dict_hopper_jump_promp['movement_primitives_kwargs']['action_dim'] = 3 + kwargs_dict_hopper_jump_promp['phase_generator_kwargs']['tau'] = 2 + kwargs_dict_hopper_jump_promp['controller_kwargs']['p_gains'] = np.ones(3) + kwargs_dict_hopper_jump_promp['controller_kwargs']['d_gains'] = 0.1 * np.ones(3) + kwargs_dict_hopper_jump_promp['name'] = f"alr_envs:{_v}" + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + kwargs=kwargs_dict_hopper_jump_promp + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + +######################################################################################################################## + + +## Walker2DJump +_versions = ['ALRWalker2DJump-v0'] +for _v in _versions: + _name = _v.split("-") + _env_id = f'{_name[0]}ProMP-{_name[1]}' + kwargs_dict_walker2d_jump_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_walker2d_jump_promp['wrappers'].append('TODO') # TODO + kwargs_dict_walker2d_jump_promp['movement_primitives_kwargs']['action_dim'] = 6 + kwargs_dict_walker2d_jump_promp['phase_generator_kwargs']['tau'] = 2.4 + kwargs_dict_walker2d_jump_promp['controller_kwargs']['p_gains'] = np.ones(6) + kwargs_dict_walker2d_jump_promp['controller_kwargs']['d_gains'] = 0.1 * np.ones(6) + kwargs_dict_walker2d_jump_promp['name'] = f"alr_envs:{_v}" + register( + id=_env_id, + entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + kwargs=kwargs_dict_walker2d_jump_promp + ) + ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + +### Depricated, we will not provide non random starts anymore +""" +register( + id='SimpleReacher-v1', + entry_point='alr_envs.alr.classic_control:SimpleReacherEnv', + max_episode_steps=200, + kwargs={ + "n_links": 2, + "random_start": False + } +) + +register( + id='LongSimpleReacher-v1', + entry_point='alr_envs.alr.classic_control:SimpleReacherEnv', + max_episode_steps=200, + kwargs={ + "n_links": 5, + "random_start": False + } +) +register( + id='HoleReacher-v1', + entry_point='alr_envs.alr.classic_control:HoleReacherEnv', + max_episode_steps=200, + kwargs={ + "n_links": 5, + "random_start": False, + "allow_self_collision": False, + "allow_wall_collision": False, + "hole_width": 0.25, + "hole_depth": 1, + "hole_x": None, + "collision_penalty": 100, + } +) +register( + id='HoleReacher-v2', + entry_point='alr_envs.alr.classic_control:HoleReacherEnv', + max_episode_steps=200, + kwargs={ + "n_links": 5, + "random_start": False, + "allow_self_collision": False, + "allow_wall_collision": False, + "hole_width": 0.25, + "hole_depth": 1, + "hole_x": 2, + "collision_penalty": 1, + } +) + +# CtxtFree are v0, Contextual are v1 +register( + id='ALRAntJump-v0', + entry_point='alr_envs.alr.mujoco:ALRAntJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_ANTJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_ANTJUMP, + "context": False + } +) +# CtxtFree are v0, Contextual are v1 +register( + id='ALRHalfCheetahJump-v0', + entry_point='alr_envs.alr.mujoco:ALRHalfCheetahJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_HALFCHEETAHJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HALFCHEETAHJUMP, + "context": False + } +) +register( + id='ALRHopperJump-v0', + entry_point='alr_envs.alr.mujoco:ALRHopperJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, + kwargs={ + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, + "context": False, + "healthy_reward": 1.0 + } +) + +""" + +### Deprecated used for CorL paper +""" _vs = np.arange(101).tolist() + [1e-5, 5e-5, 1e-4, 5e-4, 1e-3, 5e-3, 1e-2, 5e-2, 1e-1, 5e-1] +for i in _vs: + _env_id = f'ALRReacher{i}-v0' + register( + id=_env_id, + entry_point='alr_envs.alr.mujoco:ALRReacherEnv', + max_episode_steps=200, + kwargs={ + "steps_before_reward": 0, + "n_links": 5, + "balance": False, + 'ctrl_cost_weight': i + } + ) + + _env_id = f'ALRReacherSparse{i}-v0' + register( + id=_env_id, + entry_point='alr_envs.alr.mujoco:ALRReacherEnv', + max_episode_steps=200, + kwargs={ + "steps_before_reward": 200, + "n_links": 5, + "balance": False, + 'ctrl_cost_weight': i + } + ) + _vs = np.arange(101).tolist() + [1e-5, 5e-5, 1e-4, 5e-4, 1e-3, 5e-3, 1e-2, 5e-2, 1e-1, 5e-1] for i in _vs: _env_id = f'ALRReacher{i}ProMP-v0' register( @@ -736,543 +793,56 @@ for i in _vs: } } ) - - -# ## Beerpong -# _versions = ["v0", "v1"] -# for _v in _versions: -# _env_id = f'BeerpongProMP-{_v}' -# register( -# id=_env_id, -# entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', -# kwargs={ -# "name": f"alr_envs:ALRBeerPong-{_v}", -# "wrappers": [mujoco.beerpong.MPWrapper], -# "mp_kwargs": { -# "num_dof": 7, -# "num_basis": 2, -# # "duration": 1, -# "duration": 0.5, -# # "post_traj_time": 2, -# "post_traj_time": 2.5, -# "policy_type": "motor", -# "weights_scale": 0.14, -# # "weights_scale": 1, -# "zero_start": True, -# "zero_goal": False, -# "policy_kwargs": { -# "p_gains": np.array([ 1.5, 5, 2.55, 3, 2., 2, 1.25]), -# "d_gains": np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) -# } -# } -# } -# ) -# ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -## Beerpong -_versions = ["v0", "v1"] -for _v in _versions: - _env_id = f'BeerpongProMP-{_v}' + register( - id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + id='ALRHopperJumpOnBox-v0', + entry_point='alr_envs.alr.mujoco:ALRHopperJumpOnBoxEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMPONBOX, kwargs={ - "name": f"alr_envs:ALRBeerPong-{_v}", - "wrappers": [mujoco.beerpong.NewMPWrapper], - "ep_wrapper_kwargs": { - "weight_scale": 1 - }, - "movement_primitives_kwargs": { - 'movement_primitives_type': 'promp', - 'action_dim': 7 - }, - "phase_generator_kwargs": { - 'phase_generator_type': 'linear', - 'delay': 0, - 'tau': 0.8, # initial value - 'learn_tau': True, - 'learn_delay': False - }, - "controller_kwargs": { - 'controller_type': 'motor', - "p_gains": np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]), - "d_gains": np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]), - }, - "basis_generator_kwargs": { - 'basis_generator_type': 'zero_rbf', - 'num_basis': 2, - 'num_basis_zero_start': 2 - } - } + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMPONBOX, + "context": False + } ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -## Beerpong ProMP fixed release -_env_id = 'BeerpongProMP-v2' -register( - id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + register( + id='ALRHopperThrow-v0', + entry_point='alr_envs.alr.mujoco:ALRHopperThrowEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROW, kwargs={ - "name": "alr_envs:ALRBeerPong-v4", - "wrappers": [mujoco.beerpong.NewMPWrapper], - "ep_wrapper_kwargs": { - "weight_scale": 1 - }, - "movement_primitives_kwargs": { - 'movement_primitives_type': 'promp', - 'action_dim': 7 - }, - "phase_generator_kwargs": { - 'phase_generator_type': 'linear', - 'delay': 0, - 'tau': 0.62, # initial value - 'learn_tau': False, - 'learn_delay': False - }, - "controller_kwargs": { - 'controller_type': 'motor', - "p_gains": np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]), - "d_gains": np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]), - }, - "basis_generator_kwargs": { - 'basis_generator_type': 'zero_rbf', - 'num_basis': 2, - 'num_basis_zero_start': 2 - } - } -) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -## Table Tennis -ctxt_dim = [2, 4] -for _v, cd in enumerate(ctxt_dim): - _env_id = f'TableTennisProMP-v{_v}' + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROW, + "context": False + } + ) register( - id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": "alr_envs:TableTennis{}DCtxt-v0".format(cd), - "wrappers": [mujoco.table_tennis.MPWrapper], - "mp_kwargs": { - "num_dof": 7, - "num_basis": 2, - "duration": 1.25, - "post_traj_time": 1.5, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": 0.5*np.array([1.0, 4.0, 2.0, 4.0, 1.0, 4.0, 1.0]), - "d_gains": 0.5*np.array([0.1, 0.4, 0.2, 0.4, 0.1, 0.4, 0.1]) - } - } - } - ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -## AntJump -_versions = ["v0", "v1"] -for _v in _versions: - _env_id = f'ALRAntJumpProMP-{_v}' - register( - id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": f"alr_envs:ALRAntJump-{_v}", - "wrappers": [mujoco.ant_jump.MPWrapper], - "mp_kwargs": { - "num_dof": 8, - "num_basis": 5, - "duration": 10, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(8), - "d_gains": 0.1*np.ones(8) - } - } - } - ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -## AntJump -_versions = ["v0", "v1"] -for _v in _versions: - _env_id = f'ALRAntJumpProMP-{_v}' - register( - id= _env_id, - entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', - kwargs={ - "name": f"alr_envs:ALRAntJump-{_v}", - "wrappers": [mujoco.ant_jump.NewMPWrapper], - "ep_wrapper_kwargs": { - "weight_scale": 1 - }, - "movement_primitives_kwargs": { - 'movement_primitives_type': 'promp', - 'action_dim': 8 - }, - "phase_generator_kwargs": { - 'phase_generator_type': 'linear', - 'delay': 0, - 'tau': 10, # initial value - 'learn_tau': False, - 'learn_delay': False - }, - "controller_kwargs": { - 'controller_type': 'motor', - "p_gains": np.ones(8), - "d_gains": 0.1*np.ones(8), - }, - "basis_generator_kwargs": { - 'basis_generator_type': 'zero_rbf', - 'num_basis': 5, - 'num_basis_zero_start': 2 - } - } - ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - - - -## HalfCheetahJump -_versions = ["v0", "v1"] -for _v in _versions: - _env_id = f'ALRHalfCheetahJumpProMP-{_v}' - register( - id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": f"alr_envs:ALRHalfCheetahJump-{_v}", - "wrappers": [mujoco.half_cheetah_jump.MPWrapper], - "mp_kwargs": { - "num_dof": 6, - "num_basis": 5, - "duration": 5, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(6), - "d_gains": 0.1*np.ones(6) - } - } - } - ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -# ## HopperJump -# _versions = ["v0", "v1"] -# for _v in _versions: -# _env_id = f'ALRHopperJumpProMP-{_v}' -# register( -# id= _env_id, -# entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', -# kwargs={ -# "name": f"alr_envs:ALRHopperJump-{_v}", -# "wrappers": [mujoco.hopper_jump.MPWrapper], -# "mp_kwargs": { -# "num_dof": 3, -# "num_basis": 5, -# "duration": 2, -# "post_traj_time": 0, -# "policy_type": "motor", -# "weights_scale": 1.0, -# "zero_start": True, -# "zero_goal": False, -# "policy_kwargs": { -# "p_gains": np.ones(3), -# "d_gains": 0.1*np.ones(3) -# } -# } -# } -# ) -# ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -# ## HopperJump -# register( -# id= "ALRHopperJumpProMP-v2", -# entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', -# kwargs={ -# "name": f"alr_envs:ALRHopperJump-v2", -# "wrappers": [mujoco.hopper_jump.HighCtxtMPWrapper], -# "mp_kwargs": { -# "num_dof": 3, -# "num_basis": 5, -# "duration": 2, -# "post_traj_time": 0, -# "policy_type": "motor", -# "weights_scale": 1.0, -# "zero_start": True, -# "zero_goal": False, -# "policy_kwargs": { -# "p_gains": np.ones(3), -# "d_gains": 0.1*np.ones(3) -# } -# } -# } -# ) -# ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ALRHopperJumpProMP-v2") - -## HopperJump -_versions = ["v0", "v1"] -for _v in _versions: - _env_id = f'ALRHopperJumpProMP-{_v}' - register( - id= _env_id, - entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', - kwargs={ - "name": f"alr_envs:ALRHopperJump-{_v}", - "wrappers": [mujoco.hopper_jump.NewMPWrapper], - "ep_wrapper_kwargs": { - "weight_scale": 1 - }, - "movement_primitives_kwargs": { - 'movement_primitives_type': 'promp', - 'action_dim': 3 - }, - "phase_generator_kwargs": { - 'phase_generator_type': 'linear', - 'delay': 0, - 'tau': 2, # initial value - 'learn_tau': False, - 'learn_delay': False - }, - "controller_kwargs": { - 'controller_type': 'motor', - "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3), - }, - "basis_generator_kwargs": { - 'basis_generator_type': 'zero_rbf', - 'num_basis': 5, - 'num_basis_zero_start': 1 - } - } - ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -## HopperJump -register( - id= "ALRHopperJumpProMP-v2", - entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + id='ALRHopperThrowInBasket-v0', + entry_point='alr_envs.alr.mujoco:ALRHopperThrowInBasketEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, kwargs={ - "name": f"alr_envs:ALRHopperJump-v2", - "wrappers": [mujoco.hopper_jump.NewHighCtxtMPWrapper], - "ep_wrapper_kwargs": { - "weight_scale": 1 - }, - "movement_primitives_kwargs": { - 'movement_primitives_type': 'promp', - 'action_dim': 3 - }, - "phase_generator_kwargs": { - 'phase_generator_type': 'linear', - 'delay': 0, - 'tau': 2, # initial value - 'learn_tau': False, - 'learn_delay': False - }, - "controller_kwargs": { - 'controller_type': 'motor', - "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3), - }, - "basis_generator_kwargs": { - 'basis_generator_type': 'zero_rbf', - 'num_basis': 5, - 'num_basis_zero_start': 1 - } - } -) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ALRHopperJumpProMP-v2") - - -## HopperJump -register( - id= "ALRHopperJumpProMP-v3", - entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, + "context": False + } + ) + register( + id='ALRWalker2DJump-v0', + entry_point='alr_envs.alr.mujoco:ALRWalker2dJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_WALKERJUMP, kwargs={ - "name": f"alr_envs:ALRHopperJump-v3", - "wrappers": [mujoco.hopper_jump.NewHighCtxtMPWrapper], - "ep_wrapper_kwargs": { - "weight_scale": 1 - }, - "movement_primitives_kwargs": { - 'movement_primitives_type': 'promp', - 'action_dim': 3 - }, - "phase_generator_kwargs": { - 'phase_generator_type': 'linear', - 'delay': 0, - 'tau': 2, # initial value - 'learn_tau': False, - 'learn_delay': False - }, - "controller_kwargs": { - 'controller_type': 'motor', - "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3), - }, - "basis_generator_kwargs": { - 'basis_generator_type': 'zero_rbf', - 'num_basis': 5, - 'num_basis_zero_start': 1 - } - } -) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ALRHopperJumpProMP-v3") - - -## HopperJump -register( - id= "ALRHopperJumpProMP-v4", - entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', - kwargs={ - "name": f"alr_envs:ALRHopperJump-v4", - "wrappers": [mujoco.hopper_jump.NewHighCtxtMPWrapper], - "ep_wrapper_kwargs": { - "weight_scale": 1 - }, - "movement_primitives_kwargs": { - 'movement_primitives_type': 'promp', - 'action_dim': 3 - }, - "phase_generator_kwargs": { - 'phase_generator_type': 'linear', - 'delay': 0, - 'tau': 2, # initial value - 'learn_tau': False, - 'learn_delay': False - }, - "controller_kwargs": { - 'controller_type': 'motor', - "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3), - }, - "basis_generator_kwargs": { - 'basis_generator_type': 'zero_rbf', - 'num_basis': 5, - 'num_basis_zero_start': 1 - } - } -) -ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ALRHopperJumpProMP-v4") - -## HopperJumpOnBox -_versions = ["v0", "v1"] -for _v in _versions: - _env_id = f'ALRHopperJumpOnBoxProMP-{_v}' - register( - id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": f"alr_envs:ALRHopperJumpOnBox-{_v}", - "wrappers": [mujoco.hopper_jump.MPWrapper], - "mp_kwargs": { - "num_dof": 3, - "num_basis": 5, - "duration": 2, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3) - } - } - } + "max_episode_steps": MAX_EPISODE_STEPS_WALKERJUMP, + "context": False + } ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + register(id='TableTennis2DCtxt-v1', + entry_point='alr_envs.alr.mujoco:TTEnvGym', + max_episode_steps=MAX_EPISODE_STEPS, + kwargs={'ctxt_dim': 2, 'fixed_goal': True}) -#HopperThrow -_versions = ["v0", "v1"] -for _v in _versions: - _env_id = f'ALRHopperThrowProMP-{_v}' register( - id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + id='ALRBeerPong-v0', + entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', + max_episode_steps=300, kwargs={ - "name": f"alr_envs:ALRHopperThrow-{_v}", - "wrappers": [mujoco.hopper_throw.MPWrapper], - "mp_kwargs": { - "num_dof": 3, - "num_basis": 5, - "duration": 2, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3) - } - } + "rndm_goal": False, + "cup_goal_pos": [0.1, -2.0], + "frame_skip": 2 } - ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -## HopperThrowInBasket -_versions = ["v0", "v1"] -for _v in _versions: - _env_id = f'ALRHopperThrowInBasketProMP-{_v}' - register( - id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": f"alr_envs:ALRHopperThrowInBasket-{_v}", - "wrappers": [mujoco.hopper_throw.MPWrapper], - "mp_kwargs": { - "num_dof": 3, - "num_basis": 5, - "duration": 2, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(3), - "d_gains": 0.1*np.ones(3) - } - } - } - ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) - -## Walker2DJump -_versions = ["v0", "v1"] -for _v in _versions: - _env_id = f'ALRWalker2DJumpProMP-{_v}' - register( - id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', - kwargs={ - "name": f"alr_envs:ALRWalker2DJump-{_v}", - "wrappers": [mujoco.walker_2d_jump.MPWrapper], - "mp_kwargs": { - "num_dof": 6, - "num_basis": 5, - "duration": 2.4, - "post_traj_time": 0, - "policy_type": "motor", - "weights_scale": 1.0, - "zero_start": True, - "zero_goal": False, - "policy_kwargs": { - "p_gains": np.ones(6), - "d_gains": 0.1*np.ones(6) - } - } - } - ) - ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) \ No newline at end of file + ) +""" diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index b7d376e..64d9e78 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -178,8 +178,6 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): [self._steps], ]) - def compute_reward(self): - @property def dt(self): return super(ALRBeerBongEnv, self).dt * self.repeat_action @@ -213,37 +211,37 @@ class ALRBeerBongEnvStepBasedEpisodicReward(ALRBeerBongEnv): return ob, reward, done, infos -class ALRBeerBongEnvStepBased(ALRBeerBongEnv): - def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): - super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) - self.release_step = 62 # empirically evaluated for frame_skip=2! - - def step(self, a): - if self._steps < self.release_step: - return super(ALRBeerBongEnvStepBased, self).step(a) - else: - reward = 0 - done = False - while not done: - sub_ob, sub_reward, done, sub_infos = super(ALRBeerBongEnvStepBased, self).step(np.zeros(a.shape)) - if not done or sub_infos['sim_crash']: - reward += sub_reward - else: - ball_pos = self.sim.data.body_xpos[self.sim.model._body_name2id["ball"]].copy() - cup_goal_dist_final = np.linalg.norm(ball_pos - self.sim.data.site_xpos[ - self.sim.model._site_name2id["cup_goal_final_table"]].copy()) - cup_goal_dist_top = np.linalg.norm(ball_pos - self.sim.data.site_xpos[ - self.sim.model._site_name2id["cup_goal_table"]].copy()) - if sub_infos['success']: - dist_rew = -cup_goal_dist_final ** 2 - else: - dist_rew = -0.5 * cup_goal_dist_final ** 2 - cup_goal_dist_top ** 2 - reward = reward - sub_infos['action_cost'] + dist_rew - infos = sub_infos - ob = sub_ob - ob[-1] = self.release_step + 1 # Since we simulate until the end of the episode, PPO does not see the - # internal steps and thus, the observation also needs to be set correctly - return ob, reward, done, infos +# class ALRBeerBongEnvStepBased(ALRBeerBongEnv): +# def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): +# super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) +# self.release_step = 62 # empirically evaluated for frame_skip=2! +# +# def step(self, a): +# if self._steps < self.release_step: +# return super(ALRBeerBongEnvStepBased, self).step(a) +# else: +# reward = 0 +# done = False +# while not done: +# sub_ob, sub_reward, done, sub_infos = super(ALRBeerBongEnvStepBased, self).step(np.zeros(a.shape)) +# if not done or sub_infos['sim_crash']: +# reward += sub_reward +# else: +# ball_pos = self.sim.data.body_xpos[self.sim.model._body_name2id["ball"]].copy() +# cup_goal_dist_final = np.linalg.norm(ball_pos - self.sim.data.site_xpos[ +# self.sim.model._site_name2id["cup_goal_final_table"]].copy()) +# cup_goal_dist_top = np.linalg.norm(ball_pos - self.sim.data.site_xpos[ +# self.sim.model._site_name2id["cup_goal_table"]].copy()) +# if sub_infos['success']: +# dist_rew = -cup_goal_dist_final ** 2 +# else: +# dist_rew = -0.5 * cup_goal_dist_final ** 2 - cup_goal_dist_top ** 2 +# reward = reward - sub_infos['action_cost'] + dist_rew +# infos = sub_infos +# ob = sub_ob +# ob[-1] = self.release_step + 1 # Since we simulate until the end of the episode, PPO does not see the +# # internal steps and thus, the observation also needs to be set correctly +# return ob, reward, done, infos if __name__ == "__main__": diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index 146b039..5cd234c 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -298,76 +298,6 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): return observation, reward, done, info -class ALRHopperJumpRndmPosEnv(ALRHopperJumpEnv): - def __init__(self, max_episode_steps=250): - super(ALRHopperJumpRndmPosEnv, self).__init__(exclude_current_positions_from_observation=False, - reset_noise_scale=5e-1, - max_episode_steps=max_episode_steps) - - def reset_model(self): - self._floor_geom_id = self.model.geom_name2id('floor') - self._foot_geom_id = self.model.geom_name2id('foot_geom') - noise_low = -np.ones(self.model.nq) * self._reset_noise_scale - noise_low[1] = 0 - noise_low[2] = 0 - noise_low[3] = -0.2 - noise_low[4] = -0.2 - noise_low[5] = -0.1 - - noise_high = np.ones(self.model.nq) * self._reset_noise_scale - noise_high[1] = 0 - noise_high[2] = 0 - noise_high[3] = 0 - noise_high[4] = 0 - noise_high[5] = 0.1 - - rnd_vec = self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) - # rnd_vec[2] *= 0.05 # the angle around the y axis shouldn't be too high as the agent then falls down quickly and - # can not recover - # rnd_vec[1] = np.clip(rnd_vec[1], 0, 0.3) - qpos = self.init_qpos + rnd_vec - qvel = self.init_qvel - - self.set_state(qpos, qvel) - - observation = self._get_obs() - return observation - - def step(self, action): - - self.current_step += 1 - self.do_simulation(action, self.frame_skip) - - self.contact_with_floor = self._contact_checker(self._floor_geom_id, self._foot_geom_id) if not \ - self.contact_with_floor else True - - height_after = self.get_body_com("torso")[2] - self.max_height = max(height_after, self.max_height) if self.contact_with_floor else 0 - - ctrl_cost = self.control_cost(action) - costs = ctrl_cost - done = False - - if self.current_step >= self.max_episode_steps: - healthy_reward = 0 - height_reward = self._forward_reward_weight * self.max_height # maybe move reward calculation into if structure and define two different _forward_reward_weight variables for context and episodic seperatley - rewards = height_reward + healthy_reward - - else: - # penalty for wrong start direction of first two joints; not needed, could be removed - rewards = ((action[:2] > 0) * self.penalty).sum() if self.current_step < 10 else 0 - - observation = self._get_obs() - reward = rewards - costs - info = { - 'height': height_after, - 'max_height': self.max_height, - 'goal': self.goal - } - - return observation, reward, done, info - - if __name__ == '__main__': render_mode = "human" # "human" or "partial" or "final" # env = ALRHopperJumpEnv() From 02b8a65bab918e18d72a0ead7770e39a8b982cb7 Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 29 Jun 2022 09:37:18 +0200 Subject: [PATCH 043/104] restructuring --- README.md | 4 +- alr_envs/alr/__init__.py | 8 +- .../alr/mujoco/ant_jump/new_mp_wrapper.py | 7 +- .../alr/mujoco/beerpong/new_mp_wrapper.py | 19 +- .../alr/mujoco/hopper_jump/new_mp_wrapper.py | 8 +- alr_envs/alr/mujoco/reacher/alr_reacher.py | 2 +- alr_envs/alr/mujoco/reacher/new_mp_wrapper.py | 6 +- alr_envs/dmc/__init__.py | 28 +-- alr_envs/examples/examples_dmc.py | 6 +- alr_envs/examples/examples_metaworld.py | 6 +- .../examples/examples_motion_primitives.py | 4 +- alr_envs/examples/examples_open_ai.py | 2 +- alr_envs/examples/pd_control_gain_tuning.py | 2 +- alr_envs/meta/__init__.py | 8 +- ...isodic_wrapper.py => black_box_wrapper.py} | 199 ++++++------------ .../mp/controllers/meta_world_controller.py | 4 +- alr_envs/mp/controllers/pd_controller.py | 2 +- alr_envs/mp/controllers/pos_controller.py | 2 +- alr_envs/mp/controllers/vel_controller.py | 2 +- alr_envs/mp/mp_factory.py | 14 +- alr_envs/mp/raw_interface_wrapper.py | 88 ++++++++ alr_envs/open_ai/__init__.py | 14 +- alr_envs/utils/make_env_helpers.py | 184 +++++----------- 23 files changed, 280 insertions(+), 339 deletions(-) rename alr_envs/mp/{episodic_wrapper.py => black_box_wrapper.py} (51%) create mode 100644 alr_envs/mp/raw_interface_wrapper.py diff --git a/README.md b/README.md index c08a1d4..607af63 100644 --- a/README.md +++ b/README.md @@ -198,8 +198,8 @@ wrappers = [alr_envs.dmc.suite.ball_in_cup.MPWrapper] mp_kwargs = {...} kwargs = {...} env = alr_envs.make_dmp_env(base_env_id, wrappers=wrappers, seed=1, mp_kwargs=mp_kwargs, **kwargs) -# OR for a deterministic ProMP (other mp_kwargs are required): -# env = alr_envs.make_promp_env(base_env, wrappers=wrappers, seed=seed, mp_kwargs=mp_args) +# OR for a deterministic ProMP (other traj_gen_kwargs are required): +# env = alr_envs.make_promp_env(base_env, wrappers=wrappers, seed=seed, traj_gen_kwargs=mp_args) rewards = 0 obs = env.reset() diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index ec539db..d8169a8 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -346,7 +346,7 @@ for _v in _versions: kwargs={ "name": f"alr_envs:{_v}", "wrappers": [classic_control.simple_reacher.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 2 if "long" not in _v.lower() else 5, "num_basis": 5, "duration": 2, @@ -386,7 +386,7 @@ register( kwargs={ "name": "alr_envs:ViaPointReacher-v0", "wrappers": [classic_control.viapoint_reacher.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 5, "num_basis": 5, "duration": 2, @@ -424,7 +424,7 @@ for _v in _versions: kwargs={ "name": f"alr_envs:HoleReacher-{_v}", "wrappers": [classic_control.hole_reacher.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 5, "num_basis": 5, "duration": 2, @@ -467,7 +467,7 @@ for _v in _versions: kwargs={ "name": f"alr_envs:{_v}", "wrappers": [mujoco.reacher.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 5 if "long" not in _v.lower() else 7, "num_basis": 2, "duration": 4, diff --git a/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py index c33048f..c12aa56 100644 --- a/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py @@ -1,12 +1,13 @@ -from alr_envs.mp.episodic_wrapper import EpisodicWrapper +from alr_envs.mp.black_box_wrapper import BlackBoxWrapper from typing import Union, Tuple import numpy as np +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class NewMPWrapper(EpisodicWrapper): +class NewMPWrapper(RawInterfaceWrapper): - def set_active_obs(self): + def get_context_mask(self): return np.hstack([ [False] * 111, # ant has 111 dimensional observation space !! [True] # goal height diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py index 53d7a1a..0df1a7c 100644 --- a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py @@ -1,15 +1,11 @@ -from typing import Tuple, Union +from typing import Union, Tuple import numpy as np -from alr_envs.mp.episodic_wrapper import EpisodicWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class NewMPWrapper(EpisodicWrapper): - - # def __init__(self, replanning_model): - # self.replanning_model = replanning_model - +class NewMPWrapper(RawInterfaceWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qpos[0:7].copy() @@ -18,7 +14,7 @@ class NewMPWrapper(EpisodicWrapper): def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qvel[0:7].copy() - def set_active_obs(self): + def get_context_mask(self): return np.hstack([ [False] * 7, # cos [False] * 7, # sin @@ -27,12 +23,7 @@ class NewMPWrapper(EpisodicWrapper): [False] * 3, # cup_goal_diff_top [True] * 2, # xy position of cup [False] # env steps - ]) - - def do_replanning(self, pos, vel, s, a, t, last_replan_step): - return False - # const = np.arange(0, 1000, 10) - # return bool(self.replanning_model(s)) + ]) def _episode_callback(self, action: np.ndarray) -> Tuple[np.ndarray, Union[np.ndarray, None]]: if self.mp.learn_tau: diff --git a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py index 77a1bf6..ccd8f76 100644 --- a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py @@ -1,9 +1,9 @@ -from alr_envs.mp.episodic_wrapper import EpisodicWrapper +from alr_envs.mp.black_box_wrapper import BlackBoxWrapper from typing import Union, Tuple import numpy as np -class NewMPWrapper(EpisodicWrapper): +class NewMPWrapper(BlackBoxWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qpos[3:6].copy() @@ -21,7 +21,7 @@ class NewMPWrapper(EpisodicWrapper): # ]) # Random x goal + random init pos - def set_active_obs(self): + def get_context_mask(self): return np.hstack([ [False] * (2 + int(not self.env.exclude_current_positions_from_observation)), # position [True] * 3, # set to true if randomize initial pos @@ -31,7 +31,7 @@ class NewMPWrapper(EpisodicWrapper): class NewHighCtxtMPWrapper(NewMPWrapper): - def set_active_obs(self): + def get_context_mask(self): return np.hstack([ [False] * (2 + int(not self.env.exclude_current_positions_from_observation)), # position [True] * 3, # set to true if randomize initial pos diff --git a/alr_envs/alr/mujoco/reacher/alr_reacher.py b/alr_envs/alr/mujoco/reacher/alr_reacher.py index c12352a..0699c44 100644 --- a/alr_envs/alr/mujoco/reacher/alr_reacher.py +++ b/alr_envs/alr/mujoco/reacher/alr_reacher.py @@ -149,4 +149,4 @@ if __name__ == '__main__': if d: env.reset() - env.close() \ No newline at end of file + env.close() diff --git a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py index 02dc1d8..8df365a 100644 --- a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py @@ -1,9 +1,9 @@ -from alr_envs.mp.episodic_wrapper import EpisodicWrapper +from alr_envs.mp.black_box_wrapper import BlackBoxWrapper from typing import Union, Tuple import numpy as np -class MPWrapper(EpisodicWrapper): +class MPWrapper(BlackBoxWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: @@ -12,7 +12,7 @@ class MPWrapper(EpisodicWrapper): def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qvel.flat[:self.env.n_links] - def set_active_obs(self): + def get_context_mask(self): return np.concatenate([ [False] * self.env.n_links, # cos [False] * self.env.n_links, # sin diff --git a/alr_envs/dmc/__init__.py b/alr_envs/dmc/__init__.py index ac34415..dc3adf0 100644 --- a/alr_envs/dmc/__init__.py +++ b/alr_envs/dmc/__init__.py @@ -15,7 +15,7 @@ register( "time_limit": 20, "episode_length": 1000, "wrappers": [suite.ball_in_cup.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 2, "num_basis": 5, "duration": 20, @@ -41,7 +41,7 @@ register( "time_limit": 20, "episode_length": 1000, "wrappers": [suite.ball_in_cup.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 2, "num_basis": 5, "duration": 20, @@ -65,7 +65,7 @@ register( "time_limit": 20, "episode_length": 1000, "wrappers": [suite.reacher.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 2, "num_basis": 5, "duration": 20, @@ -92,7 +92,7 @@ register( "time_limit": 20, "episode_length": 1000, "wrappers": [suite.reacher.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 2, "num_basis": 5, "duration": 20, @@ -117,7 +117,7 @@ register( "time_limit": 20, "episode_length": 1000, "wrappers": [suite.reacher.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 2, "num_basis": 5, "duration": 20, @@ -144,7 +144,7 @@ register( "time_limit": 20, "episode_length": 1000, "wrappers": [suite.reacher.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 2, "num_basis": 5, "duration": 20, @@ -174,7 +174,7 @@ for _task in _dmc_cartpole_tasks: "camera_id": 0, "episode_length": 1000, "wrappers": [suite.cartpole.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 1, "num_basis": 5, "duration": 10, @@ -203,7 +203,7 @@ for _task in _dmc_cartpole_tasks: "camera_id": 0, "episode_length": 1000, "wrappers": [suite.cartpole.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 1, "num_basis": 5, "duration": 10, @@ -230,7 +230,7 @@ register( "camera_id": 0, "episode_length": 1000, "wrappers": [suite.cartpole.TwoPolesMPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 1, "num_basis": 5, "duration": 10, @@ -259,7 +259,7 @@ register( "camera_id": 0, "episode_length": 1000, "wrappers": [suite.cartpole.TwoPolesMPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 1, "num_basis": 5, "duration": 10, @@ -286,7 +286,7 @@ register( "camera_id": 0, "episode_length": 1000, "wrappers": [suite.cartpole.ThreePolesMPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 1, "num_basis": 5, "duration": 10, @@ -315,7 +315,7 @@ register( "camera_id": 0, "episode_length": 1000, "wrappers": [suite.cartpole.ThreePolesMPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 1, "num_basis": 5, "duration": 10, @@ -342,7 +342,7 @@ register( # "time_limit": 1, "episode_length": 250, "wrappers": [manipulation.reach_site.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 9, "num_basis": 5, "duration": 10, @@ -365,7 +365,7 @@ register( # "time_limit": 1, "episode_length": 250, "wrappers": [manipulation.reach_site.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 9, "num_basis": 5, "duration": 10, diff --git a/alr_envs/examples/examples_dmc.py b/alr_envs/examples/examples_dmc.py index d223d3c..5658b1f 100644 --- a/alr_envs/examples/examples_dmc.py +++ b/alr_envs/examples/examples_dmc.py @@ -69,7 +69,7 @@ def example_custom_dmc_and_mp(seed=1, iterations=1, render=True): "learn_goal": True, # learn the goal position (recommended) "alpha_phase": 2, "bandwidth_factor": 2, - "policy_type": "motor", # controller type, 'velocity', 'position', and 'motor' (torque control) + "policy_type": "motor", # tracking_controller type, 'velocity', 'position', and 'motor' (torque control) "weights_scale": 1, # scaling of MP weights "goal_scale": 1, # scaling of learned goal position "policy_kwargs": { # only required for torque control/PD-Controller @@ -83,8 +83,8 @@ def example_custom_dmc_and_mp(seed=1, iterations=1, render=True): # "frame_skip": 1 } env = alr_envs.make_dmp_env(base_env, wrappers=wrappers, seed=seed, mp_kwargs=mp_kwargs, **kwargs) - # OR for a deterministic ProMP (other mp_kwargs are required, see metaworld_examples): - # env = alr_envs.make_promp_env(base_env, wrappers=wrappers, seed=seed, mp_kwargs=mp_args) + # OR for a deterministic ProMP (other traj_gen_kwargs are required, see metaworld_examples): + # env = alr_envs.make_promp_env(base_env, wrappers=wrappers, seed=seed, traj_gen_kwargs=mp_args) # This renders the full MP trajectory # It is only required to call render() once in the beginning, which renders every consecutive trajectory. diff --git a/alr_envs/examples/examples_metaworld.py b/alr_envs/examples/examples_metaworld.py index 9ead50c..3e040cc 100644 --- a/alr_envs/examples/examples_metaworld.py +++ b/alr_envs/examples/examples_metaworld.py @@ -73,12 +73,12 @@ def example_custom_dmc_and_mp(seed=1, iterations=1, render=True): "width": 0.025, # width of the basis functions "zero_start": True, # start from current environment position if True "weights_scale": 1, # scaling of MP weights - "policy_type": "metaworld", # custom controller type for metaworld environments + "policy_type": "metaworld", # custom tracking_controller type for metaworld environments } env = alr_envs.make_promp_env(base_env, wrappers=wrappers, seed=seed, mp_kwargs=mp_kwargs) - # OR for a DMP (other mp_kwargs are required, see dmc_examples): - # env = alr_envs.make_dmp_env(base_env, wrappers=wrappers, seed=seed, mp_kwargs=mp_kwargs, **kwargs) + # OR for a DMP (other traj_gen_kwargs are required, see dmc_examples): + # env = alr_envs.make_dmp_env(base_env, wrappers=wrappers, seed=seed, traj_gen_kwargs=traj_gen_kwargs, **kwargs) # This renders the full MP trajectory # It is only required to call render() once in the beginning, which renders every consecutive trajectory. diff --git a/alr_envs/examples/examples_motion_primitives.py b/alr_envs/examples/examples_motion_primitives.py index 1a679df..b9d355a 100644 --- a/alr_envs/examples/examples_motion_primitives.py +++ b/alr_envs/examples/examples_motion_primitives.py @@ -57,7 +57,7 @@ def example_custom_mp(env_name="alr_envs:HoleReacherDMP-v1", seed=1, iterations= Returns: """ - # Changing the mp_kwargs is possible by providing them to gym. + # Changing the traj_gen_kwargs is possible by providing them to gym. # E.g. here by providing way to many basis functions mp_kwargs = { "num_dof": 5, @@ -126,7 +126,7 @@ def example_fully_custom_mp(seed=1, iterations=1, render=True): } env = alr_envs.make_dmp_env(base_env, wrappers=wrappers, seed=seed, mp_kwargs=mp_kwargs) # OR for a deterministic ProMP: - # env = make_promp_env(base_env, wrappers=wrappers, seed=seed, mp_kwargs=mp_kwargs) + # env = make_promp_env(base_env, wrappers=wrappers, seed=seed, traj_gen_kwargs=traj_gen_kwargs) if render: env.render(mode="human") diff --git a/alr_envs/examples/examples_open_ai.py b/alr_envs/examples/examples_open_ai.py index dc0c558..631a3a1 100644 --- a/alr_envs/examples/examples_open_ai.py +++ b/alr_envs/examples/examples_open_ai.py @@ -4,7 +4,7 @@ import alr_envs def example_mp(env_name, seed=1): """ Example for running a motion primitive based version of a OpenAI-gym environment, which is already registered. - For more information on motion primitive specific stuff, look at the mp examples. + For more information on motion primitive specific stuff, look at the trajectory_generator examples. Args: env_name: ProMP env_id seed: seed diff --git a/alr_envs/examples/pd_control_gain_tuning.py b/alr_envs/examples/pd_control_gain_tuning.py index 1683c6f..e05bad1 100644 --- a/alr_envs/examples/pd_control_gain_tuning.py +++ b/alr_envs/examples/pd_control_gain_tuning.py @@ -8,7 +8,7 @@ from alr_envs.utils.make_env_helpers import make_promp_env def visualize(env): t = env.t - pos_features = env.mp.basis_generator.basis(t) + pos_features = env.trajectory_generator.basis_generator.basis(t) plt.plot(t, pos_features) plt.show() diff --git a/alr_envs/meta/__init__.py b/alr_envs/meta/__init__.py index 5651224..e0d0ea0 100644 --- a/alr_envs/meta/__init__.py +++ b/alr_envs/meta/__init__.py @@ -19,7 +19,7 @@ for _task in _goal_change_envs: kwargs={ "name": _task, "wrappers": [goal_change_mp_wrapper.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 4, "num_basis": 5, "duration": 6.25, @@ -42,7 +42,7 @@ for _task in _object_change_envs: kwargs={ "name": _task, "wrappers": [object_change_mp_wrapper.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 4, "num_basis": 5, "duration": 6.25, @@ -75,7 +75,7 @@ for _task in _goal_and_object_change_envs: kwargs={ "name": _task, "wrappers": [goal_object_change_mp_wrapper.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 4, "num_basis": 5, "duration": 6.25, @@ -98,7 +98,7 @@ for _task in _goal_and_endeffector_change_envs: kwargs={ "name": _task, "wrappers": [goal_endeffector_change_mp_wrapper.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 4, "num_basis": 5, "duration": 6.25, diff --git a/alr_envs/mp/episodic_wrapper.py b/alr_envs/mp/black_box_wrapper.py similarity index 51% rename from alr_envs/mp/episodic_wrapper.py rename to alr_envs/mp/black_box_wrapper.py index b2eb391..5ae0ff9 100644 --- a/alr_envs/mp/episodic_wrapper.py +++ b/alr_envs/mp/black_box_wrapper.py @@ -1,5 +1,5 @@ -from abc import ABC, abstractmethod -from typing import Union, Tuple +from abc import ABC +from typing import Tuple import gym import numpy as np @@ -7,77 +7,77 @@ from gym import spaces from mp_pytorch.mp.mp_interfaces import MPInterface from alr_envs.mp.controllers.base_controller import BaseController +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class EpisodicWrapper(gym.Env, gym.wrappers.TransformReward, ABC): - """ - Base class for movement primitive based gym.Wrapper implementations. +class BlackBoxWrapper(gym.ObservationWrapper, ABC): - Args: - env: The (wrapped) environment this wrapper is applied on - num_dof: Dimension of the action space of the wrapped env - num_basis: Number of basis functions per dof - duration: Length of the trajectory of the movement primitive in seconds - controller: Type or object defining the policy that is used to generate action based on the trajectory - weight_scale: Scaling parameter for the actions given to this wrapper - render_mode: Equivalent to gym render mode - """ + def __init__(self, + env: RawInterfaceWrapper, + trajectory_generator: MPInterface, tracking_controller: BaseController, + duration: float, verbose: int = 1, sequencing=True, reward_aggregation: callable = np.sum): + """ + gym.Wrapper for leveraging a black box approach with a trajectory generator. - def __init__( - self, - env: gym.Env, - mp: MPInterface, - controller: BaseController, - duration: float, - render_mode: str = None, - verbose: int = 1, - weight_scale: float = 1, - sequencing=True, - reward_aggregation=np.mean, - ): + Args: + env: The (wrapped) environment this wrapper is applied on + trajectory_generator: Generates the full or partial trajectory + tracking_controller: Translates the desired trajectory to raw action sequences + duration: Length of the trajectory of the movement primitive in seconds + verbose: level of detail for returned values in info dict. + reward_aggregation: function that takes the np.ndarray of step rewards as input and returns the trajectory + reward, default summation over all values. + """ super().__init__() self.env = env - try: - self.dt = env.dt - except AttributeError: - raise AttributeError("step based environment needs to have a function 'dt' ") self.duration = duration self.traj_steps = int(duration / self.dt) self.post_traj_steps = self.env.spec.max_episode_steps - self.traj_steps # duration = self.env.max_episode_steps * self.dt - self.mp = mp - self.env = env - self.controller = controller - self.weight_scale = weight_scale - - # rendering - self.render_mode = render_mode - self.render_kwargs = {} + # trajectory generation + self.trajectory_generator = trajectory_generator + self.tracking_controller = tracking_controller + # self.weight_scale = weight_scale self.time_steps = np.linspace(0, self.duration, self.traj_steps) - self.mp.set_mp_times(self.time_steps) - # self.mp.set_mp_duration(self.time_steps, dt) - # action_bounds = np.inf * np.ones((np.prod(self.mp.num_params))) - self.mp_action_space = self.get_mp_action_space() + self.trajectory_generator.set_mp_times(self.time_steps) + # self.trajectory_generator.set_mp_duration(self.time_steps, dt) + # action_bounds = np.inf * np.ones((np.prod(self.trajectory_generator.num_params))) + self.reward_aggregation = reward_aggregation + # spaces + self.mp_action_space = self.get_mp_action_space() self.action_space = self.get_action_space() - self.active_obs = self.set_active_obs() - self.observation_space = spaces.Box(low=self.env.observation_space.low[self.active_obs], - high=self.env.observation_space.high[self.active_obs], + self.observation_space = spaces.Box(low=self.env.observation_space.low[self.env.context_mask], + high=self.env.observation_space.high[self.env.context_mask], dtype=self.env.observation_space.dtype) + # rendering + self.render_mode = None + self.render_kwargs = {} + self.verbose = verbose + @property + def dt(self): + return self.env.dt + + def observation(self, observation): + return observation[self.env.context_mask] + def get_trajectory(self, action: np.ndarray) -> Tuple: # TODO: this follows the implementation of the mp_pytorch library which includes the parameters tau and delay at # the beginning of the array. - ignore_indices = int(self.mp.learn_tau) + int(self.mp.learn_delay) - scaled_mp_params = action.copy() - scaled_mp_params[ignore_indices:] *= self.weight_scale - self.mp.set_params(np.clip(scaled_mp_params, self.mp_action_space.low, self.mp_action_space.high)) - self.mp.set_boundary_conditions(bc_time=self.time_steps[:1], bc_pos=self.current_pos, bc_vel=self.current_vel) - traj_dict = self.mp.get_mp_trajs(get_pos=True, get_vel=True) + # ignore_indices = int(self.trajectory_generator.learn_tau) + int(self.trajectory_generator.learn_delay) + # scaled_mp_params = action.copy() + # scaled_mp_params[ignore_indices:] *= self.weight_scale + + clipped_params = np.clip(action, self.mp_action_space.low, self.mp_action_space.high) + self.trajectory_generator.set_params(clipped_params) + self.trajectory_generator.set_boundary_conditions(bc_time=self.time_steps[:1], bc_pos=self.current_pos, + bc_vel=self.current_vel) + traj_dict = self.trajectory_generator.get_mp_trajs(get_pos=True, get_vel=True) trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] trajectory = trajectory_tensor.numpy() @@ -86,13 +86,13 @@ class EpisodicWrapper(gym.Env, gym.wrappers.TransformReward, ABC): # TODO: Do we need this or does mp_pytorch have this? if self.post_traj_steps > 0: trajectory = np.vstack([trajectory, np.tile(trajectory[-1, :], [self.post_traj_steps, 1])]) - velocity = np.vstack([velocity, np.zeros(shape=(self.post_traj_steps, self.mp.num_dof))]) + velocity = np.vstack([velocity, np.zeros(shape=(self.post_traj_steps, self.trajectory_generator.num_dof))]) return trajectory, velocity def get_mp_action_space(self): - """This function can be used to set up an individual space for the parameters of the mp.""" - min_action_bounds, max_action_bounds = self.mp.get_param_bounds() + """This function can be used to set up an individual space for the parameters of the trajectory_generator.""" + min_action_bounds, max_action_bounds = self.trajectory_generator.get_param_bounds() mp_action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), dtype=np.float32) return mp_action_space @@ -109,71 +109,6 @@ class EpisodicWrapper(gym.Env, gym.wrappers.TransformReward, ABC): except AttributeError: return self.get_mp_action_space() - def _episode_callback(self, action: np.ndarray) -> Tuple[np.ndarray, Union[np.ndarray, None]]: - """ - Used to extract the parameters for the motion primitive and other parameters from an action array which might - include other actions like ball releasing time for the beer pong environment. - This only needs to be overwritten if the action space is modified. - Args: - action: a vector instance of the whole action space, includes mp parameters and additional parameters if - specified, else only mp parameters - - Returns: - Tuple: mp_arguments and other arguments - """ - return action, None - - def _step_callback(self, t: int, env_spec_params: Union[np.ndarray, None], step_action: np.ndarray) -> Union[ - np.ndarray]: - """ - This function can be used to modify the step_action with additional parameters e.g. releasing the ball in the - Beerpong env. The parameters used should not be part of the motion primitive parameters. - Returns step_action by default, can be overwritten in individual mp_wrappers. - Args: - t: the current time step of the episode - env_spec_params: the environment specific parameter, as defined in fucntion _episode_callback - (e.g. ball release time in Beer Pong) - step_action: the current step-based action - - Returns: - modified step action - """ - return step_action - - @abstractmethod - def set_active_obs(self) -> np.ndarray: - """ - This function defines the contexts. The contexts are defined as specific observations. - Returns: - boolearn array representing the indices of the observations - - """ - return np.ones(self.env.observation_space.shape[0], dtype=bool) - - @property - @abstractmethod - def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - """ - Returns the current position of the action/control dimension. - The dimensionality has to match the action/control dimension. - This is not required when exclusively using velocity control, - it should, however, be implemented regardless. - E.g. The joint positions that are directly or indirectly controlled by the action. - """ - raise NotImplementedError() - - @property - @abstractmethod - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - """ - Returns the current velocity of the action/control dimension. - The dimensionality has to match the action/control dimension. - This is not required when exclusively using position control, - it should, however, be implemented regardless. - E.g. The joint velocities that are directly or indirectly controlled by the action. - """ - raise NotImplementedError() - def step(self, action: np.ndarray): """ This function generates a trajectory based on a MP and then does the usual loop over reset and step""" # TODO: Think about sequencing @@ -184,46 +119,52 @@ class EpisodicWrapper(gym.Env, gym.wrappers.TransformReward, ABC): # TODO # self.time_steps = np.linspace(0, learned_duration, self.traj_steps) - # self.mp.set_mp_times(self.time_steps) + # self.trajectory_generator.set_mp_times(self.time_steps) trajectory_length = len(trajectory) + rewards = np.zeros(shape=(trajectory_length,)) if self.verbose >= 2: actions = np.zeros(shape=(trajectory_length,) + self.env.action_space.shape) observations = np.zeros(shape=(trajectory_length,) + self.env.observation_space.shape, dtype=self.env.observation_space.dtype) - rewards = np.zeros(shape=(trajectory_length,)) - trajectory_return = 0 infos = dict() + done = False for t, pos_vel in enumerate(zip(trajectory, velocity)): - step_action = self.controller.get_action(pos_vel[0], pos_vel[1], self.current_pos, self.current_vel) + step_action = self.tracking_controller.get_action(pos_vel[0], pos_vel[1], self.current_pos, + self.current_vel) step_action = self._step_callback(t, env_spec_params, step_action) # include possible callback info c_action = np.clip(step_action, self.env.action_space.low, self.env.action_space.high) # print('step/clipped action ratio: ', step_action/c_action) obs, c_reward, done, info = self.env.step(c_action) + rewards[t] = c_reward + if self.verbose >= 2: actions[t, :] = c_action - rewards[t] = c_reward observations[t, :] = obs - trajectory_return += c_reward + for k, v in info.items(): elems = infos.get(k, [None] * trajectory_length) elems[t] = v infos[k] = elems - # infos['step_infos'].append(info) - if self.render_mode: + + if self.render_mode is not None: self.render(mode=self.render_mode, **self.render_kwargs) - if done or do_replanning(kwargs): + + if done or self.env.do_replanning(self.env.current_pos, self.env.current_vel, obs, c_action, t): break + infos.update({k: v[:t + 1] for k, v in infos.items()}) + if self.verbose >= 2: infos['trajectory'] = trajectory infos['step_actions'] = actions[:t + 1] infos['step_observations'] = observations[:t + 1] infos['step_rewards'] = rewards[:t + 1] + infos['trajectory_length'] = t + 1 - done = True + trajectory_return = self.reward_aggregation(rewards[:t + 1]) return self.get_observation_from_step(obs), trajectory_return, done, infos def reset(self): diff --git a/alr_envs/mp/controllers/meta_world_controller.py b/alr_envs/mp/controllers/meta_world_controller.py index 07988e5..5747f9e 100644 --- a/alr_envs/mp/controllers/meta_world_controller.py +++ b/alr_envs/mp/controllers/meta_world_controller.py @@ -6,8 +6,8 @@ from alr_envs.mp.controllers.base_controller import BaseController class MetaWorldController(BaseController): """ A Metaworld Controller. Using position and velocity information from a provided environment, - the controller calculates a response based on the desired position and velocity. - Unlike the other Controllers, this is a special controller for MetaWorld environments. + the tracking_controller calculates a response based on the desired position and velocity. + Unlike the other Controllers, this is a special tracking_controller for MetaWorld environments. They use a position delta for the xyz coordinates and a raw position for the gripper opening. :param env: A position environment diff --git a/alr_envs/mp/controllers/pd_controller.py b/alr_envs/mp/controllers/pd_controller.py index d22f6b4..140aeee 100644 --- a/alr_envs/mp/controllers/pd_controller.py +++ b/alr_envs/mp/controllers/pd_controller.py @@ -6,7 +6,7 @@ from alr_envs.mp.controllers.base_controller import BaseController class PDController(BaseController): """ A PD-Controller. Using position and velocity information from a provided environment, - the controller calculates a response based on the desired position and velocity + the tracking_controller calculates a response based on the desired position and velocity :param env: A position environment :param p_gains: Factors for the proportional gains diff --git a/alr_envs/mp/controllers/pos_controller.py b/alr_envs/mp/controllers/pos_controller.py index bec3c68..5570307 100644 --- a/alr_envs/mp/controllers/pos_controller.py +++ b/alr_envs/mp/controllers/pos_controller.py @@ -3,7 +3,7 @@ from alr_envs.mp.controllers.base_controller import BaseController class PosController(BaseController): """ - A Position Controller. The controller calculates a response only based on the desired position. + A Position Controller. The tracking_controller calculates a response only based on the desired position. """ def get_action(self, des_pos, des_vel, c_pos, c_vel): return des_pos diff --git a/alr_envs/mp/controllers/vel_controller.py b/alr_envs/mp/controllers/vel_controller.py index 38128be..67bab2a 100644 --- a/alr_envs/mp/controllers/vel_controller.py +++ b/alr_envs/mp/controllers/vel_controller.py @@ -3,7 +3,7 @@ from alr_envs.mp.controllers.base_controller import BaseController class VelController(BaseController): """ - A Velocity Controller. The controller calculates a response only based on the desired velocity. + A Velocity Controller. The tracking_controller calculates a response only based on the desired velocity. """ def get_action(self, des_pos, des_vel, c_pos, c_vel): return des_vel diff --git a/alr_envs/mp/mp_factory.py b/alr_envs/mp/mp_factory.py index 5cf7231..d2c5460 100644 --- a/alr_envs/mp/mp_factory.py +++ b/alr_envs/mp/mp_factory.py @@ -7,16 +7,16 @@ from mp_pytorch.basis_gn.basis_generator import BasisGenerator ALL_TYPES = ["promp", "dmp", "idmp"] -def get_movement_primitive( - movement_primitives_type: str, action_dim: int, basis_generator: BasisGenerator, **kwargs +def get_trajectory_generator( + trajectory_generator_type: str, action_dim: int, basis_generator: BasisGenerator, **kwargs ): - movement_primitives_type = movement_primitives_type.lower() - if movement_primitives_type == "promp": + trajectory_generator_type = trajectory_generator_type.lower() + if trajectory_generator_type == "promp": return ProMP(basis_generator, action_dim, **kwargs) - elif movement_primitives_type == "dmp": + elif trajectory_generator_type == "dmp": return DMP(basis_generator, action_dim, **kwargs) - elif movement_primitives_type == 'idmp': + elif trajectory_generator_type == 'idmp': return IDMP(basis_generator, action_dim, **kwargs) else: - raise ValueError(f"Specified movement primitive type {movement_primitives_type} not supported, " + raise ValueError(f"Specified movement primitive type {trajectory_generator_type} not supported, " f"please choose one of {ALL_TYPES}.") \ No newline at end of file diff --git a/alr_envs/mp/raw_interface_wrapper.py b/alr_envs/mp/raw_interface_wrapper.py new file mode 100644 index 0000000..45d5daf --- /dev/null +++ b/alr_envs/mp/raw_interface_wrapper.py @@ -0,0 +1,88 @@ +from typing import Union, Tuple + +import gym +import numpy as np +from abc import abstractmethod + + +class RawInterfaceWrapper(gym.Wrapper): + + @property + @abstractmethod + def context_mask(self) -> np.ndarray: + """ + This function defines the contexts. The contexts are defined as specific observations. + Returns: + bool array representing the indices of the observations + + """ + return np.ones(self.env.observation_space.shape[0], dtype=bool) + + @property + @abstractmethod + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + """ + Returns the current position of the action/control dimension. + The dimensionality has to match the action/control dimension. + This is not required when exclusively using velocity control, + it should, however, be implemented regardless. + E.g. The joint positions that are directly or indirectly controlled by the action. + """ + raise NotImplementedError() + + @property + @abstractmethod + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + """ + Returns the current velocity of the action/control dimension. + The dimensionality has to match the action/control dimension. + This is not required when exclusively using position control, + it should, however, be implemented regardless. + E.g. The joint velocities that are directly or indirectly controlled by the action. + """ + raise NotImplementedError() + + @property + @abstractmethod + def dt(self) -> float: + """ + Control frequency of the environment + Returns: float + + """ + + def do_replanning(self, pos, vel, s, a, t): + # return t % 100 == 0 + # return bool(self.replanning_model(s)) + return False + + def _episode_callback(self, action: np.ndarray) -> Tuple[np.ndarray, Union[np.ndarray, None]]: + """ + Used to extract the parameters for the motion primitive and other parameters from an action array which might + include other actions like ball releasing time for the beer pong environment. + This only needs to be overwritten if the action space is modified. + Args: + action: a vector instance of the whole action space, includes trajectory_generator parameters and additional parameters if + specified, else only trajectory_generator parameters + + Returns: + Tuple: mp_arguments and other arguments + """ + return action, None + + def _step_callback(self, t: int, env_spec_params: Union[np.ndarray, None], step_action: np.ndarray) -> Union[ + np.ndarray]: + """ + This function can be used to modify the step_action with additional parameters e.g. releasing the ball in the + Beerpong env. The parameters used should not be part of the motion primitive parameters. + Returns step_action by default, can be overwritten in individual mp_wrappers. + Args: + t: the current time step of the episode + env_spec_params: the environment specific parameter, as defined in function _episode_callback + (e.g. ball release time in Beer Pong) + step_action: the current step-based action + + Returns: + modified step action + """ + return step_action diff --git a/alr_envs/open_ai/__init__.py b/alr_envs/open_ai/__init__.py index 41b770f..04610fa 100644 --- a/alr_envs/open_ai/__init__.py +++ b/alr_envs/open_ai/__init__.py @@ -21,7 +21,7 @@ register( kwargs={ "name": "alr_envs:MountainCarContinuous-v1", "wrappers": [classic_control.continuous_mountain_car.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 1, "num_basis": 4, "duration": 2, @@ -43,7 +43,7 @@ register( kwargs={ "name": "gym.envs.classic_control:MountainCarContinuous-v0", "wrappers": [classic_control.continuous_mountain_car.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 1, "num_basis": 4, "duration": 19.98, @@ -65,7 +65,7 @@ register( kwargs={ "name": "gym.envs.mujoco:Reacher-v2", "wrappers": [mujoco.reacher_v2.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 2, "num_basis": 6, "duration": 1, @@ -87,7 +87,7 @@ register( kwargs={ "name": "gym.envs.robotics:FetchSlideDense-v1", "wrappers": [FlattenObservation, robotics.fetch.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 4, "num_basis": 5, "duration": 2, @@ -105,7 +105,7 @@ register( kwargs={ "name": "gym.envs.robotics:FetchSlide-v1", "wrappers": [FlattenObservation, robotics.fetch.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 4, "num_basis": 5, "duration": 2, @@ -123,7 +123,7 @@ register( kwargs={ "name": "gym.envs.robotics:FetchReachDense-v1", "wrappers": [FlattenObservation, robotics.fetch.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 4, "num_basis": 5, "duration": 2, @@ -141,7 +141,7 @@ register( kwargs={ "name": "gym.envs.robotics:FetchReach-v1", "wrappers": [FlattenObservation, robotics.fetch.MPWrapper], - "mp_kwargs": { + "traj_gen_kwargs": { "num_dof": 4, "num_basis": 5, "duration": 2, diff --git a/alr_envs/utils/make_env_helpers.py b/alr_envs/utils/make_env_helpers.py index dbefeee..9af0a2d 100644 --- a/alr_envs/utils/make_env_helpers.py +++ b/alr_envs/utils/make_env_helpers.py @@ -4,17 +4,15 @@ from typing import Iterable, Type, Union, Mapping, MutableMapping import gym import numpy as np from gym.envs.registration import EnvSpec - -from mp_env_api.mp_wrappers.dmp_wrapper import DmpWrapper -from mp_env_api.mp_wrappers.promp_wrapper import ProMPWrapper from mp_pytorch import MPInterface from alr_envs.mp.basis_generator_factory import get_basis_generator +from alr_envs.mp.black_box_wrapper import BlackBoxWrapper from alr_envs.mp.controllers.base_controller import BaseController from alr_envs.mp.controllers.controller_factory import get_controller -from alr_envs.mp.mp_factory import get_movement_primitive -from alr_envs.mp.episodic_wrapper import EpisodicWrapper +from alr_envs.mp.mp_factory import get_trajectory_generator from alr_envs.mp.phase_generator_factory import get_phase_generator +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper def make_rank(env_id: str, seed: int, rank: int = 0, return_callable=True, **kwargs): @@ -100,9 +98,8 @@ def make(env_id: str, seed, **kwargs): def _make_wrapped_env( - env_id: str, wrappers: Iterable[Type[gym.Wrapper]], mp: MPInterface, controller: BaseController, - ep_wrapper_kwargs: Mapping, seed=1, **kwargs - ): + env_id: str, wrappers: Iterable[Type[gym.Wrapper]], seed=1, **kwargs +): """ Helper function for creating a wrapped gym environment using MPs. It adds all provided wrappers to the specified environment and verifies at least one MPEnvWrapper is @@ -118,73 +115,74 @@ def _make_wrapped_env( """ # _env = gym.make(env_id) _env = make(env_id, seed, **kwargs) - has_episodic_wrapper = False + has_black_box_wrapper = False for w in wrappers: - # only wrap the environment if not EpisodicWrapper, e.g. for vision - if not issubclass(w, EpisodicWrapper): - _env = w(_env) - else: # if EpisodicWrapper, use specific constructor - has_episodic_wrapper = True - _env = w(env=_env, mp=mp, controller=controller, **ep_wrapper_kwargs) - if not has_episodic_wrapper: - raise ValueError("An EpisodicWrapper is required in order to leverage movement primitive environments.") + # only wrap the environment if not BlackBoxWrapper, e.g. for vision + if issubclass(w, RawInterfaceWrapper): + has_black_box_wrapper = True + _env = w(_env) + if not has_black_box_wrapper: + raise ValueError("An RawInterfaceWrapper is required in order to leverage movement primitive environments.") return _env -def make_mp_from_kwargs( - env_id: str, wrappers: Iterable, ep_wrapper_kwargs: MutableMapping, mp_kwargs: MutableMapping, +def make_bb_env( + env_id: str, wrappers: Iterable, black_box_wrapper_kwargs: MutableMapping, traj_gen_kwargs: MutableMapping, controller_kwargs: MutableMapping, phase_kwargs: MutableMapping, basis_kwargs: MutableMapping, seed=1, - sequenced=False, **kwargs - ): + sequenced=False, **kwargs): """ This can also be used standalone for manually building a custom DMP environment. Args: - ep_wrapper_kwargs: - basis_kwargs: - phase_kwargs: - controller_kwargs: + black_box_wrapper_kwargs: kwargs for the black-box wrapper + basis_kwargs: kwargs for the basis generator + phase_kwargs: kwargs for the phase generator + controller_kwargs: kwargs for the tracking controller env_id: base_env_name, - wrappers: list of wrappers (at least an EpisodicWrapper), + wrappers: list of wrappers (at least an BlackBoxWrapper), seed: seed of environment sequenced: When true, this allows to sequence multiple ProMPs by specifying the duration of each sub-trajectory, this behavior is much closer to step based learning. - mp_kwargs: dict of at least {num_dof: int, num_basis: int} for DMP + traj_gen_kwargs: dict of at least {num_dof: int, num_basis: int} for DMP Returns: DMP wrapped gym env """ - _verify_time_limit(mp_kwargs.get("duration", None), kwargs.get("time_limit", None)) - dummy_env = make(env_id, seed) - if ep_wrapper_kwargs.get('duration', None) is None: - ep_wrapper_kwargs['duration'] = dummy_env.spec.max_episode_steps * dummy_env.dt + _verify_time_limit(traj_gen_kwargs.get("duration", None), kwargs.get("time_limit", None)) + _env = _make_wrapped_env(env_id=env_id, wrappers=wrappers, seed=seed, **kwargs) + + if black_box_wrapper_kwargs.get('duration', None) is None: + black_box_wrapper_kwargs['duration'] = _env.spec.max_episode_steps * _env.dt if phase_kwargs.get('tau', None) is None: - phase_kwargs['tau'] = ep_wrapper_kwargs['duration'] - mp_kwargs['action_dim'] = mp_kwargs.get('action_dim', np.prod(dummy_env.action_space.shape).item()) + phase_kwargs['tau'] = black_box_wrapper_kwargs['duration'] + traj_gen_kwargs['action_dim'] = traj_gen_kwargs.get('action_dim', np.prod(_env.action_space.shape).item()) + phase_gen = get_phase_generator(**phase_kwargs) basis_gen = get_basis_generator(phase_generator=phase_gen, **basis_kwargs) controller = get_controller(**controller_kwargs) - mp = get_movement_primitive(basis_generator=basis_gen, **mp_kwargs) - _env = _make_wrapped_env(env_id=env_id, wrappers=wrappers, mp=mp, controller=controller, - ep_wrapper_kwargs=ep_wrapper_kwargs, seed=seed, **kwargs) - return _env + traj_gen = get_trajectory_generator(basis_generator=basis_gen, **traj_gen_kwargs) + + bb_env = BlackBoxWrapper(_env, trajectory_generator=traj_gen, tracking_controller=controller, + **black_box_wrapper_kwargs) + + return bb_env -def make_mp_env_helper(**kwargs): +def make_bb_env_helper(**kwargs): """ - Helper function for registering a DMP gym environments. + Helper function for registering a black box gym environment. Args: **kwargs: expects at least the following: { "name": base environment name. - "wrappers": list of wrappers (at least an EpisodicWrapper is required), - "movement_primitives_kwargs": { - "movement_primitives_type": type_of_your_movement_primitive, + "wrappers": list of wrappers (at least an BlackBoxWrapper is required), + "traj_gen_kwargs": { + "trajectory_generator_type": type_of_your_movement_primitive, non default arguments for the movement primitive instance ... } "controller_kwargs": { "controller_type": type_of_your_controller, - non default arguments for the controller instance + non default arguments for the tracking_controller instance ... }, "basis_generator_kwargs": { @@ -205,95 +203,17 @@ def make_mp_env_helper(**kwargs): seed = kwargs.pop("seed", None) wrappers = kwargs.pop("wrappers") - mp_kwargs = kwargs.pop("movement_primitives_kwargs") - ep_wrapper_kwargs = kwargs.pop('ep_wrapper_kwargs') - contr_kwargs = kwargs.pop("controller_kwargs") - phase_kwargs = kwargs.pop("phase_generator_kwargs") - basis_kwargs = kwargs.pop("basis_generator_kwargs") + traj_gen_kwargs = kwargs.pop("traj_gen_kwargs", {}) + black_box_kwargs = kwargs.pop('black_box_wrapper_kwargs', {}) + contr_kwargs = kwargs.pop("controller_kwargs", {}) + phase_kwargs = kwargs.pop("phase_generator_kwargs", {}) + basis_kwargs = kwargs.pop("basis_generator_kwargs", {}) - return make_mp_from_kwargs(env_id=kwargs.pop("name"), wrappers=wrappers, ep_wrapper_kwargs=ep_wrapper_kwargs, - mp_kwargs=mp_kwargs, controller_kwargs=contr_kwargs, phase_kwargs=phase_kwargs, - basis_kwargs=basis_kwargs, **kwargs, seed=seed) - - -def make_dmp_env(env_id: str, wrappers: Iterable, seed=1, mp_kwargs={}, **kwargs): - """ - This can also be used standalone for manually building a custom DMP environment. - Args: - env_id: base_env_name, - wrappers: list of wrappers (at least an MPEnvWrapper), - seed: seed of environment - mp_kwargs: dict of at least {num_dof: int, num_basis: int} for DMP - - Returns: DMP wrapped gym env - - """ - _verify_time_limit(mp_kwargs.get("duration", None), kwargs.get("time_limit", None)) - - _env = _make_wrapped_env(env_id=env_id, wrappers=wrappers, seed=seed, **kwargs) - - _verify_dof(_env, mp_kwargs.get("num_dof")) - - return DmpWrapper(_env, **mp_kwargs) - - -def make_promp_env(env_id: str, wrappers: Iterable, seed=1, mp_kwargs={}, **kwargs): - """ - This can also be used standalone for manually building a custom ProMP environment. - Args: - env_id: base_env_name, - wrappers: list of wrappers (at least an MPEnvWrapper), - mp_kwargs: dict of at least {num_dof: int, num_basis: int, width: int} - - Returns: ProMP wrapped gym env - - """ - _verify_time_limit(mp_kwargs.get("duration", None), kwargs.get("time_limit", None)) - - _env = _make_wrapped_env(env_id=env_id, wrappers=wrappers, seed=seed, **kwargs) - - _verify_dof(_env, mp_kwargs.get("num_dof")) - - return ProMPWrapper(_env, **mp_kwargs) - - -def make_dmp_env_helper(**kwargs): - """ - Helper function for registering a DMP gym environments. - Args: - **kwargs: expects at least the following: - { - "name": base_env_name, - "wrappers": list of wrappers (at least an MPEnvWrapper), - "mp_kwargs": dict of at least {num_dof: int, num_basis: int} for DMP - } - - Returns: DMP wrapped gym env - - """ - seed = kwargs.pop("seed", None) - return make_dmp_env(env_id=kwargs.pop("name"), wrappers=kwargs.pop("wrappers"), seed=seed, - mp_kwargs=kwargs.pop("mp_kwargs"), **kwargs) - - -def make_promp_env_helper(**kwargs): - """ - Helper function for registering ProMP gym environments. - This can also be used standalone for manually building a custom ProMP environment. - Args: - **kwargs: expects at least the following: - { - "name": base_env_name, - "wrappers": list of wrappers (at least an MPEnvWrapper), - "mp_kwargs": dict of at least {num_dof: int, num_basis: int, width: int} - } - - Returns: ProMP wrapped gym env - - """ - seed = kwargs.pop("seed", None) - return make_promp_env(env_id=kwargs.pop("name"), wrappers=kwargs.pop("wrappers"), seed=seed, - mp_kwargs=kwargs.pop("mp_kwargs"), **kwargs) + return make_bb_env(env_id=kwargs.pop("name"), wrappers=wrappers, + black_box_wrapper_kwargs=black_box_kwargs, + traj_gen_kwargs=traj_gen_kwargs, controller_kwargs=contr_kwargs, + phase_kwargs=phase_kwargs, + basis_kwargs=basis_kwargs, **kwargs, seed=seed) def _verify_time_limit(mp_time_limit: Union[None, float], env_time_limit: Union[None, float]): @@ -304,7 +224,7 @@ def _verify_time_limit(mp_time_limit: Union[None, float], env_time_limit: Union[ It can be found in the BaseMP class. Args: - mp_time_limit: max trajectory length of mp in seconds + mp_time_limit: max trajectory length of trajectory_generator in seconds env_time_limit: max trajectory length of DMC environment in seconds Returns: From 6e06e11cfa90487f7cb2de1cda20ed7c029d3210 Mon Sep 17 00:00:00 2001 From: Onur Date: Wed, 29 Jun 2022 10:39:28 +0200 Subject: [PATCH 044/104] added new mp wrappers to all environments --- alr_envs/alr/__init__.py | 2 +- .../hole_reacher/new_mp_wrapper.py | 31 ++++++++++++++++++ .../simple_reacher/new_mp_wrapper.py | 31 ++++++++++++++++++ .../viapoint_reacher/new_mp_wrapper.py | 32 +++++++++++++++++++ .../half_cheetah_jump/new_mp_wrapper.py | 24 ++++++++++++++ .../alr/mujoco/hopper_throw/mp_wrapper.py | 2 +- .../alr/mujoco/hopper_throw/new_mp_wrapper.py | 27 ++++++++++++++++ alr_envs/alr/mujoco/reacher/new_mp_wrapper.py | 8 +++-- .../mujoco/walker_2d_jump/new_mp_wrapper.py | 28 ++++++++++++++++ 9 files changed, 180 insertions(+), 5 deletions(-) create mode 100644 alr_envs/alr/classic_control/hole_reacher/new_mp_wrapper.py create mode 100644 alr_envs/alr/classic_control/simple_reacher/new_mp_wrapper.py create mode 100644 alr_envs/alr/classic_control/viapoint_reacher/new_mp_wrapper.py create mode 100644 alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py create mode 100644 alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py create mode 100644 alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index d8169a8..4c90512 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -537,7 +537,7 @@ for _v in _versions: register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', - kwargs=kwargs_dict_bp_promp_fixed_release + kwargs=kwargs_dict_bp_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) ######################################################################################################################## diff --git a/alr_envs/alr/classic_control/hole_reacher/new_mp_wrapper.py b/alr_envs/alr/classic_control/hole_reacher/new_mp_wrapper.py new file mode 100644 index 0000000..1f1d198 --- /dev/null +++ b/alr_envs/alr/classic_control/hole_reacher/new_mp_wrapper.py @@ -0,0 +1,31 @@ +from typing import Tuple, Union + +import numpy as np + +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper + + +class NewMPWrapper(RawInterfaceWrapper): + + def get_context_mask(self): + return np.hstack([ + [self.env.random_start] * self.env.n_links, # cos + [self.env.random_start] * self.env.n_links, # sin + [self.env.random_start] * self.env.n_links, # velocity + [self.env.initial_width is None], # hole width + # [self.env.hole_depth is None], # hole depth + [True] * 2, # x-y coordinates of target distance + [False] # env steps + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.current_pos + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.current_vel + + @property + def dt(self) -> Union[float, int]: + return self.env.dt diff --git a/alr_envs/alr/classic_control/simple_reacher/new_mp_wrapper.py b/alr_envs/alr/classic_control/simple_reacher/new_mp_wrapper.py new file mode 100644 index 0000000..c1497e6 --- /dev/null +++ b/alr_envs/alr/classic_control/simple_reacher/new_mp_wrapper.py @@ -0,0 +1,31 @@ +from typing import Tuple, Union + +import numpy as np + +from mp_env_api import MPEnvWrapper + +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper + + +class MPWrapper(RawInterfaceWrapper): + + def context_mask(self): + return np.hstack([ + [self.env.random_start] * self.env.n_links, # cos + [self.env.random_start] * self.env.n_links, # sin + [self.env.random_start] * self.env.n_links, # velocity + [True] * 2, # x-y coordinates of target distance + [False] # env steps + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.current_pos + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.current_vel + + @property + def dt(self) -> Union[float, int]: + return self.env.dt diff --git a/alr_envs/alr/classic_control/viapoint_reacher/new_mp_wrapper.py b/alr_envs/alr/classic_control/viapoint_reacher/new_mp_wrapper.py new file mode 100644 index 0000000..f02dfe1 --- /dev/null +++ b/alr_envs/alr/classic_control/viapoint_reacher/new_mp_wrapper.py @@ -0,0 +1,32 @@ +from typing import Tuple, Union + +import numpy as np + +from mp_env_api import MPEnvWrapper + +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper + + +class MPWrapper(RawInterfaceWrapper): + + def context_mask(self): + return np.hstack([ + [self.env.random_start] * self.env.n_links, # cos + [self.env.random_start] * self.env.n_links, # sin + [self.env.random_start] * self.env.n_links, # velocity + [self.env.initial_via_target is None] * 2, # x-y coordinates of via point distance + [True] * 2, # x-y coordinates of target distance + [False] # env steps + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.current_pos + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.current_vel + + @property + def dt(self) -> Union[float, int]: + return self.env.dt diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py new file mode 100644 index 0000000..f098c2d --- /dev/null +++ b/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py @@ -0,0 +1,24 @@ +from typing import Tuple, Union + +import numpy as np + +from mp_env_api import MPEnvWrapper + +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper + + +class MPWrapper(RawInterfaceWrapper): + def context_mask(self): + return np.hstack([ + [False] * 17, + [True] # goal height + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray]: + return self.env.sim.data.qpos[3:9].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[3:9].copy() + diff --git a/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py b/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py index e5e9486..909e00a 100644 --- a/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py @@ -10,7 +10,7 @@ class MPWrapper(MPEnvWrapper): def active_obs(self): return np.hstack([ [False] * 17, - [True] # goal pos + [True] # goal pos ]) @property diff --git a/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py b/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py new file mode 100644 index 0000000..049c2f0 --- /dev/null +++ b/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py @@ -0,0 +1,27 @@ +from typing import Tuple, Union + +import numpy as np + +from mp_env_api import MPEnvWrapper + +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper + + +class MPWrapper(RawInterfaceWrapper): + def context_mask(self): + return np.hstack([ + [False] * 17, + [True] # goal pos + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray]: + return self.env.sim.data.qpos[3:6].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[3:6].copy() + + @property + def dt(self) -> Union[float, int]: + return self.env.dt diff --git a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py index 8df365a..54910e5 100644 --- a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py @@ -2,8 +2,10 @@ from alr_envs.mp.black_box_wrapper import BlackBoxWrapper from typing import Union, Tuple import numpy as np +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(BlackBoxWrapper): + +class MPWrapper(RawInterfaceWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: @@ -12,7 +14,7 @@ class MPWrapper(BlackBoxWrapper): def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qvel.flat[:self.env.n_links] - def get_context_mask(self): + def context_mask(self): return np.concatenate([ [False] * self.env.n_links, # cos [False] * self.env.n_links, # sin @@ -21,4 +23,4 @@ class MPWrapper(BlackBoxWrapper): [False] * 3, # goal distance # self.get_body_com("target"), # only return target to make problem harder [False], # step - ]) \ No newline at end of file + ]) diff --git a/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py new file mode 100644 index 0000000..dde928f --- /dev/null +++ b/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py @@ -0,0 +1,28 @@ +from typing import Tuple, Union + +import numpy as np + +from mp_env_api import MPEnvWrapper + +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper + + +class MPWrapper(RawInterfaceWrapper): + def context_mask(self): + return np.hstack([ + [False] * 17, + [True] # goal pos + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray]: + return self.env.sim.data.qpos[3:9].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[3:9].copy() + + @property + def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: + raise ValueError("Goal position is not available and has to be learnt based on the environment.") + From a042f9f67143b4c5c7a379dd0cb24c7dcf440f81 Mon Sep 17 00:00:00 2001 From: Onur Date: Wed, 29 Jun 2022 11:55:40 +0200 Subject: [PATCH 045/104] fix dict copy issue --- alr_envs/alr/__init__.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 4c90512..2badc2b 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -1,5 +1,6 @@ import numpy as np from gym import register +from copy import deepcopy from . import classic_control, mujoco from .classic_control.hole_reacher.hole_reacher import HoleReacherEnv @@ -364,7 +365,7 @@ for _v in _versions: ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_simple_reacher_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_simple_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) kwargs_dict_simple_reacher_promp['wrappers'].append('TODO') # TODO kwargs_dict_simple_reacher_promp['movement_primitives_kwargs']['action_dim'] = 2 if "long" not in _v.lower() else 5 kwargs_dict_simple_reacher_promp['phase_generator_kwargs']['tau'] = 2 @@ -399,7 +400,7 @@ register( ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append("ViaPointReacherDMP-v0") -kwargs_dict_via_point_reacher_promp = dict(DEFAULT_MP_ENV_DICT) +kwargs_dict_via_point_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) kwargs_dict_via_point_reacher_promp['wrappers'].append('TODO') # TODO kwargs_dict_via_point_reacher_promp['movement_primitives_kwargs']['action_dim'] = 5 kwargs_dict_via_point_reacher_promp['phase_generator_kwargs']['tau'] = 2 @@ -440,7 +441,7 @@ for _v in _versions: ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_hole_reacher_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_hole_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) kwargs_dict_hole_reacher_promp['wrappers'].append('TODO') # TODO kwargs_dict_hole_reacher_promp['ep_wrapper_kwargs']['weight_scale'] = 2 kwargs_dict_hole_reacher_promp['movement_primitives_kwargs']['action_dim'] = 5 @@ -485,7 +486,7 @@ for _v in _versions: ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_alr_reacher_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_alr_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) kwargs_dict_alr_reacher_promp['wrappers'].append('TODO') # TODO kwargs_dict_alr_reacher_promp['movement_primitives_kwargs']['action_dim'] = 5 if "long" not in _v.lower() else 7 kwargs_dict_alr_reacher_promp['phase_generator_kwargs']['tau'] = 4 @@ -505,7 +506,7 @@ _versions = ['ALRBeerPong-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_bp_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_bp_promp = deepcopy(DEFAULT_MP_ENV_DICT) kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.NewMPWrapper) kwargs_dict_bp_promp['movement_primitives_kwargs']['action_dim'] = 7 kwargs_dict_bp_promp['phase_generator_kwargs']['tau'] = 0.8 @@ -526,7 +527,7 @@ _versions = ["ALRBeerPongStepBased-v0", "ALRBeerPongFixedRelease-v0"] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_bp_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_bp_promp = deepcopy(DEFAULT_MP_ENV_DICT) kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.NewMPWrapper) kwargs_dict_bp_promp['movement_primitives_kwargs']['action_dim'] = 7 kwargs_dict_bp_promp['phase_generator_kwargs']['tau'] = 0.62 @@ -551,7 +552,7 @@ _versions = ['ALRAntJump-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_ant_jump_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_ant_jump_promp = deepcopy(DEFAULT_MP_ENV_DICT) kwargs_dict_ant_jump_promp['wrappers'].append(mujoco.ant_jump.NewMPWrapper) kwargs_dict_ant_jump_promp['movement_primitives_kwargs']['action_dim'] = 8 kwargs_dict_ant_jump_promp['phase_generator_kwargs']['tau'] = 10 @@ -572,7 +573,7 @@ _versions = ['ALRHalfCheetahJump-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_halfcheetah_jump_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_halfcheetah_jump_promp = deepcopy(DEFAULT_MP_ENV_DICT) kwargs_dict_halfcheetah_jump_promp['wrappers'].append(mujoco.ant_jump.NewMPWrapper) kwargs_dict_halfcheetah_jump_promp['movement_primitives_kwargs']['action_dim'] = 6 kwargs_dict_halfcheetah_jump_promp['phase_generator_kwargs']['tau'] = 5 @@ -596,7 +597,7 @@ _versions = ['ALRHopperJump-v0', 'ALRHopperJumpRndmJointsDesPos-v0', 'ALRHopperJ for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_hopper_jump_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_hopper_jump_promp = deepcopy(DEFAULT_MP_ENV_DICT) kwargs_dict_hopper_jump_promp['wrappers'].append('TODO') # TODO kwargs_dict_hopper_jump_promp['movement_primitives_kwargs']['action_dim'] = 3 kwargs_dict_hopper_jump_promp['phase_generator_kwargs']['tau'] = 2 @@ -618,7 +619,7 @@ _versions = ['ALRWalker2DJump-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_walker2d_jump_promp = dict(DEFAULT_MP_ENV_DICT) + kwargs_dict_walker2d_jump_promp = deepcopy(DEFAULT_MP_ENV_DICT) kwargs_dict_walker2d_jump_promp['wrappers'].append('TODO') # TODO kwargs_dict_walker2d_jump_promp['movement_primitives_kwargs']['action_dim'] = 6 kwargs_dict_walker2d_jump_promp['phase_generator_kwargs']['tau'] = 2.4 From 9b48fc9d489d14bc14d6bdaa3cac54ce94ad2bb1 Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 29 Jun 2022 12:25:40 +0200 Subject: [PATCH 046/104] todos --- alr_envs/alr/__init__.py | 10 ++++-- .../half_cheetah_jump/new_mp_wrapper.py | 2 -- alr_envs/mp/black_box_wrapper.py | 31 ++++++++++--------- alr_envs/mp/raw_interface_wrapper.py | 2 +- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 4c90512..86491b5 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -24,13 +24,17 @@ ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": []} DEFAULT_MP_ENV_DICT = { "name": 'EnvName', "wrappers": [], + # TODO move scale to traj_gen "ep_wrapper_kwargs": { "weight_scale": 1 }, + # TODO traj_gen_kwargs + # TODO remove action_dim "movement_primitives_kwargs": { 'movement_primitives_type': 'promp', 'action_dim': 7 }, + # TODO remove tau "phase_generator_kwargs": { 'phase_generator_type': 'linear', 'delay': 0, @@ -40,13 +44,13 @@ DEFAULT_MP_ENV_DICT = { }, "controller_kwargs": { 'controller_type': 'motor', - "p_gains": np.ones(7), - "d_gains": np.ones(7) * 0.1, + "p_gains": 1.0, + "d_gains": 0.1, }, "basis_generator_kwargs": { 'basis_generator_type': 'zero_rbf', 'num_basis': 5, - 'num_basis_zero_start': 2 + 'num_basis_zero_start': 2 # TODO: Change to 1 } } diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py index f098c2d..d14c9a9 100644 --- a/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py @@ -2,8 +2,6 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper - from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper diff --git a/alr_envs/mp/black_box_wrapper.py b/alr_envs/mp/black_box_wrapper.py index 5ae0ff9..d87c332 100644 --- a/alr_envs/mp/black_box_wrapper.py +++ b/alr_envs/mp/black_box_wrapper.py @@ -32,18 +32,24 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): self.env = env self.duration = duration - self.traj_steps = int(duration / self.dt) - self.post_traj_steps = self.env.spec.max_episode_steps - self.traj_steps + self.sequencing = sequencing + # self.traj_steps = int(duration / self.dt) + # self.post_traj_steps = self.env.spec.max_episode_steps - self.traj_steps # duration = self.env.max_episode_steps * self.dt # trajectory generation self.trajectory_generator = trajectory_generator self.tracking_controller = tracking_controller # self.weight_scale = weight_scale - self.time_steps = np.linspace(0, self.duration, self.traj_steps) - self.trajectory_generator.set_mp_times(self.time_steps) - # self.trajectory_generator.set_mp_duration(self.time_steps, dt) - # action_bounds = np.inf * np.ones((np.prod(self.trajectory_generator.num_params))) + # self.time_steps = np.linspace(0, self.duration, self.traj_steps) + # self.trajectory_generator.set_mp_times(self.time_steps) + if not sequencing: + self.trajectory_generator.set_mp_duration(np.array([self.duration]), np.array([self.dt])) + else: + # sequencing stuff + pass + + # reward computation self.reward_aggregation = reward_aggregation # spaces @@ -67,15 +73,12 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): return observation[self.env.context_mask] def get_trajectory(self, action: np.ndarray) -> Tuple: - # TODO: this follows the implementation of the mp_pytorch library which includes the parameters tau and delay at - # the beginning of the array. - # ignore_indices = int(self.trajectory_generator.learn_tau) + int(self.trajectory_generator.learn_delay) - # scaled_mp_params = action.copy() - # scaled_mp_params[ignore_indices:] *= self.weight_scale - clipped_params = np.clip(action, self.mp_action_space.low, self.mp_action_space.high) self.trajectory_generator.set_params(clipped_params) - self.trajectory_generator.set_boundary_conditions(bc_time=self.time_steps[:1], bc_pos=self.current_pos, + # if self.trajectory_generator.learn_tau: + # self.trajectory_generator.set_mp_duration(self.trajectory_generator.tau, np.array([self.dt])) + self.trajectory_generator.set_mp_duration(None if self.sequencing else self.duration, np.array([self.dt])) + self.trajectory_generator.set_boundary_conditions(bc_time=, bc_pos=self.current_pos, bc_vel=self.current_vel) traj_dict = self.trajectory_generator.get_mp_trajs(get_pos=True, get_vel=True) trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] @@ -152,7 +155,7 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): if self.render_mode is not None: self.render(mode=self.render_mode, **self.render_kwargs) - if done or self.env.do_replanning(self.env.current_pos, self.env.current_vel, obs, c_action, t): + if done or self.env.do_replanning(self.current_pos, self.current_vel, obs, c_action, t + past_steps): break infos.update({k: v[:t + 1] for k, v in infos.items()}) diff --git a/alr_envs/mp/raw_interface_wrapper.py b/alr_envs/mp/raw_interface_wrapper.py index 45d5daf..d57ff9a 100644 --- a/alr_envs/mp/raw_interface_wrapper.py +++ b/alr_envs/mp/raw_interface_wrapper.py @@ -43,13 +43,13 @@ class RawInterfaceWrapper(gym.Wrapper): raise NotImplementedError() @property - @abstractmethod def dt(self) -> float: """ Control frequency of the environment Returns: float """ + return self.env.dt def do_replanning(self, pos, vel, s, a, t): # return t % 100 == 0 From b200cf4b69883494bfbfb77080e90926ca24ec1e Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 29 Jun 2022 16:30:36 +0200 Subject: [PATCH 047/104] sequencing and replanning --- alr_envs/mp/black_box_wrapper.py | 84 +++++++++++--------------------- alr_envs/utils/utils.py | 5 ++ 2 files changed, 34 insertions(+), 55 deletions(-) diff --git a/alr_envs/mp/black_box_wrapper.py b/alr_envs/mp/black_box_wrapper.py index d87c332..9e6a9e5 100644 --- a/alr_envs/mp/black_box_wrapper.py +++ b/alr_envs/mp/black_box_wrapper.py @@ -8,6 +8,7 @@ from mp_pytorch.mp.mp_interfaces import MPInterface from alr_envs.mp.controllers.base_controller import BaseController from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.utils.utils import get_numpy class BlackBoxWrapper(gym.ObservationWrapper, ABC): @@ -15,7 +16,7 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): def __init__(self, env: RawInterfaceWrapper, trajectory_generator: MPInterface, tracking_controller: BaseController, - duration: float, verbose: int = 1, sequencing=True, reward_aggregation: callable = np.sum): + duration: float, verbose: int = 1, sequencing: bool = True, reward_aggregation: callable = np.sum): """ gym.Wrapper for leveraging a black box approach with a trajectory generator. @@ -33,67 +34,50 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): self.env = env self.duration = duration self.sequencing = sequencing - # self.traj_steps = int(duration / self.dt) - # self.post_traj_steps = self.env.spec.max_episode_steps - self.traj_steps - # duration = self.env.max_episode_steps * self.dt + self.current_traj_steps = 0 # trajectory generation self.trajectory_generator = trajectory_generator self.tracking_controller = tracking_controller - # self.weight_scale = weight_scale # self.time_steps = np.linspace(0, self.duration, self.traj_steps) # self.trajectory_generator.set_mp_times(self.time_steps) - if not sequencing: - self.trajectory_generator.set_mp_duration(np.array([self.duration]), np.array([self.dt])) - else: - # sequencing stuff - pass + self.trajectory_generator.set_duration(np.array([self.duration]), np.array([self.dt])) # reward computation self.reward_aggregation = reward_aggregation # spaces - self.mp_action_space = self.get_mp_action_space() + self.return_context_observation = not (self.sequencing) # TODO or we_do_replanning?) + self.traj_gen_action_space = self.get_traj_gen_action_space() self.action_space = self.get_action_space() self.observation_space = spaces.Box(low=self.env.observation_space.low[self.env.context_mask], high=self.env.observation_space.high[self.env.context_mask], dtype=self.env.observation_space.dtype) # rendering - self.render_mode = None self.render_kwargs = {} - self.verbose = verbose - @property - def dt(self): - return self.env.dt - def observation(self, observation): - return observation[self.env.context_mask] + # return context space if we are + return observation[self.context_mask] if self.return_context_observation else observation def get_trajectory(self, action: np.ndarray) -> Tuple: - clipped_params = np.clip(action, self.mp_action_space.low, self.mp_action_space.high) + clipped_params = np.clip(action, self.traj_gen_action_space.low, self.traj_gen_action_space.high) self.trajectory_generator.set_params(clipped_params) # if self.trajectory_generator.learn_tau: # self.trajectory_generator.set_mp_duration(self.trajectory_generator.tau, np.array([self.dt])) - self.trajectory_generator.set_mp_duration(None if self.sequencing else self.duration, np.array([self.dt])) - self.trajectory_generator.set_boundary_conditions(bc_time=, bc_pos=self.current_pos, + # TODO: Bruce said DMP, ProMP, ProDMP can have 0 bc_time + self.trajectory_generator.set_boundary_conditions(bc_time=np.zeros((1,)), bc_pos=self.current_pos, bc_vel=self.current_vel) - traj_dict = self.trajectory_generator.get_mp_trajs(get_pos=True, get_vel=True) + # TODO: is this correct for replanning? Do we need to adjust anything here? + self.trajectory_generator.set_duration(None if self.sequencing else self.duration, np.array([self.dt])) + traj_dict = self.trajectory_generator.get_trajs(get_pos=True, get_vel=True) trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] - trajectory = trajectory_tensor.numpy() - velocity = velocity_tensor.numpy() + return get_numpy(trajectory_tensor), get_numpy(velocity_tensor) - # TODO: Do we need this or does mp_pytorch have this? - if self.post_traj_steps > 0: - trajectory = np.vstack([trajectory, np.tile(trajectory[-1, :], [self.post_traj_steps, 1])]) - velocity = np.vstack([velocity, np.zeros(shape=(self.post_traj_steps, self.trajectory_generator.num_dof))]) - - return trajectory, velocity - - def get_mp_action_space(self): + def get_traj_gen_action_space(self): """This function can be used to set up an individual space for the parameters of the trajectory_generator.""" min_action_bounds, max_action_bounds = self.trajectory_generator.get_param_bounds() mp_action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), @@ -108,22 +92,17 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): Only needs to be overwritten if the action space needs to be modified. """ try: - return self.mp_action_space + return self.traj_gen_action_space except AttributeError: - return self.get_mp_action_space() + return self.get_traj_gen_action_space() def step(self, action: np.ndarray): """ This function generates a trajectory based on a MP and then does the usual loop over reset and step""" - # TODO: Think about sequencing - # TODO: Reward Function rather here? + # agent to learn when to release the ball mp_params, env_spec_params = self._episode_callback(action) trajectory, velocity = self.get_trajectory(mp_params) - # TODO - # self.time_steps = np.linspace(0, learned_duration, self.traj_steps) - # self.trajectory_generator.set_mp_times(self.time_steps) - trajectory_length = len(trajectory) rewards = np.zeros(shape=(trajectory_length,)) if self.verbose >= 2: @@ -152,13 +131,15 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): elems[t] = v infos[k] = elems - if self.render_mode is not None: - self.render(mode=self.render_mode, **self.render_kwargs) + if self.render_kwargs: + self.render(**self.render_kwargs) - if done or self.env.do_replanning(self.current_pos, self.current_vel, obs, c_action, t + past_steps): + if done or self.env.do_replanning(self.current_pos, self.current_vel, obs, c_action, + t + 1 + self.current_traj_steps): break infos.update({k: v[:t + 1] for k, v in infos.items()}) + self.current_traj_steps += t + 1 if self.verbose >= 2: infos['trajectory'] = trajectory @@ -168,24 +149,17 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): infos['trajectory_length'] = t + 1 trajectory_return = self.reward_aggregation(rewards[:t + 1]) - return self.get_observation_from_step(obs), trajectory_return, done, infos + return obs, trajectory_return, done, infos - def reset(self): - return self.get_observation_from_step(self.env.reset()) - - def render(self, mode='human', **kwargs): + def render(self, **kwargs): """Only set render options here, such that they can be used during the rollout. This only needs to be called once""" - self.render_mode = mode self.render_kwargs = kwargs # self.env.render(mode=self.render_mode, **self.render_kwargs) - self.env.render(mode=self.render_mode) + self.env.render(**kwargs) - def get_observation_from_step(self, observation: np.ndarray) -> np.ndarray: - return observation[self.active_obs] - - def seed(self, seed=None): - self.env.seed(seed) + def reset(self, **kwargs): + self.current_traj_steps = 0 def plot_trajs(self, des_trajs, des_vels): import matplotlib.pyplot as plt diff --git a/alr_envs/utils/utils.py b/alr_envs/utils/utils.py index 3354db3..b90cf60 100644 --- a/alr_envs/utils/utils.py +++ b/alr_envs/utils/utils.py @@ -1,4 +1,5 @@ import numpy as np +import torch as ch def angle_normalize(x, type="deg"): @@ -19,3 +20,7 @@ def angle_normalize(x, type="deg"): two_pi = 2 * np.pi return x - two_pi * np.floor((x + np.pi) / two_pi) + + +def get_numpy(x: ch.Tensor): + return x.detach().cpu().numpy() From 3273f455c538ea1c5a3cea66679ff55c9f475f90 Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 30 Jun 2022 14:08:54 +0200 Subject: [PATCH 048/104] wrappers updated --- alr_envs/__init__.py | 2 +- alr_envs/alr/__init__.py | 8 +- .../hole_reacher/mp_wrapper.py | 24 +-- .../hole_reacher/new_mp_wrapper.py | 31 ---- .../simple_reacher/mp_wrapper.py | 12 +- .../simple_reacher/new_mp_wrapper.py | 31 ---- .../viapoint_reacher/mp_wrapper.py | 6 +- .../viapoint_reacher/new_mp_wrapper.py | 2 - alr_envs/alr/mujoco/__init__.py | 11 +- alr_envs/alr/mujoco/ant_jump/mp_wrapper.py | 6 +- .../ball_in_a_cup/ball_in_a_cup_mp_wrapper.py | 6 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 6 +- .../alr/mujoco/beerpong/beerpong_reward.py | 171 ------------------ .../mujoco/beerpong/beerpong_reward_simple.py | 141 --------------- .../alr/mujoco/beerpong/beerpong_simple.py | 166 ----------------- alr_envs/alr/mujoco/beerpong/mp_wrapper.py | 6 +- .../mujoco/half_cheetah_jump/mp_wrapper.py | 6 +- .../alr/mujoco/hopper_jump/hopper_jump.py | 3 +- alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py | 6 +- .../alr/mujoco/hopper_throw/mp_wrapper.py | 6 +- .../alr/mujoco/hopper_throw/new_mp_wrapper.py | 2 - alr_envs/alr/mujoco/reacher/__init__.py | 3 +- alr_envs/alr/mujoco/reacher/mp_wrapper.py | 7 +- alr_envs/alr/mujoco/reacher/new_mp_wrapper.py | 14 +- .../alr/mujoco/table_tennis/mp_wrapper.py | 6 +- .../alr/mujoco/walker_2d_jump/mp_wrapper.py | 6 +- .../mujoco/walker_2d_jump/new_mp_wrapper.py | 2 - .../dmc/manipulation/reach_site/mp_wrapper.py | 6 +- alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py | 6 +- alr_envs/dmc/suite/cartpole/mp_wrapper.py | 7 +- alr_envs/dmc/suite/reacher/mp_wrapper.py | 6 +- alr_envs/examples/examples_dmc.py | 2 +- alr_envs/examples/examples_metaworld.py | 2 +- ...ves.py => examples_movement_primitives.py} | 29 ++- alr_envs/examples/examples_open_ai.py | 2 +- alr_envs/examples/pd_control_gain_tuning.py | 2 +- alr_envs/meta/goal_change_mp_wrapper.py | 6 +- .../goal_endeffector_change_mp_wrapper.py | 6 +- .../meta/goal_object_change_mp_wrapper.py | 6 +- alr_envs/meta/object_change_mp_wrapper.py | 6 +- alr_envs/mp/black_box_wrapper.py | 50 +++-- alr_envs/mp/raw_interface_wrapper.py | 4 +- .../continuous_mountain_car/mp_wrapper.py | 5 +- .../open_ai/mujoco/reacher_v2/mp_wrapper.py | 9 +- alr_envs/open_ai/robotics/fetch/mp_wrapper.py | 4 +- alr_envs/utils/make_env_helpers.py | 71 +++++--- alr_envs/utils/utils.py | 22 +++ 47 files changed, 219 insertions(+), 722 deletions(-) delete mode 100644 alr_envs/alr/classic_control/hole_reacher/new_mp_wrapper.py delete mode 100644 alr_envs/alr/classic_control/simple_reacher/new_mp_wrapper.py delete mode 100644 alr_envs/alr/mujoco/beerpong/beerpong_reward.py delete mode 100644 alr_envs/alr/mujoco/beerpong/beerpong_reward_simple.py delete mode 100644 alr_envs/alr/mujoco/beerpong/beerpong_simple.py rename alr_envs/examples/{examples_motion_primitives.py => examples_movement_primitives.py} (82%) diff --git a/alr_envs/__init__.py b/alr_envs/__init__.py index 858a66c..cf910b9 100644 --- a/alr_envs/__init__.py +++ b/alr_envs/__init__.py @@ -1,6 +1,6 @@ from alr_envs import dmc, meta, open_ai -from alr_envs.utils.make_env_helpers import make, make_dmp_env, make_promp_env, make_rank from alr_envs.utils import make_dmc +from alr_envs.utils.make_env_helpers import make, make_bb, make_rank # Convenience function for all MP environments from .alr import ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 7a7db6d..607ef18 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -406,8 +406,6 @@ ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append("ViaPointReacherDMP-v0") kwargs_dict_via_point_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) kwargs_dict_via_point_reacher_promp['wrappers'].append('TODO') # TODO -kwargs_dict_via_point_reacher_promp['movement_primitives_kwargs']['action_dim'] = 5 -kwargs_dict_via_point_reacher_promp['phase_generator_kwargs']['tau'] = 2 kwargs_dict_via_point_reacher_promp['controller_kwargs']['controller_type'] = 'velocity' kwargs_dict_via_point_reacher_promp['name'] = "ViaPointReacherProMP-v0" register( @@ -448,10 +446,10 @@ for _v in _versions: kwargs_dict_hole_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) kwargs_dict_hole_reacher_promp['wrappers'].append('TODO') # TODO kwargs_dict_hole_reacher_promp['ep_wrapper_kwargs']['weight_scale'] = 2 - kwargs_dict_hole_reacher_promp['movement_primitives_kwargs']['action_dim'] = 5 - kwargs_dict_hole_reacher_promp['phase_generator_kwargs']['tau'] = 2 + # kwargs_dict_hole_reacher_promp['movement_primitives_kwargs']['action_dim'] = 5 + # kwargs_dict_hole_reacher_promp['phase_generator_kwargs']['tau'] = 2 kwargs_dict_hole_reacher_promp['controller_kwargs']['controller_type'] = 'velocity' - kwargs_dict_hole_reacher_promp['basis_generator_kwargs']['num_basis'] = 5 + # kwargs_dict_hole_reacher_promp['basis_generator_kwargs']['num_basis'] = 5 kwargs_dict_hole_reacher_promp['name'] = f"alr_envs:{_v}" register( id=_env_id, diff --git a/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py index feb545f..e249a71 100644 --- a/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py +++ b/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py @@ -2,12 +2,12 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): - @property - def active_obs(self): +class MPWrapper(RawInterfaceWrapper): + + def get_context_mask(self): return np.hstack([ [self.env.random_start] * self.env.n_links, # cos [self.env.random_start] * self.env.n_links, # sin @@ -18,14 +18,6 @@ class MPWrapper(MPEnvWrapper): [False] # env steps ]) - # @property - # def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - # return self._joint_angles.copy() - # - # @property - # def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - # return self._angle_velocity.copy() - @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.current_pos @@ -33,11 +25,3 @@ class MPWrapper(MPEnvWrapper): @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.current_vel - - @property - def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: - raise ValueError("Goal position is not available and has to be learnt based on the environment.") - - @property - def dt(self) -> Union[float, int]: - return self.env.dt diff --git a/alr_envs/alr/classic_control/hole_reacher/new_mp_wrapper.py b/alr_envs/alr/classic_control/hole_reacher/new_mp_wrapper.py deleted file mode 100644 index 1f1d198..0000000 --- a/alr_envs/alr/classic_control/hole_reacher/new_mp_wrapper.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Tuple, Union - -import numpy as np - -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper - - -class NewMPWrapper(RawInterfaceWrapper): - - def get_context_mask(self): - return np.hstack([ - [self.env.random_start] * self.env.n_links, # cos - [self.env.random_start] * self.env.n_links, # sin - [self.env.random_start] * self.env.n_links, # velocity - [self.env.initial_width is None], # hole width - # [self.env.hole_depth is None], # hole depth - [True] * 2, # x-y coordinates of target distance - [False] # env steps - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.current_pos - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.current_vel - - @property - def dt(self) -> Union[float, int]: - return self.env.dt diff --git a/alr_envs/alr/classic_control/simple_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/simple_reacher/mp_wrapper.py index 4b71e3a..30b0985 100644 --- a/alr_envs/alr/classic_control/simple_reacher/mp_wrapper.py +++ b/alr_envs/alr/classic_control/simple_reacher/mp_wrapper.py @@ -2,12 +2,12 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): - @property - def active_obs(self): +class MPWrapper(RawInterfaceWrapper): + + def context_mask(self): return np.hstack([ [self.env.random_start] * self.env.n_links, # cos [self.env.random_start] * self.env.n_links, # sin @@ -24,10 +24,6 @@ class MPWrapper(MPEnvWrapper): def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.current_vel - @property - def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: - raise ValueError("Goal position is not available and has to be learnt based on the environment.") - @property def dt(self) -> Union[float, int]: return self.env.dt diff --git a/alr_envs/alr/classic_control/simple_reacher/new_mp_wrapper.py b/alr_envs/alr/classic_control/simple_reacher/new_mp_wrapper.py deleted file mode 100644 index c1497e6..0000000 --- a/alr_envs/alr/classic_control/simple_reacher/new_mp_wrapper.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Tuple, Union - -import numpy as np - -from mp_env_api import MPEnvWrapper - -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - - def context_mask(self): - return np.hstack([ - [self.env.random_start] * self.env.n_links, # cos - [self.env.random_start] * self.env.n_links, # sin - [self.env.random_start] * self.env.n_links, # velocity - [True] * 2, # x-y coordinates of target distance - [False] # env steps - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.current_pos - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.current_vel - - @property - def dt(self) -> Union[float, int]: - return self.env.dt diff --git a/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py index 6b3e85d..68d203f 100644 --- a/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py +++ b/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py @@ -2,12 +2,12 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: return np.hstack([ [self.env.random_start] * self.env.n_links, # cos [self.env.random_start] * self.env.n_links, # sin diff --git a/alr_envs/alr/classic_control/viapoint_reacher/new_mp_wrapper.py b/alr_envs/alr/classic_control/viapoint_reacher/new_mp_wrapper.py index f02dfe1..9f40292 100644 --- a/alr_envs/alr/classic_control/viapoint_reacher/new_mp_wrapper.py +++ b/alr_envs/alr/classic_control/viapoint_reacher/new_mp_wrapper.py @@ -2,8 +2,6 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper - from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index 2885321..f2f4536 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -1,13 +1,12 @@ -from .reacher.balancing import BalancingEnv +from .ant_jump.ant_jump import ALRAntJumpEnv from .ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv from .ball_in_a_cup.biac_pd import ALRBallInACupPDEnv -from .table_tennis.tt_gym import TTEnvGym -from .beerpong.beerpong import ALRBeerBongEnv, ALRBeerBongEnvStepBased, ALRBeerBongEnvStepBasedEpisodicReward, ALRBeerBongEnvFixedReleaseStep -from .ant_jump.ant_jump import ALRAntJumpEnv +from .beerpong.beerpong import ALRBeerBongEnv from .half_cheetah_jump.half_cheetah_jump import ALRHalfCheetahJumpEnv -from .hopper_jump.hopper_jump import ALRHopperJumpEnv, ALRHopperJumpRndmPosEnv, ALRHopperXYJumpEnv, ALRHopperXYJumpEnvStepBased from .hopper_jump.hopper_jump_on_box import ALRHopperJumpOnBoxEnv from .hopper_throw.hopper_throw import ALRHopperThrowEnv from .hopper_throw.hopper_throw_in_basket import ALRHopperThrowInBasketEnv +from .reacher.alr_reacher import ALRReacherEnv +from .reacher.balancing import BalancingEnv +from .table_tennis.tt_gym import TTEnvGym from .walker_2d_jump.walker_2d_jump import ALRWalker2dJumpEnv -from .reacher.alr_reacher import ALRReacherEnv \ No newline at end of file diff --git a/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py b/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py index 4967b64..4d5c0d6 100644 --- a/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py @@ -2,13 +2,13 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: return np.hstack([ [False] * 111, # ant has 111 dimensional observation space !! [True] # goal height diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_mp_wrapper.py b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_mp_wrapper.py index 945fa8d..609858b 100644 --- a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_mp_wrapper.py +++ b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_mp_wrapper.py @@ -2,13 +2,13 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class BallInACupMPWrapper(MPEnvWrapper): +class BallInACupMPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: # TODO: @Max Filter observations correctly return np.hstack([ [False] * 7, # cos diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 64d9e78..dfd6ea4 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -22,7 +22,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def __init__( self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None - ): + ): cup_goal_pos = np.array(cup_goal_pos if cup_goal_pos is not None else [-0.3, -1.2, 0.840]) if cup_goal_pos.shape[0] == 2: @@ -154,7 +154,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): success=success, is_collided=is_collided, sim_crash=crash, table_contact_first=int(not self.reward_function.ball_ground_contact_first) - ) + ) infos.update(reward_infos) return ob, reward, done, infos @@ -176,7 +176,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): cup_goal_diff_top, self.sim.model.body_pos[self.cup_table_id][:2].copy(), [self._steps], - ]) + ]) @property def dt(self): diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward.py deleted file mode 100644 index dc39ca8..0000000 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward.py +++ /dev/null @@ -1,171 +0,0 @@ -import numpy as np - - -class BeerPongReward: - def __init__(self): - - self.robot_collision_objects = ["wrist_palm_link_convex_geom", - "wrist_pitch_link_convex_decomposition_p1_geom", - "wrist_pitch_link_convex_decomposition_p2_geom", - "wrist_pitch_link_convex_decomposition_p3_geom", - "wrist_yaw_link_convex_decomposition_p1_geom", - "wrist_yaw_link_convex_decomposition_p2_geom", - "forearm_link_convex_decomposition_p1_geom", - "forearm_link_convex_decomposition_p2_geom", - "upper_arm_link_convex_decomposition_p1_geom", - "upper_arm_link_convex_decomposition_p2_geom", - "shoulder_link_convex_decomposition_p1_geom", - "shoulder_link_convex_decomposition_p2_geom", - "shoulder_link_convex_decomposition_p3_geom", - "base_link_convex_geom", "table_contact_geom"] - - self.cup_collision_objects = ["cup_geom_table3", "cup_geom_table4", "cup_geom_table5", "cup_geom_table6", - "cup_geom_table7", "cup_geom_table8", "cup_geom_table9", "cup_geom_table10", - # "cup_base_table", "cup_base_table_contact", - "cup_geom_table15", - "cup_geom_table16", - "cup_geom_table17", "cup_geom1_table8", - # "cup_base_table_contact", - # "cup_base_table" - ] - - - self.ball_traj = None - self.dists = None - self.dists_final = None - self.costs = None - self.action_costs = None - self.angle_rewards = None - self.cup_angles = None - self.cup_z_axes = None - self.collision_penalty = 500 - self.reset(None) - - def reset(self, context): - self.ball_traj = [] - self.dists = [] - self.dists_final = [] - self.costs = [] - self.action_costs = [] - self.angle_rewards = [] - self.cup_angles = [] - self.cup_z_axes = [] - self.ball_ground_contact = False - self.ball_table_contact = False - self.ball_wall_contact = False - self.ball_cup_contact = False - - def compute_reward(self, env, action): - self.ball_id = env.sim.model._body_name2id["ball"] - self.ball_collision_id = env.sim.model._geom_name2id["ball_geom"] - self.goal_id = env.sim.model._site_name2id["cup_goal_table"] - self.goal_final_id = env.sim.model._site_name2id["cup_goal_final_table"] - self.cup_collision_ids = [env.sim.model._geom_name2id[name] for name in self.cup_collision_objects] - self.cup_table_id = env.sim.model._body_name2id["cup_table"] - self.table_collision_id = env.sim.model._geom_name2id["table_contact_geom"] - self.wall_collision_id = env.sim.model._geom_name2id["wall"] - self.cup_table_collision_id = env.sim.model._geom_name2id["cup_base_table_contact"] - self.init_ball_pos_site_id = env.sim.model._site_name2id["init_ball_pos_site"] - self.ground_collision_id = env.sim.model._geom_name2id["ground"] - self.robot_collision_ids = [env.sim.model._geom_name2id[name] for name in self.robot_collision_objects] - - goal_pos = env.sim.data.site_xpos[self.goal_id] - ball_pos = env.sim.data.body_xpos[self.ball_id] - ball_vel = env.sim.data.body_xvelp[self.ball_id] - goal_final_pos = env.sim.data.site_xpos[self.goal_final_id] - self.dists.append(np.linalg.norm(goal_pos - ball_pos)) - self.dists_final.append(np.linalg.norm(goal_final_pos - ball_pos)) - - action_cost = np.sum(np.square(action)) - self.action_costs.append(action_cost) - - ball_table_bounce = self._check_collision_single_objects(env.sim, self.ball_collision_id, - self.table_collision_id) - - if ball_table_bounce: # or ball_cup_table_cont or ball_wall_con - self.ball_table_contact = True - - ball_cup_cont = self._check_collision_with_set_of_objects(env.sim, self.ball_collision_id, - self.cup_collision_ids) - if ball_cup_cont: - self.ball_cup_contact = True - - ball_wall_cont = self._check_collision_single_objects(env.sim, self.ball_collision_id, self.wall_collision_id) - if ball_wall_cont and not self.ball_table_contact: - self.ball_wall_contact = True - - ball_ground_contact = self._check_collision_single_objects(env.sim, self.ball_collision_id, - self.ground_collision_id) - if ball_ground_contact and not self.ball_table_contact: - self.ball_ground_contact = True - - self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) - if env._steps == env.ep_length - 1 or self._is_collided: - - min_dist = np.min(self.dists) - - ball_in_cup = self._check_collision_single_objects(env.sim, self.ball_collision_id, self.cup_table_collision_id) - - cost_offset = 0 - - if self.ball_ground_contact: # or self.ball_wall_contact: - cost_offset += 2 - - if not self.ball_table_contact: - cost_offset += 2 - - if not ball_in_cup: - cost_offset += 2 - cost = cost_offset + min_dist ** 2 + 0.5 * self.dists_final[-1] ** 2 + 1e-4 * action_cost # + min_dist ** 2 - else: - if self.ball_cup_contact: - cost_offset += 1 - cost = cost_offset + self.dists_final[-1] ** 2 + 1e-4 * action_cost - - reward = - 1*cost - self.collision_penalty * int(self._is_collided) - success = ball_in_cup and not self.ball_ground_contact and not self.ball_wall_contact and not self.ball_cup_contact - else: - reward = - 1e-4 * action_cost - success = False - - infos = {} - infos["success"] = success - infos["is_collided"] = self._is_collided - infos["ball_pos"] = ball_pos.copy() - infos["ball_vel"] = ball_vel.copy() - infos["action_cost"] = 5e-4 * action_cost - - return reward, infos - - def _check_collision_single_objects(self, sim, id_1, id_2): - for coni in range(0, sim.data.ncon): - con = sim.data.contact[coni] - - collision = con.geom1 == id_1 and con.geom2 == id_2 - collision_trans = con.geom1 == id_2 and con.geom2 == id_1 - - if collision or collision_trans: - return True - return False - - def _check_collision_with_itself(self, sim, collision_ids): - col_1, col_2 = False, False - for j, id in enumerate(collision_ids): - col_1 = self._check_collision_with_set_of_objects(sim, id, collision_ids[:j]) - if j != len(collision_ids) - 1: - col_2 = self._check_collision_with_set_of_objects(sim, id, collision_ids[j + 1:]) - else: - col_2 = False - collision = True if col_1 or col_2 else False - return collision - - def _check_collision_with_set_of_objects(self, sim, id_1, id_list): - for coni in range(0, sim.data.ncon): - con = sim.data.contact[coni] - - collision = con.geom1 in id_list and con.geom2 == id_1 - collision_trans = con.geom1 == id_1 and con.geom2 in id_list - - if collision or collision_trans: - return True - return False \ No newline at end of file diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_simple.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_simple.py deleted file mode 100644 index fbe2163..0000000 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_simple.py +++ /dev/null @@ -1,141 +0,0 @@ -import numpy as np -from alr_envs.alr.mujoco import alr_reward_fct - - -class BeerpongReward(alr_reward_fct.AlrReward): - def __init__(self, sim, sim_time): - - self.sim = sim - self.sim_time = sim_time - - self.collision_objects = ["cup_geom1", "cup_geom2", "wrist_palm_link_convex_geom", - "wrist_pitch_link_convex_decomposition_p1_geom", - "wrist_pitch_link_convex_decomposition_p2_geom", - "wrist_pitch_link_convex_decomposition_p3_geom", - "wrist_yaw_link_convex_decomposition_p1_geom", - "wrist_yaw_link_convex_decomposition_p2_geom", - "forearm_link_convex_decomposition_p1_geom", - "forearm_link_convex_decomposition_p2_geom"] - - self.ball_id = None - self.ball_collision_id = None - self.goal_id = None - self.goal_final_id = None - self.collision_ids = None - - self.ball_traj = None - self.dists = None - self.dists_ctxt = None - self.dists_final = None - self.costs = None - - self.reset(None) - - def reset(self, context): - self.ball_traj = np.zeros(shape=(self.sim_time, 3)) - self.dists = [] - self.dists_ctxt = [] - self.dists_final = [] - self.costs = [] - self.action_costs = [] - self.context = context - self.ball_in_cup = False - self.dist_ctxt = 5 - self.bounce_dist = 2 - self.min_dist = 2 - self.dist_final = 2 - self.table_contact = False - - self.ball_id = self.sim.model._body_name2id["ball"] - self.ball_collision_id = self.sim.model._geom_name2id["ball_geom"] - self.cup_robot_id = self.sim.model._site_name2id["cup_robot_final"] - self.goal_id = self.sim.model._site_name2id["cup_goal_table"] - self.goal_final_id = self.sim.model._site_name2id["cup_goal_final_table"] - self.collision_ids = [self.sim.model._geom_name2id[name] for name in self.collision_objects] - self.cup_table_id = self.sim.model._body_name2id["cup_table"] - self.bounce_table_id = self.sim.model._site_name2id["bounce_table"] - - def compute_reward(self, action, sim, step): - action_cost = np.sum(np.square(action)) - self.action_costs.append(action_cost) - - stop_sim = False - success = False - - if self.check_collision(sim): - reward = - 1e-2 * action_cost - 10 - stop_sim = True - return reward, success, stop_sim - - # Compute the current distance from the ball to the inner part of the cup - goal_pos = sim.data.site_xpos[self.goal_id] - ball_pos = sim.data.body_xpos[self.ball_id] - bounce_pos = sim.data.site_xpos[self.bounce_table_id] - goal_final_pos = sim.data.site_xpos[self.goal_final_id] - self.dists.append(np.linalg.norm(goal_pos - ball_pos)) - self.dists_final.append(np.linalg.norm(goal_final_pos - ball_pos)) - self.ball_traj[step, :] = ball_pos - - ball_in_cup = self.check_ball_in_cup(sim, self.ball_collision_id) - table_contact = self.check_ball_table_contact(sim, self.ball_collision_id) - - if table_contact and not self.table_contact: - self.bounce_dist = np.minimum((np.linalg.norm(bounce_pos - ball_pos)), 2) - self.table_contact = True - - if step == self.sim_time - 1: - min_dist = np.min(self.dists) - self.min_dist = min_dist - dist_final = self.dists_final[-1] - self.dist_final = dist_final - - cost = 0.33 * min_dist + 0.33 * dist_final + 0.33 * self.bounce_dist - reward = np.exp(-2 * cost) - 1e-2 * action_cost - success = self.bounce_dist < 0.05 and dist_final < 0.05 and ball_in_cup - else: - reward = - 1e-2 * action_cost - success = False - - return reward, success, stop_sim - - def _get_stage_wise_cost(self, ball_in_cup, min_dist, dist_final, dist_to_ctxt): - if not ball_in_cup: - cost = 3 + 2*(0.5 * min_dist**2 + 0.5 * dist_final**2) - else: - cost = 2 * dist_to_ctxt ** 2 - print('Context Distance:', dist_to_ctxt) - return cost - - def check_ball_table_contact(self, sim, ball_collision_id): - table_collision_id = sim.model._geom_name2id["table_contact_geom"] - for coni in range(0, sim.data.ncon): - con = sim.data.contact[coni] - collision = con.geom1 == table_collision_id and con.geom2 == ball_collision_id - collision_trans = con.geom1 == ball_collision_id and con.geom2 == table_collision_id - - if collision or collision_trans: - return True - return False - - def check_ball_in_cup(self, sim, ball_collision_id): - cup_base_collision_id = sim.model._geom_name2id["cup_base_table_contact"] - for coni in range(0, sim.data.ncon): - con = sim.data.contact[coni] - - collision = con.geom1 == cup_base_collision_id and con.geom2 == ball_collision_id - collision_trans = con.geom1 == ball_collision_id and con.geom2 == cup_base_collision_id - - if collision or collision_trans: - return True - return False - - def check_collision(self, sim): - for coni in range(0, sim.data.ncon): - con = sim.data.contact[coni] - - collision = con.geom1 in self.collision_ids and con.geom2 == self.ball_collision_id - collision_trans = con.geom1 == self.ball_collision_id and con.geom2 in self.collision_ids - - if collision or collision_trans: - return True - return False diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_simple.py b/alr_envs/alr/mujoco/beerpong/beerpong_simple.py deleted file mode 100644 index 1708d38..0000000 --- a/alr_envs/alr/mujoco/beerpong/beerpong_simple.py +++ /dev/null @@ -1,166 +0,0 @@ -from gym import utils -import os -import numpy as np -from gym.envs.mujoco import MujocoEnv - - -class ALRBeerpongEnv(MujocoEnv, utils.EzPickle): - def __init__(self, n_substeps=4, apply_gravity_comp=True, reward_function=None): - self._steps = 0 - - self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", - "beerpong" + ".xml") - - self.start_pos = np.array([0.0, 1.35, 0.0, 1.18, 0.0, -0.786, -1.59]) - self.start_vel = np.zeros(7) - - self._q_pos = [] - self._q_vel = [] - # self.weight_matrix_scale = 50 - self.max_ctrl = np.array([150., 125., 40., 60., 5., 5., 2.]) - self.p_gains = 1 / self.max_ctrl * np.array([200, 300, 100, 100, 10, 10, 2.5]) - self.d_gains = 1 / self.max_ctrl * np.array([7, 15, 5, 2.5, 0.3, 0.3, 0.05]) - - self.j_min = np.array([-2.6, -1.985, -2.8, -0.9, -4.55, -1.5707, -2.7]) - self.j_max = np.array([2.6, 1.985, 2.8, 3.14159, 1.25, 1.5707, 2.7]) - - self.context = None - - # alr_mujoco_env.AlrMujocoEnv.__init__(self, - # self.xml_path, - # apply_gravity_comp=apply_gravity_comp, - # n_substeps=n_substeps) - - self.sim_time = 8 # seconds - # self.sim_steps = int(self.sim_time / self.dt) - if reward_function is None: - from alr_envs.alr.mujoco.beerpong.beerpong_reward_simple import BeerpongReward - reward_function = BeerpongReward - self.reward_function = reward_function(self.sim, self.sim_steps) - self.cup_robot_id = self.sim.model._site_name2id["cup_robot_final"] - self.ball_id = self.sim.model._body_name2id["ball"] - self.cup_table_id = self.sim.model._body_name2id["cup_table"] - # self.bounce_table_id = self.sim.model._body_name2id["bounce_table"] - - MujocoEnv.__init__(self, model_path=self.xml_path, frame_skip=n_substeps) - utils.EzPickle.__init__(self) - - @property - def current_pos(self): - return self.sim.data.qpos[0:7].copy() - - @property - def current_vel(self): - return self.sim.data.qvel[0:7].copy() - - def configure(self, context): - if context is None: - context = np.array([0, -2, 0.840]) - self.context = context - self.reward_function.reset(context) - - def reset_model(self): - init_pos_all = self.init_qpos.copy() - init_pos_robot = self.start_pos - init_vel = np.zeros_like(init_pos_all) - - self._steps = 0 - self._q_pos = [] - self._q_vel = [] - - start_pos = init_pos_all - start_pos[0:7] = init_pos_robot - # start_pos[7:] = np.copy(self.sim.data.site_xpos[self.cup_robot_id, :]) + np.array([0., 0.0, 0.05]) - - self.set_state(start_pos, init_vel) - - ball_pos = np.copy(self.sim.data.site_xpos[self.cup_robot_id, :]) + np.array([0., 0.0, 0.05]) - self.sim.model.body_pos[self.ball_id] = ball_pos.copy() - self.sim.model.body_pos[self.cup_table_id] = self.context.copy() - # self.sim.model.body_pos[self.bounce_table_id] = self.context.copy() - - self.sim.forward() - - return self._get_obs() - - def step(self, a): - reward_dist = 0.0 - angular_vel = 0.0 - reward_ctrl = - np.square(a).sum() - action_cost = np.sum(np.square(a)) - - crash = self.do_simulation(a, self.frame_skip) - joint_cons_viol = self.check_traj_in_joint_limits() - - self._q_pos.append(self.sim.data.qpos[0:7].ravel().copy()) - self._q_vel.append(self.sim.data.qvel[0:7].ravel().copy()) - - ob = self._get_obs() - - if not crash and not joint_cons_viol: - reward, success, stop_sim = self.reward_function.compute_reward(a, self.sim, self._steps) - done = success or self._steps == self.sim_steps - 1 or stop_sim - self._steps += 1 - else: - reward = -10 - 1e-2 * action_cost - success = False - done = True - return ob, reward, done, dict(reward_dist=reward_dist, - reward_ctrl=reward_ctrl, - velocity=angular_vel, - traj=self._q_pos, is_success=success, - is_collided=crash or joint_cons_viol) - - def check_traj_in_joint_limits(self): - return any(self.current_pos > self.j_max) or any(self.current_pos < self.j_min) - - def extend_des_pos(self, des_pos): - des_pos_full = self.start_pos.copy() - des_pos_full[1] = des_pos[0] - des_pos_full[3] = des_pos[1] - des_pos_full[5] = des_pos[2] - return des_pos_full - - def extend_des_vel(self, des_vel): - des_vel_full = self.start_vel.copy() - des_vel_full[1] = des_vel[0] - des_vel_full[3] = des_vel[1] - des_vel_full[5] = des_vel[2] - return des_vel_full - - def _get_obs(self): - theta = self.sim.data.qpos.flat[:7] - return np.concatenate([ - np.cos(theta), - np.sin(theta), - # self.get_body_com("target"), # only return target to make problem harder - [self._steps], - ]) - - - -if __name__ == "__main__": - env = ALRBeerpongEnv() - ctxt = np.array([0, -2, 0.840]) # initial - - env.configure(ctxt) - env.reset() - env.render() - for i in range(16000): - # test with random actions - ac = 0.0 * env.action_space.sample()[0:7] - ac[1] = -0.01 - ac[3] = - 0.01 - ac[5] = -0.01 - # ac = env.start_pos - # ac[0] += np.pi/2 - obs, rew, d, info = env.step(ac) - env.render() - - print(rew) - - if d: - break - - env.close() - diff --git a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py index 022490c..40c371b 100644 --- a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py @@ -2,13 +2,13 @@ from typing import Tuple, Union import numpy as np -from mp_env_api.interface_wrappers.mp_env_wrapper import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: return np.hstack([ [False] * 7, # cos [False] * 7, # sin diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py b/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py index 6179b07..f9a298a 100644 --- a/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py @@ -2,12 +2,12 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: return np.hstack([ [False] * 17, [True] # goal height diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index 5cd234c..025bb8d 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -54,7 +54,8 @@ class ALRHopperJumpEnv(HopperEnv): self.current_step += 1 self.do_simulation(action, self.frame_skip) height_after = self.get_body_com("torso")[2] - site_pos_after = self.sim.data.site_xpos[self.model.site_name2id('foot_site')].copy() + # site_pos_after = self.sim.data.site_xpos[self.model.site_name2id('foot_site')].copy() + site_pos_after = self.get_body_com('foot_site') self.max_height = max(height_after, self.max_height) ctrl_cost = self.control_cost(action) diff --git a/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py b/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py index 36b7158..e3279aa 100644 --- a/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py @@ -2,12 +2,12 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: return np.hstack([ [False] * (5 + int(not self.exclude_current_positions_from_observation)), # position [False] * 6, # velocity diff --git a/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py b/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py index 909e00a..f5bf08d 100644 --- a/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py @@ -2,12 +2,12 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: return np.hstack([ [False] * 17, [True] # goal pos diff --git a/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py b/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py index 049c2f0..a8cd696 100644 --- a/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py @@ -2,8 +2,6 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper - from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper diff --git a/alr_envs/alr/mujoco/reacher/__init__.py b/alr_envs/alr/mujoco/reacher/__init__.py index 989b5a9..c1a25d3 100644 --- a/alr_envs/alr/mujoco/reacher/__init__.py +++ b/alr_envs/alr/mujoco/reacher/__init__.py @@ -1 +1,2 @@ -from .mp_wrapper import MPWrapper \ No newline at end of file +from .mp_wrapper import MPWrapper +from .new_mp_wrapper import MPWrapper as NewMPWrapper \ No newline at end of file diff --git a/alr_envs/alr/mujoco/reacher/mp_wrapper.py b/alr_envs/alr/mujoco/reacher/mp_wrapper.py index 3b655d4..e51843c 100644 --- a/alr_envs/alr/mujoco/reacher/mp_wrapper.py +++ b/alr_envs/alr/mujoco/reacher/mp_wrapper.py @@ -1,13 +1,14 @@ from typing import Union import numpy as np -from mp_env_api import MPEnvWrapper + +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: return np.concatenate([ [False] * self.n_links, # cos [False] * self.n_links, # sin diff --git a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py index 54910e5..6b50d80 100644 --- a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py @@ -8,12 +8,6 @@ from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): @property - def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qpos.flat[:self.env.n_links] - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel.flat[:self.env.n_links] - def context_mask(self): return np.concatenate([ [False] * self.env.n_links, # cos @@ -24,3 +18,11 @@ class MPWrapper(RawInterfaceWrapper): # self.get_body_com("target"), # only return target to make problem harder [False], # step ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qpos.flat[:self.env.n_links] + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel.flat[:self.env.n_links] diff --git a/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py b/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py index 473583f..408124a 100644 --- a/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py +++ b/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py @@ -2,13 +2,13 @@ from typing import Tuple, Union import numpy as np -from mp_env_api.interface_wrappers.mp_env_wrapper import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: # TODO: @Max Filter observations correctly return np.hstack([ [False] * 7, # Joint Pos diff --git a/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py b/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py index 445fa40..0c2dba5 100644 --- a/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py @@ -2,12 +2,12 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: return np.hstack([ [False] * 17, [True] # goal pos diff --git a/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py index dde928f..96b0739 100644 --- a/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py @@ -2,8 +2,6 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper - from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper diff --git a/alr_envs/dmc/manipulation/reach_site/mp_wrapper.py b/alr_envs/dmc/manipulation/reach_site/mp_wrapper.py index 2d03f7b..6d5029e 100644 --- a/alr_envs/dmc/manipulation/reach_site/mp_wrapper.py +++ b/alr_envs/dmc/manipulation/reach_site/mp_wrapper.py @@ -2,13 +2,13 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: # Joint and target positions are randomized, velocities are always set to 0. return np.hstack([ [True] * 3, # target position diff --git a/alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py b/alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py index fb068b3..9687bed 100644 --- a/alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py +++ b/alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py @@ -2,13 +2,13 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: # Besides the ball position, the environment is always set to 0. return np.hstack([ [False] * 2, # cup position diff --git a/alr_envs/dmc/suite/cartpole/mp_wrapper.py b/alr_envs/dmc/suite/cartpole/mp_wrapper.py index 1ca99f5..3f16d24 100644 --- a/alr_envs/dmc/suite/cartpole/mp_wrapper.py +++ b/alr_envs/dmc/suite/cartpole/mp_wrapper.py @@ -2,18 +2,17 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): def __init__(self, env, n_poles: int = 1): self.n_poles = n_poles super().__init__(env) - @property - def active_obs(self): + def context_mask(self) -> np.ndarray: # Besides the ball position, the environment is always set to 0. return np.hstack([ [True], # slider position diff --git a/alr_envs/dmc/suite/reacher/mp_wrapper.py b/alr_envs/dmc/suite/reacher/mp_wrapper.py index 86bc992..ac857c1 100644 --- a/alr_envs/dmc/suite/reacher/mp_wrapper.py +++ b/alr_envs/dmc/suite/reacher/mp_wrapper.py @@ -2,13 +2,13 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: # Joint and target positions are randomized, velocities are always set to 0. return np.hstack([ [True] * 2, # joint position diff --git a/alr_envs/examples/examples_dmc.py b/alr_envs/examples/examples_dmc.py index 5658b1f..41d2231 100644 --- a/alr_envs/examples/examples_dmc.py +++ b/alr_envs/examples/examples_dmc.py @@ -59,7 +59,7 @@ def example_custom_dmc_and_mp(seed=1, iterations=1, render=True): # Base DMC name, according to structure of above example base_env = "ball_in_cup-catch" - # Replace this wrapper with the custom wrapper for your environment by inheriting from the MPEnvWrapper. + # Replace this wrapper with the custom wrapper for your environment by inheriting from the RawInterfaceWrapper. # You can also add other gym.Wrappers in case they are needed. wrappers = [alr_envs.dmc.suite.ball_in_cup.MPWrapper] mp_kwargs = { diff --git a/alr_envs/examples/examples_metaworld.py b/alr_envs/examples/examples_metaworld.py index 3e040cc..f179149 100644 --- a/alr_envs/examples/examples_metaworld.py +++ b/alr_envs/examples/examples_metaworld.py @@ -62,7 +62,7 @@ def example_custom_dmc_and_mp(seed=1, iterations=1, render=True): # Base MetaWorld name, according to structure of above example base_env = "button-press-v2" - # Replace this wrapper with the custom wrapper for your environment by inheriting from the MPEnvWrapper. + # Replace this wrapper with the custom wrapper for your environment by inheriting from the RawInterfaceWrapper. # You can also add other gym.Wrappers in case they are needed. wrappers = [alr_envs.meta.goal_and_object_change.MPWrapper] mp_kwargs = { diff --git a/alr_envs/examples/examples_motion_primitives.py b/alr_envs/examples/examples_movement_primitives.py similarity index 82% rename from alr_envs/examples/examples_motion_primitives.py rename to alr_envs/examples/examples_movement_primitives.py index b9d355a..bf1f950 100644 --- a/alr_envs/examples/examples_motion_primitives.py +++ b/alr_envs/examples/examples_movement_primitives.py @@ -59,6 +59,17 @@ def example_custom_mp(env_name="alr_envs:HoleReacherDMP-v1", seed=1, iterations= """ # Changing the traj_gen_kwargs is possible by providing them to gym. # E.g. here by providing way to many basis functions + # mp_dict = alr_envs.from_default_config('ALRReacher-v0', {'basis_generator_kwargs': {'num_basis': 10}}) + # mp_dict.update({'basis_generator_kwargs': {'num_basis': 10}}) + # mp_dict.update({'black_box_kwargs': {'learn_sub_trajectories': True}}) + # mp_dict.update({'black_box_kwargs': {'do_replanning': lambda pos, vel, t: lambda t: t % 100}}) + + # default env with promp and no learn_sub_trajectories and replanning + # env = alr_envs.make('ALRReacherProMP-v0', 1, n_links=7) + env = alr_envs.make('ALRReacherProMP-v0', 1, basis_generator_kwargs={'num_basis': 10}, n_links=7) + # env = alr_envs.make('ALRReacher-v0', seed=1, bb_kwargs=mp_dict, n_links=1) + # env = alr_envs.make_bb('ALRReacher-v0', **mp_dict) + mp_kwargs = { "num_dof": 5, "num_basis": 1000, @@ -110,7 +121,7 @@ def example_fully_custom_mp(seed=1, iterations=1, render=True): base_env = "alr_envs:HoleReacher-v1" - # Replace this wrapper with the custom wrapper for your environment by inheriting from the MPEnvWrapper. + # Replace this wrapper with the custom wrapper for your environment by inheriting from the RawInterfaceWrapper. # You can also add other gym.Wrappers in case they are needed. wrappers = [alr_envs.alr.classic_control.hole_reacher.MPWrapper] mp_kwargs = { @@ -148,14 +159,14 @@ def example_fully_custom_mp(seed=1, iterations=1, render=True): if __name__ == '__main__': render = False - # DMP - example_mp("alr_envs:HoleReacherDMP-v1", seed=10, iterations=1, render=render) - - # ProMP - example_mp("alr_envs:HoleReacherProMP-v1", seed=10, iterations=1, render=render) - - # DetProMP - example_mp("alr_envs:HoleReacherDetPMP-v1", seed=10, iterations=1, render=render) + # # DMP + # example_mp("alr_envs:HoleReacherDMP-v1", seed=10, iterations=1, render=render) + # + # # ProMP + # example_mp("alr_envs:HoleReacherProMP-v1", seed=10, iterations=1, render=render) + # + # # DetProMP + # example_mp("alr_envs:HoleReacherDetPMP-v1", seed=10, iterations=1, render=render) # Altered basis functions example_custom_mp("alr_envs:HoleReacherDMP-v1", seed=10, iterations=1, render=render) diff --git a/alr_envs/examples/examples_open_ai.py b/alr_envs/examples/examples_open_ai.py index 631a3a1..46dcf60 100644 --- a/alr_envs/examples/examples_open_ai.py +++ b/alr_envs/examples/examples_open_ai.py @@ -4,7 +4,7 @@ import alr_envs def example_mp(env_name, seed=1): """ Example for running a motion primitive based version of a OpenAI-gym environment, which is already registered. - For more information on motion primitive specific stuff, look at the trajectory_generator examples. + For more information on motion primitive specific stuff, look at the traj_gen examples. Args: env_name: ProMP env_id seed: seed diff --git a/alr_envs/examples/pd_control_gain_tuning.py b/alr_envs/examples/pd_control_gain_tuning.py index e05bad1..27cf8f8 100644 --- a/alr_envs/examples/pd_control_gain_tuning.py +++ b/alr_envs/examples/pd_control_gain_tuning.py @@ -8,7 +8,7 @@ from alr_envs.utils.make_env_helpers import make_promp_env def visualize(env): t = env.t - pos_features = env.trajectory_generator.basis_generator.basis(t) + pos_features = env.traj_gen.basis_generator.basis(t) plt.plot(t, pos_features) plt.show() diff --git a/alr_envs/meta/goal_change_mp_wrapper.py b/alr_envs/meta/goal_change_mp_wrapper.py index a558365..17495da 100644 --- a/alr_envs/meta/goal_change_mp_wrapper.py +++ b/alr_envs/meta/goal_change_mp_wrapper.py @@ -2,10 +2,10 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): """ This Wrapper is for environments where merely the goal changes in the beginning and no secondary objects or end effectors are altered at the start of an episode. @@ -27,7 +27,7 @@ class MPWrapper(MPEnvWrapper): """ @property - def active_obs(self): + def context_mask(self) -> np.ndarray: # This structure is the same for all metaworld environments. # Only the observations which change could differ return np.hstack([ diff --git a/alr_envs/meta/goal_endeffector_change_mp_wrapper.py b/alr_envs/meta/goal_endeffector_change_mp_wrapper.py index 8912a72..3a6ad1c 100644 --- a/alr_envs/meta/goal_endeffector_change_mp_wrapper.py +++ b/alr_envs/meta/goal_endeffector_change_mp_wrapper.py @@ -2,10 +2,10 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): """ This Wrapper is for environments where merely the goal changes in the beginning and no secondary objects or end effectors are altered at the start of an episode. @@ -27,7 +27,7 @@ class MPWrapper(MPEnvWrapper): """ @property - def active_obs(self): + def context_mask(self) -> np.ndarray: # This structure is the same for all metaworld environments. # Only the observations which change could differ return np.hstack([ diff --git a/alr_envs/meta/goal_object_change_mp_wrapper.py b/alr_envs/meta/goal_object_change_mp_wrapper.py index 63e16b7..97c64b8 100644 --- a/alr_envs/meta/goal_object_change_mp_wrapper.py +++ b/alr_envs/meta/goal_object_change_mp_wrapper.py @@ -2,10 +2,10 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): """ This Wrapper is for environments where merely the goal changes in the beginning and no secondary objects or end effectors are altered at the start of an episode. @@ -27,7 +27,7 @@ class MPWrapper(MPEnvWrapper): """ @property - def active_obs(self): + def context_mask(self) -> np.ndarray: # This structure is the same for all metaworld environments. # Only the observations which change could differ return np.hstack([ diff --git a/alr_envs/meta/object_change_mp_wrapper.py b/alr_envs/meta/object_change_mp_wrapper.py index 4293148..f832c9f 100644 --- a/alr_envs/meta/object_change_mp_wrapper.py +++ b/alr_envs/meta/object_change_mp_wrapper.py @@ -2,10 +2,10 @@ from typing import Tuple, Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): """ This Wrapper is for environments where merely the goal changes in the beginning and no secondary objects or end effectors are altered at the start of an episode. @@ -27,7 +27,7 @@ class MPWrapper(MPEnvWrapper): """ @property - def active_obs(self): + def context_mask(self) -> np.ndarray: # This structure is the same for all metaworld environments. # Only the observations which change could differ return np.hstack([ diff --git a/alr_envs/mp/black_box_wrapper.py b/alr_envs/mp/black_box_wrapper.py index 9e6a9e5..0c2a7c8 100644 --- a/alr_envs/mp/black_box_wrapper.py +++ b/alr_envs/mp/black_box_wrapper.py @@ -1,5 +1,5 @@ from abc import ABC -from typing import Tuple +from typing import Tuple, Union import gym import numpy as np @@ -16,7 +16,9 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): def __init__(self, env: RawInterfaceWrapper, trajectory_generator: MPInterface, tracking_controller: BaseController, - duration: float, verbose: int = 1, sequencing: bool = True, reward_aggregation: callable = np.sum): + duration: float, verbose: int = 1, learn_sub_trajectories: bool = False, + replanning_schedule: Union[None, callable] = None, + reward_aggregation: callable = np.sum): """ gym.Wrapper for leveraging a black box approach with a trajectory generator. @@ -26,6 +28,9 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): tracking_controller: Translates the desired trajectory to raw action sequences duration: Length of the trajectory of the movement primitive in seconds verbose: level of detail for returned values in info dict. + learn_sub_trajectories: Transforms full episode learning into learning sub-trajectories, similar to + step-based learning + replanning_schedule: callable that receives reward_aggregation: function that takes the np.ndarray of step rewards as input and returns the trajectory reward, default summation over all values. """ @@ -33,21 +38,22 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): self.env = env self.duration = duration - self.sequencing = sequencing + self.learn_sub_trajectories = learn_sub_trajectories + self.replanning_schedule = replanning_schedule self.current_traj_steps = 0 # trajectory generation - self.trajectory_generator = trajectory_generator + self.traj_gen = trajectory_generator self.tracking_controller = tracking_controller # self.time_steps = np.linspace(0, self.duration, self.traj_steps) - # self.trajectory_generator.set_mp_times(self.time_steps) - self.trajectory_generator.set_duration(np.array([self.duration]), np.array([self.dt])) + # self.traj_gen.set_mp_times(self.time_steps) + self.traj_gen.set_duration(np.array([self.duration]), np.array([self.dt])) # reward computation self.reward_aggregation = reward_aggregation # spaces - self.return_context_observation = not (self.sequencing) # TODO or we_do_replanning?) + self.return_context_observation = not (self.learn_sub_trajectories or replanning_schedule) self.traj_gen_action_space = self.get_traj_gen_action_space() self.action_space = self.get_action_space() self.observation_space = spaces.Box(low=self.env.observation_space.low[self.env.context_mask], @@ -60,26 +66,26 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): def observation(self, observation): # return context space if we are - return observation[self.context_mask] if self.return_context_observation else observation + return observation[self.env.context_mask] if self.return_context_observation else observation def get_trajectory(self, action: np.ndarray) -> Tuple: clipped_params = np.clip(action, self.traj_gen_action_space.low, self.traj_gen_action_space.high) - self.trajectory_generator.set_params(clipped_params) - # if self.trajectory_generator.learn_tau: - # self.trajectory_generator.set_mp_duration(self.trajectory_generator.tau, np.array([self.dt])) - # TODO: Bruce said DMP, ProMP, ProDMP can have 0 bc_time - self.trajectory_generator.set_boundary_conditions(bc_time=np.zeros((1,)), bc_pos=self.current_pos, - bc_vel=self.current_vel) + self.traj_gen.set_params(clipped_params) + # TODO: Bruce said DMP, ProMP, ProDMP can have 0 bc_time for sequencing + # TODO Check with Bruce for replanning + self.traj_gen.set_boundary_conditions( + bc_time=np.zeros((1,)) if not self.replanning_schedule else self.current_traj_steps * self.dt, + bc_pos=self.current_pos, bc_vel=self.current_vel) # TODO: is this correct for replanning? Do we need to adjust anything here? - self.trajectory_generator.set_duration(None if self.sequencing else self.duration, np.array([self.dt])) - traj_dict = self.trajectory_generator.get_trajs(get_pos=True, get_vel=True) + self.traj_gen.set_duration(None if self.learn_sub_trajectories else self.duration, np.array([self.dt])) + traj_dict = self.traj_gen.get_trajs(get_pos=True, get_vel=True) trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] return get_numpy(trajectory_tensor), get_numpy(velocity_tensor) def get_traj_gen_action_space(self): - """This function can be used to set up an individual space for the parameters of the trajectory_generator.""" - min_action_bounds, max_action_bounds = self.trajectory_generator.get_param_bounds() + """This function can be used to set up an individual space for the parameters of the traj_gen.""" + min_action_bounds, max_action_bounds = self.traj_gen.get_param_bounds() mp_action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), dtype=np.float32) return mp_action_space @@ -134,8 +140,11 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): if self.render_kwargs: self.render(**self.render_kwargs) - if done or self.env.do_replanning(self.current_pos, self.current_vel, obs, c_action, - t + 1 + self.current_traj_steps): + if done: + break + + if self.replanning_schedule and self.replanning_schedule(self.current_pos, self.current_vel, obs, c_action, + t + 1 + self.current_traj_steps): break infos.update({k: v[:t + 1] for k, v in infos.items()}) @@ -160,6 +169,7 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): def reset(self, **kwargs): self.current_traj_steps = 0 + super(BlackBoxWrapper, self).reset(**kwargs) def plot_trajs(self, des_trajs, des_vels): import matplotlib.pyplot as plt diff --git a/alr_envs/mp/raw_interface_wrapper.py b/alr_envs/mp/raw_interface_wrapper.py index d57ff9a..fdbc2f7 100644 --- a/alr_envs/mp/raw_interface_wrapper.py +++ b/alr_envs/mp/raw_interface_wrapper.py @@ -62,8 +62,8 @@ class RawInterfaceWrapper(gym.Wrapper): include other actions like ball releasing time for the beer pong environment. This only needs to be overwritten if the action space is modified. Args: - action: a vector instance of the whole action space, includes trajectory_generator parameters and additional parameters if - specified, else only trajectory_generator parameters + action: a vector instance of the whole action space, includes traj_gen parameters and additional parameters if + specified, else only traj_gen parameters Returns: Tuple: mp_arguments and other arguments diff --git a/alr_envs/open_ai/classic_control/continuous_mountain_car/mp_wrapper.py b/alr_envs/open_ai/classic_control/continuous_mountain_car/mp_wrapper.py index 2a2357a..189563c 100644 --- a/alr_envs/open_ai/classic_control/continuous_mountain_car/mp_wrapper.py +++ b/alr_envs/open_ai/classic_control/continuous_mountain_car/mp_wrapper.py @@ -1,10 +1,11 @@ from typing import Union import numpy as np -from mp_env_api import MPEnvWrapper + +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property def current_vel(self) -> Union[float, int, np.ndarray]: return np.array([self.state[1]]) diff --git a/alr_envs/open_ai/mujoco/reacher_v2/mp_wrapper.py b/alr_envs/open_ai/mujoco/reacher_v2/mp_wrapper.py index 16202e5..9d627b6 100644 --- a/alr_envs/open_ai/mujoco/reacher_v2/mp_wrapper.py +++ b/alr_envs/open_ai/mujoco/reacher_v2/mp_wrapper.py @@ -1,10 +1,11 @@ from typing import Union import numpy as np -from mp_env_api import MPEnvWrapper + +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property def current_vel(self) -> Union[float, int, np.ndarray]: @@ -13,7 +14,3 @@ class MPWrapper(MPEnvWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray]: return self.sim.data.qpos[:2] - - @property - def dt(self) -> Union[float, int]: - return self.env.dt \ No newline at end of file diff --git a/alr_envs/open_ai/robotics/fetch/mp_wrapper.py b/alr_envs/open_ai/robotics/fetch/mp_wrapper.py index 218e175..7a7bed6 100644 --- a/alr_envs/open_ai/robotics/fetch/mp_wrapper.py +++ b/alr_envs/open_ai/robotics/fetch/mp_wrapper.py @@ -2,10 +2,10 @@ from typing import Union import numpy as np -from mp_env_api import MPEnvWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class MPWrapper(MPEnvWrapper): +class MPWrapper(RawInterfaceWrapper): @property def active_obs(self): diff --git a/alr_envs/utils/make_env_helpers.py b/alr_envs/utils/make_env_helpers.py index 9af0a2d..b5587a7 100644 --- a/alr_envs/utils/make_env_helpers.py +++ b/alr_envs/utils/make_env_helpers.py @@ -1,18 +1,19 @@ import warnings -from typing import Iterable, Type, Union, Mapping, MutableMapping +from copy import deepcopy +from typing import Iterable, Type, Union, MutableMapping import gym import numpy as np -from gym.envs.registration import EnvSpec -from mp_pytorch import MPInterface +from gym.envs.registration import EnvSpec, registry +from gym.wrappers import TimeAwareObservation from alr_envs.mp.basis_generator_factory import get_basis_generator from alr_envs.mp.black_box_wrapper import BlackBoxWrapper -from alr_envs.mp.controllers.base_controller import BaseController from alr_envs.mp.controllers.controller_factory import get_controller from alr_envs.mp.mp_factory import get_trajectory_generator from alr_envs.mp.phase_generator_factory import get_phase_generator from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.utils.utils import nested_update def make_rank(env_id: str, seed: int, rank: int = 0, return_callable=True, **kwargs): @@ -41,7 +42,15 @@ def make_rank(env_id: str, seed: int, rank: int = 0, return_callable=True, **kwa return f if return_callable else f() -def make(env_id: str, seed, **kwargs): +def make(env_id, seed, **kwargs): + spec = registry.get(env_id) + # This access is required to allow for nested dict updates + all_kwargs = deepcopy(spec._kwargs) + nested_update(all_kwargs, **kwargs) + return _make(env_id, seed, **all_kwargs) + + +def _make(env_id: str, seed, **kwargs): """ Converts an env_id to an environment with the gym API. This also works for DeepMind Control Suite interface_wrappers @@ -102,12 +111,12 @@ def _make_wrapped_env( ): """ Helper function for creating a wrapped gym environment using MPs. - It adds all provided wrappers to the specified environment and verifies at least one MPEnvWrapper is + It adds all provided wrappers to the specified environment and verifies at least one RawInterfaceWrapper is provided to expose the interface for MPs. Args: env_id: name of the environment - wrappers: list of wrappers (at least an MPEnvWrapper), + wrappers: list of wrappers (at least an RawInterfaceWrapper), seed: seed of environment Returns: gym environment with all specified wrappers applied @@ -126,22 +135,20 @@ def _make_wrapped_env( return _env -def make_bb_env( - env_id: str, wrappers: Iterable, black_box_wrapper_kwargs: MutableMapping, traj_gen_kwargs: MutableMapping, +def make_bb( + env_id: str, wrappers: Iterable, black_box_kwargs: MutableMapping, traj_gen_kwargs: MutableMapping, controller_kwargs: MutableMapping, phase_kwargs: MutableMapping, basis_kwargs: MutableMapping, seed=1, - sequenced=False, **kwargs): + **kwargs): """ This can also be used standalone for manually building a custom DMP environment. Args: - black_box_wrapper_kwargs: kwargs for the black-box wrapper + black_box_kwargs: kwargs for the black-box wrapper basis_kwargs: kwargs for the basis generator phase_kwargs: kwargs for the phase generator controller_kwargs: kwargs for the tracking controller env_id: base_env_name, wrappers: list of wrappers (at least an BlackBoxWrapper), seed: seed of environment - sequenced: When true, this allows to sequence multiple ProMPs by specifying the duration of each sub-trajectory, - this behavior is much closer to step based learning. traj_gen_kwargs: dict of at least {num_dof: int, num_basis: int} for DMP Returns: DMP wrapped gym env @@ -150,19 +157,33 @@ def make_bb_env( _verify_time_limit(traj_gen_kwargs.get("duration", None), kwargs.get("time_limit", None)) _env = _make_wrapped_env(env_id=env_id, wrappers=wrappers, seed=seed, **kwargs) - if black_box_wrapper_kwargs.get('duration', None) is None: - black_box_wrapper_kwargs['duration'] = _env.spec.max_episode_steps * _env.dt - if phase_kwargs.get('tau', None) is None: - phase_kwargs['tau'] = black_box_wrapper_kwargs['duration'] + learn_sub_trajs = black_box_kwargs.get('learn_sub_trajectories') + do_replanning = black_box_kwargs.get('replanning_schedule') + if learn_sub_trajs and do_replanning: + raise ValueError('Cannot used sub-trajectory learning and replanning together.') + + if learn_sub_trajs or do_replanning: + # add time_step observation when replanning + kwargs['wrappers'].append(TimeAwareObservation) + traj_gen_kwargs['action_dim'] = traj_gen_kwargs.get('action_dim', np.prod(_env.action_space.shape).item()) + if black_box_kwargs.get('duration') is None: + black_box_kwargs['duration'] = _env.spec.max_episode_steps * _env.dt + if phase_kwargs.get('tau') is None: + phase_kwargs['tau'] = black_box_kwargs['duration'] + + if learn_sub_trajs is not None: + # We have to learn the length when learning sub_trajectories trajectories + phase_kwargs['learn_tau'] = True + phase_gen = get_phase_generator(**phase_kwargs) basis_gen = get_basis_generator(phase_generator=phase_gen, **basis_kwargs) controller = get_controller(**controller_kwargs) traj_gen = get_trajectory_generator(basis_generator=basis_gen, **traj_gen_kwargs) bb_env = BlackBoxWrapper(_env, trajectory_generator=traj_gen, tracking_controller=controller, - **black_box_wrapper_kwargs) + **black_box_kwargs) return bb_env @@ -204,16 +225,16 @@ def make_bb_env_helper(**kwargs): wrappers = kwargs.pop("wrappers") traj_gen_kwargs = kwargs.pop("traj_gen_kwargs", {}) - black_box_kwargs = kwargs.pop('black_box_wrapper_kwargs', {}) + black_box_kwargs = kwargs.pop('black_box_kwargs', {}) contr_kwargs = kwargs.pop("controller_kwargs", {}) phase_kwargs = kwargs.pop("phase_generator_kwargs", {}) basis_kwargs = kwargs.pop("basis_generator_kwargs", {}) - return make_bb_env(env_id=kwargs.pop("name"), wrappers=wrappers, - black_box_wrapper_kwargs=black_box_kwargs, - traj_gen_kwargs=traj_gen_kwargs, controller_kwargs=contr_kwargs, - phase_kwargs=phase_kwargs, - basis_kwargs=basis_kwargs, **kwargs, seed=seed) + return make_bb(env_id=kwargs.pop("name"), wrappers=wrappers, + black_box_kwargs=black_box_kwargs, + traj_gen_kwargs=traj_gen_kwargs, controller_kwargs=contr_kwargs, + phase_kwargs=phase_kwargs, + basis_kwargs=basis_kwargs, **kwargs, seed=seed) def _verify_time_limit(mp_time_limit: Union[None, float], env_time_limit: Union[None, float]): @@ -224,7 +245,7 @@ def _verify_time_limit(mp_time_limit: Union[None, float], env_time_limit: Union[ It can be found in the BaseMP class. Args: - mp_time_limit: max trajectory length of trajectory_generator in seconds + mp_time_limit: max trajectory length of traj_gen in seconds env_time_limit: max trajectory length of DMC environment in seconds Returns: diff --git a/alr_envs/utils/utils.py b/alr_envs/utils/utils.py index b90cf60..b212aac 100644 --- a/alr_envs/utils/utils.py +++ b/alr_envs/utils/utils.py @@ -1,3 +1,5 @@ +from collections import Mapping, MutableMapping + import numpy as np import torch as ch @@ -23,4 +25,24 @@ def angle_normalize(x, type="deg"): def get_numpy(x: ch.Tensor): + """ + Returns numpy array from torch tensor + Args: + x: + + Returns: + + """ return x.detach().cpu().numpy() + + +def nested_update(base: MutableMapping, update): + """ + Updated method for nested Mappings + Args: + base: main Mapping to be updated + update: updated values for base Mapping + + """ + for k, v in update.items(): + base[k] = nested_update(base.get(k, {}), v) if isinstance(v, Mapping) else v From c3a8352c63f68a010b5d3b0288367574264f0fbd Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 30 Jun 2022 14:20:52 +0200 Subject: [PATCH 049/104] call on superclass for obs wrapper --- .../base_reacher/base_reacher.py | 5 +-- .../hole_reacher/mp_wrapper.py | 27 -------------- .../viapoint_reacher/mp_wrapper.py | 8 ++--- .../viapoint_reacher/new_mp_wrapper.py | 30 ---------------- alr_envs/alr/mujoco/reacher/__init__.py | 2 +- alr_envs/alr/mujoco/reacher/mp_wrapper.py | 36 ++++++------------- alr_envs/alr/mujoco/reacher/new_mp_wrapper.py | 28 --------------- alr_envs/mp/black_box_wrapper.py | 5 ++- 8 files changed, 18 insertions(+), 123 deletions(-) delete mode 100644 alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py delete mode 100644 alr_envs/alr/classic_control/viapoint_reacher/new_mp_wrapper.py delete mode 100644 alr_envs/alr/mujoco/reacher/new_mp_wrapper.py diff --git a/alr_envs/alr/classic_control/base_reacher/base_reacher.py b/alr_envs/alr/classic_control/base_reacher/base_reacher.py index 1b1ad19..e76ce85 100644 --- a/alr_envs/alr/classic_control/base_reacher/base_reacher.py +++ b/alr_envs/alr/classic_control/base_reacher/base_reacher.py @@ -1,10 +1,11 @@ -from typing import Iterable, Union from abc import ABC, abstractmethod +from typing import Union + import gym -import matplotlib.pyplot as plt import numpy as np from gym import spaces from gym.utils import seeding + from alr_envs.alr.classic_control.utils import intersect diff --git a/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py deleted file mode 100644 index e249a71..0000000 --- a/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Tuple, Union - -import numpy as np - -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - - def get_context_mask(self): - return np.hstack([ - [self.env.random_start] * self.env.n_links, # cos - [self.env.random_start] * self.env.n_links, # sin - [self.env.random_start] * self.env.n_links, # velocity - [self.env.initial_width is None], # hole width - # [self.env.hole_depth is None], # hole depth - [True] * 2, # x-y coordinates of target distance - [False] # env steps - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.current_pos - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.current_vel diff --git a/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py index 68d203f..9f40292 100644 --- a/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py +++ b/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py @@ -6,8 +6,8 @@ from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): - @property - def context_mask(self) -> np.ndarray: + + def context_mask(self): return np.hstack([ [self.env.random_start] * self.env.n_links, # cos [self.env.random_start] * self.env.n_links, # sin @@ -25,10 +25,6 @@ class MPWrapper(RawInterfaceWrapper): def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.current_vel - @property - def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: - raise ValueError("Goal position is not available and has to be learnt based on the environment.") - @property def dt(self) -> Union[float, int]: return self.env.dt diff --git a/alr_envs/alr/classic_control/viapoint_reacher/new_mp_wrapper.py b/alr_envs/alr/classic_control/viapoint_reacher/new_mp_wrapper.py deleted file mode 100644 index 9f40292..0000000 --- a/alr_envs/alr/classic_control/viapoint_reacher/new_mp_wrapper.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Tuple, Union - -import numpy as np - -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - - def context_mask(self): - return np.hstack([ - [self.env.random_start] * self.env.n_links, # cos - [self.env.random_start] * self.env.n_links, # sin - [self.env.random_start] * self.env.n_links, # velocity - [self.env.initial_via_target is None] * 2, # x-y coordinates of via point distance - [True] * 2, # x-y coordinates of target distance - [False] # env steps - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.current_pos - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.current_vel - - @property - def dt(self) -> Union[float, int]: - return self.env.dt diff --git a/alr_envs/alr/mujoco/reacher/__init__.py b/alr_envs/alr/mujoco/reacher/__init__.py index c1a25d3..6a15beb 100644 --- a/alr_envs/alr/mujoco/reacher/__init__.py +++ b/alr_envs/alr/mujoco/reacher/__init__.py @@ -1,2 +1,2 @@ from .mp_wrapper import MPWrapper -from .new_mp_wrapper import MPWrapper as NewMPWrapper \ No newline at end of file +from .mp_wrapper import MPWrapper as NewMPWrapper \ No newline at end of file diff --git a/alr_envs/alr/mujoco/reacher/mp_wrapper.py b/alr_envs/alr/mujoco/reacher/mp_wrapper.py index e51843c..966be23 100644 --- a/alr_envs/alr/mujoco/reacher/mp_wrapper.py +++ b/alr_envs/alr/mujoco/reacher/mp_wrapper.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Union, Tuple import numpy as np @@ -8,37 +8,21 @@ from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): @property - def context_mask(self) -> np.ndarray: + def context_mask(self): return np.concatenate([ - [False] * self.n_links, # cos - [False] * self.n_links, # sin + [False] * self.env.n_links, # cos + [False] * self.env.n_links, # sin [True] * 2, # goal position - [False] * self.n_links, # angular velocity + [False] * self.env.n_links, # angular velocity [False] * 3, # goal distance # self.get_body_com("target"), # only return target to make problem harder [False], # step ]) - # @property - # def active_obs(self): - # return np.concatenate([ - # [True] * self.n_links, # cos, True - # [True] * self.n_links, # sin, True - # [True] * 2, # goal position - # [True] * self.n_links, # angular velocity, True - # [True] * 3, # goal distance - # # self.get_body_com("target"), # only return target to make problem harder - # [False], # step - # ]) + @property + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qpos.flat[:self.env.n_links] @property - def current_vel(self) -> Union[float, int, np.ndarray]: - return self.sim.data.qvel.flat[:self.n_links] - - @property - def current_pos(self) -> Union[float, int, np.ndarray]: - return self.sim.data.qpos.flat[:self.n_links] - - @property - def dt(self) -> Union[float, int]: - return self.env.dt \ No newline at end of file + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel.flat[:self.env.n_links] diff --git a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py b/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py deleted file mode 100644 index 6b50d80..0000000 --- a/alr_envs/alr/mujoco/reacher/new_mp_wrapper.py +++ /dev/null @@ -1,28 +0,0 @@ -from alr_envs.mp.black_box_wrapper import BlackBoxWrapper -from typing import Union, Tuple -import numpy as np - -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - - @property - def context_mask(self): - return np.concatenate([ - [False] * self.env.n_links, # cos - [False] * self.env.n_links, # sin - [True] * 2, # goal position - [False] * self.env.n_links, # angular velocity - [False] * 3, # goal distance - # self.get_body_com("target"), # only return target to make problem harder - [False], # step - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qpos.flat[:self.env.n_links] - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel.flat[:self.env.n_links] diff --git a/alr_envs/mp/black_box_wrapper.py b/alr_envs/mp/black_box_wrapper.py index 0c2a7c8..f1ba41f 100644 --- a/alr_envs/mp/black_box_wrapper.py +++ b/alr_envs/mp/black_box_wrapper.py @@ -11,7 +11,7 @@ from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper from alr_envs.utils.utils import get_numpy -class BlackBoxWrapper(gym.ObservationWrapper, ABC): +class BlackBoxWrapper(gym.ObservationWrapper): def __init__(self, env: RawInterfaceWrapper, @@ -34,9 +34,8 @@ class BlackBoxWrapper(gym.ObservationWrapper, ABC): reward_aggregation: function that takes the np.ndarray of step rewards as input and returns the trajectory reward, default summation over all values. """ - super().__init__() + super().__init__(env) - self.env = env self.duration = duration self.learn_sub_trajectories = learn_sub_trajectories self.replanning_schedule = replanning_schedule From f31d85451f7b3c153dff9fd61096cb3c4ef81649 Mon Sep 17 00:00:00 2001 From: Onur Date: Thu, 30 Jun 2022 14:55:34 +0200 Subject: [PATCH 050/104] adjust env registries in __init__ --- alr_envs/alr/__init__.py | 68 +++++-------------- .../viapoint_reacher/__init__.py | 2 +- alr_envs/alr/mujoco/ant_jump/__init__.py | 3 +- .../alr/mujoco/ant_jump/new_mp_wrapper.py | 2 +- alr_envs/alr/mujoco/beerpong/__init__.py | 3 +- .../alr/mujoco/beerpong/new_mp_wrapper.py | 2 +- .../alr/mujoco/half_cheetah_jump/__init__.py | 2 +- alr_envs/alr/mujoco/hopper_jump/__init__.py | 3 +- .../alr/mujoco/hopper_jump/new_mp_wrapper.py | 4 +- alr_envs/alr/mujoco/reacher/__init__.py | 3 +- .../alr/mujoco/walker_2d_jump/__init__.py | 2 +- 11 files changed, 29 insertions(+), 65 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 607ef18..435cfdb 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -25,21 +25,13 @@ ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": []} DEFAULT_MP_ENV_DICT = { "name": 'EnvName', "wrappers": [], - # TODO move scale to traj_gen - "ep_wrapper_kwargs": { - "weight_scale": 1 + "traj_gen_kwargs": { + "weight_scale": 1, + 'movement_primitives_type': 'promp' }, - # TODO traj_gen_kwargs - # TODO remove action_dim - "movement_primitives_kwargs": { - 'movement_primitives_type': 'promp', - 'action_dim': 7 - }, - # TODO remove tau "phase_generator_kwargs": { 'phase_generator_type': 'linear', 'delay': 0, - 'tau': 1.5, # initial value 'learn_tau': False, 'learn_delay': False }, @@ -51,7 +43,7 @@ DEFAULT_MP_ENV_DICT = { "basis_generator_kwargs": { 'basis_generator_type': 'zero_rbf', 'num_basis': 5, - 'num_basis_zero_start': 2 # TODO: Change to 1 + 'num_basis_zero_start': 1 } } @@ -370,9 +362,7 @@ for _v in _versions: _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_simple_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) - kwargs_dict_simple_reacher_promp['wrappers'].append('TODO') # TODO - kwargs_dict_simple_reacher_promp['movement_primitives_kwargs']['action_dim'] = 2 if "long" not in _v.lower() else 5 - kwargs_dict_simple_reacher_promp['phase_generator_kwargs']['tau'] = 2 + kwargs_dict_simple_reacher_promp['wrappers'].append(classic_control.simple_reacher.MPWrapper) kwargs_dict_simple_reacher_promp['controller_kwargs']['p_gains'] = 0.6 kwargs_dict_simple_reacher_promp['controller_kwargs']['d_gains'] = 0.075 kwargs_dict_simple_reacher_promp['name'] = _env_id @@ -405,7 +395,7 @@ register( ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append("ViaPointReacherDMP-v0") kwargs_dict_via_point_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) -kwargs_dict_via_point_reacher_promp['wrappers'].append('TODO') # TODO +kwargs_dict_via_point_reacher_promp['wrappers'].append(classic_control.viapoint_reacher.MPWrapper) kwargs_dict_via_point_reacher_promp['controller_kwargs']['controller_type'] = 'velocity' kwargs_dict_via_point_reacher_promp['name'] = "ViaPointReacherProMP-v0" register( @@ -444,12 +434,9 @@ for _v in _versions: _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_hole_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) - kwargs_dict_hole_reacher_promp['wrappers'].append('TODO') # TODO - kwargs_dict_hole_reacher_promp['ep_wrapper_kwargs']['weight_scale'] = 2 - # kwargs_dict_hole_reacher_promp['movement_primitives_kwargs']['action_dim'] = 5 - # kwargs_dict_hole_reacher_promp['phase_generator_kwargs']['tau'] = 2 + kwargs_dict_hole_reacher_promp['wrappers'].append(classic_control.hole_reacher.MPWrapper) + kwargs_dict_hole_reacher_promp['traj_gen_kwargs']['weight_scale'] = 2 kwargs_dict_hole_reacher_promp['controller_kwargs']['controller_type'] = 'velocity' - # kwargs_dict_hole_reacher_promp['basis_generator_kwargs']['num_basis'] = 5 kwargs_dict_hole_reacher_promp['name'] = f"alr_envs:{_v}" register( id=_env_id, @@ -489,9 +476,7 @@ for _v in _versions: _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_alr_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) - kwargs_dict_alr_reacher_promp['wrappers'].append('TODO') # TODO - kwargs_dict_alr_reacher_promp['movement_primitives_kwargs']['action_dim'] = 5 if "long" not in _v.lower() else 7 - kwargs_dict_alr_reacher_promp['phase_generator_kwargs']['tau'] = 4 + kwargs_dict_alr_reacher_promp['wrappers'].append(mujoco.reacher.MPWrapper) kwargs_dict_alr_reacher_promp['controller_kwargs']['p_gains'] = 1 kwargs_dict_alr_reacher_promp['controller_kwargs']['d_gains'] = 0.1 kwargs_dict_alr_reacher_promp['name'] = f"alr_envs:{_v}" @@ -509,13 +494,12 @@ for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_bp_promp = deepcopy(DEFAULT_MP_ENV_DICT) - kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.NewMPWrapper) - kwargs_dict_bp_promp['movement_primitives_kwargs']['action_dim'] = 7 - kwargs_dict_bp_promp['phase_generator_kwargs']['tau'] = 0.8 + kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.MPWrapper) kwargs_dict_bp_promp['phase_generator_kwargs']['learn_tau'] = True kwargs_dict_bp_promp['controller_kwargs']['p_gains'] = np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]) kwargs_dict_bp_promp['controller_kwargs']['d_gains'] = np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis'] = 2 + kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis_zero_start'] = 2 kwargs_dict_bp_promp['name'] = f"alr_envs:{_v}" register( id=_env_id, @@ -530,12 +514,12 @@ for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_bp_promp = deepcopy(DEFAULT_MP_ENV_DICT) - kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.NewMPWrapper) - kwargs_dict_bp_promp['movement_primitives_kwargs']['action_dim'] = 7 + kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.MPWrapper) kwargs_dict_bp_promp['phase_generator_kwargs']['tau'] = 0.62 kwargs_dict_bp_promp['controller_kwargs']['p_gains'] = np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]) kwargs_dict_bp_promp['controller_kwargs']['d_gains'] = np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis'] = 2 + kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis_zero_start'] = 2 kwargs_dict_bp_promp['name'] = f"alr_envs:{_v}" register( id=_env_id, @@ -555,11 +539,7 @@ for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_ant_jump_promp = deepcopy(DEFAULT_MP_ENV_DICT) - kwargs_dict_ant_jump_promp['wrappers'].append(mujoco.ant_jump.NewMPWrapper) - kwargs_dict_ant_jump_promp['movement_primitives_kwargs']['action_dim'] = 8 - kwargs_dict_ant_jump_promp['phase_generator_kwargs']['tau'] = 10 - kwargs_dict_ant_jump_promp['controller_kwargs']['p_gains'] = np.ones(8) - kwargs_dict_ant_jump_promp['controller_kwargs']['d_gains'] = 0.1 * np.ones(8) + kwargs_dict_ant_jump_promp['wrappers'].append(mujoco.ant_jump.MPWrapper) kwargs_dict_ant_jump_promp['name'] = f"alr_envs:{_v}" register( id=_env_id, @@ -576,11 +556,7 @@ for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_halfcheetah_jump_promp = deepcopy(DEFAULT_MP_ENV_DICT) - kwargs_dict_halfcheetah_jump_promp['wrappers'].append(mujoco.ant_jump.NewMPWrapper) - kwargs_dict_halfcheetah_jump_promp['movement_primitives_kwargs']['action_dim'] = 6 - kwargs_dict_halfcheetah_jump_promp['phase_generator_kwargs']['tau'] = 5 - kwargs_dict_halfcheetah_jump_promp['controller_kwargs']['p_gains'] = np.ones(6) - kwargs_dict_halfcheetah_jump_promp['controller_kwargs']['d_gains'] = 0.1 * np.ones(6) + kwargs_dict_halfcheetah_jump_promp['wrappers'].append(mujoco.half_cheetah_jump.MPWrapper) kwargs_dict_halfcheetah_jump_promp['name'] = f"alr_envs:{_v}" register( id=_env_id, @@ -595,16 +571,12 @@ for _v in _versions: ## HopperJump _versions = ['ALRHopperJump-v0', 'ALRHopperJumpRndmJointsDesPos-v0', 'ALRHopperJumpRndmJointsDesPosStepBased-v0', 'ALRHopperJumpOnBox-v0', 'ALRHopperThrow-v0', 'ALRHopperThrowInBasket-v0'] - +# TODO: Check if all environments work with the same MPWrapper for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_hopper_jump_promp = deepcopy(DEFAULT_MP_ENV_DICT) - kwargs_dict_hopper_jump_promp['wrappers'].append('TODO') # TODO - kwargs_dict_hopper_jump_promp['movement_primitives_kwargs']['action_dim'] = 3 - kwargs_dict_hopper_jump_promp['phase_generator_kwargs']['tau'] = 2 - kwargs_dict_hopper_jump_promp['controller_kwargs']['p_gains'] = np.ones(3) - kwargs_dict_hopper_jump_promp['controller_kwargs']['d_gains'] = 0.1 * np.ones(3) + kwargs_dict_hopper_jump_promp['wrappers'].append(mujoco.hopper_jump.MPWrapper) kwargs_dict_hopper_jump_promp['name'] = f"alr_envs:{_v}" register( id=_env_id, @@ -622,11 +594,7 @@ for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_walker2d_jump_promp = deepcopy(DEFAULT_MP_ENV_DICT) - kwargs_dict_walker2d_jump_promp['wrappers'].append('TODO') # TODO - kwargs_dict_walker2d_jump_promp['movement_primitives_kwargs']['action_dim'] = 6 - kwargs_dict_walker2d_jump_promp['phase_generator_kwargs']['tau'] = 2.4 - kwargs_dict_walker2d_jump_promp['controller_kwargs']['p_gains'] = np.ones(6) - kwargs_dict_walker2d_jump_promp['controller_kwargs']['d_gains'] = 0.1 * np.ones(6) + kwargs_dict_walker2d_jump_promp['wrappers'].append(mujoco.walker_2d_jump.MPWrapper) kwargs_dict_walker2d_jump_promp['name'] = f"alr_envs:{_v}" register( id=_env_id, diff --git a/alr_envs/alr/classic_control/viapoint_reacher/__init__.py b/alr_envs/alr/classic_control/viapoint_reacher/__init__.py index 989b5a9..a919c3a 100644 --- a/alr_envs/alr/classic_control/viapoint_reacher/__init__.py +++ b/alr_envs/alr/classic_control/viapoint_reacher/__init__.py @@ -1 +1 @@ -from .mp_wrapper import MPWrapper \ No newline at end of file +from new_mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/ant_jump/__init__.py b/alr_envs/alr/mujoco/ant_jump/__init__.py index 5d15867..8a04a02 100644 --- a/alr_envs/alr/mujoco/ant_jump/__init__.py +++ b/alr_envs/alr/mujoco/ant_jump/__init__.py @@ -1,2 +1 @@ -from .mp_wrapper import MPWrapper -from .new_mp_wrapper import NewMPWrapper +from .new_mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py index c12aa56..0886065 100644 --- a/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py @@ -5,7 +5,7 @@ import numpy as np from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class NewMPWrapper(RawInterfaceWrapper): +class MPWrapper(RawInterfaceWrapper): def get_context_mask(self): return np.hstack([ diff --git a/alr_envs/alr/mujoco/beerpong/__init__.py b/alr_envs/alr/mujoco/beerpong/__init__.py index 18e33ce..8a04a02 100644 --- a/alr_envs/alr/mujoco/beerpong/__init__.py +++ b/alr_envs/alr/mujoco/beerpong/__init__.py @@ -1,2 +1 @@ -from .mp_wrapper import MPWrapper -from .new_mp_wrapper import NewMPWrapper \ No newline at end of file +from .new_mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py index 0df1a7c..2969b82 100644 --- a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py @@ -5,7 +5,7 @@ import numpy as np from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper -class NewMPWrapper(RawInterfaceWrapper): +class MPWrapper(RawInterfaceWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qpos[0:7].copy() diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/__init__.py b/alr_envs/alr/mujoco/half_cheetah_jump/__init__.py index c5e6d2f..8a04a02 100644 --- a/alr_envs/alr/mujoco/half_cheetah_jump/__init__.py +++ b/alr_envs/alr/mujoco/half_cheetah_jump/__init__.py @@ -1 +1 @@ -from .mp_wrapper import MPWrapper +from .new_mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/hopper_jump/__init__.py b/alr_envs/alr/mujoco/hopper_jump/__init__.py index fbffe48..8a04a02 100644 --- a/alr_envs/alr/mujoco/hopper_jump/__init__.py +++ b/alr_envs/alr/mujoco/hopper_jump/__init__.py @@ -1,2 +1 @@ -from .mp_wrapper import MPWrapper, HighCtxtMPWrapper -from .new_mp_wrapper import NewMPWrapper, NewHighCtxtMPWrapper +from .new_mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py index ccd8f76..b919b22 100644 --- a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py @@ -3,7 +3,7 @@ from typing import Union, Tuple import numpy as np -class NewMPWrapper(BlackBoxWrapper): +class MPWrapper(BlackBoxWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qpos[3:6].copy() @@ -30,7 +30,7 @@ class NewMPWrapper(BlackBoxWrapper): ]) -class NewHighCtxtMPWrapper(NewMPWrapper): +class NewHighCtxtMPWrapper(MPWrapper): def get_context_mask(self): return np.hstack([ [False] * (2 + int(not self.env.exclude_current_positions_from_observation)), # position diff --git a/alr_envs/alr/mujoco/reacher/__init__.py b/alr_envs/alr/mujoco/reacher/__init__.py index c1a25d3..8a04a02 100644 --- a/alr_envs/alr/mujoco/reacher/__init__.py +++ b/alr_envs/alr/mujoco/reacher/__init__.py @@ -1,2 +1 @@ -from .mp_wrapper import MPWrapper -from .new_mp_wrapper import MPWrapper as NewMPWrapper \ No newline at end of file +from .new_mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/walker_2d_jump/__init__.py b/alr_envs/alr/mujoco/walker_2d_jump/__init__.py index 989b5a9..8a04a02 100644 --- a/alr_envs/alr/mujoco/walker_2d_jump/__init__.py +++ b/alr_envs/alr/mujoco/walker_2d_jump/__init__.py @@ -1 +1 @@ -from .mp_wrapper import MPWrapper \ No newline at end of file +from .new_mp_wrapper import MPWrapper From fea2ae7d11548654e505f8e28a8d3b0748adcc83 Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 30 Jun 2022 17:33:05 +0200 Subject: [PATCH 051/104] current state --- alr_envs/alr/__init__.py | 190 +++++------------- .../hole_reacher/mp_wrapper.py | 27 +++ .../simple_reacher/mp_wrapper.py | 2 +- .../viapoint_reacher/mp_wrapper.py | 2 +- alr_envs/alr/mujoco/__init__.py | 2 +- alr_envs/alr/mujoco/ant_jump/mp_wrapper.py | 2 +- .../alr/mujoco/ant_jump/new_mp_wrapper.py | 4 +- .../ball_in_a_cup/ball_in_a_cup_mp_wrapper.py | 2 +- alr_envs/alr/mujoco/beerpong/mp_wrapper.py | 2 +- .../alr/mujoco/beerpong/new_mp_wrapper.py | 2 +- .../mujoco/half_cheetah_jump/mp_wrapper.py | 2 +- .../half_cheetah_jump/new_mp_wrapper.py | 2 +- alr_envs/alr/mujoco/hopper_jump/__init__.py | 2 +- .../alr/mujoco/hopper_jump/hopper_jump.py | 147 +++++++------- alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py | 52 +---- .../alr/mujoco/hopper_jump/new_mp_wrapper.py | 45 ----- .../alr/mujoco/hopper_throw/hopper_throw.py | 2 +- .../alr/mujoco/hopper_throw/mp_wrapper.py | 2 +- .../alr/mujoco/hopper_throw/new_mp_wrapper.py | 2 +- alr_envs/alr/mujoco/reacher/alr_reacher.py | 152 -------------- alr_envs/alr/mujoco/reacher/balancing.py | 53 ----- alr_envs/alr/mujoco/reacher/mp_wrapper.py | 2 +- alr_envs/alr/mujoco/reacher/reacher.py | 105 ++++++++++ .../alr/mujoco/table_tennis/mp_wrapper.py | 2 +- .../alr/mujoco/walker_2d_jump/mp_wrapper.py | 2 +- .../mujoco/walker_2d_jump/new_mp_wrapper.py | 2 +- alr_envs/{mp => black_box}/__init__.py | 0 .../{mp => black_box}/black_box_wrapper.py | 14 +- .../controller}/__init__.py | 0 .../controller}/base_controller.py | 0 .../controller}/controller_factory.py | 8 +- .../controller}/meta_world_controller.py | 2 +- .../controller}/pd_controller.py | 2 +- .../controller}/pos_controller.py | 2 +- .../controller}/vel_controller.py | 2 +- alr_envs/black_box/factory/__init__.py | 0 .../factory}/basis_generator_factory.py | 0 .../factory}/phase_generator_factory.py | 2 +- .../factory/trajectory_generator_factory.py} | 4 +- .../raw_interface_wrapper.py | 0 .../dmc/manipulation/reach_site/mp_wrapper.py | 2 +- alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py | 2 +- alr_envs/dmc/suite/cartpole/mp_wrapper.py | 2 +- alr_envs/dmc/suite/reacher/mp_wrapper.py | 2 +- alr_envs/meta/goal_change_mp_wrapper.py | 2 +- .../goal_endeffector_change_mp_wrapper.py | 2 +- .../meta/goal_object_change_mp_wrapper.py | 2 +- alr_envs/meta/object_change_mp_wrapper.py | 2 +- .../continuous_mountain_car/mp_wrapper.py | 2 +- .../open_ai/mujoco/reacher_v2/mp_wrapper.py | 2 +- alr_envs/open_ai/robotics/fetch/mp_wrapper.py | 2 +- alr_envs/utils/make_env_helpers.py | 15 +- 52 files changed, 325 insertions(+), 557 deletions(-) create mode 100644 alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py delete mode 100644 alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py delete mode 100644 alr_envs/alr/mujoco/reacher/alr_reacher.py delete mode 100644 alr_envs/alr/mujoco/reacher/balancing.py create mode 100644 alr_envs/alr/mujoco/reacher/reacher.py rename alr_envs/{mp => black_box}/__init__.py (100%) rename alr_envs/{mp => black_box}/black_box_wrapper.py (94%) rename alr_envs/{mp/controllers => black_box/controller}/__init__.py (100%) rename alr_envs/{mp/controllers => black_box/controller}/base_controller.py (100%) rename alr_envs/{mp/controllers => black_box/controller}/controller_factory.py (60%) rename alr_envs/{mp/controllers => black_box/controller}/meta_world_controller.py (92%) rename alr_envs/{mp/controllers => black_box/controller}/pd_controller.py (93%) rename alr_envs/{mp/controllers => black_box/controller}/pos_controller.py (77%) rename alr_envs/{mp/controllers => black_box/controller}/vel_controller.py (77%) create mode 100644 alr_envs/black_box/factory/__init__.py rename alr_envs/{mp => black_box/factory}/basis_generator_factory.py (100%) rename alr_envs/{mp => black_box/factory}/phase_generator_factory.py (93%) rename alr_envs/{mp/mp_factory.py => black_box/factory/trajectory_generator_factory.py} (91%) rename alr_envs/{mp => black_box}/raw_interface_wrapper.py (100%) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 435cfdb..cf009a4 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -1,33 +1,31 @@ -import numpy as np -from gym import register from copy import deepcopy +import numpy as np +from gym import register + +from alr_envs.alr.mujoco.table_tennis.tt_gym import MAX_EPISODE_STEPS from . import classic_control, mujoco from .classic_control.hole_reacher.hole_reacher import HoleReacherEnv from .classic_control.simple_reacher.simple_reacher import SimpleReacherEnv from .classic_control.viapoint_reacher.viapoint_reacher import ViaPointReacherEnv +from .mujoco.ant_jump.ant_jump import MAX_EPISODE_STEPS_ANTJUMP from .mujoco.ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv from .mujoco.ball_in_a_cup.biac_pd import ALRBallInACupPDEnv -from .mujoco.reacher.alr_reacher import ALRReacherEnv -from .mujoco.reacher.balancing import BalancingEnv - -from alr_envs.alr.mujoco.table_tennis.tt_gym import MAX_EPISODE_STEPS -from .mujoco.ant_jump.ant_jump import MAX_EPISODE_STEPS_ANTJUMP from .mujoco.half_cheetah_jump.half_cheetah_jump import MAX_EPISODE_STEPS_HALFCHEETAHJUMP from .mujoco.hopper_jump.hopper_jump import MAX_EPISODE_STEPS_HOPPERJUMP from .mujoco.hopper_jump.hopper_jump_on_box import MAX_EPISODE_STEPS_HOPPERJUMPONBOX from .mujoco.hopper_throw.hopper_throw import MAX_EPISODE_STEPS_HOPPERTHROW from .mujoco.hopper_throw.hopper_throw_in_basket import MAX_EPISODE_STEPS_HOPPERTHROWINBASKET +from .mujoco.reacher.reacher import ReacherEnv from .mujoco.walker_2d_jump.walker_2d_jump import MAX_EPISODE_STEPS_WALKERJUMP ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": []} -DEFAULT_MP_ENV_DICT = { +DEFAULT_BB_DICT = { "name": 'EnvName', "wrappers": [], "traj_gen_kwargs": { - "weight_scale": 1, - 'movement_primitives_type': 'promp' + 'trajectory_generator_type': 'promp' }, "phase_generator_kwargs": { 'phase_generator_type': 'linear', @@ -100,80 +98,47 @@ register( # Mujoco ## Reacher +for _dims in [5, 7]: + register( + id=f'Reacher{_dims}d-v0', + entry_point='alr_envs.alr.mujoco:ReacherEnv', + max_episode_steps=200, + kwargs={ + "n_links": _dims, + } + ) + + register( + id=f'Reacher{_dims}dSparse-v0', + entry_point='alr_envs.alr.mujoco:ReacherEnv', + max_episode_steps=200, + kwargs={ + "sparse": True, + "n_links": _dims, + } + ) + +## Hopper Jump random joints and desired position register( - id='ALRReacher-v0', - entry_point='alr_envs.alr.mujoco:ALRReacherEnv', - max_episode_steps=200, + id='HopperJumpSparse-v0', + entry_point='alr_envs.alr.mujoco:ALRHopperXYJumpEnv', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ - "steps_before_reward": 0, - "n_links": 5, - "balance": False, + # "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, + "sparse": True, + # "healthy_reward": 1.0 } ) +## Hopper Jump random joints and desired position step based reward register( - id='ALRReacherSparse-v0', - entry_point='alr_envs.alr.mujoco:ALRReacherEnv', - max_episode_steps=200, + id='HopperJump-v0', + entry_point='alr_envs.alr.mujoco:ALRHopperXYJumpEnvStepBased', + max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ - "steps_before_reward": 200, - "n_links": 5, - "balance": False, - } -) - -register( - id='ALRReacherSparseOptCtrl-v0', - entry_point='alr_envs.alr.mujoco:ALRReacherOptCtrlEnv', - max_episode_steps=200, - kwargs={ - "steps_before_reward": 200, - "n_links": 5, - "balance": False, - } -) - -register( - id='ALRReacherSparseBalanced-v0', - entry_point='alr_envs.alr.mujoco:ALRReacherEnv', - max_episode_steps=200, - kwargs={ - "steps_before_reward": 200, - "n_links": 5, - "balance": True, - } -) - -register( - id='ALRLongReacher-v0', - entry_point='alr_envs.alr.mujoco:ALRReacherEnv', - max_episode_steps=200, - kwargs={ - "steps_before_reward": 0, - "n_links": 7, - "balance": False, - } -) - -register( - id='ALRLongReacherSparse-v0', - entry_point='alr_envs.alr.mujoco:ALRReacherEnv', - max_episode_steps=200, - kwargs={ - "steps_before_reward": 200, - "n_links": 7, - "balance": False, - } -) - -register( - id='ALRLongReacherSparseBalanced-v0', - entry_point='alr_envs.alr.mujoco:ALRReacherEnv', - max_episode_steps=200, - kwargs={ - "steps_before_reward": 200, - "n_links": 7, - "balance": True, + # "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, + "sparse": False, + # "healthy_reward": 1.0 } ) @@ -198,41 +163,7 @@ register( ) register( - id='ALRHopperJump-v0', - entry_point='alr_envs.alr.mujoco:ALRHopperJumpEnv', - max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, - kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, - "context": True - } -) - -#### Hopper Jump random joints and des position -register( - id='ALRHopperJumpRndmJointsDesPos-v0', - entry_point='alr_envs.alr.mujoco:ALRHopperXYJumpEnv', - max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, - kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, - "context": True, - "healthy_reward": 1.0 - } -) - -##### Hopper Jump random joints and des position step based reward -register( - id='ALRHopperJumpRndmJointsDesPosStepBased-v0', - entry_point='alr_envs.alr.mujoco:ALRHopperXYJumpEnvStepBased', - max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, - kwargs={ - "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, - "context": True, - "healthy_reward": 1.0 - } -) - -register( - id='ALRHopperJumpOnBox-v0', + id='HopperJumpOnBox-v0', entry_point='alr_envs.alr.mujoco:ALRHopperJumpOnBoxEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMPONBOX, kwargs={ @@ -271,17 +202,6 @@ register( } ) -## Balancing Reacher - -register( - id='Balancing-v0', - entry_point='alr_envs.alr.mujoco:BalancingEnv', - max_episode_steps=200, - kwargs={ - "n_links": 5, - } -) - ## Table Tennis register(id='TableTennis2DCtxt-v0', entry_point='alr_envs.alr.mujoco:TTEnvGym', @@ -361,7 +281,7 @@ for _v in _versions: ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_simple_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) + kwargs_dict_simple_reacher_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_simple_reacher_promp['wrappers'].append(classic_control.simple_reacher.MPWrapper) kwargs_dict_simple_reacher_promp['controller_kwargs']['p_gains'] = 0.6 kwargs_dict_simple_reacher_promp['controller_kwargs']['d_gains'] = 0.075 @@ -394,7 +314,7 @@ register( ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append("ViaPointReacherDMP-v0") -kwargs_dict_via_point_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) +kwargs_dict_via_point_reacher_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_via_point_reacher_promp['wrappers'].append(classic_control.viapoint_reacher.MPWrapper) kwargs_dict_via_point_reacher_promp['controller_kwargs']['controller_type'] = 'velocity' kwargs_dict_via_point_reacher_promp['name'] = "ViaPointReacherProMP-v0" @@ -433,7 +353,7 @@ for _v in _versions: ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_hole_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) + kwargs_dict_hole_reacher_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_hole_reacher_promp['wrappers'].append(classic_control.hole_reacher.MPWrapper) kwargs_dict_hole_reacher_promp['traj_gen_kwargs']['weight_scale'] = 2 kwargs_dict_hole_reacher_promp['controller_kwargs']['controller_type'] = 'velocity' @@ -475,7 +395,7 @@ for _v in _versions: ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_alr_reacher_promp = deepcopy(DEFAULT_MP_ENV_DICT) + kwargs_dict_alr_reacher_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_alr_reacher_promp['wrappers'].append(mujoco.reacher.MPWrapper) kwargs_dict_alr_reacher_promp['controller_kwargs']['p_gains'] = 1 kwargs_dict_alr_reacher_promp['controller_kwargs']['d_gains'] = 0.1 @@ -493,7 +413,7 @@ _versions = ['ALRBeerPong-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_bp_promp = deepcopy(DEFAULT_MP_ENV_DICT) + kwargs_dict_bp_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.MPWrapper) kwargs_dict_bp_promp['phase_generator_kwargs']['learn_tau'] = True kwargs_dict_bp_promp['controller_kwargs']['p_gains'] = np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]) @@ -513,7 +433,7 @@ _versions = ["ALRBeerPongStepBased-v0", "ALRBeerPongFixedRelease-v0"] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_bp_promp = deepcopy(DEFAULT_MP_ENV_DICT) + kwargs_dict_bp_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.MPWrapper) kwargs_dict_bp_promp['phase_generator_kwargs']['tau'] = 0.62 kwargs_dict_bp_promp['controller_kwargs']['p_gains'] = np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]) @@ -538,7 +458,7 @@ _versions = ['ALRAntJump-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_ant_jump_promp = deepcopy(DEFAULT_MP_ENV_DICT) + kwargs_dict_ant_jump_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_ant_jump_promp['wrappers'].append(mujoco.ant_jump.MPWrapper) kwargs_dict_ant_jump_promp['name'] = f"alr_envs:{_v}" register( @@ -555,7 +475,7 @@ _versions = ['ALRHalfCheetahJump-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_halfcheetah_jump_promp = deepcopy(DEFAULT_MP_ENV_DICT) + kwargs_dict_halfcheetah_jump_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_halfcheetah_jump_promp['wrappers'].append(mujoco.half_cheetah_jump.MPWrapper) kwargs_dict_halfcheetah_jump_promp['name'] = f"alr_envs:{_v}" register( @@ -575,7 +495,7 @@ _versions = ['ALRHopperJump-v0', 'ALRHopperJumpRndmJointsDesPos-v0', 'ALRHopperJ for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_hopper_jump_promp = deepcopy(DEFAULT_MP_ENV_DICT) + kwargs_dict_hopper_jump_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_hopper_jump_promp['wrappers'].append(mujoco.hopper_jump.MPWrapper) kwargs_dict_hopper_jump_promp['name'] = f"alr_envs:{_v}" register( @@ -593,7 +513,7 @@ _versions = ['ALRWalker2DJump-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_walker2d_jump_promp = deepcopy(DEFAULT_MP_ENV_DICT) + kwargs_dict_walker2d_jump_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_walker2d_jump_promp['wrappers'].append(mujoco.walker_2d_jump.MPWrapper) kwargs_dict_walker2d_jump_promp['name'] = f"alr_envs:{_v}" register( @@ -695,7 +615,7 @@ for i in _vs: _env_id = f'ALRReacher{i}-v0' register( id=_env_id, - entry_point='alr_envs.alr.mujoco:ALRReacherEnv', + entry_point='alr_envs.alr.mujoco:ReacherEnv', max_episode_steps=200, kwargs={ "steps_before_reward": 0, @@ -708,7 +628,7 @@ for i in _vs: _env_id = f'ALRReacherSparse{i}-v0' register( id=_env_id, - entry_point='alr_envs.alr.mujoco:ALRReacherEnv', + entry_point='alr_envs.alr.mujoco:ReacherEnv', max_episode_steps=200, kwargs={ "steps_before_reward": 200, diff --git a/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py new file mode 100644 index 0000000..19bb0c5 --- /dev/null +++ b/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py @@ -0,0 +1,27 @@ +from typing import Tuple, Union + +import numpy as np + +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper + + +class MPWrapper(RawInterfaceWrapper): + + def get_context_mask(self): + return np.hstack([ + [self.env.random_start] * self.env.n_links, # cos + [self.env.random_start] * self.env.n_links, # sin + [self.env.random_start] * self.env.n_links, # velocity + [self.env.initial_width is None], # hole width + # [self.env.hole_depth is None], # hole depth + [True] * 2, # x-y coordinates of target distance + [False] # env steps + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.current_pos + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.current_vel diff --git a/alr_envs/alr/classic_control/simple_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/simple_reacher/mp_wrapper.py index 30b0985..c5ef66f 100644 --- a/alr_envs/alr/classic_control/simple_reacher/mp_wrapper.py +++ b/alr_envs/alr/classic_control/simple_reacher/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py index 9f40292..2b210de 100644 --- a/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py +++ b/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index f2f4536..df52cfc 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -6,7 +6,7 @@ from .half_cheetah_jump.half_cheetah_jump import ALRHalfCheetahJumpEnv from .hopper_jump.hopper_jump_on_box import ALRHopperJumpOnBoxEnv from .hopper_throw.hopper_throw import ALRHopperThrowEnv from .hopper_throw.hopper_throw_in_basket import ALRHopperThrowInBasketEnv -from .reacher.alr_reacher import ALRReacherEnv +from .reacher.reacher import ReacherEnv from .reacher.balancing import BalancingEnv from .table_tennis.tt_gym import TTEnvGym from .walker_2d_jump.walker_2d_jump import ALRWalker2dJumpEnv diff --git a/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py b/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py index 4d5c0d6..f6e99a3 100644 --- a/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py index 0886065..f6f026b 100644 --- a/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py @@ -1,8 +1,8 @@ -from alr_envs.mp.black_box_wrapper import BlackBoxWrapper +from alr_envs.black_box.black_box_wrapper import BlackBoxWrapper from typing import Union, Tuple import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_mp_wrapper.py b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_mp_wrapper.py index 609858b..81a08f5 100644 --- a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_mp_wrapper.py +++ b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class BallInACupMPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py index 40c371b..20e7532 100644 --- a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py index 2969b82..bd22442 100644 --- a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Union, Tuple import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py b/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py index f9a298a..930da6d 100644 --- a/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py index d14c9a9..9a65952 100644 --- a/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/hopper_jump/__init__.py b/alr_envs/alr/mujoco/hopper_jump/__init__.py index 8a04a02..c5e6d2f 100644 --- a/alr_envs/alr/mujoco/hopper_jump/__init__.py +++ b/alr_envs/alr/mujoco/hopper_jump/__init__.py @@ -1 +1 @@ -from .new_mp_wrapper import MPWrapper +from .mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index 025bb8d..78b06d3 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -1,3 +1,5 @@ +from typing import Optional + from gym.envs.mujoco.hopper_v3 import HopperEnv import numpy as np import os @@ -8,10 +10,10 @@ MAX_EPISODE_STEPS_HOPPERJUMP = 250 class ALRHopperJumpEnv(HopperEnv): """ Initialization changes to normal Hopper: - - healthy_reward: 1.0 -> 0.1 -> 0 - - healthy_angle_range: (-0.2, 0.2) -> (-float('inf'), float('inf')) + - terminate_when_unhealthy: True -> False - healthy_z_range: (0.7, float('inf')) -> (0.5, float('inf')) - - exclude current positions from observatiosn is set to False + - healthy_angle_range: (-0.2, 0.2) -> (-float('inf'), float('inf')) + - exclude_current_positions_from_observation: True -> False """ def __init__( @@ -19,76 +21,93 @@ class ALRHopperJumpEnv(HopperEnv): xml_file='hopper_jump.xml', forward_reward_weight=1.0, ctrl_cost_weight=1e-3, - healthy_reward=0.0, + healthy_reward=1.0, penalty=0.0, - context=True, terminate_when_unhealthy=False, healthy_state_range=(-100.0, 100.0), healthy_z_range=(0.5, float('inf')), healthy_angle_range=(-float('inf'), float('inf')), reset_noise_scale=5e-3, exclude_current_positions_from_observation=False, - max_episode_steps=250 - ): + ): - self.current_step = 0 + self._steps = 0 self.max_height = 0 - self.max_episode_steps = max_episode_steps - self.penalty = penalty + # self.penalty = penalty self.goal = 0 - self.context = context - self.exclude_current_positions_from_observation = exclude_current_positions_from_observation + self._floor_geom_id = None self._foot_geom_id = None + self.contact_with_floor = False self.init_floor_contact = False self.has_left_floor = False self.contact_dist = None + xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, exclude_current_positions_from_observation) def step(self, action): + self._steps += 1 + + self._floor_geom_id = self.model.geom_name2id('floor') + self._foot_geom_id = self.model.geom_name2id('foot_geom') - self.current_step += 1 self.do_simulation(action, self.frame_skip) + height_after = self.get_body_com("torso")[2] - # site_pos_after = self.sim.data.site_xpos[self.model.site_name2id('foot_site')].copy() - site_pos_after = self.get_body_com('foot_site') + site_pos_after = self.data.get_site_xpos('foot_site') self.max_height = max(height_after, self.max_height) + has_floor_contact = self._is_floor_foot_contact() if not self.contact_with_floor else False + + if not self.init_floor_contact: + self.init_floor_contact = has_floor_contact + if self.init_floor_contact and not self.has_left_floor: + self.has_left_floor = not has_floor_contact + if not self.contact_with_floor and self.has_left_floor: + self.contact_with_floor = has_floor_contact + ctrl_cost = self.control_cost(action) costs = ctrl_cost done = False + goal_dist = np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0])) + + if self.contact_dist is None and self.contact_with_floor: + self.contact_dist = goal_dist + rewards = 0 - if self.current_step >= self.max_episode_steps: - hight_goal_distance = -10 * np.linalg.norm(self.max_height - self.goal) if self.context else self.max_height - healthy_reward = 0 if self.context else self.healthy_reward * 2 # self.current_step - height_reward = self._forward_reward_weight * hight_goal_distance # maybe move reward calculation into if structure and define two different _forward_reward_weight variables for context and episodic seperatley - rewards = height_reward + healthy_reward + if self._steps >= MAX_EPISODE_STEPS_HOPPERJUMP: + # healthy_reward = 0 if self.context else self.healthy_reward * self._steps + healthy_reward = self.healthy_reward * 2 # * self._steps + contact_dist = self.contact_dist if self.contact_dist is not None else 5 + dist_reward = self._forward_reward_weight * (-3 * goal_dist + 10 * self.max_height - 2 * contact_dist) + rewards = dist_reward + healthy_reward observation = self._get_obs() reward = rewards - costs - - info = { - 'height': height_after, - 'x_pos': site_pos_after, - 'max_height': self.max_height, - 'height_rew': self.max_height, - 'healthy_reward': self.healthy_reward * 2, - 'healthy': self.is_healthy - } - + info = dict( + height=height_after, + x_pos=site_pos_after, + max_height=self.max_height, + goal=self.goal, + goal_dist=goal_dist, + height_rew=self.max_height, + healthy_reward=self.healthy_reward * 2, + healthy=self.is_healthy, + contact_dist=self.contact_dist if self.contact_dist is not None else 0 + ) return observation, reward, done, info def _get_obs(self): return np.append(super()._get_obs(), self.goal) - def reset(self): + def reset(self, *, seed: Optional[int] = None, return_info: bool = False, options: Optional[dict] = None, ): self.goal = self.np_random.uniform(1.4, 2.16, 1)[0] # 1.3 2.3 self.max_height = 0 - self.current_step = 0 + self._steps = 0 return super().reset() # overwrite reset_model to make it deterministic @@ -106,11 +125,13 @@ class ALRHopperJumpEnv(HopperEnv): self.contact_dist = None return observation - def _contact_checker(self, id_1, id_2): - for coni in range(0, self.sim.data.ncon): - con = self.sim.data.contact[coni] - collision = con.geom1 == id_1 and con.geom2 == id_2 - collision_trans = con.geom1 == id_2 and con.geom2 == id_1 + def _is_floor_foot_contact(self): + floor_geom_id = self.model.geom_name2id('floor') + foot_geom_id = self.model.geom_name2id('foot_geom') + for i in range(self.data.ncon): + contact = self.data.contact[i] + collision = contact.geom1 == floor_geom_id and contact.geom2 == foot_geom_id + collision_trans = contact.geom1 == foot_geom_id and contact.geom2 == floor_geom_id if collision or collision_trans: return True return False @@ -122,7 +143,7 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): self._floor_geom_id = self.model.geom_name2id('floor') self._foot_geom_id = self.model.geom_name2id('foot_geom') - self.current_step += 1 + self._steps += 1 self.do_simulation(action, self.frame_skip) height_after = self.get_body_com("torso")[2] site_pos_after = self.sim.data.site_xpos[self.model.site_name2id('foot_site')].copy() @@ -133,8 +154,8 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): # self.has_left_floor = not floor_contact if self.init_floor_contact and not self.has_left_floor else self.has_left_floor # self.contact_with_floor = floor_contact if not self.contact_with_floor and self.has_left_floor else self.contact_with_floor - floor_contact = self._contact_checker(self._floor_geom_id, - self._foot_geom_id) if not self.contact_with_floor else False + floor_contact = self._is_floor_foot_contact(self._floor_geom_id, + self._foot_geom_id) if not self.contact_with_floor else False if not self.init_floor_contact: self.init_floor_contact = floor_contact if self.init_floor_contact and not self.has_left_floor: @@ -151,9 +172,9 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): done = False goal_dist = np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0])) rewards = 0 - if self.current_step >= self.max_episode_steps: - # healthy_reward = 0 if self.context else self.healthy_reward * self.current_step - healthy_reward = self.healthy_reward * 2 # * self.current_step + if self._steps >= self.max_episode_steps: + # healthy_reward = 0 if self.context else self.healthy_reward * self._steps + healthy_reward = self.healthy_reward * 2 # * self._steps contact_dist = self.contact_dist if self.contact_dist is not None else 5 dist_reward = self._forward_reward_weight * (-3 * goal_dist + 10 * self.max_height - 2 * contact_dist) rewards = dist_reward + healthy_reward @@ -170,7 +191,7 @@ class ALRHopperXYJumpEnv(ALRHopperJumpEnv): 'healthy_reward': self.healthy_reward * 2, 'healthy': self.is_healthy, 'contact_dist': self.contact_dist if self.contact_dist is not None else 0 - } + } return observation, reward, done, info def reset_model(self): @@ -242,7 +263,7 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): height_scale=10, dist_scale=3, healthy_scale=2 - ): + ): self.height_scale = height_scale self.dist_scale = dist_scale self.healthy_scale = healthy_scale @@ -254,7 +275,7 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): self._floor_geom_id = self.model.geom_name2id('floor') self._foot_geom_id = self.model.geom_name2id('foot_geom') - self.current_step += 1 + self._steps += 1 self.do_simulation(action, self.frame_skip) height_after = self.get_body_com("torso")[2] site_pos_after = self.sim.data.site_xpos[self.model.site_name2id('foot_site')].copy() @@ -273,8 +294,8 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): ########################################################### # This is only for logging the distance to goal when first having the contact ########################################################## - floor_contact = self._contact_checker(self._floor_geom_id, - self._foot_geom_id) if not self.contact_with_floor else False + floor_contact = self._is_floor_foot_contact(self._floor_geom_id, + self._foot_geom_id) if not self.contact_with_floor else False if not self.init_floor_contact: self.init_floor_contact = floor_contact if self.init_floor_contact and not self.has_left_floor: @@ -295,33 +316,5 @@ class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): 'healthy_reward': self.healthy_reward * self.healthy_reward, 'healthy': self.is_healthy, 'contact_dist': self.contact_dist if self.contact_dist is not None else 0 - } + } return observation, reward, done, info - - -if __name__ == '__main__': - render_mode = "human" # "human" or "partial" or "final" - # env = ALRHopperJumpEnv() - # env = ALRHopperXYJumpEnv() - np.random.seed(0) - env = ALRHopperXYJumpEnvStepBased() - env.seed(0) - # env = ALRHopperJumpRndmPosEnv() - obs = env.reset() - - for k in range(1000): - obs = env.reset() - print('observation :', obs[:]) - for i in range(200): - # objective.load_result("/tmp/cma") - # test with random actions - ac = env.action_space.sample() - obs, rew, d, info = env.step(ac) - # if i % 10 == 0: - # env.render(mode=render_mode) - env.render(mode=render_mode) - if d: - print('After ', i, ' steps, done: ', d) - env.reset() - - env.close() diff --git a/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py b/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py index e3279aa..c7b16db 100644 --- a/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py @@ -1,57 +1,25 @@ -from typing import Tuple, Union +from typing import Union, Tuple import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): - @property - def context_mask(self) -> np.ndarray: + + # Random x goal + random init pos + def context_mask(self): return np.hstack([ - [False] * (5 + int(not self.exclude_current_positions_from_observation)), # position + [False] * (2 + int(not self.exclude_current_positions_from_observation)), # position + [True] * 3, # set to true if randomize initial pos [False] * 6, # velocity [True] ]) @property - def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.sim.data.qpos[3:6].copy() + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + return self.sim.data.qpos[3:6].copy() @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[3:6].copy() - - @property - def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: - raise ValueError("Goal position is not available and has to be learnt based on the environment.") - - @property - def dt(self) -> Union[float, int]: - return self.env.dt - - -class HighCtxtMPWrapper(MPWrapper): - @property - def active_obs(self): - return np.hstack([ - [True] * (5 + int(not self.exclude_current_positions_from_observation)), # position - [False] * 6, # velocity - [False] - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.sim.data.qpos[3:6].copy() - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[3:6].copy() - - @property - def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: - raise ValueError("Goal position is not available and has to be learnt based on the environment.") - - @property - def dt(self) -> Union[float, int]: - return self.env.dt + return self.sim.data.qvel[3:6].copy() diff --git a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py deleted file mode 100644 index b919b22..0000000 --- a/alr_envs/alr/mujoco/hopper_jump/new_mp_wrapper.py +++ /dev/null @@ -1,45 +0,0 @@ -from alr_envs.mp.black_box_wrapper import BlackBoxWrapper -from typing import Union, Tuple -import numpy as np - - -class MPWrapper(BlackBoxWrapper): - @property - def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qpos[3:6].copy() - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[3:6].copy() - - # # random goal - # def set_active_obs(self): - # return np.hstack([ - # [False] * (5 + int(not self.env.exclude_current_positions_from_observation)), # position - # [False] * 6, # velocity - # [True] - # ]) - - # Random x goal + random init pos - def get_context_mask(self): - return np.hstack([ - [False] * (2 + int(not self.env.exclude_current_positions_from_observation)), # position - [True] * 3, # set to true if randomize initial pos - [False] * 6, # velocity - [True] - ]) - - -class NewHighCtxtMPWrapper(MPWrapper): - def get_context_mask(self): - return np.hstack([ - [False] * (2 + int(not self.env.exclude_current_positions_from_observation)), # position - [True] * 3, # set to true if randomize initial pos - [False] * 6, # velocity - [True], # goal - [False] * 3 # goal diff - ]) - - def set_context(self, context): - return self.get_observation_from_step(self.env.env.set_context(context)) - diff --git a/alr_envs/alr/mujoco/hopper_throw/hopper_throw.py b/alr_envs/alr/mujoco/hopper_throw/hopper_throw.py index 03553f2..7ae33d1 100644 --- a/alr_envs/alr/mujoco/hopper_throw/hopper_throw.py +++ b/alr_envs/alr/mujoco/hopper_throw/hopper_throw.py @@ -67,7 +67,7 @@ class ALRHopperThrowEnv(HopperEnv): info = { 'ball_pos': ball_pos_after, 'ball_pos_y': ball_pos_after_y, - 'current_step' : self.current_step, + '_steps' : self.current_step, 'goal' : self.goal, } diff --git a/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py b/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py index f5bf08d..7778e8c 100644 --- a/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py b/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py index a8cd696..01d87a4 100644 --- a/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/reacher/alr_reacher.py b/alr_envs/alr/mujoco/reacher/alr_reacher.py deleted file mode 100644 index 0699c44..0000000 --- a/alr_envs/alr/mujoco/reacher/alr_reacher.py +++ /dev/null @@ -1,152 +0,0 @@ -import os - -import numpy as np -from gym import utils -from gym.envs.mujoco import MujocoEnv - -import alr_envs.utils.utils as alr_utils - - -class ALRReacherEnv(MujocoEnv, utils.EzPickle): - def __init__(self, steps_before_reward: int = 200, n_links: int = 5, ctrl_cost_weight: int = 1, - balance: bool = False): - utils.EzPickle.__init__(**locals()) - - self._steps = 0 - self.steps_before_reward = steps_before_reward - self.n_links = n_links - - self.balance = balance - self.balance_weight = 1.0 - self.ctrl_cost_weight = ctrl_cost_weight - - self.reward_weight = 1 - if steps_before_reward == 200: - self.reward_weight = 200 - elif steps_before_reward == 50: - self.reward_weight = 50 - - if n_links == 5: - file_name = 'reacher_5links.xml' - elif n_links == 7: - file_name = 'reacher_7links.xml' - else: - raise ValueError(f"Invalid number of links {n_links}, only 5 or 7 allowed.") - - MujocoEnv.__init__(self, os.path.join(os.path.dirname(__file__), "assets", file_name), 2) - - def step(self, a): - self._steps += 1 - - reward_dist = 0.0 - angular_vel = 0.0 - reward_balance = 0.0 - is_delayed = self.steps_before_reward > 0 - reward_ctrl = - np.square(a).sum() * self.ctrl_cost_weight - if self._steps >= self.steps_before_reward: - vec = self.get_body_com("fingertip") - self.get_body_com("target") - reward_dist -= self.reward_weight * np.linalg.norm(vec) - if is_delayed: - # avoid giving this penalty for normal step based case - # angular_vel -= 10 * np.linalg.norm(self.sim.data.qvel.flat[:self.n_links]) - angular_vel -= 10 * np.square(self.sim.data.qvel.flat[:self.n_links]).sum() - # if is_delayed: - # # Higher control penalty for sparse reward per timestep - # reward_ctrl *= 10 - - if self.balance: - reward_balance -= self.balance_weight * np.abs( - alr_utils.angle_normalize(np.sum(self.sim.data.qpos.flat[:self.n_links]), type="rad")) - - reward = reward_dist + reward_ctrl + angular_vel + reward_balance - self.do_simulation(a, self.frame_skip) - ob = self._get_obs() - done = False - return ob, reward, done, dict(reward_dist=reward_dist, reward_ctrl=reward_ctrl, - velocity=angular_vel, reward_balance=reward_balance, - end_effector=self.get_body_com("fingertip").copy(), - goal=self.goal if hasattr(self, "goal") else None) - - def viewer_setup(self): - self.viewer.cam.trackbodyid = 0 - - # def reset_model(self): - # qpos = self.init_qpos - # if not hasattr(self, "goal"): - # self.goal = np.array([-0.25, 0.25]) - # # self.goal = self.init_qpos.copy()[:2] + 0.05 - # qpos[-2:] = self.goal - # qvel = self.init_qvel - # qvel[-2:] = 0 - # self.set_state(qpos, qvel) - # self._steps = 0 - # - # return self._get_obs() - - def reset_model(self): - qpos = self.init_qpos.copy() - while True: - # full space - # self.goal = self.np_random.uniform(low=-self.n_links / 10, high=self.n_links / 10, size=2) - # I Quadrant - # self.goal = self.np_random.uniform(low=0, high=self.n_links / 10, size=2) - # II Quadrant - # self.goal = np.random.uniform(low=[-self.n_links / 10, 0], high=[0, self.n_links / 10], size=2) - # II + III Quadrant - # self.goal = np.random.uniform(low=-self.n_links / 10, high=[0, self.n_links / 10], size=2) - # I + II Quadrant - self.goal = np.random.uniform(low=[-self.n_links / 10, 0], high=self.n_links, size=2) - if np.linalg.norm(self.goal) < self.n_links / 10: - break - qpos[-2:] = self.goal - qvel = self.init_qvel.copy() - qvel[-2:] = 0 - self.set_state(qpos, qvel) - self._steps = 0 - - return self._get_obs() - - # def reset_model(self): - # qpos = self.np_random.uniform(low=-0.1, high=0.1, size=self.model.nq) + self.init_qpos - # while True: - # self.goal = self.np_random.uniform(low=-self.n_links / 10, high=self.n_links / 10, size=2) - # if np.linalg.norm(self.goal) < self.n_links / 10: - # break - # qpos[-2:] = self.goal - # qvel = self.init_qvel + self.np_random.uniform(low=-.005, high=.005, size=self.model.nv) - # qvel[-2:] = 0 - # self.set_state(qpos, qvel) - # self._steps = 0 - # - # return self._get_obs() - - def _get_obs(self): - theta = self.sim.data.qpos.flat[:self.n_links] - target = self.get_body_com("target") - return np.concatenate([ - np.cos(theta), - np.sin(theta), - target[:2], # x-y of goal position - self.sim.data.qvel.flat[:self.n_links], # angular velocity - self.get_body_com("fingertip") - target, # goal distance - [self._steps], - ]) - - -if __name__ == '__main__': - nl = 5 - render_mode = "human" # "human" or "partial" or "final" - env = ALRReacherEnv(n_links=nl) - obs = env.reset() - - for i in range(2000): - # objective.load_result("/tmp/cma") - # test with random actions - ac = env.action_space.sample() - obs, rew, d, info = env.step(ac) - if i % 10 == 0: - env.render(mode=render_mode) - if d: - env.reset() - - env.close() diff --git a/alr_envs/alr/mujoco/reacher/balancing.py b/alr_envs/alr/mujoco/reacher/balancing.py deleted file mode 100644 index 3e34298..0000000 --- a/alr_envs/alr/mujoco/reacher/balancing.py +++ /dev/null @@ -1,53 +0,0 @@ -import os - -import numpy as np -from gym import utils -from gym.envs.mujoco import mujoco_env - -import alr_envs.utils.utils as alr_utils - - -class BalancingEnv(mujoco_env.MujocoEnv, utils.EzPickle): - def __init__(self, n_links=5): - utils.EzPickle.__init__(**locals()) - - self.n_links = n_links - - if n_links == 5: - file_name = 'reacher_5links.xml' - elif n_links == 7: - file_name = 'reacher_7links.xml' - else: - raise ValueError(f"Invalid number of links {n_links}, only 5 or 7 allowed.") - - mujoco_env.MujocoEnv.__init__(self, os.path.join(os.path.dirname(__file__), "assets", file_name), 2) - - def step(self, a): - angle = alr_utils.angle_normalize(np.sum(self.sim.data.qpos.flat[:self.n_links]), type="rad") - reward = - np.abs(angle) - - self.do_simulation(a, self.frame_skip) - ob = self._get_obs() - done = False - return ob, reward, done, dict(angle=angle, end_effector=self.get_body_com("fingertip").copy()) - - def viewer_setup(self): - self.viewer.cam.trackbodyid = 1 - - def reset_model(self): - # This also generates a goal, we however do not need/use it - qpos = self.np_random.uniform(low=-0.1, high=0.1, size=self.model.nq) + self.init_qpos - qpos[-2:] = 0 - qvel = self.init_qvel + self.np_random.uniform(low=-.005, high=.005, size=self.model.nv) - qvel[-2:] = 0 - self.set_state(qpos, qvel) - - return self._get_obs() - - def _get_obs(self): - theta = self.sim.data.qpos.flat[:self.n_links] - return np.concatenate([ - np.cos(theta), - np.sin(theta), - self.sim.data.qvel.flat[:self.n_links], # this is angular velocity - ]) diff --git a/alr_envs/alr/mujoco/reacher/mp_wrapper.py b/alr_envs/alr/mujoco/reacher/mp_wrapper.py index 966be23..de33ae0 100644 --- a/alr_envs/alr/mujoco/reacher/mp_wrapper.py +++ b/alr_envs/alr/mujoco/reacher/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Union, Tuple import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/reacher/reacher.py b/alr_envs/alr/mujoco/reacher/reacher.py new file mode 100644 index 0000000..a5d34ee --- /dev/null +++ b/alr_envs/alr/mujoco/reacher/reacher.py @@ -0,0 +1,105 @@ +import os + +import numpy as np +from gym import utils +from gym.envs.mujoco import MujocoEnv + + +class ReacherEnv(MujocoEnv, utils.EzPickle): + """ + More general version of the gym mujoco Reacher environment + """ + + def __init__(self, sparse: bool = False, n_links: int = 5, ctrl_cost_weight: int = 1): + utils.EzPickle.__init__(**locals()) + + self._steps = 0 + self.n_links = n_links + + self.ctrl_cost_weight = ctrl_cost_weight + + self.sparse = sparse + self.reward_weight = 1 if not sparse else 200 + + file_name = f'reacher_{n_links}links.xml' + + MujocoEnv.__init__(self, os.path.join(os.path.dirname(__file__), "assets", file_name), 2) + + def step(self, action): + self._steps += 1 + + is_reward = not self.sparse or (self.sparse and self._steps == 200) + + reward_dist = 0.0 + angular_vel = 0.0 + if is_reward: + reward_dist = self.distance_reward() + angular_vel = self.velocity_reward() + + reward_ctrl = -self.ctrl_cost_weight * np.square(action).sum() + + reward = reward_dist + reward_ctrl + angular_vel + self.do_simulation(action, self.frame_skip) + ob = self._get_obs() + done = False + + infos = dict( + reward_dist=reward_dist, + reward_ctrl=reward_ctrl, + velocity=angular_vel, + end_effector=self.get_body_com("fingertip").copy(), + goal=self.goal if hasattr(self, "goal") else None + ) + + return ob, reward, done, infos + + def distance_reward(self): + vec = self.get_body_com("fingertip") - self.get_body_com("target") + return -self.reward_weight * np.linalg.norm(vec) + + def velocity_reward(self): + return -10 * np.square(self.sim.data.qvel.flat[:self.n_links]).sum() if self.sparse else 0.0 + + def viewer_setup(self): + self.viewer.cam.trackbodyid = 0 + + def reset_model(self): + qpos = ( + # self.np_random.uniform(low=-0.1, high=0.1, size=self.model.nq) + + self.init_qpos.copy() + ) + while True: + # full space + self.goal = self.np_random.uniform(low=-self.n_links / 10, high=self.n_links / 10, size=2) + # I Quadrant + # self.goal = self.np_random.uniform(low=0, high=self.n_links / 10, size=2) + # II Quadrant + # self.goal = np.random.uniform(low=[-self.n_links / 10, 0], high=[0, self.n_links / 10], size=2) + # II + III Quadrant + # self.goal = np.random.uniform(low=-self.n_links / 10, high=[0, self.n_links / 10], size=2) + # I + II Quadrant + # self.goal = np.random.uniform(low=[-self.n_links / 10, 0], high=self.n_links, size=2) + if np.linalg.norm(self.goal) < self.n_links / 10: + break + + qpos[-2:] = self.goal + qvel = ( + # self.np_random.uniform(low=-0.005, high=0.005, size=self.model.nv) + + self.init_qvel.copy() + ) + qvel[-2:] = 0 + self.set_state(qpos, qvel) + self._steps = 0 + + return self._get_obs() + + def _get_obs(self): + theta = self.sim.data.qpos.flat[:self.n_links] + target = self.get_body_com("target") + return np.concatenate([ + np.cos(theta), + np.sin(theta), + target[:2], # x-y of goal position + self.sim.data.qvel.flat[:self.n_links], # angular velocity + self.get_body_com("fingertip") - target, # goal distance + ]) diff --git a/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py b/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py index 408124a..40e4252 100644 --- a/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py +++ b/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py b/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py index 0c2dba5..5e9d0eb 100644 --- a/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py index 96b0739..b2bfde9 100644 --- a/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/mp/__init__.py b/alr_envs/black_box/__init__.py similarity index 100% rename from alr_envs/mp/__init__.py rename to alr_envs/black_box/__init__.py diff --git a/alr_envs/mp/black_box_wrapper.py b/alr_envs/black_box/black_box_wrapper.py similarity index 94% rename from alr_envs/mp/black_box_wrapper.py rename to alr_envs/black_box/black_box_wrapper.py index f1ba41f..0c10ef8 100644 --- a/alr_envs/mp/black_box_wrapper.py +++ b/alr_envs/black_box/black_box_wrapper.py @@ -6,8 +6,8 @@ import numpy as np from gym import spaces from mp_pytorch.mp.mp_interfaces import MPInterface -from alr_envs.mp.controllers.base_controller import BaseController -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.controller.base_controller import BaseController +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper from alr_envs.utils.utils import get_numpy @@ -15,10 +15,14 @@ class BlackBoxWrapper(gym.ObservationWrapper): def __init__(self, env: RawInterfaceWrapper, - trajectory_generator: MPInterface, tracking_controller: BaseController, - duration: float, verbose: int = 1, learn_sub_trajectories: bool = False, + trajectory_generator: MPInterface, + tracking_controller: BaseController, + duration: float, + verbose: int = 1, + learn_sub_trajectories: bool = False, replanning_schedule: Union[None, callable] = None, - reward_aggregation: callable = np.sum): + reward_aggregation: callable = np.sum + ): """ gym.Wrapper for leveraging a black box approach with a trajectory generator. diff --git a/alr_envs/mp/controllers/__init__.py b/alr_envs/black_box/controller/__init__.py similarity index 100% rename from alr_envs/mp/controllers/__init__.py rename to alr_envs/black_box/controller/__init__.py diff --git a/alr_envs/mp/controllers/base_controller.py b/alr_envs/black_box/controller/base_controller.py similarity index 100% rename from alr_envs/mp/controllers/base_controller.py rename to alr_envs/black_box/controller/base_controller.py diff --git a/alr_envs/mp/controllers/controller_factory.py b/alr_envs/black_box/controller/controller_factory.py similarity index 60% rename from alr_envs/mp/controllers/controller_factory.py rename to alr_envs/black_box/controller/controller_factory.py index 1c1cfec..6ef7960 100644 --- a/alr_envs/mp/controllers/controller_factory.py +++ b/alr_envs/black_box/controller/controller_factory.py @@ -1,7 +1,7 @@ -from alr_envs.mp.controllers.meta_world_controller import MetaWorldController -from alr_envs.mp.controllers.pd_controller import PDController -from alr_envs.mp.controllers.vel_controller import VelController -from alr_envs.mp.controllers.pos_controller import PosController +from alr_envs.black_box.controller.meta_world_controller import MetaWorldController +from alr_envs.black_box.controller.pd_controller import PDController +from alr_envs.black_box.controller.vel_controller import VelController +from alr_envs.black_box.controller.pos_controller import PosController ALL_TYPES = ["motor", "velocity", "position", "metaworld"] diff --git a/alr_envs/mp/controllers/meta_world_controller.py b/alr_envs/black_box/controller/meta_world_controller.py similarity index 92% rename from alr_envs/mp/controllers/meta_world_controller.py rename to alr_envs/black_box/controller/meta_world_controller.py index 5747f9e..296ea3a 100644 --- a/alr_envs/mp/controllers/meta_world_controller.py +++ b/alr_envs/black_box/controller/meta_world_controller.py @@ -1,6 +1,6 @@ import numpy as np -from alr_envs.mp.controllers.base_controller import BaseController +from alr_envs.black_box.controller.base_controller import BaseController class MetaWorldController(BaseController): diff --git a/alr_envs/mp/controllers/pd_controller.py b/alr_envs/black_box/controller/pd_controller.py similarity index 93% rename from alr_envs/mp/controllers/pd_controller.py rename to alr_envs/black_box/controller/pd_controller.py index 140aeee..ab21444 100644 --- a/alr_envs/mp/controllers/pd_controller.py +++ b/alr_envs/black_box/controller/pd_controller.py @@ -1,6 +1,6 @@ from typing import Union, Tuple -from alr_envs.mp.controllers.base_controller import BaseController +from alr_envs.black_box.controller.base_controller import BaseController class PDController(BaseController): diff --git a/alr_envs/mp/controllers/pos_controller.py b/alr_envs/black_box/controller/pos_controller.py similarity index 77% rename from alr_envs/mp/controllers/pos_controller.py rename to alr_envs/black_box/controller/pos_controller.py index 5570307..3f3526a 100644 --- a/alr_envs/mp/controllers/pos_controller.py +++ b/alr_envs/black_box/controller/pos_controller.py @@ -1,4 +1,4 @@ -from alr_envs.mp.controllers.base_controller import BaseController +from alr_envs.black_box.controller.base_controller import BaseController class PosController(BaseController): diff --git a/alr_envs/mp/controllers/vel_controller.py b/alr_envs/black_box/controller/vel_controller.py similarity index 77% rename from alr_envs/mp/controllers/vel_controller.py rename to alr_envs/black_box/controller/vel_controller.py index 67bab2a..2134207 100644 --- a/alr_envs/mp/controllers/vel_controller.py +++ b/alr_envs/black_box/controller/vel_controller.py @@ -1,4 +1,4 @@ -from alr_envs.mp.controllers.base_controller import BaseController +from alr_envs.black_box.controller.base_controller import BaseController class VelController(BaseController): diff --git a/alr_envs/black_box/factory/__init__.py b/alr_envs/black_box/factory/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/alr_envs/mp/basis_generator_factory.py b/alr_envs/black_box/factory/basis_generator_factory.py similarity index 100% rename from alr_envs/mp/basis_generator_factory.py rename to alr_envs/black_box/factory/basis_generator_factory.py diff --git a/alr_envs/mp/phase_generator_factory.py b/alr_envs/black_box/factory/phase_generator_factory.py similarity index 93% rename from alr_envs/mp/phase_generator_factory.py rename to alr_envs/black_box/factory/phase_generator_factory.py index 45cfdc1..ca0dd84 100644 --- a/alr_envs/mp/phase_generator_factory.py +++ b/alr_envs/black_box/factory/phase_generator_factory.py @@ -17,4 +17,4 @@ def get_phase_generator(phase_generator_type, **kwargs): return SmoothPhaseGenerator(**kwargs) else: raise ValueError(f"Specified phase generator type {phase_generator_type} not supported, " - f"please choose one of {ALL_TYPES}.") \ No newline at end of file + f"please choose one of {ALL_TYPES}.") diff --git a/alr_envs/mp/mp_factory.py b/alr_envs/black_box/factory/trajectory_generator_factory.py similarity index 91% rename from alr_envs/mp/mp_factory.py rename to alr_envs/black_box/factory/trajectory_generator_factory.py index d2c5460..784513e 100644 --- a/alr_envs/mp/mp_factory.py +++ b/alr_envs/black_box/factory/trajectory_generator_factory.py @@ -9,7 +9,7 @@ ALL_TYPES = ["promp", "dmp", "idmp"] def get_trajectory_generator( trajectory_generator_type: str, action_dim: int, basis_generator: BasisGenerator, **kwargs - ): +): trajectory_generator_type = trajectory_generator_type.lower() if trajectory_generator_type == "promp": return ProMP(basis_generator, action_dim, **kwargs) @@ -19,4 +19,4 @@ def get_trajectory_generator( return IDMP(basis_generator, action_dim, **kwargs) else: raise ValueError(f"Specified movement primitive type {trajectory_generator_type} not supported, " - f"please choose one of {ALL_TYPES}.") \ No newline at end of file + f"please choose one of {ALL_TYPES}.") diff --git a/alr_envs/mp/raw_interface_wrapper.py b/alr_envs/black_box/raw_interface_wrapper.py similarity index 100% rename from alr_envs/mp/raw_interface_wrapper.py rename to alr_envs/black_box/raw_interface_wrapper.py diff --git a/alr_envs/dmc/manipulation/reach_site/mp_wrapper.py b/alr_envs/dmc/manipulation/reach_site/mp_wrapper.py index 6d5029e..d918edc 100644 --- a/alr_envs/dmc/manipulation/reach_site/mp_wrapper.py +++ b/alr_envs/dmc/manipulation/reach_site/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py b/alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py index 9687bed..b3f882e 100644 --- a/alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py +++ b/alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/dmc/suite/cartpole/mp_wrapper.py b/alr_envs/dmc/suite/cartpole/mp_wrapper.py index 3f16d24..6cc0687 100644 --- a/alr_envs/dmc/suite/cartpole/mp_wrapper.py +++ b/alr_envs/dmc/suite/cartpole/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/dmc/suite/reacher/mp_wrapper.py b/alr_envs/dmc/suite/reacher/mp_wrapper.py index ac857c1..82e4da8 100644 --- a/alr_envs/dmc/suite/reacher/mp_wrapper.py +++ b/alr_envs/dmc/suite/reacher/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/meta/goal_change_mp_wrapper.py b/alr_envs/meta/goal_change_mp_wrapper.py index 17495da..e628a0c 100644 --- a/alr_envs/meta/goal_change_mp_wrapper.py +++ b/alr_envs/meta/goal_change_mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/meta/goal_endeffector_change_mp_wrapper.py b/alr_envs/meta/goal_endeffector_change_mp_wrapper.py index 3a6ad1c..1a128e7 100644 --- a/alr_envs/meta/goal_endeffector_change_mp_wrapper.py +++ b/alr_envs/meta/goal_endeffector_change_mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/meta/goal_object_change_mp_wrapper.py b/alr_envs/meta/goal_object_change_mp_wrapper.py index 97c64b8..1a6f57e 100644 --- a/alr_envs/meta/goal_object_change_mp_wrapper.py +++ b/alr_envs/meta/goal_object_change_mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/meta/object_change_mp_wrapper.py b/alr_envs/meta/object_change_mp_wrapper.py index f832c9f..07e88dc 100644 --- a/alr_envs/meta/object_change_mp_wrapper.py +++ b/alr_envs/meta/object_change_mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/open_ai/classic_control/continuous_mountain_car/mp_wrapper.py b/alr_envs/open_ai/classic_control/continuous_mountain_car/mp_wrapper.py index 189563c..db9f1f2 100644 --- a/alr_envs/open_ai/classic_control/continuous_mountain_car/mp_wrapper.py +++ b/alr_envs/open_ai/classic_control/continuous_mountain_car/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/open_ai/mujoco/reacher_v2/mp_wrapper.py b/alr_envs/open_ai/mujoco/reacher_v2/mp_wrapper.py index 9d627b6..1e02f10 100644 --- a/alr_envs/open_ai/mujoco/reacher_v2/mp_wrapper.py +++ b/alr_envs/open_ai/mujoco/reacher_v2/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/open_ai/robotics/fetch/mp_wrapper.py b/alr_envs/open_ai/robotics/fetch/mp_wrapper.py index 7a7bed6..331aa40 100644 --- a/alr_envs/open_ai/robotics/fetch/mp_wrapper.py +++ b/alr_envs/open_ai/robotics/fetch/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/utils/make_env_helpers.py b/alr_envs/utils/make_env_helpers.py index b5587a7..3a8eec5 100644 --- a/alr_envs/utils/make_env_helpers.py +++ b/alr_envs/utils/make_env_helpers.py @@ -7,12 +7,12 @@ import numpy as np from gym.envs.registration import EnvSpec, registry from gym.wrappers import TimeAwareObservation -from alr_envs.mp.basis_generator_factory import get_basis_generator -from alr_envs.mp.black_box_wrapper import BlackBoxWrapper -from alr_envs.mp.controllers.controller_factory import get_controller -from alr_envs.mp.mp_factory import get_trajectory_generator -from alr_envs.mp.phase_generator_factory import get_phase_generator -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.factory.basis_generator_factory import get_basis_generator +from alr_envs.black_box.black_box_wrapper import BlackBoxWrapper +from alr_envs.black_box.controller.controller_factory import get_controller +from alr_envs.black_box.factory.trajectory_generator_factory import get_trajectory_generator +from alr_envs.black_box.factory.phase_generator_factory import get_phase_generator +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper from alr_envs.utils.utils import nested_update @@ -46,6 +46,7 @@ def make(env_id, seed, **kwargs): spec = registry.get(env_id) # This access is required to allow for nested dict updates all_kwargs = deepcopy(spec._kwargs) + # TODO append wrapper here nested_update(all_kwargs, **kwargs) return _make(env_id, seed, **all_kwargs) @@ -224,8 +225,8 @@ def make_bb_env_helper(**kwargs): seed = kwargs.pop("seed", None) wrappers = kwargs.pop("wrappers") - traj_gen_kwargs = kwargs.pop("traj_gen_kwargs", {}) black_box_kwargs = kwargs.pop('black_box_kwargs', {}) + traj_gen_kwargs = kwargs.pop("traj_gen_kwargs", {}) contr_kwargs = kwargs.pop("controller_kwargs", {}) phase_kwargs = kwargs.pop("phase_generator_kwargs", {}) basis_kwargs = kwargs.pop("basis_generator_kwargs", {}) From a7051cd8b70721fc640571fbc04416b211e18b79 Mon Sep 17 00:00:00 2001 From: Onur Date: Thu, 30 Jun 2022 17:55:00 +0200 Subject: [PATCH 052/104] mainly tidied up beerpong.py and beerpong_reward_staged.py --- alr_envs/alr/__init__.py | 6 +- .../hole_reacher/mp_wrapper.py | 8 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 57 +++---- .../mujoco/beerpong/beerpong_reward_staged.py | 156 +++++++++--------- alr_envs/alr/mujoco/reacher/__init__.py | 2 +- alr_envs/utils/make_env_helpers.py | 15 +- 6 files changed, 120 insertions(+), 124 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index cf009a4..3d2415c 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -24,7 +24,7 @@ ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": []} DEFAULT_BB_DICT = { "name": 'EnvName', "wrappers": [], - "traj_gen_kwargs": { + "trajectory_generator_kwargs": { 'trajectory_generator_type': 'promp' }, "phase_generator_kwargs": { @@ -231,7 +231,6 @@ register( entry_point='alr_envs.alr.mujoco:ALRBeerBongEnvStepBased', max_episode_steps=300, kwargs={ - "rndm_goal": True, "cup_goal_pos": [-0.3, -1.2], "frame_skip": 2 } @@ -243,7 +242,6 @@ register( entry_point='alr_envs.alr.mujoco:ALRBeerBongEnvFixedReleaseStep', max_episode_steps=300, kwargs={ - "rndm_goal": True, "cup_goal_pos": [-0.3, -1.2], "frame_skip": 2 } @@ -355,7 +353,7 @@ for _v in _versions: _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_hole_reacher_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_hole_reacher_promp['wrappers'].append(classic_control.hole_reacher.MPWrapper) - kwargs_dict_hole_reacher_promp['traj_gen_kwargs']['weight_scale'] = 2 + kwargs_dict_hole_reacher_promp['trajectory_generator_kwargs']['weight_scale'] = 2 kwargs_dict_hole_reacher_promp['controller_kwargs']['controller_type'] = 'velocity' kwargs_dict_hole_reacher_promp['name'] = f"alr_envs:{_v}" register( diff --git a/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py index 19bb0c5..85bc784 100644 --- a/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py +++ b/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py @@ -2,12 +2,12 @@ from typing import Tuple, Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): - def get_context_mask(self): + def context_mask(self): return np.hstack([ [self.env.random_start] * self.env.n_links, # cos [self.env.random_start] * self.env.n_links, # sin @@ -25,3 +25,7 @@ class MPWrapper(RawInterfaceWrapper): @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.current_vel + + @property + def dt(self) -> Union[float, int]: + return self.env.dt diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index dfd6ea4..117003f 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -19,12 +19,9 @@ CUP_POS_MAX = np.array([1.42, -1.25]) # CUP_POS_MAX = np.array([0.16, -1.7]) class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): - def __init__( - self, frame_skip=1, apply_gravity_comp=True, noisy=False, - rndm_goal=False, cup_goal_pos=None - ): + def __init__(self, frame_skip=2, apply_gravity_comp=True): - cup_goal_pos = np.array(cup_goal_pos if cup_goal_pos is not None else [-0.3, -1.2, 0.840]) + cup_goal_pos = np.array([-0.3, -1.2, 0.840]) if cup_goal_pos.shape[0] == 2: cup_goal_pos = np.insert(cup_goal_pos, 2, 0.840) self.cup_goal_pos = np.array(cup_goal_pos) @@ -38,9 +35,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.j_min = np.array([-2.6, -1.985, -2.8, -0.9, -4.55, -1.5707, -2.7]) self.j_max = np.array([2.6, 1.985, 2.8, 3.14159, 1.25, 1.5707, 2.7]) - self.rndm_goal = rndm_goal self.apply_gravity_comp = apply_gravity_comp - self.add_noise = noisy self._start_pos = np.array([0.0, 1.35, 0.0, 1.18, 0.0, -0.786, -1.59]) self._start_vel = np.zeros(7) @@ -48,17 +43,13 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.ball_site_id = 0 self.ball_id = 11 - # self._release_step = 175 # time step of ball release - # self._release_step = 130 # time step of ball release self.release_step = 100 # time step of ball release self.ep_length = 600 // frame_skip self.cup_table_id = 10 - if noisy: - self.noise_std = 0.01 - else: - self.noise_std = 0 + self.add_noise = False + reward_function = BeerPongReward self.reward_function = reward_function() self.repeat_action = frame_skip @@ -74,7 +65,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): return self._start_vel def reset(self): - self.reward_function.reset(self.add_noise) + self.reward_function.reset() return super().reset() def reset_model(self): @@ -88,15 +79,13 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): start_pos[0:7] = init_pos_robot self.set_state(start_pos, init_vel) - self.sim.model.body_pos[self.cup_table_id] = self.cup_goal_pos start_pos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() self.set_state(start_pos, init_vel) - if self.rndm_goal: - xy = self.np_random.uniform(CUP_POS_MIN, CUP_POS_MAX) - xyz = np.zeros(3) - xyz[:2] = xy - xyz[-1] = 0.840 - self.sim.model.body_pos[self.cup_table_id] = xyz + xy = self.np_random.uniform(CUP_POS_MIN, CUP_POS_MAX) + xyz = np.zeros(3) + xyz[:2] = xy + xyz[-1] = 0.840 + self.sim.model.body_pos[self.cup_table_id] = xyz return self._get_obs() def step(self, a): @@ -115,12 +104,9 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): if self._steps < self.release_step: self.sim.data.qpos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() self.sim.data.qvel[7::] = self.sim.data.site_xvelp[self.ball_site_id, :].copy() - elif self._steps == self.release_step and self.add_noise: - self.sim.data.qvel[7::] += self.noise_std * np.random.randn(3) crash = False except mujoco_py.builder.MujocoException: crash = True - # joint_cons_viol = self.check_traj_in_joint_limits() ob = self._get_obs() @@ -184,14 +170,14 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): class ALRBeerBongEnvFixedReleaseStep(ALRBeerBongEnv): - def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): - super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) + def __init__(self, frame_skip=2, apply_gravity_comp=True): + super().__init__(frame_skip, apply_gravity_comp) self.release_step = 62 # empirically evaluated for frame_skip=2! class ALRBeerBongEnvStepBasedEpisodicReward(ALRBeerBongEnv): - def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): - super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) + def __init__(self, frame_skip=2, apply_gravity_comp=True): + super().__init__(frame_skip, apply_gravity_comp) self.release_step = 62 # empirically evaluated for frame_skip=2! def step(self, a): @@ -245,18 +231,21 @@ class ALRBeerBongEnvStepBasedEpisodicReward(ALRBeerBongEnv): if __name__ == "__main__": - # env = ALRBeerBongEnv(rndm_goal=True) - # env = ALRBeerBongEnvStepBased(frame_skip=2, rndm_goal=True) - # env = ALRBeerBongEnvStepBasedEpisodicReward(frame_skip=2, rndm_goal=True) - env = ALRBeerBongEnvFixedReleaseStep(frame_skip=2, rndm_goal=True) + env = ALRBeerBongEnv(frame_skip=2) + # env = ALRBeerBongEnvStepBased(frame_skip=2) + # env = ALRBeerBongEnvStepBasedEpisodicReward(frame_skip=2) + # env = ALRBeerBongEnvFixedReleaseStep(frame_skip=2) import time env.reset() env.render("human") for i in range(1500): - ac = 10 * env.action_space.sample() + # ac = 10 * env.action_space.sample() + ac = np.ones(7) # ac = np.zeros(7) - # ac[0] = -1 + # ac[0] = 0 + # ac[1] = -0.01 + # ac[3] = -0.01 # if env._steps > 150: # ac[0] = 1 obs, rew, d, info = env.step(ac) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index 7e5fda6..cd2ab75 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -32,6 +32,21 @@ class BeerPongReward: self.dists = None self.dists_final = None self.action_costs = None + self.ball_ground_contact_first = False + self.ball_table_contact = False + self.ball_wall_contact = False + self.ball_cup_contact = False + self.ball_in_cup = False + self.dist_ground_cup = -1 # distance floor to cup if first floor contact + + ### IDs + self.ball_collision_id = None + self.table_collision_id = None + self.wall_collision_id = None + self.cup_table_collision_id = None + self.ground_collision_id = None + self.cup_collision_ids = None + self.robot_collision_ids = None self.reset() self.is_initialized = False @@ -50,25 +65,27 @@ class BeerPongReward: if not self.is_initialized: self.is_initialized = True - self.ball_id = env.sim.model._body_name2id["ball"] - self.goal_id = env.sim.model._site_name2id["cup_goal_table"] - self.goal_final_id = env.sim.model._site_name2id["cup_goal_final_table"] - self.cup_table_id = env.sim.model._body_name2id["cup_table"] - - self.ball_collision_id = env.sim.model._geom_name2id["ball_geom"] - self.table_collision_id = env.sim.model._geom_name2id["table_contact_geom"] - self.wall_collision_id = env.sim.model._geom_name2id["wall"] - self.cup_table_collision_id = env.sim.model._geom_name2id["cup_base_table_contact"] - self.ground_collision_id = env.sim.model._geom_name2id["ground"] - self.cup_collision_ids = [env.sim.model._geom_name2id[name] for name in self.cup_collision_objects] - self.robot_collision_ids = [env.sim.model._geom_name2id[name] for name in self.robot_collision_objects] + # TODO: Find a more elegant way to acces to the geom ids in each step -> less code + self.ball_collision_id = {env.model.geom_name2id("ball_geom")} + # self.ball_collision_id = env.model.geom_name2id("ball_geom") + self.table_collision_id = {env.model.geom_name2id("table_contact_geom")} + # self.table_collision_id = env.model.geom_name2id("table_contact_geom") + self.wall_collision_id = {env.model.geom_name2id("wall")} + # self.wall_collision_id = env.model.geom_name2id("wall") + self.cup_table_collision_id = {env.model.geom_name2id("cup_base_table_contact")} + # self.cup_table_collision_id = env.model.geom_name2id("cup_base_table_contact") + self.ground_collision_id = {env.model.geom_name2id("ground")} + # self.ground_collision_id = env.model.geom_name2id("ground") + self.cup_collision_ids = set(env.model.geom_name2id(name) for name in self.cup_collision_objects) + # self.cup_collision_ids = [env.model.geom_name2id(name) for name in self.cup_collision_objects] + self.robot_collision_ids = [env.model.geom_name2id(name) for name in self.robot_collision_objects] def compute_reward(self, env, action): - goal_pos = env.sim.data.site_xpos[self.goal_id] - ball_pos = env.sim.data.body_xpos[self.ball_id] - ball_vel = env.sim.data.body_xvelp[self.ball_id] - goal_final_pos = env.sim.data.site_xpos[self.goal_final_id] + goal_pos = env.data.get_site_xpos("cup_goal_table") + ball_pos = env.data.get_body_xpos("ball") + ball_vel = env.data.get_body_xvelp("ball") + goal_final_pos = env.data.get_site_xpos("cup_goal_final_table") self.check_contacts(env.sim) self.dists.append(np.linalg.norm(goal_pos - ball_pos)) @@ -77,16 +94,16 @@ class BeerPongReward: if self.ball_ground_contact_first and self.dist_ground_cup == -1 else self.dist_ground_cup action_cost = np.sum(np.square(action)) self.action_costs.append(np.copy(action_cost)) - # # ##################### Reward function which does not force to bounce once on the table (quad dist) ############ + # # ##################### Reward function which does not force to bounce once on the table (quad dist) ######### - self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) + # Comment Onur: Is this needed? + # self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) - if env._steps == env.ep_length - 1 or self._is_collided: + if env._steps == env.ep_length - 1:# or self._is_collided: min_dist = np.min(self.dists) final_dist = self.dists_final[-1] if self.ball_ground_contact_first: - min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 2, -4 # relative rew offset when first bounding on ground - # min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 0, -6 # absolute rew offset when first bouncing on ground + min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 2, -4 else: if not self.ball_in_cup: if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact: @@ -95,85 +112,74 @@ class BeerPongReward: min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 0, -2 else: min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 0, 1, 0, 0 - # dist_ground_cup = 1 * self.dist_ground_cup action_cost = 1e-4 * np.mean(action_cost) reward = rew_offset - min_dist_coeff * min_dist ** 2 - final_dist_coeff * final_dist ** 2 - \ action_cost - ground_contact_dist_coeff * self.dist_ground_cup ** 2 - # 1e-7*np.mean(action_cost) # release step punishment min_time_bound = 0.1 max_time_bound = 1.0 release_time = env.release_step * env.dt - release_time_rew = int(release_time < min_time_bound) * (-30 - 10 * (release_time - min_time_bound) ** 2) \ - + int(release_time > max_time_bound) * (-30 - 10 * (release_time - max_time_bound) ** 2) + release_time_rew = int(release_time < min_time_bound) * (-30 - 10 * (release_time - min_time_bound) ** 2) + \ + int(release_time > max_time_bound) * (-30 - 10 * (release_time - max_time_bound) ** 2) reward += release_time_rew success = self.ball_in_cup - # print('release time :', release_time) - # print('dist_ground_cup :', dist_ground_cup) else: action_cost = 1e-2 * action_cost reward = - action_cost - # reward = - 1e-4 * action_cost - # reward = 0 success = False - # ################################################################################################################ - infos = {} - infos["success"] = success - infos["is_collided"] = self._is_collided - infos["ball_pos"] = ball_pos.copy() - infos["ball_vel"] = ball_vel.copy() - infos["action_cost"] = action_cost - infos["task_reward"] = reward + # ############################################################################################################## + infos = {"success": success, "ball_pos": ball_pos.copy(), + "ball_vel": ball_vel.copy(), "action_cost": action_cost, "task_reward": reward, "is_collided": False} # TODO: Check if is collided is needed return reward, infos def check_contacts(self, sim): if not self.ball_table_contact: - self.ball_table_contact = self._check_collision_single_objects(sim, self.ball_collision_id, - self.table_collision_id) + self.ball_table_contact = self._check_collision(sim, self.ball_collision_id, self.table_collision_id) if not self.ball_cup_contact: - self.ball_cup_contact = self._check_collision_with_set_of_objects(sim, self.ball_collision_id, - self.cup_collision_ids) + self.ball_cup_contact = self._check_collision(sim, self.ball_collision_id, self.cup_collision_ids) if not self.ball_wall_contact: - self.ball_wall_contact = self._check_collision_single_objects(sim, self.ball_collision_id, - self.wall_collision_id) + self.ball_wall_contact = self._check_collision(sim, self.ball_collision_id, self.wall_collision_id) if not self.ball_in_cup: - self.ball_in_cup = self._check_collision_single_objects(sim, self.ball_collision_id, - self.cup_table_collision_id) + self.ball_in_cup = self._check_collision(sim, self.ball_collision_id, self.cup_table_collision_id) if not self.ball_ground_contact_first: - if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact and not self.ball_in_cup: - self.ball_ground_contact_first = self._check_collision_single_objects(sim, self.ball_collision_id, - self.ground_collision_id) + if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact \ + and not self.ball_in_cup: + self.ball_ground_contact_first = self._check_collision(sim, self.ball_collision_id, + self.ground_collision_id) - def _check_collision_single_objects(self, sim, id_1, id_2): - for coni in range(0, sim.data.ncon): + # Checks if id_set1 has a collision with id_set2 + def _check_collision(self, sim, id_set_1, id_set_2): + """ + If id_set_2 is set to None, it will check for a collision with itself (id_set_1). + """ + collision_id_set = id_set_2 - id_set_1 if id_set_2 is not None else id_set_1 + for coni in range(sim.data.ncon): con = sim.data.contact[coni] - - collision = con.geom1 == id_1 and con.geom2 == id_2 - collision_trans = con.geom1 == id_2 and con.geom2 == id_1 - - if collision or collision_trans: + if ((con.geom1 in id_set_1 and con.geom2 in collision_id_set) or + (con.geom2 in id_set_1 and con.geom1 in collision_id_set)): return True return False - def _check_collision_with_itself(self, sim, collision_ids): - col_1, col_2 = False, False - for j, id in enumerate(collision_ids): - col_1 = self._check_collision_with_set_of_objects(sim, id, collision_ids[:j]) - if j != len(collision_ids) - 1: - col_2 = self._check_collision_with_set_of_objects(sim, id, collision_ids[j + 1:]) - else: - col_2 = False - collision = True if col_1 or col_2 else False - return collision + # def _check_collision_with_itself(self, sim, collision_ids): + # col_1, col_2 = False, False + # for j, id in enumerate(collision_ids): + # col_1 = self._check_collision_with_set_of_objects(sim, id, collision_ids[:j]) + # if j != len(collision_ids) - 1: + # col_2 = self._check_collision_with_set_of_objects(sim, id, collision_ids[j + 1:]) + # else: + # col_2 = False + # collision = True if col_1 or col_2 else False + # return collision - def _check_collision_with_set_of_objects(self, sim, id_1, id_list): - for coni in range(0, sim.data.ncon): - con = sim.data.contact[coni] - - collision = con.geom1 in id_list and con.geom2 == id_1 - collision_trans = con.geom1 == id_1 and con.geom2 in id_list - - if collision or collision_trans: - return True - return False + ### This function will not be needed if we really do not need to check for collision with itself + # def _check_collision_with_set_of_objects(self, sim, id_1, id_list): + # for coni in range(0, sim.data.ncon): + # con = sim.data.contact[coni] + # + # collision = con.geom1 in id_list and con.geom2 == id_1 + # collision_trans = con.geom1 == id_1 and con.geom2 in id_list + # + # if collision or collision_trans: + # return True + # return False diff --git a/alr_envs/alr/mujoco/reacher/__init__.py b/alr_envs/alr/mujoco/reacher/__init__.py index 8a04a02..c5e6d2f 100644 --- a/alr_envs/alr/mujoco/reacher/__init__.py +++ b/alr_envs/alr/mujoco/reacher/__init__.py @@ -1 +1 @@ -from .new_mp_wrapper import MPWrapper +from .mp_wrapper import MPWrapper diff --git a/alr_envs/utils/make_env_helpers.py b/alr_envs/utils/make_env_helpers.py index 3a8eec5..b5587a7 100644 --- a/alr_envs/utils/make_env_helpers.py +++ b/alr_envs/utils/make_env_helpers.py @@ -7,12 +7,12 @@ import numpy as np from gym.envs.registration import EnvSpec, registry from gym.wrappers import TimeAwareObservation -from alr_envs.black_box.factory.basis_generator_factory import get_basis_generator -from alr_envs.black_box.black_box_wrapper import BlackBoxWrapper -from alr_envs.black_box.controller.controller_factory import get_controller -from alr_envs.black_box.factory.trajectory_generator_factory import get_trajectory_generator -from alr_envs.black_box.factory.phase_generator_factory import get_phase_generator -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.mp.basis_generator_factory import get_basis_generator +from alr_envs.mp.black_box_wrapper import BlackBoxWrapper +from alr_envs.mp.controllers.controller_factory import get_controller +from alr_envs.mp.mp_factory import get_trajectory_generator +from alr_envs.mp.phase_generator_factory import get_phase_generator +from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper from alr_envs.utils.utils import nested_update @@ -46,7 +46,6 @@ def make(env_id, seed, **kwargs): spec = registry.get(env_id) # This access is required to allow for nested dict updates all_kwargs = deepcopy(spec._kwargs) - # TODO append wrapper here nested_update(all_kwargs, **kwargs) return _make(env_id, seed, **all_kwargs) @@ -225,8 +224,8 @@ def make_bb_env_helper(**kwargs): seed = kwargs.pop("seed", None) wrappers = kwargs.pop("wrappers") - black_box_kwargs = kwargs.pop('black_box_kwargs', {}) traj_gen_kwargs = kwargs.pop("traj_gen_kwargs", {}) + black_box_kwargs = kwargs.pop('black_box_kwargs', {}) contr_kwargs = kwargs.pop("controller_kwargs", {}) phase_kwargs = kwargs.pop("phase_generator_kwargs", {}) basis_kwargs = kwargs.pop("basis_generator_kwargs", {}) From 4437ab9577dc07b7b7b8c2123cb59ff6df41a689 Mon Sep 17 00:00:00 2001 From: Onur Date: Thu, 30 Jun 2022 18:17:02 +0200 Subject: [PATCH 053/104] change accessing body position in beerpong.py --- alr_envs/alr/mujoco/beerpong/beerpong.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 117003f..11c09e4 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -144,16 +144,15 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): infos.update(reward_infos) return ob, reward, done, infos - def _check_traj_in_joint_limits(self): - return any(self.current_pos > self.j_max) or any(self.current_pos < self.j_min) + # def _check_traj_in_joint_limits(self): + # return any(self.current_pos > self.j_max) or any(self.current_pos < self.j_min) def _get_obs(self): theta = self.sim.data.qpos.flat[:7] theta_dot = self.sim.data.qvel.flat[:7] - ball_pos = self.sim.data.body_xpos[self.sim.model._body_name2id["ball"]].copy() - cup_goal_diff_final = ball_pos - self.sim.data.site_xpos[ - self.sim.model._site_name2id["cup_goal_final_table"]].copy() - cup_goal_diff_top = ball_pos - self.sim.data.site_xpos[self.sim.model._site_name2id["cup_goal_table"]].copy() + ball_pos = self.data.get_body_xpos("ball").copy() + cup_goal_diff_final = ball_pos - self.data.get_site_xpos("cup_goal_final_table").copy() + cup_goal_diff_top = ball_pos - self.data.get_site_xpos("cup_goal_table").copy() return np.concatenate([ np.cos(theta), np.sin(theta), From d4e3b957a9693ee64cd6e1fc0b363a13dc291692 Mon Sep 17 00:00:00 2001 From: Onur Date: Fri, 1 Jul 2022 09:54:42 +0200 Subject: [PATCH 054/104] finish up beerpong, walker2d and ant needs more extensions, fix import bugs. --- alr_envs/alr/__init__.py | 11 +++- .../hole_reacher/mp_wrapper.py | 2 +- alr_envs/alr/mujoco/__init__.py | 1 - alr_envs/alr/mujoco/ant_jump/ant_jump.py | 25 ++++---- alr_envs/alr/mujoco/beerpong/beerpong.py | 57 +++++-------------- .../mujoco/beerpong/beerpong_reward_staged.py | 16 +++--- .../mujoco/walker_2d_jump/assets/walker2d.xml | 4 +- .../mujoco/walker_2d_jump/walker_2d_jump.py | 28 ++++----- alr_envs/utils/make_env_helpers.py | 12 ++-- 9 files changed, 62 insertions(+), 94 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 3d2415c..459a0e6 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -218,8 +218,15 @@ register( entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', max_episode_steps=300, kwargs={ - "rndm_goal": True, - "cup_goal_pos": [-0.3, -1.2], + "frame_skip": 2 + } +) + +register( + id='ALRBeerPong-v1', + entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', + max_episode_steps=300, + kwargs={ "frame_skip": 2 } ) diff --git a/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py index 85bc784..0a5eaa6 100644 --- a/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py +++ b/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index df52cfc..359f97b 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -7,6 +7,5 @@ from .hopper_jump.hopper_jump_on_box import ALRHopperJumpOnBoxEnv from .hopper_throw.hopper_throw import ALRHopperThrowEnv from .hopper_throw.hopper_throw_in_basket import ALRHopperThrowInBasketEnv from .reacher.reacher import ReacherEnv -from .reacher.balancing import BalancingEnv from .table_tennis.tt_gym import TTEnvGym from .walker_2d_jump.walker_2d_jump import ALRWalker2dJumpEnv diff --git a/alr_envs/alr/mujoco/ant_jump/ant_jump.py b/alr_envs/alr/mujoco/ant_jump/ant_jump.py index 09c623d..27098ac 100644 --- a/alr_envs/alr/mujoco/ant_jump/ant_jump.py +++ b/alr_envs/alr/mujoco/ant_jump/ant_jump.py @@ -2,6 +2,10 @@ import numpy as np from gym.envs.mujoco.ant_v3 import AntEnv MAX_EPISODE_STEPS_ANTJUMP = 200 +# TODO: This environment was not testet yet. Do the following todos and test it. +# TODO: Right now this environment only considers jumping to a specific height, which is not nice. It should be extended +# to the same structure as the Hopper, where the angles are randomized (->contexts) and the agent should jump as heigh +# as possible, while landing at a specific target position class ALRAntJumpEnv(AntEnv): @@ -22,14 +26,12 @@ class ALRAntJumpEnv(AntEnv): healthy_z_range=(0.3, float('inf')), contact_force_range=(-1.0, 1.0), reset_noise_scale=0.1, - context=True, # variable to decide if context is used or not exclude_current_positions_from_observation=True, max_episode_steps=200): self.current_step = 0 self.max_height = 0 - self.context = context self.max_episode_steps = max_episode_steps - self.goal = 0 # goal when training with context + self.goal = 0 super().__init__(xml_file, ctrl_cost_weight, contact_cost_weight, healthy_reward, terminate_when_unhealthy, healthy_z_range, contact_force_range, reset_noise_scale, exclude_current_positions_from_observation) @@ -53,15 +55,11 @@ class ALRAntJumpEnv(AntEnv): done = height < 0.3 # fall over -> is the 0.3 value from healthy_z_range? TODO change 0.3 to the value of healthy z angle if self.current_step == self.max_episode_steps or done: - if self.context: - # -10 for scaling the value of the distance between the max_height and the goal height; only used when context is enabled - # height_reward = -10 * (np.linalg.norm(self.max_height - self.goal)) - height_reward = -10*np.linalg.norm(self.max_height - self.goal) - # no healthy reward when using context, because we optimize a negative value - healthy_reward = 0 - else: - height_reward = self.max_height - 0.7 - healthy_reward = self.healthy_reward * self.current_step + # -10 for scaling the value of the distance between the max_height and the goal height; only used when context is enabled + # height_reward = -10 * (np.linalg.norm(self.max_height - self.goal)) + height_reward = -10*np.linalg.norm(self.max_height - self.goal) + # no healthy reward when using context, because we optimize a negative value + healthy_reward = 0 rewards = height_reward + healthy_reward @@ -105,7 +103,6 @@ if __name__ == '__main__': obs = env.reset() for i in range(2000): - # objective.load_result("/tmp/cma") # test with random actions ac = env.action_space.sample() obs, rew, d, info = env.step(ac) @@ -114,4 +111,4 @@ if __name__ == '__main__': if d: env.reset() - env.close() \ No newline at end of file + env.close() diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 11c09e4..218df6d 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -7,16 +7,6 @@ from gym.envs.mujoco import MujocoEnv from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward -CUP_POS_MIN = np.array([-1.42, -4.05]) -CUP_POS_MAX = np.array([1.42, -1.25]) - - -# CUP_POS_MIN = np.array([-0.32, -2.2]) -# CUP_POS_MAX = np.array([0.32, -1.2]) - -# smaller context space -> Easier task -# CUP_POS_MIN = np.array([-0.16, -2.2]) -# CUP_POS_MAX = np.array([0.16, -1.7]) class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): def __init__(self, frame_skip=2, apply_gravity_comp=True): @@ -27,10 +17,16 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.cup_goal_pos = np.array(cup_goal_pos) self._steps = 0 + # Small Context -> Easier. Todo: Should we do different versions? # self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", # "beerpong_wo_cup" + ".xml") + # self.cup_pos_min = np.array([-0.32, -2.2]) + # self.cup_pos_max = np.array([0.32, -1.2]) + self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", "beerpong_wo_cup_big_table" + ".xml") + self.cup_pos_min = np.array([-1.42, -4.05]) + self.cup_pos_max = np.array([1.42, -1.25]) self.j_min = np.array([-2.6, -1.985, -2.8, -0.9, -4.55, -1.5707, -2.7]) self.j_max = np.array([2.6, 1.985, 2.8, 3.14159, 1.25, 1.5707, 2.7]) @@ -49,9 +45,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.cup_table_id = 10 self.add_noise = False - - reward_function = BeerPongReward - self.reward_function = reward_function() + self.reward_function = BeerPongReward() self.repeat_action = frame_skip MujocoEnv.__init__(self, self.xml_path, frame_skip=1) utils.EzPickle.__init__(self) @@ -78,10 +72,11 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): start_pos = init_pos_all start_pos[0:7] = init_pos_robot + # TODO: Ask Max why we need to set the state twice. self.set_state(start_pos, init_vel) start_pos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() self.set_state(start_pos, init_vel) - xy = self.np_random.uniform(CUP_POS_MIN, CUP_POS_MAX) + xy = self.np_random.uniform(self.cup_pos_min, self.cup_pos_max) xyz = np.zeros(3) xyz[:2] = xy xyz[-1] = 0.840 @@ -89,9 +84,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): return self._get_obs() def step(self, a): - reward_dist = 0.0 - angular_vel = 0.0 - + crash = False for _ in range(self.repeat_action): if self.apply_gravity_comp: applied_action = a + self.sim.data.qfrc_bias[:len(a)].copy() / self.model.actuator_gear[:, 0] @@ -100,7 +93,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): try: self.do_simulation(applied_action, self.frame_skip) self.reward_function.initialize(self) - self.reward_function.check_contacts(self.sim) + # self.reward_function.check_contacts(self.sim) # I assume this is not important? if self._steps < self.release_step: self.sim.data.qpos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() self.sim.data.qvel[7::] = self.sim.data.site_xvelp[self.ball_site_id, :].copy() @@ -112,34 +105,19 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): if not crash: reward, reward_infos = self.reward_function.compute_reward(self, applied_action) - success = reward_infos['success'] is_collided = reward_infos['is_collided'] - ball_pos = reward_infos['ball_pos'] - ball_vel = reward_infos['ball_vel'] done = is_collided or self._steps == self.ep_length - 1 self._steps += 1 else: reward = -30 - reward_infos = dict() - success = False - is_collided = False done = True - ball_pos = np.zeros(3) - ball_vel = np.zeros(3) + reward_infos = {"success": False, "ball_pos": np.zeros(3), "ball_vel": np.zeros(3), "is_collided": False} infos = dict( - reward_dist=reward_dist, reward=reward, - velocity=angular_vel, - # traj=self._q_pos, action=a, q_pos=self.sim.data.qpos[0:7].ravel().copy(), - q_vel=self.sim.data.qvel[0:7].ravel().copy(), - ball_pos=ball_pos, - ball_vel=ball_vel, - success=success, - is_collided=is_collided, sim_crash=crash, - table_contact_first=int(not self.reward_function.ball_ground_contact_first) + q_vel=self.sim.data.qvel[0:7].ravel().copy(), sim_crash=crash, ) infos.update(reward_infos) return ob, reward, done, infos @@ -239,14 +217,7 @@ if __name__ == "__main__": env.reset() env.render("human") for i in range(1500): - # ac = 10 * env.action_space.sample() - ac = np.ones(7) - # ac = np.zeros(7) - # ac[0] = 0 - # ac[1] = -0.01 - # ac[3] = -0.01 - # if env._steps > 150: - # ac[0] = 1 + ac = 10 * env.action_space.sample() obs, rew, d, info = env.step(ac) env.render("human") print(env.dt) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index cd2ab75..807fb19 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -21,12 +21,9 @@ class BeerPongReward: self.cup_collision_objects = ["cup_geom_table3", "cup_geom_table4", "cup_geom_table5", "cup_geom_table6", "cup_geom_table7", "cup_geom_table8", "cup_geom_table9", "cup_geom_table10", - # "cup_base_table", "cup_base_table_contact", "cup_geom_table15", "cup_geom_table16", "cup_geom_table17", "cup_geom1_table8", - # "cup_base_table_contact", - # "cup_base_table" ] self.dists = None @@ -39,7 +36,7 @@ class BeerPongReward: self.ball_in_cup = False self.dist_ground_cup = -1 # distance floor to cup if first floor contact - ### IDs + # IDs self.ball_collision_id = None self.table_collision_id = None self.wall_collision_id = None @@ -96,10 +93,10 @@ class BeerPongReward: self.action_costs.append(np.copy(action_cost)) # # ##################### Reward function which does not force to bounce once on the table (quad dist) ######### - # Comment Onur: Is this needed? + # Is this needed? # self._is_collided = self._check_collision_with_itself(env.sim, self.robot_collision_ids) - if env._steps == env.ep_length - 1:# or self._is_collided: + if env._steps == env.ep_length - 1: # or self._is_collided: min_dist = np.min(self.dists) final_dist = self.dists_final[-1] if self.ball_ground_contact_first: @@ -128,9 +125,10 @@ class BeerPongReward: reward = - action_cost success = False # ############################################################################################################## - infos = {"success": success, "ball_pos": ball_pos.copy(), - "ball_vel": ball_vel.copy(), "action_cost": action_cost, "task_reward": reward, "is_collided": False} # TODO: Check if is collided is needed - + infos = {"success": success, "ball_pos": ball_pos.copy(), + "ball_vel": ball_vel.copy(), "action_cost": action_cost, "task_reward": reward, + "table_contact_first": int(not self.ball_ground_contact_first), + "is_collided": False} # TODO: Check if is collided is needed return reward, infos def check_contacts(self, sim): diff --git a/alr_envs/alr/mujoco/walker_2d_jump/assets/walker2d.xml b/alr_envs/alr/mujoco/walker_2d_jump/assets/walker2d.xml index 1b48e36..f3bcbd1 100644 --- a/alr_envs/alr/mujoco/walker_2d_jump/assets/walker2d.xml +++ b/alr_envs/alr/mujoco/walker_2d_jump/assets/walker2d.xml @@ -21,6 +21,7 @@ + @@ -34,6 +35,7 @@ + @@ -59,4 +61,4 @@ - \ No newline at end of file + diff --git a/alr_envs/alr/mujoco/walker_2d_jump/walker_2d_jump.py b/alr_envs/alr/mujoco/walker_2d_jump/walker_2d_jump.py index 009dd9d..1ab0d29 100644 --- a/alr_envs/alr/mujoco/walker_2d_jump/walker_2d_jump.py +++ b/alr_envs/alr/mujoco/walker_2d_jump/walker_2d_jump.py @@ -4,6 +4,10 @@ import numpy as np MAX_EPISODE_STEPS_WALKERJUMP = 300 +# TODO: Right now this environment only considers jumping to a specific height, which is not nice. It should be extended +# to the same structure as the Hopper, where the angles are randomized (->contexts) and the agent should jump as height +# as possible, while landing at a specific target position + class ALRWalker2dJumpEnv(Walker2dEnv): """ @@ -21,14 +25,12 @@ class ALRWalker2dJumpEnv(Walker2dEnv): healthy_angle_range=(-1.0, 1.0), reset_noise_scale=5e-3, penalty=0, - context=True, exclude_current_positions_from_observation=True, max_episode_steps=300): self.current_step = 0 self.max_episode_steps = max_episode_steps self.max_height = 0 self._penalty = penalty - self.context = context self.goal = 0 xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, @@ -43,31 +45,24 @@ class ALRWalker2dJumpEnv(Walker2dEnv): self.max_height = max(height, self.max_height) - fell_over = height < 0.2 - done = fell_over + done = height < 0.2 ctrl_cost = self.control_cost(action) costs = ctrl_cost - + rewards = 0 if self.current_step >= self.max_episode_steps or done: done = True - height_goal_distance = -10 * (np.linalg.norm(self.max_height - self.goal)) if self.context else self.max_height + height_goal_distance = -10 * (np.linalg.norm(self.max_height - self.goal)) healthy_reward = self.healthy_reward * self.current_step rewards = height_goal_distance + healthy_reward - else: - # penalty not needed - rewards = 0 - rewards += ((action[:2] > 0) * self._penalty).sum() if self.current_step < 4 else 0 - rewards += ((action[3:5] > 0) * self._penalty).sum() if self.current_step < 4 else 0 - observation = self._get_obs() reward = rewards - costs info = { 'height': height, 'max_height': self.max_height, - 'goal' : self.goal, + 'goal': self.goal, } return observation, reward, done, info @@ -78,7 +73,7 @@ class ALRWalker2dJumpEnv(Walker2dEnv): def reset(self): self.current_step = 0 self.max_height = 0 - self.goal = np.random.uniform(1.5, 2.5, 1) # 1.5 3.0 + self.goal = np.random.uniform(1.5, 2.5, 1) # 1.5 3.0 return super().reset() # overwrite reset_model to make it deterministic @@ -99,8 +94,7 @@ if __name__ == '__main__': env = ALRWalker2dJumpEnv() obs = env.reset() - for i in range(2000): - # objective.load_result("/tmp/cma") + for i in range(6000): # test with random actions ac = env.action_space.sample() obs, rew, d, info = env.step(ac) @@ -110,4 +104,4 @@ if __name__ == '__main__': print('After ', i, ' steps, done: ', d) env.reset() - env.close() \ No newline at end of file + env.close() diff --git a/alr_envs/utils/make_env_helpers.py b/alr_envs/utils/make_env_helpers.py index b5587a7..57b4c69 100644 --- a/alr_envs/utils/make_env_helpers.py +++ b/alr_envs/utils/make_env_helpers.py @@ -7,12 +7,12 @@ import numpy as np from gym.envs.registration import EnvSpec, registry from gym.wrappers import TimeAwareObservation -from alr_envs.mp.basis_generator_factory import get_basis_generator -from alr_envs.mp.black_box_wrapper import BlackBoxWrapper -from alr_envs.mp.controllers.controller_factory import get_controller -from alr_envs.mp.mp_factory import get_trajectory_generator -from alr_envs.mp.phase_generator_factory import get_phase_generator -from alr_envs.mp.raw_interface_wrapper import RawInterfaceWrapper +from alr_envs.black_box.black_box_wrapper import BlackBoxWrapper +from alr_envs.black_box.controller.controller_factory import get_controller +from alr_envs.black_box.factory.basis_generator_factory import get_basis_generator +from alr_envs.black_box.factory.phase_generator_factory import get_phase_generator +from alr_envs.black_box.factory.trajectory_generator_factory import get_trajectory_generator +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper from alr_envs.utils.utils import nested_update From 2161cfd3a6e0c0d52cc4f7cf789653a4abdfd95a Mon Sep 17 00:00:00 2001 From: Onur Date: Fri, 1 Jul 2022 11:42:42 +0200 Subject: [PATCH 055/104] Fix bugs to create mp environments. Still conflicts with mp_pytorch_lib --- alr_envs/alr/__init__.py | 2 +- alr_envs/alr/classic_control/viapoint_reacher/__init__.py | 2 +- alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py | 5 +++-- alr_envs/black_box/black_box_wrapper.py | 5 ++--- alr_envs/black_box/raw_interface_wrapper.py | 5 +++-- alr_envs/utils/make_env_helpers.py | 7 ++++--- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 459a0e6..53828ed 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -428,7 +428,7 @@ for _v in _versions: kwargs_dict_bp_promp['name'] = f"alr_envs:{_v}" register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_bp_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) diff --git a/alr_envs/alr/classic_control/viapoint_reacher/__init__.py b/alr_envs/alr/classic_control/viapoint_reacher/__init__.py index a919c3a..c5e6d2f 100644 --- a/alr_envs/alr/classic_control/viapoint_reacher/__init__.py +++ b/alr_envs/alr/classic_control/viapoint_reacher/__init__.py @@ -1 +1 @@ -from new_mp_wrapper import MPWrapper +from .mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py index bd22442..e447a49 100644 --- a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py @@ -25,8 +25,9 @@ class MPWrapper(RawInterfaceWrapper): [False] # env steps ]) - def _episode_callback(self, action: np.ndarray) -> Tuple[np.ndarray, Union[np.ndarray, None]]: - if self.mp.learn_tau: + # TODO: Fix this + def _episode_callback(self, action: np.ndarray, mp) -> Tuple[np.ndarray, Union[np.ndarray, None]]: + if mp.learn_tau: self.env.env.release_step = action[0] / self.env.dt # Tau value return action, None else: diff --git a/alr_envs/black_box/black_box_wrapper.py b/alr_envs/black_box/black_box_wrapper.py index 0c10ef8..43cc4f0 100644 --- a/alr_envs/black_box/black_box_wrapper.py +++ b/alr_envs/black_box/black_box_wrapper.py @@ -1,4 +1,3 @@ -from abc import ABC from typing import Tuple, Union import gym @@ -80,7 +79,7 @@ class BlackBoxWrapper(gym.ObservationWrapper): bc_time=np.zeros((1,)) if not self.replanning_schedule else self.current_traj_steps * self.dt, bc_pos=self.current_pos, bc_vel=self.current_vel) # TODO: is this correct for replanning? Do we need to adjust anything here? - self.traj_gen.set_duration(None if self.learn_sub_trajectories else self.duration, np.array([self.dt])) + self.traj_gen.set_duration(None if self.learn_sub_trajectories else np.array([self.duration]), np.array([self.dt])) traj_dict = self.traj_gen.get_trajs(get_pos=True, get_vel=True) trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] @@ -109,7 +108,7 @@ class BlackBoxWrapper(gym.ObservationWrapper): """ This function generates a trajectory based on a MP and then does the usual loop over reset and step""" # agent to learn when to release the ball - mp_params, env_spec_params = self._episode_callback(action) + mp_params, env_spec_params = self.env._episode_callback(action, self.traj_gen) trajectory, velocity = self.get_trajectory(mp_params) trajectory_length = len(trajectory) diff --git a/alr_envs/black_box/raw_interface_wrapper.py b/alr_envs/black_box/raw_interface_wrapper.py index fdbc2f7..becbfe3 100644 --- a/alr_envs/black_box/raw_interface_wrapper.py +++ b/alr_envs/black_box/raw_interface_wrapper.py @@ -1,8 +1,9 @@ from typing import Union, Tuple +from mp_pytorch.mp.mp_interfaces import MPInterface +from abc import abstractmethod import gym import numpy as np -from abc import abstractmethod class RawInterfaceWrapper(gym.Wrapper): @@ -56,7 +57,7 @@ class RawInterfaceWrapper(gym.Wrapper): # return bool(self.replanning_model(s)) return False - def _episode_callback(self, action: np.ndarray) -> Tuple[np.ndarray, Union[np.ndarray, None]]: + def _episode_callback(self, action: np.ndarray, traj_gen: MPInterface) -> Tuple[np.ndarray, Union[np.ndarray, None]]: """ Used to extract the parameters for the motion primitive and other parameters from an action array which might include other actions like ball releasing time for the beer pong environment. diff --git a/alr_envs/utils/make_env_helpers.py b/alr_envs/utils/make_env_helpers.py index 57b4c69..0051546 100644 --- a/alr_envs/utils/make_env_helpers.py +++ b/alr_envs/utils/make_env_helpers.py @@ -43,10 +43,11 @@ def make_rank(env_id: str, seed: int, rank: int = 0, return_callable=True, **kwa def make(env_id, seed, **kwargs): - spec = registry.get(env_id) + # spec = registry.get(env_id) # TODO: This doesn't work with gym ==0.21.0 + spec = registry.spec(env_id) # This access is required to allow for nested dict updates all_kwargs = deepcopy(spec._kwargs) - nested_update(all_kwargs, **kwargs) + nested_update(all_kwargs, kwargs) return _make(env_id, seed, **all_kwargs) @@ -224,7 +225,7 @@ def make_bb_env_helper(**kwargs): seed = kwargs.pop("seed", None) wrappers = kwargs.pop("wrappers") - traj_gen_kwargs = kwargs.pop("traj_gen_kwargs", {}) + traj_gen_kwargs = kwargs.pop("trajectory_generator_kwargs", {}) black_box_kwargs = kwargs.pop('black_box_kwargs', {}) contr_kwargs = kwargs.pop("controller_kwargs", {}) phase_kwargs = kwargs.pop("phase_generator_kwargs", {}) From d80df03145a30a3727fb41ce45826ffb546a4001 Mon Sep 17 00:00:00 2001 From: Onur Date: Mon, 4 Jul 2022 11:29:51 +0200 Subject: [PATCH 056/104] minor changes at beerpong during call with Fabian --- alr_envs/alr/mujoco/__init__.py | 2 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 42 +++++++------------ .../mujoco/beerpong/beerpong_reward_staged.py | 2 +- 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index 359f97b..ac10cda 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -1,7 +1,7 @@ from .ant_jump.ant_jump import ALRAntJumpEnv from .ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv from .ball_in_a_cup.biac_pd import ALRBallInACupPDEnv -from .beerpong.beerpong import ALRBeerBongEnv +from .beerpong.beerpong import BeerPongEnv from .half_cheetah_jump.half_cheetah_jump import ALRHalfCheetahJumpEnv from .hopper_jump.hopper_jump_on_box import ALRHopperJumpOnBoxEnv from .hopper_throw.hopper_throw import ALRHopperThrowEnv diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 218df6d..5415073 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -8,14 +8,9 @@ from gym.envs.mujoco import MujocoEnv from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward -class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): +class BeerPongEnv(MujocoEnv, utils.EzPickle): + # TODO: always use gravity compensation def __init__(self, frame_skip=2, apply_gravity_comp=True): - - cup_goal_pos = np.array([-0.3, -1.2, 0.840]) - if cup_goal_pos.shape[0] == 2: - cup_goal_pos = np.insert(cup_goal_pos, 2, 0.840) - self.cup_goal_pos = np.array(cup_goal_pos) - self._steps = 0 # Small Context -> Easier. Todo: Should we do different versions? # self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", @@ -25,26 +20,22 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", "beerpong_wo_cup_big_table" + ".xml") - self.cup_pos_min = np.array([-1.42, -4.05]) - self.cup_pos_max = np.array([1.42, -1.25]) - - self.j_min = np.array([-2.6, -1.985, -2.8, -0.9, -4.55, -1.5707, -2.7]) - self.j_max = np.array([2.6, 1.985, 2.8, 3.14159, 1.25, 1.5707, 2.7]) + self._cup_pos_min = np.array([-1.42, -4.05]) + self._cup_pos_max = np.array([1.42, -1.25]) self.apply_gravity_comp = apply_gravity_comp self._start_pos = np.array([0.0, 1.35, 0.0, 1.18, 0.0, -0.786, -1.59]) self._start_vel = np.zeros(7) + # TODO: check if we need to define that in the constructor? self.ball_site_id = 0 self.ball_id = 11 - - self.release_step = 100 # time step of ball release - - self.ep_length = 600 // frame_skip self.cup_table_id = 10 - self.add_noise = False + self.release_step = 100 # time step of ball release + self.ep_length = 600 // frame_skip + self.reward_function = BeerPongReward() self.repeat_action = frame_skip MujocoEnv.__init__(self, self.xml_path, frame_skip=1) @@ -76,7 +67,7 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): self.set_state(start_pos, init_vel) start_pos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() self.set_state(start_pos, init_vel) - xy = self.np_random.uniform(self.cup_pos_min, self.cup_pos_max) + xy = self.np_random.uniform(self._cup_pos_min, self._cup_pos_max) xyz = np.zeros(3) xyz[:2] = xy xyz[-1] = 0.840 @@ -122,9 +113,6 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): infos.update(reward_infos) return ob, reward, done, infos - # def _check_traj_in_joint_limits(self): - # return any(self.current_pos > self.j_max) or any(self.current_pos < self.j_min) - def _get_obs(self): theta = self.sim.data.qpos.flat[:7] theta_dot = self.sim.data.qvel.flat[:7] @@ -143,28 +131,28 @@ class ALRBeerBongEnv(MujocoEnv, utils.EzPickle): @property def dt(self): - return super(ALRBeerBongEnv, self).dt * self.repeat_action + return super(BeerPongEnv, self).dt * self.repeat_action -class ALRBeerBongEnvFixedReleaseStep(ALRBeerBongEnv): +class BeerPongEnvFixedReleaseStep(BeerPongEnv): def __init__(self, frame_skip=2, apply_gravity_comp=True): super().__init__(frame_skip, apply_gravity_comp) self.release_step = 62 # empirically evaluated for frame_skip=2! -class ALRBeerBongEnvStepBasedEpisodicReward(ALRBeerBongEnv): +class BeerPongEnvStepBasedEpisodicReward(BeerPongEnv): def __init__(self, frame_skip=2, apply_gravity_comp=True): super().__init__(frame_skip, apply_gravity_comp) self.release_step = 62 # empirically evaluated for frame_skip=2! def step(self, a): if self._steps < self.release_step: - return super(ALRBeerBongEnvStepBasedEpisodicReward, self).step(a) + return super(BeerPongEnvStepBasedEpisodicReward, self).step(a) else: reward = 0 done = False while not done: - sub_ob, sub_reward, done, sub_infos = super(ALRBeerBongEnvStepBasedEpisodicReward, self).step( + sub_ob, sub_reward, done, sub_infos = super(BeerPongEnvStepBasedEpisodicReward, self).step( np.zeros(a.shape)) reward += sub_reward infos = sub_infos @@ -208,7 +196,7 @@ class ALRBeerBongEnvStepBasedEpisodicReward(ALRBeerBongEnv): if __name__ == "__main__": - env = ALRBeerBongEnv(frame_skip=2) + env = BeerPongEnv(frame_skip=2) # env = ALRBeerBongEnvStepBased(frame_skip=2) # env = ALRBeerBongEnvStepBasedEpisodicReward(frame_skip=2) # env = ALRBeerBongEnvFixedReleaseStep(frame_skip=2) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py index 807fb19..4308921 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py @@ -73,7 +73,7 @@ class BeerPongReward: # self.cup_table_collision_id = env.model.geom_name2id("cup_base_table_contact") self.ground_collision_id = {env.model.geom_name2id("ground")} # self.ground_collision_id = env.model.geom_name2id("ground") - self.cup_collision_ids = set(env.model.geom_name2id(name) for name in self.cup_collision_objects) + self.cup_collision_ids = {env.model.geom_name2id(name) for name in self.cup_collision_objects} # self.cup_collision_ids = [env.model.geom_name2id(name) for name in self.cup_collision_objects] self.robot_collision_ids = [env.model.geom_name2id(name) for name in self.robot_collision_objects] From 4dc33b0e976505f3adfb25c11a9e04d5cc7eb8a5 Mon Sep 17 00:00:00 2001 From: Onur Date: Mon, 4 Jul 2022 19:14:31 +0200 Subject: [PATCH 057/104] slim down beerpong constructor further. Not sure, if we should merge the reward into the environment class. --- .../beerpong/assets/beerpong_wo_cup.xml | 2 +- .../assets/beerpong_wo_cup_big_table.xml | 2 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 43 ++++++++----------- alr_envs/utils/utils.py | 1 + 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml index e96d2bc..6786ecf 100644 --- a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml +++ b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup.xml @@ -123,7 +123,7 @@ - + diff --git a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml index 78e2c32..99df1d3 100644 --- a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml +++ b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml @@ -123,7 +123,7 @@ - + diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 5415073..51b3ed3 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -9,35 +9,31 @@ from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward class BeerPongEnv(MujocoEnv, utils.EzPickle): - # TODO: always use gravity compensation - def __init__(self, frame_skip=2, apply_gravity_comp=True): + def __init__(self, frame_skip=2): self._steps = 0 # Small Context -> Easier. Todo: Should we do different versions? # self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", # "beerpong_wo_cup" + ".xml") - # self.cup_pos_min = np.array([-0.32, -2.2]) - # self.cup_pos_max = np.array([0.32, -1.2]) + # self._cup_pos_min = np.array([-0.32, -2.2]) + # self._cup_pos_max = np.array([0.32, -1.2]) self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", "beerpong_wo_cup_big_table" + ".xml") self._cup_pos_min = np.array([-1.42, -4.05]) self._cup_pos_max = np.array([1.42, -1.25]) - self.apply_gravity_comp = apply_gravity_comp - self._start_pos = np.array([0.0, 1.35, 0.0, 1.18, 0.0, -0.786, -1.59]) self._start_vel = np.zeros(7) - # TODO: check if we need to define that in the constructor? - self.ball_site_id = 0 - self.ball_id = 11 - self.cup_table_id = 10 - self.release_step = 100 # time step of ball release self.ep_length = 600 // frame_skip self.reward_function = BeerPongReward() self.repeat_action = frame_skip + self.model = None + self.site_id = lambda x: self.model.site_name2id(x) + self.body_id = lambda x: self.model.body_name2id(x) + MujocoEnv.__init__(self, self.xml_path, frame_skip=1) utils.EzPickle.__init__(self) @@ -65,29 +61,26 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): # TODO: Ask Max why we need to set the state twice. self.set_state(start_pos, init_vel) - start_pos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() + start_pos[7::] = self.sim.data.site_xpos[self.site_id("init_ball_pos"), :].copy() self.set_state(start_pos, init_vel) xy = self.np_random.uniform(self._cup_pos_min, self._cup_pos_max) xyz = np.zeros(3) xyz[:2] = xy xyz[-1] = 0.840 - self.sim.model.body_pos[self.cup_table_id] = xyz + self.sim.model.body_pos[self.body_id("cup_table")] = xyz return self._get_obs() def step(self, a): crash = False for _ in range(self.repeat_action): - if self.apply_gravity_comp: - applied_action = a + self.sim.data.qfrc_bias[:len(a)].copy() / self.model.actuator_gear[:, 0] - else: - applied_action = a + applied_action = a + self.sim.data.qfrc_bias[:len(a)].copy() / self.model.actuator_gear[:, 0] try: self.do_simulation(applied_action, self.frame_skip) self.reward_function.initialize(self) # self.reward_function.check_contacts(self.sim) # I assume this is not important? if self._steps < self.release_step: - self.sim.data.qpos[7::] = self.sim.data.site_xpos[self.ball_site_id, :].copy() - self.sim.data.qvel[7::] = self.sim.data.site_xvelp[self.ball_site_id, :].copy() + self.sim.data.qpos[7::] = self.sim.data.site_xpos[self.site_id("init_ball_pos"), :].copy() + self.sim.data.qvel[7::] = self.sim.data.site_xvelp[self.site_id("init_ball_pos"), :].copy() crash = False except mujoco_py.builder.MujocoException: crash = True @@ -102,7 +95,7 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): else: reward = -30 done = True - reward_infos = {"success": False, "ball_pos": np.zeros(3), "ball_vel": np.zeros(3), "is_collided": False} + reward_infos = {"success": False, "ball_pos": np.zeros(3), "ball_vel": np.zeros(3), "is_collided": False} infos = dict( reward=reward, @@ -125,7 +118,7 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): theta_dot, cup_goal_diff_final, cup_goal_diff_top, - self.sim.model.body_pos[self.cup_table_id][:2].copy(), + self.sim.model.body_pos[self.body_id("cup_table")][:2].copy(), [self._steps], ]) @@ -135,14 +128,14 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): class BeerPongEnvFixedReleaseStep(BeerPongEnv): - def __init__(self, frame_skip=2, apply_gravity_comp=True): - super().__init__(frame_skip, apply_gravity_comp) + def __init__(self, frame_skip=2): + super().__init__(frame_skip) self.release_step = 62 # empirically evaluated for frame_skip=2! class BeerPongEnvStepBasedEpisodicReward(BeerPongEnv): - def __init__(self, frame_skip=2, apply_gravity_comp=True): - super().__init__(frame_skip, apply_gravity_comp) + def __init__(self, frame_skip=2): + super().__init__(frame_skip) self.release_step = 62 # empirically evaluated for frame_skip=2! def step(self, a): diff --git a/alr_envs/utils/utils.py b/alr_envs/utils/utils.py index b212aac..cf09e24 100644 --- a/alr_envs/utils/utils.py +++ b/alr_envs/utils/utils.py @@ -46,3 +46,4 @@ def nested_update(base: MutableMapping, update): """ for k, v in update.items(): base[k] = nested_update(base.get(k, {}), v) if isinstance(v, Mapping) else v + From 69de4286b32011e4e277866a3a7ba526523f2185 Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 5 Jul 2022 10:12:01 +0200 Subject: [PATCH 058/104] beerpong only one file --- alr_envs/alr/__init__.py | 20 +++++++++---------- alr_envs/alr/mujoco/__init__.py | 2 +- .../mujoco/beerpong/deprecated/__init__.py | 0 .../beerpong_reward_staged.py | 0 4 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 alr_envs/alr/mujoco/beerpong/deprecated/__init__.py rename alr_envs/alr/mujoco/beerpong/{ => deprecated}/beerpong_reward_staged.py (100%) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 53828ed..1bcb02e 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -214,8 +214,8 @@ register(id='TableTennis4DCtxt-v0', kwargs={'ctxt_dim': 4}) register( - id='ALRBeerPong-v0', - entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', + id='BeerPong-v0', + entry_point='alr_envs.alr.mujoco:BeerBongEnv', max_episode_steps=300, kwargs={ "frame_skip": 2 @@ -223,8 +223,8 @@ register( ) register( - id='ALRBeerPong-v1', - entry_point='alr_envs.alr.mujoco:ALRBeerBongEnv', + id='BeerPong-v1', + entry_point='alr_envs.alr.mujoco:BeerBongEnv', max_episode_steps=300, kwargs={ "frame_skip": 2 @@ -234,8 +234,8 @@ register( # Here we use the same reward as in ALRBeerPong-v0, but now consider after the release, # only one time step, i.e. we simulate until the end of th episode register( - id='ALRBeerPongStepBased-v0', - entry_point='alr_envs.alr.mujoco:ALRBeerBongEnvStepBased', + id='BeerPongStepBased-v0', + entry_point='alr_envs.alr.mujoco:BeerBongEnvStepBased', max_episode_steps=300, kwargs={ "cup_goal_pos": [-0.3, -1.2], @@ -245,8 +245,8 @@ register( # Beerpong with episodic reward, but fixed release time step register( - id='ALRBeerPongFixedRelease-v0', - entry_point='alr_envs.alr.mujoco:ALRBeerBongEnvFixedReleaseStep', + id='BeerPongFixedRelease-v0', + entry_point='alr_envs.alr.mujoco:BeerBongEnvFixedReleaseStep', max_episode_steps=300, kwargs={ "cup_goal_pos": [-0.3, -1.2], @@ -414,7 +414,7 @@ for _v in _versions: ######################################################################################################################## ## Beerpong ProMP -_versions = ['ALRBeerPong-v0'] +_versions = ['BeerPong-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' @@ -434,7 +434,7 @@ for _v in _versions: ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) ### BP with Fixed release -_versions = ["ALRBeerPongStepBased-v0", "ALRBeerPongFixedRelease-v0"] +_versions = ["BeerPongStepBased-v0", "BeerPongFixedRelease-v0"] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index ac10cda..f880578 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -1,7 +1,7 @@ from .ant_jump.ant_jump import ALRAntJumpEnv from .ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv from .ball_in_a_cup.biac_pd import ALRBallInACupPDEnv -from .beerpong.beerpong import BeerPongEnv +from alr_envs.alr.mujoco.beerpong.beerpong import BeerPongEnv from .half_cheetah_jump.half_cheetah_jump import ALRHalfCheetahJumpEnv from .hopper_jump.hopper_jump_on_box import ALRHopperJumpOnBoxEnv from .hopper_throw.hopper_throw import ALRHopperThrowEnv diff --git a/alr_envs/alr/mujoco/beerpong/deprecated/__init__.py b/alr_envs/alr/mujoco/beerpong/deprecated/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py b/alr_envs/alr/mujoco/beerpong/deprecated/beerpong_reward_staged.py similarity index 100% rename from alr_envs/alr/mujoco/beerpong/beerpong_reward_staged.py rename to alr_envs/alr/mujoco/beerpong/deprecated/beerpong_reward_staged.py From 38f301dffbb97edac2c2e6548fd4add19bd87d0e Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 5 Jul 2022 13:12:47 +0200 Subject: [PATCH 059/104] remove reward_function attribute from Beerpong env --- .../mujoco/beerpong/deprecated/beerpong.py | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 alr_envs/alr/mujoco/beerpong/deprecated/beerpong.py diff --git a/alr_envs/alr/mujoco/beerpong/deprecated/beerpong.py b/alr_envs/alr/mujoco/beerpong/deprecated/beerpong.py new file mode 100644 index 0000000..0fe7a42 --- /dev/null +++ b/alr_envs/alr/mujoco/beerpong/deprecated/beerpong.py @@ -0,0 +1,212 @@ +import os + +import mujoco_py.builder +import numpy as np +from gym import utils +from gym.envs.mujoco import MujocoEnv + +from alr_envs.alr.mujoco.beerpong.deprecated.beerpong_reward_staged import BeerPongReward + + +class BeerPongEnv(MujocoEnv, utils.EzPickle): + def __init__(self, frame_skip=2): + self._steps = 0 + # Small Context -> Easier. Todo: Should we do different versions? + # self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", + # "beerpong_wo_cup" + ".xml") + # self._cup_pos_min = np.array([-0.32, -2.2]) + # self._cup_pos_max = np.array([0.32, -1.2]) + + self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../assets", + "beerpong_wo_cup_big_table" + ".xml") + self._cup_pos_min = np.array([-1.42, -4.05]) + self._cup_pos_max = np.array([1.42, -1.25]) + + self._start_pos = np.array([0.0, 1.35, 0.0, 1.18, 0.0, -0.786, -1.59]) + self._start_vel = np.zeros(7) + + self.release_step = 100 # time step of ball release + self.ep_length = 600 // frame_skip + + self.reward_function = BeerPongReward() + self.repeat_action = frame_skip + self.model = None + self.site_id = lambda x: self.model.site_name2id(x) + self.body_id = lambda x: self.model.body_name2id(x) + + MujocoEnv.__init__(self, self.xml_path, frame_skip=1) + utils.EzPickle.__init__(self) + + @property + def start_pos(self): + return self._start_pos + + @property + def start_vel(self): + return self._start_vel + + def reset(self): + self.reward_function.reset() + return super().reset() + + def reset_model(self): + init_pos_all = self.init_qpos.copy() + init_pos_robot = self.start_pos + init_vel = np.zeros_like(init_pos_all) + + self._steps = 0 + + start_pos = init_pos_all + start_pos[0:7] = init_pos_robot + + # TODO: Ask Max why we need to set the state twice. + self.set_state(start_pos, init_vel) + start_pos[7::] = self.sim.data.site_xpos[self.site_id("init_ball_pos"), :].copy() + self.set_state(start_pos, init_vel) + xy = self.np_random.uniform(self._cup_pos_min, self._cup_pos_max) + xyz = np.zeros(3) + xyz[:2] = xy + xyz[-1] = 0.840 + self.sim.model.body_pos[self.body_id("cup_table")] = xyz + return self._get_obs() + + def step(self, a): + crash = False + for _ in range(self.repeat_action): + applied_action = a + self.sim.data.qfrc_bias[:len(a)].copy() / self.model.actuator_gear[:, 0] + try: + self.do_simulation(applied_action, self.frame_skip) + self.reward_function.initialize(self) + # self.reward_function.check_contacts(self.sim) # I assume this is not important? + if self._steps < self.release_step: + self.sim.data.qpos[7::] = self.sim.data.site_xpos[self.site_id("init_ball_pos"), :].copy() + self.sim.data.qvel[7::] = self.sim.data.site_xvelp[self.site_id("init_ball_pos"), :].copy() + crash = False + except mujoco_py.builder.MujocoException: + crash = True + + ob = self._get_obs() + + if not crash: + reward, reward_infos = self.reward_function.compute_reward(self, applied_action) + is_collided = reward_infos['is_collided'] + done = is_collided or self._steps == self.ep_length - 1 + self._steps += 1 + else: + reward = -30 + done = True + reward_infos = {"success": False, "ball_pos": np.zeros(3), "ball_vel": np.zeros(3), "is_collided": False} + + infos = dict( + reward=reward, + action=a, + q_pos=self.sim.data.qpos[0:7].ravel().copy(), + q_vel=self.sim.data.qvel[0:7].ravel().copy(), sim_crash=crash, + ) + infos.update(reward_infos) + return ob, reward, done, infos + + def _get_obs(self): + theta = self.sim.data.qpos.flat[:7] + theta_dot = self.sim.data.qvel.flat[:7] + ball_pos = self.data.get_body_xpos("ball").copy() + cup_goal_diff_final = ball_pos - self.data.get_site_xpos("cup_goal_final_table").copy() + cup_goal_diff_top = ball_pos - self.data.get_site_xpos("cup_goal_table").copy() + return np.concatenate([ + np.cos(theta), + np.sin(theta), + theta_dot, + cup_goal_diff_final, + cup_goal_diff_top, + self.sim.model.body_pos[self.body_id("cup_table")][:2].copy(), + [self._steps], + ]) + + @property + def dt(self): + return super(BeerPongEnv, self).dt * self.repeat_action + + +class BeerPongEnvFixedReleaseStep(BeerPongEnv): + def __init__(self, frame_skip=2): + super().__init__(frame_skip) + self.release_step = 62 # empirically evaluated for frame_skip=2! + + +class BeerPongEnvStepBasedEpisodicReward(BeerPongEnv): + def __init__(self, frame_skip=2): + super().__init__(frame_skip) + self.release_step = 62 # empirically evaluated for frame_skip=2! + + def step(self, a): + if self._steps < self.release_step: + return super(BeerPongEnvStepBasedEpisodicReward, self).step(a) + else: + reward = 0 + done = False + while not done: + sub_ob, sub_reward, done, sub_infos = super(BeerPongEnvStepBasedEpisodicReward, self).step( + np.zeros(a.shape)) + reward += sub_reward + infos = sub_infos + ob = sub_ob + ob[-1] = self.release_step + 1 # Since we simulate until the end of the episode, PPO does not see the + # internal steps and thus, the observation also needs to be set correctly + return ob, reward, done, infos + + +# class ALRBeerBongEnvStepBased(ALRBeerBongEnv): +# def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): +# super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) +# self.release_step = 62 # empirically evaluated for frame_skip=2! +# +# def step(self, a): +# if self._steps < self.release_step: +# return super(ALRBeerBongEnvStepBased, self).step(a) +# else: +# reward = 0 +# done = False +# while not done: +# sub_ob, sub_reward, done, sub_infos = super(ALRBeerBongEnvStepBased, self).step(np.zeros(a.shape)) +# if not done or sub_infos['sim_crash']: +# reward += sub_reward +# else: +# ball_pos = self.sim.data.body_xpos[self.sim.model._body_name2id["ball"]].copy() +# cup_goal_dist_final = np.linalg.norm(ball_pos - self.sim.data.site_xpos[ +# self.sim.model._site_name2id["cup_goal_final_table"]].copy()) +# cup_goal_dist_top = np.linalg.norm(ball_pos - self.sim.data.site_xpos[ +# self.sim.model._site_name2id["cup_goal_table"]].copy()) +# if sub_infos['success']: +# dist_rew = -cup_goal_dist_final ** 2 +# else: +# dist_rew = -0.5 * cup_goal_dist_final ** 2 - cup_goal_dist_top ** 2 +# reward = reward - sub_infos['action_cost'] + dist_rew +# infos = sub_infos +# ob = sub_ob +# ob[-1] = self.release_step + 1 # Since we simulate until the end of the episode, PPO does not see the +# # internal steps and thus, the observation also needs to be set correctly +# return ob, reward, done, infos + + +if __name__ == "__main__": + env = BeerPongEnv(frame_skip=2) + env.seed(0) + # env = ALRBeerBongEnvStepBased(frame_skip=2) + # env = ALRBeerBongEnvStepBasedEpisodicReward(frame_skip=2) + # env = ALRBeerBongEnvFixedReleaseStep(frame_skip=2) + import time + + env.reset() + env.render("human") + for i in range(600): + # ac = 10 * env.action_space.sample() + ac = 0.05 * np.ones(7) + obs, rew, d, info = env.step(ac) + env.render("human") + + if d: + print('reward:', rew) + print('RESETTING') + env.reset() + time.sleep(1) + env.close() From eddef33d9a15d4843a2e2125beb492993fe4fdb6 Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 5 Jul 2022 13:15:43 +0200 Subject: [PATCH 060/104] remove reward_function attribute from Beerpong env --- alr_envs/alr/mujoco/beerpong/beerpong.py | 144 +++++++++++++++++++++-- 1 file changed, 134 insertions(+), 10 deletions(-) diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 51b3ed3..9adab60 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -5,7 +5,27 @@ import numpy as np from gym import utils from gym.envs.mujoco import MujocoEnv -from alr_envs.alr.mujoco.beerpong.beerpong_reward_staged import BeerPongReward +from alr_envs.alr.mujoco.beerpong.deprecated.beerpong_reward_staged import BeerPongReward + +# XML Variables +ROBOT_COLLISION_OBJ = ["wrist_palm_link_convex_geom", + "wrist_pitch_link_convex_decomposition_p1_geom", + "wrist_pitch_link_convex_decomposition_p2_geom", + "wrist_pitch_link_convex_decomposition_p3_geom", + "wrist_yaw_link_convex_decomposition_p1_geom", + "wrist_yaw_link_convex_decomposition_p2_geom", + "forearm_link_convex_decomposition_p1_geom", + "forearm_link_convex_decomposition_p2_geom", + "upper_arm_link_convex_decomposition_p1_geom", + "upper_arm_link_convex_decomposition_p2_geom", + "shoulder_link_convex_decomposition_p1_geom", + "shoulder_link_convex_decomposition_p2_geom", + "shoulder_link_convex_decomposition_p3_geom", + "base_link_convex_geom", "table_contact_geom"] + +CUP_COLLISION_OBJ = ["cup_geom_table3", "cup_geom_table4", "cup_geom_table5", "cup_geom_table6", + "cup_geom_table7", "cup_geom_table8", "cup_geom_table9", "cup_geom_table10", + "cup_geom_table15", "cup_geom_table16", "cup_geom_table17", "cup_geom1_table8"] class BeerPongEnv(MujocoEnv, utils.EzPickle): @@ -28,11 +48,22 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): self.release_step = 100 # time step of ball release self.ep_length = 600 // frame_skip - self.reward_function = BeerPongReward() self.repeat_action = frame_skip self.model = None self.site_id = lambda x: self.model.site_name2id(x) self.body_id = lambda x: self.model.body_name2id(x) + self.geom_id = lambda x: self.model.geom_name2id(x) + + # for reward calculation + self.dists = [] + self.dists_final = [] + self.action_costs = [] + self.ball_ground_contact_first = False + self.ball_table_contact = False + self.ball_wall_contact = False + self.ball_cup_contact = False + self.ball_in_cup = False + self.dist_ground_cup = -1 # distance floor to cup if first floor contact MujocoEnv.__init__(self, self.xml_path, frame_skip=1) utils.EzPickle.__init__(self) @@ -46,7 +77,15 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): return self._start_vel def reset(self): - self.reward_function.reset() + self.dists = [] + self.dists_final = [] + self.action_costs = [] + self.ball_ground_contact_first = False + self.ball_table_contact = False + self.ball_wall_contact = False + self.ball_cup_contact = False + self.ball_in_cup = False + self.dist_ground_cup = -1 # distance floor to cup if first floor contact return super().reset() def reset_model(self): @@ -76,7 +115,6 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): applied_action = a + self.sim.data.qfrc_bias[:len(a)].copy() / self.model.actuator_gear[:, 0] try: self.do_simulation(applied_action, self.frame_skip) - self.reward_function.initialize(self) # self.reward_function.check_contacts(self.sim) # I assume this is not important? if self._steps < self.release_step: self.sim.data.qpos[7::] = self.sim.data.site_xpos[self.site_id("init_ball_pos"), :].copy() @@ -88,7 +126,7 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): ob = self._get_obs() if not crash: - reward, reward_infos = self.reward_function.compute_reward(self, applied_action) + reward, reward_infos = self._get_reward(applied_action) is_collided = reward_infos['is_collided'] done = is_collided or self._steps == self.ep_length - 1 self._steps += 1 @@ -119,13 +157,98 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): cup_goal_diff_final, cup_goal_diff_top, self.sim.model.body_pos[self.body_id("cup_table")][:2].copy(), - [self._steps], + # [self._steps], # Use TimeAwareObservation Wrapper instead .... ]) @property def dt(self): return super(BeerPongEnv, self).dt * self.repeat_action + def _get_reward(self, action): + goal_pos = self.data.get_site_xpos("cup_goal_table") + ball_pos = self.data.get_body_xpos("ball") + ball_vel = self.data.get_body_xvelp("ball") + goal_final_pos = self.data.get_site_xpos("cup_goal_final_table") + + self._check_contacts() + self.dists.append(np.linalg.norm(goal_pos - ball_pos)) + self.dists_final.append(np.linalg.norm(goal_final_pos - ball_pos)) + self.dist_ground_cup = np.linalg.norm(ball_pos - goal_pos) \ + if self.ball_ground_contact_first and self.dist_ground_cup == -1 else self.dist_ground_cup + action_cost = np.sum(np.square(action)) + self.action_costs.append(np.copy(action_cost)) + # # ##################### Reward function which does not force to bounce once on the table (quad dist) ######### + + # Is this needed? + # self._is_collided = self._check_collision_with_itself([self.geom_id(name) for name in CUP_COLLISION_OBJ]) + + if self._steps == self.ep_length - 1:# or self._is_collided: + min_dist = np.min(self.dists) + final_dist = self.dists_final[-1] + if self.ball_ground_contact_first: + min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 2, -4 + else: + if not self.ball_in_cup: + if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact: + min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 0, -4 + else: + min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 1, 0.5, 0, -2 + else: + min_dist_coeff, final_dist_coeff, ground_contact_dist_coeff, rew_offset = 0, 1, 0, 0 + action_cost = 1e-4 * np.mean(action_cost) + reward = rew_offset - min_dist_coeff * min_dist ** 2 - final_dist_coeff * final_dist ** 2 - \ + action_cost - ground_contact_dist_coeff * self.dist_ground_cup ** 2 + # release step punishment + min_time_bound = 0.1 + max_time_bound = 1.0 + release_time = self.release_step * self.dt + release_time_rew = int(release_time < min_time_bound) * (-30 - 10 * (release_time - min_time_bound) ** 2) + \ + int(release_time > max_time_bound) * (-30 - 10 * (release_time - max_time_bound) ** 2) + reward += release_time_rew + success = self.ball_in_cup + else: + action_cost = 1e-2 * action_cost + reward = - action_cost + success = False + # ############################################################################################################## + infos = {"success": success, "ball_pos": ball_pos.copy(), + "ball_vel": ball_vel.copy(), "action_cost": action_cost, "task_reward": reward, + "table_contact_first": int(not self.ball_ground_contact_first), + "is_collided": False} # TODO: Check if is collided is needed + return reward, infos + + def _check_contacts(self): + if not self.ball_table_contact: + self.ball_table_contact = self._check_collision({self.geom_id("ball_geom")}, + {self.geom_id("table_contact_geom")}) + if not self.ball_cup_contact: + self.ball_cup_contact = self._check_collision({self.geom_id("ball_geom")}, + {self.geom_id(name) for name in CUP_COLLISION_OBJ}) + if not self.ball_wall_contact: + self.ball_wall_contact = self._check_collision({self.geom_id("ball_geom")}, + {self.geom_id("wall")}) + if not self.ball_in_cup: + self.ball_in_cup = self._check_collision({self.geom_id("ball_geom")}, + {self.geom_id("cup_base_table_contact")}) + if not self.ball_ground_contact_first: + if not self.ball_table_contact and not self.ball_cup_contact and not self.ball_wall_contact \ + and not self.ball_in_cup: + self.ball_ground_contact_first = self._check_collision({self.geom_id("ball_geom")}, + {self.geom_id("ground")}) + + # Checks if id_set1 has a collision with id_set2 + def _check_collision(self, id_set_1, id_set_2): + """ + If id_set_2 is set to None, it will check for a collision with itself (id_set_1). + """ + collision_id_set = id_set_2 - id_set_1 if id_set_2 is not None else id_set_1 + for coni in range(self.sim.data.ncon): + con = self.sim.data.contact[coni] + if ((con.geom1 in id_set_1 and con.geom2 in collision_id_set) or + (con.geom2 in id_set_1 and con.geom1 in collision_id_set)): + return True + return False + class BeerPongEnvFixedReleaseStep(BeerPongEnv): def __init__(self, frame_skip=2): @@ -190,6 +313,7 @@ class BeerPongEnvStepBasedEpisodicReward(BeerPongEnv): if __name__ == "__main__": env = BeerPongEnv(frame_skip=2) + env.seed(0) # env = ALRBeerBongEnvStepBased(frame_skip=2) # env = ALRBeerBongEnvStepBasedEpisodicReward(frame_skip=2) # env = ALRBeerBongEnvFixedReleaseStep(frame_skip=2) @@ -197,14 +321,14 @@ if __name__ == "__main__": env.reset() env.render("human") - for i in range(1500): - ac = 10 * env.action_space.sample() + for i in range(600): + # ac = 10 * env.action_space.sample() + ac = 0.05 * np.ones(7) obs, rew, d, info = env.step(ac) env.render("human") - print(env.dt) - print(rew) if d: + print('reward:', rew) print('RESETTING') env.reset() time.sleep(1) From 6704c9d63a5bce2a517af4450a004dfcacd2e6d9 Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 6 Jul 2022 09:05:35 +0200 Subject: [PATCH 061/104] mp wrapper fixes --- alr_envs/alr/__init__.py | 53 ++-- .../base_reacher/base_reacher.py | 9 +- .../hole_reacher/hole_reacher.py | 7 +- .../hole_reacher/mp_wrapper.py | 5 +- .../simple_reacher/mp_wrapper.py | 5 +- .../simple_reacher/simple_reacher.py | 8 +- .../viapoint_reacher/mp_wrapper.py | 5 +- .../viapoint_reacher/viapoint_reacher.py | 8 +- alr_envs/alr/mujoco/__init__.py | 2 +- alr_envs/alr/mujoco/ant_jump/__init__.py | 2 +- alr_envs/alr/mujoco/ant_jump/ant_jump.py | 38 +-- alr_envs/alr/mujoco/ant_jump/mp_wrapper.py | 16 +- .../alr/mujoco/ant_jump/new_mp_wrapper.py | 22 -- .../{ => ball_in_a_cup}/alr_reward_fct.py | 0 .../ball_in_a_cup/ball_in_a_cup_reward.py | 2 +- .../ball_in_a_cup_reward_simple.py | 2 +- alr_envs/alr/mujoco/ball_in_a_cup/biac_pd.py | 11 - alr_envs/alr/mujoco/beerpong/__init__.py | 2 +- alr_envs/alr/mujoco/beerpong/beerpong.py | 5 +- alr_envs/alr/mujoco/beerpong/mp_wrapper.py | 38 +-- .../alr/mujoco/beerpong/new_mp_wrapper.py | 41 --- .../alr/mujoco/half_cheetah_jump/__init__.py | 2 +- .../half_cheetah_jump/half_cheetah_jump.py | 34 +- .../mujoco/half_cheetah_jump/mp_wrapper.py | 10 +- .../half_cheetah_jump/new_mp_wrapper.py | 22 -- alr_envs/alr/mujoco/hopper_jump/__init__.py | 1 + .../alr/mujoco/hopper_jump/hopper_jump.py | 293 +++++++----------- alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py | 1 + .../alr/mujoco/hopper_throw/mp_wrapper.py | 15 +- .../alr/mujoco/hopper_throw/new_mp_wrapper.py | 25 -- .../mujoco/reacher/assets/reacher_5links.xml | 2 +- alr_envs/alr/mujoco/reacher/mp_wrapper.py | 7 +- alr_envs/alr/mujoco/reacher/reacher.py | 4 +- .../alr/mujoco/walker_2d_jump/__init__.py | 2 +- .../alr/mujoco/walker_2d_jump/mp_wrapper.py | 17 +- .../mujoco/walker_2d_jump/new_mp_wrapper.py | 26 -- alr_envs/black_box/black_box_wrapper.py | 71 +++-- alr_envs/black_box/raw_interface_wrapper.py | 20 +- alr_envs/examples/examples_general.py | 4 +- .../examples/examples_movement_primitives.py | 33 +- alr_envs/utils/make_env_helpers.py | 8 +- alr_envs/utils/utils.py | 3 +- setup.py | 29 +- 43 files changed, 302 insertions(+), 608 deletions(-) delete mode 100644 alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py rename alr_envs/alr/mujoco/{ => ball_in_a_cup}/alr_reward_fct.py (100%) delete mode 100644 alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py delete mode 100644 alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py delete mode 100644 alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py delete mode 100644 alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index 1bcb02e..cdff3a1 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -118,33 +118,30 @@ for _dims in [5, 7]: } ) -## Hopper Jump random joints and desired position register( id='HopperJumpSparse-v0', - entry_point='alr_envs.alr.mujoco:ALRHopperXYJumpEnv', + entry_point='alr_envs.alr.mujoco:HopperJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ - # "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, "sparse": True, - # "healthy_reward": 1.0 } ) -## Hopper Jump random joints and desired position step based reward register( id='HopperJump-v0', - entry_point='alr_envs.alr.mujoco:ALRHopperXYJumpEnvStepBased', + entry_point='alr_envs.alr.mujoco:HopperJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ - # "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, "sparse": False, - # "healthy_reward": 1.0 + "healthy_reward": 1.0, + "contact_weight": 0.0, + "height_weight": 3.0, } ) register( id='ALRAntJump-v0', - entry_point='alr_envs.alr.mujoco:ALRAntJumpEnv', + entry_point='alr_envs.alr.mujoco:AntJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_ANTJUMP, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_ANTJUMP, @@ -266,7 +263,7 @@ for _v in _versions: entry_point='alr_envs.utils.make_env_helpers:make_dmp_env_helper', # max_episode_steps=1, kwargs={ - "name": f"alr_envs:{_v}", + "name": f"{_v}", "wrappers": [classic_control.simple_reacher.MPWrapper], "traj_gen_kwargs": { "num_dof": 2 if "long" not in _v.lower() else 5, @@ -304,7 +301,7 @@ register( entry_point='alr_envs.utils.make_env_helpers:make_dmp_env_helper', # max_episode_steps=1, kwargs={ - "name": "alr_envs:ViaPointReacher-v0", + "name": "ViaPointReacher-v0", "wrappers": [classic_control.viapoint_reacher.MPWrapper], "traj_gen_kwargs": { "num_dof": 5, @@ -340,7 +337,7 @@ for _v in _versions: entry_point='alr_envs.utils.make_env_helpers:make_dmp_env_helper', # max_episode_steps=1, kwargs={ - "name": f"alr_envs:HoleReacher-{_v}", + "name": f"HoleReacher-{_v}", "wrappers": [classic_control.hole_reacher.MPWrapper], "traj_gen_kwargs": { "num_dof": 5, @@ -362,7 +359,7 @@ for _v in _versions: kwargs_dict_hole_reacher_promp['wrappers'].append(classic_control.hole_reacher.MPWrapper) kwargs_dict_hole_reacher_promp['trajectory_generator_kwargs']['weight_scale'] = 2 kwargs_dict_hole_reacher_promp['controller_kwargs']['controller_type'] = 'velocity' - kwargs_dict_hole_reacher_promp['name'] = f"alr_envs:{_v}" + kwargs_dict_hole_reacher_promp['name'] = f"{_v}" register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', @@ -370,8 +367,8 @@ for _v in _versions: ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) -## ALRReacher -_versions = ["ALRReacher-v0", "ALRLongReacher-v0", "ALRReacherSparse-v0", "ALRLongReacherSparse-v0"] +## ReacherNd +_versions = ["Reacher5d-v0", "Reacher7d-v0", "Reacher5dSparse-v0", "Reacher7dSparse-v0"] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}DMP-{_name[1]}' @@ -380,7 +377,7 @@ for _v in _versions: entry_point='alr_envs.utils.make_env_helpers:make_dmp_env_helper', # max_episode_steps=1, kwargs={ - "name": f"alr_envs:{_v}", + "name": f"{_v}", "wrappers": [mujoco.reacher.MPWrapper], "traj_gen_kwargs": { "num_dof": 5 if "long" not in _v.lower() else 7, @@ -404,10 +401,10 @@ for _v in _versions: kwargs_dict_alr_reacher_promp['wrappers'].append(mujoco.reacher.MPWrapper) kwargs_dict_alr_reacher_promp['controller_kwargs']['p_gains'] = 1 kwargs_dict_alr_reacher_promp['controller_kwargs']['d_gains'] = 0.1 - kwargs_dict_alr_reacher_promp['name'] = f"alr_envs:{_v}" + kwargs_dict_alr_reacher_promp['name'] = f"{_v}" register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_alr_reacher_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -425,7 +422,7 @@ for _v in _versions: kwargs_dict_bp_promp['controller_kwargs']['d_gains'] = np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis'] = 2 kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis_zero_start'] = 2 - kwargs_dict_bp_promp['name'] = f"alr_envs:{_v}" + kwargs_dict_bp_promp['name'] = f"{_v}" register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', @@ -445,7 +442,7 @@ for _v in _versions: kwargs_dict_bp_promp['controller_kwargs']['d_gains'] = np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis'] = 2 kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis_zero_start'] = 2 - kwargs_dict_bp_promp['name'] = f"alr_envs:{_v}" + kwargs_dict_bp_promp['name'] = f"{_v}" register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', @@ -465,7 +462,7 @@ for _v in _versions: _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_ant_jump_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_ant_jump_promp['wrappers'].append(mujoco.ant_jump.MPWrapper) - kwargs_dict_ant_jump_promp['name'] = f"alr_envs:{_v}" + kwargs_dict_ant_jump_promp['name'] = f"{_v}" register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', @@ -482,7 +479,7 @@ for _v in _versions: _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_halfcheetah_jump_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_halfcheetah_jump_promp['wrappers'].append(mujoco.half_cheetah_jump.MPWrapper) - kwargs_dict_halfcheetah_jump_promp['name'] = f"alr_envs:{_v}" + kwargs_dict_halfcheetah_jump_promp['name'] = f"{_v}" register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', @@ -502,7 +499,7 @@ for _v in _versions: _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_hopper_jump_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_hopper_jump_promp['wrappers'].append(mujoco.hopper_jump.MPWrapper) - kwargs_dict_hopper_jump_promp['name'] = f"alr_envs:{_v}" + kwargs_dict_hopper_jump_promp['name'] = f"{_v}" register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', @@ -520,7 +517,7 @@ for _v in _versions: _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_walker2d_jump_promp = deepcopy(DEFAULT_BB_DICT) kwargs_dict_walker2d_jump_promp['wrappers'].append(mujoco.walker_2d_jump.MPWrapper) - kwargs_dict_walker2d_jump_promp['name'] = f"alr_envs:{_v}" + kwargs_dict_walker2d_jump_promp['name'] = f"{_v}" register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', @@ -583,7 +580,7 @@ register( # CtxtFree are v0, Contextual are v1 register( id='ALRAntJump-v0', - entry_point='alr_envs.alr.mujoco:ALRAntJumpEnv', + entry_point='alr_envs.alr.mujoco:AntJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_ANTJUMP, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_ANTJUMP, @@ -602,7 +599,7 @@ register( ) register( id='ALRHopperJump-v0', - entry_point='alr_envs.alr.mujoco:ALRHopperJumpEnv', + entry_point='alr_envs.alr.mujoco:HopperJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, @@ -649,7 +646,7 @@ for i in _vs: id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', kwargs={ - "name": f"alr_envs:{_env_id.replace('ProMP', '')}", + "name": f"{_env_id.replace('ProMP', '')}", "wrappers": [mujoco.reacher.MPWrapper], "mp_kwargs": { "num_dof": 5, @@ -672,7 +669,7 @@ for i in _vs: id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', kwargs={ - "name": f"alr_envs:{_env_id.replace('ProMP', '')}", + "name": f"{_env_id.replace('ProMP', '')}", "wrappers": [mujoco.reacher.MPWrapper], "mp_kwargs": { "num_dof": 5, diff --git a/alr_envs/alr/classic_control/base_reacher/base_reacher.py b/alr_envs/alr/classic_control/base_reacher/base_reacher.py index e76ce85..1af8187 100644 --- a/alr_envs/alr/classic_control/base_reacher/base_reacher.py +++ b/alr_envs/alr/classic_control/base_reacher/base_reacher.py @@ -1,9 +1,10 @@ from abc import ABC, abstractmethod -from typing import Union +from typing import Union, Tuple, Optional import gym import numpy as np from gym import spaces +from gym.core import ObsType from gym.utils import seeding from alr_envs.alr.classic_control.utils import intersect @@ -14,8 +15,7 @@ class BaseReacherEnv(gym.Env, ABC): Base class for all reaching environments. """ - def __init__(self, n_links: int, random_start: bool = True, - allow_self_collision: bool = False): + def __init__(self, n_links: int, random_start: bool = True, allow_self_collision: bool = False): super().__init__() self.link_lengths = np.ones(n_links) self.n_links = n_links @@ -70,7 +70,8 @@ class BaseReacherEnv(gym.Env, ABC): def current_vel(self): return self._angle_velocity.copy() - def reset(self): + def reset(self, *, seed: Optional[int] = None, return_info: bool = False, + options: Optional[dict] = None, ) -> Union[ObsType, Tuple[ObsType, dict]]: # Sample only orientation of first link, i.e. the arm is always straight. if self.random_start: first_joint = self.np_random.uniform(np.pi / 4, 3 * np.pi / 4) diff --git a/alr_envs/alr/classic_control/hole_reacher/hole_reacher.py b/alr_envs/alr/classic_control/hole_reacher/hole_reacher.py index 883be8c..8f0122f 100644 --- a/alr_envs/alr/classic_control/hole_reacher/hole_reacher.py +++ b/alr_envs/alr/classic_control/hole_reacher/hole_reacher.py @@ -1,8 +1,9 @@ -from typing import Union +from typing import Union, Optional, Tuple import gym import matplotlib.pyplot as plt import numpy as np +from gym.core import ObsType from matplotlib import patches from alr_envs.alr.classic_control.base_reacher.base_reacher_direct import BaseReacherDirectEnv @@ -51,7 +52,8 @@ class HoleReacherEnv(BaseReacherDirectEnv): else: raise ValueError("Unknown reward function {}".format(rew_fct)) - def reset(self): + def reset(self, *, seed: Optional[int] = None, return_info: bool = False, + options: Optional[dict] = None, ) -> Union[ObsType, Tuple[ObsType, dict]]: self._generate_hole() self._set_patches() self.reward_function.reset() @@ -223,6 +225,7 @@ class HoleReacherEnv(BaseReacherDirectEnv): if __name__ == "__main__": import time + env = HoleReacherEnv(5) env.reset() diff --git a/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py index 0a5eaa6..00a5eb8 100644 --- a/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py +++ b/alr_envs/alr/classic_control/hole_reacher/mp_wrapper.py @@ -7,6 +7,7 @@ from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): + @property def context_mask(self): return np.hstack([ [self.env.random_start] * self.env.n_links, # cos @@ -25,7 +26,3 @@ class MPWrapper(RawInterfaceWrapper): @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.current_vel - - @property - def dt(self) -> Union[float, int]: - return self.env.dt diff --git a/alr_envs/alr/classic_control/simple_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/simple_reacher/mp_wrapper.py index c5ef66f..3fa12d8 100644 --- a/alr_envs/alr/classic_control/simple_reacher/mp_wrapper.py +++ b/alr_envs/alr/classic_control/simple_reacher/mp_wrapper.py @@ -7,6 +7,7 @@ from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): + @property def context_mask(self): return np.hstack([ [self.env.random_start] * self.env.n_links, # cos @@ -23,7 +24,3 @@ class MPWrapper(RawInterfaceWrapper): @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.current_vel - - @property - def dt(self) -> Union[float, int]: - return self.env.dt diff --git a/alr_envs/alr/classic_control/simple_reacher/simple_reacher.py b/alr_envs/alr/classic_control/simple_reacher/simple_reacher.py index dac06a3..eb079d0 100644 --- a/alr_envs/alr/classic_control/simple_reacher/simple_reacher.py +++ b/alr_envs/alr/classic_control/simple_reacher/simple_reacher.py @@ -1,8 +1,9 @@ -from typing import Iterable, Union +from typing import Iterable, Union, Optional, Tuple import matplotlib.pyplot as plt import numpy as np from gym import spaces +from gym.core import ObsType from alr_envs.alr.classic_control.base_reacher.base_reacher_torque import BaseReacherTorqueEnv @@ -15,7 +16,7 @@ class SimpleReacherEnv(BaseReacherTorqueEnv): """ def __init__(self, n_links: int, target: Union[None, Iterable] = None, random_start: bool = True, - allow_self_collision: bool = False,): + allow_self_collision: bool = False, ): super().__init__(n_links, random_start, allow_self_collision) # provided initial parameters @@ -41,7 +42,8 @@ class SimpleReacherEnv(BaseReacherTorqueEnv): # def start_pos(self): # return self._start_pos - def reset(self): + def reset(self, *, seed: Optional[int] = None, return_info: bool = False, + options: Optional[dict] = None, ) -> Union[ObsType, Tuple[ObsType, dict]]: self._generate_goal() return super().reset() diff --git a/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py b/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py index 2b210de..d152f3b 100644 --- a/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py +++ b/alr_envs/alr/classic_control/viapoint_reacher/mp_wrapper.py @@ -7,6 +7,7 @@ from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): + @property def context_mask(self): return np.hstack([ [self.env.random_start] * self.env.n_links, # cos @@ -24,7 +25,3 @@ class MPWrapper(RawInterfaceWrapper): @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.current_vel - - @property - def dt(self) -> Union[float, int]: - return self.env.dt diff --git a/alr_envs/alr/classic_control/viapoint_reacher/viapoint_reacher.py b/alr_envs/alr/classic_control/viapoint_reacher/viapoint_reacher.py index 292e40a..569ca2c 100644 --- a/alr_envs/alr/classic_control/viapoint_reacher/viapoint_reacher.py +++ b/alr_envs/alr/classic_control/viapoint_reacher/viapoint_reacher.py @@ -1,8 +1,9 @@ -from typing import Iterable, Union +from typing import Iterable, Union, Tuple, Optional import gym import matplotlib.pyplot as plt import numpy as np +from gym.core import ObsType from gym.utils import seeding from alr_envs.alr.classic_control.base_reacher.base_reacher_direct import BaseReacherDirectEnv @@ -40,7 +41,8 @@ class ViaPointReacherEnv(BaseReacherDirectEnv): # def start_pos(self): # return self._start_pos - def reset(self): + def reset(self, *, seed: Optional[int] = None, return_info: bool = False, + options: Optional[dict] = None, ) -> Union[ObsType, Tuple[ObsType, dict]]: self._generate_goal() return super().reset() @@ -183,8 +185,10 @@ class ViaPointReacherEnv(BaseReacherDirectEnv): plt.pause(0.01) + if __name__ == "__main__": import time + env = ViaPointReacherEnv(5) env.reset() diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index f880578..906a9a5 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -1,4 +1,4 @@ -from .ant_jump.ant_jump import ALRAntJumpEnv +from .ant_jump.ant_jump import AntJumpEnv from .ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv from .ball_in_a_cup.biac_pd import ALRBallInACupPDEnv from alr_envs.alr.mujoco.beerpong.beerpong import BeerPongEnv diff --git a/alr_envs/alr/mujoco/ant_jump/__init__.py b/alr_envs/alr/mujoco/ant_jump/__init__.py index 8a04a02..c5e6d2f 100644 --- a/alr_envs/alr/mujoco/ant_jump/__init__.py +++ b/alr_envs/alr/mujoco/ant_jump/__init__.py @@ -1 +1 @@ -from .new_mp_wrapper import MPWrapper +from .mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/ant_jump/ant_jump.py b/alr_envs/alr/mujoco/ant_jump/ant_jump.py index 27098ac..deffcfa 100644 --- a/alr_envs/alr/mujoco/ant_jump/ant_jump.py +++ b/alr_envs/alr/mujoco/ant_jump/ant_jump.py @@ -1,14 +1,19 @@ +from typing import Tuple, Union, Optional + import numpy as np +from gym.core import ObsType from gym.envs.mujoco.ant_v3 import AntEnv MAX_EPISODE_STEPS_ANTJUMP = 200 -# TODO: This environment was not testet yet. Do the following todos and test it. + + +# TODO: This environment was not tested yet. Do the following todos and test it. # TODO: Right now this environment only considers jumping to a specific height, which is not nice. It should be extended # to the same structure as the Hopper, where the angles are randomized (->contexts) and the agent should jump as heigh # as possible, while landing at a specific target position -class ALRAntJumpEnv(AntEnv): +class AntJumpEnv(AntEnv): """ Initialization changes to normal Ant: - healthy_reward: 1.0 -> 0.01 -> 0.0 no healthy reward needed - Paul and Marc @@ -27,17 +32,15 @@ class ALRAntJumpEnv(AntEnv): contact_force_range=(-1.0, 1.0), reset_noise_scale=0.1, exclude_current_positions_from_observation=True, - max_episode_steps=200): + ): self.current_step = 0 self.max_height = 0 - self.max_episode_steps = max_episode_steps self.goal = 0 super().__init__(xml_file, ctrl_cost_weight, contact_cost_weight, healthy_reward, terminate_when_unhealthy, healthy_z_range, contact_force_range, reset_noise_scale, exclude_current_positions_from_observation) def step(self, action): - self.current_step += 1 self.do_simulation(action, self.frame_skip) @@ -52,12 +55,12 @@ class ALRAntJumpEnv(AntEnv): costs = ctrl_cost + contact_cost - done = height < 0.3 # fall over -> is the 0.3 value from healthy_z_range? TODO change 0.3 to the value of healthy z angle + done = height < 0.3 # fall over -> is the 0.3 value from healthy_z_range? TODO change 0.3 to the value of healthy z angle - if self.current_step == self.max_episode_steps or done: + if self.current_step == MAX_EPISODE_STEPS_ANTJUMP or done: # -10 for scaling the value of the distance between the max_height and the goal height; only used when context is enabled # height_reward = -10 * (np.linalg.norm(self.max_height - self.goal)) - height_reward = -10*np.linalg.norm(self.max_height - self.goal) + height_reward = -10 * np.linalg.norm(self.max_height - self.goal) # no healthy reward when using context, because we optimize a negative value healthy_reward = 0 @@ -77,7 +80,8 @@ class ALRAntJumpEnv(AntEnv): def _get_obs(self): return np.append(super()._get_obs(), self.goal) - def reset(self): + def reset(self, *, seed: Optional[int] = None, return_info: bool = False, + options: Optional[dict] = None, ) -> Union[ObsType, Tuple[ObsType, dict]]: self.current_step = 0 self.max_height = 0 self.goal = np.random.uniform(1.0, 2.5, @@ -96,19 +100,3 @@ class ALRAntJumpEnv(AntEnv): observation = self._get_obs() return observation - -if __name__ == '__main__': - render_mode = "human" # "human" or "partial" or "final" - env = ALRAntJumpEnv() - obs = env.reset() - - for i in range(2000): - # test with random actions - ac = env.action_space.sample() - obs, rew, d, info = env.step(ac) - if i % 10 == 0: - env.render(mode=render_mode) - if d: - env.reset() - - env.close() diff --git a/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py b/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py index f6e99a3..a481d6f 100644 --- a/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py @@ -1,4 +1,4 @@ -from typing import Tuple, Union +from typing import Union, Tuple import numpy as np @@ -8,10 +8,10 @@ from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): @property - def context_mask(self) -> np.ndarray: + def context_mask(self): return np.hstack([ - [False] * 111, # ant has 111 dimensional observation space !! - [True] # goal height + [False] * 111, # ant has 111 dimensional observation space !! + [True] # goal height ]) @property @@ -21,11 +21,3 @@ class MPWrapper(RawInterfaceWrapper): @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qvel[6:14].copy() - - @property - def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: - raise ValueError("Goal position is not available and has to be learnt based on the environment.") - - @property - def dt(self) -> Union[float, int]: - return self.env.dt diff --git a/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py deleted file mode 100644 index f6f026b..0000000 --- a/alr_envs/alr/mujoco/ant_jump/new_mp_wrapper.py +++ /dev/null @@ -1,22 +0,0 @@ -from alr_envs.black_box.black_box_wrapper import BlackBoxWrapper -from typing import Union, Tuple -import numpy as np - -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - - def get_context_mask(self): - return np.hstack([ - [False] * 111, # ant has 111 dimensional observation space !! - [True] # goal height - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.sim.data.qpos[7:15].copy() - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[6:14].copy() diff --git a/alr_envs/alr/mujoco/alr_reward_fct.py b/alr_envs/alr/mujoco/ball_in_a_cup/alr_reward_fct.py similarity index 100% rename from alr_envs/alr/mujoco/alr_reward_fct.py rename to alr_envs/alr/mujoco/ball_in_a_cup/alr_reward_fct.py diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward.py b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward.py index 4ea4381..b4d0e6e 100644 --- a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward.py +++ b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward.py @@ -1,5 +1,5 @@ import numpy as np -from alr_envs.alr.mujoco import alr_reward_fct +from alr_envs.alr.mujoco.ball_in_a_cup import alr_reward_fct class BallInACupReward(alr_reward_fct.AlrReward): diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward_simple.py b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward_simple.py index 0762e22..8044eb8 100644 --- a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward_simple.py +++ b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward_simple.py @@ -1,5 +1,5 @@ import numpy as np -from alr_envs.alr.mujoco import alr_reward_fct +from alr_envs.alr.mujoco.ball_in_a_cup import alr_reward_fct class BallInACupReward(alr_reward_fct.AlrReward): diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/biac_pd.py b/alr_envs/alr/mujoco/ball_in_a_cup/biac_pd.py index b047c54..4abfb6c 100644 --- a/alr_envs/alr/mujoco/ball_in_a_cup/biac_pd.py +++ b/alr_envs/alr/mujoco/ball_in_a_cup/biac_pd.py @@ -6,17 +6,6 @@ import mujoco_py.builder import numpy as np from gym import utils -from mp_env_api.mp_wrappers.detpmp_wrapper import DetPMPWrapper -from mp_env_api.utils.policies import PDControllerExtend - - -def make_detpmp_env(**kwargs): - name = kwargs.pop("name") - _env = gym.make(name) - policy = PDControllerExtend(_env, p_gains=kwargs.pop('p_gains'), d_gains=kwargs.pop('d_gains')) - kwargs['policy_type'] = policy - return DetPMPWrapper(_env, **kwargs) - class ALRBallInACupPDEnv(mujoco_env.MujocoEnv, utils.EzPickle): def __init__(self, frame_skip=4, apply_gravity_comp=True, simplified: bool = False, diff --git a/alr_envs/alr/mujoco/beerpong/__init__.py b/alr_envs/alr/mujoco/beerpong/__init__.py index 8a04a02..c5e6d2f 100644 --- a/alr_envs/alr/mujoco/beerpong/__init__.py +++ b/alr_envs/alr/mujoco/beerpong/__init__.py @@ -1 +1 @@ -from .new_mp_wrapper import MPWrapper +from .mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/beerpong/beerpong.py b/alr_envs/alr/mujoco/beerpong/beerpong.py index 9adab60..fd820eb 100644 --- a/alr_envs/alr/mujoco/beerpong/beerpong.py +++ b/alr_envs/alr/mujoco/beerpong/beerpong.py @@ -1,12 +1,11 @@ import os +from typing import Optional import mujoco_py.builder import numpy as np from gym import utils from gym.envs.mujoco import MujocoEnv -from alr_envs.alr.mujoco.beerpong.deprecated.beerpong_reward_staged import BeerPongReward - # XML Variables ROBOT_COLLISION_OBJ = ["wrist_palm_link_convex_geom", "wrist_pitch_link_convex_decomposition_p1_geom", @@ -76,7 +75,7 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): def start_vel(self): return self._start_vel - def reset(self): + def reset(self, *, seed: Optional[int] = None, return_info: bool = False, options: Optional[dict] = None): self.dists = [] self.dists_final = [] self.action_costs = [] diff --git a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py index 20e7532..e69d4f9 100644 --- a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py +++ b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py @@ -1,4 +1,4 @@ -from typing import Tuple, Union +from typing import Union, Tuple import numpy as np @@ -7,34 +7,36 @@ from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): - @property - def context_mask(self) -> np.ndarray: + def get_context_mask(self): return np.hstack([ [False] * 7, # cos [False] * 7, # sin - [False] * 7, # joint velocities - [False] * 3, # cup_goal_diff_final - [False] * 3, # cup_goal_diff_top + [False] * 7, # joint velocities + [False] * 3, # cup_goal_diff_final + [False] * 3, # cup_goal_diff_top [True] * 2, # xy position of cup [False] # env steps ]) - @property - def start_pos(self): - return self._start_pos - @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.sim.data.qpos[0:7].copy() + return self.env.sim.data.qpos[0:7].copy() @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.sim.data.qvel[0:7].copy() + return self.env.sim.data.qvel[0:7].copy() - @property - def goal_pos(self): - raise ValueError("Goal position is not available and has to be learnt based on the environment.") + # TODO: Fix this + def _episode_callback(self, action: np.ndarray, mp) -> Tuple[np.ndarray, Union[np.ndarray, None]]: + if mp.learn_tau: + self.env.env.release_step = action[0] / self.env.dt # Tau value + return action, None + else: + return action, None - @property - def dt(self) -> Union[float, int]: - return self.env.dt + def set_context(self, context): + xyz = np.zeros(3) + xyz[:2] = context + xyz[-1] = 0.840 + self.env.env.model.body_pos[self.env.env.cup_table_id] = xyz + return self.get_observation_from_step(self.env.env._get_obs()) diff --git a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py deleted file mode 100644 index e447a49..0000000 --- a/alr_envs/alr/mujoco/beerpong/new_mp_wrapper.py +++ /dev/null @@ -1,41 +0,0 @@ -from typing import Union, Tuple - -import numpy as np - -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - @property - def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qpos[0:7].copy() - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[0:7].copy() - - def get_context_mask(self): - return np.hstack([ - [False] * 7, # cos - [False] * 7, # sin - [False] * 7, # joint velocities - [False] * 3, # cup_goal_diff_final - [False] * 3, # cup_goal_diff_top - [True] * 2, # xy position of cup - [False] # env steps - ]) - - # TODO: Fix this - def _episode_callback(self, action: np.ndarray, mp) -> Tuple[np.ndarray, Union[np.ndarray, None]]: - if mp.learn_tau: - self.env.env.release_step = action[0] / self.env.dt # Tau value - return action, None - else: - return action, None - - def set_context(self, context): - xyz = np.zeros(3) - xyz[:2] = context - xyz[-1] = 0.840 - self.env.env.model.body_pos[self.env.env.cup_table_id] = xyz - return self.get_observation_from_step(self.env.env._get_obs()) diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/__init__.py b/alr_envs/alr/mujoco/half_cheetah_jump/__init__.py index 8a04a02..c5e6d2f 100644 --- a/alr_envs/alr/mujoco/half_cheetah_jump/__init__.py +++ b/alr_envs/alr/mujoco/half_cheetah_jump/__init__.py @@ -1 +1 @@ -from .new_mp_wrapper import MPWrapper +from .mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/half_cheetah_jump.py b/alr_envs/alr/mujoco/half_cheetah_jump/half_cheetah_jump.py index 4b53a5d..a90edf6 100644 --- a/alr_envs/alr/mujoco/half_cheetah_jump/half_cheetah_jump.py +++ b/alr_envs/alr/mujoco/half_cheetah_jump/half_cheetah_jump.py @@ -1,4 +1,7 @@ import os +from typing import Tuple, Union, Optional + +from gym.core import ObsType from gym.envs.mujoco.half_cheetah_v3 import HalfCheetahEnv import numpy as np @@ -20,7 +23,7 @@ class ALRHalfCheetahJumpEnv(HalfCheetahEnv): max_episode_steps=100): self.current_step = 0 self.max_height = 0 - self.max_episode_steps = max_episode_steps + # self.max_episode_steps = max_episode_steps self.goal = 0 self.context = context xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) @@ -37,15 +40,15 @@ class ALRHalfCheetahJumpEnv(HalfCheetahEnv): ## Didnt use fell_over, because base env also has no done condition - Paul and Marc # fell_over = abs(self.sim.data.qpos[2]) > 2.5 # how to figure out if the cheetah fell over? -> 2.5 oke? - # TODO: Should a fall over be checked herE? + # TODO: Should a fall over be checked here? done = False ctrl_cost = self.control_cost(action) costs = ctrl_cost - if self.current_step == self.max_episode_steps: - height_goal_distance = -10*np.linalg.norm(self.max_height - self.goal) + 1e-8 if self.context \ - else self.max_height + if self.current_step == MAX_EPISODE_STEPS_HALFCHEETAHJUMP: + height_goal_distance = -10 * np.linalg.norm(self.max_height - self.goal) + 1e-8 if self.context \ + else self.max_height rewards = self._forward_reward_weight * height_goal_distance else: rewards = 0 @@ -62,7 +65,8 @@ class ALRHalfCheetahJumpEnv(HalfCheetahEnv): def _get_obs(self): return np.append(super()._get_obs(), self.goal) - def reset(self): + def reset(self, *, seed: Optional[int] = None, return_info: bool = False, + options: Optional[dict] = None, ) -> Union[ObsType, Tuple[ObsType, dict]]: self.max_height = 0 self.current_step = 0 self.goal = np.random.uniform(1.1, 1.6, 1) # 1.1 1.6 @@ -80,21 +84,3 @@ class ALRHalfCheetahJumpEnv(HalfCheetahEnv): observation = self._get_obs() return observation - -if __name__ == '__main__': - render_mode = "human" # "human" or "partial" or "final" - env = ALRHalfCheetahJumpEnv() - obs = env.reset() - - for i in range(2000): - # objective.load_result("/tmp/cma") - # test with random actions - ac = env.action_space.sample() - obs, rew, d, info = env.step(ac) - if i % 10 == 0: - env.render(mode=render_mode) - if d: - print('After ', i, ' steps, done: ', d) - env.reset() - - env.close() \ No newline at end of file diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py b/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py index 930da6d..298bf53 100644 --- a/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/half_cheetah_jump/mp_wrapper.py @@ -10,7 +10,7 @@ class MPWrapper(RawInterfaceWrapper): def context_mask(self) -> np.ndarray: return np.hstack([ [False] * 17, - [True] # goal height + [True] # goal height ]) @property @@ -20,11 +20,3 @@ class MPWrapper(RawInterfaceWrapper): @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: return self.env.sim.data.qvel[3:9].copy() - - @property - def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: - raise ValueError("Goal position is not available and has to be learnt based on the environment.") - - @property - def dt(self) -> Union[float, int]: - return self.env.dt diff --git a/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py deleted file mode 100644 index 9a65952..0000000 --- a/alr_envs/alr/mujoco/half_cheetah_jump/new_mp_wrapper.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Tuple, Union - -import numpy as np - -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - def context_mask(self): - return np.hstack([ - [False] * 17, - [True] # goal height - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.sim.data.qpos[3:9].copy() - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[3:9].copy() - diff --git a/alr_envs/alr/mujoco/hopper_jump/__init__.py b/alr_envs/alr/mujoco/hopper_jump/__init__.py index c5e6d2f..e901144 100644 --- a/alr_envs/alr/mujoco/hopper_jump/__init__.py +++ b/alr_envs/alr/mujoco/hopper_jump/__init__.py @@ -1 +1,2 @@ from .mp_wrapper import MPWrapper + diff --git a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py index 78b06d3..7409300 100644 --- a/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/alr/mujoco/hopper_jump/hopper_jump.py @@ -1,3 +1,4 @@ +import copy from typing import Optional from gym.envs.mujoco.hopper_v3 import HopperEnv @@ -7,10 +8,11 @@ import os MAX_EPISODE_STEPS_HOPPERJUMP = 250 -class ALRHopperJumpEnv(HopperEnv): +class HopperJumpEnv(HopperEnv): """ Initialization changes to normal Hopper: - terminate_when_unhealthy: True -> False + - healthy_reward: 1.0 -> 2.0 - healthy_z_range: (0.7, float('inf')) -> (0.5, float('inf')) - healthy_angle_range: (-0.2, 0.2) -> (-float('inf'), float('inf')) - exclude_current_positions_from_observation: True -> False @@ -21,24 +23,28 @@ class ALRHopperJumpEnv(HopperEnv): xml_file='hopper_jump.xml', forward_reward_weight=1.0, ctrl_cost_weight=1e-3, - healthy_reward=1.0, - penalty=0.0, + healthy_reward=2.0, # 1 step + contact_weight=2.0, # 0 step + height_weight=10.0, # 3 step + dist_weight=3.0, # 3 step terminate_when_unhealthy=False, healthy_state_range=(-100.0, 100.0), healthy_z_range=(0.5, float('inf')), healthy_angle_range=(-float('inf'), float('inf')), reset_noise_scale=5e-3, exclude_current_positions_from_observation=False, + sparse=False, ): - self._steps = 0 + self.sparse = sparse + self._height_weight = height_weight + self._dist_weight = dist_weight + self._contact_weight = contact_weight + self.max_height = 0 - # self.penalty = penalty self.goal = 0 - self._floor_geom_id = None - self._foot_geom_id = None - + self._steps = 0 self.contact_with_floor = False self.init_floor_contact = False self.has_left_floor = False @@ -49,12 +55,12 @@ class ALRHopperJumpEnv(HopperEnv): healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, exclude_current_positions_from_observation) + # increase initial height + self.init_qpos[1] = 1.5 + def step(self, action): self._steps += 1 - self._floor_geom_id = self.model.geom_name2id('floor') - self._foot_geom_id = self.model.geom_name2id('foot_geom') - self.do_simulation(action, self.frame_skip) height_after = self.get_body_com("torso")[2] @@ -73,18 +79,19 @@ class ALRHopperJumpEnv(HopperEnv): ctrl_cost = self.control_cost(action) costs = ctrl_cost done = False - goal_dist = np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0])) + goal_dist = np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0])) if self.contact_dist is None and self.contact_with_floor: self.contact_dist = goal_dist rewards = 0 - if self._steps >= MAX_EPISODE_STEPS_HOPPERJUMP: - # healthy_reward = 0 if self.context else self.healthy_reward * self._steps - healthy_reward = self.healthy_reward * 2 # * self._steps - contact_dist = self.contact_dist if self.contact_dist is not None else 5 - dist_reward = self._forward_reward_weight * (-3 * goal_dist + 10 * self.max_height - 2 * contact_dist) - rewards = dist_reward + healthy_reward + if not self.sparse or (self.sparse and self._steps >= MAX_EPISODE_STEPS_HOPPERJUMP): + healthy_reward = self.healthy_reward + distance_reward = goal_dist * self._dist_weight + height_reward = (self.max_height if self.sparse else self.get_body_com("torso")[2]) * self._height_weight + contact_reward = (self.contact_dist or 5) * self._contact_weight + # dist_reward = self._forward_reward_weight * (-3 * goal_dist + 10 * self.max_height - 2 * contact_dist) + rewards = self._forward_reward_weight * (distance_reward + height_reward + contact_reward + healthy_reward) observation = self._get_obs() reward = rewards - costs @@ -97,24 +104,40 @@ class ALRHopperJumpEnv(HopperEnv): height_rew=self.max_height, healthy_reward=self.healthy_reward * 2, healthy=self.is_healthy, - contact_dist=self.contact_dist if self.contact_dist is not None else 0 + contact_dist=self.contact_dist or 0 ) return observation, reward, done, info def _get_obs(self): - return np.append(super()._get_obs(), self.goal) + goal_dist = self.data.get_site_xpos('foot_site') - np.array([self.goal, 0, 0]) + return np.concatenate((super(HopperJumpEnv, self)._get_obs(), goal_dist.copy(), self.goal.copy())) - def reset(self, *, seed: Optional[int] = None, return_info: bool = False, options: Optional[dict] = None, ): - self.goal = self.np_random.uniform(1.4, 2.16, 1)[0] # 1.3 2.3 + def reset_model(self): + super(HopperJumpEnv, self).reset_model() + + self.goal = self.np_random.uniform(0.3, 1.35, 1)[0] + self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = np.array([self.goal, 0, 0]) self.max_height = 0 self._steps = 0 - return super().reset() - # overwrite reset_model to make it deterministic - def reset_model(self): + noise_low = -np.zeros(self.model.nq) + noise_low[3] = -0.5 + noise_low[4] = -0.2 + noise_low[5] = 0 - qpos = self.init_qpos # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) - qvel = self.init_qvel # + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) + noise_high = np.zeros(self.model.nq) + noise_high[3] = 0 + noise_high[4] = 0 + noise_high[5] = 0.785 + + qpos = ( + self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) + + self.init_qpos + ) + qvel = ( + # self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nv) + + self.init_qvel + ) self.set_state(qpos, qvel) @@ -123,6 +146,7 @@ class ALRHopperJumpEnv(HopperEnv): self.contact_with_floor = False self.init_floor_contact = False self.contact_dist = None + return observation def _is_floor_foot_contact(self): @@ -137,184 +161,75 @@ class ALRHopperJumpEnv(HopperEnv): return False -class ALRHopperXYJumpEnv(ALRHopperJumpEnv): +class HopperJumpStepEnv(HopperJumpEnv): + + def __init__(self, + xml_file='hopper_jump.xml', + forward_reward_weight=1.0, + ctrl_cost_weight=1e-3, + healthy_reward=1.0, + height_weight=3, + dist_weight=3, + terminate_when_unhealthy=False, + healthy_state_range=(-100.0, 100.0), + healthy_z_range=(0.5, float('inf')), + healthy_angle_range=(-float('inf'), float('inf')), + reset_noise_scale=5e-3, + exclude_current_positions_from_observation=False + ): + + self._height_weight = height_weight + self._dist_weight = dist_weight + super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, + healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, + exclude_current_positions_from_observation) def step(self, action): - self._floor_geom_id = self.model.geom_name2id('floor') - self._foot_geom_id = self.model.geom_name2id('foot_geom') - self._steps += 1 + self.do_simulation(action, self.frame_skip) + height_after = self.get_body_com("torso")[2] - site_pos_after = self.sim.data.site_xpos[self.model.site_name2id('foot_site')].copy() + site_pos_after = self.data.get_site_xpos('foot_site') self.max_height = max(height_after, self.max_height) - # floor_contact = self._contact_checker(self._floor_geom_id, self._foot_geom_id) if not self.contact_with_floor else False - # self.init_floor_contact = floor_contact if not self.init_floor_contact else self.init_floor_contact - # self.has_left_floor = not floor_contact if self.init_floor_contact and not self.has_left_floor else self.has_left_floor - # self.contact_with_floor = floor_contact if not self.contact_with_floor and self.has_left_floor else self.contact_with_floor - - floor_contact = self._is_floor_foot_contact(self._floor_geom_id, - self._foot_geom_id) if not self.contact_with_floor else False - if not self.init_floor_contact: - self.init_floor_contact = floor_contact - if self.init_floor_contact and not self.has_left_floor: - self.has_left_floor = not floor_contact - if not self.contact_with_floor and self.has_left_floor: - self.contact_with_floor = floor_contact - - if self.contact_dist is None and self.contact_with_floor: - self.contact_dist = np.linalg.norm(self.sim.data.site_xpos[self.model.site_name2id('foot_site')] - - np.array([self.goal, 0, 0])) - ctrl_cost = self.control_cost(action) + healthy_reward = self.healthy_reward + height_reward = self._height_weight * height_after + goal_dist = np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0])) + goal_dist_reward = -self._dist_weight * goal_dist + dist_reward = self._forward_reward_weight * (goal_dist_reward + height_reward) + + rewards = dist_reward + healthy_reward costs = ctrl_cost done = False - goal_dist = np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0])) - rewards = 0 - if self._steps >= self.max_episode_steps: - # healthy_reward = 0 if self.context else self.healthy_reward * self._steps - healthy_reward = self.healthy_reward * 2 # * self._steps - contact_dist = self.contact_dist if self.contact_dist is not None else 5 - dist_reward = self._forward_reward_weight * (-3 * goal_dist + 10 * self.max_height - 2 * contact_dist) - rewards = dist_reward + healthy_reward + + # This is only for logging the distance to goal when first having the contact + has_floor_contact = self._is_floor_foot_contact() if not self.contact_with_floor else False + + if not self.init_floor_contact: + self.init_floor_contact = has_floor_contact + if self.init_floor_contact and not self.has_left_floor: + self.has_left_floor = not has_floor_contact + if not self.contact_with_floor and self.has_left_floor: + self.contact_with_floor = has_floor_contact + + if self.contact_dist is None and self.contact_with_floor: + self.contact_dist = goal_dist + + ############################################################## observation = self._get_obs() reward = rewards - costs info = { 'height': height_after, 'x_pos': site_pos_after, - 'max_height': self.max_height, - 'goal': self.goal, + 'max_height': copy.copy(self.max_height), + 'goal': copy.copy(self.goal), 'goal_dist': goal_dist, - 'height_rew': self.max_height, - 'healthy_reward': self.healthy_reward * 2, - 'healthy': self.is_healthy, - 'contact_dist': self.contact_dist if self.contact_dist is not None else 0 - } - return observation, reward, done, info - - def reset_model(self): - self.init_qpos[1] = 1.5 - self._floor_geom_id = self.model.geom_name2id('floor') - self._foot_geom_id = self.model.geom_name2id('foot_geom') - noise_low = -np.zeros(self.model.nq) - noise_low[3] = -0.5 - noise_low[4] = -0.2 - noise_low[5] = 0 - - noise_high = np.zeros(self.model.nq) - noise_high[3] = 0 - noise_high[4] = 0 - noise_high[5] = 0.785 - - rnd_vec = self.np_random.uniform(low=noise_low, high=noise_high, size=self.model.nq) - qpos = self.init_qpos + rnd_vec - qvel = self.init_qvel - self.set_state(qpos, qvel) - - observation = self._get_obs() - self.has_left_floor = False - self.contact_with_floor = False - self.init_floor_contact = False - self.contact_dist = None - - return observation - - def reset(self): - super().reset() - self.goal = self.np_random.uniform(0.3, 1.35, 1)[0] - self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = np.array([self.goal, 0, 0]) - return self.reset_model() - - def _get_obs(self): - goal_diff = self.sim.data.site_xpos[self.model.site_name2id('foot_site')].copy() \ - - np.array([self.goal, 0, 0]) - return np.concatenate((super(ALRHopperXYJumpEnv, self)._get_obs(), goal_diff)) - - def set_context(self, context): - # context is 4 dimensional - qpos = self.init_qpos - qvel = self.init_qvel - qpos[-3:] = context[:3] - self.goal = context[-1] - self.set_state(qpos, qvel) - self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = np.array([self.goal, 0, 0]) - return self._get_obs() - - -class ALRHopperXYJumpEnvStepBased(ALRHopperXYJumpEnv): - - def __init__( - self, - xml_file='hopper_jump.xml', - forward_reward_weight=1.0, - ctrl_cost_weight=1e-3, - healthy_reward=0.0, - penalty=0.0, - context=True, - terminate_when_unhealthy=False, - healthy_state_range=(-100.0, 100.0), - healthy_z_range=(0.5, float('inf')), - healthy_angle_range=(-float('inf'), float('inf')), - reset_noise_scale=5e-3, - exclude_current_positions_from_observation=False, - max_episode_steps=250, - height_scale=10, - dist_scale=3, - healthy_scale=2 - ): - self.height_scale = height_scale - self.dist_scale = dist_scale - self.healthy_scale = healthy_scale - super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, penalty, context, - terminate_when_unhealthy, healthy_state_range, healthy_z_range, healthy_angle_range, - reset_noise_scale, exclude_current_positions_from_observation, max_episode_steps) - - def step(self, action): - self._floor_geom_id = self.model.geom_name2id('floor') - self._foot_geom_id = self.model.geom_name2id('foot_geom') - - self._steps += 1 - self.do_simulation(action, self.frame_skip) - height_after = self.get_body_com("torso")[2] - site_pos_after = self.sim.data.site_xpos[self.model.site_name2id('foot_site')].copy() - self.max_height = max(height_after, self.max_height) - ctrl_cost = self.control_cost(action) - - healthy_reward = self.healthy_reward * self.healthy_scale - height_reward = self.height_scale * height_after - goal_dist = np.atleast_1d(np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0], dtype=object)))[0] - goal_dist_reward = -self.dist_scale * goal_dist - dist_reward = self._forward_reward_weight * (goal_dist_reward + height_reward) - reward = -ctrl_cost + healthy_reward + dist_reward - done = False - observation = self._get_obs() - - ########################################################### - # This is only for logging the distance to goal when first having the contact - ########################################################## - floor_contact = self._is_floor_foot_contact(self._floor_geom_id, - self._foot_geom_id) if not self.contact_with_floor else False - if not self.init_floor_contact: - self.init_floor_contact = floor_contact - if self.init_floor_contact and not self.has_left_floor: - self.has_left_floor = not floor_contact - if not self.contact_with_floor and self.has_left_floor: - self.contact_with_floor = floor_contact - - if self.contact_dist is None and self.contact_with_floor: - self.contact_dist = np.linalg.norm(self.sim.data.site_xpos[self.model.site_name2id('foot_site')] - - np.array([self.goal, 0, 0])) - info = { - 'height': height_after, - 'x_pos': site_pos_after, - 'max_height': self.max_height, - 'goal': self.goal, - 'goal_dist': goal_dist, - 'height_rew': self.max_height, - 'healthy_reward': self.healthy_reward * self.healthy_reward, - 'healthy': self.is_healthy, - 'contact_dist': self.contact_dist if self.contact_dist is not None else 0 + 'height_rew': height_reward, + 'healthy_reward': healthy_reward, + 'healthy': copy.copy(self.is_healthy), + 'contact_dist': copy.copy(self.contact_dist) or 0 } return observation, reward, done, info diff --git a/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py b/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py index c7b16db..394893e 100644 --- a/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_jump/mp_wrapper.py @@ -8,6 +8,7 @@ from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): # Random x goal + random init pos + @property def context_mask(self): return np.hstack([ [False] * (2 + int(not self.exclude_current_positions_from_observation)), # position diff --git a/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py b/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py index 7778e8c..78c2f51 100644 --- a/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py +++ b/alr_envs/alr/mujoco/hopper_throw/mp_wrapper.py @@ -6,8 +6,9 @@ from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): + @property - def context_mask(self) -> np.ndarray: + def context_mask(self): return np.hstack([ [False] * 17, [True] # goal pos @@ -15,16 +16,8 @@ class MPWrapper(RawInterfaceWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.sim.data.qpos[3:6].copy() + return self.env.data.qpos[3:6].copy() @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[3:6].copy() - - @property - def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: - raise ValueError("Goal position is not available and has to be learnt based on the environment.") - - @property - def dt(self) -> Union[float, int]: - return self.env.dt + return self.env.data.qvel[3:6].copy() diff --git a/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py b/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py deleted file mode 100644 index 01d87a4..0000000 --- a/alr_envs/alr/mujoco/hopper_throw/new_mp_wrapper.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Tuple, Union - -import numpy as np - -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - def context_mask(self): - return np.hstack([ - [False] * 17, - [True] # goal pos - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.sim.data.qpos[3:6].copy() - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[3:6].copy() - - @property - def dt(self) -> Union[float, int]: - return self.env.dt diff --git a/alr_envs/alr/mujoco/reacher/assets/reacher_5links.xml b/alr_envs/alr/mujoco/reacher/assets/reacher_5links.xml index 25a3208..742f45c 100644 --- a/alr_envs/alr/mujoco/reacher/assets/reacher_5links.xml +++ b/alr_envs/alr/mujoco/reacher/assets/reacher_5links.xml @@ -41,7 +41,7 @@ - + diff --git a/alr_envs/alr/mujoco/reacher/mp_wrapper.py b/alr_envs/alr/mujoco/reacher/mp_wrapper.py index de33ae0..37422b1 100644 --- a/alr_envs/alr/mujoco/reacher/mp_wrapper.py +++ b/alr_envs/alr/mujoco/reacher/mp_wrapper.py @@ -15,14 +15,13 @@ class MPWrapper(RawInterfaceWrapper): [True] * 2, # goal position [False] * self.env.n_links, # angular velocity [False] * 3, # goal distance - # self.get_body_com("target"), # only return target to make problem harder - [False], # step + # [False], # step ]) @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qpos.flat[:self.env.n_links] + return self.env.data.qpos.flat[:self.env.n_links] @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel.flat[:self.env.n_links] + return self.env.data.qvel.flat[:self.env.n_links] diff --git a/alr_envs/alr/mujoco/reacher/reacher.py b/alr_envs/alr/mujoco/reacher/reacher.py index a5d34ee..a344879 100644 --- a/alr_envs/alr/mujoco/reacher/reacher.py +++ b/alr_envs/alr/mujoco/reacher/reacher.py @@ -94,12 +94,12 @@ class ReacherEnv(MujocoEnv, utils.EzPickle): return self._get_obs() def _get_obs(self): - theta = self.sim.data.qpos.flat[:self.n_links] + theta = self.data.qpos.flat[:self.n_links] target = self.get_body_com("target") return np.concatenate([ np.cos(theta), np.sin(theta), target[:2], # x-y of goal position - self.sim.data.qvel.flat[:self.n_links], # angular velocity + self.data.qvel.flat[:self.n_links], # angular velocity self.get_body_com("fingertip") - target, # goal distance ]) diff --git a/alr_envs/alr/mujoco/walker_2d_jump/__init__.py b/alr_envs/alr/mujoco/walker_2d_jump/__init__.py index 8a04a02..c5e6d2f 100644 --- a/alr_envs/alr/mujoco/walker_2d_jump/__init__.py +++ b/alr_envs/alr/mujoco/walker_2d_jump/__init__.py @@ -1 +1 @@ -from .new_mp_wrapper import MPWrapper +from .mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py b/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py index 5e9d0eb..63432a7 100644 --- a/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py +++ b/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py @@ -6,25 +6,18 @@ from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): + @property - def context_mask(self) -> np.ndarray: + def context_mask(self): return np.hstack([ [False] * 17, - [True] # goal pos + [True] # goal pos ]) @property def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.sim.data.qpos[3:9].copy() + return self.env.data.qpos[3:9].copy() @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[3:9].copy() - - @property - def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: - raise ValueError("Goal position is not available and has to be learnt based on the environment.") - - @property - def dt(self) -> Union[float, int]: - return self.env.dt + return self.env.data.qvel[3:9].copy() diff --git a/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py b/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py deleted file mode 100644 index b2bfde9..0000000 --- a/alr_envs/alr/mujoco/walker_2d_jump/new_mp_wrapper.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Tuple, Union - -import numpy as np - -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - def context_mask(self): - return np.hstack([ - [False] * 17, - [True] # goal pos - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.sim.data.qpos[3:9].copy() - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[3:9].copy() - - @property - def goal_pos(self) -> Union[float, int, np.ndarray, Tuple]: - raise ValueError("Goal position is not available and has to be learnt based on the environment.") - diff --git a/alr_envs/black_box/black_box_wrapper.py b/alr_envs/black_box/black_box_wrapper.py index 43cc4f0..cec2943 100644 --- a/alr_envs/black_box/black_box_wrapper.py +++ b/alr_envs/black_box/black_box_wrapper.py @@ -1,4 +1,4 @@ -from typing import Tuple, Union +from typing import Tuple, Union, Optional import gym import numpy as np @@ -19,7 +19,7 @@ class BlackBoxWrapper(gym.ObservationWrapper): duration: float, verbose: int = 1, learn_sub_trajectories: bool = False, - replanning_schedule: Union[None, callable] = None, + replanning_schedule: Optional[callable] = None, reward_aggregation: callable = np.sum ): """ @@ -41,7 +41,8 @@ class BlackBoxWrapper(gym.ObservationWrapper): self.duration = duration self.learn_sub_trajectories = learn_sub_trajectories - self.replanning_schedule = replanning_schedule + self.do_replanning = replanning_schedule is not None + self.replanning_schedule = replanning_schedule or (lambda *x: False) self.current_traj_steps = 0 # trajectory generation @@ -55,12 +56,10 @@ class BlackBoxWrapper(gym.ObservationWrapper): self.reward_aggregation = reward_aggregation # spaces - self.return_context_observation = not (self.learn_sub_trajectories or replanning_schedule) - self.traj_gen_action_space = self.get_traj_gen_action_space() - self.action_space = self.get_action_space() - self.observation_space = spaces.Box(low=self.env.observation_space.low[self.env.context_mask], - high=self.env.observation_space.high[self.env.context_mask], - dtype=self.env.observation_space.dtype) + self.return_context_observation = not (learn_sub_trajectories or self.do_replanning) + self.traj_gen_action_space = self._get_traj_gen_action_space() + self.action_space = self._get_action_space() + self.observation_space = self._get_observation_space() # rendering self.render_kwargs = {} @@ -76,23 +75,24 @@ class BlackBoxWrapper(gym.ObservationWrapper): # TODO: Bruce said DMP, ProMP, ProDMP can have 0 bc_time for sequencing # TODO Check with Bruce for replanning self.traj_gen.set_boundary_conditions( - bc_time=np.zeros((1,)) if not self.replanning_schedule else self.current_traj_steps * self.dt, + bc_time=np.zeros((1,)) if not self.do_replanning else np.array([self.current_traj_steps * self.dt]), bc_pos=self.current_pos, bc_vel=self.current_vel) # TODO: is this correct for replanning? Do we need to adjust anything here? - self.traj_gen.set_duration(None if self.learn_sub_trajectories else np.array([self.duration]), np.array([self.dt])) + self.traj_gen.set_duration(None if self.learn_sub_trajectories else np.array([self.duration]), + np.array([self.dt])) traj_dict = self.traj_gen.get_trajs(get_pos=True, get_vel=True) trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] return get_numpy(trajectory_tensor), get_numpy(velocity_tensor) - def get_traj_gen_action_space(self): + def _get_traj_gen_action_space(self): """This function can be used to set up an individual space for the parameters of the traj_gen.""" min_action_bounds, max_action_bounds = self.traj_gen.get_param_bounds() - mp_action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), - dtype=np.float32) - return mp_action_space + action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), + dtype=self.env.action_space.dtype) + return action_space - def get_action_space(self): + def _get_action_space(self): """ This function can be used to modify the action space for considering actions which are not learned via motion primitives. E.g. ball releasing time for the beer pong task. By default, it is the parameter space of the @@ -102,12 +102,21 @@ class BlackBoxWrapper(gym.ObservationWrapper): try: return self.traj_gen_action_space except AttributeError: - return self.get_traj_gen_action_space() + return self._get_traj_gen_action_space() + + def _get_observation_space(self): + mask = self.env.context_mask + if not self.return_context_observation: + # return full observation + mask = np.ones_like(mask, dtype=bool) + min_obs_bound = self.env.observation_space.low[mask] + max_obs_bound = self.env.observation_space.high[mask] + return spaces.Box(low=min_obs_bound, high=max_obs_bound, dtype=self.env.observation_space.dtype) def step(self, action: np.ndarray): """ This function generates a trajectory based on a MP and then does the usual loop over reset and step""" - # agent to learn when to release the ball + # TODO remove this part, right now only needed for beer pong mp_params, env_spec_params = self.env._episode_callback(action, self.traj_gen) trajectory, velocity = self.get_trajectory(mp_params) @@ -121,10 +130,8 @@ class BlackBoxWrapper(gym.ObservationWrapper): infos = dict() done = False - for t, pos_vel in enumerate(zip(trajectory, velocity)): - step_action = self.tracking_controller.get_action(pos_vel[0], pos_vel[1], self.current_pos, - self.current_vel) - step_action = self._step_callback(t, env_spec_params, step_action) # include possible callback info + for t, (pos, vel) in enumerate(zip(trajectory, velocity)): + step_action = self.tracking_controller.get_action(pos, vel, self.current_pos, self.current_vel) c_action = np.clip(step_action, self.env.action_space.low, self.env.action_space.high) # print('step/clipped action ratio: ', step_action/c_action) obs, c_reward, done, info = self.env.step(c_action) @@ -142,36 +149,34 @@ class BlackBoxWrapper(gym.ObservationWrapper): if self.render_kwargs: self.render(**self.render_kwargs) - if done: - break - - if self.replanning_schedule and self.replanning_schedule(self.current_pos, self.current_vel, obs, c_action, - t + 1 + self.current_traj_steps): + if done or self.replanning_schedule(self.current_pos, self.current_vel, obs, c_action, + t + 1 + self.current_traj_steps): break infos.update({k: v[:t + 1] for k, v in infos.items()}) self.current_traj_steps += t + 1 if self.verbose >= 2: - infos['trajectory'] = trajectory + infos['positions'] = trajectory + infos['velocities'] = velocity infos['step_actions'] = actions[:t + 1] infos['step_observations'] = observations[:t + 1] infos['step_rewards'] = rewards[:t + 1] infos['trajectory_length'] = t + 1 trajectory_return = self.reward_aggregation(rewards[:t + 1]) - return obs, trajectory_return, done, infos + return self.observation(obs), trajectory_return, done, infos def render(self, **kwargs): """Only set render options here, such that they can be used during the rollout. This only needs to be called once""" - self.render_kwargs = kwargs + self.render_kwargs = kwargs or self.render_kwargs # self.env.render(mode=self.render_mode, **self.render_kwargs) - self.env.render(**kwargs) + self.env.render(**self.render_kwargs) - def reset(self, **kwargs): + def reset(self, *, seed: Optional[int] = None, return_info: bool = False, options: Optional[dict] = None): self.current_traj_steps = 0 - super(BlackBoxWrapper, self).reset(**kwargs) + return super(BlackBoxWrapper, self).reset(seed=seed, return_info=return_info, options=options) def plot_trajs(self, des_trajs, des_vels): import matplotlib.pyplot as plt diff --git a/alr_envs/black_box/raw_interface_wrapper.py b/alr_envs/black_box/raw_interface_wrapper.py index becbfe3..019a268 100644 --- a/alr_envs/black_box/raw_interface_wrapper.py +++ b/alr_envs/black_box/raw_interface_wrapper.py @@ -57,7 +57,8 @@ class RawInterfaceWrapper(gym.Wrapper): # return bool(self.replanning_model(s)) return False - def _episode_callback(self, action: np.ndarray, traj_gen: MPInterface) -> Tuple[np.ndarray, Union[np.ndarray, None]]: + def _episode_callback(self, action: np.ndarray, traj_gen: MPInterface) -> Tuple[ + np.ndarray, Union[np.ndarray, None]]: """ Used to extract the parameters for the motion primitive and other parameters from an action array which might include other actions like ball releasing time for the beer pong environment. @@ -70,20 +71,3 @@ class RawInterfaceWrapper(gym.Wrapper): Tuple: mp_arguments and other arguments """ return action, None - - def _step_callback(self, t: int, env_spec_params: Union[np.ndarray, None], step_action: np.ndarray) -> Union[ - np.ndarray]: - """ - This function can be used to modify the step_action with additional parameters e.g. releasing the ball in the - Beerpong env. The parameters used should not be part of the motion primitive parameters. - Returns step_action by default, can be overwritten in individual mp_wrappers. - Args: - t: the current time step of the episode - env_spec_params: the environment specific parameter, as defined in function _episode_callback - (e.g. ball release time in Beer Pong) - step_action: the current step-based action - - Returns: - modified step action - """ - return step_action diff --git a/alr_envs/examples/examples_general.py b/alr_envs/examples/examples_general.py index d043d6d..4f184b8 100644 --- a/alr_envs/examples/examples_general.py +++ b/alr_envs/examples/examples_general.py @@ -87,10 +87,10 @@ if __name__ == '__main__': render = True # Basic gym task - example_general("Pendulum-v0", seed=10, iterations=200, render=render) + example_general("Reacher5d-v0", seed=10, iterations=200, render=render) # # Basis task from framework - example_general("alr_envs:HoleReacher-v0", seed=10, iterations=200, render=render) + example_general("Reacher-v0", seed=10, iterations=200, render=render) # # OpenAI Mujoco task example_general("HalfCheetah-v2", seed=10, render=render) diff --git a/alr_envs/examples/examples_movement_primitives.py b/alr_envs/examples/examples_movement_primitives.py index bf1f950..a2f5d54 100644 --- a/alr_envs/examples/examples_movement_primitives.py +++ b/alr_envs/examples/examples_movement_primitives.py @@ -45,7 +45,7 @@ def example_mp(env_name="alr_envs:HoleReacherDMP-v1", seed=1, iterations=1, rend obs = env.reset() -def example_custom_mp(env_name="alr_envs:HoleReacherDMP-v1", seed=1, iterations=1, render=True): +def example_custom_mp(env_name="Reacher5dProMP-v0", seed=1, iterations=1, render=True): """ Example for running a motion primitive based environment, which is already registered Args: @@ -57,32 +57,12 @@ def example_custom_mp(env_name="alr_envs:HoleReacherDMP-v1", seed=1, iterations= Returns: """ - # Changing the traj_gen_kwargs is possible by providing them to gym. - # E.g. here by providing way to many basis functions - # mp_dict = alr_envs.from_default_config('ALRReacher-v0', {'basis_generator_kwargs': {'num_basis': 10}}) - # mp_dict.update({'basis_generator_kwargs': {'num_basis': 10}}) + # Changing the arguments of the black box env is possible by providing them to gym as with all kwargs. + # E.g. here for way to many basis functions + env = alr_envs.make(env_name, seed, basis_generator_kwargs={'num_basis': 1000}) # mp_dict.update({'black_box_kwargs': {'learn_sub_trajectories': True}}) # mp_dict.update({'black_box_kwargs': {'do_replanning': lambda pos, vel, t: lambda t: t % 100}}) - # default env with promp and no learn_sub_trajectories and replanning - # env = alr_envs.make('ALRReacherProMP-v0', 1, n_links=7) - env = alr_envs.make('ALRReacherProMP-v0', 1, basis_generator_kwargs={'num_basis': 10}, n_links=7) - # env = alr_envs.make('ALRReacher-v0', seed=1, bb_kwargs=mp_dict, n_links=1) - # env = alr_envs.make_bb('ALRReacher-v0', **mp_dict) - - mp_kwargs = { - "num_dof": 5, - "num_basis": 1000, - "duration": 2, - "learn_goal": True, - "alpha_phase": 2, - "bandwidth_factor": 2, - "policy_type": "velocity", - "weights_scale": 50, - "goal_scale": 0.1 - } - env = alr_envs.make(env_name, seed, mp_kwargs=mp_kwargs) - # This time rendering every trajectory if render: env.render(mode="human") @@ -100,6 +80,7 @@ def example_custom_mp(env_name="alr_envs:HoleReacherDMP-v1", seed=1, iterations= print(rewards) rewards = 0 obs = env.reset() + print(obs) def example_fully_custom_mp(seed=1, iterations=1, render=True): @@ -169,7 +150,7 @@ if __name__ == '__main__': # example_mp("alr_envs:HoleReacherDetPMP-v1", seed=10, iterations=1, render=render) # Altered basis functions - example_custom_mp("alr_envs:HoleReacherDMP-v1", seed=10, iterations=1, render=render) + example_custom_mp("Reacher5dProMP-v0", seed=10, iterations=10, render=render) # Custom MP - example_fully_custom_mp(seed=10, iterations=1, render=render) + # example_fully_custom_mp(seed=10, iterations=1, render=render) diff --git a/alr_envs/utils/make_env_helpers.py b/alr_envs/utils/make_env_helpers.py index 0051546..ce24205 100644 --- a/alr_envs/utils/make_env_helpers.py +++ b/alr_envs/utils/make_env_helpers.py @@ -43,10 +43,10 @@ def make_rank(env_id: str, seed: int, rank: int = 0, return_callable=True, **kwa def make(env_id, seed, **kwargs): - # spec = registry.get(env_id) # TODO: This doesn't work with gym ==0.21.0 - spec = registry.spec(env_id) + # TODO: This doesn't work with gym ==0.21.0 # This access is required to allow for nested dict updates - all_kwargs = deepcopy(spec._kwargs) + spec = registry.get(env_id) + all_kwargs = deepcopy(spec.kwargs) nested_update(all_kwargs, kwargs) return _make(env_id, seed, **all_kwargs) @@ -148,7 +148,7 @@ def make_bb( phase_kwargs: kwargs for the phase generator controller_kwargs: kwargs for the tracking controller env_id: base_env_name, - wrappers: list of wrappers (at least an BlackBoxWrapper), + wrappers: list of wrappers (at least an RawInterfaceWrapper), seed: seed of environment traj_gen_kwargs: dict of at least {num_dof: int, num_basis: int} for DMP diff --git a/alr_envs/utils/utils.py b/alr_envs/utils/utils.py index cf09e24..f4fea74 100644 --- a/alr_envs/utils/utils.py +++ b/alr_envs/utils/utils.py @@ -1,4 +1,4 @@ -from collections import Mapping, MutableMapping +from collections.abc import Mapping, MutableMapping import numpy as np import torch as ch @@ -46,4 +46,5 @@ def nested_update(base: MutableMapping, update): """ for k, v in update.items(): base[k] = nested_update(base.get(k, {}), v) if isinstance(v, Mapping) else v + return base diff --git a/setup.py b/setup.py index 796c569..055ac81 100644 --- a/setup.py +++ b/setup.py @@ -1,24 +1,35 @@ +import itertools + from setuptools import setup +# Environment-specific dependencies for dmc and metaworld +extras = { + "dmc": ["dm_control"], + "meta": ["mujoco_py<2.2,>=2.1, git+https://github.com/rlworkgroup/metaworld.git@master#egg=metaworld"], + "mujoco": ["mujoco==2.2.0", "imageio>=2.14.1"], +} + +# All dependencies +all_groups = set(extras.keys()) +extras["all"] = list(set(itertools.chain.from_iterable(map(lambda group: extras[group], all_groups)))) + setup( - name='alr_envs', + author='Fabian Otto, Onur Celik, Marcel Sandermann, Maximilian Huettenrauch', + name='simple_gym', version='0.0.1', packages=['alr_envs', 'alr_envs.alr', 'alr_envs.open_ai', 'alr_envs.dmc', 'alr_envs.meta', 'alr_envs.utils'], install_requires=[ 'gym', 'PyQt5', - #'matplotlib', - #'mp_env_api @ git+https://github.com/ALRhub/motion_primitive_env_api.git', -# 'mp_env_api @ git+ssh://git@github.com/ALRhub/motion_primitive_env_api.git', + # 'matplotlib', + # 'mp_env_api @ git+https://github.com/ALRhub/motion_primitive_env_api.git', + # 'mp_env_api @ git+ssh://git@github.com/ALRhub/motion_primitive_env_api.git', 'mujoco-py<2.1,>=2.0', 'dm_control', 'metaworld @ git+https://github.com/rlworkgroup/metaworld.git@master#egg=metaworld', ], - url='https://github.com/ALRhub/alr_envs/', - license='MIT', - author='Fabian Otto, Marcel Sandermann, Maximilian Huettenrauch', + # license='AGPL-3.0 license', author_email='', - description='Custom Gym environments for various (robotics) tasks. integration of DMC environments into the' - 'gym interface, and support for using motion primitives with gym environments.' + description='Simple Gym: Aggregating interface for various RL environments with support for Black Box approaches.' ) From 3a989e179b00552205080b4c6e67440d93886b6e Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 6 Jul 2022 09:10:31 +0200 Subject: [PATCH 062/104] remove two table tennis and Ball in cup envs --- alr_envs/alr/mujoco/ant_jump/mp_wrapper.py | 23 - alr_envs/alr/mujoco/ball_in_a_cup/__init__.py | 1 - .../mujoco/ball_in_a_cup/alr_reward_fct.py | 21 - .../mujoco/ball_in_a_cup/assets/biac_base.xml | 361 ---------------- .../alr/mujoco/ball_in_a_cup/ball_in_a_cup.py | 195 --------- .../ball_in_a_cup/ball_in_a_cup_mp_wrapper.py | 42 -- .../ball_in_a_cup/ball_in_a_cup_reward.py | 142 ------- .../ball_in_a_cup_reward_simple.py | 116 ----- alr_envs/alr/mujoco/ball_in_a_cup/biac_pd.py | 194 --------- alr_envs/alr/mujoco/beerpong/mp_wrapper.py | 42 -- .../alr/mujoco/gym_table_tennis/__init__.py | 1 - .../mujoco/gym_table_tennis/envs/__init__.py | 1 - .../envs/assets/include_7_motor_actuator.xml | 12 - .../assets/include_barrett_wam_7dof_left.xml | 76 ---- .../assets/include_barrett_wam_7dof_right.xml | 95 ----- .../envs/assets/include_table.xml | 38 -- .../envs/assets/include_target_ball.xml | 10 - .../envs/assets/include_test_balls.xml | 80 ---- .../envs/assets/meshes/base_link_convex.stl | Bin 16584 -> 0 bytes .../envs/assets/meshes/base_link_fine.stl | Bin 720584 -> 0 bytes .../meshes/bhand_finger_dist_link_fine.stl | Bin 410684 -> 0 bytes .../meshes/bhand_finger_med_link_convex.stl | Bin 16084 -> 0 bytes .../meshes/bhand_finger_med_link_fine.stl | Bin 87484 -> 0 bytes ...nger_prox_link_convex_decomposition_p1.stl | Bin 7084 -> 0 bytes ...nger_prox_link_convex_decomposition_p3.stl | Bin 4584 -> 0 bytes .../meshes/bhand_finger_prox_link_fine.stl | Bin 235784 -> 0 bytes ...hand_palm_link_convex_decomposition_p1.stl | Bin 96584 -> 0 bytes ...hand_palm_link_convex_decomposition_p2.stl | Bin 59384 -> 0 bytes ...hand_palm_link_convex_decomposition_p3.stl | Bin 77684 -> 0 bytes ...hand_palm_link_convex_decomposition_p4.stl | Bin 6884 -> 0 bytes .../envs/assets/meshes/elbow_link_convex.stl | Bin 16484 -> 0 bytes .../forearm_link_convex_decomposition_p1.stl | Bin 33484 -> 0 bytes .../forearm_link_convex_decomposition_p2.stl | Bin 205484 -> 0 bytes .../envs/assets/meshes/forearm_link_fine.stl | Bin 154484 -> 0 bytes .../shoulder_link_convex_decomposition_p1.stl | Bin 23284 -> 0 bytes .../shoulder_link_convex_decomposition_p2.stl | Bin 60284 -> 0 bytes .../shoulder_link_convex_decomposition_p3.stl | Bin 56284 -> 0 bytes .../envs/assets/meshes/shoulder_link_fine.stl | Bin 362984 -> 0 bytes .../meshes/shoulder_pitch_link_convex.stl | Bin 24284 -> 0 bytes .../meshes/shoulder_pitch_link_fine.stl | Bin 146084 -> 0 bytes ...upper_arm_link_convex_decomposition_p1.stl | Bin 104884 -> 0 bytes ...upper_arm_link_convex_decomposition_p2.stl | Bin 13484 -> 0 bytes .../assets/meshes/upper_arm_link_fine.stl | Bin 615684 -> 0 bytes .../assets/meshes/wrist_palm_link_convex.stl | Bin 7684 -> 0 bytes ...ist_pitch_link_convex_decomposition_p1.stl | Bin 35284 -> 0 bytes ...ist_pitch_link_convex_decomposition_p2.stl | Bin 34284 -> 0 bytes ...ist_pitch_link_convex_decomposition_p3.stl | Bin 33284 -> 0 bytes .../assets/meshes/wrist_pitch_link_fine.stl | Bin 563684 -> 0 bytes ...wrist_yaw_link_convex_decomposition_p1.stl | Bin 19284 -> 0 bytes ...wrist_yaw_link_convex_decomposition_p2.stl | Bin 63684 -> 0 bytes .../assets/meshes/wrist_yaw_link_fine.stl | Bin 1316784 -> 0 bytes .../envs/assets/right_arm_actuator.xml | 19 - .../gym_table_tennis/envs/assets/shared.xml | 49 --- .../envs/assets/table_tennis_env.xml | 41 -- .../gym_table_tennis/envs/table_tennis_env.py | 244 ----------- .../mujoco/gym_table_tennis/utils/__init__.py | 0 .../gym_table_tennis/utils/experiment.py | 83 ---- .../utils/rewards/__init__.py | 0 .../utils/rewards/hierarchical_reward.py | 402 ------------------ .../gym_table_tennis/utils/rewards/rewards.py | 136 ------ .../alr/mujoco/gym_table_tennis/utils/util.py | 49 --- alr_envs/alr/mujoco/table_tennis/__init__.py | 1 - .../alr/mujoco/table_tennis/mp_wrapper.py | 38 -- alr_envs/alr/mujoco/table_tennis/tt_gym.py | 184 -------- alr_envs/alr/mujoco/table_tennis/tt_reward.py | 48 --- alr_envs/alr/mujoco/table_tennis/tt_utils.py | 26 -- .../xml/include_7_motor_actuator.xml | 12 - .../xml/include_barrett_wam_7dof_right.xml | 103 ----- .../mujoco/table_tennis/xml/include_table.xml | 30 -- .../table_tennis/xml/include_target_ball.xml | 10 - .../table_tennis/xml/right_arm_actuator.xml | 47 -- .../alr/mujoco/table_tennis/xml/shared.xml | 46 -- .../table_tennis/xml/table_tennis_env.xml | 18 - .../alr/mujoco/walker_2d_jump/mp_wrapper.py | 23 - 74 files changed, 3059 deletions(-) delete mode 100644 alr_envs/alr/mujoco/ant_jump/mp_wrapper.py delete mode 100644 alr_envs/alr/mujoco/ball_in_a_cup/__init__.py delete mode 100644 alr_envs/alr/mujoco/ball_in_a_cup/alr_reward_fct.py delete mode 100644 alr_envs/alr/mujoco/ball_in_a_cup/assets/biac_base.xml delete mode 100644 alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup.py delete mode 100644 alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_mp_wrapper.py delete mode 100644 alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward.py delete mode 100644 alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward_simple.py delete mode 100644 alr_envs/alr/mujoco/ball_in_a_cup/biac_pd.py delete mode 100644 alr_envs/alr/mujoco/beerpong/mp_wrapper.py delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/__init__.py delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/__init__.py delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_7_motor_actuator.xml delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_barrett_wam_7dof_left.xml delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_barrett_wam_7dof_right.xml delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_table.xml delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_target_ball.xml delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_test_balls.xml delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/base_link_convex.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/base_link_fine.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_finger_dist_link_fine.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_finger_med_link_convex.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_finger_med_link_fine.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_finger_prox_link_convex_decomposition_p1.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_finger_prox_link_convex_decomposition_p3.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_finger_prox_link_fine.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_palm_link_convex_decomposition_p1.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_palm_link_convex_decomposition_p2.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_palm_link_convex_decomposition_p3.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_palm_link_convex_decomposition_p4.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/elbow_link_convex.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/forearm_link_convex_decomposition_p1.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/forearm_link_convex_decomposition_p2.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/forearm_link_fine.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/shoulder_link_convex_decomposition_p1.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/shoulder_link_convex_decomposition_p2.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/shoulder_link_convex_decomposition_p3.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/shoulder_link_fine.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/shoulder_pitch_link_convex.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/shoulder_pitch_link_fine.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/upper_arm_link_convex_decomposition_p1.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/upper_arm_link_convex_decomposition_p2.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/upper_arm_link_fine.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_palm_link_convex.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_pitch_link_convex_decomposition_p1.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_pitch_link_convex_decomposition_p2.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_pitch_link_convex_decomposition_p3.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_pitch_link_fine.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_yaw_link_convex_decomposition_p1.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_yaw_link_convex_decomposition_p2.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_yaw_link_fine.stl delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/right_arm_actuator.xml delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/shared.xml delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/assets/table_tennis_env.xml delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/envs/table_tennis_env.py delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/utils/__init__.py delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/utils/experiment.py delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/utils/rewards/__init__.py delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/utils/rewards/hierarchical_reward.py delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/utils/rewards/rewards.py delete mode 100644 alr_envs/alr/mujoco/gym_table_tennis/utils/util.py delete mode 100644 alr_envs/alr/mujoco/table_tennis/__init__.py delete mode 100644 alr_envs/alr/mujoco/table_tennis/mp_wrapper.py delete mode 100644 alr_envs/alr/mujoco/table_tennis/tt_gym.py delete mode 100644 alr_envs/alr/mujoco/table_tennis/tt_reward.py delete mode 100644 alr_envs/alr/mujoco/table_tennis/tt_utils.py delete mode 100644 alr_envs/alr/mujoco/table_tennis/xml/include_7_motor_actuator.xml delete mode 100644 alr_envs/alr/mujoco/table_tennis/xml/include_barrett_wam_7dof_right.xml delete mode 100644 alr_envs/alr/mujoco/table_tennis/xml/include_table.xml delete mode 100644 alr_envs/alr/mujoco/table_tennis/xml/include_target_ball.xml delete mode 100644 alr_envs/alr/mujoco/table_tennis/xml/right_arm_actuator.xml delete mode 100644 alr_envs/alr/mujoco/table_tennis/xml/shared.xml delete mode 100644 alr_envs/alr/mujoco/table_tennis/xml/table_tennis_env.xml delete mode 100644 alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py diff --git a/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py b/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py deleted file mode 100644 index a481d6f..0000000 --- a/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Union, Tuple - -import numpy as np - -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - - @property - def context_mask(self): - return np.hstack([ - [False] * 111, # ant has 111 dimensional observation space !! - [True] # goal height - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.sim.data.qpos[7:15].copy() - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[6:14].copy() diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/__init__.py b/alr_envs/alr/mujoco/ball_in_a_cup/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/alr_envs/alr/mujoco/ball_in_a_cup/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/alr_reward_fct.py b/alr_envs/alr/mujoco/ball_in_a_cup/alr_reward_fct.py deleted file mode 100644 index c96dd07..0000000 --- a/alr_envs/alr/mujoco/ball_in_a_cup/alr_reward_fct.py +++ /dev/null @@ -1,21 +0,0 @@ -class AlrReward: - """ - A base class for non-Markovian reward functions which may need trajectory information to calculate an episodic - reward. Call the methods in reset() and step() of the environment. - """ - - # methods to override: - # ---------------------------- - def reset(self, *args, **kwargs): - """ - Reset the reward function, empty state buffers before an episode, set contexts that influence reward, etc. - """ - raise NotImplementedError - - def compute_reward(self, *args, **kwargs): - """ - - Returns: Useful things to return are reward values, success flags or crash flags - - """ - raise NotImplementedError diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/assets/biac_base.xml b/alr_envs/alr/mujoco/ball_in_a_cup/assets/biac_base.xml deleted file mode 100644 index 9229ad5..0000000 --- a/alr_envs/alr/mujoco/ball_in_a_cup/assets/biac_base.xml +++ /dev/null @@ -1,361 +0,0 @@ - - - diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup.py b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup.py deleted file mode 100644 index 7b286bc..0000000 --- a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup.py +++ /dev/null @@ -1,195 +0,0 @@ -from gym import utils -import os -import numpy as np -from gym.envs.mujoco import MujocoEnv - - -class ALRBallInACupEnv(MujocoEnv, utils.EzPickle): - def __init__( - self, n_substeps=4, apply_gravity_comp=True, simplified: bool = False, - reward_type: str = None, context: np.ndarray = None - ): - utils.EzPickle.__init__(**locals()) - self._steps = 0 - - self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", "biac_base.xml") - - self._q_pos = [] - self._q_vel = [] - # self.weight_matrix_scale = 50 - self.max_ctrl = np.array([150., 125., 40., 60., 5., 5., 2.]) - - self.j_min = np.array([-2.6, -1.985, -2.8, -0.9, -4.55, -1.5707, -2.7]) - self.j_max = np.array([2.6, 1.985, 2.8, 3.14159, 1.25, 1.5707, 2.7]) - - self.context = context - - alr_mujoco_env.AlrMujocoEnv.__init__(self, self.xml_path, apply_gravity_comp=apply_gravity_comp, - n_substeps=n_substeps) - self._start_pos = np.array([0.0, 0.58760536, 0.0, 1.36004913, 0.0, -0.32072943, -1.57]) - self._start_vel = np.zeros(7) - - self.simplified = simplified - - self.sim_time = 8 # seconds - self.sim_steps = int(self.sim_time / self.dt) - if reward_type == "no_context": - from alr_envs.alr.mujoco.ball_in_a_cup.ball_in_a_cup_reward_simple import BallInACupReward - reward_function = BallInACupReward - elif reward_type == "contextual_goal": - from alr_envs.alr.mujoco.ball_in_a_cup.ball_in_a_cup_reward import BallInACupReward - reward_function = BallInACupReward - else: - raise ValueError("Unknown reward type: {}".format(reward_type)) - self.reward_function = reward_function(self.sim_steps) - - @property - def start_pos(self): - if self.simplified: - return self._start_pos[1::2] - else: - return self._start_pos - - @property - def start_vel(self): - if self.simplified: - return self._start_vel[1::2] - else: - return self._start_vel - - @property - def current_pos(self): - return self.sim.data.qpos[0:7].copy() - - @property - def current_vel(self): - return self.sim.data.qvel[0:7].copy() - - def reset(self): - self.reward_function.reset(None) - return super().reset() - - def reset_model(self): - init_pos_all = self.init_qpos.copy() - init_pos_robot = self._start_pos - init_vel = np.zeros_like(init_pos_all) - - self._steps = 0 - self._q_pos = [] - self._q_vel = [] - - start_pos = init_pos_all - start_pos[0:7] = init_pos_robot - - self.set_state(start_pos, init_vel) - - return self._get_obs() - - def step(self, a): - reward_dist = 0.0 - angular_vel = 0.0 - reward_ctrl = - np.square(a).sum() - - crash = self.do_simulation(a) - # joint_cons_viol = self.check_traj_in_joint_limits() - - self._q_pos.append(self.sim.data.qpos[0:7].ravel().copy()) - self._q_vel.append(self.sim.data.qvel[0:7].ravel().copy()) - - ob = self._get_obs() - - if not crash: - reward, success, is_collided = self.reward_function.compute_reward(a, self) - done = success or self._steps == self.sim_steps - 1 or is_collided - self._steps += 1 - else: - reward = -2000 - success = False - is_collided = False - done = True - return ob, reward, done, dict(reward_dist=reward_dist, - reward_ctrl=reward_ctrl, - velocity=angular_vel, - # traj=self._q_pos, - action=a, - q_pos=self.sim.data.qpos[0:7].ravel().copy(), - q_vel=self.sim.data.qvel[0:7].ravel().copy(), - is_success=success, - is_collided=is_collided, sim_crash=crash) - - def check_traj_in_joint_limits(self): - return any(self.current_pos > self.j_max) or any(self.current_pos < self.j_min) - - # TODO: extend observation space - def _get_obs(self): - theta = self.sim.data.qpos.flat[:7] - return np.concatenate([ - np.cos(theta), - np.sin(theta), - # self.get_body_com("target"), # only return target to make problem harder - [self._steps], - ]) - - # TODO - @property - def active_obs(self): - return np.hstack([ - [False] * 7, # cos - [False] * 7, # sin - # [True] * 2, # x-y coordinates of target distance - [False] # env steps - ]) - - # These functions are for the task with 3 joint actuations - def extend_des_pos(self, des_pos): - des_pos_full = self._start_pos.copy() - des_pos_full[1] = des_pos[0] - des_pos_full[3] = des_pos[1] - des_pos_full[5] = des_pos[2] - return des_pos_full - - def extend_des_vel(self, des_vel): - des_vel_full = self._start_vel.copy() - des_vel_full[1] = des_vel[0] - des_vel_full[3] = des_vel[1] - des_vel_full[5] = des_vel[2] - return des_vel_full - - def render(self, render_mode, **render_kwargs): - if render_mode == "plot_trajectory": - if self._steps == 1: - import matplotlib.pyplot as plt - # plt.ion() - self.fig, self.axs = plt.subplots(3, 1) - - if self._steps <= 1750: - for ax, cp in zip(self.axs, self.current_pos[1::2]): - ax.scatter(self._steps, cp, s=2, marker=".") - - # self.fig.show() - - else: - super().render(render_mode, **render_kwargs) - - -if __name__ == "__main__": - env = ALRBallInACupEnv() - ctxt = np.array([-0.20869846, -0.66376693, 1.18088501]) - - env.configure(ctxt) - env.reset() - # env.render() - for i in range(16000): - # test with random actions - ac = 0.001 * env.action_space.sample()[0:7] - # ac = env.start_pos - # ac[0] += np.pi/2 - obs, rew, d, info = env.step(ac) - # env.render() - - print(rew) - - if d: - break - - env.close() diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_mp_wrapper.py b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_mp_wrapper.py deleted file mode 100644 index 81a08f5..0000000 --- a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_mp_wrapper.py +++ /dev/null @@ -1,42 +0,0 @@ -from typing import Tuple, Union - -import numpy as np - -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper - - -class BallInACupMPWrapper(RawInterfaceWrapper): - - @property - def context_mask(self) -> np.ndarray: - # TODO: @Max Filter observations correctly - return np.hstack([ - [False] * 7, # cos - [False] * 7, # sin - # [True] * 2, # x-y coordinates of target distance - [False] # env steps - ]) - - @property - def start_pos(self): - if self.simplified: - return self._start_pos[1::2] - else: - return self._start_pos - - @property - def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.sim.data.qpos[0:7].copy() - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.sim.data.qvel[0:7].copy() - - @property - def goal_pos(self): - # TODO: @Max I think the default value of returning to the start is reasonable here - raise ValueError("Goal position is not available and has to be learnt based on the environment.") - - @property - def dt(self) -> Union[float, int]: - return self.env.dt diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward.py b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward.py deleted file mode 100644 index b4d0e6e..0000000 --- a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward.py +++ /dev/null @@ -1,142 +0,0 @@ -import numpy as np -from alr_envs.alr.mujoco.ball_in_a_cup import alr_reward_fct - - -class BallInACupReward(alr_reward_fct.AlrReward): - def __init__(self, sim_time): - self.sim_time = sim_time - - self.collision_objects = ["cup_geom1", "cup_geom2", "wrist_palm_link_convex_geom", - "wrist_pitch_link_convex_decomposition_p1_geom", - "wrist_pitch_link_convex_decomposition_p2_geom", - "wrist_pitch_link_convex_decomposition_p3_geom", - "wrist_yaw_link_convex_decomposition_p1_geom", - "wrist_yaw_link_convex_decomposition_p2_geom", - "forearm_link_convex_decomposition_p1_geom", - "forearm_link_convex_decomposition_p2_geom"] - - self.ball_id = None - self.ball_collision_id = None - self.goal_id = None - self.goal_final_id = None - self.collision_ids = None - - self.ball_traj = None - self.dists = None - self.dists_ctxt = None - self.dists_final = None - self.costs = None - - self.reset(None) - - def reset(self, context): - self.ball_traj = np.zeros(shape=(self.sim_time, 3)) - self.cup_traj = np.zeros(shape=(self.sim_time, 3)) - self.dists = [] - self.dists_ctxt = [] - self.dists_final = [] - self.costs = [] - self.context = context - self.ball_in_cup = False - self.ball_above_threshold = False - self.dist_ctxt = 3 - self.action_costs = [] - self.cup_angles = [] - - def compute_reward(self, action, sim, step): - action_cost = np.sum(np.square(action)) - self.action_costs.append(action_cost) - - stop_sim = False - success = False - - self.ball_id = sim.model._body_name2id["ball"] - self.ball_collision_id = sim.model._geom_name2id["ball_geom"] - self.goal_id = sim.model._site_name2id["cup_goal"] - self.goal_final_id = sim.model._site_name2id["cup_goal_final"] - self.collision_ids = [sim.model._geom_name2id[name] for name in self.collision_objects] - - if self.check_collision(sim): - reward = - 1e-3 * action_cost - 1000 - stop_sim = True - return reward, success, stop_sim - - # Compute the current distance from the ball to the inner part of the cup - goal_pos = sim.data.site_xpos[self.goal_id] - ball_pos = sim.data.body_xpos[self.ball_id] - goal_final_pos = sim.data.site_xpos[self.goal_final_id] - self.dists.append(np.linalg.norm(goal_pos - ball_pos)) - self.dists_final.append(np.linalg.norm(goal_final_pos - ball_pos)) - self.dists_ctxt.append(np.linalg.norm(ball_pos - self.context)) - self.ball_traj[step, :] = np.copy(ball_pos) - self.cup_traj[step, :] = np.copy(goal_pos) # ? - cup_quat = np.copy(sim.data.body_xquat[sim.model._body_name2id["cup"]]) - self.cup_angles.append(np.arctan2(2 * (cup_quat[0] * cup_quat[1] + cup_quat[2] * cup_quat[3]), - 1 - 2 * (cup_quat[1] ** 2 + cup_quat[2] ** 2))) - - # Determine the first time when ball is in cup - if not self.ball_in_cup: - ball_in_cup = self.check_ball_in_cup(sim, self.ball_collision_id) - self.ball_in_cup = ball_in_cup - if ball_in_cup: - dist_to_ctxt = np.linalg.norm(ball_pos - self.context) - self.dist_ctxt = dist_to_ctxt - - if step == self.sim_time - 1: - t_min_dist = np.argmin(self.dists) - angle_min_dist = self.cup_angles[t_min_dist] - cost_angle = (angle_min_dist - np.pi / 2) ** 2 - - min_dist = np.min(self.dists) - dist_final = self.dists_final[-1] - # dist_ctxt = self.dists_ctxt[-1] - - # # max distance between ball and cup and cup height at that time - # ball_to_cup_diff = self.ball_traj[:, 2] - self.cup_traj[:, 2] - # t_max_diff = np.argmax(ball_to_cup_diff) - # t_max_ball_height = np.argmax(self.ball_traj[:, 2]) - # max_ball_height = np.max(self.ball_traj[:, 2]) - - # cost = self._get_stage_wise_cost(ball_in_cup, min_dist, dist_final, dist_ctxt) - cost = 0.5 * min_dist + 0.5 * dist_final + 0.3 * np.minimum(self.dist_ctxt, 3) + 0.01 * cost_angle - reward = np.exp(-2 * cost) - 1e-3 * action_cost - # if max_ball_height < self.context[2] or ball_to_cup_diff[t_max_ball_height] < 0: - # reward -= 1 - - success = dist_final < 0.05 and self.dist_ctxt < 0.05 - else: - reward = - 1e-3 * action_cost - success = False - - return reward, success, stop_sim - - def _get_stage_wise_cost(self, ball_in_cup, min_dist, dist_final, dist_to_ctxt): - if not ball_in_cup: - cost = 3 + 2*(0.5 * min_dist**2 + 0.5 * dist_final**2) - else: - cost = 2 * dist_to_ctxt ** 2 - print('Context Distance:', dist_to_ctxt) - return cost - - def check_ball_in_cup(self, sim, ball_collision_id): - cup_base_collision_id = sim.model._geom_name2id["cup_base_contact"] - for coni in range(0, sim.data.ncon): - con = sim.data.contact[coni] - - collision = con.geom1 == cup_base_collision_id and con.geom2 == ball_collision_id - collision_trans = con.geom1 == ball_collision_id and con.geom2 == cup_base_collision_id - - if collision or collision_trans: - return True - return False - - def check_collision(self, sim): - for coni in range(0, sim.data.ncon): - con = sim.data.contact[coni] - - collision = con.geom1 in self.collision_ids and con.geom2 == self.ball_collision_id - collision_trans = con.geom1 == self.ball_collision_id and con.geom2 in self.collision_ids - - if collision or collision_trans: - return True - return False diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward_simple.py b/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward_simple.py deleted file mode 100644 index 8044eb8..0000000 --- a/alr_envs/alr/mujoco/ball_in_a_cup/ball_in_a_cup_reward_simple.py +++ /dev/null @@ -1,116 +0,0 @@ -import numpy as np -from alr_envs.alr.mujoco.ball_in_a_cup import alr_reward_fct - - -class BallInACupReward(alr_reward_fct.AlrReward): - def __init__(self, env): - self.env = env - self.collision_objects = ["cup_geom1", "cup_geom2", "cup_base_contact_below", - "wrist_palm_link_convex_geom", - "wrist_pitch_link_convex_decomposition_p1_geom", - "wrist_pitch_link_convex_decomposition_p2_geom", - "wrist_pitch_link_convex_decomposition_p3_geom", - "wrist_yaw_link_convex_decomposition_p1_geom", - "wrist_yaw_link_convex_decomposition_p2_geom", - "forearm_link_convex_decomposition_p1_geom", - "forearm_link_convex_decomposition_p2_geom"] - - self.ball_id = None - self.ball_collision_id = None - self.goal_id = None - self.goal_final_id = None - self.collision_ids = None - self._is_collided = False - self.collision_penalty = 1000 - - self.ball_traj = None - self.dists = None - self.dists_final = None - self.costs = None - - self.reset(None) - - def reset(self, context): - # self.sim_time = self.env.sim.dtsim_time - self.ball_traj = [] # np.zeros(shape=(self.sim_time, 3)) - self.dists = [] - self.dists_final = [] - self.costs = [] - self.action_costs = [] - self.angle_costs = [] - self.cup_angles = [] - - def compute_reward(self, action): - self.ball_id = self.env.sim.model._body_name2id["ball"] - self.ball_collision_id = self.env.sim.model._geom_name2id["ball_geom"] - self.goal_id = self.env.sim.model._site_name2id["cup_goal"] - self.goal_final_id = self.env.sim.model._site_name2id["cup_goal_final"] - self.collision_ids = [self.env.sim.model._geom_name2id[name] for name in self.collision_objects] - - ball_in_cup = self.check_ball_in_cup(self.env.sim, self.ball_collision_id) - - # Compute the current distance from the ball to the inner part of the cup - goal_pos = self.env.sim.data.site_xpos[self.goal_id] - ball_pos = self.env.sim.data.body_xpos[self.ball_id] - goal_final_pos = self.env.sim.data.site_xpos[self.goal_final_id] - self.dists.append(np.linalg.norm(goal_pos - ball_pos)) - self.dists_final.append(np.linalg.norm(goal_final_pos - ball_pos)) - # self.ball_traj[self.env._steps, :] = ball_pos - self.ball_traj.append(ball_pos) - cup_quat = np.copy(self.env.sim.data.body_xquat[self.env.sim.model._body_name2id["cup"]]) - cup_angle = np.arctan2(2 * (cup_quat[0] * cup_quat[1] + cup_quat[2] * cup_quat[3]), - 1 - 2 * (cup_quat[1]**2 + cup_quat[2]**2)) - cost_angle = (cup_angle - np.pi / 2) ** 2 - self.angle_costs.append(cost_angle) - self.cup_angles.append(cup_angle) - - action_cost = np.sum(np.square(action)) - self.action_costs.append(action_cost) - - self._is_collided = self.check_collision(self.env.sim) or self.env._check_traj_in_joint_limits() - - if self.env._steps == self.env.ep_length - 1 or self._is_collided: - t_min_dist = np.argmin(self.dists) - angle_min_dist = self.cup_angles[t_min_dist] - # cost_angle = (angle_min_dist - np.pi / 2)**2 - - - # min_dist = self.dists[t_min_dist] - dist_final = self.dists_final[-1] - min_dist_final = np.min(self.dists_final) - - # cost = 0.5 * dist_final + 0.05 * cost_angle # TODO: Increase cost_angle weight # 0.5 * min_dist + - # reward = np.exp(-2 * cost) - 1e-2 * action_cost - self.collision_penalty * int(self._is_collided) - # reward = - dist_final**2 - 1e-4 * cost_angle - 1e-5 * action_cost - self.collision_penalty * int(self._is_collided) - reward = - dist_final**2 - min_dist_final**2 - 1e-4 * cost_angle - 1e-3 * action_cost - self.collision_penalty * int(self._is_collided) - success = dist_final < 0.05 and ball_in_cup and not self._is_collided - crash = self._is_collided - else: - reward = - 1e-3 * action_cost - 1e-4 * cost_angle # TODO: increase action_cost weight - success = False - crash = False - - return reward, success, crash - - def check_ball_in_cup(self, sim, ball_collision_id): - cup_base_collision_id = sim.model._geom_name2id["cup_base_contact"] - for coni in range(0, sim.data.ncon): - con = sim.data.contact[coni] - - collision = con.geom1 == cup_base_collision_id and con.geom2 == ball_collision_id - collision_trans = con.geom1 == ball_collision_id and con.geom2 == cup_base_collision_id - - if collision or collision_trans: - return True - return False - - def check_collision(self, sim): - for coni in range(0, sim.data.ncon): - con = sim.data.contact[coni] - - collision = con.geom1 in self.collision_ids and con.geom2 == self.ball_collision_id - collision_trans = con.geom1 == self.ball_collision_id and con.geom2 in self.collision_ids - - if collision or collision_trans: - return True - return False diff --git a/alr_envs/alr/mujoco/ball_in_a_cup/biac_pd.py b/alr_envs/alr/mujoco/ball_in_a_cup/biac_pd.py deleted file mode 100644 index 4abfb6c..0000000 --- a/alr_envs/alr/mujoco/ball_in_a_cup/biac_pd.py +++ /dev/null @@ -1,194 +0,0 @@ -import os - -import gym.envs.mujoco -import gym.envs.mujoco as mujoco_env -import mujoco_py.builder -import numpy as np -from gym import utils - - -class ALRBallInACupPDEnv(mujoco_env.MujocoEnv, utils.EzPickle): - def __init__(self, frame_skip=4, apply_gravity_comp=True, simplified: bool = False, - reward_type: str = None, context: np.ndarray = None): - utils.EzPickle.__init__(**locals()) - self._steps = 0 - - self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", "biac_base.xml") - - self.max_ctrl = np.array([150., 125., 40., 60., 5., 5., 2.]) - - self.j_min = np.array([-2.6, -1.985, -2.8, -0.9, -4.55, -1.5707, -2.7]) - self.j_max = np.array([2.6, 1.985, 2.8, 3.14159, 1.25, 1.5707, 2.7]) - - self.context = context - self.apply_gravity_comp = apply_gravity_comp - self.simplified = simplified - - self._start_pos = np.array([0.0, 0.58760536, 0.0, 1.36004913, 0.0, -0.32072943, -1.57]) - self._start_vel = np.zeros(7) - - self.sim_time = 8 # seconds - self._dt = 0.02 - self.ep_length = 4000 # based on 8 seconds with dt = 0.02 int(self.sim_time / self.dt) - if reward_type == "no_context": - from alr_envs.alr.mujoco.ball_in_a_cup.ball_in_a_cup_reward_simple import BallInACupReward - reward_function = BallInACupReward - elif reward_type == "contextual_goal": - from alr_envs.alr.mujoco.ball_in_a_cup.ball_in_a_cup_reward import BallInACupReward - reward_function = BallInACupReward - else: - raise ValueError("Unknown reward type: {}".format(reward_type)) - self.reward_function = reward_function(self) - - mujoco_env.MujocoEnv.__init__(self, self.xml_path, frame_skip) - - @property - def dt(self): - return self._dt - - # TODO: @Max is this even needed? - @property - def start_vel(self): - if self.simplified: - return self._start_vel[1::2] - else: - return self._start_vel - - # def _set_action_space(self): - # if self.simplified: - # bounds = self.model.actuator_ctrlrange.copy().astype(np.float32)[1::2] - # else: - # bounds = self.model.actuator_ctrlrange.copy().astype(np.float32) - # low, high = bounds.T - # self.action_space = spaces.Box(low=low, high=high, dtype=np.float32) - # return self.action_space - - def reset(self): - self.reward_function.reset(None) - return super().reset() - - def reset_model(self): - init_pos_all = self.init_qpos.copy() - init_pos_robot = self._start_pos - init_vel = np.zeros_like(init_pos_all) - - self._steps = 0 - self._q_pos = [] - self._q_vel = [] - - start_pos = init_pos_all - start_pos[0:7] = init_pos_robot - - self.set_state(start_pos, init_vel) - - return self._get_obs() - - def step(self, a): - reward_dist = 0.0 - angular_vel = 0.0 - reward_ctrl = - np.square(a).sum() - - # if self.simplified: - # tmp = np.zeros(7) - # tmp[1::2] = a - # a = tmp - - if self.apply_gravity_comp: - a += self.sim.data.qfrc_bias[:len(a)].copy() / self.model.actuator_gear[:, 0] - - crash = False - try: - self.do_simulation(a, self.frame_skip) - except mujoco_py.builder.MujocoException: - crash = True - # joint_cons_viol = self.check_traj_in_joint_limits() - - ob = self._get_obs() - - if not crash: - reward, success, is_collided = self.reward_function.compute_reward(a) - done = success or is_collided # self._steps == self.sim_steps - 1 - self._steps += 1 - else: - reward = -2000 - success = False - is_collided = False - done = True - - return ob, reward, done, dict(reward_dist=reward_dist, - reward_ctrl=reward_ctrl, - velocity=angular_vel, - # traj=self._q_pos, - action=a, - q_pos=self.sim.data.qpos[0:7].ravel().copy(), - q_vel=self.sim.data.qvel[0:7].ravel().copy(), - is_success=success, - is_collided=is_collided, sim_crash=crash) - - def check_traj_in_joint_limits(self): - return any(self.current_pos > self.j_max) or any(self.current_pos < self.j_min) - - # TODO: extend observation space - def _get_obs(self): - theta = self.sim.data.qpos.flat[:7] - return np.concatenate([ - np.cos(theta), - np.sin(theta), - # self.get_body_com("target"), # only return target to make problem harder - [self._steps], - ]) - - # These functions are for the task with 3 joint actuations - def extend_des_pos(self, des_pos): - des_pos_full = self._start_pos.copy() - des_pos_full[1] = des_pos[0] - des_pos_full[3] = des_pos[1] - des_pos_full[5] = des_pos[2] - return des_pos_full - - def extend_des_vel(self, des_vel): - des_vel_full = self._start_vel.copy() - des_vel_full[1] = des_vel[0] - des_vel_full[3] = des_vel[1] - des_vel_full[5] = des_vel[2] - return des_vel_full - - def render(self, render_mode, **render_kwargs): - if render_mode == "plot_trajectory": - if self._steps == 1: - import matplotlib.pyplot as plt - # plt.ion() - self.fig, self.axs = plt.subplots(3, 1) - - if self._steps <= 1750: - for ax, cp in zip(self.axs, self.current_pos[1::2]): - ax.scatter(self._steps, cp, s=2, marker=".") - - # self.fig.show() - - else: - super().render(render_mode, **render_kwargs) - - -if __name__ == "__main__": - env = ALRBallInACupPDEnv(reward_type="no_context", simplified=True) - # env = gym.make("alr_envs:ALRBallInACupPDSimpleDetPMP-v0") - # ctxt = np.array([-0.20869846, -0.66376693, 1.18088501]) - - # env.configure(ctxt) - env.reset() - env.render("human") - for i in range(16000): - # test with random actions - ac = 0.02 * env.action_space.sample()[0:7] - # ac = env.start_pos - # ac[0] += np.pi/2 - obs, rew, d, info = env.step(ac) - env.render("human") - - print(rew) - - if d: - break - - env.close() diff --git a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py deleted file mode 100644 index e69d4f9..0000000 --- a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py +++ /dev/null @@ -1,42 +0,0 @@ -from typing import Union, Tuple - -import numpy as np - -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - - def get_context_mask(self): - return np.hstack([ - [False] * 7, # cos - [False] * 7, # sin - [False] * 7, # joint velocities - [False] * 3, # cup_goal_diff_final - [False] * 3, # cup_goal_diff_top - [True] * 2, # xy position of cup - [False] # env steps - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qpos[0:7].copy() - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[0:7].copy() - - # TODO: Fix this - def _episode_callback(self, action: np.ndarray, mp) -> Tuple[np.ndarray, Union[np.ndarray, None]]: - if mp.learn_tau: - self.env.env.release_step = action[0] / self.env.dt # Tau value - return action, None - else: - return action, None - - def set_context(self, context): - xyz = np.zeros(3) - xyz[:2] = context - xyz[-1] = 0.840 - self.env.env.model.body_pos[self.env.env.cup_table_id] = xyz - return self.get_observation_from_step(self.env.env._get_obs()) diff --git a/alr_envs/alr/mujoco/gym_table_tennis/__init__.py b/alr_envs/alr/mujoco/gym_table_tennis/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/__init__.py b/alr_envs/alr/mujoco/gym_table_tennis/envs/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/envs/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_7_motor_actuator.xml b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_7_motor_actuator.xml deleted file mode 100644 index 7772d14..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_7_motor_actuator.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_barrett_wam_7dof_left.xml b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_barrett_wam_7dof_left.xml deleted file mode 100644 index a8df915..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_barrett_wam_7dof_left.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_barrett_wam_7dof_right.xml b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_barrett_wam_7dof_right.xml deleted file mode 100644 index 011b95a..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_barrett_wam_7dof_right.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_table.xml b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_table.xml deleted file mode 100644 index ad1ae35..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_table.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_target_ball.xml b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_target_ball.xml deleted file mode 100644 index eb2b347..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_target_ball.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_test_balls.xml b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_test_balls.xml deleted file mode 100644 index 29a21e1..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/include_test_balls.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/base_link_convex.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/base_link_convex.stl deleted file mode 100644 index 133b112fe7304d4e9dad10ca3f79b4455f6d7b1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16584 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 CQjskH diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/base_link_fine.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/base_link_fine.stl deleted file mode 100644 index 047e9df1b12fe6f20d76152bdf1bf475517aea2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 720584 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 J;k|bu{vRfET@wHR diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_finger_dist_link_fine.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_finger_dist_link_fine.stl deleted file mode 100644 index 5ff94a2d6a592ca0923002d19ee61bbf4a0feb72..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 410684 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 YEyylq=;>^KDZwebl)u7Op+Cm{4@j94H~;_u diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_finger_med_link_fine.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_finger_med_link_fine.stl deleted file mode 100644 index 495160d30880fe5c7407f5a936872d66d1b0807c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 87484 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%0Dn!Q8~WO)ClxKt&j!}hFh$ts58fHv>=h7 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 O^rLT?a^JSiHvb5wl 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
=dl-h5f)|)hX{Zqqy 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 diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/shoulder_link_convex_decomposition_p2.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/shoulder_link_convex_decomposition_p2.stl deleted file mode 100644 index 5cca6a9c33728693d7492ec2b15df3e4e8699736..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60284 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 Vigx8 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 Oj4neo+W+rkxcwi#RAb!$ diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/shoulder_link_fine.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/shoulder_link_fine.stl deleted file mode 100644 index ae505fde83026321eba6bbc28f1303df8b997162..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 362984 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

th%=vkEW+Uu4L4_;buSu|tdG+!->V2{a~ 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 diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/shoulder_pitch_link_fine.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/shoulder_pitch_link_fine.stl deleted file mode 100644 index dc633c4ae647ebd57b3586b8a4fab952caebc2f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146084 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

uUNiKWd)_8N75dl+QLO7R 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 KDy~-^&;J41?__@f diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/upper_arm_link_convex_decomposition_p1.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/upper_arm_link_convex_decomposition_p1.stl deleted file mode 100644 index 82d009304d7b17c6fb95f8f2c927621f0e50b9f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104884 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 z

jK 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 diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_yaw_link_convex_decomposition_p2.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_yaw_link_convex_decomposition_p2.stl deleted file mode 100644 index 48e1bb1b079b9be6480d9812b377c02c9d1c0645..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63684 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 UHtQSi^h~->0W#wMPv7wW15)-4IsgCw diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_yaw_link_fine.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_yaw_link_fine.stl deleted file mode 100644 index 0d9523929fdaf3725296b0658f29058efb519f81..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1316784 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�>-KYfC`+R8(d(lVMj=5C= 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%0Atvr91i`Tx!ahzC1yvfKX zW` z&83b$t^$Fse?DsE^7b>lju=}wPrDYRZccTn-8EN&3KGwUXypa1rh6T!tp2vsnAR;x z`lbTXi?RIoonc$(n*2>G*D15mD|4}0j}Mbt5?$!=Hb)na)T55*P zL?3e0caq_INL7JASCi5@`R_fr1NCnng=Zs!C8nqSiRAys7OWuZtmShWkH0 z#45d(Y&~2g(B)Q4C*RCG=hbPinsI!u4+$SONRIAam7sz|gE3k;Y|dX^{{^TS*SEGL zSLi)?*10MIfv)mzwQ|#IkG$Gtsu`!&wjh(5R8U-+RUxP#;WJn(7w2y=+Eq|9R=p?W z-#I?YcsEypK-aOCTDfS0=U#)-)Qsp{LN>n)RH_tpC8!`Vdw^EHbMuLpYgsj;W>bm8 zcN(Zz)prpHbdA2El^Y!W;I+zM&A9c>n|S>>TB$P3nV^Ei_YkeTc;tJp4p-FcW8Pn$ zd97RFR;9L`*%cob$YZzUm}3qu^_I zaxM6Ta@fv6Akg(@p;lgUrHDTFfSM8J(SR%qzMx#O)e%&X2yx&(@?GGX~wNMLdI^D{p^RAgCa5xS&=Z-=&zoZFM!HoNqO9 z-?0E2bEdpNpsPPMcKI1)&vzK=H9iJ$@)_IK7XriyY040 zNMah=w^;p9w zvA>Hh?8)YR^RxGQz#5;*Ta;ZRZDgMba&F^Y{iyo)x{u5EseeyCY9qIJ!*Y+#?!z+gffiuV=2;S9J^-2~?24Jj(>S)W0if z`{b&1;?Ez$Y#6UONp4zHX)(@P?)_h{+&-5hjCq)i;4^s{H+#8Pxk~zn{RdN}lD*vguS)u1t<_%NshA3^-{T5blbTrfv2z2>3 zvzKqzsHiVFQLV?jFV$J}K5ud&vXO!c68MzCzgKgu!x{!QC4GB07YKAUXk{9xl3k~L@ECi%bx*WCt_xj7mc6(q#*k{SMomB`-F zWRq@_Fd~RV$b36_?ll+va|g9lTXJ?QWxm9awj=NF!)>7p$NhK@;Mkwa>HD!{Qkm1a z=<1eZC)aRs)rbEa_}d6%>A=m(r=4*`7u8pf+d|^r1Uva#V^@9akLpuuk)5lQEgtct zZoAIjNT3Tx3i*7v*7KDsvfq6%q!zG~(+*Y9x2EFAHja2}G#S$zl{cZO#OdvQfk4;%x_m5r zaTR?%SG82zyBn0xLsLkp&dh)c5;(T3(Rj2Pq|{nHf^#Yo1syJ)VgfgY5pB=wvU263mn-Ldl~oL z>$5v|8WO*Z00k8!s($1j*=JSMx1j11ORb2;Z0FoM#C>B2fk2njKzsSeczgZCPijx5 z;73muaiBUm+qsv53K9YKyr1|W7h)7tkg#^;8I`p9-cD*pom##uy0eyCC_h3V(6xcT*~tFeR)4Lrx_8I^ z8Nj~sr^m_F#we&Dv8f@ic@;Z-nLste>2(mB^RYO|t)D3n=*r>08}7NWyxzw6yW#Ic z!q}bH1<1{slN3~tn9#{y*1MF~-&vq$^bG05y0(8VrInu{5a?R5&0h9+Qbr%PT&>5d zsa=_E+D$3++H3_CBm(-`%ad=H)&G&JX4D$cgDp(_ONy;DUm(y`h1$za`U7(dEGgU-ldg#4SuW{!&Z;1Ag%M=C=lqvHkiN7;BNr@J@!jebqf_N`>|2>^4g6h z^`qX$P_Z8OUPrRxKi5k0)0QfzAkl%>Y2^K4`qc7jsmg}*V{e}>k(O937YKAM;^WlM zZHwvc->Lh`d*1*izsZptp089;K?3&zpV2scAd4xRE&an*2?V-s-sJDR+7!{d6j56^ zyGw&vv~7Q>XZTtL6(sOD@pTQF-BdIu`?GUbTFOyx%E|AF>T?TJ=|jsUmy^G@4$8GI z-J4##R8IcG$|tvzR((qC?|D}7elv&_3@s|7f<(QTa&qqV;M^DQdU2v$r4vd*`zY3O z&1GR*=<2YfoV@o(tK7d9s!!Wr&h1zHD-U4{cV|;nkkHmECtq6BKKDgWHDhnv9ZJjj zvFv1n8vBqyS3vJ_a^3GCxuZ&}8O!!>RMvcrW8HEN=}|!W`?tbnZzRywszf=tAE%0|=>af>V-t^DjJ=3SCed^lf zo3ZwuZfyUqZVD;_aoSe?J8I0Hgj|(qHlZ1FUsjV{I@Vor00jwuT?N^_Z@E3iSE_H~ z{u)MDolqxMX->32pzFip3i9?pM|lohrrtkR-SlA>ZfTkAk>Ls|NK|@OL9VcUv}ahR z+TR`4GLX5vDaY>493v3un)tSY?0P24^W=P$$i4npS-Crs6;?(F*T>PI@^bg?4RgEJ z?Md-U<5%sA4@!2=o~*`{CBij`L~2rbdC7^oxnHKLXX3^>Kb1%4y0bbX{}c#xP48S@ z&hf63+q9fIL#Y3QVyxAaj_hOcTQVw0q_wb-&xaPvP3xo1{#@6@nzhh{v4|o+1p-}T zo|cy{RV|zQvZp#H)wYBk+t5FV?Q7%P(mLjLwH4b|)K(zS zMcdlQJEZq}3kRvk{DzY=TaxU|ofd2N z`b|}5A&qZSpVd0mkj?QAP*6bv&uNWj@uU7MtJf@L_tO;$_SJ+w+*E!yI6TX1R6F%< zFl9%7=6QLx@&|ttkPZqG+OGEUvZD*VjxJU2&U;@(vih~xDZBbD6$o@?dfLlz17f{i zPFBzMp|^UoMc;NRYcz`$RFIhd+D^{t7v)ucliKS`JkXuBxqn_6Q-7X7pzGR0JK4TQ z6R+MU)Uk|hYrC=L;eRVjU(HcaL8A0YJNfPH5HF|pYQ~N_omqkTkCpJpGXw%%8LRE& zV+XZf(Vl9?fma<_`|>Z9mWk69RFH`4Y$q=awe@1b>V432btwDdW5wdDP80}qiC68r z`XMazY*A)tpQWIJ#KBh;61qqz} zZJ9t9&de4G^{AQOVBnnr&wPLSer;#vq(jL9SQ> zXMP=XRFJUTielS`&u7?HilssY34Fe?OrQ(za3XWIN~W1s33v!p8p>N%(})APmw?cw=2$i;moh|3JG-KIHQ<>3KBTW#xj8} z9E}tSRFJ^AKb8q};b^2tpn?R>VX{o13r8bG0u>~1E|z5iT{t={5~v`7bIL3e=n_Yr zIrHl*!RHU`qhK#e%s>SR{6gL`fi8TK5eXdM!_h%($3y}ZByjxFGJ!7aqlyHsCxYuD z;Tj+!feI4hT1cGvbv%$j7p?&!W}t$^Yhg`U%s>KNxCV%rfeI41a;#+nUAP8_NT7m* zxC$-S0||8D8X#f@DoBVcd13|<=!z587C{0PByi>^a0LNe-5OUf5D8R}z|{pU6X?QK7(@aUBye>>%LKY`H3^YG1qobT&@zE8 zTopqkP(cD$7qm>E3s?6L33TC#f|dzXkifM9#SA3SC9ZhFnO|)pDoEg3fno*{=)#q) zL;@8gaIHYg1iEl#E0I7230(QlGJ!6<6Nv;WNZ?w5mI-v>{YoUTXMuC*E%!1|K>}y_ ziy26u3+Eb%1S&}2*9w*ibm5F7kw66r{OZCofi9epBoe3~fnSeUCeVd5l0*U(B=9R3 z%LKY`Mv_RNf&_leW0^n~&PWmoRFJ^0k}MPG!nau>feI4%b(LiTUHCRjBv3&DzY?=d zpbOt-i3BQ0;MZ=J33TDxERjG33H)l$GJ!69nWS|-qi@4rL>6(sO0O3MVg zEWcMn1qu8bRLnpET{s6pBv3)Z@>>8T&?UY_<|)7K&Zr=PZyn5~%KIH&{PG3AO2IEX z{+BR+se^?0{YOvTaivX86bZX}hL-(QUJiU7NT2QLMW^oJzc@5IkUoADNhi42$xB9t z&~`=CnH)%g0cH!)V4Mb&l8h0lAXH&kiIl@PdR25*IoBZEh(2 zHe3CDwXre#q_CwOi0@sIK-cNXI(cl_FuMA=nsLmltYlj>fwXd%CY7wLljRp-bo$d6 zigmi7*U7ErFuJ#aN<0}}Lpt~^jts0gS3(5|vF2}rI!I?SqsjVKD+K~wbvx+fpgCc* zVU(INv`eCtY&D3uw%sJ5f&}hEzW#3J1Zi>Yek7;DE`dPTw@95lC_aq#&rvgS92QI4 zLVJ>g3I`=rkifmpf34tzGl}Bg&{wZ-O-?S=$&3C8rU~~GXt4?oa+PKwbbZcHI)m@s z?(re?(DnqL5gY7G+`~$cRgcONRFG)n;vl~b4xw{fs%J^N%MK(X-iCBOSxO+#^<%hB zuJ&IDeU+|e94=x{?zGd9-AhXlRFEk3j(?FG*Os3ATm42cpsO`m^4XQ#-B?5*1XrAT zCbp%=hpHL9yObp>I#eZPwMB>q6eQ-o(aAfK+R`DH)QpjUq ztR~O6uV#GO`&e@E^C2Ydg@g(c-8S>%u^^Pz@KiIFth^+>R@#u5srLi|U3dj+G}D|< zNF!oGN!X+75-Ldanxd17mI$M5{#DQRe&?yw!KniY-*izR&?UAEQ%a^tPumY<>tAi= zYw&92P8VCynw{h6o$Xrr18G4+*-%=yj7~n6*_?VGQ(Mu7->Z@Mte;AYIyPj|Ih|aq zfghDa6Y00pI$2xBkB$#aqz6MB|!fxf(jD;%^c+OF1~ba zl1jY%Qi=3?QI;JpU5227MAKb5d3LfdeQlG-iP4{INpk;6tn}dG0wK7nImo{2d}y^c zYDVtY@sgu$e^$hGhlDj;8qKfm&=$1ovRI0Hg#X@z(_HCc-`=dzcUjn1NT_?d_q-OS z<8fj0a_QwWKHquUVSzx`!}>bewS7yv_m+BI-8{Kb>b|8biym=OLInwr75sP{Zb5rF zsppmE>0W6}&5o?9^#y@I*N7mUJaQ|~a8j>9r?Cg5(-G}hK*ALX6(qVH)5%s%Tha&d zYR1qFm!x-c8#Z(DJ%K=1ecoa`sp3N$#;X|%mfw;#-U?uMavw>kAR#@~$%U75oqzUi5Sd8BXfk4;&IXb!Y1s^)=l$zo9r~uh_uo26-|4l*#iKliBa-%38y3n`= z#OLZI2(hZo=GC$yNTBQPYMorr!IzGEt!8}oD@Cq{*JN!X3lUV1&wXpX zIlPEKpvz^0PWE;8r5(Sh8LxMgC#P0Bv5OAHh@ilBg=D*!&^MjDdQ2cK zu}jTpV&_ZZ7nGn8(?kMYi+D!yuL0DzmYT7okT2Q)0Fgk~uCWgCw;2I+S`{^;SbHBbdeu6)P-Xs0d7vOs^b6lt%LC|yt!l=% z?=8sWekGN&J*o%Gbz64G1V<2>$9r!H1AHk{Uz zeS;?`buT*!1iG@K9OQ`oezfo_^{y8ArWx6CW3h6-z9T_b_&+*X_tB5;9g|2!!hd^X z@<%=XT|+bedyud#BwRTi{N9hY=Cnrhy;Eb78M;e(XC)Ho@*314+r0W{Gkf&R;% zOJ33dTEjuTtA(x`%=1r;Qk_vAf*mVs2)M!n;_I2FTo=rq#xQkw(nz`{63g3B(U3KH$t>*O0> z1L<`m@h&TlExDIPE8A>QP(fl6FO>%;B16?u&F>V)9@#aO6EAEQ2y~s{`^we36%9A; ztMZlNShE>p<>!+(E2to`hwrzYfvspgzTY&OloEW!_Xn@!d1RA7pzAO{OO$=BXjnD1 z=BLWUupdXY%DGA#6;zPu-d!gz{ks*7_B9^!deN+9;a1ApV(SG0T}PJbWW$eEv;zOl zMU7_2nn-r+)OzJ&*Qz0T2nhs9DUCJztES~v|1%KV@Rj| zZ2Y2m%G+8i6jYE9GZyU}$UgF~CTBfbB@pN;*jXo+b#6_2d8rxIMn-LIsK8;e4EFVKCiOL2Vf>_Op`;CB`#X*BJtVt`qm{<*wC3XtnEV zMy;3#wy53-xygLISMLB3}~Q}HDBA%r?=I+ z+Q{>r*tjN7m3~8K2n4!{jn>I4R<@xxPpPFUIiMXYy8o+^HY7(u1&MOW{5k5cHq=g0 ziSAFr*r*E{)_Lb71r;P#*4D`*DhAP~7u8Y?>Jr3y+LdJItBn^3bcGMp$qRgf=)k#Z z#)VP=tnEu1HpFU_f(jBN?R4_04MDW*3N>R!w-(H0dL>q={!oEH*Smf?`Apj&`g*#W zA?<6<79>|@tL0b)UG99lKAVDQ@8$7SBnl0c*qK~s_O$vdqCZjNKdhLq-LO$dg*x;-I=<>?~fv*4T`EzY@Fg<(A_zhNzFNQr)iLB14i4tDhnS4dD2HS#Z!zM$hc%8?6 zcxnjM3}Y`6vn5oJaObPmea{W1^ZnGeq*)PaXrDfuO@Ev&5a@ERtd)BY385V#)t36N zbJ2#e@grFIKVv0SkXSxTE7#>UpR`%cIA&AOPct*TvNyk*?w%uPK(3Rd&D?b?(LdWb?Gg@D4 zBk#GL${v5HFQI}&+%By==1DMJ^i9oZvvCQ3T2Eu4j!puBuJOTIIXx|ezPX@g)N;Qi z-z}ELHb`(&uit=4}$3yy_&IaQ+ws!v}E?Z!YYA4*C@Us>E*Z(`nHam;X1jS zQprD=jj6rJfC>_BSG98XtzeqgTFt1rI$rUqGlG@M87mOzYBgFbI}Hq>xBb)%_c4P^^v;)6(ro=Xypn=f~i-Ano-Mkg;H)=Je$*Tg110`tHlDX+{!0}*33{dUQXYx ze4w$+U?{c^72NLYPg=S4?qFJfj+&8LL{Zvq9l|oMMp7iuwPU$fW=%urhPi5nbo7j} z)PFErUc7*e3K9dXb@IBLVA}Jvno%j@zT)cMj~xlsc}?NQiAoQk}2LTI&cl_VGG_Kv&tLT6yQQU>g2Z%?SFSVYV;3v7fPfWmJ&B zwo9WakPsmaniR!W-CZr^ekd>BU+qVeNAYj9gKgv=k9}$A$letDL?VF-66zbe(+^vj z-u7Vz66nI76MviG)`w{->`*qQEmp8p_;udOt3n z;%H>k;yQUrsvjMgq26)$zh7@(Q9%Mn4J{Msn&YCAxBcTsx6o1&Os(Cl~)1ME`PCM-BMDUo}SpUD($W2~?24H*}T>bYZ_sBv3&D z-|2}2j&k9s8a{=I1S&}2xSwSLUHB9x5~v`7UXJe_M%UhtrGH(ummNEV(Sb)|DfVhb0u>~%uPqYRt#q=@YkzvvK7ry0 zB#wBB1m0!veucABL;@8g@cw9-Ko^VPD>TWWG;@R6FX8`wox7+Yfg=_of&0gCzrAd4 z2%~)`$Nu)jf*H6MkvOx!UcPS~Mw>KIpS&y)=(1cYRFJ4K!d`ZN5K28B{a$k<(1m+M zEES$tc*gv6*2-PShEd08_1OUHfeI4%>|>cg*CbD^{9|mIEfeU% zH%%ge3KBSeZJ9t9zG)H(RFJ^2cgqC2@J*9Qpn?Rxfv`-V3*S141S&{4wb#k_q626@ zcXjNQ|NGVYAb~D?Hzg9NAmPJjAyo+speJkno`D3qEVtCCAQ8yh{7-NEX%Fr18AzZD z?-F7?P&q+#^6@49G^U_tL33PpfnLJ_!Do9-7a|er! z^`}9ff6qVyUE*8=p7QIMqib(7om?^6pE|vbrf)?_sCrx$MiUMeKeCCrRa ztNyE0s32kaISL7M;S3LP@1lYPKDUVkwwyQyWVsbZ1qmG85i^iL7tVnd2~?24u^P(+ zx^O0_NT7lQj@4Ku(1kNWMFJHhaCFBqfi9fOD-x(6fulQ?33TBML6JZO2^`(AOrQ&A zI*J4;NQfgvocVP{A%QNOu_$qDP6nwA|sd1l~F-L z%(zAivLi>jlAgs62n4#^9d+^^8$a6gg__Ybt_Zu}+nE%pazRD~3499YZ+KUfVNXKB z$=N3#1p-|aTkx67S$_1oxB66caEJ}NFe!xWEnHMV1qpl#=j(+ptH>N@2avwsbpnAd zr%wEh;yFH^7^`Mn{pQG`vwZn)VY?`(Ac4>Ad~WTlD$MmXA@8KR0)ej2eCEKvPyJ}4 zk!r@Rdezv#DH7@I(m+842^=rw>ukH#VNd;=lHH}63k15}#p~oIt^MhLThxrT?cCYB zM0axjQyT>pByhZx|90l0Cais#+N9Zl&H{n1QwjVUZ0k>-7=KYmbIXrCI8uRh%}Q0u zWa;E#%%AqX9ZQSzH{jc*`O`c64LJ56`1;h<2;0t_$e#C6d_~0n+hajO%Hmx+th1fpy~ZMYjjCnO^0{juPoY2KKM8etfn_LJ(_v zrvzCyXuME!B(QJC*D5X^!hV!3Mw)qN2?V+hP1MO9Z}TH){8r}P0zX3WWj5((lAO(Xa2?V;-c@9zE{7o|;CVGam$VM8HTYj=}K7(070{hn*&A2xm zSpT+fB)8CM0)eibv-rGM_W=6*yLu-6Rj)I1pY>SEx<5lf1qplt&}fn`bz@5673oK< zxdMT%k#lu&Xa0=SsgODbVD+#Y^Q?JAvNgbsE7 zR2UsV*OpZ?92)dub5=2Fhtom@6(sNpiO-rWxkq_%FNTbocyHg7xBPcsXN6JkX3-SC zyTWlT{(IXGwktC?#gdXf<@ce2<1n}-jpn~^8A62Auh7b<^kParMpoe(l`yEtCPOI2XLvc)}-bh-Q3 z8@G#f!qW1Y96e_!`f9_-E3fhfRB*evB|gt`X_hiSXE>SZ;bTAr2^<6DzsGWUjPiH4 zB(kVeAAvxZSn~llB9uDL$z*@_d|_Xq>*!Fe{Mb62mWWW_(HEE+tQ@+UOxEt-WIzQ8 z9Bt$M632#0iGwL5q~>XXK-ZH@tz6SCoL-rtX7shHs9f)zN=6rcVn78696RH`Sv>Q# z{OI3Qvd*KJgao?29ni|xs)kd4d$rH7cgZYyuXP&9+2|^vf&`A8@wWZ7o7{GPD#^Lk zNFdPVeo-s0t`ttKh?>!K-Tr;2-=`2iU26#yB=D(^pI7OBct5X}LaZ-#76^3teCF>a zN`%vw#`ovv{+12l@xw{k`eP+@;jcl{J;oOt3Na5#-L z{-%Y~m$?SlX-Q<`L3A~bONARb5Pa{5 z?~3s22#scI;hLna_M`M-m@SD2a*$7*g3o2B?!Eet!`}S&ynsLjiRA^lQ!C$E zCSr5l6^h%W7}C`UKGGMV(9;cV}*udR2=yW}vHG-S)I#a#dr7 zWdao>e)eil2fwOf%6PM9i{u_+%7E>bb?io$l&)dSuuPzW#ADws^dYNe$}kjZ!MfFT zWjFY~LIsIgMLN+Nw&qe5dDWb`wRUBXIe`ii-?BQdrn5xT+?O?K>1aF?QTcc`n9ja!XLR9~_+1SM zRFJq`J(v!CU}rw&h9IUrlXqUBs}5^R54N&3W>_XrL1Mzhw$x*ejVa@nv_}fuG}w4v zp@M{Z6_9+n7niKTkoA&6brkau2T zscLWSM8|~{|DO`_`v(wM5+umxPIOJDVy04s7jI2G&)5<5Zm?x(KN|BR@2CZK?oS=R zS2Vhi)@YDG1qroI&dW>XlYs=f#8Ne_9Yk(DvN0ZWEY;~fk@V#fM`O(~kN3!cKn011 zFC*#UaC1wYaB_#D=@MnkKm`f4gl(_o?FHV;00I>xCNAtq&(1MlQI-gF-S69x-gh#e z?cFkuDq(DZu~g`Kuq~99E@N-3xn%+sB(|;yr}Z+-S8d4xK4j)eC!*d5Q9(kj-`<(# zJ0}vTAc1`e{)GZ$Ab~FIOBhEvH8#$MYW#QR30~)T{P9W?2~?24^UX4WF1*r20$WaO z=W#EH1S&}2oyanQF5GV-fxQf&R|7qR-w05Uz`mAc0$q4-7YS65uv`x$(1rJQF#{DO zaKDKJ9zi@dc<&MkRFJ@H(=vfBJf}qh6(q1-u}q)~&wTz|o700_T=-g1uk)9D#fAlT zdH0OIdt>S2uX%U44u#_Br%&d)0TQSnQM+gyUHPkRzjQcIiLg#$mwCqLXZ`8b<0bO$ z8Q?-%qp?JwOKmYebTpR=2~?06b)++G5MI>SK8hJgpeyKMC)#sgQPVx@!loYVQ}x%9 zdLKkr#Ts2{#F0YA?OG;KK|;CSg`TKb$du7c+gCa`bC~g7iwY8IY5(h-AAt%Iy@n5< zlWv-8ju}XxOFd5Qs+wz#1S&}UJ$C?23NjNO`o2=`^t^hYYZzbMq;<>6kw$T$^>& zd$NoR?h-0UoOBvY|8p#2Iv&#+)?#zMd9q5EL;_t{LXF0uup8T0R?k{pbeB*;Lac|C zz8?FxX%pl9JYhgjn$YxvUVYlm+!8^H4E>;2pRloheAF2TRFF`Q(@c9SQ#~vZ=)%3g zf2nCk4|ZnaYe{Vxuv82G?M27Tc>O;m6bUQ|60KJDqObJ-8tbIdR7g&gD$h+c_A=@; zh@qd{KN`3Drd~3YxSoKTHiA61&szXkU&?5t^Mi9Pj~XkKn01S ziT!BO=vyX&j_<(^<>sAdGo$Iq5wwH-7o!VlzUCPas35WLY!vJ(O9Z;aQXN{&&EA! znLq`JQtb!QyJPeA8~;}Se75p@b-Xd-d-FbY$Nl%l?H-KiOD6>6T}4QX1S&|VN4C}O z&!!`Y8AzZ@ES2ZZI%LwirsVhD683|zv>FW(s34){xt0HJDwQPyU05fL#%I=nO}#%} z-K0JhVOxU7AFp7MKm`drLoE~N!mCRpu-(Ob3GNY*Km`fB+gT>ig}qvlz#bCz=diyb z5~v`7y-dply0B*;5~v_yxgJQM3wtqn7{l{*!+r++Gb3~luCys`E1+c}yBR>-?&v_CzD{uq1Sbk!n( z3KB0$j-emgTr&}qu1%GHCZ!r%xRY%M(p-AUn6ZB30P1t>veAXKMuP+@NPMo4LW{+j z?}L^Ibcv<1sT##9-r8yG^*;0_;ny1R{k$j&D+d7Zs>M1 z#n_6XtMQlNv}Cah#th2@DoETdmP9w*J7>z!#T_%0x|^4=x$h|2HT|M-yJwoG(R$DG zjvCS$4HBpzq3*Y*Y35^Yi9nZFsyiFXF~`Hf%!)s;^gNeLQ%avPma6BN5wwW=DdXQy z+(yu{E~icP_*kwS+tVO~_22}S1nZ>cxnDQ$-DTP3Sdm-7Y&<7WK?1Win!!KHv1t>6 zS?q5Fx|Z}!rv7)%m`XMJayhnSbug>S2~>~}>yhADfwgSZ#`s1tCwvIKcqG?YTV+W! zHPqW@+%E0~K9ULqDo9kVJe;<7JYg!8B?4Vysm41-v2&mE&UV}`mhjn+Xd2mauPFlw zRFJ5W7DI0x+F`68{{>>mKmuJE6=Uf5aobH952BwM)(p-&cTqt?J+h7=yYeAWL1II> zG}`jjZd0i+0||6ZaZRH=j+-;i*gY`(m!4NDbiM19PJ`n28nOPXXJ8Uy%SSCi*!uU3rp6El!N*Obv?>CuPGw0CX0UY83mOEI49s34)%BPv7Ahd>1h+eyP| z*zA3#Qeg%X=;}UVI6aq3O&JHjmQ%75lZ~Z9*H70t8nrX;I=4)qf<(2*c=|OvubtOu z{$6QAzIF{V_5e^pLM`o)wMR{*LIM>eu%{+wAc3xRCsN`5ff=YEfqgsvF16yS%`=Zb z->g1)VS9yV30}=2feI3MPFp6>h1b7G;2i+(QMlhk0u?0i9&DLF7w$Kaz+NBrGO^z! z5~v`7{b0)ky09N45~v_yxgJQM3;RK01}XvpJwTDbBZ$Wa@4+I03KDoVTPDzj=d?(m zf&{iimI-v>na@`R&WHjV-{Vd|px&3_T7ATi4?gMLq#@qcTcFM+NlCXu1CukqYPS6f3Cy}5j(F~c%}3K9d8vgr7_ zV@w$%Cip4Ey^@S)A}UCzce|^9n(KiCDoE_7u~aGF&vcepBG4t5iKV3<^f#5NvObCZ zo8V_WchPmabsR1GzKe0YmI+jl*m)(EzVq&6${3jAC;jc2cLY&ELakqwAwBaUP(k9z z@-*srA<|TH%s>KN^%|$rmEpZi8TAGRFdrWWw(^X-)cH~hUDqtasGtjJjiyLwAak|T zu^PwSB~<$LPo-@p_b`?Ox5OtKK5oT)zuB>7vY3Iy&A?PT`(}4jJsNKcVRL(0vzs?W z0$m=RQfUA5Zl-!T4sXv+?I_9~esh;lL1O*36sql#cQpA5W;2pm4^~EUy6i5wy-KE^ zKKL5bzjaTh(HXwR?S4L;Ol$2AG?i*yY6>gy@uA`1VLmbe3KCgOlWEe2KvSvqHBDtD z*R40~pC%IM@;a4FSGl(`WfMg`|&wr+xhGJ~HbNT6%O`()Z6Bg~Xh_n#!zF}A7lq^O64 z3KAFj*iv+na8t(0sfo^1lI4ySf$}(cL^0FUJg&D z<;Ju#WlSY;Ea%)jrQ|D-K$p}gg${M?V9L1EI)fL-D^N66ktKQfN|^Ib&L4f7UeOv{I^(hlC0eBe$f`nnC7k@JVJrHZJ3wQmC4T zgs$DklWD)&c`c_%(7C-?A?tfeY9S8^6(rP_&u4rWQ#}sqdaylyZh3?dQn@UAH4P>sn z4oL-XiUhjWMWpbrO(j!??}b6E+ypAkXs!fd?pg;!WNvrF&Uc3+8r1! zE#(9%NMNh2(RjyIV%2x}k;;5#%@4Pc^hlsV3T{Du-wQ69h$DiXJ z*_h(KPo2q$Jf~`Z#a0yS#^l z3KGQ)Y4qkJ4^ycEW9u`gQjJL?D-Q`3Btp-p(yrm|ro9{3r5PLetv2yq|!$*)L-cNKKK8}VLbTjV7l^Nrxty0}scB{JM=&6M@O?%h3 zvYWJX;s|1Y!d*fIi5cGG=+!QHv_^C8eL>0YQ!;tTk2wKFfdID}_wuHAezn2ab-Rs}sx_t0xyy8b3=WvkQ7is30+Q-x!)*%X~cgT=rD{ zKAuEc{zjn7x8oQZ(LV27;9s&93s>gP7*4wIULPt*eDxheZ`;){9gj(kGnC2!38YO0 zkwDjy^`q&R4z*0j<4e<-O3lhcNxO0$5-Ldin=+cdsan&Nakk0|#cFa4IdGr9?SpNh ztK_`VG<%>qqd~Qm%DtX3MB)T0NQ4g_O~*7gXT0&=p`;CsBBzRZ2n4#aca5UOpVl_j zW2^R%^6&70WC?GnQ9+_|@+dm&oSUg0#ieV?=&_OHAaCK2Kv&WBqv*G3bxawx{^}Bo0`QqCR75nKIa=w@UQe?u76RB+#|z{7BmDdR z1&N4^k#zjS+NO*l`jYHr?QnA7sYsv;@4PNzOybWtqlRYFwbeTtYgjTjo2D%2Y~1e7^la+* zz}#;yIxL0MZv04|&IweIxO_63Zm-bZRI0mKsbojrY&qkeNT91~b~Y{O5pLSMg)gR( zXh$OZKXjK+LBjJwHtnl5KY#RgNF(pQt=bpQ`#wmZYi?FHl~$Ucqayj2UAvw2i4Awqyjk^0dBm zn%|v~K-bjxY+9wN`PsSMrX;c=)LRNaQDkwDks zPT90;>i|yt!67!k<4-LBcOHo5q*Q8wugP47b6g^{HH`RACQ+K-cTK+4OvWA5%S^ zT^&eVnjes|`SCyn3CgduY9m^j>d~y_0J44Gap|6oNT4gZb~c^X!kkgI+5obk#R;hh zzki^DL}+X_O>1Y)*l8b0&fdN*`A3Qbx{5u|qLUMdsUH1pBFV!J zf<%WKSu|;!m#H4{Ljy=TcL#E!ib$YqcIPY__pq5MBkf{Ka^t%bDOScqLIsJ?=~;B~ zz^0~*O2j~pO|MP{@Vgok=-S;Ti31Q2kSDkORD@j|vjX*erVDk-4Y8X_^-a zp6*84{YIc`5g!*n@}K!>qRmQA@^xk{V#5hkkmx!ri>AezGc?5;k}f0NiTqqW7EFU2h=4!D>o(OKD$e(An{q7MLkb6H0`U}J*$u)tL9`Bzn>$4t|6N;>CVgM zr@JAUPGovBAEM=>AE+R)?q(*9D&t|wX#b~{lv)@_zVet# z9cWFCZ~_%1?ybqBQ{FW&Wt{C+icE_NBRMZc0$q!WXVO=L%+Jo(XkjvNX9rU3HQ&3S zAaSx@CY>?Z{Cr-1{5R=H)2^gBAK69%T}!@=r^!{#83)|HO1J;$N;Y!>6(qj9WYSO7 z%o*bo_(s0VTW%UwbR3H^`pw0D-d@AD|= zu{5VpFS7c&NTBQD^QJfH#K(P5L89MAP7J7HIvxcpAD0694InxE zZh!>3MqkXJYu=gryXPA0k+S*M{eN)+6(pv;%%FdrF!y&)S6nU)+Z#hpUv(DhJ^jW0_ZhVxZV_^3fncqUD6FvPgu@jV{Cq2qH0KP8Yzmr+V}{yd1iN$i(8 zPtT@J8}%?9kFwW?k{dmzC|celLj{S(ZL;atWb-?g(+^_E%ZAI8igQE)UAre{(={*5 z8L2H|_?m+&72N{fih_c~8oz8h(;@FIkVdoGBZ|1s*s09s=PnZHQtyf9@0s6uwHx1` zG^}`9>0Zi1LIsJDw%IgbTrbnP`(@`fX&Z%S07@+@0@|oI;ZCvgyp@Kxt zmQ1>)qd6ny%15d5FQb3-!|G* zj}1@DlD~e2uws`)0$ug1WYMxi2AMKas@RYcdxF>jey>FZiH<>8bYPb#Q^xl&Et&F9 zAgj&ak|BYvH;uDsxi14v8Rw?zNYJ|g=EvM6RFHVsJ&S()Z?GvtQ_+RYeBOec$wHtcK4`1;w0 zoSf~*F7k07RFL>sFq_J=`WoQtqMZ$tuJhstEr*H6q>ZP%JzNVl>Yral#+f<(=>+4N4y zKBkPmb9#`UBVQ|<_y{Bt=n`9o4vg80&$1@zSge8t#{O z2f*VbW}t#Zi>?{;_(1dh12d37m*c~6G-PXj1kQTESr+quq|qkU-SXL2lk23@dr5h% z{uQTm`cFjO-*|?K^*{xQd4tDLmqzAx7wdrpx-6eps2~wpV+wW5f(pkSOUrlHQ(X?pb0666msgCgOF6vmq>BgQy^Z^Blx_ zAb~DV{+@G=Rr`Fd4^)uAc@AO*66k8wER9~PWS%pD`wA5#aMpsDfdsk^q^HqUk2>X3 z4^)uASqowY66i{roJQR}^Tx~%RkBQ=tH$g!S}85R3{;S?d|tJ?l1cZi?rq#B z*w?yzCzFSQz6cV!@j-{*J^Sk5VJqlge=8N?}1qtsb>Gbjw^D_=!A4s4J?_FYs{ftrc z#hAQNK%Aq2b16gudq`NP4u{9n(0Ar17AzGiNZ^ycn1KYko;)2--5TYWfeI4%^eSc` zfv!P~GHLa_`Q15DK?0ve#SA3Sb7PCyCE3A4N)j9j+(iti(P=(6aiLiz1oRFJ?ojba88=z3Eoiyn_OzkS8)92F$+ zO{18B1iCu#443ZtW#By=$2Bb9&rv}FM=ZorA%U*GzFE}mPS5ism6k~gOSXM!Gml12-?FwZr>y^9JG*c%WtkU-a=q%?Z{X^VVX zA5@UQ{)(7^J$>xmKhTb%?uEVb$v_1OoHZ?GAb~FZpCf6>5c8Y~+*ha|fpeh63?$Gs zebh+mul3HS9;hIJv!=xiB+z9yd?anuBEJk&kic2fVg?fE!t+feP(cD`Oxyy3{;RP z`IeW^)BME<)&mK2;hYdL0~I9f`B%;DE1Ty=VFnWD!r3rl1}aGW2*{*6TIH941iElm zkC=f95-+>(cd6&{%RmBMIM+zbKm~~t(=%!2+5B2K>9P37lUh zmI?`UMefU_4ngJ_ba(_&K?3KOi5W}y>SSHYg`%NV9dxOD+)2VM}-fT1cazP|eLE>5CbXuUdd9E5BK_t+HUtowCs37s^ zIRE~me|{NApbNhw5i?LhqKVU3T6%DP8AzZDzlaetP(i}-nTQ0sa6XfmfeI3M=8FW5 zw_@)MXXA?mDo8v!I*Jx5ns+r@CeVf7A&3MjNNgWFnx=KguVp|2UHEl`n1Kosmu8Ko z%WLPCfdsnnD-SUP6(q>T(e!bydA=xKA4s4Jzi$yUP(h*)fBRZon_mVJ=)$jV#0*rB z@ErADg$=X#DC4x=^x(aSz)&uPLj%p#{VD2-a5XD9%|bS6nA&G;?P3Tc7nURLn%_A zEd}bjcfG}39{j=GHG6`)!-KoKyMC+f%zN&I`HZ5@8lEAZdH-$}@ylw?@p`%O znYMlKK<-=ESwjU0oN+-rT8}xWm6<%0|3`BNkwBMvR1Tj`Xtra+xC_nSMFk0*2g2C> zv|F^0Tch}EDpyFL3$F-cPZtF9W9_o*K3{3|Ky;WG5}LYO2adgW8yzOj)G}8IotqlM zJJq~xn?mbSQ9%Mn)#)1wOG5c3-yoY8)mkJJmuHwbS)-j%YYW{CxIR03Tq5^1e|ug*q{7XE&G(TV_V z#7-v-6(n$m2V-HrWB86@Q#D^&p@0OszU~PVQB}>=fEA8<^C`1eYLaF&qJjj@@Lp-4xp_evyHkw;x5O4eEvF5qONkat*oD;%Wg*F5D>Bq0Mb~IBK33Pc^2^Vpn%^2_Q z_vg;T-)JT1exQN`&Iw^`b+g|5$-Y0@5t>7f1iEquhl^i_&7DGC-R;i(0@CvgR6kHb zLY-f7>wSBEXLxQtk5;lGfvz?u!^OEx<~~I?rnTjJcI4xisGg&O1kRJ9@BD0U!Dl-b zPMga3M-6)hsu zr>-)?cbqFFqC}0oF2>a@Fz&AHa6*XOklk5B1qpl$V{CS1A6u=pp>iGFK_t+1>xfm{ z-e$%a_on@}WFj-{1hNTBOhCaXAo*^J?v?}A$n+NG%`?IDB;5^8_<#(__6 zUJXO!Lt4jz1iIe;v52n^%ouu)A8uOt5ZRK-E-FZ1|C+I4hl^{g{shU*bmmB)>&60$ zIOS)q)U&j$uN6KUD5ufB2B;u`y?&Yves7SraKFEFpta#hple5vMJ!uu#<<+ZORHAE zU#_9`YN#NAZ!e6M=J8tWt+Da|^-GXIS0>FOI<+!aPHwI!=l34AMN?CPBB+Nqiz^7kHcA3Gsc0Cn_5#b zSbir06(sQOp0SG$UTeqF4v?AY$%zEIoC-vWm0#-{ZAsyx^n4oETQVwFs33u(6pVG; zkeL^7?kYP|pBf2tMLdoWdxx1Ta=Sdu%3JQ~EPbhdpn?RBw$MB0?z}vvO*^@io}5Ua z>%M=4*mWj#pDM-?5KNL{*5(~jjyQ$x(-q9ZunPo_455+ zj(q%&hH?-+)lfkKvuBJQvsLHbdtBs3dPX6EuC%Yi#g&ETZdL_5IPszlYRQt+UZH{n zX3rSQ*1t9%QK6=+LRS|FbltccF8bXvW1MN^!t=V;ki)5kLj?)Uo-tOlJgpLnD=)3| zu7(7<#taJ=4a=H4W>xFag1as%Du+?84;3UZ-^SSR+#UGn=DFo{e5U!OCMvvXV$_fKclz?>|9;k& z(`s^5kic9qV~+RS`Nj8l^zn2*kU-b6?_t8{vl*jViNQST$8G%!5vU-c=AE-&7|b&i zyQyENI*0_iT;EV$y<1b`JQgkX;LY}3)o;*S5h_UF%sLwVnB~bA2OZEmS8!GcbPd}Q zCI((=Zp2u;){75YvtHj?+F3&d37jX#Sjl(3y!gl&dN9=wB+ylv_CJdmXznvH_1qXP z7ERJ0)3rhc37jWK-wfL}jyEfA)rV0%M*>~=7S7nm(|-KvFJJvR5vU-6Z{D=qTZNu_ z=MDjKE1d`S!mvMg*FRdM>0v&jS`{3v?|AMf%e+$wbYXsnv1YYq=p#P*$}f$bHB^u& zwJ%1D7-zP-n^$ho--dh1H`Gr=0$rGUp+0q^bTZT89&!>9m^n@x87o?hNo_wc+e>Hu zHH+-qy^EY%##uuJiHIYyqGE1tloJ2Dx#Zc79i(Fcl|UC}dl?JqdQ3msXSlpc&vQIp zJP*uMG1e;Xn0~V3@RS|^Do8xvA0ze#n%Bzj)E&LpBX?Q1iL-_Ty6}oH)_VLa{b=t2 z@{Ff?t&pff`y?-DZnnF1{z)sXOM1$lw6Yj~3tf2K7_-$IA|stH>xZ&9Yd9AN=Ml=2 zaiT^*>If2jJ;HOK{Iuqo?y}!WLj?((A;{R*K?7v$lvjE!n@XSybH$9kJ3Ue%Aj6PnnqTfdS7(H=NL1M%AIB{>WIpW1%dCNLth3<4kCD4WQ znHW2sFh<7uPto7e`v)pWyviLfR(3N-qyFjQClfaW>B;Z4NT3VnWieK9Z-A`ctfL-C zR~Ho|meG9CiVe)ssPYa$(jlLVzLwrtkU$sCFJsKDQLua;Tu}c+V=|~9v9(0Jh;lVY zqjtK7$Zl(1*ecL@Ab~ENCr4lB`WPZV-PvbLA_5g8PL_%nGri5xsA;!CWq1GTwwkmH zEfVO$`F@Of7YvgPTyuy!M4*Di@^bNF=|Xc)Sr3X)x0sXLSQ@iL0$n(7k+E+JLuI

lC^y9%joLUZL@xMv%Psn|N}vnpU(z>U{tcGFJF{t=-f>Vt;#h%r zQKEBCqlI$~DkhJwZZ0pL(&m5L`Idgt5KHE6ShE8p)sK>&l@-pn}A^0&&92p|KI;<-J-m-;$d00`(J-Ko`!wV625xec3vD z6*-6YxkCjB$3Ai5TU)d5GtarH+%>VJEJk$@33TBs62|tlZZ7+LE+)It^BffGs0irr<} z`5EMI2kO1TEFE;IE%ni}y=3X-OfLN3q@jYumIHC(!L^pgdHn3$U!D(rr|;dT66nI` z3iaD_`pND4!n9MgKOEK%tP?nEnx5w#W98&!N!n=|vqS}n^}pl9`>K76qq;K5SBBo7 zrRj7(kU$sC{-!stdcM-?FjsS>ej+MJETI^;s+loH6!ntJ)^F1CXwC|OE}X^ASkCUl z<%>SYG~UQrLj{R#SK@>$(cd_aYd_s(zUVvJBYF-Zfi7HKM`N!oPw5{+hw;5sKWuqv z?fg^El;6TtV(k{kic_zL88J>Qxv9_DIG9V?(+L$MaQzo!2j+a#pZNFV>FMesfv$rG zW5weJW{m1dKlKn7+NX%JWT+s4>%XY9*T^h$M0Mp=C?|{rx|(H-69Es080X<$J(rwy zx&t3f1S&}2`Y*-?UMwVsM782a={%4?mqVdAk$;>SgO26Z6`dIpIvRYRgS8YVa4-!l8l$uK%L3@KSDa+2#s-EfrA_vi|;WS|u9GKm`f44u(z}Bqx@C zr1hs#f&{t({)-c(+L$pG&vKXZOWe~6Q|p5Y5?JSHlyjt`Ht?Sy?m(lQnAOKw7K=Va ziJvdb-C@>k&!y=R!Mq&xWKcl@SGCeNU-}+&tNtQ{Cs0oY33Qc?r*F7bGIzP@Qg4Ra zP_Iz_551+Lf&{M4rM%jjZLS-#gz-J^RRUevS&Z1-*NibcICsMbv}5Qb+JOcYByjyO zV|TCDw|QI+<<04+kU&?lt}&uoQ8Px+k9gZH+WGXuCnpURBye8~$}}wdVvBSR;allE zkU-agg)ze8u6aKuc;(PtW(4z1^wkAakigwG7@Iezj(+rQATLEd03^^=aaW9(wZ@F$ zXKAW`>=MXZ(YPooNZ@`TjQuk>Q13g;j}QN@66nI`3S*s5CFu_R$MV%gpn?QGOVn=( zVS9z`3XbBc1ZI&j+lx;LmB6_;ILpR9fjJh;gzt14afR{Jp+}%_a%If!nZJ$z!;e4#&{}$3KE#Xwojl7+e($d zIbJvy%l@@O1qqy&rN+SejB`!!msA23Byh%seF9xL4@4#KsfH~o)<=~<1qsYe+9%M3 zc|(=JCky7eu`H+rDo9`k+dhFV`%eRGcQMn1_eqU`3KEzRvQMB3^E)bmB@SooVQiH^ z1qqy4XP-b9_Ha}JOB~L0!q_T-3KBTW%07WE>_w>rmN?8PW0_V7RFJ@2v3&wv_Md7v zs)8-2`W}@WC2uLW^2xg)qJjjDu&GCd*%!>p;4i5JDo9`!NF}h0Vs;VltV*DQ1kUTV zPbe;!*Q*lP1Hh-K{XPRKNZ?#|m)?Gxz2Op{8Wf;lgYtrDmpfmu2G1iCO+s1n!{ z#?deA)v5$4NMH%IPoN8Dx2gmxNZ2pCnAOEBGG?vS7EW7{Xtg>M-u zfeI4pc`TZj$!++TP#Hio`ww^|3eRdw8r1uGz_rjJ+BG>M_3yFm5{2*e=7z2(?}}*ZpjmgVn?miBT-}gsq@C|X15SIn9c(g zB=%-Y61{IMGtT4KprYFDLcy{qjjADmu7(wo#O|AmjPpq9*it)DHc)<{*`KH&f#=6q z<1_=bLT~(KHQJ3G33OF%m?T7u8RKbFtG0UMIN6iF^MeW!>b07qVorNTBQL+$7;w^??ziLe?*{OWa42|Kd|g#jcT|hQG_ku zWDvf?dhk;JrsI*xF+f3L;OInAyXaQqsQP#9$7kmKq**BMj0C!_q)8H63+y&xP(kASp+wQ(;a(#~3%?Nl&&9`XWvP_l9UM$0qgbibl7Xd%u^Np+`1gd5 zZa4o|xk4iM^dzy<_p)(RA6PJ-@^5i%9L?Ur-$K`e>Pe!x!&&2~wu}$t-5+UM7Rvmf zg2b$VB%wK+F=Bju;m0rJ7_Hr;Il@SwE4XBmxLW;$5hEmg93Q?lO50BD6)H#+8Jr|W zemH8x(5LwFo9Aa~KWPpN66iWb_v1~M!$yn>=Y06r8B4T^H=Q(8khs(`Nt8Ku(1*47{QSzcNVuaB*s`@lPuC<_?Fe*rF$ebi1UYMmMAjyMgEO||< zL0^eM0$pk;nOC2_QRRDG3n2m(Bz|T}5-YEoF;0CN%ugiV(448gLIPb_LKzDUbmT!} zU8Rk3ELU9;#ftRVQg*q>Um;Pv3rhX_Y?DOcy)uW9wXA=;EdMZ*%RlsGIaCxPZ=!hi zG?k`|NvC4G*NNuRmF5T|aTZ*gG9-!*HF6m-iaF=!tLwCt<7lQ6DoAWTlOWuu_+oskU-bkFA3sGfElC3zO4NFrOvV&)hJYuXmBh+{M>2Ah`W`R=Lqg8 z57D>JkU-bj>kxnIJaw$z{YS^00?(=e|(6k6P+Ev{Ulv znt4)`Z#1)_VtBrk-~G34yzpq2`u~jetn^7t{Szwx+wG*Gf<$^EY>BBfW9L_YZg`_u zm^?gBCD65#zW;Heof+fP`=72Ke}&3RTj;wopdhg%fMx+a^aD^w2KsuJjm z9~&>WH#K9p&-lkJqF<DpzGscj0JKY-QqVL{Q-vb0pea2r_S*sH0ili8G{wIdqHc}hzWiCUQ%W96ogDuJ$=E(zlOTeBn%{W4!mJ7csgLYZn*kjT&>L3}G{ z#t2B*O!Edu$+6U1LIPc%J0*xsYs?te8}8E9uOBIY(L8-rkVyXiM-`h{qmExasFm#O zDQ8nFiUhjU8r41Nm=@A$xJ-Y-Nkat*TU3H*5@W__-0On2ywp&+jA|_s=)&5}*q51= z_`0M9GI>4&wxaJxC5r3wvZvf%#6t5x+Zw5kvpf zomcCgULL2}BB&tY`882wzn9TCj}dqJa4)y-dLHTlAc3wa^gg(_gBfGV_kO(N&iDEi zD($Es5tJuMluyiH#OPDRgSWeXUGGrLSs~EX_gA85*fXth9&+<=K4i}ky(T@?P(fmW zmLw_#JDB%l^(Y=tZmZsrN(mC^YUhw7GVDrY#Bi_W#j~{9q}QVJKm`fMR`gzLNo&L? zN2YK;*PHA0D_54tbi2s^e4-Tz~5w|~O zOt}Zg`o{=|v6+mkySiOhd3k(h$zq)}RFHT-KSsnkrP7S)i@M8mPt(i1kt%_%f!$+7 z*8FCS6OH;xp9f!c_P|L)1&KTEF{06P2cwiUYv3+7#@^RkP+Nioy3XW}5yfk#GtQ%A zv0?HcJENbWmH`zcO43(*-ZwL2M3ovYqlX^X3sOH333R>686( zHvMG8=r=JymYCW_FHP&bkU-ZDTeRqw<+BlEce{47z@EHvGL17}xjK^+BMy3`wzXJ7 z8H;piF1vLqF5m7{%Ptaomc|HIudK#B&ohI|w|C3RzVw!gzlE-)Z)3#uHCc>u)!;{c zd8Kw`*^90fDoCW?8zVY4GM{S2bJdmSdRCLS=zbu9F8MA-yx4BWu+^<4t8{ddC0@`f zAyAMQULaQdd&PX#zW1)CSLzug2heIj?0I7!eoeDD(RZ!cTZ(GjThCT4Ko%(Htf7KL z-R^Os=SZ_>S$Ia2J~L{ZOfFYQpzCs@II(E48KdozXuZdPaWeV4;iw={vRj;}JKT)% zHs5r;XW22b${&?LSEH}7qVRuaZ|Q5ErFy#EK5{VCb5xLU%|lq1||+ zXW!RfzNK*=RFHT-BUT(cWWLvy*zrq0bF;V1NaH?8pzD-RtZ?09zB@a5WstX9beFzF zpn}BE;8@YEjTs~EP&Qe*Y-d@KzUhqwx?WX_6(xOh8nt$5j=ZwOp?0z;y%nK?ghO9C z^Q7!XtPe_jxof<0d z9FDeCrZYzZU3h01yM8lN?p)?%%S{9-NZ{RMtV^RWw#qIcayqp>czy6nclaJ9Htk$! z9F=c}r?wJ4A#xr)2T?)dzZX#=)0er%wd(lfr0w~+5a~+usgXd}Fc~GX^)h2*->}nm zHfN~ZLnHL4AQ5>uN*oksjJK!D@C=cSWIKBEYJSurrgu!ujBWa65gWIpW|UrDwTLH! z%$(QxlO_0~b4_K)1t$#^ByttBij7XGxiDINwyXdzRiTZnLw#x_&{gD@Mf5*m=5Y$e z=H!E$ca+zu2Y?C^9_6i~-_oVV)!lX>1J9nZyL6$P7ZT_ynae8Xe_UW(-R@t0YeOP> zOK*CQLInvA+TW*IQfeNLu`CtdYID~0mpy5`L?OWSxr9~Z8f(Tl{PvzUc96TQK(!VX z{N1*$R?%d|eB-FP#a+|-_1h?4 z{8Q^cW8E8W({79%C7aSwp@KyH2&*V|C$*KJ71BrMYk3xomRo5(4ie~E8)+4j@|!Vc z)a`1kb0AcAWYUE0u>}YwJ7m=s2L;fbC8?If>61m6787@zlARE zYgVx)+KjQk$Za>r$sw|M17{5tB)%T7ijGC+8TWj2t}@z)|AM45)hHy;)%~nhj9zKR z$akoUR@*yB79j!^Bxdclib9pl7?=L*q#arsAn(#DQzX!JWV%%ZgqZid$Uc8@x0o z`d|+}e(*KD4drp%>9^L6-H@X6@w137!&397mz^!*eXZ30r=wakm=_c`^@`M!K?R8k zp%zhN%tqs=E}W^$b4{u$j~}C~47BIi&VM*=5$lVsGKl$OT=}?gN7-fxec2imB-T!~ zh|Oh|8|U$HP&2-uWC@u$P$kgSWfSc#_HMNiBXDR-zNK9e*({XqIVecX46ulx+$)V3 zTTgW0&h>K1BRf`i%3{(a6NeJ4GgQ9)uH?Pxvw+GZoh`y)g6kN+;}52=@d1iG-UFm}-4n3mRSIL|?2 z0Nt!s@u6bsh)~Xr)Uz1;C*`i`tF59}z3)bhq1pCpJ0E%S^3+d61&LnQsR!`mSA#Dp z^L;{J2ra!nf^VaYI}+&Hkv>YaooJ5x{1j)kojZo|p>#j+sF3y^&Ro#E z9ES2o)WV^H#MK0=SX|j0<#c)eQY#oYfX{31tPtpOe@dm~lR1)lHY$|&j7hQ;qicn& zD7L#La#_TUeCLd7wcuPRAL8HG){lA_s35UBDN?NXWX^y%RVa*i4gS5i+((r_SM}@` z@%+doBSuDAXW9JrmWIvfTA_kOaBQSFVZCV7!F$(3dB173+z!xDA%U(WD(!zJn=^#Y z%?#yrMp@mq(7PHcNOYVYDcpag&NX7}7Z2e_GJkaYL{Cm6&~>nwMJ&jE+c=Mpvx2#A z)*RY0$|$0OgyVuparmw|3u(PyAn$Bzq{UI|g9N&~D_X?i4|k0i{(%8}U#4za6lF|M zL82$^*H=2nedAhX%sr0JJ`=0GrP&EcpzC@qi}-lLoavNy?HHb6_GIlm^}VjAr` zcw_cMBSy!)KHMSqQmq5Mu^@r2Os*EuKHVeZJYH_{=IQdR((cg=AykkkNY7fA1?Kzt z?I2GcneCvql4cGdfv)OZE#hIwQzORbjzf8Yu=83AYOhd1VnSAn=zjB=aUR8n58~s` zJkqjLPX-Bez3O2RAur7sX$}tL2iiQ<%F>ymg2ded7I8G!3nRwKYy)`Oqp!6q)W1Rk zUF&;Vgsa0d<2;%d>&+*WX1qV;?odIZZ5@lq;rZH#;V`TVUv?)8&qu4tkwDiI>Se5q zcxl8a(7!D&=#Za#Nhb{zB%&Kx#E2$uj2K%Rw&v&W7UY&aDuJ$-5f+i@xEaH7V@n?P zv@pL*nIBY;_|V28#+H6-#3=l4BYt>M8SY4R5D9eUUTqOG*1a*#YW|B^WKP2EYgYh$XtutXbb=ebY0zT5#KMoHDY-6tj62ttjkBz(*PADCe5V# z;b4yGk4jgOU;osQU%jCc=(=*oA~<_*#Mrc}EVu38d@m8GAQ7_8BC3}7Y@A1Q+0y*g zgU0+Cl|&@a_4&F*b{iwd~qc07Fx{g z0pz9m+Dp37e)>e9f<&&XVPa>_vqmY|Ry0g@x*5~3FXgt8K-W{+$y3QWsh@iO( z_I9JuT2zo|aWPEH9(%!vahyg62lTFKD?`s(B+&IDHe7VxZ$6#6aU!62m zkcjyZCg!-_GGa6=93pRJ{B1i-y;mgAHF0jZ@Z4k05gyk*Se|>6UtdlA5>$}Ln>Ac) zC}BQ1ZG!@(rBf4qGSxvO&{h3ZxX4uYxpA#dRHPAuRlW5zG;xfS9P6AI}+#$iir>#MwoLZJgT_M zWryzTr)dNd6(n4;Mu=Huei<=(%Y9q_~&MoWrucMthkjAdl?n=&YfF#Pv-PqC${4hh<8d z7Sc6GF)1k1fCReo)`%3-yP7fFsx^}?y-P?>YD-W-qWakgv9+8zJHd6Bt2`CuC}-t% zRtR)`+88Oy`Is{xoN~IzR$et^64hE%km%edQZ&n--pJkcty@*zFIi7MJn5tm=yJRf zDVCKk1YTH8s5v zBZ?Q58<)0_*QpMof<%)qk-{?AoPX7Fb$wRFLrO zLnDwqGaL8AZ^C!I&Cx#cI*sWgfiC}D7SY_toDVnB<&_>5FhG`|(Q{OgP@lEotM2Ih zgS$*ieK;i06?xktV&0iCDr}-%Xqyd}$El@81qpn%GgfQMF8%BDktsVBB7rXK)zH4@ zTix_8a{_q<`a(t4IIE~!KPsh_nHz2uhZ={bv>)ZaSj5w>(MIcYH#2uuJHR7@xeRBY~dP*$bdp0-2$jwVb22lDCzQt z!x&kaJi)T$=b~EfFHRaNNMyJXE)o`)qqVzA1j;+nEw%68RRUd8Xpip<6W18$QR4MX zy~uW7UVx4YkNwF>i&*k3^=#GiD0*_9zUIwnK8DU56(nK>jX*ZF7%^DCwfdAo-uwy8 zU(9D;IZNpX)n@n&H9c#L2mkfTNkavRob-M^CU3M6V_s#dAAtk7Uc^};&^5Y)MQoU#V8nRa zjY*$Bz4!_mBSQs==kyi6Y6oMC825fdANc ztMb*sG*=B2B$mF76vZ!2Fk(10uPLiFsm-%3PziJ$(<6mzu>>PV*qBOk*X9O%(*&A% z1_~0Ta#}>$CF6}4C5DxiuUI2qYo1D=%km&n{Kyb*#PGROOb+eWoco`kbzYz#q27-Z zM+(X>9q2R3`&9y6W71fJQ?ocD#*8C5<${78`D&WwjS3QY{~7ag^p~?5kJ22d&wwoe zwhZ$Jhl|GJ%$6Zj8GqU8pHW(6B2Yo1^Otb(e9>CtT6u0ABinSEtc{?r*CBzfvlqg} zrR9r^^I)>I%<5c_SELaZELV3^c%RmV#>kLB*PK2P zVo6g+sowFVdPr0HK1Ea+7L8(0h z#v;6Dx%Ku8D#)bq$yAH`2#uIAOdoBDHy0G^_>!b2G*dBZe zRo1qtkN(ANrX>u%e>hww{OO7J`!X{O}Ng!q)Qgh!|ns31}6Ppnw^+I(_$zqCew zRMVS3qG#=l3rT{1qic2IpsVArBr#}2>N7mokR;Jzx%nKdz4D`Lzu%!e2le_!SrWvv z#z`qh5>+lyjC!B?cXnD!xGtC3UNuNlM}PS_kT?HGd&D0}6i3&@rrd+kw1)F}+En76 zOOnXD$b1ftXgOFvvCg0SQE5j7iAh1UrlGv~91L%5)yr)d#|Pe233RFF@oM7~{k(My zA42(BRFEjXDoG3(mU^WbTmNN|?wWrz52v>YB+!M|kg-*nnb=NWczjMRHC_|ERs(|* zMTCcWt+EHt7aFa^?oam|6(mN{4g!6Oo6o5DAyaHF{-OLZy-gs2F1+fDWp8!FcI<8l z|3$rURFHUbE>SG)ka}+z`+TaPKFc+j7oc7S66nHv!&o8P3b*1sl>ectizNqT%m#lmN&-MSv=epZx7{f=~^Lyt{pK6qP?#f1~N1zLL6HsHIf&`W^`vkhwT?&TRb6<0` zLAff)dphCS;?>0!@-+Js2)xf&N^r*tl|Tgv`!P^K0!zLc0||8D`KiSHS+Qb}OX?Hy zdFMFs=XB~$5qK3;0u>}y)1J#8^O?^myjFPTxDy6mLp25}NZ=k9_6c;Ubr6pV6(n$v z3pEB3=)(3k<6nNee4y~Fu}_Uj-jNZ`yvH3kys!Z%BmKm`e$4{4u3 z7ryVR1S&}2yiS$CnX5Q{fwN6j0u>~1{J}nfF8fD?3KBS)pvFJ~U3f)Q0!JWmwE~W1 zsst)X;K~J+!1{r8!hUH-1qqxTuf{+EU0Bmp0{eqI3dM_3&z7b<_3^o@5~v^%R5f07 z2>SOgeFh}Zh5cYP1}aD_TpKU8{Lfrxd`2OGt|{l^#gvt+{&G~f9vs)&rrj4SGPE+Y zmKXySBybh2dLBriEBtz_uw^oLDZm)0Ac5;{)fh;i>-oo6QEKtuVxWQquJco4AfdR5 z#fdByGy96?fh{t&)Hw4{je!ahIG4gcfi9eRs1m3kfpaPB6X?R3hbn;z5;!x$K7lTr zd8iVoAb~R@>=Wq1nTINY3KBRo!ajj6oO!4cs33teBkU9C!kLFEfeI2hGr~TBE}VI& z5~v`7Gb8L1=)#$YDuD_TIG4gcfiCQ$sst)X;9Ls(1iG*%s}h(8#uY>OMy3*|Ab~3| z>=Wq1_coQl9suT}@Y${ss33tEGy4R(iYV(ju@yxH3C#SdF_1tPt|e6oRFJ?7rhNik z*ndo z1qs}vQ;mTHx}v%zh_i40)~7}V3EXQ`je!KZ()LRbhYtKL1}aG4{&B+%7zT!Q#o z=Wj7kK?3)`Q)3{3uIUpJMBU)Oy+`3FC+<0cJKdAb~3!?Gxz29-vBC z_aun&t#_uhGPtAl@rVSmDsjtSS|3!9z_wD2fdsl14@nTU{Wtw31}aF{Z+G!LRv$?a z)yJi-gvTRPj|vqePFzS3x9|Qf^MeGsa4%*x1}aE2&6X%KuGsgNGe-hlxTmxl0~I9t z(*DbfU!|^yu}`22_r_KUbTw&|C;~E^NI7=<1S&`@YMdx~xu?=<3?$HnyMn6(Do8}q zle3x2>AzfEB+!Mso2xNUL1K9CL@~aSx#}1D3`n30cWGB+pn^o;;6#z3*Wa?1NT3V9 zDxk(d1qtl0*eB41UlmXZRFJ^_ib`PbC9!FuC_FMXmu9~wg9;KAYb1&;1OAq~Ljqm6 z`=)wSs37sKc%taI-CQ||_Z$gy;l8743{;Sa_(Q!V?{9x8yGWo5cSBWUpn}Azr__6` zXRejO^FRV!xT~ug0~I8e-A@pC&-^V066nJHY}FX(ntm@q6nL2WyY>lGkl437K}^oh zj1?nz=18Cm_vKZO3Kb;MZcY&QhyN`G66nJHh1D3SAYs3shy=QDpJX)#Do9|zR3)&d zAC)yh%xIpv&IjKzR00(wdOwdBmDif9gz$bKfiB$lUX6hY5;hSp?$$9^@L&ui(1km8 zt1&P)aZkjGwpCL5>X;W%2~?0MJuy~Pe4e@=hIu{MiK8I66nHxa@829Akn5(tO!W| z!Ve(PX-&vz~AZzDoEg04Ai4S z0$skN;>Fo@e~W<%68PN%H3kys+OjZSl=u5v3{;T7?;fZzkU*EdE?z|R{96oEkif4P zs4iS{S| z76TO|aHnH61`_D1wKq=e@%&q9M+FJov006Q1iCib;zT2#zr{cW3EX*Fje!KZUVn}g zmv{dy1}aG44%%uAB+!K|pGu&D1b%79K7lT5!5OPk$Y#sO=!-fuTOH?%;z+vR!K_5;G5p^5v|}s z1qqyG!`PMS)Aipu$H=a~RRUdOrp3|Dk;{$qIO!duPiZtxwx-<{P(cFc0nr}6yoWxe zPk{8IbrVRS>#AFv$lJpFj^fn5P4#o#17&$yONI&(I1in%)9niDMXLwPFj}dH1iJ9f z(ki-s4*H2t!7`S1P(}p_EIqV)Ywc{Ze|%^8gjW6HUBmm2xfjNoKg=cz=k6>E(fvRL ziB`+wMTY+7{)q>7=8?M`XdV4ql|UC}Xc)Wkq>$8oTgk4pLK+n$Dm;xB;j7KvDL3UT zDTC)Wl{x7=kU$sabQs%uw1Qla%}ti2)n}+6p^iX~PO2iAUQbq{a)qu+l#hx}Ox-z9 zB^C%L+2WM5yiTPA6(mX)Nf3qHw-_aH!)O<|JxdMgb4w-Ah2y1+J=Yq@M$alqKib6u z6(k0?pp03Bxqsq>XPVrwvYf0(F_1tPj^Z+Q?^ILy@oWj%p3VamBwh?i5L*46#(DH> z)molBSx}Cnm0?Jr3rBGo8~>$~yqqz+Ttus#P(h;8v;=Xnow-k{^-8Fms5Nl&qczpP z^CgO?^Qk+>VP0*1!9sT>ShR&kqMVweQ8B5DoEg17JcuIb_CvY$VH6Wq7vx( zQi#4+^x=vT<2`-%%)RJOabTyDh6)lmCdXKx;i2;F^I0}8+J6@bbQR8(DAtOLMvT)} zLgb3e$8A&T4x)ktjx91)klGQ)GKKYd-&6u!N7B*Cu)gN^ASZqZls~mPdKKC!1QjH3 zjFhqI!e6%K?)pjE)e#AFP5esh3a6Yj&ZE&yKlv$xul|Yl1Vk5(@2Z5~?QwG3#z=hw zt<*yW2^@i@qiQo&dbS_0fBLEt=vw(GL1b%m)Htei-+knO35)fk1)Mchkiao=##Rg% zCC9Jarst-;Sdl>2{?oKxZTmqZMnT~ze_Y+KpQd|`3KBTJ&)A?XL*=z|XZ0p@t&l+1 zstq(gQ&<`?2A3ZsGaY%XH>dp>P(cFo6pZEi)kiM5^iA(aH3|uIsdcb)?Vi%VyMvre zH3}6ZFyBHeC!cqd&(ma-RgbF#y0HE;c6ARu18Zc_uF)P4IEIY17VAG_O>4B16>jF` z+35=vI9i9JgVUBK2&XpYUaV&y1j(AqN@?9`w>SK)*z}1ao0j@rT#U`whn<14d3ZzZ zj!iu(Bt|+Uinqnh-K=t550K(jJM94Npp3tTE*#}%taV#I*)MCbmi%o%RFG)(JV6A0 zH1`CoJ!6cVS$&F@fl3Jy=)zHMTKoFKNBVqRtX-j!hzb(@9w&&Mx851$YVtWRX??p+ z+fDl|A%QL&<)+okyN1gmvyW)63ps13An{aB5UaacvG87&krQfg`?bz z9dABB=6?T5OWwH!6(pwaOb|V& zqJo54t_n@>D$f_m%okB9K>}Sk;>}pK30-99`Yc?~T76WIz;eu3w*djJFY<)(wp2=v z{fZL>y;Apw!nYU4j`8BMzqxPJ@}Pf2y&PeD5AA1(3KIAx!`Rm=iMD$&pyeltb~+Er!Fq#`_mzGH&-U|>>$ za7aqsXBpcV#xk{TBwJ@M%iB@E9Tg-T=nInP@|pXpy{zIUN35*C_fWY)0$rF9U~J^r zIx_NGHNHHrvxW*1k$n?{WyT+)MlBm%Lsre|!r#z&Ab~E-2+)2@-z!Srf(>~%?IMT@ z64`quhz_^S7!&f8m*>Z8+>dH466nI&FpT9bP+F#c-I!0JJ_9O93}}`h`g${C|En+m z7Lk97w&bg*^+5t%IID-T2|WtRtxH<-tW?iYLE?Lj1p0!#86)eNJaY7>c03cciAbOe zXD2ZxYi5$?H+AMFL%zd!eV=$xr&XQvLWN z+JOcYB-W*&jN&;n#{4-i^gfRU@UK({kw6z_Xc!Bgc~x(*%7ZVYFFT-uM6#? z&t1j_hxOv=J^3E$`yhcX%+S!=#PjWXmC~d5Q!4GKAo1W}ytu#JjKSBf(8s;@=6$I5 ziUhiFyp(o_(WmN8J;(4O)O$q*3ALW*sbSRvH;?1ZsgxjrE*!;W>~bY&h9!J6$ z+tkQO6E%bQ>K#rRDo9*C6(@dHFR4Fmb>DJp?39MPk_?#HyyIy(jO(nO$w z#H{0S;?)1_RJe0=p!RZzAD>TqU?YJp9GRrOUb0Nr63UL@dy6}3=$bY$PWaKPofZEa za#e|Ych_m2m%Mn`87B=DB&sLGiODm}a<%H#Mr}|_FFt`r)sR3Jj>$4s{rYw-vD_&B zGr6|}Bfm(jvc!p;;bx5LoojNvMs0q9_Ws0si}!rn_gK+tt$ELHudczrUZ~C8s1Bln z1m-5`4brPJ&vm#y52rm$kwDk!tZ|}bN3(_7Q`M1Y+v>{u(~iBUAc5GVyM|y7DQscN;25USZ8-E-aypof;O(kKUf;Hs_v`7SlXdJpFJvrEh@y8cd+Y%Fb^!qFtb1h5!=PSHy~g*Uh)0+OvA{ z8>`dup$%06U6`+@J+=<@=Z!DE(PHW9qJl&Tim{ybZ%=Nu8LJdIfOjhTN?S{hFq;-2s-@J$YE09pj z)y3Cixb^%*ttOQcB+!MsR4~@>gCEZ~-$%7q+g9bzMO_S)Cr|c9hNo6(q1lWhwvimU1hfyr&b6!{G=U z##RZ;N8y#m?3qfSf&^yhR03mQZVG9YKm`fRQ`slbg(Xxa@cLlh!2Y#D1qsY-s4}MPi3D#7uFk@756X?Pbo&QC^Xg|ioF*%h$1qmEsQweloJC7wsB~U>Ed(QR= zbYVYOC9tQ5JxhESRS7KB_`ZYZrxK_jf$t^u33TCmv`V0YZ}b>jB~U>EM-%K5=)!Rg zmB12*W0n|OB~U>EM^)_;=(1lDu{7Y@3zj!E1}aEkpV2;nuK$l#6zZUoF;RMC$x+N! z6t5K$nA1^@3JG*!rb#6*{3Vq@1qsY~+b7V48Eln61vAPRTP09I0&~Uo33OqP zQzft-;CLd&RtZ#)z#Ni&0$ui>gLrQ-Yl*S#$3Oz}s`d$VVYXK#P{EAy|G%R`0%xkI zG4Qw0g=JbL@SPl=4EP?c5~v_y|M`Igy0G7+#y|xL9Luy%pbPujj2$Qt#%C?FBgLt-FH?>rg1+rDq51EWBe74Qf`pGxf*8Lc?O%=x z33TDnGM10dA$wp4*W?+dcvQ{2BSm!Kh5xT3R0%v1B%0ia5Gw|bH?D54pB-IU!LXEl z&(XEKLzL+2wm2n*eF7CEZn{|MyBQOV7(r=6<;exY)@rYlHe*zTh_76IXY#$R#ORCJ zbw}(>zW+N$Mu>Y`8>jp~V-+Iki)^1K*#4#2ZKxpeTLBAH1ll!>-x4J znrDdwx;}VBh}oO8U8&`&U^aK@uRYMkcPDM$hX_&p!k&7`O80S*VoR$z^^$-0{=o>* zH|M03|EEm#xS{gl-E(?p`jQzcNGx%U6q#!`Ora?!96Ul=8|nHe8uvj0U3<6D4*XYq zjTo^{N6I5Pck1J5WC9f=F4c_`dmq;{Vw`C0BWulBrVH9(90_zCj*AeJOW&xQdgh*y zV`QuKQ}pDoN1%d4RQ^c8ms{$lUfs6^{bYrvVfs$`<|Gp6>J%FxI_x}Q#3*ysPeyh3 z)hE#G1XPeXmpxMC>sHK&QFVTxeAL5Df9UM25a`0v!&t@I!SwC3Lb^lpe)>?ZkQkDd zzG}5@=Z@6#I4~zfjyrSHR+45qA%QL|V~oXR%_x`L?Iy?5wZc-3r9HG0eOor6lTq3O zk7SmfCA-T1D35~*5=(EKWTWftDpMFL$j=u6{IDz`RbWcZd> zdKPUbhf{7F6(nkV)0b#wS2kko>sU%InA${M`#@(7zlE;ccO!-O)rv+8-=*c`zppg8 zmcE093KF+#TEzW<`HUDJ*Hn|M_SKO~D7TFSx<)OD6p>vE88I5%sVPUUs3m_=rWzF_ ztm*0N^6P&YrM-KD2J+VHN^$_rHbeqlpZY`!KbhW$@hrhr?iuJPKhSt0Do8{>i4?oD zy)(;;1dLO3M z1E3(W^a_0$=)$Dk&r-gy8sXbd#;^ORO`@xd1iFUoj1)Cn&NE`H{2U@543cgxloQ71 z1U^3sM@NX^&7bW`J*p}1gXP{h2dxwls375#D^gTyeQQ^0>r?1Ypgc6(MUzxNkU&?h zqzEytPdekM?)(mv3%p!3K?EvDI8%%YUCbDp%lgZaPNTFW$`v7jt~JLf#?rb*j0w}m z%F1;UwSL{4HB^wO)hSZc_*o_8-Z1v6insLmxkmd&H3|uIO}rZ+^6<7sjDX_aa&5b{ zS~L-;An}c2^x9L^h%xPlr~Ea4pH`1%_9KBVyt9l2Wf&$mc0Z$4p`0)(NTl6E_k8*= zBSyxr1Ldcz#6jSeCLyTE*%ropxuW zFT1D&Do9|dv`?U`TwANi)vbkb9(Yu!Ac1v-u?#;3@jsIu=*@OHX?RpfM>MsHp`LC= zjE#9IV{&)9ZOs=attg|f`+2NNDb=q(S;XzoG%0_-<5p2}?JuJbH}g;k{~3JNmhmmk z7X>A}nN`&95t34i@Rt}n`Y@Ph9GG73O?^02knm_@70q%lFzTRl=3u@(ZE-y#WtWgZ zSGP1)5prjnQ3uPl4&)EZHq$53oI6yIDB060CceIB#JJtkkMF7&tWTm9RY;)AwTM;Z zjmctMtGtEA@Ixb}>x-$@qJl(#yH#ZS{mVR$v7>q6(+l+alzl}4U3ZFGg=11~BSzyq zUi`xAO}fu7%D97q#N!C7*!#MIQ3scv8_xIFIHG5#xr0ccOTFj8w>GDtYl9dQwtLSa?UNY)dkvm&vgE+K+^XdPU~qEt#e#)iJA&yP2+ z%op8M33R1DV-@)p=Qd(Iv()AT{?y>XpPV#Qkm$UTYFZ^1BS!m;)%n7sE_@ZuZbJfH zUiYk`TKOVIj8-p?XfA7pr+n`YuSsj4C^3Css}vVrL&i>IxuU(zGK4=`pk7@h*7b-I zK6{!PG0M++ptb)th{x0HHvBDgbuStvI-lrooJaZfFSLpG2k<5v0$s&&Mu}F<`WP`vbZ5LB>&@3tZwVD73YLo!8@tptV!TLGo`0C5 z@%q$n$E%1}*EwsHa1EJXcU_pZ>M_sQz4p@M|l536`y*L<63IwK?hHlZ7TOZ5W@bm0}DSr+R;`T5XM zZl`Hg3bxePwwG&e6>p*+)Jd&TV>5;F9Z9?0+R*pzP(k9y4~r0w8X9kRXRZbFyW28o zK6F$_pz9#TSo5@@@djBhA((%@no}E31S&{e_-PTNGEFvO6e$wK$NzHHM!r`GbWLq< zrFmqxjTqfd1@I#0+iPX$tq2t)Z0W7ygKO@3seQPkYsYb)E>_Luvr3@Lk)9tR7A>WX zVXWb$F}!}*BrW4dnx_v667jjL;)&l#BSzAu(L7D(`C5G%13&^@=jfMOIy5n2^qo7J zzrHd`4}l&yV?xac$8i1Ey2o7=*I zp*)bTE-FYw+=v$E9|RdKTLH9$CRz!{-M+Ym07-7D-P64C3Vbu3GxQ06wss zvxW*1FK0!IW7Q@aN2QG`tDQa)#AB$QBY`gUs6>krTDPA;JO>e|AkpDmv}j*$vJoQ> zPp7qb9n4?T^Bf6u;T55^$XlAb#u($Gczy6nCy(4txf*MnITENKfg|2(3?$H%JR&^$ zS^QsOpn?RBkuz56Q9{)xD_>Mip0|Xf&Pd=9ssxT%;q}4mrV==YjAPdLODcg15_q)s z33TBRsst)X*gtbTLo8Q#v}z1gkie2}pFkJ(qErI=hB(%TJr0#X1qtjws02R4aV!+a zNL2#gCh%<=-(*w*6(n#xz&?R4d?Ql{RFJ@N4f_PT@Xb;sP(i{;8TY|Dhy=Rus;e=Wq1yQvab;;=`KWm+XrK|<|W;+Z3XE-aO53{;T7o~(TWUG_^mmTJr!;8j;+ zpn?QuHtZAV!k(;3pn?QuXzUZ{!k(;3pn?Qun(Pzk!k(;3pn`-tB8;U3N1$-b3P%&v z7^onjj@)4kB+!NJm>L5WBygnAK7lT5?NkEWcI@e4El>$mkib5peF9yW(@_ajkied- zeF9yW(@_ajkiZ_feF9yW(@_ajkia(!`vkf$r=t?6Ac1d4_6c-hPDdqBK?2|O>=Wq1 zoQ_JMf&|uP`vkf$3#1aLAfdJleUF85KU;gZ~#Tuu@X`cz1v?Gxw|uO2DhO>FR&^FRX61BtfNBgCAJO^q`zwx^?Q&yi4`Jl_XhhigWOY*)3E81@NN zkhn)<8KWAtFk-lG3z1zmU9wpy3sA97gb<^WQhvAfk#OPQoRs3qJ~TqS(c)A7pD~Xj zA#!7y-?rp6qo^QJ{BpQhdOg;NvFrcPb=GlJH0>K-eeCW|>=rCg*s-w#5xY^qCZyvK zhXdH%-Q7Lx*xiYpk3M#H{cg_Lecx-|-*fznkJt4*_s;I@^vre*6V3J))|?K=1iG&K zMf2g_iF%CCU!kINi!xebs-ubu5~r?5@sQ<4j2hWP#p}uSwIwu5h6K8T1ETrqn+Zlb zIys4#jh#dSt&=%hFNPPpJ;Zvw0Z}o$?5h!0*Ns=veEVx3JsnFnyNJq3)kPoLv5pE7 zwOI`R;5$~2(M@@)UD(l2WTmrr@V?{oC|kkAV^(EA&riF4;Rzz~VO9*^H)XgU$$ z=7&b}$9Mhpd$oOvmsm46ldvq733PeUDyuO(SdY;nXq@=?X{hE}-buw=jk*0(QZ)Bk z5T_HhRt1U*Lt-_Rc21&##Mtjq{9Wx>{i;g!9xXhYuh2%*h%gf9Dz-41SDI(iV^qsA zS~%ugrM;nXQB;tK{T0Qto-*k%0tO5hUHD!tGwlsW0$q656(wMTuW;XVNXtiSicmq~ zhGR7U`)-&XW7Ds}B8Sf{?GUXmK>}U)Y!s!TSU^D{W_2_#>^e%ns&C!g#oR$9#KmbcfiAf$Iq%$3wC!9*jGgJI zqJl)tv(dcj(BXQFv>Z${Fjo}QC|@CgE-c4r4NC?eF;qFF9-il@=JAc@&tsQcf6MD- zG_QYXsWr9EIb(Pq&lP&gcaIng|!`>71m;;c=69>b@d;5=8#&9moP1we{!Fvr`+YxXwmxKQZ)me;(-bh zK_#R4udfUBtD4#A>r~I*95e-)Yt> z!SpH0pX1?TFZumLEYw+6+A%Z-{oNTBOa)@Xjpd%hkcCkqgn){a;2(7i$h3A}HL z;(l+YI&$||>uTHqonrZpBFn75g*l@)tu+YQv}9in>-rKTP(cFom>dHMbPaxL;(eMf z)^iEQKm`fR`HIqUkPrLV@Pw8^Cjwy%q)R<8@dHH{=`o7tjbx`iXYy|}2N}A-#Mzc9 zR%P#66Hh2>YtJqHVB$S`+uC!qGV?peJEYKyOqDk{6kbw6^F^}gXRDatH5EzA5m zIW-H-0-%CK%`Yb2*nNur1ZQNAVAUV)O?^UjEfVNDNLRb0|5QC4@gKw3wl;rh#c7TO z6(maiG4bq!jhvYFEQBR|X{fo-ITJ{r%Op(PVf<`8#*;bY*y!Cuv^KOF7ZoI&v&Hf` zBWCI8@JtC}w_1+Vrqk>a66m^f(8Nt1bMzReO9imri4!zVZ8%hrSX?HSUma!S_V&w1 zv$m6$X*ubn5G2qgKl2iWMzDvqcWJk&-Hr+pVU=Qe%-{ujI(F3eWs`ax(ZXrY3kh^# zexp-|rVV9@eJ*I%UdlNU34GJ&6u~`>S)6w@mYv$vp<`nCtNWv^(SJ3J<-M2tTJMh* z8_RtvjnuE|d3Yms3Xd2UYS6b!!(-Vt^A*Q zP?@i$JRQTP&^+hF;5gnTt&8=y0+Zvo$H`vSE16v>j{jQesmB=Hd9|us8^vx>&4~&U zIanOeUC7p_R+L7o4ylKy`!ZK*0U&{{B~N3ysnNHGG3VKiD!QhYjpL@! z{?@CKiQz-9s=r5jv-xH^=@xzqiC0D9_=-<9npW0)x~Cp`IEcMjE)(b)aEtaE^z5l$ zRd9}H>Zhp#*i*V!s36hzJ*~?~8KghKsQJ~|wuLUN7_CCW`;N~ed_yenn_~2%M#NTT zLpr*#LDW}61&R4lvAoC-qyO=#VR1IKQ5!a!%LKX}T#V(fuiE->io*Siuos=$v6Zy4 z1{EZ(O^M}|+xFK}e!6*1R=3eVrV9i?4Wl)XNTBNmmAhl!#_2IK+zenpdsx&5R7atLME64`etSl&9^=#f z(d<|CrRstYGJ&p{g(${MqyN$Jz)04(^+xsQTSpZYB<7x{-u6{nuaEYzv>(nY*4?K@ zQf+_)y3z{A@=HEOjQ(^EOIU{eY9As{L88J%8UyHO#JD@ohxJW6uKu997728Xqq6ccUVTL^WK@vwr<{0xe1INf&W>)Z;`3~59hGoMpz9&E)S?dr>M`0^?8f3xWM|7} z(4HSqkjPAHQtxi_*JDht-=0-(SeQ9dI*>pY)W3Q}w!f0KWr+m3u)b21WnQkTgsZ zwwYGSqJo4=Ksrx-ar2%R!OCBk33RP*@@j62A4M=m^#>|QY^k2W2TpCP z$H?#6wej0hk*p1kmmqDsN9yz= z5!NS&1iI2khll?$#>kLB1qmD%R}^~$x^NtxT1)-hH}<}IWMlgJ5*)!s0^`X9jtFAP z@lMMGjv?ciHU5%Jpn?Qmt$hMrc!e^73KI5Hj-$>v){8Zq90TtO=5|bK1ak@Yaj>_I{VO>JDoEgXfPDg8_U|q#NZ^Qt90Lh-;ggjKY*S$y z4)2>xpn?RpGVK%Svj04=PmaBK>|e<-P(cF6&g>KDx+C>DF_)l%1deOTF_1tP_IG6h z6(ka*F*3X=B+!Lua^NXYGWOgR$h!W=5cKm`fx zC)g*@h3}0_V6MiN43~%1!$i@7tZO(1S&{iOV&PtE_tp9 zpE)W>V2fOifdsm6~Xg_6c<1oP|uFf&})EWCHtVIR9mzKm`e$dy!)xfiApS znZR}e&X{3MBonA0fpcN@33OqvSSC7o^-2aJo5Er7eQGNH<*q^@Eq~J+29~5r;n@*wq5+dpsXsA`CZ-zMp zC-E{T3R_(RMG{XcRb+qqiWF;G`(6?2|0@dH7%VJqU9|f&hKvdl+m$j zI9MAO6eOlm-=M=AGmo26%c|fNw#<{rYjv^xzoPi}4%9BL2@*Z1SA+@@aysJH$7_Lo z1I0TULq-B!LZxpUo~Wr`Rm8C*?ZWB+k$lflMFolXRTKF+b9FuCZQHNZ)>o$)So#(O z66pGTJdtbeHS`$cO}n(A8Aga$nmi7sBdV;7R;kho6 zm#S@}6{XY3Gg`u+VIqC6B@*b0xRS_MRWz>3@A4h3qxWDjkw&9XL1Jlc3!lEIik|XP z?cZyxa6hq{X7!Ok*Q&M_zP)laJ>{)yW)#Dp_7JP-38I3;bO#IXP{W9^dQE1r>Tq{a zkW!8Wx=#1B@RN_L>M^3Hh@z)mg%6#9jS3QJ6D>SqVnsb2$$h=Wn-y2JH}uvvubspbc9ga%4g8aMrY&Wx zzq@%Xt;O1J`8v?d7W^X>Mg1qzM?JopL^AgzQ@sd<^R8LiW2u=sJNE- zy!MmkKk$ws;oC5YAIoN=>3b~o{lvbhLilpDxZNs=-`P=8Plwm+F@k+tpxvPP4I=2Ia&j^cFYLZN#OD@|zf&<0!%<-DXWJeVhBoc%!I8mqg za4mVaOrQ(v6-CLM&{dcl<`O+mNu>`eNGvOy z#2*c+fP29z~h!UbTy|qZ7tJpycFZJ6&Plu&$b8+Q(Injgi6)H$%_+;UOQ!45) zhMiT#-=`{y6*T{W1iFMqUnb30L61?hs*A``yoTsP->yMLB976QFsm75$;52+#H%Pr z(T!F>AR)jdmn980*A%Xs8;M4g+fhN{Go{?CgAwEQ}s(7Ql$-X1;8Ri}n6s-7XWTAo2GRGf(-`c>e?I87UY833OpQNRELD5`7k% zd4t}r`t$g-tDSoAV=x;-=M0CE?h7rMU;9;DC*tpfu!*kD>cP8|+d)CX^|c_^+g!D^!uB0a;=xK?J>^$!sO;O` zimdu=M->$$`u<4bOCHqH3D1wsS-YEM*<+f6L|4G!B!0_eYlX>#&xh7*$ITMV?*Prj z!EYfEd?|^~e`T~}3jNidnIa0azv!xvKo_f<%zK$1=u1AcrB({<_8#ex$>P)+^Q97YlMkz-EUGfwB zaHTh!-SxZbSJg>H1&J4~$^276BbR*q+>M!{v$1=WawO1&xkphJ4S1*i)3YDTMDKZy zjTXM}eM9T@I#RnWc6KA{-*@|1_}`}*=uhxn^dq(ZuYv3%wS7=Q;(jL!51Hbur+j_d z4b`vT5cY#+6p=tzR1FLNIjW%^WBI5{YTJ@S*?qbyRFLS{-omTQH)5EI9a3v;@MV{1 zbsG}s`n)lbmnm$Na2MEm^=!#e%(uFeiV70PCM5DAR~zf;NIE%Hz3Ju84$w140$p+` z>M$Fbv-4kXZpCAgwY4Q;L#=^w%_(t00M zkdSMGkrh6xg|qc#>18`UkDAFA?vlawoG~xZ_XiLER_{#d#rn`*eN>QWFvG%&U#PD? z!EV*Fu)+S_S^AeSkwDjy97()Do(B5ejXIl)H7M7WB~!ja1&JSbEj+kNJw1lU?LusA zSbO$`+M-CH>wC>4-l%VVJ;uHt#hLeFca}_RCQw1*CAH34&2!XaQ4Wf1W zNTBQ2Kx&cSchX}Fy-|U6T)@~4x>u+m(Zwl=KXo)>9Jp4AWq9ny4$-V766i{AS(c49 zVmM5#!Jh4LW^=qbf>=peAa}&JgjNPE}!-61dOwv(|apQMVJg5)x>6<@iF6i^M(ZBnv zJ#UW_)#%$bs375+fxc?B?u%gnt4Z{_(*vd33NSrMPKcyaZ!&EH78z891tk} zAp#X7W@Jy~qmLLdEIH?^YwwQ{8|ZsQNTBPl=ZXAV>@_{cV$U7w@Zlpwi0Y)Gf<%v! z7VdEAlAew`rZegy|6$?+-CZQmmHac2E5)ztF+OiTr(XRy)OwmODo8k&qL%)3BSwj| zJL=b6)l_yt4?V^F>iXBA{dvzc}Ew9%F3n;;f5X8xctFITGmdZIZ-i z`ajZR{OnnVX|-C4O;nbkf<*e8Hm2cyBgXBDte~a}^In-i*R5_z{Or-kdJL!hm09#w zH?f)sRFHT`?ciarj2KgTRb?^jn~0ZGCL)2ZNAx}V;n9EVF=G58m}$%mx5ZWH+p^HQ z$5wyaYAL+);yii@SLR0q`%&|wYY94A1QjIw?j`f17xU<)XifSC@1&KJ`4j4MB7v@7 zRZ{r2nnsL>+>vY%+sOCRTZ;-3C+|>8*42nneRBl6u*5gD(l?nvSA2;SzS5jsPsgzm z5v+j!_SE~-dPN0^fQ!kz^V#frI<6fEV=bm-*Q!we90_!FFOddFVi|{1^6(nZQPU2pJY_y`>@N!}U>o|!!)Mh{e zU3X|)Jof4f{h9Mv7q)I^b@7l+P(}p_*Dp!D*5iNlynDZHGv@WZyeLB{M*>|VFH(=} z$4fm%u6`|;N3XJ?Fpa9Ag2d1g$^1{77kZ4q;cc1s!lJ^7Y6B$DRkvU=FZSZS9;2c| zCw9>xzYui(6)H%y>XOX!^?9qu=xgz0FXm`zuX>DZ_xiDzF>kblG)EN` zB;w{K^T&(6=rJnvAHdq2d!}u^Dii3+(DoB)HL_M!g zU-cLt2M=ZcI9$}4RdA9BbiJ9L%%?bK(BF^8Q~lV)ovGRbDoap7qGDPyPYqJ^_hWF_ zD0a8)TJ05$8X$qLT(gq-s{Td{w-TdSmOU%A@ibRdJL6QVw9>E#wMOB zrVXdJ78NA0>{68a6GO$$2UWG#RC5*^5y`VpwUvFLX%YPIX10>EV@f3VKA1&M$E?Dk z!hL2v%}sMuQ9)wOw+L=_&!XR}RdvP*OVV)d2kjX}0$q#VM)JseiXP)us{j!_c)Yfe zzIclY5)Zv2sU>6Nt36dmi!`5=+5<{C66orgC5jJcfAsgGN$*kO!uPeB3%yaOAQ2TA z$=^)BPc%9IC5rGO43ol1~XmPPX`TmR8xl>O11 z#;D7RDNh|$RFG)k6wN1X`&*CEw<8mAP8G$7*D`^wQV*kf(#R)z3`-F=@g}vh`1OYN zFByEi05iUlI%r6UxXTI%4%~DPh zfvy{2CZ6|ZnjWLjr(B|Q#;&4FQ707@B))mjE{NAx^mOml5!kAnodMlCk+ zx6J4d&b|6a8^wBwd_O7#W6q(cCxn5zFa~LIPd4_L+G8_C~+9#@P>A zlTCev4-u#!QEHBf$2BzioLlz(qy4pNfS5w9J|xgp{&V^%1y}TYl_~cF%{*_As80kc zNUXj_`whY_=;^qU;iNXBo{yMLCyXP3E{~D1{9-R-48Wz?9<9#0;UbuJzMz7Ht7k0# z^W7K&xVd?yHlWmK;YqC}B+xY|G?rJYY{WSEb-C8rceL;#0u>}?45VFK$BY=x#inWf z+WLz|lnx}&<(V;#Ke~2KzgG>m#%hfh(e8WN)rblb$KKHyrae#T_bT5aFD+m9V6ltl zSdc(h!$xu3?W1k1Mo~7Vw9{g~28-SFexQOxO7%GYXXr^ihUHB?t!lnd(U@8?NTBQF za5`sXh!JCIU^T5xVyJjZttC{D_|`X$f4goQHBywhNkz2*EKIzj`Wy*#6`CB!J2x_7 zD3$YRf#xvLnFv&nC~l79dsi7T#y#AVdNo^wXivL2kU&?r=y?9K$Qk{4^eEIkHSKJK zs6qrPNIZ^+=jTF>>-Xwf{cKH2l!_E%s0Dxox~9=dp2a#DF>bnKcYRenQdA=X6(lxp ziRXUXj2J(*ws)IBXUdeI+>QjgaC}Zt)>YZ)wx~vgs7?ebNZ^>9q7+dA#g49t>Q}m| zd2=FpgFUu+zpevJe9Id}HV%)hkPP=XjVwb4ALIsIibTaqYP$R~|GgGy}p8l*6 ztqMZ|UHPem%j#sz0*u(cN}KUw6njK_s!>6rQ*}DI{x93C6P?oBP1Dwo^J71#Rzm_^ z?`p*Iy@AFoK#}rCw1v%l*$;Yxs30*ePb}X$$CzoTcIUFz^r$zRN2BLRpv#Nu!B1C= z5&Bs1t&>gUuI|ZJ(l{I{ zNc_rU;sr}P>gm`}x`4PJ)R8sXDHG^g^fiVr$YPs`r>`iDEGpJbYs&`H{0AyXM9`Ph zJ~yqS$2h&9jL7%31=~&c3JG*+Gh_IZMaCM)9Yr0)$>Pme^}V!j8x$lgbc#>>klK2T z-JNQPnxCB6K3V~R1iJR0j^Mb1Sn3dG=2XA?`YTnx}z?(`E2>_?pWSfct%!ZSLr=R z1&Lerqq)Z{W8JIyN>dRv)Pbo#WddEdOGooVos3z1?~|>?k=!MjGri}iAW>jV6fe5Q zSp6x+brf4m7GQaVOrWdX?I<3Uv63;Cv8{{f;-8znqW1$8Bo44BUL(?2ozQJ%H}U9C zHa2OKOrWdOLFzmAHCAj{)^!)xFK1>0Hc;;l6eR9fh~k}37^^Hc?dl<3$7E#Bx5@;% znkGf@Dcfx8))eLT{a)h0&R^=Hb&e`3NTg+s;zw`%XH}T{08y{PbF~@GpCf^;run1z z`9@{+du84@qFo7BgUMQVXX1&Y-;)nx}2#A z{MAp}+*ZPm1Rgl?xwTb{w4xw^3KFyFJpKQ!Vzo!0OTMZl(<8*wp|Pp?sNG)fWD-9& z*Vcl>y#TnYKvAA;3e~1{31T;B?KxfvrYX-8GyfFyT5su(>M}tqRw;lv(HJr+NbtYS ze8jA0dT(NF;A*Yn*-`8q^;nQVmrG6B3((ORRf~7oqHSt0l6|0(8WkkCdm_)0$C#Dz zu6asx_%Mtu|MouwxI$(na#OJndOF5u?kgsi`>a-_(b}wzN&Mte+c@slTuHp7r)~T@ zche+(Xl_RRtxbF2C9>cAi@l?r-l!lkBtsG(d-*TDb`JmBQ#{L-mHGY;fv!%pa`{$H zBSvy)XYspXUiOsg4^)syUkO@<<|b_4N-50SioA|R*(f@5010&E`(xpz#m0#6-GVK} z-q14aDb+ZrAkjlu`1MD|sB^oo5yGWb#?%PvM`8XM9+SlTZOCuE63lN@pBIZ11G?68 zb)mH%s374%wAUGc$gAJ03@H)f1nri2NimQ>R~*IIHr|Lac~7_~zv7ZxLE3473KG2nlK9WGTzZTa zp<%*L&97FVQyq~&SI#|2{Bz@6dOExwhlp%z8>uz!IjZQ|O*;k(thW8GOmv$cB3kTr zQyqyw1&Q>z^e%&ptLmIBL_F@+R#j>A90_y<(K?w@ET?`|BT|FJ@W=jYChDc4g2WSA zt$uErG4H&sZGd>}FoSl)SDpn)Jn&&QJ;tRGV?>@03)M5}B?Bl(gmq2guCKD` zcQ;qaDAB+BS~U}mQzL<{)Z`>yF}pEWv~|=7@u<%Zbs3Grp@PH`TG^lLtuePiMZ;*WvdGtLS;!kZ(5ap`IEIo{zJQ6Do5Dn zPxHjm8kY0M%#Y{#dLrdkUDk+3KTttp$axEI{_2NbwpR#o5f=|tXD2_(1iIw1WNd<~ z$mCsx)unrd3KBbSS$LzvKlK=AZZ#FB`a7`il-rR&7nWmm&cyL+T4WJ#R)fyP!FpoO zTG|bk@Y?#ja%~X(j0LMMkY`}qSLKJ-l^(a{i=H8{i0cp^kMmEZ7mY$s((L` z`)xJm&!4o(AR3S9$x2hoQ91-j+;I{~QT)<@L1i8*jhsF=n`6 zGq-Jbgna^C*ejL^RFJ?vgG}J_z&nj27BYbf5_N}}_~dY74L#l~B+!N9C~^!`ka#i4 z#COdzdZ`!#33TCjkQ@UQB${of6U;goy={zv1iEk}Opalq6O5+xu=QB5-Tq{29N*u< z*v)}4P(cEFGI9(g(1pD)nQ-|P$9?nLt_sKZ@oHrP6(n%1-#&pZOp{EYf&{M8wNIc6 zdoMD9 z5?g!6^330={7XrV1iEk>UXFnZ5|{VI^7;*p(OOIg66nI&0XYV~ojBiuZ?jCGf&|W_ z*eB41S11#xAb~R}_6c;^PdSc}VE+?W=E^ZJhX=)&_=G;TH9q!pJ1R&dQ62SWlhNwK zCx`^Pa5ap4Rj45GCVj?aozd#U7$4}n^CutYu;x*7U^M@d+qU)?=L+Q*s37sfKbjBv zV)UIc1`_DPHjx|y6(lOscL63oG-gII1`_DPmXjO<+ae?Bbo5F+idpZ1{dNf|NRPoN9;rON~=NZ_t-nZWZ)aNiw1 zCz(J63EUZIpFkHrO_{(k3mnV9JpwX;?L=JZhW%ZcKm`e0!)BjASFM;>KC6te`V-$; zRFJ?mY;p`F(6wS}EKi;N^j})9s33uB*yI>UpzE(YvHV$gV}&WE0~I824VxST33N@Y z700vwHg-E<3{;T7HEePWB+%8pNgRLh=-*C#={f(1j;&$OI}#;JGjM33TE495R6l5_o=% zeF9y0K8H+Te+hR^V*g4eP(cFEPO(p*3r{?f2~?24(>?4H=)#kmWCH7Ltj}>@p-kZD z5bnsfKT?DW61dk|j)4Taa9-qp2$(ZR0{2?mC(wnnCo+Kw61dmeK7lTrJ&_4ikifmx z_6c<1?1@aEf&}ihwojl7XHR4T6(n$XwtWI!IC~-!SVxH}G5mBP+lmAnpOXnxkjPvv zhF=+KtY^U5010&A9y2)xDoAX(L0{o?H)cjL1`_DPy>fC4RFGJ4ESgWvYwQNZ7)YQC z_x#B*P(cDmUhEU-!ZqSDfeI2h@*)#hhGW@|C+x@sDoEfNYxW6r;YmRkihjbattKU zh5Mjo0u>~1{ftatO9oF9z!3|XKm`drS-?JlE?mPV6R048Ckxmo&?T>v!RLVr5_qzJ z90Lh-;Tj#8Km`drC%`^|E?hYz6R048=LFa%(1k0YWC9f=@SFhq1iI|!L{yN#a{}ZT zNT3Vf0-3-T5}qw%zqN!45_n3990Lh-;mRtRKm`f=y$K}Hg)6J%7^onDy%(9lIvh`L zwO^m3f&`u%E5|?rU3h|_OrU}Uo^))VKo{1JGJy&bcowsL0$o^(DvD)C{?u>pBG@Zh z$AkQn_lju%~JoO09ajN-becqAJ`du5P7 z7ml4Nidz1?Ysl{i=1b??p@PKKopHS4TqDMk3uE1iu8m*=X)Pxb=)y5TMVWYWg4^2Y z2$n#r4N*bj@1=2k$N?k9*2%Zr&d&>HDYO#_33TCDrlP#?$*pc#5XP$fc2rS8;<9@j z-{k+ySQq}bu9~G@DD$VQLIPblCaWlyO$}7{-yy6o5vU+>%q5O@pJ>E*kg=N@m>A3^ z(oQ`j(1l~mic&MzNOfR|ajYeswtxx}*WSePGN){N4;1CXl*#JD4gM?-t@1_!T{uQg zXOdrCpx&H6hAp5SBd8$JW=$;L`O`SrXimG0>d_-3StgTApbN+P6{S$c5N7$>T76a4 zNu6CJhPSVm)4H-3dn}i`#qiF;I8~+T-XIoNHb5Of>#0#e0{c{ovMRGbvpk)yPNwyV zNTBQf&=}q?gAwC;t+8x=o4M*LTAzpt64*CXl))WGvUA%us|{#}~7? z7?aJ9WgBupolVai6(q2at0-G?4rSf;T~ceVmI-vZ(}@n*3K%gmF7{@Xrd(0Wu5naR zK?3{gw2Llf5IfTOf%=Qi-a!Ig=DRWc-ZW#s!QYGevwF*3s&TYB8WkjPG(k}!>i1?X zCjC@rP|1J)zj1YT@1~=Q3KBTt ztthQO*JWL%)?+2Q?Qus130yOyDCTA5*s9LW*)58J1iE5(n|ShA zBgW(nbpCbm7OVipKm`e0)kAgdkYY@`+J@z&_3cQY>&{mbZ@2WFo{p%4`I+ za)SyIxSCE;8mDAocN%tQi-b&|t6POwp6#4*B2cFZ8JM|kPu7HXPNISYt_oC?k;~qz zZ8G&^e<#WWx>mG~QCo+Q`rs*5;(g|XD-jYqCQ>d%~q|D33Tn6 z6U$HbeyQK9`A$dFpUjtSq7n`jB;@*|wDWdVT{nU?3z7+R6`L2!`*ks5{H(u4t=MEF zOAV)!zd%6(>nlYWTPA`{J-E%SH`NAM%V2$ltDY1k;CciLyz1=M?m3lku!0JSshMN= zw?oEGq~*_>F-xiPA}^gsR;ibXyXPurE&Fig^2>@QzU8g)O^c*ftyt~frGyJTb5xMP z)hUXy_j7wT(W#IaM9%{WbUjf_JR-7`Uhb-{omr=udBwFYjw&ih;3^y1)wslyl@G}( zE*+2wbd`A+!*k3s&dd0=-;0G8%OrxS^g#s)TrH$1Cpz?FTI@TmJeBQ8per;bhQ|~$ z_H8GO9K?F_2ih9i1%V0@xavt!y7w8%ig;brw$L+20$r)eF+3{25o7MKp=?{li`q6K zP(cD$Zz;-;Z9dFz|1s?o?Gr`NT6#M4*C%yb`d|=`i-Cd^YVd3=}Dp zuaH0&u0yB(;J};e$|gg^!nckpDoDH<7t5c#HqK{wkakv0s4z^7{T~8dxDH)WJS!bg z`xo&O^{LN^3KE~9WBIcDmG!r_L#G{T^q3K1G3}y50$sTJTTu??ov-etQ_MHh9(Pob z*c}+hBSu!$V@x_9r+y6$6!WMJhXlHC6+87HkA{ih9ND$2v`-kvWYC49Ei!=$5*Sah z{wr9{ty21aH6-wP;PaOWtevq=#9xvLRFJ^h&OU)Ith;0aQ;5$4W6K08NMMe!PoN9$ zn@nImi1iir8Ds)ei0x8rKgtA-!{E3N{*p|ff&`9C$pq#GELZRz$^tCa{dc)-vWwnLq^zjAx%f7mn4)1S&}29gzua?_#?Yd&M$=3Xa_3FUbTd zNZ^>PeF9yWCYeA52^__>PoN7&SY-kg93#cpGJy&bIQnUyK$n~obG{lSMry0Hwlvmv zb+?&ke-~|SNBO0h`R=Td*1zx4i9qr0(fhwzzx20t>1gq0-7>8QjjEx7L}cMaK50Re zz7MjW&sZ_(&TQ=qozaL25_9V%@`dxlb)waa0Fn1WqLzui^MeW!xqq1XG{;cA)faL* zNL(v0R;xhY9zX(Jek~HY!-h~jMzySawfpAbEd5NU+Q$-ki3+jS-@?0q=~EOWE)KHr zO~vA@1kyF>n_+8v$L@b_y;n$}f`t7TNT91@V+-%P!1OQaKm`fB>+}uj)DbLT{Wdj% z&UMBZNY{y`lPNqR^cXcGe3-}K<7!5FfT|G8Iq7x0&8Wa83D_VCmO^)D|ci9pwu z`xf4ItMLT;RvgQ+c+XWYx;d$+AR%AXj{HHa>)J>)k@7AQ=n9-;;ioB=q<=|UQJO6) z%3OTfiXL>9-rh16{arqmd%K5+r7QNaPQk zY_y`38m2Jw$DX3oADKYcw9FPBb7zpAj)0*b)F~(XikCDWg$fdTA18A4?GXK5Egbk* z&2@O7`1DRD(3SN;BCp%Yh_PbqEw$hG!J-89?odIZ&A~+8H^PYVPr^lYc9)?djov{d z(Dm_NBLCXv*CDO8rAf<%F8i9BZ4AU($5IuliwECFHb&gShe$wATgWfijY9pj<*TC_KCiFj51+^)yVbZ z#BW+TfC>_q?kDi9IR@x4{6$&zHhT-PlV;*DhtH)_t<@;oJ0a)x!IP`8Z<8B~fpk6` zDoC^)ZQ;YaclbwIy49 zt+d$d=p+&7YB7wy^q1PT9=STHs36hk9G&lT+E-6U*B`@Je4bNU2#t6lfv#OsEnL(auE%&} z@nNkj$F(PPViqb$RJ%kaYF0lz#-Egt>{riC+Si&+5`nH`%Pm}eJwlH$?E4t@c=$Z6 zN@FJ#6(r6)r>~iNjnHF!zY@q!S2Ag}>8g-GSNJLmkE=UUk8!7W5G&>ss=Xuv6(lOY zp^{oNVjQU!!dAt$)|%3Y7ZT`7-fH1l-A3y%6o)X@y>8MY36)&hV6iPAV!$l%p6o*N@d>{G@NVX_-E|cF!Uc=(@Je z!q5C2pvPFVCxW#u)ZgtRog9e@61RU^c#|&ydW?K-5p3q%)o$ruKScsv>GyDL)j&PQ z+1e58*qse->EoiPAn}x*N2z{+dW_Lk!&&f$Z*D6o9Y~-{ZpmzU7RpZFFRN}R0u>~% zO+<4OTfEfkp1~r$y^E#(;C~``-LD?jYsXqbCQw15Ih~sSre0S)9p?rGvuOvrtLY=D z=*pB7$s32dTVvQKP(k8JqbPoBdn-N0%}6hGS&v|GnPQ-;-@~7{R-oKJ9gD`3Eivz#6SXF6DEZ5+!H(L zF+yK?siv;BCy1_dS%P?u;vKBNYo9;`iDy>=`P<2D^%(uGHWbHa*0SajbiF#@&nIu_ zZjE7|Kn00=OUClsd3xwEGT-vjVm*SbJuh^<85G6~dG@u&uuq_ZM6qq5yhSmieRaw^ zSWHOiuBGP^bVXZ2`He!h(%C+N3KA=>hj4boC`BnJYLpXMdJI&MNPn`O&yLYkjsz-5 zR0;^^xetuebBR3yUA-TLa|e@ACQ`~7rCd$FDs(OE5W)HHe%9Z$PoRRtxzq?=Sq#+E z@hVRbZ9`|<6GT_(%?Z4ZyR8nlPoRQC{ly8qdh$p;hF{(>+PN1&Y$L5nMFolQI%d9j zt?@j1E{WAzFAKC1s37sDxtYJ2V6*_vb)Bf0GX$`cR8k{>F2T&a$|)npmv^z1nc~$DvB0v!fsQK1r;Q`_nCQ6l95YR zKJgc&a!*p<9HXfH@Eofx#Z*KF~YI$0@bvO#xg)b z!t1-47Y#OQwWnz##p`Pu)Q&S{0$n$#S9B=Ah|#Cga54D9K6MVANsbB<_dl4q>8Zc| z1Y30W5qD>tP&aIs33Qcjn8;VYGg<(xDi0N&tuLwJw4xCeB(6}5V^542YaY`#mmc0z zb5lzn33TPFk;qe={}aQjzbLZhm6}MacThoM{c|%<9%#f^>f2ikzWGBMG2LlU>c&wrfv$;N6ZxluL3%pg)3=0PpI*kF_NP@Zpdew+lE_0& z1?e#Y^F|5}uL-V2DVHFDu4VK~Yjztk(q2Z025kzv?V?#!D(dwlwGJ!5EQ59utOt@%Q=aF0b7gq7wYf@^P zWU-}IPDh0$VPbv7+-fblDpZibD^!%5%R|K>jOdLj?(kR5MpD8!=9}J=dx?8^G>RZGZ&2 zzRx%FxetsONta)0y{GkOnQ8PK6(n*TH1jqOj2IV>{LtEs>dpGRkqLA;tT*#HwT&_{ z(kfbU=I>|tk`dp2~?249+^yF>mK_e*gBU9 zRFJ^7woKr-F^*GX9+L?iHNY7YtRH0p>slOD#g>6gpn?RBu-Yfkh3yrYz#b&_SnL;$F6_O?1S&}2=#G5?U07<%1S&}29D;oUU07<%1S&{i zp0-b*3rlU8Km`f=?+4C?;`}MTD{>4}kihw9`vkh|zk{e?yA2&#>3fOnLq^z`!y#L=)&1vIR+|7U`=hGKo`#T$^^Qw&0wEE1qp1`$T5&W7uLHn zfeI4XIKo^dk$pk7$;4Gkh0$n%;C=;k4kzTs~cSaFg$Vi|I`_ys_RFJ?~ zK>Gx`(zvt=1)w`p`L3OFNjQUZiAki>a0uMPcS0DFD+BH_Rd^}TYPvZ^PLvR3J`w{;!|uj;jnnV*@k$a*E1K1D$S6(m};+y;n$}(!Q^m zcPOyrU+yjv7z2rCln&==i}aM+BhZCUR#A4|^=6I%m(`s#zKd6d=?L(l^@+EQC)gl# zEc@<1TOCg;YZ|OJ^M@5}cQNX%I;C@;Pch0>nleU6(kOA zGV_HUZ23)5W~>~}@(tUgW}u!h66lhz>RKs3);!Ar^%9L`pn^n0iqWO35#!mFVQkgD zQ|d1IA{!Fu!aJfUhmQ_r52MekfwTt;6(q{iD9(SMNA@g3*xXjP)a>*|A%QM@nu@aF zYZKNWLshYzp2yF{ba$IivE5N$Gk=nCs`ZX0Pc`!lKPT(Ye9oeVtkv0CBKv!qqX%Uc z5EnX|`G9#-^yl&ZNLJ=G##6N1>!==9&Ai^1N!H(L(#6cfO51+7yn~r%%3=_GuH{HjmSys1H)T3DEEeAZ5+&=?siNR$|C=6k%1bc`KUmJMy+Lfm*O6X;sj zmfjVU5u@MuN^HG@Dms02R8c`9mx=P#E+fXv$~D>E+RkDzqIMaj}B6N^~jB~EUY?{3!OX8!ffWb0GI z=cFj#Xw_uauRX;R8s9|)iH7;jJjWdyO=HOAzo?lG_7OK|mnjnHDn;?Ot+3?<+V$)B zN_7qEF9y;Zg$fdRza;Q4n~WGYW<69roCk?!bgz&=*Wj-S{AXVyhSS!IYPFU_ML(L& zKn01#gA(}0)sytRD@+H}%o+W}=y$X(1AYr#i^CFlwapXt_v76At!m_>5#k)B0~I8A z7y1%zvJs=<+2v}@(W6C88bd|`U1b`?^J?$M>oJB7nWc_jI#xu`dQnu6I6E|+Kk7SC zPsfiD$!hJX0irSOgG2&d&gJ8Ip}Yn$_tZGHzv)0VfX1n@rUBonL|kx_nC}@^vw@^ccS@N3hH{H@OAT3L#XG*m1$k ztB#qar{nac2<8*T+_KUf3liw+SvrxwaWZ05`4hp~G<)rO;U7m86(lqob&k6}Q;)Hx zXe7J6s~CSx>#vZITqP2D=V~+cbmV#+!NS`XO&vlt4!Ry+GV{uv_1~3iYD^Oqi5(>wdgoMY{1+!Z|9@?hajw&ih^r3YJ4+{%qLCL)A4-J2zGh?4s9Ym4^)uYw$03!f1ResaH{3Y3P&E%4y3PEhu=b1 z3z|Paet)VS!~N6{_B>mfcAjS9P(fnRTr;m*(unc%Xg`*6{*AVaR#_l{uGouaex;WY z<7H}ZR&w`u?a)>_9R?I6qG-;m%^O>bLs4p1@M1^uW)>4^uM86CI-;5RwHvnfilU^I z^=M+)2QWg~?c0`-`=y67j@RuD~P*8r+dB04ctJHoo|L3?7BTGtq*5GI%ah1*- zKn00hG~4Ii+KAElL~B+zZ%MKFsZ5{?+g*y1RJ{f3I=ieWPW=y5kZ3f<%r7FeoJmw`y$P_cRm+f?*@kPUb_ea8 z{wsm5KHkCnVV-#Xsuo^NRKL8k-78d(=<+%Mt_lfMkZACJEHCC7t6!Bp0$puSj^(M3 zjb~n@UM+FgsgZT31u96CtvVL23JFw@Xf=5>cNfO{VUIwU>xfajf0so4UIlJS)P{Zt zVCk!hQ9%jlK|B8YHDoE7M5zH??PS)?0Jpx_jJ;(8f+fwwadhk9#IBm1#D|EH_ z8pK~Lu$5}|2~?19ZXU#QjxcIY%IzAxQPvR_bRE4O%p+FWYBKu-DoC7HLwH;Pqa{P> zV3ZDP>4UCq&q8>;*D2QfW1m0;iQQd7dC%Sx^n0ZoN!0wPluLgH``wP?jn;HppwHcDY|GqUxk5P8XG%c-x zKbt^nKOTC<^JOD#PYP3x_fS#B-}V*0nGdSp4>_slJrnpHH(QH-K)wW?W1X$7?$SAd zulZxNcL!Y_DhlL0uV%VUtMouY!Yx|@?>*FL>GwJ_SU4)TRriZBfv#We5@-dT5u;k| z{=!uFwOZ(vlZpxwE7SzuF4-W$lfy;HcK1`)(RoXFPw-yV@Jrw;>KON`z|U|IFf%pv zA+6p)1&O+461Ybn<9VbliV$ZCg{2m!UJ(-LDn~JnR54a__g;}zy72tZv}J&e2(6NT4hJaXimj)`)RI z`=j-6@5M%Ijw&ih%sd~@w>>xdoP8UA)5=xv!(Q!kR8c|V*^YQ#FoSVbD^5Pv{MQa- ztErcY1iI4p#`Eh(j2LA;-PH0G8^T7>NuKEXHJ`5ilC2DuiSe0FXaOUA*dOZSpn^p8 zN%8#EZlkWv(@AK-&HUH|T6>NJy2{L?5w8T}st$SY&?bx+!79Cbr20x*EGA@TG%|`a`SZ zDFznG#>#D=ovffBQRG)V=lP8o(_VBIJ_&i);6*Zlu2yvuc)^B74EH@9#jTC`*`29Q zDk?~Xe2nMq9~(LG#?Dsa+u%~H>1dfiSB-KB{P*9+`*FynndtnqJloxg>L^fsvP#rhC=cG#VX50$p`VP`l)W5hJB{W3l^WHP(&@NrB&8@=rW}veJmrxIhEJ zee19yR1YG7uG_g2c*g}sj2u@TMbWKJtP7pwi3$?EZpHHvfkuqF7b*#lCvGe!jjADm zE-c3srJtposN~(8U7|5$RFJrNA)Y6;H)1TFSX_jCa%Z8mR|W}mVQHr*?Msf|xP1QZ z4e9Gev1f|CZR{J$1S&{izfC5vrH?%eY@N#lDo9|?56_>blJZu zRFJ^?CSMg2=#tATe1bTGfiosp6Ui}9!MX&0NhVN10?T~+1iEl8L?&=X5$6i=-INJb zkia=T`vkhAGDdnoa0UZsOt3vK$3O*J~%t!eF9xLzAqD~Ab~9$`vkghd|xI|K>}Mi_6c<1_`XbF`GGV1_RA7f zkdS8quxv*HU3i7^RiT0e&N|p9&}Bd6Se|2x+@V?n6P(cFkp?q2>#=tZoEfc69fp=X|vc_~%FUJIn_cY?w;{G_E;oiOdpJ-)o zu?^$+`C9j^sSP|E%)hR+{Y~fTZ}$?vD`gUMX|416Zc%*y@LSe9YPuH5Go8O_C6?ce zL4+^zg@;*+}FuwJdATr?NcMmUFwUUMA(kFm3kt|IB8ePhAh z-CYx0(uKRbh8PfczX|THGdK+HI=}!YU4y&3I}AFw%R7);^LBkNcdhpyi@kr@x9{z) zuC6*&ZMG^HOJyzl(bkBi+`E$gU8`CwRk?fHPIL_~Yfa?&qOiq0rVmOu5a;{E(wDXB zyUN<3sb#c|mY2Aa90_!7J{?PQ7paWsR|BmAevxuBSBs#6M7y=IRDGz*DDv-ct8;X? zJn=sSx?ZM?qdntQ#>PC;tm{3WJsWENeBoBWMy)$nhjD@FAf+ICMJ$AlxdX`>M@tMZ#qP(h;3ztOZfjjR7RIc?aZLlQ8I@2PCx=(*v1$}-6`L#?hAU!zMr`sE~SmOZoBpC zdw2U1N3%k2{<^lSOtw+4EJ^=w7**Rj$u)ht$sMQPX(sl zuph_KvQ^~B7PaI^9<4$!XDb`*D>1x0CGhTSnQHtM0Kq$5uP_ka${{c+F0H zDA`UMe?(6nh@puR+_sDpq2v81WBZ=jg&ubv=~t22~&0ufgN* zZ<+tz@(}I0y~^9uM!nbG|D_z>Xrq+JzHe%)0T;dQ{6{CX0 z*kVJ-xU8TJm0bk4?Yu7LBjv@V9HWkwe2(VcM+S;+3wvc&8O!VS7Cj@snk9G#ek9OU`Q;G0R94+T)<^Xhr3XDW zyK-d>Do9*9K7@ChR=x0x?YxEGy$fbEe<~!Kv#h~@pP}L zIurkDlUWQr-cfY@+u1|~i9Zj<)2%mm?HT|4n^SBm+g4PYqZ8=*SU7>s-??W$cO&ET ziH(O^iaAW6g2dg_36yiO%Gh(Wh-kI9iSXc0g#@|^oZ=^zJ$LOH!%LSI7Y3WcgO3~) zB+~dLkmo(svutQp5XFYn6)U#s1iBXdNT9i4D&xTH$|Cw)EzzCt&Zr_Y+Y;Vh3jwIIjAM&R(^J?~h8nN3~9%3tJ3+-*)eMqScA=;tuy-Q9Kf`UZVpcrc1MiGxMKXJX`&3jbyGbg(C zE{&lVzDb`%Cq_S5?YgX%O;qKx1QjF>y2Q|^cy%0GJx98}o@x`h`L2cpx+WHnp>J)~ zr`q1IyKAF8Hu0E$K~#_sQ8c%& z%2?o)&B`_`R-8!9wI9$oKo|BU3}e-d8WuUlh|F9qf(jCPzoh#0-_6AXL&Ri$9>jCE zRD2v=@JqUi@Jcg`d~qwyStkNTiLLrIh(zs~adfMjx&{}P*=FW#;V;f`jWGT#bd7Si zQHgh|C$p^j0kg7`k9fe>2P#NlpNL1JGG8!H4)GSVxh+8gUFqlAsMOyoFRy(?0$tJbhEm^q=k3R_vr(+bUofxf$?s4=1quJoL#gDR^Y)Ar3**GG zJl9;W9M%bRjaodEyn|H6n!|D8`u>xy>zP0WiLmZNNe)mMpBmc4rSdCWgScft0$nYZ z4W-;G&e@Nn#v+@DSrO-YnCtpbL1Iy#p){-FIs0)G`fd}OC%tR1nOis{&_zpza^34$ zd&ZMI@#3Oe`v$A|Y)1u&H~jwUxcO)88JFMNM0ATZi6MNQBZ01S{NC4Zt4`Z9)(x{I1QyJ|l$B92jeM+1v zf9{|7e-$KJa7J-=l@YczMpVyN+B(4J6%y#`IBY2Wo#&+eI4Ycp62Aqtv(|lbHc>&M zOP!(Q+V7#Z1L_b+D?6(o+99ZF-`sEndRgGGaw z1y%{Z8z6zMLHz9|K09VVjv=iBMQGPGR!M#fI4VeN$}*JZbvTxuKs8*e*BYF-r~Lw66ktAVF>VgZAU7H?p4SwxGP+%&UHpK-U$Y!L<9setSmy>ovvQ*;S+;SAU{{#PatE zbbH$Ydqyv_su*t8lqvWZL;_v5LW5~|sLH6Gxw2T@y|z5aEj21goZFE=Q(LKwm?~w& z<(aPX8h5*B28hn>LpJ@OOm@5)JOh)2{3L?8nh0dqMHxP;>c_ zKNS+_I%y`5%iF#7j0}wnh?hPsWNN0r(4A-DE;^^IOa$9W|6BQ)3X0}ny$UXMsc=Fdf^LXjL@**Dx66k8t#YPVXsEprS z-kA3;_mw|)TR;VgMpxq~(M4rc?e&kj#Og2i@E9@@==%A5)y75Ik0X2DYi8GMUa~Gf z6`_K}$gHu{F<#n_=`%Od&u-P?^;n`_|1zQ{b=LA zN!Qw~!@l$;?(i>Hqn!Q}@JgLm(Plr{an~#B@GEB%6(r8g@}oyx57;yM-{>w6-c2R{ z=Fuo5&=t_ypT;#*8KeH{DqD3-E35GDfeI3DPx;Z}x$63`J?bQb~!3%d--!#9|?5%+k&WmPIaA!tV%D( zxpa{s{EjMAknpG)L@#oy>wMjtFV<@J-ZCxUYmq?L*9%N6wCumfi1}}=juCz3Q=ThA z1qrtaLDXKo^*i~GIhW+qTU;#|#OdY@5c zOrO8gx-igB9(kz~=-Qe-gc|;yXg`h|SJqjL&j-k_ysiipBqZdU427C z=%KsHsJ?HL`8j`pe8nT%2DIVWw)ZL&P3iwp8D;Y?HgjhQmZz9N1&Kkgqo`;q^?P_c zo?xD@878}MpBf2trA~~Zh09gO_zW$8lP z7lprtu3Oh5Xvw49_TQuHin`{#BhfNF6R04u`A`Ji=CdT}4Xb~ANo%e=87qDH+eHFh zHR2*@_TMUFl-GCHS^47RJbp?=1&O=95w!Lp*)wv9#jY;xY;qcpOdx@-j8DU;{1lbp zQKO=3xmz}QCbx@;3KDPLgi+BQD&zaJCA-TOjF;oD@cak-Ep)k03!{y%$8722;doO_&2oV7Df9>~VW0e>rQ zWGHR3e?L00-Y2`&E-qHyRH}av|Pxa3Kb;uE9zinPpjDaNV$YZIgvoupRM_wVNKQ9p0mYxYh!4b%*9m}s33t? zuwjg@m`l$8)JBx$IOr`G(Kr&toGdisJtMGQEqSwA6>+?|i-`&n&A$6n?S$+08~ zj>y8#oJgPxzXikC{jI$Gw{ktPk9)|dAkidy07cDL8JQcGlz9s@6#hKIf&{wsZ})Rd zE17CiUeSi{oOt9_eEjI*mZW+?{MHTQbmq45LgrlJ6ZiB{K_XWNKROtostwOZbdc8? zWEE?eMq3ox27Kr zIIhNb{a1O&LYHov2l*F71&Qg)eW`L4m2p0HfK0XTw0Vl_$dEwS`NzKWdXO65E#~Aa z%MAG2JjN{pDoCXA@TH|EFWSGWCq)D0{aS0yyzjVL1pXGfHXZY&V^=QNzpG4XgJp1w z#b)mh{N8X-keFTBm%bgmV9zMHBt&lV{LNg!Gww*BYnSCqQ^u-{R3}4axeb#|XTCmA zL1I`5UuqSnGMY^ZlVc;tnce?~K-ZKFzBKf`8bfX#5-u+l9AWn0z7Hx$R4eRDotvl( zkJFLz)rtOQ6`o^30$t-q`qIB~Y7BYkd~VmHT+M4dT8j!2gWma2mQ`w;I$fJsnXPjk z^CP!#NT4fxurK{+qB2J8i@mY;iXId90uU)?A+KHcvkU&@S za9?Wl?u`96FV@T^NA_OkT7i4vs339qmJc0Br!vw%w#mA!i@KKOJPd69uX&Ru6&rdjqg!Nplf=(FL^#uW8o=!#K{qhUnH*QwgeRMxbkUBDV}p)fn=>Zc(zw#%@->GA<@6NW@k2rES@c+mEA( zN4P9MVT9F*uP7wY)%zr0=l71;zpIW$xQy;N+B(AoDoA{4=u3TOsIhRr@4>RT$6PBg zjf+O03&(>DV}9j8x$@x}YZ?=%Ac12*hS6<%cM)1V^{>?f*XB_-gNLRTR$RkDS zKDhc>xOjJIur-6{4f5Rar#w}XW~x302ax~6GrxZ4V^IP0sG_>gFD?reE&rNgjpaTZ z66h+EK7cmVQ|;C6#5hr~@|nc4e6O9?Hh|u|Pr42^b_k%A3zDw8(g*!X7E-NG-+i$n zSE=;YG=6qQ1&PBw0x0iGb=69)mk9GIZVi5;6X%vR#zem%oQ);|wIwmHM1N?LDP3?z%*Zt)YI_pWN=Ef&_kthVfS;o9L3T-1Qi@ zqP2JWQ{5LyEkG*EpWKTi{X3y`03F?xkE98Mc_1vdgAD4y^qV|PYvj)#Dp@PJRfdO=;t;)#TI7-yN z-^1+sMJLd8Y@a_R9#=DQ)wo`w{>~a^LEf_l6(scUsztF_F?M?a)0x{{B+ylzGb&wB z8C8eJiX}s`nK!wghzb(;+ZaZNZMcbw%};ziaI3mV+#u_YwX^<%3)d7oBywU4>t#g%eh=_x-=pn?Qm z&4%H1%O-jUR7qUMcTObG^?JKM`8%n*bBM5s)ytPBKI8qbP(cE(f5Vv7x2TBe-9&ES za~E4`Z0(vf4WfHfRLw+smy#lNg@&>de^;m=p|^>h%a#|mSM}sto&`VxU30$$(&cp}_tp~CS5=l%x$lDny6(;hq=3q*-|p(yKF9IyY_Mj2W3jbKFH#uMqKDwb@oIuZhFE%!VNWRMRKvzNFuA+(LuI%DK8?2w>iAbR989!|gj#PKGz<6I#vVvtD{^)F?g2c*w0hG&9J^hCb28v~aPFQ2O z^+5t%)p^EbP(Ag;GOL`ID7^iu^_hE1s37t9Fprm9RvF<{-NpGO53LtmO@#!yrbGl# zmu%`6{AXle(XQWHs~xuts34*L9#MsQiI!yynTcCCB+xaTf17JADq~%bZX%?!lf24z z15}W}-`_BfN-vSmyll4Q9x~o#@P3seb0DqBtm+y1cJdIXYu`0ba_t8yNGu&6K&wU` zvG+wc_v$NBIK4B^uha>2U2POd85^m32D;EoBwYJuiuKMWDo8Ba&tqiER2{&pd0mCq z;IyJ2*Y6^MuAI?<)M!J}45nc`ebGs{&B-VR@R6f}MEUOl6p%(`Z0y`xgbvChBDvN8 z33S=c2hyT-s-B^H`(`5Hc_Fca2~?2S=@m%M&;P46h%iOYYNbVPJ`<5ZSCzMcRArFL z*mbFa$dtCMxXtY@Do8XN9Z2v0P#Fa-))865D~js;B#Z>QM6n=R?xZrZ<*6m!^{XPT z@hB%MNZe24cDJ0$sOD5fr1PmI`tVo=66hK{K8R|zS9KW`ML8j5eKCf|OHe_gPsJcA zAE@SQv$QTEn%8M6Jh?}P1iG4D45D>M)x5KtUw#phxuw|7S1l??9336Rcjx`~bGLft zY+}fR_F~a1oj_N{YQZ$IkIH!LoRLr4&ccP;c2tlUaVLo4JyeFl@BcXcrl)Yr!lUQ# zx6t*+l3?0#Ld`oLs`bX~c)qVlRX)b9stOOrU~9z?fi4yHI7w+*iy$#(Rk@?{xxQJMRTk;h8EUw!;N;ZIHKE zz`r>vNVHrLOyx(bjDLDtrctQ#C9x=U1DJ`UVOwt`pO(k>L>%B}H6+kga9s!ud9O0IdrUX)icry$2~?11Ha>*TTu>QXe#DuP zSuK58x|FKkM6!Gh9#!ie9|8T_?DoD)j5=wc8sf-83ikgGp#E7(6XspU`UzW|>HZ)ea@LUlpNEG`cl%m~LM*4-PU9bHeCzkNN7728HtP@7HVpT?b z$ZXf&J#C^m_e)Sg;=OYi9q+6%!V``(sE{^Zq~z-y33OejFv{ewGSUvuy8Basc(IM| zgQy^p;$#@*YN|43dz4Hp{>UbNjt(M$t|m_5)WW7Re8%)jtZmsub|z3k;&aw;8r?-@ zybL&y317yk_8?CF{lfk_na1V%ny!!C!1NBstSSLts&avDo%zZdikcgg{K&{5BC$EI; zA+k{Bxz_uMI)SdfB?gn*ZIxj(43V{-%(f~qfeI3n<|I(sAeC{`EnK#mKEhhZ_gW;- zHM-ki>g}wayjG=*lJ&axwc2x)H!4W%+m}Eqzo{p$PcvfVyISR}e%z-<0$pu9220uMbp^=zcnZo=#C2xv$2`E*qUJcm4&DK-Z!{gQ;_n%BWmBPC8$F zpID0faHt^h*M$W7t)9y8$YGO(7jI82#YycOamHhfC*HPxOqN-%(Lp5v*-I*=}|b9 z`G`kSkw90j&V%VgZ#AB{X-JIx^rE~un|rUQATdfNP~fPfkz2!9SvN|S-P6;Ywpu69 zwYNEEd{JXE1vf;>t`VMQm8H%mDo8xtoP(h;Q)_6MkM$ImjSkX*wO(-NT^K3X0=<2jOo?d-Z zs|SvF3pqY_De;VJ4NyTM#5JBu9#*qU;W2e&(3Og!M541spzF}0cq;NtWem?*M~-b) zNmO706(kl^kEes%R7TY-E^=|Ki&((38AzaO^A8)P-=jt*K8Z@QcJ4YN17GK;AmOpl zMtc^j(T|p;O34&`gjmAA2NLM|CT--@T4jvOP(n5?*+?wlI}R#Hgm~L1&_!kB>y=MB zU2iF}W#us56E6(n%aBF6-}aNVs=pn?SMz2ulc7p@=H2~?24J)|5H=)!f-I)Mrj zj?Y~r(1k0&^$b*yz-vV((1kmH;gzNns33v6jyWdKg{zEp0u>}SYkRl-WO5dBE&X#J zdL+<=tBmywRFJ^^)*KV)!d1pPfeI41Q;=f0$sSHhfbh^1nxTKm_Qfq&!H2jAc6aoIVRAxL)-V` zC!?+pRFKej%yLAa3wQL;KNTuS==*+P1}aG4o?dze66nI+fph}b&f{8r9DmRW996*; zZa5O66R048Yw#Qs=)yjcPT)8tj*DW&w@%=!F3uuj6|+v@H;Oy4IsSH0K?3)R(=(7j z7w)~J6R048d)_%F(1m+1=>#fB;NGT=33TB(rW2?jfn#Tm33NF=cTvHyEW8Tz3{;T7 zQ7Xp-x^M>xoj?T%9HnwhpbK}9&=jtO+(_=8TMf&}g+;Fv%c zj-&h!0b?&n;I0Uc33TCjkWQe21n%zOm_QefYv}|kNZ>9NjtO+(Xq!%;f&}ii;g~=d zjvDF&w&%Fg+i}~D3KF;$UC%%QUHIIt6R048Yw8^n=)&;_oj?T%+#A3#fi4_J(Fs(L zz&#Ee6X?R{cAY>43EZo}F@Y|8y4MN3Z{z(O*I?=dDoEf=tYZRQxRz8W@KfP>HSB%p z1S&}2iaN&xx^R|MCs08G*Zesq(1o+4I)MrjxL(mQfi9dS)d^IPz;&0733TBssZOAR z1g;--OrQ&ANp%7hByb(9V**_`OR5v7Ac5<79TVun{=810f&{Khc1)lPd;L0r*BV}f zxXN57P(cE#Ivf+|!nN-@feI2>o#L247p~#g33Op)jbj28B(U~J&p<+R!F~rif%_UD zfi+By33TDU4LX5OSoq|HYdduU6(q32*fD`FTn(xds33u>M;sIA(pRPYWYjnV_SJEI z*m1ud6(n%xSN~KI5pdau)xRPN0GWu5fispbIPIbpjP6aD}T*V4H|*^>LI+Cs08GSD8B| z(52U&|728qg$fe5%3RMt0$o`5t`n#rfve0N6X?Qfe4RiA30!6Fm_Qevl{$e661d9T zF@Y{Tr*#6`53Im;+?Jq%1lEY_8AzZDce&CDRFJ@0cgF;}aJMd~%b=3)M)e>RNpyL(}6(n%YpPqpPx^Ts@PM`}{?Kvh;K>}Cs=^03%3s-0B1iEkq zpko3RBya_vo`D3qaFw}Epn?Rh;B!o%3s=kQ1S&}2nm@+`x^UIMPN0H>zJBm0quO>P z(1p7f=ozRWfvbTX6X?QS7<2*^Byjz(V**`{@3p8Pp|3^$nWDZcB+!NTdBgDi$6NT; zJ!dACa53|yjigL(Q`3rh`y0fL;{B-BrKX>IUZuMiNkh}8`t|>Y5!}>Q9H=hM@?1%d z3KBWHMUr_dn%02aUC)$NX!@* zNhKDmjL8%#su!GMCh*!mB+!*#L{aPYDeM`}Kf=YbtqJBKUT=U366>}^QsSf(_Twmh zJ4!r{Z)=X;rxWO^05cy$dD=n8xjN#%Ec zw`aURW)pYQv`7r)b;771v3o=mJ=*o%zH7wS{PE(^+>#W}dvYLwuGyUN!%`Vn3dM_F z+0ETPyzd7pNDLekMLo*?uxEUJVG|k70?;DQ9Yx*d$9E6vq;)w)--7+AcCxtgm#Q9%OFF~c|&lTy6i(L;XXRVmAB z1XIcbPk;TkrES4< z9?2>u<>?@Oxsn_SbPX*QN{y<%uxCt8mtDBkZZ9wJRf`G|E-|6>q?XFaf3$$u_o=x& zR?|fz&{b)-|dstG{zLkw91HrQx)E$!mMY z_{H_ar-btIAh$lKAaOrCzX$8#EBkRwO50F;=~GgkBAr0j*)`!5xkY98cWor%&lHzG zD`inZ;&Y=2y3paZJtOVD=3+&jf-*br2Y>{+=Cz8THbHOg$5H)E8}ZUJmvlYF)zP3J zk!oKA{dV|`J;VEYXEDYlgN)%)v~>}XOzgyrah!Y` zCj1wTwkGjgDp5fqdyOb+TIjPqW5KRSQ7OU0+Qx6FKmuJuk3`atfTVk{VaSJN0xC!>?-)e~Qhc#zq`Dq0mXE4qdHtyq=)(KFVYI6hBQmUTw&pT{3KFTjqp0Ts zl~MAa81Z6IG3(Suoj@1%1`LDtPq8j736=AC?b3_D0rc(bKfk`kp7jRMv`3GAeRjEY zAnomt^#6u2srg`Q>DzF*k_l9h@EI|X`d3Y&`Tc{7J6H|2MacoYiw6?u%Ku~_1(Z`6 zGcq-?>i3G4N0>lY)8hl_cc-Mks}oIUI$P^1#>j5xxqk(J3yDws|LqL*sVY{>WK~}o zE3fk^Iwa85=GGv}{Na)PygJd0`NFoL29TI@Qo4vE2@vJk6^h zkU&@KRz9@-j>>5IszPG+yEgfOSIeS;M8QTrWbRTK*T1DBcivm=G@tEApzGK@-hK71 z%9wt>Sc6&l;^omByu$`4NEp|B=-p10@g=N)Yl-JJIsK$gpsQ4IUou{*46ot!T>UTE zOH1^({3^1d|esLIHfd#~%k=W((SuS-P&U9Mh!w6nH4OKRRrZ#wOcmFa%Ixfc{9 zh9&Th?>W?O?lP&SdHh?n4B@*066h*2%#YknmC>(LZQjQ+TDmiV3KGs!{Ag_+m60!` zhuN)Vl)UgwC(u=Iu|G|^pfWPGiZBoS9wB}Bib4emI_yvFcB+h7|4cO}#DvO#fB0QO z@VC&_qYdx3RrRs`+oD@^B9LDGfq=SZL{ z$Hf5JyGCW~8okb}c0WM&+mF2M+!xk`9Bwi{6R05Z zW|tRDS^dQR?e1TnQg)lu<5#Z_33T<~jD!DWl=Mp_x0mT5f4)->6(p`K_oCjG%BZk7 zgG@cWvn>BwC(!kNfhSG7nAC?ijC5PG%j#A;Y4KW1RFF9K-jn{^oAd-=7zGL!l7a7= z$pMFS0$savc~XmoPwn5;=4Zv^!t9OZcD|pZf<$!>PpbOIGy8XS=$|rj{p$vD8Mh2b zpzF;g4_cc4nLT6t<#IAZo%-??e^;m=F{GX+dA?E^y)IXkrB~LF_h0D*x-OOUpqgXU z)5P1rn(}hSs&W;t^hO1VzovOmkq+vKWp@@=S@LKZIgEQ`NTBP=Id_^;{)PQGysij2 zV_Hf1H}_sqL85wf5BiwnU;B5JX;M=;_ikbNp1&(3(A8&zJAKUguRWtxmKO5V_5$)T z_sCE|BFjg2TDf0kjOTZl9LbnXZsA=#kU-bdiT(MVyy|IU@4sDT_BT#)M?n`86(q9! z)1UUgQ%@7)XZM!%YJ9PN9*0JNtK`7`RM$s6O+?M|mWLLdx3(5{F;T(4yLg%#ozC^% ze&qeW_(chtaWrvuRR*GZJ8iB6EgWag!0+n%WW{{ll zZi)4dpIA^qqD{vBlcB3*mKiSWcR{l_SIcx7vAHWR2IF>R9@ zofxJv`td!mVb9uDNAB+;fv)9Q+~{5^)u)cy93%H7l(sJOZ;lEQ4`#d3mpQ86zU)w} zJa#;tHH&xULIPdOQoBK)x_aL@IoPbQq-eCr zB)1RgBtG+=97v#RTP`oUe%HyKvF~&?X}Yx+XP7_*iOJ+iEBmU97t0FB!TDQ=&-_*r zB+ymrwFk-cDx*T35^~|EhN2_iIZ;8P)j$v0)7i;>9DgpTBzsu3#Q=WC2omT@$3$gY z8vAifUR_NdyjERI<~{=|NId=OPEYTqv1dfztu4DnR}w3D2LU9|)$%I0aLH<6l_7exmZQA#hYQG zU(%?$Va&eVP0pE+Ms%2`6X>dat3Q>PqB0g2=_!w%Pa&=>;e8-ML84jX{^YV!jnLQY z*IT~K@YP(tKqt_(b5DN?>#H)JH}5M~wSH&1{=vH^fr7+^lKm-Lh{~9>#!dDe{LI|N z-!2m9dOET{b-$`c=$kxqm+Ow+Gvk;*1&JBo-Kb|ll@V}qfXvkGlsSWU5kvxAzZdII z%TuY0kt=t&s2~wG+>P?4P#J4ChRE+Je>0o%n-`HlSE(az)bgwvb&hEkE(fv7-e)39Tho=t$WTGzuY7Lw zG)QG!-X1M|m)1AU4LX6Yt!vz9O%Ijf)-y)dKUUf7vzFg>0}2v5v$|2odMe{esaP4~ zQNXl#yaWk!b(rTy9wUF)@0@fqRu1anWHw#Ldq9AKgm+pun!i%bG-N1dlRvU=ajnVE z=SZMy8~=jiSA4T)xE`{}o1fdcZs#X2RFIhaZ$Fyi_RW5G?w&VZZh7j~Ao~uTK-Zy> zd?xl&8L11!%K`l_*6;Wi?>PVp5>;RHqwV!oM)S`$**xJp`SMdL66n(JoXrz#vhSpc zi52;dg9;KiQn^t=ZZ#TpW=))&HR@90&we`+=)$|UVXTe5Z8fz#gg4K`;r$iw)Rj&T zr1T5Y+wUKbevX$AJnGgEI`GX1UYb+ub&q4_eWe2Z=WPRD=Y&evasjSgkUC z?2}eRd0$b9?>ML+ai0cJD<757{YYnVwpj*o)^ss(ZWCuoTXhYmW-;pS{M*wuVppwP z;!7PD6BQ(8oeHP-N7daq&G;tbZi%Ae=bPn_K-ZFn;gn*M%6M?Hu~?n9nCQdp6)H$f z*&I$^o~VqR85@W{AD0zlc#I4QbghdGqc?7xkDk_34&wPiRFE)JhthMQ&i1!OznQht^%iHp>IAw*B?i+UUDeq>x!N=H#V$AT z^ZkRUAd%{OFtxp^GTJY?YF4h|C9d$fiv+p~ZVRT#y;R1W!B@?UwYOqBlPqpn}A%^}$rm$Y5`M8Z?(? zj>f*CH}@HkK-Z$JLG*FA%4k`2lX5%hT<7JsiL~6dBZ01&qj}He+A3pxhxM*+D%r#!CQw15 z+VlW=a#Uqhikj`3*2^YR{SSezF9QO|sHZYII8Ar$9A*=V+`^%PglP+)E5}tvzNH@< zjQDI5<@n8uNT6$|k3Vg%r7{N2I=DMSzIc&|-};6M61P13Y2ts!Q93X*vGFRKc*Juo zNT4g#XFqE3-|sP_>C8mGK%02WeIHbiX!yyGHXl*Pv7_6a#DQbt#8ZB{LjqkR+WJw^ zeCjxwJxXi+c`}yYtm|x|f<%uRel&8m%Gmg4Ju5**i&H!njs&`D@*7;5y;ax8^?_Zi zYQv(0jd$`y1&L4n`E5|6RmQvMNGsEr2qCy-KmuLeoPDX>O_fn>Q-ZbFh!8*LqfkNO zYX)D+6`(S{J(yvoN);;3@orW~piA#%G|IEgn&=)RvhckY6(q`z9z=UzsW$P^keybM zKtJ({cZfv-UD(4hj732m*Y-+rY0b}FRf-(*pv6Yg%sP&$b*$}4OSiwV_ji#%1qmD} z)H4db8$fwVB#p7+c)K6JqB7M3Rgr=js33tejd}(W=vte75H0^BxeQd0_|kh29hj3G zfo%z1!QVsxC3>iy3?2s_d4Z(^C_}IR_gm191CJJo_wxqOxqfP#8Z(eU7tT898K@x9 z>!LR;%c{nZF#`#7;jDw6feI3? z6(lmu^`h5vR233_S4f}>XC3qmRFIh1*NbMPQB_Eofdsm6)$|AZu6u*kCMwk0$tdS>BoWBGhXNOiUd&L ze@{ht9H=0H_h3B(33OSm{*tK&p-lQPwx6rE|FXY-VH{K^`M@alIA?H zo!2u^L1J8t2MzaDGbZ?5A%QNOZ_zVQL85LY51N%;RUu&p66nJD7Ci$MB%YMF+uwP(h-c;X(WUR`WP`66nHbQ9Wa7 zy)Zi2A!#lJN562CN++)&~_Nuy?L!Ac3y*Q+%n`12sm5XCf*{VDDVdKmuJE z3;NRdgUMx}f&})?^$aA?RrC{Ao;6J_0~I82{8GnkIP>CzB@HbhR1;l z5;(`IXCQ$tY+ZE%6(n$u)iHrCY=dBf&|Wg>KRC&YtUPFD%2>s3{;T78B;w233MgAcBfS(lFL8^37r4bGmt>n zxo7UweYmPA!tV+dByj#y&p-lQj{DT8Ac0j+dIl2c!v4HYVDAoleK^aZ6R02&GA)Sq zXG*STi3GZEwnooD1qoh(LO$P;>-!*qE}V7JGf+Wd#u0EXidcfi9f?)H6^);`i<$bkI4u3?$Hnv$A>yK1~c- z8Akb6C-tfD$wDVkL88m2FbaN`TrUF&bYTxi&p-u<8#%+N-tOcwkU$sqgY*m>Y0eL8 zS{#o$qk;skJ<&6eKvz0fA4(XO+{iX6NZ{HNJp&1J&2Q^NXNDw~feI41T1C%50$nEy z@T!ze$z`B|1g<^NGmt>n^G!UDb1u0IJj0LN3ZVfPlAfI$pY5n1kv4lMk6_#8E66nI35IqAGBo1#1rCMo{%RmBMjz%j+4M z0>37H>pF3zQ5au&W7 zB+&IVS2(Sjlw9u>6(n%ot)77dx;_;Qr?l&n%RmJQTz9KyAc3ys<-+OTcgba-f&{MA z)iaPl*R9Usl-V`8rwLS$z?Hgs1`_DX%-7@9GRa-Fs33uRb?6yLpv!T~fC>`0SBIW~ z1iG+Q(uwDvL&z;4sd7Nuv0zsymCE)Znb|%+P>{f#1@sIg&{a7_7&Tj)Tm~vg;LZYi z1`_DP7DFdcK?3(8a7>^J+ZCO_z6h>rb=)sO1qoc?s%Id9u6&35$QG1btpO@X;CfX( z0||7MjPWPWGs$J33)iSRCQv~FSD)&i3JG+z?Gr#77AIFZfC>`0URBRP0$qbn1d{*j z`7^RzqPMQY1z7~$oM_2sLVTlwva&A zA1^$q`C_%dkKchd;(J6cQG?(6iV6}~mtz>;6Pt+`??Pe$@7#g}x-M4nqLo=yMw;P` z#d+^yVjWjzqJjig3-OL8cj}6H?JI}^yjK_!=;|=li&vSd)ytb|)(|DzRuhAG)h{YY zVAYdh6uDPXWDlw%rt|NC1iJEBUgUgFt-?OvqP(bZuAZ30EALT30;{(SV|Yj@(IvkS z&v`czB+#|;nHN2usxlt@QCzsiH4@GEI!6TwtU@!4d7JZ#4i{U9vAp^W33M&+_NFIK zRC|>*O)fD#XIqiwm9vQo5?D=V7~@8#6NO)P5zD#09SL-OKj=*dJypiLnyL+KcWwSx=81eQSe=1Orz}jKM2p^Nm?DaNQ4CB=U zNTBP!?;!eUsf-5Q9=iS!87F4(of8!#a1@u@lBvU7zt6CVoV=3`66nfP*oRWCP#IS@ z?`SYPZM>*o$;Ctk3H|;NS!OoX%Nj5Gy?53Kbfu{4Lm&Uk*gxSQ72u4eADm58kih$u zVN_r3E7mtow5FDIF>!_$XJT7F_MoSQ)e6ubTRlYSmAB1`d?w<33GZ-Nd1x3`fTwu5 z>xQ|7*EFDl#F65j^r4R01H$89Z{c3yoVoL=PM`}b4-KQ*vjJk|xs&EnKHE`2qH#)3 z8huq|lvwC53bfm5dUH<(33OrQp3&Xipa5hmv;@b+Y zXLz78GTjOi&#V1mmFBf%_}k)dzI(3+RSQ)saueSNizZX&T0u;pf&|X18^-pdVdB#6 zG1dsaK9E4y#QWBwf&|X18^*;p(c;^&CYHCePM~Yacn@;z zrB>wr7#Abbo+xKkEzN5!K|uoN)eWO>syNYnehMp$uP7wYHF=B&y(+3Q9y-T~M%IVK zwoIUc1kS4)M$n-+v2o?e#BaO~5(#v@8ty?(N7bIPgRjPkF{chEc6jP+qJjj@s~bi` zUWN2|eo*3B{ymUDSLiSgiW;R>7CUoa_gVBM%Ec?gP(cFc)eWQm7n`^}*>GLTcV{Hf zHD{;?Z9l2@FS&ZjCa!#_>*~z=m!N_K&a3m;p1~%p(K}t8xDST}y3FakhUU52hviKF zI8mbYGuLN)4Wfbs*4c6&u5gT~agpE1enKbErC(7QOGk?im0OqtdCwYDkidFj!=W zqjBym;&sE0GLZMPL;_vAK6+F4_i8VTdZV(7t2f%ot-Jyh6(q0<(J;ugh8E-T1H?!%#i z1pfYp(cU&tOlf}HO2K0Qc*ki|#*^w=Nj(efeHg}!9-g9pj+<6#zRpoWqDDQeOWm=4?uU#D5=S^A!%daZ?lsO%_7(F zjzFj&f!9CptXiyx93GxZj^*cC@6uru=$UkmVkO608A|!St8=$Ro31kOYg)PfptFez z68|&9d%nFaQz4u5_){m)^>%b9P3xwv^K%v3%J+|QN@E8Tpdf)W$~>x;uDML@R7iH` zmKq6kc{B>8HOo}Sg1E+VWMDD*o$pboAc6DThOzB(U3si$1^JM#C?wFe?`a4bPHLZ` z1`}#X^IcV0fZGyOkihwR!?^dTqAc!LM^@rp(vU#c?u{YjS6^k6nq5xL3#%`Ec^5%c zkifbF!{`!SQg(hRWFFE9bVW`Mp)|czhWWJ^Z*A3BuC|;_RFJ^>3BxG*A+KCsww2uY zRwvMv-YJBpZ&w+8wq}!gLfgx0+*?8g39RrijBYE^$Xxro$)CGfA%U)J+k?sHxyo2` z$dHMY8Q_k+wWV~*SX6Nd>p7C zffZsrs`mPXHK*V}>A_DENTBQCfgq~mrZU70%i7w_SB@&x2KqZdU0FK?P@0n} zBZF8+`!mMNNne~zRFJ^+ScdU!*OUe#N4$K%?Jg4N@+uiXSC6QSG^@@w80Qo(_Z;WF z+dx4A*I;tn-fygHhtW3a#%CfD=&IG(pZ0B68FP1>cJ-EVvIg&@g9;M32GcOcyv=RS zXdf#_^9Upo=!(qhPwO_R41cE*X7q&^nVUx@P(cD$LGg}q^SYUB+@s{DqAnVNu0=b2 zDXf>u$kTC%+2d}wT+j0#s33u>pbVqk(cjH>ej&0Bj{zWou7N(j^cSyPO4{)~ciDwz zJ+EMSp9xfuz*SIuAKbRt9Q52@Zs)Td33MH==|lZUwYz1#|2C_o^Ofhh_lgPsvRf?|Fy>axwj!!)?fw9 z{Fz~ty{vlLe$VY;qtYwPW4yZg36V}OW|_lzw`nBMRd0V7JsqJ&4Jy13 zlWQl9Hpg=7g9;K@+hQ1H|BRHOw>`}1JPwBhx>8;XqZ1X>2+PBJQF2J}wq|7}P(cD~ zTlif?r($HIl_kvHe0?B+t{jiUsDB|fQuNe{l{3$!Hy81BjtUZ3+hQ1na@u6Uxb3dK z{F@_zF5eGf)GNK}g?C$LlUAny*H}KUP(cDK_V^yfZPkap6C3R1rwJs`<@Yg+9<@># z1$no(h7;!On!-I~RFL>t8>ea&dDI|xyllS4kAnD#9tm_Eeji4?`>BlBZ1J+dgSoVl zpFcDO|1MP18OERmHaUNMY+^_um;Z-Q6_kA*gwerD>J3Lnx5vrzxy~i7;yr6L1^%v9 z6=?LY9xLac&u2a79h8wkSI>K4w7aRwD8y$;-)$wVRXjh43KCe|Xc*7_jFJ-*I#~C) zrA7i>{da^>_y?7-(I-OYsU2-CPvv5wf&|uI8pgXKp|V-S8Nc?%MFL%eR)>j6ty$r0qJjig zuJef3U0=DU8CjEg?@uJqm^cd&#|Nu3ByRib4emd^R+UHz`xdd~MH< zrK@Pi_b4RLb!t`!jclrBGje|_FQco~6M_89i3$=}al>umw(63ORuiM@yJ!TuUbhaV z4JXu_XoAw$lbs4z5Px*y-Nisb0xJZ0W;AbOdE{0x(Y%^Ypet`eD2=G6<|anXYbsY9 zDJ)!hOdk~_utLx<@_cM18{EhvwsHm%=qh(Ol+xu>Bf`u4+ex<)IYc&oryeRuU`?T6 zguLq_^V-shMcgAp0$pkHhtVo0HL|^@Nl&?aQVMaNcY;O*39L`%eqyVB^4hFdW*6>R zB7v@_)x#(;R%Prs?T>+PB2bXPUKHP>dI!kkp&QM7eC{HFt_BmhO?;y=takx&bjfw*RwhtE z0((*VyBhJC6Dx$UB1tFkEWuwB|B_Cif>kzH4Wkn{8ik`q_^s;%{w=J4!EBvC1qrNe zaZI2KD^+v?zeTJg!)%>E1qrNlb4;KM?-DwJpBF1&Fk2^3K>}-A924lmN)?^J&x>~- z%+?81kih$jV**`xm(U4R@XmnQI)Mrj*ycMX(1ll;PT;qQbvc-=6R0486*rCvbYcCB zPN0GnFqo|qs30*%tCRW3sQ11ifiA36(KArNS`++BI)MrjSa;%>Ko?e#=maWQQ-aw# zfeI2>bLp5s7q;^{flsOUG>LN-I)SY-j=ei>sZl`!$Kmx1B+!MU>Ny&#cZ8G1qmFJbxfcOM_6?NM<#GQ!0{D@3KICFuV)~EE_`m+2^{Og8Gigm zbOIG5aPHnQfi9eh*9n~U#+nJ7iPZ_LVZrJY{7X843KCdFq7$fKRT%yyoj?T%tXp$T zpbP8dbOIHu(!*?>Km`e`BXmrl3(p0ez_AQGD{)jrCs0Ac@wtlxx^Q$y&p-tU9Hr6; zJV&vr!|{=$f&^B0=ov_$3x6k_!0P}jAh6=XF@aTqjx$g}0;~7*3?$HnwRk##3RctM zU(yLwkia@Q#{{~t#n1_S=EVCTo|XSYK#d0y_}uQ8Ko>r@>jWzJ6#xJCsgS@~4m|_^ z7P_!E_-Z>=Xl*wnI0Ojpn#Co-lJra$o)Cc$!`(edkOYUt-4yY zqFQ}mD~$7z7-?1lElA+pWaz2p3{^x3U z-nB%2*L*D!Xh9;eVlTevPHq>mO?a{+KSPYam)fsnbIv|E&xf*0&H42*&c6&(=59+~ zz}GyvJ~aYW=ueW6KnoI|=~SID7jynEcZCG1tk1DDeW)nC+w*@s$H%?V{Ks?W-vYpA zqFDeS(1OIYr%^mGhxvB_V&;2_pG88A?}4fj{af;H^RpV?BXt5TNQ__FoUi$o#r5P1 z>(hZPgw>F)vzI?@SAIh?;==;89=;o&RXLo15d)m8#krFl4ScEa@0JZfdl%rw_og63EfA2;JG+_DMh#SEb_EDQM^}%Y{vbbsTRc#dO5EzHHqQ_hC6?WRwsNrsx7M4 zO%$S?7HC0YeAP%E_uV8$`Cifr_;wbxXy*&6=3R^Abwiv!ti;l+54AVZ?L{c9jz)`x z7#hj1j&stIH15<(ZRX)Nq8`l^Au%3Qb-W_^#4{h_I79y0^k)Z_%@9PnK z-Zj(5fi~5|yYk*5lx7t1z2o=D`Xih_pJING`wglJhrPPUNV5QFL88KvaQ>pO`OO_K zyu_a;?cyZOh9iNhu%QvWS9#M%SXgm!Xm(xUNxPTPg2b?b5&YD4^T`W*&LeKF4HCzw zBqD(->yyXM%_BVD1c?Sz!=VL?xT=*X7~jdTt*Jfhv6KlGLl9A6Mz` zxQ(Tfh-LKkvu6CpTxZl`nUeRDV_y@?m^>FuHgi3uy4@ntTW_FDcj!|`QUyy#DB zqmV#VnqtlPlq_c1-QxG%@xEZ3=udm9(Sk%6kLERZJMWOz2?@a7jJrMj`FeMGR;9EfvVhpNAaFbO&_bX z&CrV8?=KWuhl~~^F#c&zL&EP`aH)Qx5zX)-fvQvOqIk_ArjJ~6HfXi_^bvp1z6rD- zfi;FC?OYrwYLCny66p(KJ%}~xgPmbK>w+AvsI9-UnRvA#t=LLy)zE^(p6X3`y<0h4 z^{#h^)*{oRcUt2;RsvOLM}+Z#uS_3LinJ9KroPZVtKJG)knneF%7d!rbon^9vy*7t z<%(8^z6TPh%HtEpXRb3_&XM)Ii7bgnwV9u3?<-i4c(ON)Ke%rCsI#TFP&aSZPF}YX zs9Ge2@#@7qUGHk2h!jWaXJGnY+bnmzDUbi??3au^9mdCX%4evS)NIP9zs>7jqML<Eqw69YoBU+sZjV z9|bK)JgpkW`!~$%dXCl0yNSz1jwmzeu8=_0&W&Nb^BZShOOh%L?JhbMIjCf%^*(4p z;z02*eyxn@!*RE#@F<_C457a`g#@a8pBu(^?=pR48`@ip`+JM>gW>}%Nc_wY#-}~Z z<9ZI|N?#Gwb)|CfvXwwp!lW=BJk9iRQtKx+eO#i9Ap$K(9RAvbciLn6IG2B*;M0Cp z=F(amBv7@aOBnaaX!>X!6f0Jr>8?B_0xd`!ztDu2_cDF({zHT)Qb&o^O9}iIs-oJ5 z@iOmnyUJDB9Ye&OJF;?u2(%y}PB-DrJWLEn0$%cNNghuVu0 zffgkC>~6yMd6_;6Wg9MjuH9@)pf897s?IbD<9_K)ANOhH*|hrYYy*fu3li6NHQ}q= zOds0|(R#SV!Ey+db|g@Bg`T7K$6T)OQHlD9m)ig8_m#c}T97zI&++p^E?3$8huYch z7qU98(9SRwwKv>;)v+XrWk5$!50*6vapWg(yi7`K4Fc~#R#+7f-mqIn6LeqIJz@OQB-k)&V$ zs3G2;s4S|{+YOu(#A{Y9XuOk;y@UAZ*3Ro~X@j`e=K`)$(!IJYs$MHA9@E-dv>=gf zTO;lfTF^xV-mEP$v@9t)P}HIYiAS3o@p`O~>wEY&Z72fP7ZSNBH$Vba4Qn>ywH}#1 zZib%XM`*QrJz7=lJ*WwPGQin-VXKDiqa^*KG!LWVBo!)r9YL%WvEX{*okJ zt+d8*BOqQ(+i3NH#QN4vc#OM~mZXh4xnoS)c+q30l|a?`JWY6!A!b|ac{sB+Z|5)( z^@;Wmf(41|ts3)ORZSlYu2m6Yb#-z5z4Z&?w@G>u#DCl<;Cj2$XI2mo_xOs;wAL9d zNchbU;w?Ly-(0#~Lc}+$BWh8<1PN5RH4Nr^7nwd1`zn}c9b)=ecI=*Z|51C9@vD_U z)u=}y+7o3*{@{nk6x`&JwNEKmEir+KGe&s&Zv-%!}DgADw&5(Bdxj z7r)XjQ?wvaGclCcP)#3)ePgskR|kpq6tzg8%39jTJn5`$o)9Y*)0hlekmzY|%uBB{ zef%5bqdh7yRIK=DB~XQtMtkD677*F52C$*Dy6x%yV7~ElX(Mv(_YCF@`+FI++NV1~ zynL|p|7oXQwIX6~z6Oj_MvoRG&P)yBuMU=W)rkk!l@!O9)n>J6Ul9_h8o4xxSIKDl z$kMO0SV89$jiE6Bv>;JW4&u89n?8Cys4PxQufdksd@Ka2I;?BNZx<@%su?C+t0_KB zs>IsT8Cz&U;;5|=Pa0dw^&IubGO^)9DRz}=Q6x}RZ+;_Q+RgM4)TXwGdtZ{hB?2u- zv?|?*|JK3uk+EY#k#SZbwwM0KIufWVQ?3!8)~}@NIX0FJ7FiqQVOeMoFItfB*&4`K z94P5}4&SJ7@#1S{)|yHQ5~#}kiii@XkEQz}MdsQWSSE^dv>-8TU?Bgkzv*Mnz!pL+ z{8QOVy(J`2b@Ess55H8x^&E)_t;B|*AC)Gwh8`_QObZC)D+`%Ea(wO}I*z`jw5NS{ zNT7<34dj!9Odsx!E~3HwGs;rhqlgwHI(-e`^CpyVy{q}BdWbPgx$-Bir$z!*AL0Ue z=9;FDiP1ephF5!)hZG-ZLE`4C0A8k-=_BrQFX206yYllt1gZx14CKQzn?5rC(_2(i z|4{y=h(ZezOYQ{lw)IRO*H^`eNsSjMz3GGvBv3W7Q6PUat+?xZy+%5jA@+}ud z6j+ehus47&*izi}u8IyBEM|B`Dx7*tNTBMXZy+BQYWi>s7$SW7)>kANvqTFL9o7f% znte?l%Nq<63l`>8Hq$s95~w;+DUjd2QOxxmh5X_~_rCA#WobP%T9A0QIDk)lR?PJr zWk=)?o@S+8YU9$qX=M>XNWKP;`SZunj z5PfqbP*s9_{NB;@@i6ajar3<0Ht=6>1uaNaBOi@>nLf7VA1?UteEfH6KafCGy|RIP zeI?UJC)#KEy2mcQgGLR|f`rHX0A8!C>0^HDcyaL1BFD;dRA0ewp=w$6K;CO+QP=nQ zZ9tr`r+Mh8Oe_1*f<)xX0KQ{nQP=nA^jJ3PXZpCZYp~d(G|^VttputrcL?NnP8D%Ihi%j#QEhju=0Q)679{Td z9l+U|BChAyGN`}!BjapsD`hN5pvtd%AfL0t^wBa)e{o)$t0|P%q6LYZ{{-+!lT9Dt zzI{d3Gzr>d>hB_fDz-Y1FYq#b1Z?glM4CS}cY0T7L84xvK<@LruJ z6U(ytC}=@q*zG_bF|d&9UDNuRobAIt752{B?`_5l z)voOFfdpERc+0`*(5Vrd-=bSKFkf`b20`3Y4v>@>~ zZ%f|!Kn2%brADAipSxYUrh@Cqkw6O)ArD$|-xVe?hkG)&w4ug)En1M!f9cb*|BXNk z5@X{U^BV)qULX2E0#(h=HReUXnmw7$RR*&RHCt#6et0YY)ClIktIis^WQAbfWP$U# zyCaw{9%2W9$jEKt05$HjHi!3+~jhzU<^opaDR z!eBunTft!dV4~?`?c#Xm7eB(jghmIEK-FXVrHj2xAECA4*`xRC?cvmKM+*{H>0SBS zO&>=}#-M=7hOi;? z8!B0;pNIsi-W?6*b&i<4;l-zgtN3lhZ+1@jXN&AOy*Lpr&&*;LJ=hL43n)t0DW-nqP)8{D4X zmz_ViN}EdkM6@7L=y5Qwoz2V*GCb*l1&R5ULb%s-)5nr# zjoH`BImD;8RsvODz6bL?0cOs5{8a#3JiUN;n%PG|3lbUQLpc9n`nXiE4m+88{RcWnxO!nW@^%ApmI$;UVeMs9 zosnG(U`<$2`X2l5M)B;qopr{5=~4W_G-r=Bceg0$y(TTmEN09PH%14MK-KqSkvvmx z=j@3j{avgc8?d|>n_1aM!CD4upKldH!N*i@nR#3-%lg;!QP6_K_>&>L$xqWqdf~(J z9`|PBXnYq5R8{Z|(2hw zb50;owXAgn&)&%NQDo%_?eeOw>@JmEv>e zNL1L`nA@A0K0c3ppo|{Yp6#N(C=#fem!~oJOk;kJ$LxcW?Pn|IPG1l$NIYuanEy4} z^s%~y8{1#C8Jj?*9SKxDy&B3VlrVkRrOa&7w{R9k<8Wv}!urjtX35D0)N0H!Y_<}p z`ZO<;x1}fd{dB-aC##mp%hZWM%tqx3El6M)qxB4TXK~oe3 zYa4a7z)D*&Iw|lf(FGZ}XdXeZ0fo zqi{USM?FilAd%E8j2Av>`WQUUUAgmg82g*XsgXccSb;D;qQ2>)$n>I$`gtguL@P7V zg2XcKFy8xu>7z!MI?AX%Ls(uaB}ky^@x~^+U^CN4|7AUt=}Ih{Pcyt|K?0*$l6-x~ zD{esp*(b`pkU*6l!GUc}AL%krQ)YV)U_+15Ur_=J5*W>rbo!ttoxK}k>;=d)vpsLL z$2mt=aC>{caDsCd5qoM@0xd}Bqg3D8n7JDIKmt|RXOyImH$zzbbLZ$F-c{vV9r^9< z&MXD}SqZctk&vzvKi<&n=?|pQ$8}$wJ4VogMCHKN(6dAWEl6zljpnV+JJ*p?pBj81 zfhzqid>&xdB}kwJ3IAEqyhtl^j{fHK5VkKWmnc`)M`UMLr;pvP;*`Z$b#Xzdt(L3JN@Lo||?rW|W zjnC%A#?MqlIL+6h1&IakB6-3wbKUFOhn3mPIW@!}>h&Rks?tTGc%wq5kB;+w*sizU z;uNjqKnoH(={atWF?}R;^Jl}7%893xt093Z>ywWuUYiZASxStr?xUauiJj#m`Htu2 z+s$yjA^YuBL9vL=bg~ej!naQ6!_|&t9n)oGIp~}_fA2_MZGv-c_T%-Dyy^|-s_V%~ z5&Ts>bFFiRel3_!$)8F_fBI`4U_qjE^+-NzvALdl@b}1ks+W|TfmQ-l!}>>XzlWxeFK4>3p2ZF; zy=wa?XhEXDw+KGAkhym7ewE(rb(3vMda6Z{Kvkno5nQA**Y*82tPjgmXM^&9#+J~6 zMDZsP{91j}$LPZS*?0fB%3^wQBv6&HVFYi`-}Ldz?19WJ?^vYz3?zr|4Kn6 zl4jhIKvi^=2)@Y8Traw#SseSE@ZA1{o*XSmtUM6GTVyxai}sov&%6pvw8v2Y3JFvV zEf>MJ)iixPz7o&2%&%czLvs^oL87W7g72wk`UopHob7G?Wp5Gs=18E*yF9(!k*1Hr zd4{tRjhgcVlzE{AiQMF)U<=cS_IErRzt8T7ru-ZURQ*{gg1=m7`Z%>Mo^=T7=J-i} zbpb6%Y~LTjA5AlTT&ohtmYx3Sm`Z2kB7v%5wg}!Xv$@teuI4cIzG8muD~%4K1&MA) zB6zw}rjK-g4Q7cQ8*3YAeF+k%+CgPEypri7L;k_c_kK&QI?b4%1&KzNBKZA`=6dR= z^aGf0q3K#-jCon>zO{Ty7gvfYj4+1 z&`bjosHzql!I$qfeZ)QM$@0G2t=*&VffgkEe?;)|v?AU)k5jCA7xwn;IjscE;~;^m zU)M(POtiA!*{60(>c}<^xUM}Q0xd}FDG$@7J0K#UNUc__szRzxK-X(I!VT7BtRH>}h5tP=!4MItlt|IJ@nUSrqAD?K2>8 zzh5Lj)zs_(WcO~&&SlIgy8ow_fhz1jNRqu)A8kgaSmsCT!rx7A$?N8I?#Qdwt0lj? z+PR-^#sHeH&1UY@JN>$z){*|o(T$uw3R;lZu&o6jINsb1xUuj8?c1gpHi+``v`t&_ zj#19v(tA#&PC8ZSTauaw{;HiWHIT(oza1?|Ebh~i2dy!EZ1)(bz1uv9-KH!R2~^=7 z(hktbY$E?(VXQmlIP>l8_{ho5_B_L*w!CawXNz3+dK=z)sdG;(o$9zfv+$V|&Pq}q zg%%_poovH%);0HFJ=l{*bgs~xHGgF#Q01N2nm>_DAIHXi(rUJ9#e!%i4lPLB?%$eU z9_QShD@jA<-_QyV>d1OiuMY`SjojFZHy>brLC;y|w1OdB*m+u)ffghVPjAJ~q&Iym z?ZmbDS9`Gj^!HehKox#jNlJ*_rB$ufixsEr4lPJDD%y%~ziocO^zQ4lJ-7R?Q#9^_ z1gh}+)8Au}8?YDYi?F8T1N&6iJB!H^#l72@-=o8iI_z=U66_EWXh9;)+DLxooB2H+ zeDGtpYn5kBsEtAbRUXk%{96vw$CRu!SdEw}>>`aoq6LYNmyvwcTGPj!!WG%CwR~AS z8dXCARYw-nKFBNP_qbiSEc@e@%=EvagsLBYQ9QDn^LMR8#JXZ^XW@G6EkzVskVse* z#p~rY?`ny?0Gn7PkU8kdkw8`3e9`<`fAg+t^~}k-ya{D%X#N8&NL;=d#fLmGOX3@E z4_2p282d@8Fh>#ufY*-H8-XhGusm}b1N!z3ETBq|fm^<;Bs+aam0N+O z%FR9fSS0qm`5A2C~9l zJ{AI1gM6EFiN1%kJ#RO^g(7A;8Bdfl84{MYocx?lCA@Iu2`LFz3bfvTd7TJU1SOdpe8k~z~{uJj(pz7(k7W`52a~wO?(Gk5Xo)y&h0)PdH zUa{1kCqKur;kz6K^2W36l+h!BDr*m5{$Ix(XD-CC3iLhDg2ajaE%<}v@A0#CK`pH0 zFt&@93Qt0jq<61! zmoHi)x+4AE8-}AQI2wg}v#bQ3`+?`B;K>430xd}3xh7Tu=WcMWDD}I-Ia*wig1g$uBNmS_(t)2r2ZUeK>~YfRv$>93g4lXKnoJs?@FCO751X61bz?v1~?{bCD4Kd zma)_cRN*MDmB3vPxGo1*!&nI{OE}MocW5Qhf&|XQrcR&==ZCF?rS!o{u+&Q;T5ydQ zt|_znKmt{`+Sp2<1qoammpXweTs3Vau*6~i8q2hmKnoI>U!_i<%34!norvpcag8vp zZL#`53lg~QIduY6xZ=i2palus$Cf&QDqJ~aCD4Kd?tDv~KozclvJz-P0{5|{PM``` za#;zqAc6bXQYTP_YuKy=T9CkfY^f8d!j*Ma0xd}3KDN{eRHa@gq6G=u$7c0`1gfw; zwh|a?*jvJAwi0MT0()nv6R5&7i>w4%kicGM>IAB=?`tK{g1vC`Z6(lx1m+2;6R5(I zl&l0=kidK=bplm*l9H7`3lf;OrB0v;mEC(KnoIh=3(jts&M4iN}vS^Ja;m60#&KkyJ$fI&(E~_Kmt`* z=UWM^Uvd35*5FnGElA)xxzq_%;i)=S0#&#+E_DJeNZ_hBs}Celh3D{C3A7-AtKL#4 zP=%}BtOTAwgXg~B`b#T;79{XQm(&SV;i^z8ffgk2M3>YFRN?AYD}fdy@C=yL2~^>_ zUMqnXB=F0oPN2%VJ`po|v>=iCH^*EC&(6ScChJ|H1qnRkB6R{)xR1?Bpals$<05qe zRk%CXN}vUaiQ}B7T74jaDm+or zN}vS^T(Oxtfhs)b(n_EO30$#hC9syk+6T}6wGwDS0$0|hPM`|UFt!qCK>}CSrB0v< zPj9voxSAVRd1LR~N}vS^T!)@IfhwHGwG!A4;yJn4!dVHlAb}^~rcR&=*Q#0xv><^e z;HFNX3fJ6P3A7-AC*Y<|pbFOxTM4uvfhXXmPM|9Fh(e2nu$-ogwGR?_PA*2X^{%jl zaYZKeQ6=ZN&}u(q2RAR&rE2 zdv#Crh%MZ_&ar0(kIP-z;W^&Fmj3@%0xka=F>B*YBI-?*M9ofZ*thAW67J@r-x}R@ zul`%+_3aHall?h;AYuM)YJ`4=&cCRmui~J;q?9nD%q=zZ<<+*`OjV2450Lfi4L36y z|JJW{yOq$DrUi*M>t-AOza-$>e+cxUTXkAjBW?A879{A-xK5M(KR%E^)!mrv29dql z@g%E{W*dvIblyo$8(IDJYf{_5pKK-2f&}_boj?`b;eUMKTSS7cjrXRLRv&0Vf__QX zpNa1JKR%E^6@6KQpzrk`0xh~#|6Tq6@Rw4*DFpZV`nQL7^`E;!0#)=22CaWps}HmwL4FKE|Eg93El9xI{m)$?fhw$zC8_=FQKGk~ zQmXU)K6d^6+)G$u#5TTN{aXKjukeEuwJu^c5e~E<0dJb3wr%~9qL0{0#B&RQD)3Fj z;DW=%#vYZ|9Lv*NLkkk{1t~se*<-~4w-#$k-JWA1P^Dk%&!N9RNqU;Im*{?C{+etD zk85Z_0^T7J6%Te6_l|5>lX&)lg+P^lt^3eRjwC(2A0^IRII||*hO7cDNI+R2qFq#| zsQ2K`nk#qnTL@I?*SZhA+(}YVUw?7taGHcJ8>*Dpf@7xwP^C&Rm``G1giAwldP{sM4=>A5MZ|kC`e=m42=Ja1s=I%xrPcf&@j9 z;ltS%rPyQC4pJM{$AJW@^lRP6ku`ao?VwJS(pyfnAOZfUU*fteBA#0aRDo|IsMgV+ zytE#RXh8zrn{2d$`r9o{HJyb(6}&?t^e;&5U}-%T(SihgeNT8~{+7{#1k{f;*ai|Ua?t(un} zi%6hKzt(-|QKtJaT26yN3lj88X8z&4E4_6#?g|N1>DMXG;pzbxPmUHO=#8kZc949y zdKt#sMFLg&b;|e9`=Hbg8eb4CNYIxxd?c3=y|-kP5+qQiU+X@cgsVqplti>3K_%4i zp+`e%VVDuC&8NY`+yQvQ5k(mT!r6$n?wGwG+R^{IyKVeb)leNRp20SB zYoecihl}>6w^c8d=;tIt)RAIE_RaRZGou|7@20n%%Q3Qsu9{LNz3pM&$woa@V1GK> zyL6M2oJ3fYA>zxgW0ac{qa7vAy4wc$tA;8hJdN!@&!VbMPkSlZj=wIVI*Igax{Hb5 z{#Krkj&?Nf^<5s<)7MZ1Pkt?ToH@|AzIOJN-1XuB7csC*gy>&12dfho?b!0`V|nk1 z35Kd%{8hQ+)fL8dzKd7nCT&-^2oYCHj7aCht__TKRG)HMULCO6P_?R{%HJ9tG_LzD zO_FcyJm4ZG^~ozT?P|=D`b0bS2W^(ejXZ6r3J?2DUR?OLaXld2Z}QOow_L=?mv^-5 zQC--LZqbfEk4=yd^nGlo)?8{UCl3E$T*p^zE05gw-bGyMJWH!YXSX%#811li_LYYR zd^c1tn`V>`-A!vm(&fh)H zns1lBhYH_AP5B-_JUTMpqc4=9%=m(;`332ltMJX$ly9E7@Ibbr!g8gh%_t?RSxTr} zaVS?jrCixFjbNXzS$68+s($-WrB8r<4MKQ=B26;*heq?>w!ESrCWj;pKs%F$uoU0J$YD%2%ebbU{ z`r;<8RW)h`)vOt)E>WQ_QB&%YFFRX1-d!9lzP}i+9oV+hKX9*`P1?PJYD-D#k&rI= zdgqn&HfOn7e*L9wYJYEgi?yS~wDZ%|xu55%-WmU}Etu9t9e;L%as4twfAv%29qNn= zo9LHTd*`^zGZreZ5P$50*$vm}P`z0=7j(0_Sv0XoGx{u-RiE6g#z6OEx zfQ*~f4{t`fh*oxHpLuzoK^*yVP#x#_DoMX9q@{}c)M`iTxCr%Vh<(nrID^<9dP3db zAj}|;Zg}*Rx-|E=$XzyYi~6-_?*KCsnQTR6pGZ(iw+cRM&57=^~bYiLwvt zms8b=Y;BIJKlc9NuMccSLZsBp^By!xsqSj38Xi7Jg=&4 zcKJJrrb!L$A9ww35N#)IQ5QUqHVC8}?>M5?8&O<#66@R5v=5$t+aRK@FH-aOoM;e8 z+v+8%yEk`m5x4&;ZXYo!n?t{=iU&ulMTY)v5J-=nu~N-mb%u+`J}tey+^Sy;qTka1 z_0N|(3(NY|iQ_7khe14$ZyEws?St?AGFz+$wOR zEmNn$a=s=v+5aao{WU=Z$qXkKpe~WqsbNyX19rR~Kq@aXjjtQzmW`L`3J&UY|Isv>4Z2 zpaqFq8*<2X?){@aQuQymvu9QZ*A;l8_P@K{c6vl+Ia~S%>VqX4^zR|3d=HUWQyX;qyE1Wh3xO6S)>OzQ z|8eQIdNz-KSF@EUZD{5aY)}#to&3M}tDRn{*KV$}wZ5EIzBB8Y+Gf&v+obeO>Ysd_R|FNsUeRnf*D3uGQk@{3AtY2^d!KdbhD z1e+u1p#LrJ?`oa;3AX9!PWjK6`Bh!FE`f;aPkpp?OB=AO!wL(u%x`?jzlHQg9hZKs z4Sz|JGB|2#P39`B^6t_WA4vQ){e}M@_1~#8eDsp|>6x!K>WVLG@~OOqKvi1pg@1j& zck12hIrw7fx{)waG~GyIq5Nz3yOT5apH$6bDL?T4Bp z?`k3roGGPs@@UQe9r8&-3lhE4ul3KdOXATr))29Ecty?Aqd62b%2sq|dU-%p8t!cE zg5?GFN0EJ4Z9lGEds!hVx2HSbTVs`N@7g>`TN=3Y&pB7wq~-c*ciFs>?y4xOZMPlm$71$uw-Bhx(!J5%N^jixrbRkYtKDPX z@YfjjEGfCZ;(C46X<7x}(|ObJTBAtSyoP_uT_x`KbY!d(!){;Ns{2T`AW=EGk>5M= zk=^i7c}IQ6&|Uplnan#Z1gidg%l)Ji?)>^L{jSzT^mY_2*^lLIyHi6;>(D2DuU5G8 z#ee_zu6EX+;E?O|Wjz|~vG_ou=GZ*`BkH>I_+0d+rEx75I{wPlhxO>W#D|&^AM1b3udGnovsq7`=<$(kL1Ml-B5BgL zw0tT>8r6wU>nT+ibY|N&oV5_BqSCIWl=epjYATBsG8Q?zlqeGLA}MRjcWOfAb+%87 z&n0bt{zct)E$19ta3ylfvT!?PbDS%{#9MH_P<1<=T(%_7Xn%C zsYVT#{98y2=zK6~Mz!ziI;!m?>2i?(#c?c*Jsh7!uYHmURN)(ur0u)uET=<}>>R;OT5T1y=FK!yMi)uNpt2kF^z>l6@Dj4DmSr;@_I&jcK(E)z&1SQ z-P@!id*7%7hyS-d@AFp`rLkXS7Sy7qz?L3~KYd>&{geBhI?w0<)NW-{I)(W%)}(@k zKo!0bNm}vRSGl~)m-Q=B!Sb$Y-sO?6a^#aQ+i}sT+mqies<13b z(&T^pD0v6xVRyX(^p-QZk3;>dnjwysI|U+reZD5+c-H-PZJ} z+G(%e4(5r8PNYmaZM#|r2@fF65lD1D!OQT`a#(n6pLdxMgctLiB` z-#cEZ^(0ng?VU@_6meP|m$1opvbCog`~HI3v&JSH^}AHF-z7P|CgPYavjDZ$y&jEzO{G*|=57mc6g#T_Hhz zZI$}ks@~V8zk{_lmvXb)VdX%+9u@*s_}(Nbw%<0}wX*f>dTxL@;KZwC)k}wxR6Tp4 zKB}71dqn~*NQ@nqQ%zVV44VE*<;C;1`IlqtH;0bW`@6}%g(}Zdp6VLufI2SSAM_mV zZeI2m^N-nsri~P6Vd-+I8!8=DXWlgW)XBdjNw&n+_N{%gD3k3*pE}us1aFc{ZB_HQ znnb;GNn#Jy*+qOkA3plr0(O# z;jQ+rb6e5hEFNYdP=)19k{+MzXUkQkl;h2zQNs0pjLZwOFv<;7$_->^ZZNQOX?x4O zTOB#CjTC4>qW#mR>ifH@D_8qiy}SLx`*hl{jw37tswfvxDSMIi?1jp%n`)nXZoKxU z_+TLw%B7ySos~O{-(-vP$g3V{aY5E|5z0SQ%0Fah{xLq_sD0L)nOexeK>{sEQ1+ry z_9E-qizL0xmr0pa{e+fpaCbqOqH1P}lz*s{vB-MHLYak1`G@SxKYl$eDT6vBX(6?H zTL@I4KS`>Q{+6A!TCELm>o3rP1Z6BLWh}BYW9f4AjD5*J^R=$s2U-YJS)XI#l1j?` zwwcAL58--_qf(9|yK)?ravWLDaVW1@X@tG)(QYnv;oq1HtX2HsiECogXEDZ%(kQf+K zMlJaEne5EA`^>Jbp7exp2N79L-X>58HN7+^qWm~eIZBfRWL>a5BXRMNRsas|xp+*~#*7ixG zj4p|CK%1TeQm&Rn8J$hf=kP=$9$;|xC>oPZN*R-VS;=89v#O7HH)M}KTAOS^f-7xmBYW8$Vxp|_!DBJ0og+LXSH%ajgmP+-poKjP3zctjZwh9n~)cktAn`}XX zvPpl+Qe|hBDlMz8{c$8rh<#Zs1gh})B&o@y{MwXnb)u)x#SG&tep8*qn9b0y-cdFN*r)h zc1+O*`NirzvSbSql!eKZx5;|mCP|H+pK}J}!!ovjh)n)3@%X*IQ`Dsr_p>%8mKUk$uKUffghv(~~JTl=a+DlI}g}?fBR^leV??2n&HK z%G+eh2W4kINON9}a;`Zqni-SLc{Q5zN`4D8=Ow4id7Vwu&#~pqHizGmkpeA9;N8-= z=(d}VNe8NHnPTEB1gfy~&|fRazRyvjhh6jT7iTFYNLZia)axCzR-(SvMzIp8!ZIyM zG(YGt=LcyPQ8wow@h#B&pqw&47`t(1!f0FS9kw8_+ zL38Cw%XhoJ;HWSCH1F{nj4y~5B=E~hQmg9|wZe6;7+(+xRFxjtN4`Akf@|J6L)re? zdj3V5^KZ033ljKcDHF~ySbH@yx9C$Xz(Sx3+h9rh_e_vh=30I+`e#E+>x=}>j7!ph zDNMWLUP#!|SqW5OUqX^-t%1W_Yd|X!WOF?OmKa)VAlFM?Yw&o6=2%yzwoyvZf&`WY zNgCGLPrI4sj6<*CkU&+gBSQ8p-`iD65(+lcp2ZX}N(ow!z_K7o!wb#S2IcN-loBLR z^~HOeT*q^XtCVzmJV$e!oMV&{v><_Hf!@`ijoQsBno&xSKvl?xh4ShchpUvluC-E2 z*mu_`C1^ncOOGUZ$8FO3WXNcg5+qP{plGZ-uJbk5=tszsdD@XQ1x4(5MW6)*EN~I%ihI*N?Io)r>v8Ck?o|z@!>Pq+gh|Bf#r?rt15xog7(vm zl86MVmVZ7g`@SjTDv3E?_tCr$K5*zQ4qA}F@4(iw|~{ z#6?RsXrX(k&Y~6vEl6N_qgl(+N3{=YmK!Az2~@cq*)2D?vBFgnr}_S+ZBY(sv#Gv9 z3ldn~B&o#rOPX)_mzrK*A%UuAx0cBjCmeK@M2`uFHOZF6D2Zr60!yeQeSLIX%d@n& zQ4*0r)xcHpa(TZyu5q~6(q?VP9Uo!qSwf%%32WI+duEOHDnmn2S7fmes46wIid;49 zlk8m2FzsusCZCTK5uuVm3li3Ru;QO#+U(1nMB@3g8WO0ojv8zZ%dV}+-A$})bJj8j zfP^&@E;ICpWAMXnVrir?CX>9b4^=cvo;)fdNi71W*t5I$7c~lO&}a3NN29ExLpaV* z;Qej;xn;4&+Cdy=K%!RI?xZr0++Ax2KgeC|Q$Gw7pTj>n9KL#rqVnapl#4G|WNYGnXQ@-H3pP@?0LCr+ZCX$6f z6}{=Cl(CFsCC4cjTDCX7AX<>@$DC9!I*B(|;`7#Ckq$#9}8ySnC#MrA2^6#}lfuoAO+<>KK%Okb0V1gh|EX{>MJ4O@B&+#9^-+VsmA%BT-m@6}B{ibZL{=~L~ zR%Xg6D>KV%`P(u3pXNsUffgjNm5`*Yb((6mT4y)f4QMWE1gdh!jFz)LdEjb4K9W@0zBA4s5zY6&@|_F4aMyjEve7o+w;3ldagB)1Zhv{`AR`M--XY9Ay} zMRkdPO5MKe>utx|V?%`=gJ?lQZzWRdcG{1lnEP>P-;HYSySejpoNDgJp?x~4xlc!u zvR(g6nKZAb*mCxgzJn*(f;Alek|gDvwO?ubxU0}>IJ6*vHL4_eZoZ;Cuhmw3quK`v zRP}5%R-NDCv8!&+_H>VOFtD|FPIWt4kieEfl0M`#@?%bpl ztrcRHl4J`K*uv3T=RRDC-d@`%iTGQnqB5qY^p+;qTdaI7QcK9r-cqu~LRjWf-;`RX zoLE%eh$#Fm>ggxXxKdwBP02s{W%^ZFJ)wx1e|c&IoX6! zi=qVy8dXhR+d$`dZ78W+e7f4`=_7$E8Z}Z=MuY<<-nUPAIYHYQWQ+(WTaduD6toNb z_w)8%jaz7&jtteu`jQD$(YPP1k>t>9LCKIT#uKl20bj;jEN4w=zbGIDrqEpRXbYXcWs^;!GNuqI4yE!h3 zt59g`{4G>r9YcS!`05vB>(5F?4Tlyastia_H$6P* zYHPK+FO*}4{Eb`<2~=TSN&B{EWn{&6*o~SREl3o2x=tPc;f$*_7~V=^{YEr0S_33d zg>^pFK2bSX{O&;UgIXN4Ac1isNjG|=XOH9vqo%b$uf;v0M$J#h8_Txps5j0QVBnh;Z`mBaC@TTB{ULWccc=<$cgm<4kU$m2yd>59`+?%|=C;ubM+*|vb5>J& z;U_ykR2uMaMlT!*RAJ21saz{Fuz%drnWH$#wG0xqH|$r3^xx>}g&#~x$MSvfG-?L? zEmUF5OVZNx1=zxnyk;*vxt2lV^7g;fdOtS1YKHt@bF=qvN*Vnt{4G>r%uCYD^}n!s z_evSPaI_#%Z0%9?)^FQfHABf+#aZ=-RgGRa5~#wMr#D;d3Tv><_TBS}Xp zm1Rfb{EV6b2~=UsOVZSI6Abe(Oi+; zoGYRkzT_Q;G(w-e%Mjy{)`j1yqGY-F+{m5Lf&`6tswuMocmHgvOw)=RQHunsFdk`7 z+?xf;sXL90s6`7Bl(DKQW3N3LtWkFVGSY}zBv6I%NI7T7d1c*`Sw_^N1qsS`)s);h zapyIq`;Lu9)FOc@j7LctQ{SCUzPZ~RdrhtZkO=v4Q9XHJoGW+k{vbU&TkgCOwfI}8 z!g!RVq_Txst=3mGeHH*MNYvVLO;zembVcomHHF!rk?%A;n?M3p7>~4@!>=l5TRqElBiRa!=h_dYUV0 zgMYEHioUsws6_%*7>|;)@Ldr5R4$v*o}&c`I?(}kVHYdZfUWOTP<*B=6$w;fJW3LO z5ymzT%_;uAddYznByiU^?Ir6K#Pa-7SX??BZ6Q!a=T9WJ+BE+$L$jN6cepp0W;2p^ z6JtC|Qp1=!N|%pYjHpEm5;V@Frp%a>`=^JJ{@Z(F#0v>jVLVFGo;qult9SDoQHvHN zXp~A#8S!e~F;Ut3sjd;VNT3SiQIdKe{8wo;KiY^|v>*}o{Em8Wb`95v*S^m0mHvgt z8BvP_sxTg@hkPz4QzlI`N4%1203&eWCKAR6()-$E6}Bkch7 zsmMZxtT3V$El7lQc&R3KsO^f{#aXMc!Wp@y&zK;ADvU>(U20jERT;WV(`QW3g2d)F z@6_R)>bs(LTi$wX^}pvdeZ&h1RAD^QY#)zcf2TdH?V%Abv>-9s{ge7vIGtBxjJKZ* z4`-K_+|~5)b|g@R@hC~Z-EYSpZak;yqt0kSf=*R|(-tnbZp|_!KG*c9MFLeAkJPG- z>&m*8x}xb(ixwpCbO+iolBXjZ_{R&a>%nLXfhsx!Ci$cXNuqg9yE)H^X8_O`a`LGG z7>~5GI3`qSQ8L_ z9;mxd{^jr7O}^9jFXd9@v_{k-fhvqgNxD1pgW_2(oe{NYL83^y7iycTr~I9J^$(|Y zXGh0WF=pJ6Ko!QLB>7Y<#FqS4)`(iPAdzF^d$r?{zx|#24JP}PWVL2CH=-5^RAD^Q zZl{1+%>QwK5w&PRBG&txYU_U0-?`slQZF0(+H|Uf%F`&U5~74`)AKPcxzx2~=S`(riZW4ovbMVni)kkQkkimJh0Z$KM&X%?5O2 zF?APe`ba7gsKR)Zq#d35GWGLVBWlrt1f6UIr>blU=)*kD{;uhBkVv2k74*OYzH76Mgt4pZ`pF0|rz%inf$b_vh=z|%o69%&qI zQiO7}#VoF`lR*m-cDFlf(94B>&e^4_>R4rwlHZ70Bv6I%NVSjOZe_~&bmr_*at(k) z=$I$!%Z|VMIiq$_$5YDTg@YaX>ID2PRAD?y(%AYxlwK>CV-c-~LkkjL>%CQdnxnmvr>IAePkv;cUb@|$je$J>};8u>EUUbNO;|r__``v{hU#Iu5EqxX4M;q-qs?4DvU=-a*K~* zzw}${(0j;eK_Yaf8|N2y_&K9??xU7${q+n+)FOc@j7Le@_Ir26N9}g#vrA|}V!?!T z{N|Wle$J?^;?bLR&YsJNS|m_~@kr-0WEjjIWIy20+gh|BL8pts=}B(whA_Vs1)Wg~ zbq1<19%%(#^AW7e-$xyK)S?9mJgtdFSh9>@BbMaUS~#LD1ghvPwB(bUsGnHtqW#R1 zS+c&S2+#DvQ-ClYscxSVq4@2YY15+?ElAYpd`rE5wR4g)YLDd{uasPHQP$TKA%QB4 zM@hQVd$;m)>I0iTCyW*(4xD|Yb|2F>$r-heR-aL(P0Vc5qZSENVLVc4U;jhd`LLi} zU&V?RBm&31R-5-6lH`oq#(A@_3ip4p=~0UWsxTfYk7`kzjjYS;deou?iMRDXt5aK# zN^(Z+laJ-uxJt~XM=cVl!g!=rda-tPU+;|NzSPKcT+?5^hmf( zk6I*9h4Dx$Ii5wa5fz8o^{7P)5^I*G<(E$Vn&gby&!gI~C)GOG^fg6DpbF!WW=2c) zU^7-tuRU5{F{Ao01`Wp&I0H`N)n zd6tY(#@-6C>rsmYsxTfUDW?5)WzC&G?RwOr1&O77ZmX|jGpWv~b$fO~5q+20jg^2< zXP^q>k^cJ7-jB+J;h&7CMGF$o&OB15F7!~HQ5%tvk!@IV)~-h_5~#v>l%$X8XryRD zAw`c`v>@RT^h$kIF_-F$+9GMnvT8ej*!7hhNT3Sik!H!-`?B$AYbkovq6LXNe|%8u z`-(tdw#i=qUW_ppbF!W_J908#?Cr0isOspTO0xblDk}j zySu~9+~V%g5Rwo#Bq6v5cb68oBBi*MLT+-4OMyahS_%~VVFgMlF29-0?d7{0Y5Gr( zy!V-TGdpi~cH|8iCRcbm&?dYVB}icOMZQOP&PaKwshur!zpsu!Eglop6^T)j+_E31 zEz19w7G58LKU@URK5MFO?ZA9QBv1?eQIcBK^_1&{j#s@FB}hz)ylubQGR*0< zIqH^>2Uz;sgx4a0TIi3G6#KcV+-$-U)oW3LME$@A_U>(CoL+mPVI%pY5&+Iw2#yh=sQkD>TeZGyV*CK&h=#PB9WM!D#Y1J{+Yf*v(k8}%BPuHI7Bim1H zvx)szNT3$_qa=ORx3~Pb)oImhQGx_US(T)f4ddi&Qx4eL@AFMU0=0NtURT6bKFfLF zN4oT6u9;L-zcodM)}k63ab)wC{W}+3B@YdW75JH{`I1cP$dA zh5jf>{>_%y+J9`TdM!$jD7lZ>KhB@&^xDvhdu$G`uBz7}fm-N~Joe7*OSU0CvsJG} z2@-!CK4L#|a-P#`M|ON+TUCFSP3&7j0=3W|C24Sl9P-GPyHu}52@=71f3}zH|BcgY z-OqZ;pWbazy%q`7LVx7Z-j)@Uy-NJ5dM!$j$kF$l{c`kDr`I;TQd#z&cETn`$Vi|T z`XldsD%Fu#5InOIJ9(Ht!}`?pE`r`mRL+wa_2=8hzJh^6%l2Eas3= zg2dYgSL`=lta5tooI@Su@X+TrF&l*hYN0>!we3wEdH zsD=K>Pfk9WWP3Vwli&v6k@8*-m2pI{~LVuK`+UG0Dqh}YF z#dj@Akf`?0etV^N2c2H~Xm)+s=aIK8ycP-6LVx7(;SSZ2pKPk2dM!$j;1S;;ih1Kf zjpZZdOUS}&kw7iQ-a`eK8>4ZfKT6W|nICDw=1Qv9q6CTmH5zUIb8({6Yj2OOXv?{)t?IQ% zpceWgKN&V5z&5+@0@Z6#g2dqd6YV*M9d>%{^=Ff9*ArK%UW){3p+8EJ&%UKLuYXUg zUW*bW;{2xBPbQvndToiDdu;uhT~fUk3DiP=E2&Z6or@`AalX zy%r@%wBPoPz0Kf1oL)P~qp%#vPjm^dMFO?ZANjh$MzfsfWOG^UnnVc_{MH4ytzhxW zQgXu(o9eYlpceWgpRKK1NR}3~mBn{0N|35}rI=Pl%2yL@#7YVkWFTsI}~ zC}|ZsQ&Xoz)oU?+BE~sHf8_I5jTBmbHdVbAB}nMw4)*^go9#*82-RzmKrQq~-k01c zXFGr6JJoAZf`mTSa{3AA_U@&N>X^tY}?x9 z&sDEQ0=3W|`6&F#yX~9rDyZ*T zlpx_YwY&Y3>50>8XYT*m=6Fy^79(UNPz(K$?_xcB%+{*AO%}T>P=bW@m7l%;`{z!t z9oh1ZEqsVg7T>if<`^V|Ex0<}N@kwe~%tj%B zTIi2_uk)yTw&yfJeb=G{34Zel+)C2DkR-1y)bKw;<^!quaa%^vt6E2S{@ffby5B?-Y-6X9+~1=lmMB3&cWP65*JF$AO_pG_l^}sy`26{*zGbnkMr2>Lm7oL( zJfkW}P0#JI9p2ho7IT(JpcX!VzVdTvxvhNgKy^fh5+wNTI(F@L9Z7n)Ym05=*?9Tm z4&NjsP>bKqzn^xFhE=k_Z)0=4v~WqBSH@^GE{MS|y-n3Biy z?)hzt@{LwK3e!R@tT#!@U$C0(%;Qn=EM8YAL4wyvqE;i4G%8oLEpMI?a+Pj+0=2NF zRl=bWcn=cRG|wCEM6&L!>iG5dk#a>|S13UOYh99T_wza4T^pvJEJi}71#$Md59WTr zP8A)dwq1Vy*cE}_K)9mKOH$Yi>8Am?2g*ZFZq&uP$J5Ks=zD7Pe@XhLb6z^9dA$7n zwH?|$Cdm?rVz0kRfZqn?&~AgmTc+?XDc+{x#;F+QNMIdu9~|iBn7%w#-q3TGI2)dl7SuG}_`vsz z+P+VU^Xw-F%|E2O3j)*C-y~4Da2`dw2Mh1;!kfDITLSL$+CK2TIG@&0g0 zkiZ(@XWVl>bTqxyOMR;$fm*yDv!=Xj!|LpIt$Fi;!=wI;Xpv0|~rCgP%lFOpg22LuK3j|LF+S!h1m^iQgHfXm^I; zooaY<8Xs%J{c5Lcl~fwJw~%Y^R7c@12@+U`d`II|i}J#wmD&<9E!5&;32VytN6~LT z@q10WYvU4^1PQD|?zJobaJ1XlO|4x_3$^&$&YChJ8}ZX7N8gV<)fq^XAfbOAra{vj zTMu_tzr2t@E>|rrgs|{c|(NtY+QhUO95sA^`;&-?y+8u6qj~?EZ$7d|yPQCpD8!KOJEhoqAx+3N>ToNSkIq?%C9qKC+W>r$3 zAQGs>zu~MY^FF1nlu#}xR#}|eMhO!5oFr-ThXTs;+f;pmNT3!U)ml@&gloKg?#QvE zwKhU_Nsz$j#P9z&aMp3JR&#ZHg=wJ{A9q<(z73ugSnkO4sg*W{b4ifUKl8rrhd6%t zLez00riEI3l-Vfd#;J%N#4&DA19@*n^}Y$01PLA$8t(b|ej7g{tW=l#-l-#QsBjUe zWvlwUQ7L|>MHlr>3x02(qTSnv_cP)xjC}qY?rL1;?yuOQv&v6*t25g!2@=>A_}ccE zE=rzaxz+e3m=iK(5+txK@LfnBt0~ntl#-wFZyY30i_chC zQ)W5OR`6E3$JNwkKU@+duq{YZ=NUPaYM-mCtpw9TE&dH>O_}#u9(Ti0FG~aMd(b68 z0^0&#aX-4>G4pYCwUuC6sKviBtSPs7)LS;)aoVG%_Qm3oAc1Xx-x8zrbex`5K^}6s zf$knG)WRFJ_`cVe>W;IID$D*0}GHbyFwMx9VsWspEEzFK2VS>Y{J%U3CU_q9#TMxg`=Y(0|n z@2ghI3VRl{_dx=+`24jsWzFmHtJ=z=ie~l83nfTk>)~rfJxeLR2fWmFg#>Ex89i&t zD!_n5H>Ck9rOghyBuHTE;a~Lg|91Rwtf<7OisI;o%3tKAx?YO}YVj2zYsxC})COf0$BA6p>XJ)>1hzLx z%CfJZVzcB_=fW{9)Z%mG)|7R%kNe*^4(BeQwnUU5f$fcd(U&~$n6o{n+7gjKEk0{# zO<8H^nYh6*`%G?a2GS)#Lf>}%?~Qki%kx^@2Y_jz7M~-9n-~Ad(#&zQ*mK+ReCnM@ zE(sF)I}YFOE#}zs@P_TvgmB%>i>QUSKJt0$Sz{IL##_7v8t;1MJ2v4)=)7YRlr3M~ zCpizOdpTVaB(P2M8}bg1P-=FXMMbn8ObfO6jx>_8i*=cKkaD$j9c_1;OM(QpX?_;K zD@G~0JWOrvm=tzc1rd9JJmf!NT3$qwO~!z z>GbQr4VB+dT-J6#xFkqmo96GRf#sAzZr9cIT1*SI_&TmNW$%ZjpNCSr;7fHU2TG8@ zHqGOne|hg{-sYjY?u-O#@s%xW%4+zkC%-x>ulYw^+eQfz*rxeCqsxA9T$pu3ozq7G zwfJ1WHD!G;>x+qwiCcfu)(u<|B=r7KY*$l9z>uHRwFyiMwfM@0>sD00tGJrGV^!ZD zY+qigcWt>ONa$}SZP532(&buRZ=Ii9fLqzm zy&t7S_bcdFZdcDVxFkrR-$+u!k|Punb|Oja3d6Kei|@=PDW^H^)f%Qm%=1Fv`~xh@UW)r3cK&|){$ew8Ev>N0M zn>zlETcNEex+F;GeQ^E3cS&FU7Nf3OVp^!h*F3E$H_Poib1l3W%9$_Rb&`v!?7xeJ3AttZDR}>a{3A0)3N5L;T+o$BbFCRIfz>wfK%3YsxOY+1cYA z@ug>IyLVg?B+xhc9+tRLj{A|FRjb(Du)giM+j*P$m)SRy%Ac*H?PqXFkkI=% z-!qYbItY1QtZTg#N~KevcyK_b5_vk0KJN<-C=| zc}wMim;TC@_gR(SYxpMds2bLK7iU}VZdgwE`F!iLucoTM`Kf>Fqo~=|9Q9W5SbA^0 zLlx!rUygZ))OY|c2@>f4eC20Jm{R!DCADY3v`~wmYPP0CLU>WNk3xp8O70mzq9b&D z$q-wVvgb*HL%h#1E$k)uIZu*uHhkM3QOe;89uCnnpaco@f4)y9I#8+JZFiFB8IV9N ze)5f^oR&R1!dIE|xjb>6qH{@*K>z2ngQTTW!J{V?d!sNd)Z%A>tSRRQtNh+bIhHNA zP3*ry2@>f4d{w_rIi=v?5;k$-5DC=crz5N>C#u}?Sd@vY1J#}ZB}kzE^C(bjzBnF! zAE5RONT3$qFK$gaW8!z|56AIhW7M7jB}kzE^V70}w>#zshpIgT5~#&@&{|V=-FI9& z+fgGaTJ0H7f&}_MKR?*HnIp?THPxO03Dn|y3a!B*%bh*LFl%0idt`BKf1*o*1p2?a z2Qo?91Bq#&7T;xMopk;Or`N8!@tn;ZP*c0V)+Ip#{a=l9r)Y8Rc%(Y37Tb7s-Gi)T09DaH6?P(j-XzOBmcLmpQ8i`^k%-xV%XQp zid+5E^XEvQ7C)D6O^Ic(*`M5q@N<+Pf!@qVGRrF|6?!#L&nO~+TKw#yHRZf>=^Dk9;kzEFrgOmy z0=-#1p^&7VP(T8;_#SBM!gmXue!i}zDXHJ;LaLvm1POi5z~kI0TAVu`&(5mFs^xL+ ztXf1$9x>0V#j{mo=_z@6EWO3avGiOLB+#2BDXB^=rQU<;ir7hxX`vR62xd)*BKSGF zsZ#EMw<1RRC_w_fS(19)Xr{QI&ZUTvJ`$+KV@1VRqaML07c%cLd^kzx2 zhPPJc-C?SqBY|2xYK%1{(o_eZc1qko)77|9C_w_fnSVRS$;!u1-PI^JNT3#vqhU>n zz2mXOs?=HWT#L!!k|2TJ%y*djR8nrAotY%|Y-3ue#Ul$?Q=*YrPnA%z<-cZiMk#Pf zkU($dH?sYbM;Tb&lZta*m=zL|1R zJsXZ`p%y=VYE3z@{<-v4$DtN))$`{lK?1#*$Lot9hXa z+pY~AP0F6r&i1(^NT4^X=LeIt^Mm|spNl{(enQE*^UxrtpD(CcC8_w2pNY7C5G6>U z|MR)NAs-xCq+1@*)~dyx=aFu$T1;vlGuNucrT zOaVoV+fjl9dNV)AGPAB?d+^C2#_dR;7LVy>O^E~9bTUy|tURN>&ryN|dNW^9+*Vuh z*z$uz?2bkPwRn^(Yf5Ci;g@SG!S@F{#Azp#Ac5Y@Bk=Doqx8B{-y!@Q3Dn|of2_S+ zvBGK|E~e!1Jfp=Ba!HUtZx(k{ zKyT*zOPZc@nCzF-$Ss%_YVl|i)|7ZM@#XhA;=UfI#hGwPkU(#iq~aULIf5eMRX@kH zP>Y|Ix2`aKOq_E`#E7q0v9;ruDYLbc_bv$%=*{Zs{v_>mzb-BCd47J_ns0Ukr=JH< zIce_IgQ}nFBtW45^LBM@i=*6$cx6r%-=uMk>R5Z^{i1%8^P42B+8q=8UI=T-jXM0k z35Ryy1WJ%VZ|3jw)4w?)>V~R*js$A)h~3td+ao&l%ce{^(pmL$lpulLEJ^Qu+?3cx zO%?Hdjs$A)_`=qdxaaoGMHFRdRn^Z?f&_Xq@8L!kRdW7PSP`cOkU%XSan+gF7SqXY@`W`2YHp;F3{fA6Y(js$A)7?jqOxV3{HlvAejSd+rfQGx_|GoLS+ zTSz(9W`XMGNT3#v%4bc9Cx>{SqXY@`X1<61@9avc)?N+~Z2<|?;&IBX zDX|SZ`h0X8pR+DW_&G|DKyQ|$xGBFl`iE9m??VkqCX{NRMk3ad}@>+ z!S9HG+n@^7dhaMWutln#8nv*`=TXdOpLcZs+gBa+p#%xM!HItlj&L|$mySsF#z8H7 zckz80Q)fDg4vA0oRzm{seB#8NNJo)u!7VSKrPy?d^wf2hq(a#e)I3mv1kbNgN;!DR9Z+)D zO<$;`e}cjizNK*q|JqSruAQDZy21o?tX3-fti(n`lYj5nGBUAEw{h0wz8wkwB6|~k zvdmD4g*ksr45^m<8{%?okhmUIFLC4J z;VP}q0}0ehzZ@t*;ves(iC;dANFxs?`xzo0dpSBM+1y!Pn^R z8&)c55ZIH|w0uZxz}DDB|AD=P-YS$JVIPpwelcXLN~cet7RG1M6DUEV`TN}Vl>s}_ z$O8$~!e|ouJWzs!C2M}WTZ6MeE^Ef`s#VIP-XS^RJ{q%@Y)l zY9q>&ylZdtre=0B;eR(7jx4k>iuk)EZQ1-dDWG$L658}#8I&M_V-y~n>g;{Tiz5+A zol*g1B6Bsgo~i!Xs^-D_@`R?3)!#UC%f~P4?mF6b*)`EI+G4jHXn`E5vYYV!s7^cneVtfe2B8D#4}x8A%XK+JaXhe zF^(;5MkxDF{i7pL3+s)4rPgbtn6_3|UTrE>#(ry?HCz32YW;}+i+_uH!&Pg(fA>NI zrE;m7%A;%R%b)~T#xW&+_dv~R${fBjv$W@4T^>l_iW$Fk;ZJX6DPIwfzuH7cpw?8;er8eMe<%nBh4m&$ z7rT#D{&>1D>C%stONno#Hk(ea6;|PC1+-R@id-0@6z-ngac-Qyt{h0<-fBr&H+7UU zVv5aC^2s3`fm&E5zB0NuL1}vaEIlwxTIb9?QCNj1hR|9bG3(e^<=(=o^tn}9hY}?4 z422{`zZzz;k~5PK!JPm575IZL~-U9f4X{Chq6`IxCMinB*tEUhAD6 zrCNn&pV3+#S8cza(z01D`AF><>rsLPo@$k(Tc!|Y$ig?aM_c>r2-Lzd@x7e(+RC{0 z_2dOp>aBP7uc}perXH>3C)RV@l^49^uh0=2MA zJciJ=g36Q$UFADNx~zBhyQ)B@lwp7iIp9AB=WwC~?o z-nQGWBTx&=BuUq1U2%+zkCC?oMXh(fw^ge!5(Zk!Z>S)DJI;9x4AG@LETp7M4l1ifUHz+!J}*P zQ-jv>{_4p8$kF>_<@dUH-C&-_ao%cX$yW+OH z;s&9$YRPR-a#uN!;I#m8ad_?8pmtpZYGG6zwYA%{*3MhCo%cXmYq$S2`n6rmx1zOb zE3rWU#$3`906^JujVTB3_UEi9ATGss%czZPhBYR+0+T z$}ZnX@hDe0xEHwy?p+X-i+imNyw*ja7M4lvMP;oQ6&4B0gb(um!~U_&5!EWRR_%Rc z=zUz}K!W!~5aBQX_M)=r;ewKTI2VChSSIz2BR}D9oTvPaBc7h97hx6eYwe}3uTiZ+ zYt^1whMwA04kUQ54bejR+dzi5fr~&bER!VNzZWI1<8S9F{Ov4Sx@befD*j%whs_UBWq5PC2-LzdsUsO#8_9@XLHL`nioe6z;XcJwtI%3? z1R#g=5dcXZ0l3P61Ro7R6mvexkYSYJB2WvlPzZPX`v&_-{9N(rm@c!xcRo1Q3q z5Uo{5OEQd>T;)K5kDTB}1U@2@VMOL4Pz%eXj*w+-gzU^+9k=tbAsfEqr-s5Rv{oHi z$}qBYl>-Sr%7oih_~=!J(W{Ft^}&Nh{AdY4n?^;)kh2NL|76K$ z?xW{(88XaexJr&%SSEg!Y~x+qv<{Id!KBpI|eCb zTmG&q2NHZ{!mjOAjyKZ`u$q)p6`?Mn!|_FE7? z(Mi>EGxx-qEZ4!xwD{U<_G|BEv5+}F>hE^X`}5l6|GBJcaXl9mwVBkj4KusFQ&*-R z{8>f)y|4aKB7W9OBZ2O;8>7rNJtpDpj*Fc2N zbfd)N&&Dt8#E82a&HgTk4IkK%t+f^djE{M6lcQO>{}8Uc|3& zg!=ro^6B#s>7KdQMr{p+I(X90|7%VPi!>H#d+BnEYSm&`OBJ+)XArKU*NNuZ}R(6+Uy+nxAB%x!VR1 z+j%2_lBkm=di9Y%Y4#|yRw2>-s)>G{=}(f}A~UcGwJtp}(Y+RbGPItNKuO-$CVJzK zo@9I1$p3ieT3sQLl*>%RC-)@R#~Aa#xGmu`;i}GqYNd-w8k_t(-If_h~q_O%Yj6NCT3dqkRK@}8S}t$pcY!FZ|!JrzDZ_! zqm&<6vn(o;wTr~~rDpm$ryr?&CL^m*3wt8HRYSXa(}^oOkp1RZ*6xypy4`J0{9pD} zt`uue>Qus=&;d!j-=R*TKHzEFO z`?IR54}kNVQ@{0wwYLyy>`y9mvX$v6-|AiLX|9 z({&Gc9!HJO1Fb@>?-qH}s<%3jncIy7_SE>6!MB9|nWMx=r2SSyLj2aWuubdpKnW7q z-qI&fOZ={}t3w*2C6pk6b*Rq+3Dl|??M*)=b|6bz7;6_LNTmNf&})%EztLNT5+sU! z^rmHwG$&J58e1X~s8zF=58dzCg4BO%Bv4Ygi4P5#+JgK>`ZG)^eXEct-ouBsJKuur z>~Hj1ObfN%1^UqEk6MsAV~oU+89vnaW=rzwL4S3`+V^8iB1WuY^m^aDo%&mE750N) z>iE#|6*`bVOJvk1VvQnkx|R?9rbY*Hrm)c}Bv9*>#fLT;(Se-%!&tj0i7wznf0*5Y z1fR)le}%-0x8AhvPaR10Z;g4NRj7r1rM|AP-v1fsL+iEWHN7LV&m4)1c9FnzTl18zechUrs2p#w3e)Yr*@yoA zp*8u9=W&)3rAQmnmFKN52TG1^@SzTS8`7n0JUh15htkh&h`ET7z&wyf3-x)R1c~(X zKmxTkeB(nOpJ+?GB%@V=(0YR(7x~aCHCvGt#?Y zVucTFHntVnl;238+CP;w+t>xQWkZNI7jS)6yKfxst-PwkOcAzG(zGqR$RF%QwM zLYFjgyfPbN1Kq4;>MPU55?zlaJByEZ{~Nb!MV_c4JFK2@(Z<^`Q$2bS9mq8?C}; zaJXY38n?YUS+r#UOaFPG1c{an3ejInHYb~g8J`CdsD-tlFF8t(kjfUK&3|Y{%C!+b zFGPz4wIx619mwLw7ox!f+K^=>GTZwg5j3d~U0ksSBCp{7%qly;Ybl5@%-l&8i?XL0g$ zC4cep`A^w=sC)LVBz#w#t`^d_3JJHOJ~ZiR7c&2maiouu->p8hZBiF<2@=?P^m!nGS|1O2)9Yor zl9m=@9w9a0-uiN& z1c|Bf-gHcO04X0}%mWG38XW0Oz5ewl-!w52H9L9JB7AnavU~E1lAF}kwYv1;h<`fs zC7MLcglNR^0p9d~1-g3UmPVjf`c|O?iHB3XX$7yY4 z*Y5Qsmvi<}XHQp;>8P%SMD?@K<<)&jpDcY1qa~Dx*(i-zGSEV&pX*Ex6v&7`t?$3J z(E96r$(L{=A<`AzDb|G0!nk@C`h2NBIXStH!K#Q+7HU5bKysJu%UXV8q3`?x$@!4v z8DT9YeaSHoBwnqs&_>e&$?Sm{S%q3fH(F@kYk_3%R3m}y%D1Ep*2pJxI<0z7JAm!gRD4f zd>&{OYW-mKrde-vAqD?5T7?oM(r>#+pw^t17CLuP7eX2s^FRp_=qvi?fqpQgorNB} zPR}xcjm#0j`v2`oi@xd2F1`&j5cT~%Y4&R4+2ZA)tl~Ql z`sT_wHq;)Xt|Gh7S*oU_uPb+dle#Y7|8Y30*3v{vE(m5bSh(5;ixvLVtKp*Lngj_f zlRgh5P%Hejna-Wqn+3_nRehA~yJe>D7xiWx;-WKY6%v!&y=b#ly;;<6#yrp})DnNs z{ax=gO1|*Ena+7Lj9niU&9?q!rU8EqXS3!cTUF+l*fa>6yO~y)HiFHa5y?L0HPhdE zk6;_8MzSjLCi-ws0-IRWxVF9WgNgdJ8P28$N3!bgO>`L@&S+pHd)?5Ju6Z$r748yh zc;+ZU;@lIy2jRppmd9#b6Gn*-U(e3EZx}mSC$o7V@#kF=9lvN8J5a%x2U>+%xi6aN z|7^q9#jlJ+RHTWHJDI@NW{Y6uVomgRVgj4$6~Wr)Fw@-UhqHRajRZ=NNWXTGK&?kS zkHc4ovo#}(d7uOde46^!jz00Ak%|5&g|JcIh3kA?PoPgAF|dk>ZaWpi3XM1R3`n3> z#j+;)s#+*(9d9I1^16hHwp|~}zKP1LRYS-iU z(yEY&e*755%Js;sRY+_rVxns!!`aS2V;*P~YTe+q@VamW>%nV5|2&!;Gt=26hO)Xf zqgltZX8JLHC_CFMBR@a0-b}5PhOovDqFBTUGhJ{dmX)p-&AuOJrj0`ev*Qbldks*6 zgl~eGcI`Hp#mzPnSIlPm%lUE4dqpH0^u|O7W*^ULHG=Z&oAC^gvLSo8CPdeh?1lHffSXU_V_At@NcL~haJUo+mAkneBi8lU} zz^p@zd7#&#mS-&!E&Dcs6`o@xP|~lJiRO5gz+#llT7|@pE+$&-&jeQJsxc3=3bn8w z)3+<1StdGVPy&;JBG_gAyXt@hwmUe2_2a!yV={`3OVz{W-pu>K0tu}2x(N1w?}s|E zXAH~oYeod7g~XQQCc1gX7}os0@r{E7YE`~qqQjevVHds_3GBmX{cNJgJ%_PI&muDU zjzZ$b0TT_mGL-E+Vax;HAE?!Ror#W^IFx4=4cgaiILiGG5yjQUturPsI-ZeZV|!G_swh%hs2rcCc3V8B)dAzXchKwsI|U^ ziFU6R$$p+;B(R4Q;~j1E((bUCZpuBB1ywSRmare}eAP^seHh9f`DfH8V!BAQzQg;+ zg~OO_urUuLPz%RhdXK`fGmeUJtgRe< zA5~uC12rE%1U1Zw@0)l38Xk77R$G!odiBaLH5eK}BqME-pIn_exbl=lR7W|X3hr>P*wXny~TQ#AC7oE?);$CKrVNE=|sLX%o zx*N@KY^Ntsf<&%A%+&pCEGrsg?BS3=EgS*r^FXVR#=cTdpahAh8_l#xy&AwxSJuuUA*+#KNW1`tk-k%qV8^x*)Nq!q>J)hnx9I?KBY@&lqOjC~0bsD*v7-YV?R>x%E?)&tr1+^Y2Zc9bBIyONn!FEEHHKO6l6 z3Dj!2$xN&L7|U8eGd>TLAd#=7nYQRXhz)ehh(N9M+Z9TXcJCoMa8 zJexSqmbviIWRF>5-7}%v#Kt2NI}-bAbBRj^mH<<4m;7NSj<~>}%)^Tk6 z8DkHJR-qQoSm>?7cgC7)X4);wX!fF4X6p)xw@1zNO6f6dW{r&M3bn9T(p!anRKc-k zT4VlLR%~uY{S}rRiH*T#y1K$RHm{|zwIhLA_?+}smCoWtbGQYvb4k%meq*LJ-v_Ww z>yztBn}^pEA`eZ1#IikR>VGhR#pg<^t~3I*Ht#ai-HrhECaaN{veZO>7}ASn856-y z%r()kHuYlTqmug)Ev59WLL&DNKEqNgh$U4>>wT`Jg<5k5o9K6Sg4p`yXfN7x?uB7Pmz*>C#y_v2_3}A!)N^VzL`Sb+l zfyB6(X4=diz%Fe`t6gbnq1L$mW_phk75f?qlq7_kY0hK3Wpv7{RY+X0^4ZV30qp!g zY4r@6Rj5T8nCZXw1K9K@M&cD;|2WekkaY=(WZ&@bv%z73tN{N$!x~Ayu8`<>)JJntZnISpe(zduFXdVkw`+-Bvh|&020OIa-BU zSR?w9qrGpA@_M@%$h!ZT+18FkFW{1}5twISB-);1w z4-blFb(*AA4z0Cgx)V=&(L0V9_H3##50tF=#f!f9A%^Aq zHo5oFQqq?kEkWY=BQN^6eGEHz$(RQcs8#E4FFK}n47+#VNT6>&Z)lg^qg`$wu$ZsIE|Jc@W?nTj=qp;mq;c zml0AIqk$3%YcAM`!!j#f~f=FcHbgshTtkqj%9+(ztVUL=A z9{G9H5MTaAyOukKS*v@|fYrU(KV^;nffDpC%sc%&kVxMLF)h?WU(x4*5+pt?;IpdM z-mH6GW7|anwRHY3GI2#bK|iSU){Cz6ieVrB&8!b1F(iwHmgn=lhw^3g1W_yfzC`Tn z6MdqH2-Dz8a?d&X>wfH69&b8+U@)5!Z`^Z-`-pG`LDaf7C#$brlo*NhXK}Q&1g&Xx ztKvnsoQh?%xUpTK1PM{TpZhLQ%cr*rOL)Q4oBozRgcX>ayq8m}5j}x*g+#WJ-qinH z2%E9aSXW4(R#U#i^t~L)e%fRtP?D>hH*K*vloj2PS*wsZU7pAN85YKB>@ntnR-snT zir#dJDV*imXC!{(Bi8kQ_ha$vd$R|pyy%Hsv8>e0-s%q1v}+gZ9f?WX`1_H!wZ(0W z9)$#Il^*Ry4^D|?v#%PTIZE1(@}h&M#s@ZcV?nhsMUIgg$9N7 zVX>`@#H>R6P1dj<3vba!S3lG0TWF`m9iM6#;Wj6R42YGHfRmjheF zkx3Rhbxa?&qfusCA`;y~EcAK}z90F4@tLDlsFi*z5k%0U4r-4);x=!u{P#%re$1}~ zfBS^^vg2Kid3?ji)a&E?*d9Kn?!e!idm?+X_OE+qKww%(RCcq_j|+RUTP2NoAc0zY zx?5<#5`VVyw2?rokp8Nc7p-)$2lKCD>`PFBgnw5r8uzd}b03xwfm)swyy*6yd$7J{ zBZ2l7d9T^FftXOBE zCp`n%)A4;XX%!OXw^?X~_JQo*#l}3)D%8UErY|{4kf?LVLf@S3#YTFh<%3$=MJqlm2fp&8(caw{ITxaS8whJt z?}!&GacUlXpT059omxKrcYPishnlI|$R4cKsO0%pE!`!pcx4{=Av)8QX*HZEGa39836$ z$tqqZ-+B5n=}V63BGF_&UvEk1!D@IK^FRW%(zmKcfQcUL*ps>O6BT0JV0x~e>gobM zO}$kpLE_;CzPoXvA6vH6I4_C>YPH~T?)=C2vHYpx-1V5u&t~v%gBo8#S(9m=bUuG^h=IJmneS!K)v z(?YGI7d`2f>jA9eUL!Hz!gsEA^=EfFhqIb|FZk8w{;Ub#3yvwJZxs@DenO?s%AV|( zB;%?KriEJA7W8?by(Rhnf}A-5m_OfNfGOz-lpwL?y(hhX$DfsR&&Vp&!Wz-%f$eA7 z5x%>vnIFr3Ga{2#A<^PD6J1ckk4^J1_6%4K)Iv|wTZIxNvJ~KP2ha3i>*g5qKmxVW z@2}nr@T4DKhOz+{LRs^N1?kd)!Hl#BVtCxIDtm_}fJh0?h2YJ#_b3@sUOZr;S z=Yi=Wv44ms?L8-i75m+o2NI~2zEybMRXk1YJfHZjowe0lg%TvvkKT#|YGHIzeI6)5 zVpSgx+H!tp(wxt-q)(uhcx#I?rH*=v5+ugfDyR~J*9IE$KmxV0x)-Fi`vjBP9gIZi z@4U71c)|CMg|YixJZWe1AQCz)lm+k|P%X>$C4J+JeaQ^I%d_sIq2vYM<%zVYLy=PI zaS2M02<5v7I(_aHOeyZ`w+TP^Xbx}GC^?9Hr zNK{;Dro#{QCMz!)$394)R{G^Ayr1tWC>TS&I}*W0^Bvgrd}2rmz5^Sr)mw!UBuW-B z)00wfvUanvheHCjuuS?qo|{ed&o+^ySch&u3J3R-^KSBM;RzVVkX~7 z9x^Y8+)uTW90}A4+~r9xp9vz@Ba9;el*H}uq>m$mNkm9ytwJKlPER^)VK6xoYRm(z zLai8Hj#i69$f8u`K*@@|o;2v65aQo2vsNMT6R-7$--eQcyw>&49IZmF)+aq_n{i>} z#L`p*JlhI<7mDd(6lw4}v#kUPpMLyAWr1koV=|6jv0b4SwrPDiP=dsw873M(ESe9c^p0ENoy|(BlTB?v6_4|*~ufEyx$#`N&i6Nx0{}H%;a$L=&Z4JvEDI1 zd`^0+P=W;3VfqAWO+8^`tUssdIBX#EMMY5JB}VehTky0)sR4~^xrrrL89#K z0`%RESki*;;L%%!1Zv^iPEVi&iG@=N&^#UkNI#P?4mNw$dh1EIOo|}i;|ZKkbrZogk50_MpKx2b0zLjI9I-)SBF{AU$?| zG#OIfxYrp+88{k9zZ@t*Lj1mQYf&2G5+k8$VI8JlyO{1XzN_4G=r_cVM*>fuK&|vk zjuIpuulJzKYb_xU-WqEc3DmkUq9Dz6dI_o0(pbCBn*{9QR)VX~3($zg7B)F&pgOly zDNpe<=9WZhH3<^W4iun4(+aWdGmRdlba10L+#cD>W$&cjh+r3ETyZZ1kM?IzeHR20 zsI}khMi&J9Z9g=zqoH=Qw#`ZXX-&3AX~8zH&6RB7_10=0!rIh%h;%gx61n4Y)358B zSo>XV4S67eT4zO2a+b<lIL~o}N+c)K>$A|T0?>u`Nh)4DE(e+1{u?unC*v|Rx^iaYwwso#A z!@SeC3JH;4+NU`%E!08_^?9HK35?>BK7m?z8dOg#-}@CU-o7te{aXWF+ud37Bl*DR znA%LPVW=yVVB1A6(C2{!YF$0}j!ZxGEjzxasv!@QAR&J9J8jbNC?lb1VXf<}LJ6kp zyf=r5dvnq!Pzzg+p1{+@c=L^TnpzYeJ%JJKa1l5Wuj)DcJHGsbl_lwi8)kCsGlkYnYXMDgB!^yw{mT3}}4t_xLIrN;lNqotGM zDj1#zN|5OG^;`1Gkzr+X6sVE`fm+U#tm)>VN|12o*GO2XuPaOowVdT^lzLoJ^lCvG zR_~;JbNrt6K`|yudtOwN2rZ5H&eNU#RQZ^FUcavmR$*GGC9KlMUHWpM z1c|uVJT#~@vlso+-jD}M?n*i7((rBei(V}<81G^pNUVF9m6i@(YOnn_HROQ=Y8@h9 z(H*X{Zy->Tv&?4_Rn5rA{K&wzo{9S9)`r0)< zbM0v^US?LG;PzjP-%%*RrzyNk(5ZU{Bv4EI-u1_kGzgR+A@%{N7N)x42no~@zeja+ z*v0-!eaZ1&yB5{UQ|{-DTJD|7@E$xpff6LZ$92M=#x^PMc1ZtHvSEXwv z&9~bp8uLI267^P;;eAYNdo%kaLmo(=7T$NLFF8t(7%`xf>Vtb5O)%tvks+@At-bZMwZ-_^1_C8WIP8%UDG(Hv_21%AmOY9YwFrX0=2N^>+^8-?N;%gaQ4CKeVNW)JB_zdX#|@=eWcQBN;U%y;Yb863#J^HT7r- z3Dk0qwXCT}WGHct;jA#~`wy#-aE>3XsYjM*6>4Ek>r0LjB%C8zYq}$3^+};t`cJSp zzctccY(8tiZ;ceKZ^!<5OuJuAd?%*eCu$NTzCTceo?1SW-Dqs=cTsZVOc8o^^h{Pi zc9@!=vr%lo z?(vzl3WQuO})VQh69KUNUc+4ETRNd(!+Licw+Fy5?L}+P5 zy@vVd#ebKP(u2DhtP*uqXT?1AMvZkXeQ0#{`D9g_{_2ScbpK|H4dO|!wO@c)Gtwm^wi8D#|QpTPE3Dk=JtuXza&L+Whh`}nXE2Nzs zMN)edN{|r0#eSC5wQD3aExc(*UviXSy5e`*x5O9;O$+a?(&r)460>K*Uhe_r=;bf% z*!F8v)aN1QvQn2r5Sj#uQf(@#fA3jxhM{(mKrQk2{~jSDF`;H9I&)_MwzcZaH1g2W zLM^(zqsga1ARF>8+)`LZ#n4E@H+8YP8u-5ffp#+H`oyw`t z>FO@ymoO5jh0jKxhZr-6UQ`=j3GWiWoof~(-SrPuB4~~9+x9{IJ>scx-Urv0v7g8F zXuVY^K_dOP0TQSsehUlJet&2ZB%Et6M6BuQt=eBEA8jEmC+C`XW6m`eB35G3f8(G8 z39NN}9!Q`TTBs*bf<*dH5DC;uzvTFA@tHeU&q%r}ajFCf@mutEspoewE!1+Z0ur$b zn7ZU$XXaF&?c~j(B%C`6tYQyB>O3?8wSl2{U27yzG9n=doqxO$S@)<}Capr^>4hI-aI~uIQJgNq`)2Tl+A}0zaul8xQzT}uL66U!4v|7!oWWy{!Lmo(=miW7U zYpFE)M6?&_5p{CYRdfIes$yIjMF|q(x7NGr%V8umEpjWDN=%M6u5F_P(@np>LISm% z>$N2HzKp65J?OZP-3eI~!lv*T@dJ-dUlf@r0sI!emIm&SCL87v!iT?e(C$YCQ=79uiMeth}a!vIoB~#tHfRaydJn5$${^Z}BnY9XumVBqI zd369;c*eL>7Og@p+z+cSIZBZ5SNJ~5HoZv2$;Ld8KrP(GuFoT!$G~m2Hi9(Bn>+(4 zd|P}2?w@X^$K*(||9j&K7D~hyoklFVXr{jVBT3h;#xo6=M`fAE+?^LeW`9VI_NLK# zt1w+8+{>D2X%a!G5@~2xNT62X-29fPJK`Nqh`z|>S0v`Vg(5Ve{; zG||x=!^yQ;Mgk?rf926BZ-b!k&c~=1WI;JH_?q*gUA5C%vz-*c)f`y z7?J9{0a`U3v^@B&3(-eT5(Ju3TY3%$}Rggn2Yzj?3qSqpuYBZO4EW1NRW30mmQ ziGLG=$$>wO1m3pSO0m#8&w7#bhxGaB%Yo@4v7O)5Sg&CaY0IOxq)(vMkP{ZVVR8`J zd&x+kWcwKljWh?7qqj3_6%uk6O8rDHtG;*AjU_xa3Pg+w(@ zcY7W}2A<2vD%3i*%R<}c2qUY%GZF`fdePR|qDaxxG3<3Pk4BO|ij4U-Ic8?s?FyeD z5@S1f(Q0l{pG9I_L;v?H@O)Jw732m-i}v?5%b8*))f*X7FcLL?{MPh zZ!9@lg<7R&S!g?3IN8_ENT6gjzvZ^$wQ%w?zvUKFO23sLaU-7JU&}`s2l5*8z_d`S z#n%=(yJrNE&h|01M3ns0(n5zm2(;r_c_AyML%7qzU3Bo&x377|*8TJgud=mCZIkNj>+y;UelTI)p} z&mu{9wai+D#OqaFwA718@}ayj53~xk(9;Z7!Q8!=@zmCI#BcF6nf5%jCP4z%cl3E+ zTBs%dE}lo)d1w+O#BXvxERD4yObfN@kMgGF#)gusgN(bvQ1a(!Z+b2!l}O&SUF%l?Q7vn|0``DXI+MN9U_;0I_m^6$>Z2q@5xpT&t2U>+%*edm{ z1SLqgUGt)&miH!Sw-~(^3DoLovCuX(dy_BJ*e9aoavdI@_)84&o{${vO_V(2wNxak z@Tgqlx5tp-KO6Hvt5C}}j>nB6F+}E3%=9Hk$T7|?#9@}zP!ASCIr!fz#E7UsZ$KzRc z2q(5OMnA_Wa)MURO7NBZPW*=UPubhCSbjsh{+Xi$3GrL3W~Oe5Mnco-!Xpny&S}Gb z++%EsD8Y1vZwfkf?}G$t#l1{E)1W*w`XEY>5Wmwt1z{vKEsQRwuPc;by5hGMtt(?f z(@H;TotUBL`@hwFUE;U4B7kQE^m(8J37qTCm=Nzov34U;62H?v)1XN(UGZD^P3n~& zObfNd-vyC&9-0IR@mpJ!Onhngr7ozxheDbjpE*rX}(azf{j;&H(4wM)PL8tZ)B*bq`3(qL)^FRp_VhusHFxC1X5~wA9^OZ)H_A0U_K?2Vx z>#f4HP|LX<$;1k#p1@sGVjQIHA`tcV-#fOD5Wlq@9{M~mEz}Z!*Lu{{geE~k{MPn_ zWK3vUA`h)cO-*PLOjrCCPcZc;9MeKA@ptu^r@6;VlOU1terkMBsFBn@Xe2Z(@pth%?L0IIrYnAnC!2O2NN8Fj5Ai$gJTwWW zD}IZ%n|2;ZXj&o<@jLB2Gzq3Fev7lVY3G52rX}(azftgew|u?K3L%2sIA2q*Pw1UZ(40^e)~X6EF0?OO_y9Y*(=WM$NqZmO#{xY zvS_Ze5i*<&}6mUVak&a4^VIqKs3 zQdEk9UK@5%Z)P$Uuwz5SE-H3K*IvPny7t~HcI^Eo+-rB$U3*>Y+WXpFRP;;2;P)o3 z`}kj;d*0ujNiyZknUf^;Kdu$3a=rGZm99RpMU4M10?!NEUB#{`OP)o1vPBb@v^ z8$B{AU>}W%Qm)5kr}@?_+}C+WbLGja9CXT+X4Xa?<~OlD&6AbRyIN3e5)h%Jy!W7E zp9F}-uQmCPmWcK3vEQ36{Y#M7<^I`gg~XSg-gNu#8ReQOW-lDC6{=n>_NL1&xyrT! zW&$nS61-{i!CB;W(|i5LJ;yST=%9|fe>BS`->zsb0|``N-!$HjUEyA|a1nobqWX27 z(xtrUm=FGPa^LPhSt}$es_!J<=T=B||L&dSSSwWZsOn8SL@bfBKQpgb(1OI5bDs1< z`9gBx<>s})7&SVewmA8g8XdUX$CKWe5Gc=1?y6j?;7J#6pD({GXO0@61&O7Z)vqqx z36zigZr*)G0##S9=cR2k2g%#In2Byha%-cd?QLLtMLW)T@K;$o_FANV#Z?ZJFPt{- zhNA_E3-$8Q1@y0@|y1E{aPeYg;&Jbu5h%(QS{I} zcWq`6^KLbdqG&;)+yG~~^wt3JR7G<(6%wd&Zso4cMB?v(<}y|l^`XBV+%7kB?ydOc z^`T9lZE#D)JUMJO=&e-XwAYZR}#!^7cEHiYoC+0Ze8AXFRS?tO*m(q zY?MQ*yDdb0WBrfk540eG=VUx{Bv4hyEhlZ38fl#$YCd!9=LM3y=2fqw}fz^)PoC3A7+l?~51R^lGsj6=9w^ zkwDdtXHK*r;irBd>Hh1*a#i*FNXA+rfhwG}jRbnd=q=|v;!6APnj;>V9BL{9@40rY z&YYsQ=D=2IECVe_)UTL>-inpHD4CrX{4=~R-NT6zLPd^&j&BqoP zJj_%ET9CN^!JFptnrS;S%UlK$s2X+Gk1l)=XM4tmo60~75|clB(~{X1+r}?7mw^PT z7Ww*9DQbl+|50-pXh9+*s}H@r*I~2S4XI`(aNZuPei!%HL2p}6^}D!88*7CY zBqqJit3`MAomlW+D;880c#>C(0qtu%-b|ox;7H0!haU zN`w~i=(I{aphi5j<80;kTeV{&fx7^>n*6aZiWVgPp5#NXlBIHshrLZ@Ac3kP7ky}Q z)}^vCvyX}R^N#{F)1PbQF}(*VF~bVbp`jb(+}j2!wLJW2jjSu=zZ#g=I2b*{s2WqB z`T4x`fV^ytIm+4Ywkvi0bFFAQ8LC_?mq{x_EIuhrdA-6#D?@Dk%set+yba@UpMtV! zWr)jWo7)w7!Y@~;-;7I*w5@*M?kBx)BpNEYw7m)2i&D|1YlU7os^a$N(RMkiWVme3 z>_-a{=&2c72@62IUcPnQ}G)HUEg2az~IP}jWm*v#f9M)5d+x+C(0Et>^iZiRzAm8c&kF)g6VmYL>4W9g=g||I6P+m9LAJ79EoB=I;KJ9x@X4 z0$!STCJ(4nfkpF+x3RM`nHI{+CbCymXwCF7# zF>un)`t3;MtLZ_%jPnwAR5yF!=(nRPriKR%ZR{oXA!g$Jes}G7G};D@WBa*9r+# ztsmw}yI$zJukc;-jyqbAXjH{ri|AS3Uo`veNTBL!h$}tmI(4r#)LaHykeKW1u0;y1 z&*zxSKmt{b+q=+WFI=oXQRaCNEl6~Gjod98*7s=7^erVksgu)6gzuRqX&#HMX-T0GIZcd@w)Bv7@mxid|iAX|^T zF|Sxq<+Q?0iy>Ocz;NZq1X_>?Sm~zaYgkVWHrEOXRQ-7Ej20wvtZ~!wK&%f(nae-| zRk#W__Q3*QGt>L6mxuw|>L@2#XQp4tVzGv`wlXf-L)+~acg35>60{)kpt^^){~=F>^4r~L*!d-5&wb&_k5?0DK_aq?8=YTvshH_iebdN*1ghLddT5yn;>h33wL%LL zxvyrS?kP*ek?ZQ2%0L2Dctwm?7cEFEE}Ml8+Py?PP`IwC3?xv6_sLiW?gGpx>r21H zb**wTa%TUMNy$@fRy$rMJwYd zS}J&;sSG4gRk@v)HZxTDc-QPLp#=%wbNQ)nhN0FX#m#RpLjqM@r>oB{&h)jmaW(IA zq6LYPZSvE#&*ocm7wB&~4x*v-HdBoYm_T9}INT6!$@ci`H zkwx;L81vP|otWV3zVzX5Q{~@p{nxGxmVrbCcR%WzGFk3i-@Hmi0#$9j{Ah!YljRXz z%>?fDG~4g5W-&I9pU}9UyjDn*KjBYX*Q_URZ5sC<*9uh^uldt+p+)5$Bg_O^-rV%3 zbMh3DmyZ3}S|L$ywLd-k`zPDLujXAcyjH0C@xEGQcmS1;#>*4N#4FF#H-z4KmLLy) z7N@)kDn#=i7%n%zGs<-4_oJQYzN7Kt?ma}QyV8k{e3l?84X9FcVg`*6rw%l~|LXql zMQG}@3Dzyu6O=}k{Aj~a+rH54LzN_d3oY9_sc`7Z1XCGkL1Mu}KYCJZY-?Y~ya$N{ zs(9Hpt!!hjMHLz4PuCni{@~2I@ZnG`AXucmvpbB$;jI}}w5+0=j zs8d)*xt3_o5JCb~Kh7z_%(L+)@@g3(a(mk4C)a9749noD?HkE;74s;H>poO12v)Q7 zmIlhD3Yqiza2;N=vX{2!A-hld*%$y4W$LI;(cSWq^KCQFQCKTf`FHiwR(JBGf6N4~ z;-;4Hpc5|V5j(m3>-J!Ub}0N332mC z<7(2_uCNRw7GHJOA`@bf+U7ElK-G`eoVcz{+T*V6hFXuLG&HPne_SghX6$s=c3-Uv zUYld#SSwVu-RG|D<65_+nhCTVx4UbR32OznpS@N{gdTO*A`{kO`Ty%$p~^R-hn7=j z-MZRL?C9^IWq(;4Z*HtaANSDmx~w;T`Puv{Bz9-Ys_iIS&t)*j!tq+63ZD@$-Vclp z{I)Wi=DpYo?`fuBG{H!q1&NAkE{^J7*@}Lbi-QEJF#cdH11(6L^UbRHiMGEgn9m#u zRAH3DSO)H&$$6aVxbSvj<|s+Q{Wc?k79?U`I?)9u8i@Iw%+ z0iXqmAMZgTfvP$=-L?F7ajg2yL*sd%1qs~qG!nSZ99J$g9kXMRxb{jd<;QDIv> zUnbh8)&jA6KuuGvkU&*;bqrRs0>zx_7;LN+T98=PHxs>GZGkw(*IWh?sKVV$V;N{c zqFbd*^pH4TOrC9yks*PqA7{{^w>@n_ep+qQBDv%K#T8~FW2jCCeU(P-CZgbG+)lLec(^l3W;}*3eYw?=E(Uso8N(rwL%rf3QxzcY2^e$i&RefNH*evSmHa5vLf23n9v zeVC7Ke6v{|kkwoU5~#xG5R7Hu{^^58UbM2?PWkb{?#hq%Qqh9M<_DfMFnp)H@DFqJ z0|`{+>YA5EHrXL(XldTBMT@_0URt5x4*6+Pr=P495-a-WrjJs#$P2EtH{B1c6{@ta zuB=*gSpN>5@mdYe;iNrjA%0F375B4Wi29_3IC64%WnDfensBJBI4UnOm4Ox{YH$8T z)F&;(sn1LQ2Z5?H5$f#h>Lrd^U@ik|^?Oz)TDowQc}5nwO}m6V1fT7M>A_$v}QJKED`Bn=DZBFOT^V3 zTAHpE)(Ta8EcusjI}Lf4pAPKW!+L7i03|xM0DX5Z*y=QEpu(df;`h&Bp#_N-_X^PJ zH}6zAm1y=$kU$lW?&xtX;~hi`5)qSpX-ca#m5&q}VmfmqP=(PiV;LApX`#NyNzJE~ z+t2IzlTjQb{+g)1X{ur&x$XyZOa|j6sA@IEQ_HQDn|w7BXlby(Q+onfewy#UazC&P zB&zQ5)SelZb4Q!!K_pOxc_+qeh4GzB-MzGZdHK|rpN%acu~B_0NsR%?S1X$LSg=;8 z!klzttuTW9_e?)p{g?6b^>M>~(x*nEL82e6y=a{Lag+HO6ZEN3_4{W(I&)mS+-&G@ zQ%gikx6JB6Z*(4Ldf=~DGeb@~f5c{SaGBQW=kYJ&E{@1ZbSalhI}fqn%eMc19{PWw ziu;e^_t}ORJ=^P~=FR)8uy$JivynR__WF5fPik8CKQzbTFh+(djL#WcBDRM6C;aHc zLknfEOv8V&B_h#tqaSUZYq8wbZtk_%5>a(}lpl2)zC>==)=Z#J)w`NAtyf}}7;2Z4 zANyBmLE^Fc6^z9l=Zf3E`w9jUsCqEjnRW}FCr<8ZZdYh&de@mgKD1CQQlaWk)(VMZ z8C__BT#Ln{!_8SQSSwU@Ea^f|4O=4Kyly7YXTZ7r=snzg zPTbf^kU&-3n|!oX(QQ`OqUJRx-rM56)!on>OXX_ihy7%`LZW0dKf37BQh8#Ed1n;c z6{>!mBa9X#ZfEhMlbPn&yor%O3le;ck-v{EVL!nBfwZv< zv>?IbTJrZGG1|@qkdvpUfy+kYxd)0Jk zU9f=^99EZ{_L-v}56x1S_#d53diZWpYt_HMm2Ld36#Mw57YzzdAd#DU>8hQ>N0BMJ zhU&+eDvTl*iw@<)kV&oCr9v6>GDfvsK|YTP&{cUG%qJUmR@ILe{4kGD*v|0`K-cIQA)}mIcpvcW+@0s2DalJR2NP+IV#k5-0>=Dl#-P~!(_r2(j&pSwH zpVEajLOX8z$1JOMoHTC-={9thHI2x#BaXdmv@ZF!Uo1Tlww;VB(NG4$281n*$eV2# zn?RXes}-+_PVgG)$K!TxBjlIXavIU~cr;s4=8b)tO7OE)wEyK-K|g-sw1V8X1Sn~Q z{Y4ntzp~4(&Yneb!a{{_Dqi`*b0_)=cEY4&kG8X=p>1b<1kWrEOXL zovTwaZ6}XwmDZ1Q4c|dN@2O1|{xOS;joYENl38QUOV8ax*`a2ir5O{7>Z&0{_K=y& zE&B0?p?k=zsTT5L_9D`2?jDu6(CC~ry>kt=u+diuEl4bBnnthGi58(VrDZET+4{t4 zEZgFo`u`S|lS#i+5B+$;Fgr=jU5NA_IhWiRXIIOpANH0eY)z6DWb4gRa$gYDH!G5a zu?NZggai8Vsm}*Vy*vMi^3l1(+wG7_bl6d!PM=&`YPx4ATU20;u3E795Gg;muYT-X z@-Ufmd8e3ana_J|sWT5M?m05U`u=M?qmAEI$`-zmELQvA(5drQ-wj!)_xXk4r>tv} z7U;)-}YLHC5 z=IQqw+kzncz08R{s~_b!*0Q8D(5Hf4Mn-i6D9|JA_|?|UgpUlol{{IMi9OE{<@mMw zD~c8*uxvrtknO$X-zwZuqSr2I%Clg-jApSrNwvCqyHce8w<{&BUAbRMk!E#h=!omO zM&d0_w;)kf)LW=hGHAPctvap#B31m<*l{Fjx`9B|(gx-AvWFJisuC+!Ka@^Y4t11^ zc`UtXs<&MwiR>X*!~4@~lHV)MRC+Ab+U}cnx21R9RUJ#(q#6iRU0tfTT_t*gMzn9R zNea7A+)@8hF}6?6tCzm_wn7?y&aWTa>&m30Uty9hVu4b;v8)m^UhR@1yvsOhx)fq) zLE_q1Kb`hSu&KnsNe85dLM2DYLQeyMs?fl+S{;UwsRk_IhD$%`8 z3+Y+Ym-ZDsj0CFUr}~i=;w)aqjDln7ff7CK7bg#9%AI+7O^Q7_M9TfPS3f>o|4@1# z_NS}FHRcK zKX5&{dG&hov3_yPWk`&eVe&kEe(m$9yRK?m;V^L={Y5`MqK*=RKz^%2ANHa4{Edbg z&I4;`B=+38Nq!%BCwX#Y9778d^|o&j*PfrHmn{gZ_Ld^Qy^Bt6xj>x{p>$MXZ3Tgk zS2k_D8amahusTNR|Ha2HeI(-J6)&UKU3anfyDQ3#NAV0TNEpYf=wt3;j;p7Y15bWOsRzHhZ6ntxT}eIu zTRVf^Y4+{Rza#Pw(8qRiYp7Pn>JueJcdroo$!;W2Wvtb(C{JmBwIkAUYd6EJhBMi9 z7ri%=?mk+teR(-TO6l@N8h9Xz<=X9}^-l6W)j@U-)_W>>*l~Y)KPPGZ{LX|r(vt1( zrG@iaruTE*f<$n}6#XjLZ)^Sh;N$&|mP-(R;j5U4WN>RL=msl%-clFJ`43@vyb ze2n3>Y9ldelkJR@bT-CN1`>QM;l$}XZKN7&-$UddJKGL6|g^$`g5imADCsK22g!Jb_ zsefcB>vH;0`aDRqc@RA(K9`WR8K=&m+fpZ=s%%-UR0%Cepcf?ww?AK&LMBvZJC1uW zBv6Gl6olftPe@7>VNEu9q|YCE-H|YQWUZSYl2&+EW`#H9F%YOSp82!sU!|F&o3P#w zel>WO=uH+nug}ip@&s-Dktg1gf~_L^OY1^<*AqWo}cNvb>La zQM4d|Ybrsg;?|#CK043tT_BeJuB;#dz{g|(D_-ewkq#J8m{j`+X z_ZuNsITENE^1Krnv3~+zN4a(KViz7%WyLek zlF)*L@mgg+?8Y*0rR>4`69xiR*#8CL>bcKST#=fr{lgQ6u>=WR=?TKjg?~#i8*8(} zZ_XG9RB>-vAIAh?$>?x)pA(r@ zHDF8M+_K+SuPzd(I?R@mFlCf64&A%Ic;pe7Zb+f zTP504j(RX8P!;aBinwimE2pguoO@Mg<9;1uPyFi5(1JwmzU#=O#I2m@TCp7Kw4s^( z?a|T(0#)6buO?YyHpyu#NPY*Ib_e-A(E9|AAN;EGkzqjF>dfU?pguC71qtj0f)IGK zGK+axL?0QDKvlWcBgvcbgL(h(Yf+pH=~zbZA80`W`;8#n>F>+F3@gR7JBS3T$`0&E zGSx}obM1_pS=sN`$}{Z_q6G;)eofnl+q&Bkx*cO_J?$5L>vlG(!s#=-~)LHJ9a5xrzR) zT0$iQfhvr=2tr+_xl$HSAIFhT62oW&u5o$UJTg%;$6CqdbAZD$sX}@gx&;YdLnW=X zZ)>nsI(yE`F{ZKAK%nZeTUC;)`xIUVk6Ajjm?g%=_?)PZKD@>7vE*zM#!e5iIPQ3V z8{2gY5;(>P!n*nrtGYM9QThL4yH21gvg>5h_+@K8mWAG9EWV~ij) z@vP47PI7i=V>=S43TZuuoc&1n=o3W3SjCwS_0b0{NZ=SF2-9DQtl8s}`sjlMs;&|uY#pqtj5MN_B=hq4Fsy}`&W=<%htv=I(1|3X;P zh;An$S;6K}L>u9d;K#b^{i99f{OPIIv|c-De0{dz)I_R{aA-loCvOs2H7HU{BRZU~ z%+BB5Otn^m1ggBAtRr(LHWt(7sMQlnvd$MXNLnjF3ljYPbHY1cUiOc>iX*-j7&#Fb(b`}*qhAQGsW@?iv7czpn$2fMxYV`cjV>GL33 zkigka5H>Z=&JvRR^mz~oRQ2$UCjIM;1F5^B#g6j%CpJRz$$O-;U6Lm1giGm6v>#VNxY2cGApI(gEBa@YlRjh zjI*<==W6MXv3KqD)iRJk)!d3vq~3&dyW<)<~N!`Zv0-36I;tBOZFV2?OGfT z2~@4VJdqUWT1rXVSL1O8hZbkReMj8E#OLK`MMqO>A1qq`M*Y!$CHm6m2 zeLaW-s`%K&J+d8VE3!P3f*jghixwo%?-GQ;@#R^}9xvS^LjqNo9!w&8X0%LiiOnms z#I~6nx73!179`N`QrFI7%diDaUg;hg5~x~MY!>-a&dS?Wz}qscMCxhXBSQ-k=ywUi z@kxPf)~0Q`M}`Edu6ZmVJ4J8au6|kO&t?bD)IBn^Ac3BmAl!Z9!CY4K&|4xBs5&@p zG5PbKC)^|3n$v|1|5QOA8PI}+(TDqc`!(rk6BoTDB7rLFu_a`F|J8C@OFZ_uC(GK@ zVXu%SmhwoNz8=7soLAd*aPwU&q$B+$1L1Q(}BcA&}ZWNl1D0#)2ov!(fP_d~*&)T^HYUY~CH7lQkVTfD67 z-nt3|ygr>k4=`%i26DL6WNX@dUj0oeHurNks(F2AK>~d{L8!IQi|wB^m1<)m5~!Lf zttNh->vON~Oc6Ks{^lvF%~5DU!ssVa3sC-*!+h11(74tSt!cJ$gw;izMo0Ac3kso;D_{b`IfXtav(EdQ^3nUIto_ zFnR#l?v0m{3(d0^P_GpdsCwMKJNf592VTa`I_IQ@ku@AufBh=`(JyV+yQaGO!F~Cz zb1bC7l0|%^t{rzvIzN>;MjZYsp#=%_4Aj_C{9S39M@8LdKmt|V%j6^V-g&R2h?j+R zp8+jMpl2Wm1M}XOEZcJFJ_8b{DxKPju*;+QNZoe86Y1A28TEJxT981`KoDvqoR@qC zU)M)!Bv93_P9GAsv@7=jVn3Xg9{4BgJ_A~iK+ixBqV8;#BKObM?>Q2vQp$`Zw|Cd! zcX02Ol~S9}ee`yP79@;b#`b2vNH=a4vF8pQz>q+dF(0mThpf!wP*X?hoN*L$RWLV( z?>cb5M0${yEsYL$XfXh^Ac5Y8AQYYD!(s}A>V63lsN%6j?w2^6gP3#O5Zy093livk z2*O^MK&I3y=FnmQNT7}H0A2+?VBY~<_*CvoY zEu(mAPlzteZU?;4{Svewf!>E8^q%X(vWn+)zXS&SJpe*Oue-ufvQ>i=8%7$<>9S;?~t!j%kkZHzXUBvp!XpNb@rZ@5*C%! zTRRe{da!#wag@8y{gRnm9a7;ePI_xc3lc_8rfS$^>EgYO$y#ei0#(N*Eg*1D zp9>OBNMi=g^VplCq?eIh|9nWZy}$?LFd`#4CT>Qd-hVt4z*y`|?ZyRyNK z#ri%DT981WNNu|X+OyMn67+o>Bv3`)Zy*MZS;-{87>Bo!@4piiV`Y<+3W z4hRKxza0rw@yHb4l_~D1$MQEnnyh(CXhFj0U$y8`g|&P$Dp~WEkU$mpaBOMbQpJSQ zY;CP51-vEQ@-GDUuj=miX7A!Xh!#o3|3c4+w-RewE7_IHgPjPiLba#?T981WNDz8t zyC)5N8lihjNTABA^a`@(buI2KEe$>I#YjZ7Izwf=zws(Akp z)A|Q*?UL5oahDyln2kH`iJRLokCU&Yq3Uda79=pDCkV^FG-Fj~ev-6^FcPTZ(Rz{= z-=#b2vN>O}Fl}vs79=pDCkXeqQ8wm)o4zNE1giKLOw!`JiLXns;6}OiSRY!Dz=)n8 z{Ce7t-7214kM$veDjuaEX={T!yR)&{V{+@UKC~dgeH2bqS(hR;b9dACypTW@_g6?- zYadqbs`TMy7N)g!v><^IJwf>E@=ob#jrWqaHb4SZ+%F|*t$oL=xze?^&n2z3qXh}> zEpwv$$F9=R%SR+_ZGZ%-xOYy{)&~B4DoSqxc1c=mM+*{|^`!3VUwTJ#hK!T6){X?K z)|P)QcD2pqnakssoTRDF6Q!xm2QaiCftk{R@Gk#s8f$MWJufxHK%mN)9lfeVBCRti zK`P<&Ei+Ru9f`8O`}91r=<-^g<>VVv=#!a)q%lVZrDta91gbDITlKFBJE-%@DEm3z zZ?)31KXFZ!W3(s9d+=BNcR_gAOOOse9HaY*Xh8y3OM>vV?i1>_r@meW5~%7FS&kfO zJcgIi@K8Q!OU)sA8E8QQS4)BrIwFfSY&Fx%Kmt|#i4k5#tHI@^D*j#dGSGqqu9noO zLB|48_335wGLS&kE6*6x{d8+y#+{~bUEAn)>;7qvONk7+R3PvIXHqmqwCs|GHi)Bv8e#E+2iIpQ{sd2Q`V&0rQ#<-IIQTRVe}acUkF&5w9J4&w5_m@4qesiX z5d4{+U0H{)=e}c!=2;?vPX_TlPixv-8xz@|MMSTm+FXkk1Ch30E2a@y+I3^C>^G?v zhcghM;{KeNHrM*@jb`zI#ibknkHhH}9*5Kam-~;L*tDz>YurkdAP%QnP{lKO_+IK! zTPO?m>Mm)XC0dZ+d+D6m6JLg9D$`TaJWC`{#pAGiFSS8~LhSyfagw$-ffgkA3W?9o zOUt{n5ArYx_UQHhLKR;v@tJeTh7VG~4`cPY7A;8dT?bAanQ>IQI-;{a*CK%`9uMHH z-Ra3%$#qQ!z3rj}2_8-0#QL+nq+wS}NZMF}1giK5$9wJUNfo6DvppqkWIziNe5~XI z&rXoE>;!xcj%O<9nV>v6%%6#Cezq?wdVQ``KmWJv1l@uJUmppalt@>Bha+Hy`d@ngKnoH)UdD-#kh{{!(BE}m6bV%E*cor_>kc21mhL;Q_Ybrn z!DFPHcoDTw^8RPN-an8)6`$LAYme+POj`TrQr#Ct3liMp;KcGpr6k`!dg%QF2~=?p zhqrdG3t#B*;WhRCffgjV-^GcXk-spvitD5duCeLaJ9?ksyE6JQwn{;0c&9siw)dbk zL|v<)1qob{sZZqEJFphkQ+oeE0#(>5)y)3GQEWrz$5KhPf1m{kT#*SvtA}-2hmhxz zHh&<2Dr}X45K@4$KbH&oS`95o;EGHTN~|o&d>eh%`v(%J!d58=9yxv4@Bn9ht%epP za788v!42G4o;)df|3Cs&*eV6#X8pHPt8$<9>>acqfh#igIhK5XNGbjA==}o;RAH+W zgqEJ0CEs1wC2b!EElA*sOnn-#-~?&e?Y(;cKmt|RDg_~CW(#TK-3|KuffgiiMJ5Pa zC+C&Q^ck-A4q!{6!j#uM!m>kVLNL4u#Tetv@B ze0nzhrA0gY+@K)_0#*1#ogh^7R^NFu_*U}NT5;)XPW``-FkY*m&ErWvmyXFX>ea>n zLKQxPCkTJW?IN`wwn~mx-v@yA0Lzf8-G7m$9c-*NknYLTvwR*F?BCT;O zTk^7bMgmoMPJ&SVMOB(W-zbr48Td8|tf6ryZa``>%@Q*{d3@Bjb*+ANk-*xjS$ess z6rC}v9%sP+LKW@;s?YX)ZYwR=A?dLUv><^|3U#DjJ4f=JFhSpUMgmp1n<)sRl%q83?d|pw~;)(A@%Tm^!XTRG^MHQc~l(Z=4$Sbnc_rptl2MaAoU^bl~92j&; zDl24jXlpejP=&k8f{^>l5$V!u-|zOFk-!XmL0I1Wl;qyK?00+HsKQ-x)xYX|LaJAg zI415~jEBY};+te6x`<8UAW0kT=9TU-l zMBVw*$cTS#>9im`-*cHJT@aJ=H;6M3sKRp+gzPnH(S1I@DHoQ;r^m?jtBAy*wUfz_ z44-%zrxw?v(?^_CWOXdT|3VdB1wlxi-;TEN?yk&M$1B_c4bC!$R4%qu|KD=4vq{0< zR`W70E^bCQjBl$vUly4|Ri)st? zR)YV9D%{6a^Og!FNDpK0eYeAl1hz^+n4PjmIyt}Cce}`_!u@DL$Ts%4G}yJZK3<^( z3G6rOvr7T5r6PY!)yFF&P=)*Is_*mllN5U>NguD!f&^xp3c|ULSy|n{GkUfm5~$*< z3?*%M>7H{o_IBpW?=lCF;42GGxaRO?Rj*~y$1D6VRAHWjAe^Fk*x9`KzRQ3>0<(YB zXI~$Avxq#!zss^f73OQGZxFbcgRStc@?9ne5}3uTjwNw9*d+g&4sFee|Ai{dI}wB{ z4P05m$wrRKH-<=PLBjZsl#*XFGN<*;9BXzk1A!`hYm6YY&fSsj+@4iAsJ_iA&#C$9 z3(|e{zP3JQJ`vohe$1oidaPgd`pS2wU#sR+DyTj+T9A0(WIma3EK=W>ffgj1mz+b!$1dh&i2uaU z?cRNqp=zy=KoyQFf^fZ93HCa;fZlfT`AVKUC~I>#K9!{UqF?i}emfr~YkQDrL4xmd z^GwDCt%epP zjIG2or6pbXp^LIpod=OX6}BEVTO`h%#ZI26UtPQhJX1l>jlt_C2>AXxLxlsad*qCh@_ey5PYy)Z%e^rD-T`@u^^i#p?f zp$e~?I;%xKqt)hCSF|-JT9Cl^(HZ+W5~#xdF9^3Pcca@|R24g^UItfLHNQkV&RoB` zevCVGf>3W!d-~CpiqhhE!`>Yd+Ohh^Je?MVwPzmF#qQ1a#zn+^N2IIpoCINfU>o{$ zSPeNqU8|u5|5rPXzJF$)R$D=sq!Keu61nid5a}vT+tP^Zbvw{7M;0?x6l(s4`yNt)JV_U;7sm2dTaf zT96pLask=lxsP96zptHW(>GPbW@@dFK$Ujp>RSsrQ9f4-n%$)niCYrS`c0lg>>+dX z`r=jKeUqPgQq_C(^2}u7-t1dH*DXlk6;ZvVoL!}&bBpTxocLd;;=O?HzD69GAuXxp z{9T3+61dx|#$KNsm-4*MNVR=V{4Z2tK9lMp&$usr4c;$m<1SkMh2S}NN5*-u+>0tG z=4>h)OE51>5L%Sf8MpCPnVy6=}B%8CsP=)zr>ibI$hp>FpJaqpG zElA*Or>@Tf)whIrhUnR!NT3SySBlX$mA_MK(J||j`z;_%7g434f>{HvB-(~5c z3iJKck=m&RdpB_BcbR}l@Hjlr#;seR9rGV~^1Ez9RPp#e&k^3`-ip;M_58bxMkILl z7AM}fZN*MZ5%jEL{4Z4D8zt5E;;7H1KAo1uG3x)%rRvYIAc61BP{;PPH4f3%IDD0& z_d&ki(T}m;s9AdUXnL$+4>D@*x0zG#gGg{ch>t$rH`>#pxq6ZA>e!C|g(~d-g20Zs zvbaJ1`VJO8g^Sq&_zZ<0ME-SEs(vJg9-&7I5}0?OzVocbLFtc$_w?LBBv6G}fr4GTd7?#~F++r}mx(s}@HI6_%ab{|wh^5^ z^bA?2-a)h=!Pn}%Ry+nkwHN>rsKRsl7H1$3XV9-A5%ed_vMRS~8K`yB?4*nOa z@G7WJ>ZL_FsTSqraZ3GcG0TR>{nF3;VlsUhG@g!DSM+E>f=6CB@kj`jGE{K-ZdV^w zm>(bra@3Iq6g?SF@Tk9guO0|~}y?>wu3G6F^ z;GLR*jXD>p_dz63g&7`#@Y~}YtYFt_`c52Lkig!odVS$VS?g1^^xZxrP{qf2o{@5O zNkx`vVcXG-;*o|bCQO$LY;l=8PypFElA+I zk-zP+P}pP9`yk)J(2w~p2k%jQ|AWH*hi*ZF?}g~JAmnh{LUUi5Pmig+7XJ%X*qhZj z^{HT*;dCbYNcG#%f&|~q;AQar4+{GqdaY1}W6ZZ5EDAeV`hW4ACjFT2P4P45J6KfP z!9oiXcz%L#twdqzeY>Li=z|2R_^tyVOMXvjDTURmp^rXjK>{<9)aYRBBB{&MQF`tN z5~$+OWAXfw%C>z{iGRlHqYqk;;Bh}r4BY=n3SYKFAAOKO6^{Y(Jejwy&aB?91^VcN z79=o3Ox@dFn2$|qyGGB&K>}6$NoJn!vwwUsc53kgee^*K5}4_xKH;{LGP--QKKdYm zD(+?SyuN;NT~^^?f}WRw79=oZPrV?N9(y!NT7;8p~5q^I@asN?zC*6=U<@( z3CuiH-);D`4|6&lqUU%afhykTc^=t_CWBb{OV6nGE+n)dff^eGmy$VFr{M*}f1at>4mI?}KPT0(+Vuylyx}3M(>0 z_W+PU6=rg&-#7SsgVeC*0=*BS1qtkFYJ?@`veaYQPQ4Ezfhx>M6NE}H)MqCC-l6wF zv><^!O%OhW9QiIE4po?0CkT6v1hA;Fvfc;Lf&}(7H5R_50;?|{{4TE#RhS{D z-j7|?S-~A!^*)FeB(SHc5til=?AiIvdj2jFsKQJ~^%;{>ZQ1TQbH2-gL;`!7Ae>C; z&N5e<{9T?UsxV_yeMfw1Uv?*VtM76-k-(lN2>nhBVMCr!{n;h_FI3^z7}7j|z|KCB z<^iAu31hG2*&P7xBQ;yFdUj9im%k?E;- z=ms^)i54XA%LS@Oma`0r{JTBvt*)bxKox&8H!tIwZ9Q3B{RXYx_uG56bqf-~SM+zF zlXv=eO!`lqPAut#Y%lKp0Buo04r&~1D=g|JT>iaS@0?y-G z8R>*Z@2<4KRK~v%=_-xT-Xoq?tJuDI+1tWXEpx6m)bB_7nPW|i_oHHmVytuKm6ic- znBkryAC4wPdTf7xg$TCI|SFsRZ9C5>?SgtC`U70an8xYoNR%RleD#XH`Gp#=#S>6Bi^l*{YX zGJ0KzW{(5@w7k0VRzd<*{8&jN&fM$4YD~Cqd4B(>gcc+Uy!cHo!@El-wT$J{`>@lU zo>+=|Z!r+4;>SuF@mrq3>}>PbmbkscCA1)McH0rXj6Po;+SI+&=R;Xo>^n>F^|}TE zRs2{cW&cdGc z8Ex6UH;Rou){OWl(-q6sM8mgIMvaZu2xW5D6)JJRstYSPZkXlVoR$nN_;nS0n}iyB z&5@C1CIc*$<69dDRN;41)Hfk`1+qSm7Fo(ggt30ThLRb}Mk#FeJkm0$8~LrmM5Vm% zQgS6mYs@K7v{WfL3VIWY2S6vV? zp03XR*)Choc@|;Jc^=s}EmZk?>o8K|^bGRyYJ^hc?ikYM-aP%xQ#K4y%Sat3u><4x zSnhr<&d`Fyf{ath^1;!{z6=vpqM)ypS!Qmxq^eIlp=EIW1hVXYFD37+sirbkJ_uo* z!?svL{K^~3K%!i`ainOkzRJ6P+WokaBZLVHHd{u1FcPT3`y>eER|K;&?^av-`4PkY zKw`Ce&##W`tJK%;d3fRC%zw#B%i@~MK%fd+k07|&TCny#&RZ_7ab=aJt|fhXIV%sA zgpEMudyFti{scIqnPGu zip|)tm{XQAr92D-s#0sLBoD6^P-BBs7_GmR_!U(OEOmYuro|dDQGhsdk0#(?0R4@Eg7;|=W zSo)4CWVq)@T)I1tl=xar$)&f%GF`)1-LiIz>lY(|Ds0n&&}LvqCM!2AGoL<@nl;)^ zik4|8cU)4Kv>CXK)a*S>u2-#?>C6Ya#W1q}hGpP}M+O4#&7tkv$$*NYJnx@C^~^mY zI>(T&tK>B{IEj%bLVrvG^_hB%x)lJ&9a)`$NvX zM>N&SZ9yC6dh(K`eJR0k2azBJHjoNFFXRhF!qhUBG-}1B=D%o}r1BnQe^ts`e^ zGtR(_y;*~a4=u~P8wpg!l-)^^N?odQzOF{Nx%Ot8Cp@%#j@l#DD!r4q6t7ndh+3DNlPATj9D4wAA(vHktXPd$%Zy*jbM9d240Sne7KRAGA)gtMtJ z?BlT;mK6`~8QK*Rc}njf88_vV+g~cEmQki(40Atp!xE6~p@Be^v48x!wF?{A_Ag7$ zBUhzIZ?=#!&WptgeM^%kYqpWF-F?Np1B#k_hHLqvS*dPUEhk5ONH2qEqh;2~Ysu5* z&LnJ6xQVD+r9Eqr?V81-)0^}&*ZmJ9o;BG(ViTW=i@SxY=W()eN7ix1bxXz}PbIX} z+LuJyIsYLZKPZ~Y7_v}(uXFL6mf?LL7|KAxZRjS_x9cJCPxmTn88u&bVnctsWpQ)+ z%RrzCuZSQF+uW5UWV&l<9)D57>r*a#JINE=P&~T6u&GulA>CN7FLx|$ik>%=fy9Cb z+leivlz2Cyz75a8+WFk3|&5J!{k?(o1(Bdmd=ZJ!&T&4Ep z!MIiAc6Kka+`nb|Sfbx2^$ksbMX}@)XDuh@eVf&E3ld4C){r^F-HCfZ6SY=R3tBLt z*Llm@Yp&^IiB6yj@1{DI?5@fVH`;3{G`1)kHe)LJJ-#&=&>?|@w3tKgIqHx;a(ud% zLDD>#>L;wsJ!qHZpKPTK1fQ356>E_|;y(2v9p+C}Yqc*tl(k%M-QqxAnpV$GF#GPmY zpo;feeszmaXuw)lJ!Og4ef`Xl5SMo&rGh7tMPAz4phS@XRw!Y<<(Iv+ z3}=oiyy}8b`dLP{eenQG)znrDzlp?G5PA*q>q>&Krsr45ay8b{=w=&+79{YSPl7PQ zITNFGhg&j^Y+)$lq`eNAqxP!e2iFm#)qXB{uok07SzZ=zX1G>JT-w%(+`T=O6wJO# zYl#6l+1vIvp6>5 zUW!V{1_D+5SV<$~ox_;5?t6>hVXK4|B+&a11lRgQSkSsRmM15=8VFS3JTC~B-u7i5 z!=70VHD8hL$>=@<5=Ot|ex}~6wd$ADZD8~=P=)@AAoyJ@%wD_JaJW^;yc$=HxJt!$ zJge_vY06liyu}^!cKwrxDXf*4=jupB=G*LZ&3cCMu^n+x7}(LU?5Os`~ujr!?{@okH)Ogt-!))K>}N)APo4J zmBqV6vRdZ@3W2Ul^Mjr#8PZ(z08Htf&`AJYCn&v!b;35!)BazH4v!6Z*Zv|K-049{mRO0e0=7@ zXhFg_`V_uYlI6Ne*k|{w1_D*s76f79wjyjx-Rdm&k<5lxf&`9s>i4|P2eMv!LfPE% zo(2L{*kaVLpWbZDN-xO8W-9xGaCSy-0KW^NddP=sux;;xScMXIg7B{4l}1_+&dBQG zzg<`sU{W*BsyARGS9-B5yDl3DR2gg4G^`8D`Rg@lOH*4Az8Md_CFATo zYGxGk&h5sOFUdjpc(yl*%X8pB+y4upXWRj$(CPJJ-$sF3WTCwaZ3=^7rhKTKlOcm-P*D7pHigOv5AH=M*?do2&2n%V5N@#EqR<- zY#>mD?*~+)wR>B$##=J5&f}AU(1HYBLv;^wZ8ui2;#tY{;IR_fSfyn#R!u6@++6?GZPPCRQW)oEHL2=^dym4fffQNJ{veK0HQIzno4x=avS zkihkhApA3WAoI*ONy_q!8VFQj4b^wb9vr|z+f0)(`G*9d1qob*saY0{`m>2o=SvIo z6g3d2GM;&AYCK!qL{JJXOfHD4c${DHU08zP_@aK}_tFXR;MF-R(1HZc)ap9weLU-Y zdlCsM7rqiL7@5F-Qs2J!xB3i#Z6EOsnYa=yNMIyH5c=GUXV<4cC!Joq6hZ=3+VB6* z>Pvy zs*HQv+m?)ALwdSPhuv!jp#=$CQ}guC z#4+cOhm$LATCxgN7-2CILY;W#{%U@5`GIHkd!GKbHzY8kqsB!~#j^t){F9F*MK8zy zLY4M=XrI!B)4s`?a6O(qbGRm3e2y8~6%rVkQr8A=<5}eWg-V|rF$Mxv*wfV6xpf>H zI{0Do;MJ+CuvYy3%UVtF8VbT&^`2jh^|V)-U(j%Mk>K}Sr`6r1v%{I|!vOo~5zPz) zsxXSH&IWsiv4F`|d!N-c648PLMsC$-c*_iB&mK3o=j;=lh!!L;aw`bGj~l|u-ixtU z+Ypq979{XHXo4{7&OlbBYl3~_oInGCDvbLILgjV?SxfI?1BAW((TVKv9AN`Llj)B<}Et0fUFNMLkW{YquazAWffqJ3fJh(xp?!Dl#L zE3b>aSyIj&c4^FH1A!`I)VbY>Hthbkul6tXmM7v~0q!*LnOc9!L(Oz*5X~wad~d(D zXH6nnkifkV^^HL9W7v7;`}V#=b|j(&_gnCv)VFvX?ZT#Zy=qtfk_}}bfqOb?mY$lo z&Z%fJZ!hUmlM%~1nxAc{Ucv2tDi%$M+`n_AW&tzx)~bO zVBJO)b}VoBS0eX{^{a?0NbdXctK0Nr7>lW2$l>+Zr9`wKf%}GnFnn@2+dbdg5!c*E zpo)97yo}z#9oVr8f7`3=TWq*i+ym5A*cQ|s-d(L(>dp*~e!Y_ntpo|Y7E-tFdCo2n$D1qtJM+zx8WXr1hi9A(xT2vp%tth!%2tRV|~ zo7XY*lAMSZB=EWk!jM8G*@NNKF?ylLYK#tG)BwNqDF~~wmtozmRB>!tooO{%kTC9y z{(ihNn_Hr+qenMa1A!`RJ%Z3|nU(D$r5z=%Wm=6EBycBIT|q`m?0u0Ej=Ou@3Kv_tMp9RJTAjCVQAenc%w`ElA)uxCCMI2R}A(eQn34 zzw;RgR2lc^4_@$L?U&bgBm{V`Mhg=7MGW-|dHHiP`9Tv$0#%qlAqZaGN=jXt z4|jA_gwL@-oqoGzv zukgx2vrS!~l+V*rE#sr*e}tWNcoaz+?Slt`B$-JjID`aP+$B@hg#~ww5cfbrf`{Pl z4vV|H+jP2dXK`B`7Fl$Gg~hp5lZHLD_nUkF%k!M`%iB`&mUK-|rF2Gry-C-iD^Wq> z!4Nlk@Z%igKGw9GuKeDUd(o5KrmNL!C2?ZZ*MF1=|Agt5=XqA5GOna29dUW4 z+97AWivP*Usow2JO0yx+`nSTlq!>t~j`W~S2hUQ+&X46W7WX;D&o52X$7zKn0$q4d z{Is5(2b9qty6c0j&MQ$tqU<{pRm%UWcF)2~hSM|uwaU(Usd`1<8WMpn`B{CPm6P>8 z9H?*iFR&7y58iF@HU+7z*fh0HNDm(4NQ^V{T^^wO^U{tA5|)61v}Da`#vAm^ZDtd0 zwAGWRxJU%L!Y3D`oA*prTfDNz7*>q!&Dl&ZwI<(6RFH776`?g2PcULEpIMd_TvJcK zbJs;8(6xGR5qe_&1odXUe*8XmB{pOu!hH4H&iPjESXG<`yN$B{uZjzc(ebP=R(F#KbjeqBv3hsb zGwFzS+w<8yn{%Q5Npt0I?6(dyydq`!w<9>HVi1>>1dwriTR^PCkwTtbN+>`fm& z?58enHeAL3#D7V-c_iB$_evX5Y_t>uiT7@nr`pE^Q_kk{a(tNfy zJel>~v`^XHVZ4uV=S1B3kH1A5b>*Tr75h4yZWzvEB(zLm6HZ)EsuY{_QODESg@vIV-hO>WWyi?wd9Oi=x5;NbFq}}rkB$d_( zqP8iB)%DED%#rJTP(i|YhQ?LRdeNS}cXMNXn%|QMbe-bmI622C;`?$CkC8E{Is0Q` z5q7_k#TOMM9<(e@tA7|pT2>dtnAQzg{*9$s_irw~s32j~0^_Qzqw6xi*eY!46pKWl ztL26ww8V%BB!{=CA8TG#Vxynr=?`R_W9_f;mmi?JL^zn|Eds(F5$C zZ=uosW{{&jy8Y-4j2OT8JFy!RLfDYVyuL;|XjhOB{mRwO(@AEJW1gOa)r$^dEuVTy z1iJ7Fot!3*b7iGlbYPQC<@QAdiRFz8(zqPc$f9PV6|Gs!%%+`g%YqKLNCdj%J8%DV zuX1#BGMo3r%h%{}?Dz3>g*%;JZ4P<#A?!bQ?pxr3lGHbWU60Qu-3JmcM|eUw`AqCp{KB8YX zOWAp$H@p70s`RXoxRB;Xolngn6&j1Yq(#tDWfosmoO{2TM4$_w8*fEB6js*e9>f~? zI!Skq_q4|+AN6;dPtG>#z+;sB_8X1gGMJ5BQ_L3?B#a!+cvgdQwxZWJ4q?~&IY|V% ze*B%8C-!bSM1Pm^X?0rpxfzz-=j-y5}Nviskw`auYqml8Yu z|GugpEbjXoIstF>E&`s$mdIcURtORZg>*H_=~%}F;j zT5nxvZOZHUg^WE~{pp>VZ~S=$6(lZK%S8t?T4yac-k%f4B7W7TG>l-Wv6@7n>qOx^ zwEmU7)~YUTIkBzHP;Eh49Ghm|s-S|zoGE!|qy2lV*;=>agj?&9T8}}gZ1~h!5`nI% zyYkWY2M=27hX!!sME$!NwfJe)9Ye<`s37s#CqMnN=zw+c%ubxh*xyin6h46c;@U|f z&{aR#jrKcq#On2TI44HGEJ)9-NoRSE*H%zLqUcpOx_tg&>*AuJocQw8MG?f*9-k-@ z=z8nxVZV>R#wBoK?J`9XSJmo{PEkREjq}L7k5!@{JkW5OBJO-e-hvW=u6=yOD&B|F ztyE5Q{(Y??p6=o2MF}cMEG<^h{ywZPk~xuO#C2spe}fHI*2q8tT@$^F*vr+J4QZV4 znDv(;N{RQpDH*6B5uIMdUam}A`*LD=z5HzO;`VG{?spP_uEJG|+spKWkfEH|w$Y0X zsM?&ZpX08ff<(lq;?#e^Z0o_DA{Vt4s=!>sYO}aLOd`;=W5T1rO^6(rvJc+;fyUl_{? zlP!@ANsCwNxvbGpLE_=*()8<;v3{Eyh^q?o?!j``e@fq$*eDU`x_YHFtyXuHZ+f+H zoCs1&? zJ0F}Dufd($33M4x-In=2jHjy&`1k4B6(o%3X3KmZ-S`{yTYF4{H)to&Wt1LUX1Ov- zi3X*_t{`E&e_Lj`GD@O8?%$GVC(vco0$XPNFiN`)rQNO|VU%NAX8kZ~lnyn@PN2)E z&9=;XZq!;`)LL{IbjAu!JRfRe zyyw&>pUWu`=rYd+?I33M5)t1Yvo zcH-?W?>Tj7ckK!iMvH38Y^l3sw(UB!?RElPM!#aq>~W0#Lx=vut{`Fb47SDg9%oHv zAEmeaw~w+D=rVdcTV~H`^n?18fBQkZf`rk-*)n@hqp#JWueB5CGWvO2W(HvN=X$w+ z`*XX3gwa#mGBW@pXV4*MuoLJq@)cWVCgYl!m*|j}*cBvX62JPQA&&t3NU_JAp1E8?=dRkgo!iy{4sCZLTY) zAN`$~AvX?x*aixU?MmC$+5sqcMN zfT4nf%lU7F_nfw&6RUGVJ6=KOJ*Re{zC|L?6}jXS;XS8q?BHsgIPyz1U9`K$x)x%n zAklQwXTp0<+vFFOIZ^nEpU!(uZF^{Oi9pxwtse;QIroihScMbaODa0=Ikj2-B^fG6 ztU36R@Sbzu-JKOVv1e=p-MRkLjHGj=Bm!LlE+5F8Q+<4`Bg9p0ThWjci5XG7eHbc8 z6fXLagca}OyX$?0e+l|u0$s+{`eojSaa9zq%B~<`#PiF%4{_(b=TzX%?F71vr*6%B zAI8&F;OW{GB#h@~&3qq+GvA4> zC(vco0&8adFiJby{cmZvD@YjS*qT{Cj2gv;|68N%1iEn4_p{bAsI~U-AQDD>v}V@x zV_oiRyys+(y8rp3p4$m@;n+|f6;-IjhDEF^59}U26~hLnaUJ-K%rju_g9;K4oO02*Q5&rnJ;gkO zF&@;#cn}G6h0M%GM-7}~t^H3uP8j1sU5p1&L1OunY_wF^Tx<2$loOa)B7v@?=T0>L z<0006F8Of+vsYA*I6$({&0B|BuNf+E9;VJ^ICB<;!U=dx>lFF;zWPub{mwl_Wjv>*wjMHEZT-#+ub0TJiLr z`ms{eB|@xC{BRjid`{;cij8f1gX8yO{I%E~=Ei!TK?u3jvkNfFM zclS|HLE_hW9`+iw={GUM@*}epGetf2o(n6g5_CyGy6tjbimyw94s9`!n6xc2#7te(NP zDX1XPzeW*zt$lh~%;K2i=4zWZhwHk@&k&Krx^Yi&0lu@Z;5C@M(IK2qFX2VI(r z^;*nDQ9;7DX>of!AJkvW`(Q4L1iI2vz3p{yho4xl#at8>Bs~5qX|LxC$BB6#%tetv zSFHs;{0%m>HnfR38O%jdL1MARhxdt1tZ6yL3=8I>NTBO&jnY)qLF)`bU@nRZ5>A_Z zspwJn+z_)Ln2RETF8|79sOUKxXU-HsE-ESTfA6j;O-1kQ^;yjOU@nRTx~7gOLz70V z^j+W~2+T!ML1NRV(sXl{mA8uZfi9zsu}Q5D6C+_% zkTBX6o7BQF(ZV5tE~BlqNv$Y@R@AN_VYH|=(cAGI5ScAC8^l{`{9ouYT5y}_6MyzN zOw45%J%BxTHu?{n=$DM1$ewHSb8#|zH3q$!T|vU=;cTK$kxh(Ce&#+3-({8AZBZkK$nqm+A_0OT$?}z2_wt2 zWoECq{(%I#jLg}VnT6vT3o1w$*|IG&3&(XFB+zAy0Bo6~i63i4gZ~{H*cBv7UUR6pi7<+#u%s|fn`CCfdsnb znQe@L3KCcr~} zqZhBldB&*75rHlvwy{Q!1S&`v@r==(BLZE0u>~T z{J~fSa73WX$cc=-gGiu)gpmgss{oD&bjd4NNT7m*kp3KBRsAjd!gT}D|jc0gbZRFJ^A z0XYT|=)(OPGJy&bIBw(LpBJm5C+im!Q}%)^I=c&fd?io~_i3+2f5}bPtcq5*9BiYK z{4O*H|LuYPJzMh`ma^F^>TLZzrJkRKMgEnGcGml;6P;VAIYv9v$tnHR^tnwXn$Mn( zuBcyWbw{Z?%EIvfB2ja4Zkq3Fk~;Tua~`ADi%NRdW!Ds!j$RUhF8QkZUZ?u1Z9Npv z*Ckks_3qR({H<+Su5fi?c6ZwF)<3pNZ6ej#+uZ0c53;C_rbX}=uOATo+~A?g=~$US z*VR|9H2PPIIx1IJP7K~*)yoYWuT0xjoS}k57Jpaza%@3$iNDxYTqMI!FI8;1;_53C z=z6)=m4=Qjq~@3q%n9=%KfQdO8A=gTafS*K!8Kj!tcXJDppqhnSB#&&W!Frl-J4<( zfvyg5u2lSHL%q}Di`?ADtLV;gXO-lbf()Nx)C3nw_`3G68EsT73;e5;X;t;B?M^Aa zzsscriQ--J(mPMvsT2FO<1s#usHV?sd{ns-TSzKb=vww`UK-k=nY#FxSPg$uySiS! z=RxJwnL-Q|B=Xxh!GGW4RNMBPn9#R|z9`P7lpRx8BG7gIQa<`{sGnM5g;=A{Mr!Kg zAM8?6KNe=FAn|KJe(Jf|Pd)3>nG-d7*3zp?-mL6cS41MvRjwXi)gM?>bzTt2iCueZ z=^uXEsARiTg#Q-AzX}r0m-5phE;ZFZ%68#IMOsI{`)s)qwY#W9pbOt7|NSV}y88E~ ziJI6ssz|%0$p+`Y0xY}`{vh8Z?$c;g7w@p*o79p zJV>4WyuDQC`FR;YVBJQdwR2wDVap)(%Xaa-K?%!At&T@qw!iZY1zqjxek2`h&Q_n@ zsiHb2P(kAA{*PqbiP`GW?PC8`pC>(7^5gj#WxH;CE-l8ffPTvgq<#9w{*Dkt^HSxv3EN9^SIvs)q?-#zAzd-k|k4D<`%j1+u4i?`hRyXKJV*5%MkzwM>px&(;w;Ihs}qW{($N*T%-rmI!p2 z=47XLMz&FdM>9@LT^hxTzFVicmR};>Io|EMrOx&iuETY4=cWCl*~T-gwDnJxXs96J z|2-GoFx^LeQLY6i25*XCO4Wth&1%c7qK_I~E0%5JtL|Q9mTRaW zF}ieaI(N27J$XrdE0ggqmTkBw>CBO4lOB2|jq64)XUaK`!kofzLJap>& z7q+7}MBCoDOCsy%)I*DUDHG_z^5*39$fqkyczQ`IHS$*t-}6c(JDnQcR_!~qfhxaq z&oLov+oLnu4ez-cDo9jnm7RJXYNO^_)_`AC{pBGnPp30lXhWGm*UjzO>AJMm>gc1Q zT*@={5??`x-f?5 zecDgRW%N-*jn?an;gwZZp#VEB-KX?8+ z^?zHVwagvHyiNQc1pY51MA>Dx{;^i(V_Z1~66nIK{n@rFqW?fel$dGnUsy%2kM|@K zs30Nwm8jWIt#x_E>6k#5(SKM)Udm5Z*%rVy*M6w1nmj`@N;naDw2_w*krfAJW|rib zJ+tgQIFJR-yr;OO&D2mq!p%7w6~7rc{i(=awQ9kv%J}Qb>!jHdfv%-IN7)(OmUQPi z3O@s4VOMr)(gkI=`y34wB%Y^br(5c@A$#kIoZ&9dWES5)qZ}$VS0d0=rge5&Z%-T2 zc!h{@sYyIbn>tSUecVdzSYU3ty|#&r8s1zzzAq15r+l;OTU)7ndDeHMNp7;#p7o_x zOJtk(q$&pvuGa7=;?qUi$tk&LBD=zRDf`x~)=)tL-=>pOq38sbT4AVi>cT3CK$m<~ zlS_rMmoZ0_EdR{Y@DB0L_w(E*%l4Y&vpx55?;Oq+9MY6}K?^igkVqSxlTJJ8N0$HD zkUy){A0pUQzn#jKhKnQuUEBGnXr*&Ca(K7MuX3iwv39klDwSrg(C~Vfm&r{NN1I6S z)mAD#b$Up%Q7)2w z&A&s*HE5BB3KIC-evWIIm;=B%X!J5fjGeJ|$pk7$7~@@%Id(S2=TwZ(Q9&YL<7fM? zd!{|F%aN8T}Ozv#O2>RFE)cUWk~7x;08!TIT!wSMH7TW59t<$SbTKR@zzWq{g>&ue`gP?H4NXT0WKr271l zDcaf>B^dTH*hkIfbFbbHvXGbdxz`$xsm?YfYXv@*V5lI0{iBmp%sHa3C_PLo(p4tV z<<93`uZ}H9j@jp4_dmAkS$`X=y}MGJp@PJLMXvO5^FpLSOELGFV~L;M@AGucYL*Ff z6|C(_8*pNTub6wy%l!0$=VxgPZx&;yAR+o-+Xio=KhNVxK+s;OHS?$joE z6=C?E(Y2D#);90ZjI6ZJ)_yY8)U#jOtu?q;n4yBipriTd+&A?}{JxI-syfG3*SjVj z(9S+BBoXMElGBCW(*sHPFJgXI8Bk5n+UKZNIjRst1&P1=xzJYU1Igl8ku!`=siHsg zKCh)$FDMb{3gIgo5v!ufQogd`tUY|7|Bwka%u#vF8l)hln|{*8?l* zP1N7DeP%C-K$l#jh8(M?dltH_nK%4gF|pTeB+_c+ri*AQ39TUJeNObQpf6y5Xk{OH z{#awN6X?R){6Di-JAv&Awqr7Z*%D?o@_lgTXBLk29BVMm_QfS8<{`_ z>k7t}2~?24THu&K7uEuqKn2S&#+C_GkiZh^m_V1~H;C^XUD(gdF;GFmak)YQUD#90 zF)-i3{0g6lOrU}U=5~$=bYUhd6IdrOlf|bX6R048S*>FNU3h;ofeI3s&p9U0g-@NY zz6J%ew->G{uP4veN^daHaUX(6YROpj)pY*%wO~^Fag5sdwuyQy4kj~Bi!tY@EedNI zUV_cc+f8d$%}l5I1d?ATN2!bNn`onvfrKrNRo7H8)6NwF$))j8oVani0bA9(5PKim zTSEm2r^6hK33f^81Lm z@5&;kwPl`47H#xNGwpe#GpX=0THUeTOv?}CzwtdhUR}P*OefXvLYmKy<}u2-o7k31 zt=X04IW<&}7}M5FE84mc*M)JMxaD7%c|U2wy5uS-5$GD*!%Pb~1rX;VBF3w!#o7ID z4O!S%Zw(bBPW)n~Cu#?fISoaOpfP3HR9`DI>9r*ST@yN+Y4?5sq{DsjtkSlX=ch%~ zX3cUj4HYCf`I~^qgU09}_oGP8K!`?M6%e>l$NTnT# z#!pT3O~*j;Y>S8y(1Wsi#k^S~pLmHtmsIkdd`>=5+VqLiuMHfOk)fOE(Ejn{;lg;e zWDyT~+$n)9T^FNz4>r^O593Ib{VO5o*iTCHcAG%g3s31{zkC|3-izmwti5TT= z1=zX%?R4j>UnBxu?Q59nv7B+_MX-o*^^%#@h;OBrDW69}1&NvC%`~N792p!WVr&{7 z&7MWAR5F~FYFH1jy$aGzbbYfB^2;dEUd>n)$3~rPL*ewPV!<=tnp=b}&hix|UuC9ym?%PFbd)@!IBQ7O?xn=J_?1;>dPd6p!w z#%TjJ`gN7In_usf*%8EzUvFq16K!%dg8aqrw&`(B42>km=8713Hpj8i36r(3<0~{& zkhnS2M6<<2lC%sF<2Z?Bh1gu}uV0o+1iB8NFwyEWBT4OrB8FeR6gH`ONJgz?o3tG9 zCTg1*Mv9D#Q4``!^jL*(vSWCR8o!-i;jiIjW`ZEHE$_j~nD%9?ciN<(f<#k(=SgG2 zNhkZAFXO+}SUCTyj72RrN(8zV>@d;Lx8WqHyNL1iTN0xgg)~$44H_y){GDo|yVD{_ z-udFrXKw1wmM);$FXPrp1iJ94^It?5-HlZk+eJI5td-se5~q6dUUX&z`MN;Fn3S~} zi}a4vJXWre2z24QadPT3AcdXv|E#vZEkCQATTHayj4*O2B2vYt&fBXADXfInnymNS zEWHmTk~f>^)0i+49WI_#*3cAoC9n#8aZ-MR==z<%*{z2|iSuZ2A8)dyFtz4XdOK#5 zh6)m0x0>kX)1l;gw1{!LcMn!J;uO7me4|95OD^rty7XW-`(CDZR&CT!L1F?gSK(7b z$wPa&isfe^C*R7gxNO)U5$M92=H%r1S2SA_woH4pVyT9u8cTcCizeE}J&JtVChnv8 z$w>CG^%hO_UaX;lM7OCX`o$VW;_r!P6~e+{ zY-rFUEk~sp8Y)N}T4$nD%0v@ZO!R}%>pQaFXT8@BJ)0~M=-T>$x6~t}$*kNWhUH6p z_BsBmR_EPB4HYDw?=;cC3DG2b9TB5ksWxn}TTcCZ-?0*bu2&vrdaqdwDb`BFSP|WV zP2QPTFJ5`1hKfWSHPO27qe+`E5o7ENf3|16hn~JAT_RqA>u3ct{o_Flxj9V4Xx6np zbDvQ}*W6MyRFHW1&_s9bi6Lk0XScN+N!W?dQu+;-ScyQ__1b3I*DIFvm@i^@dRf_l zCcgUFqmddaNJKv}(YO0z$lKN8KAg_fWV&Ysoiyt#5$Gx#W~Szgv82v>5u4h8XyABl9P(h+z zWiw6xCzjN1D`FgqFT^JCUy0dT(IOG(!hFTaDfrsXjK`b%>Q3&%l(Dg%G<&`T(lWWb z>T=DKrq53xXVxdE-g!LflgI?}WKK68V{F#QjMdZo>uVY$E2tnbvY#jI@-BhgKON7B z54St2yTS+P&9ilq2z0If;z7G5B#@(NBF2gKOKq!G4$x<@whAgpERXl3%f2L#k?TZ^ zB|&ekPTAA-@qaay2z15%?Lp&{63Cud5o2TDYUD%VbiMH(jTKaoxD)P4Q=AgXuX99< zpfof6uqIuP$XiDu(Dm-92leieK#qJ(3YA2@(Q}%SN5c9vL=${W#Uzt zXdJhN&MrJqZ#JNif(jDi3;8zL678q|^Iw*8xkdeRabj&gi9lD~xgPXxN&+c6Q(V== zi0sO$Q|bEdPfiLdNPKbfq$jc`lF~L&u3U0@DPw!3>-&p8qe!5u)HDwo)GdLe4-+vO z6f2@U>YA?aihe{n1GgJFgBT|p*q)G(3Ds;5aVVmMf|C1ud?ZFGQ3KzokGx-iE zs35^^dQws;p7;zFG0v{ttj*XRsCO!NS|ZS;47Jd*B%ZJ;qGedvb+7g=sI%TwJFlRE zMA&yv`pcy_((tT^v1RaaZNaX#`mVU&B?4W~Ct2uU`QyozHX_D2<+QfSuZ@0T`b`BD zBzC%4X!!Ivvf!hLu{Ytewxn+hz0>daBm!L{`EP+_xgSUT_-}#mtGf0;Tbs{cFVXR- zf(jBF8d&JA`>|wGqBxoRScNy*k#dSYVEP-0K-ZW37J9x>965MI#Av$ti*_cXj=pW; z2L%-*1~;_OX}4p^tnMPlUnR5ZZzk2yH+=gd5$I}p+d{9Oh$X#pi;`Hku(N(~Y(@R? zmn;kwB&H`@=#3n)#QmIz5q3MDUev#|zN1MFi9pwaR~Gs@hUX`fv%<&FPdvu49Pc1#AxujkiJSW>G!YX zWvC$Wewu|AwZ@RsC3|q<_}@kK6XE&w24nI|1iGRMdePUZG34nq5u-q@VtT}zeERzh z`57umq|LI>+eKr@<6lIKdFx8(#Wv^Gy$iWY1iCJk_M%(eV#wcHM2xoEO6z9^f6-Dl znHVZa1e~74zFIea!Qxy4imx!U%*{L{4xcQxe3KDV8 zEp+p(E+khuQLYM&%cggJRgI0?@=YSp<<9HJlV<@WqqunIK1-bSzn)ZJy&7j_s34Km z-HTor7eMX|6)`ea=GV*n`!dh1IV1vI-g7LpUfw{GuZoCanqELZIJK_bn| zizclOAiqr!F`5Ot>#@~JFnTqYM4&5XnT76b97yygB1W5ACOs&BG1hmNGeZT5_)=c9 z-opTrf31i?-dOZOPG0Pt*+nAIRc*6{`Ys71ZDK@>**=AIr&(sUD=05R1&PAdyr@Tu zK$7K@h~duL!_rf7v-VY7B?4WEyq>oV4I<_2_58(bAH8&RR+f&uF*V3d{_|aW{;6$UPFE=_ZXVLxex1=-HWz58bYd;OHnUQ z^0Lo5URac*COCW1fbpTEOLb8P1D-e3ON}T&=k)Vos31{qniu_Ra46ZgN?cV*uSR;? z9h5v8FB9l;<1uos4<(bTi5TgH8tJKD9$8~2`Y=?GxG>d=rmhPmwv{5rw+{{V`+2^o z(?-h#y4K|IqRXd-k*^g*i~-9U>d%J_&B)QohoOQ*%w#WmcTpHAxkSWp{@Oq0Y$-kO*?MmxwVU$xrW8XQuWhM{$Wj7qeKqXQ-&`wGc2!F+j!9;mLO6-f08Pf-QQc6*E_R6m82G)3>AssJWe#H zxWBp{8l@`@OBI#~bTxZwq0biulOr!g3_rfJ=I>*>mCX+eGgOcmlj21OMFo>G!6HT_ z=h}LfYwMM~*@{X8x)NUUoZ(V1Y59+c;X1muzHHMPrB92Z3>73U_4cCU=LHkb7!f0J zQysnT`z6YkcQS#lvac<4agMHJ`BxERcZIt8>v0Q}XG$@K3KGHnz33UfqD+%SjB~H7 zdVJThivF;;M4)TjR|~!Lpeyk!Bue|JhgA2hn5=xyS(2fG#F0^6wEK~+q}D_cqpE8? zy;#-yim8sbM4+pB7B9NYH-v2U7BM;|)zf=L)lq&;@@A+YLB@H}`B_6qotYv=p4IjB z=qOL+ZP`*1fi7%a`ELn@G|*So{z{ikFD13RNaW^i@Pl0;1h4|r0#Es(Tiay};$nCT(0{G}&ddnJ$rJ{2QKjDZBY z9`e!MwLb#M1HnLSsC_$l<%))Wl&H>ajVL%=#>{rPra!tj_KH+PYyIG*po2bId|l zjtV6^E{Tk6BuirLyeexe8m*TIbbaC@mMV#%WTkz?vY=EqHhE8&c6i?!4HYC-_p#8f zheAmAyW*-oeUD%j-F7OInk~{|V=dIPUL>iOk*prsYN5?@Mv}$Lx~XQK^__SbK^C1B zM4kyT>_WgI<(C@EG*pnNbi_hCyb32h&x-pfc{-l$>@`Ypb6O=4=vtU=p?kiBlPWJo zj7cvO+33+x%JBtjG*pnd#A6)38BSiG6EQqDbz`cfqq3&&T8Thct0DZ(^>DKNy@*lR zoWzRkuCC}=*K4RCk>iwwUTG3eUfmQiYFLxmZEuq@GGc>7piAfPykAf_3H%~roLSm~ zUG8P0>t1ctP(i|Hl!d1M7DlRM7wuJ{=RH`}ne*v^mYXzGkZ5|wLjTSgPJX#BuBt** z3iEGVinhBa6X<$2(n4uQ7}=0b#0cr0!gfsK-+KJHNkat*FCOFFzA&=)o``X6dCyGsPR@XhjhQIg1}HcZu?>{_j1Tf2#m;%n6nCCz{1 zGZRv~yU0JD_#RCf^0$q!EDS7A6V(K>2Q?p$At@0F>K^{Bp64qzV&bXL$M*1VFO zV(n{bGI66g7SUWH&=voi2R*zv zmVC@FN}{$dE7fPFvsUx`6jYEH(#n%oa)~9^x``N1(^KgC59w^{igFTxuCEXHD%rwV za=xC3q375@4;LQD#%?LBpn}BvFi*O@Kr9(FTf}&j@`!Hwn$DWN%Oer!TI1?T+s}(7 zA6APPW7@bXSLdd)nZAEhRFK%;*ONBQ9!rXz5;5Fnl~%?UNoQx;{4Npb>RZs0&Yc@e z+NdH%dY(qg+3Ew>(A9e=DoDIvy*v8&$Ra#bx3KA(tJ?UOOhWL&UF>?7VR~9eo$@U)}Ly$n%I=*&)qjfBq z!`JTl2(no)8|QspIWu&&hM70!@U@rl>~(P@@faYU?uq(=Z2Q*x%Ez)ZHB^we(7{5- z@VW5j(?xqV@mUAfd*?@Gz?(@Dfv&Xa7Mjm1iUb6S7@Z2VV_|7oS+h0cHB^w;!{@?V zwTmKM>~rCp#kXbUBZ>}nxmT;5-hy;7R78NEHUtywJekK@r~ z@ueg+`Hm-D$#>HX8I`2YsA-{D&qR~6BkV21E_e35Xd9NRe+~^5B>LX+r1{##kT*j` zCUfkMysXpG4y^v>R~bm4tE-oVmMarOy3`XfymIDbY)Sx&d381e6(lC_^`sNF#E@K- zM2tljz9~6gbY+b%ZIuXgjWF?f(W<S2g2b^^o^;^-7_vUA zh>>{zvC?;E6np=szeJ$x@e5CSXJ`y*dRvsl@K-mK12+3UTjV@iCUki z;+y3wCSj$RYhXPV__)0E&XMr%WTBG+qlwcQ@vI(SDa+2B^J8_U*O3Tx)z5FCTjxfT zC9lP^^8dRM+h3suJ2Sblh6)llQ+O7BKZ@+lD@vkk^O|hR_6p3oQzwZ)*MpLLh1V~d zd@LqvRPjo6S@+{*SoeOR8Y)OE?rEW|uSJoQt|CUA+h^mc)>< zswlgEsHc?T7S{cdKuYED<;kyqp;O}uOC6)LaScDom4s31{sA>ZH5v%b_(VjtPkYJU2`th2RV z{GA|yt}nUG^j-N7Qs$G`Uo!8ARez?B(|k`AXQ&`?cbb{bX~TDUcM~ym3)8c<>#Sw$ zC@B%>Dw~CWp>Q#T9C;{WtTWfsbJeJ)P4o9==yIQ6rg40BXjyQyDiexNeLXbASG)eZ zH$w%9aePO-IM*QBz9YW-4s<_q({Nqt1==Tyr*)`FwQ=6(l;2G1Ei6!pOJwBF6Hg4fTVygJ`};nLyXN zZzdW$B#dOeD`LDj(m+2s=q4?EsT4y635}PMO2xxT(Z_;V^v85<*W5_vG07&4CUE=_ z)!2hJTpCU49!IvB(G-AMXPVtrak57x9vP75$Gz< zJgEQFXfo-u*dttZ(N-;_U?8&S0OPnfvy4B%yfLya8mr4DD4lwGrjo62Fk}u-V7BaTqm08ujRtY z^AJ&M`z&I*OZOH^^81n!fi7qMW!RZc;UwPvW!To!RL^^}htm8@35E(1VYB&O=Ud^# z)9aq3qGuLT~tUS(B)a&OqIhC749S29yuXe8;> zMi3KEWYyEpRcA^2zbaVzlz20JwmphmxfrL)C2@Uh9{tAta_ldfjiG`>6aF>e{V+bp zStnvdPt331j`n5GSLBcgbR9i!rdjSrk|*E9ozI72}wcssWktkAN zx`?rCyoVmSsxXUMnOh>zwUf8II}b;aQSU^I(@J6e+8K9d&6VSyRd7zJeds|lK)zqD#f<#Lmqib3uVO_+1 zWQp+ALq0jN?EK1*KvzZn{pbw$NK$W)h|$l&zmq3J1qm!;e8e*KZpP}iee^Yz#wbHpcu?nc zU5NR0oI2*X2Q74_3prFLP94VgY=6rYK+2yMZAo*}@r-xgef7ChM<{uDpE{#;7vgp) zK}9+@-yPjCxC`lM-yI#5<(~{XrnlZEcD#ZL5^@afs;5?{TTlH7n=TRPs?K*uPw(G_ zT(s|wo_D{IRqUOsrJ#buy>9$II`TbUk>aX8uAQv)JQ=0m%e7Y`&~@e||2E@B z7cwi4xT=S@7ir@>!t}zU4l1Z1QMSGZt$84Tcsq$0bI)zkJe`90?#xpXfvzRT%yeSo z08(g+=sC~t(6o0c9rYf2E-9!WF^HFv5*Gr9_Lt~6-Lo9g%DA=HCq`V82z2eUV90}o=YFdVw z=58KLlyjm+={YOtcgjA}Uaa+Gs35VVj+qwE9!ze=h?ZfGS6Th4>pxn0lvyIs6?@!F zul^ZC8vZF_uDoCh}%=FfrAaZe-h>`N5gdS8Qx4x*6t3;ry<5e^L zHX(>)xQIIsK3Y_-v?jmatXF=93KFwBnrZ!-K_q3By@kv0)GPm1Q16wHMN`u6)mfkH5`nI~@6Gh) ztw6G=y@+wCY#zNx&hq-7KG_&5NZjkgOJd(Z(*CW8ai&#vJ+(kJz4^rN3KHnbaQ2{4 zqXNnGK_bTY0a^94rEBQblfEjbAaQSqnGW+0B#C)MNqph)K|55+s+alpPA0%5mqah} zMtjVEk@m}?Hwr5FfAjM3dDF`QVMq-2dmsnwPVY@Lxv;osvduh5a)-z%Oj#y|pH*q89L?w=mWINqr* zJG*MQg8%mqvpaokZAYH>j#QDB2~?0+l;}@cla`(1lkh6X?Q{@0dUZ39QX>3?$Hnd6!J! ziXyK3;WvLWf&UA0EsQM_s33uPmtz85m=nnao<@OZy~1CB-p;E^L)#0u>~1UBoegE^NDG0(&p))$sdznLq^z+^OQ2 zKo_19AQPw{fjd6(n#^p&SDV zbm3P8GJy&bxTnxDfiCx{$`NZe#+#AH?0C`0b)hpn?SMPjyV7 z3%|jX2~?24EXpx~F8r2MCQw1baYlyu2j(U62~9l8&yt7=61dVRUlkJQ!qc;40u>~1 zeaA6@E<8O;CeVdzI*tickifMUIR+Bw!t=Id0u>~1wMHgzjRn_2@a!d-Km`drNl7M9 zK?3K+9TVunlayov*Hv(Z2G8M<2|OtRcOl{F4l;oX61eNhF@Y{T-9aW$K>~MgIVRAB zr#r|5DoEfiG{*$G@N@^6Km`fhP3M?E7oP4Q6R02|?+WA0&(;SCbm8d^atw6gelN!a zDoEf?E;$Ag=)&_LWC9f=a3_~z0$q3>giN4<1n%T=OrQ(TgOCYSkdSwUapvb6L;_uS z9)uhN6(n%Csbd0Nc)Ej3pn?SMnw1Gu@cTIYPcnfD68PntV**|H9kfiKf&_l~=9oa& zL+MLz&is6Xs33t~zR59=Ko@?OE)%FAf#1qGCeVf7*UJPdNZ_|}jtO+(m_a5`K|=nD zjx#@>E)wX%k%b%sGjIGh$8i>p3KIC$jT{3Bbm6zwGJy&bn8Q0J(1qWO%LFP&I37)4 z?t>>_ViqOGKm`f;)Kkv<-3KIBrgku6-cs7|#pn?SMPj*b83o}lcKm`fh(d?K&7v`lhftfI7$aspR zOrU}U?$~oopbPgA$^_07;faE{E+P}CAc3a~IwsJC-z8Fx^UO5OrU}Uo-XK^Ko{;YG%Xn*yKVlQ^=RnXPc%|z4NC6d#&Xw@-+ z3KDMJOw@m30vUc#TvgY~!HnOB5}Z6+L)QhxosO>GlN`JpsX8W5L1O+KciMVjD(Qby z>=5#~K1Hj+@1y^&y$ZU*N4rwLKFMUx%}~`bfeI47cU|en%}K=nf%p}^(lnU;+3~v4 zbnt8qU5QOyY0&8uGPG5w>X<+Ui5dI~^SGyy?q(5V(t#%mzYo32!9f|QATjBqoBh`k z%O;5(LP(&3#C<1sx_wS>vb(W3f!`5hTZN>7UvUB_qW=?OiRA56zM-(Lsw`e zH(GGQKr$&jTy;#Kg2brqZuH2xfuv8F5FX+4RBCJZJa7sa!hd#IA0k$hb%ZS`X4iW=%pi)`ydDkep#jtNwd=FPQm7i69t5QF5{!5(dm_P-I@%i{ZiO6(k%#DUCn9oq$Ou{R8ux~Qv*s^XpZpC>e2S%OK&7lK_aNVCry6RQO(~^?D%~g z6v67=+oLs@yih|0iR3q)G<0SwRevIO_9KA`62so|^D zGj->7aUbbN;xvBe`qXJ_6?8r4=Yus5Y@vS3(L;4ipn^mjes1m894*u&`?ctPDO^m2kfc3iDj=j@AWuU7Z|9#(Qt;5x^rZCkpfeI4k z?zmFZ=x{abJ&`k%uNB6kJ{{JUn&)e%Ah9x=8_n@CRBc#O?2bkP6(s6Ea-&7MwpZ)q z7Wd(ZKvxN#&vl;HP95zcat7Z<>6%ydcwMQsSwYwBWOw>Lwu8E-QIzVKKn01tSxhv} ztAk3;ioW*x(Q5jUJBJlAu@FNAiP29p@4RPokpUoq3KCnpxX}(x!qhMNe`6qlu0~JX z=v=ojmDqpZxwq>{?S`eT{;>TG1zmIfO>|*cjJmK!jOv&`1&PJ{m&_Iwj#iuhEpqDJ ziBW7QKXcII=3;I1LK7XhB1FwyJ5sGb)m>qRjMqnHT9|tFrHFBEFaMP>uMS#?QEN3+kdW`A;>JYwZgsqNs_7buKv$PhCVTy; z@?FI6cTQj#twv~HqE~6CAc4<~kE8M=u_0kKl*=ybHGEU}2Ja2zZ4CeI(Us3cj4dsb z*o$=)mGuGZHB^wu%b%6CPn7Cue^!4x@n4pE_J*bv+9(m|`X`lVWN#wW)C(fU+igAA zzI8ik$lHw?DoBhfXQKZkMyej~MP@m>R|>22E(hK5bdyA&D;xi9!1O5*>di|c#;H*$ zY>hS^W_G_bb2n#}Y2v^*+U=pO+3$`@ zpbM`zF_X1n9PN_a$DF-=SqOMgZ%$Q)b*7*MV-xF2Jv>9jl{)#8h!d#Z?Vt-H*$RM)uw`wT&Zx z+Q+3VUtTd%M+J#e8=Oe}<^k+riJaM)LmJTv=1RO< zVxU5xYr2b=C*0MaJ?tzqaz)ppdBr~KtWq}}6(kNEaw0np`m<~wnc+61CjBtCE+2TW zwL+k)c5yMQv4uZt>L)XHzo|h3YSrU6*0s`6L1L%aJ9GS2e-<7tGipUvqMN)u`QCO7 z6#`wRRtC~2b#5<93I-egKnzJ6jrvXp2?BEDq=vItE zpesYHk&@lqm*u-FGjcV*p%uswbE>22n^8fc3XeOR% zNQFSx{E=ebWi?;+ELc9Nm(-bPPJ2F-PuV_1Lj{R0?~KHDp$}U-Oa46`Z1}(m=}COr z*C2&J*RpUUS>ou+f?Z`swKIY2mVYwWqIzhkAkqH3kz|hWVLRK(j8EoaUf&y~@VYHq zCaFy5=I zyF#FAn5&TtDdNkn_mdg9Q!kPoMTYT#7wk1ukeD|@oO!Yj>p4x{gKfi$Xr3!mcrLFm z1POHAD`F(CZGG9Q?lR*;h?6#XVhYcf_>Q20L~??W*ochQDKewMjoRArQ^~y2{4)xH zu8WVvN+C6TS>yMzt=+q%t(b$H#La)U5mbR5 zx?1iQ>t%HIWd$;1Mw^clw5ei!h7INF5mb=KBY)lfKFn>oyg#aSo3D9Qi08X%KlDNZ zT?4j?^|k_hnOCCB_(K`|D|Ky1T zy7mn-kWCwWS?N47BfjZAt@-K!yx*663>75Q`#j(L)7qGc{dn=b*$RQKU40D1c*d8t zJuk0z>$n@*mb)e;XiFE)SgV_1C16aL>E+qR@ zFP7}spM_L$Aq7_kvYB<{8gwrUl;Rz#7U7-O6rrdfQE{`_^{ss%`#e{!rB`>K*ik3Y zm5+Z@NFmU*Laf&}E;f*b<*e7YBFdRR>`{!{Rxdx5u9o73A_`DckjTB*g&cYnz&42$&BeQ=w?%lq zTjluU$N3ZjT}6J0_g8xZ*z*(eZB%He4IehFGT(PS4@Cuu>|rjXbJqa2xsuG-xH%6m zcd`zTJM&vZ0$usUE_@q`2CyZ=Wk!6&AH7(UhTN(4cMTOJ90J6CUR(TGL{5LVOZI1d zO$#sHXVWKzK-Y<@&ZKVs0G2UOW)wa5Ngs0Ci#N~pNkavR%)Y z|L73NW49es2z22{MzrS#=IGy&LV3-{W@U_n1dd*;tV-Xi!9AW|*Y!@W6z?LuA5Fhp z$eiav%(kmMj~=;d^Y+!w>U}2{rKlhgKh%Y6D;vyaJ(gGdfmU_7N120q^{d4c0$q*% zi1)kV{nfA@G9x2jeSWd%UVY%5;uIAmOryj)+slL5TPwN0LGCLJdAY7@v~tr*Qrh2z ztohZ4Z9h4H&HLa&A{vS>GL8DPZIi`OdG%(mT_iDjzX#vCV7gYFx=~b+sA_a2%OZQT z>KXE=9@uGo#6^EiSf z&6OF`hEhK9Oh@hIJ(WP$=vgjg_KpaaSy5*E8cBK03mvqyr)4NANVF;8N*3IV5MM}T zhR@R`yv?Ah+KK&T6#`v_#eNDcmx?zNjb%n&E4kxTA?;h3J4FSFUFBTKpe^Cdev{0& z@7J7fyR?QZEmKY*(A8Y5RcsXdd0%WMGfHi0&OO|Rk)mD7QB;t~U)hz6HH5Q5yJf~o z+ZOzHzGYs=#eQB$pv!it*xw{2jOA}4Gm42Fz-~NPleKkvIf@Drrz(ma3x|fWTA4CK zJa_oR-a+OTy;TBTZsJLOVo4~Q?kO{3+cf7krj6z=rOQ!NkSHK_UTirxl$G2nGxqy7 z<1Q`!n6oCjD+IbuEN~$`dWN#<4P?f`!p(TX=YqOiBNr7Unu(p|zSB^)XPwO06V#N4 zJGkk&f0R`Sbj=ex~D`mz^U&ka9{1Q*^8EwdQu}=STs~8p=7R5SR8A+Ar{aLQMQEcL1BbhKchNZ{LzUbV4 z7HIL$2h&4mFL|MYL{bg0vvr*qcK@LyT+1)j0-6n`UGHvE2z2>15o=9$jA1Q*%YI_Y zz)@PQB17q^%RQB&!n|kAjU=yo3@dp~wm8Lp#%KYNiPW=h20;ahR_lzU#;zFV{YDO;AB1;+R;E>~susZyAIqH={plj|BBXRVIVYi#gjGa#kYtidd=y0d61QjF-+%b|OXT+ID%8b-{ zr$~RNVYK06M-2&domy)ofgJ@v|sZ?g+N!d*z-OsyFZ&TU-ow&pFV3Y_+kkC zGh?)d3KH#8oJst+7`F6^%(&!gtrtHum_~P+tPtq>TG*LP_}rf*ER`8a!>#oJronV* z|H&FENVpGkCi}<6u*uhChE+XxJt1fyU4MDDLZBYM^guGPzZFf9?rxqwLeR5EiHx;2ihESb?-d`~N~pchT`KB5rlS~A0#_=;V#id~lHk?>)ge!P_*J^ALe zh6)mE3cHXN;;h@1mv@x0)V0$tCuoJpG4)uD22Ir94Y=7!#FR2zD6 z)ME`5Br+O`9TCJ%N8K`HhJVRddh;qx=^mT63W2U8V%LRm@vK^(E;C#ve%4zI^`Z@i zf6`DvqNx}`o^2D&F6E3MkCe3HXD>FOZ)Sa02y}IN;7lGJ?Z>X+(F#wz1*W=U1le zbRLQd5{JZ&Y~zOaV_QAslcB{ydp;++EIsp&wL+k)MnM;{K36~X;)%>C(a(YVj4ne@ zw8>9VLBe~2sLKfJ$6{K`j3z5wdDtyyT6(69LZGX^mkY_eBa$@3O!S(6JYmQr}2|zech1o1+-^wNwHXB=mtsQZ*%tk>RqJff-1kOYOrU zfeI3D#J)@O+eWd+t7VVu<$&ep=ng}SxRK}Q9N ztg7Pepy-F%+EsSFFDbdXTK~Q}DoC{1 z?o7hkN3z$&B(d?U7kwq(jVAr*qoaZZ6Fboy9Nd@H%jxf)nb(k3xLTR7O!Zd?bQKaA zBgE>Ly>c>oXEdb0UR35!eEfA(kQkENg;W&1*aNom%v)@)Mdw$q!(I2ZRS0zL-r!6| z_lsn@jXaM+6>HGR4)uA=g%&z0NK_GTycRo0vY(%2Tl->EB|4z8Cr{ncP$AIu&n#!M z*Br^hZ^(A=$Aqg|O;Lr^*RQfUp}yGPb$=Ag7JJ*@Z0$^LFOOmaD+<>_XW~~aid`us zGxi5R(B{PV=F{5-m{CFEQzvIqZ(0}&r)3*H~XXJpPYqk=@Vk2pf{WQb@dGfMsWquERiYQWZ0kFPK-aRf&g9+tNM<`nX6$Zn zPjBV#!k;DnF{6S6NpmK%3P-W^IXl?j9`8(d{cgv{{jt@NK-bad&g6x-+V_i>mrxac^qpF4q5)D?1HnFzo`)rjN zal3bmwOohs+RI%P0$p-!Sa3zu{~mKvuNNfoTMDmty`Y8)67$5b`&wkA6p%fD-L=nY zhd)H|{tNRf_h3&^y>rkbin)vG9lZZV)ywcx+Tm0E_|*!p6$Oc3qTfzEqgZ!w{fc#K z)6LqcQ!#vP-R=s3t~UlT{t(rl*S5=}vW?oJUD+DP$CVxHi3$>%204?E$S9V1K#uML z#9N%eW`p^FC7ZmEKv#@-gYfiQ6f3exW+Z0J)iy@O^ILu&y--1-NQ5&vH7ts~TPid5 zhmF^?9tr&FC{Ka}x+=agk_E;3v39;PW1v-n*7VO%{&mW5f(jCcx;T?V8BuJ<5Sej^ z`DxGmlK6&@r3!(r`?tlLqALAZxae0~S)ClFX-#@3^TLHVK?MoVn$9F(X%zcdUS_PU zS6(Y#K7~KXcUvLQrCufBr){Hu!7`AJ-$7 zh6K9s3Kgx|g_l~t#bLDn&N1fmuf_f`9|BmqPc*C2)|vPu2eJwgk!)ZC(SC@vkjWo; z=J~z9YDK;TQMdIg%%~s{CB8@1FWZYbtkP}6W)||YyHmTvFbl(t)4Ss~CBI>woJ%<084 zcFFUYmf=prYBixddsNd=LBji%Gs!DfX!g#O8K-ttq60A%XRD(WB+<#kk}*lMg*JwP(DR#&Fo8`beXCTTewO`1&NOa7cx>* z_M=0*qx7hj>l6ZAj-lcmz?=xy^dFg#78^}pxAfB|*I2Kkg2Y4@G1|_I zV9xnvhV_CNy2!qQ-fhZ8g+P~YU$Lk6t8k`&kr`hO51{Xk=F;0f+N7g`L~JP+Qs}Fw zI&+a3i!x(r>0z1XuTEPO0$syI#_b#7%pqH5d^i?MHyAgXTU6bmqk_aVk#XvAIBTDi z(IqgB9{AM2?6^-Q(3L56Aa-pS&hF>zQ~haX9KHJElc|E({~Q%0&bhgeURA?cwPNx- zDh-IErP>rG`#z}zx^jz*0>#5w>#y=Wo(0EIVq1~qd$L7G1&M|t!&!XuI_oMkx}S`t zPpWJpMQl|9UERZ7NaJ2%Eb+C>@Od(T-aP!BT=}y}M+J$uVvIATMHpLHSZ2gD6Myr( zHML2NH!1|Wa)r5&nH9rW)C-vrccwr6XSs(~X4?iG6(rh<5zCJ}VeDK1nX##QG#!#B zSX-#CQwVgu@pB;;SBA1f*JMWjt5MYVaH4jq)><7EB+lEpkS-~q%=5Fn2M-?YLm$S@ z)|RYUsSxOj?BYTWyM{93VVN=DSpevnZcKb(vKbYXq(P1)=@!Xi5Pj2-68D2Rhcp6WC-n6hiRcV z7AXX}dbM{UFK&mh0efXe&w(NIU=3Zf8N5hG1&QreE@au#5Y{PYANLh=deLQ@&uEj3 z^A!SJ(VpV((KLj$pDr_EkNDI3t8ZyfZ_L(FLE_dMXL96MFe|lQp2yjY9&}m0kJ_8t zQxyVTD{HzCtE<7xH9=+^_|TQI8Nak#4=3rUAQ2?q^@WWJW?ysO^%ec6BlSqKrpsDp zC;^yY^lIx0v+>!OWXEoShDFJ)F%^`~m|_Jq>( z>dSr#fv&2y|5G!OT0v%fyhG@u^fI((mna<-B-A$QZaATjE0?9&4I>o-T@A#0>U$r8 zSnF~!x6>9=8j zPWJjHdj|gR5zCc4`?NvZ2hed%f16N2;_GrF(T9ur_I2{Nx}14P&z#tmHp{%GWgixG zx|c+){DTNq;FN*59tdPUZzEWlZU%Cd1Tv?Ua^z)byI;?~+>O$GS2R?R=qUE{3Ni(< zxu0bH?xmhw52@LmuB)aJ=&C6))`*NcIT>ZoGyP_X9yE6EB@GoMuKF2BSQSyLwnH9O z=Lgj}oqI>?rn^x56>Es<@iH@l*#s8O@K?988fB=$m#=@L-J5Du{vJpa@i*ku`^3JG ze~;JOEAX}Jern$qIVl9X)`+>tU(&H8{Jc`68!u3-fSR?tM+0~H^_|ASvU1MrQ6W!rJiW0 zAW^TDfrRc2WKmt^UohC?oxZmmrPE^HD+Id6&KG-a4e7;l50@D|jGy%fnO@?kK53{R z@k8vLd+=!>dssK;D!FOJ8~v(JGe`VT2y`8rD)zfu*Ndh1kr@u9^6&?7b?L0qzco~l zFxVSN?`FN2M**2(lU|sI<*P((#^t3*pbMW8R#w-i+4B|4%hJuattl!HuwxwdE{IrD_lafi*`x$ z!Pj{Tfv%%7j3l~G0Bbr%KB*Ue9<2?(n?NT#?LtsNf@T{@?e76>-70w=F;R=O-dhIK zT=R~5A%QNnHF(l!nHJ_en3fG%?S%>w?zx?bwM`&9XO^rFpQ9M(`lV)i=&i4O~8 z_N`=1(cTvmb(gUb^lwVr{~8lTn-<)p5a_zI+(0T#3t&%uWyUJ&aNTGfO&7OVr=fzxe4~+UE*{7x zEtDC)DK+)G&En|vxcLf!t|cc8q)N8{mT!;D*!;YOr`3~WYD#FQ;a&7b?5XBbFMtJ< zjAH5?)he@+d47{58o8&ph6)n7E{Z2yy8vc9E;D?7&NAO#GnCF4n5Yowy69;no?^Y4 z^B?7T6tli!Ubt@veG@Q7Lj{Q`qQ_A~RC(9fCo>AIeQd5!X9)FLGEO1T<<-bYK0gUy z<6p{*?9)%o-zpBF=HufuRFF`AE8lwAW_^4-ebsS-LZGWzZSf8AO#thEOJ-Ca;Hp1s zJ&3O1Gc;6?z`u>Cd)@5LOVrNGpIviMX7}T~{aDc(oSxo?l^4B1QRB6$0)KS(r~Yb| z6Ga7y56ul^_p9D4c#rHe)XG(bJLZ3@k54ly1iEVKPUKN-@ny7~%ve3RCbz#Yc7@*I zN>M?g+h#Eja%yi@rJN)xU98RhE}hV4*cPLxATe0%ia2XhZ+3B!JSx}M^||Mk9eS7W z5(DHTF%aBL4^IIcse78g|Sf-RhpzG9XapqNfvm=i3sLqV`#@i`TyUyo`$bZ;*$FusgJpzDkHb=$5AWwUdB-SO`!-}kP$wzy(hiV6}- z<~fnQ6GNHrC;98il)9+NjVfJ~C1z(4}69^N%#=*DCciFN-WkQ9;6OmJ{(G6wbapml+wCn(^MJ zuAA3ib5{s-;a#Av+=A%Lgd zKm`e0nMTb(0$td4sRY*eU=0)2q^kt}U)Ww@wo0Ia1h!q433Oq*q7pc_59i?FdnT1Y z1quAVW0}BrWSFfIs33uF@hlVQ!nsl^feI4%HqtVIE}Sc+5~v`7Z&fW5=)(CFDuK0w zSoMT;izum9fp%SPdffclt33OqVjY^<`1Xj>m zCeVddHY$M%5}lOVTEYCgju#T>!YUgz0~I9j?_`-k7uJ`l1S&{a{+nY9fK_35EvOl& zAfZ;I28wjbDLV11EF;5-(r-oZIEDuD_TSYKqB zKo`y)QVCR$uzVg!pbKX~sTrssfxnwdV0(w-9c)om0u>~1Bx9LC7p@4U66nHyn`HtO zB(MjlW*~tsTtiAFa9o357jTs$mB95~a6K7(FRl{UPrzCDmir8-Ac3>x)eI!ig|#gz zfeI2hzuq!|F09c}2~?24`Sq3wbYbO?N}z%S&abyjpbKlJR00(waDKgI0$unWPbE-6 zLY;Xpn17$`NT3Vf`>GkJAc3onStihhZ=+QL`)&A*-f|xf6(q2VK+Qk`T{yQ_B~U>E zt062C=)yV5DuD_TSk+;fKo`!nRtZ#)z!~5wfeI2>&tjQC7tUl?2~?24x*W>{x^RBI zN}vmCiYybTAc0j+Y6cSM!nFug0u>~%ddo6_E?iSVB~U>EtI#YH=)$!jR00(wu$s;? zfi7I*LM2c^0;>Wo6X;UsUmspiR1qobf&N6{6{1U4Ys33vs##tuNg~1-8jnxy6{V^N}z%St~6(vKo@?yR|!;*z?J4K6X?Pk1eL&d8Mt-^zNJtJRFJ?` zF)S14!nr3ZfeI41Du!hOT{!DTB~U>ESH-YQpbKXYsRSxW;Hnsw33TC{CY3-130xJ! zGJ!69U#1eMAc3o5SSHYA`8^!AulPmLa$AcE68OziJt`#7g)3;Q1S&}2w_D2uy401q z1@mt|5fvox8?>5%1iEm&c$Gi}34G^dnLrn=7q1eiAYu9a750{}G8f-#sTrssfwfztZI#0q1}e?e4` zP^*gZsE|MxuCuNl6)H%mHK~|^1iEmYbu|MOB(Mh7GJ!5!XI&*wK>{mtEfeU%b=Fk^ z6(lT=4Uj+=uCuOYpn?RBMXao9TneC@ldkGxtIpN?_p>AS#f;d?VvX8eJMGA=o{=o{ zYarXQ&W;=%8qK~r`H3nEBv3)3ei3_;Pptes=(i-w44$lac8lO&yY1CbL1MX!JsG~H zFRN?t|BFBciAisrNP&!jte9EW6k!Gu=&CDL1sMu*UDFnK_ABq*_W)5Xqyv!(8k?^tJDZ2N%(i9aWJcGoF za)lDv3maJ@TyhBI>l=5}=f5eV5a^ou#7L%O4`nw}WX9IIO?aVtL??b_DJn?x6&X7n z5?PnRGQ)3MQ{H!^lm5Q7yF#FAlbCTF@H&xAnj$kc-Dt)KcwRJ5{oqbfLE@FD^4^^% ziP;yG8Sa~#bE7fIJh6K@g+SL*k#X#MA{&sC@%~10UgwdQIXJc)MFoi+y^W+(mn2qE ztcN649=2=2cjmur%C|rz(6#WDk>tyj%#4%dd6fLpocAoBpBxl*OQ;~>FV16qb`sNb zRuK#s*_@vnHj6xHs1oREE;8=>CbM=EWk!p4&3NMIvt-T-cZv!Udqa$5?~Y`)!9kwK z&reNxqsfJ}^}Z^Bu5M3_CW=*PK|x|s7bAIcD}^0>BkzxO zB?zzjXP7o|d})P1*RtzI(k=He_O6%A@GR%aH+`L=9Sw7%s31{J+`-rD4r7DF9c*Pa zZ+9a;a>g?4WWG`gfv&HIjpVBPa5k})%xLRXpPx9kTcf#3P*jkJsb(ZD+lI5J^JIq4 zEV25`+aubK*kTHSu8up5gufZi2IkAjn6p^tDZxB5>wt#OC464he<@aD_a4O7HkQ?G zh5Xj(hsy-=POpz?s374LZ6FVK4r1n<^)fb&)%DiN-T4G|Ss~C>u!@)qVn3MilQP3U z-w8c$N@qUu+)WJ?B$jS5kaA-Ovt9|ZW;-;`4gJnPZFsL=j}!u3wylh$Wz=9c$VNV? zqm8$9+Zo<`$l)g%DoAYHZy>ew!OUiv%t#b*41{c8;sB;0No$m%ljZ1i=R!TWyG^Tl}Z#+SY*1iE^r8cEk~@od24oD7@X z{PVJU+%fy7h6)n1ei_KiUGZ$USmQ@L6Hn#mTe7S3JEmL|33RPZ6Se0d@$Bdfnep&L zUB0`buIFxBTxmZ#o-vZ2aS7~9^S%t*E-R~duC;i_ix>5%yhW8(4T+{ljAU}@1XjPc zyb>4vuFiKF?&yA}T@(Uc8D2)xzGDJ&*5!G4CspG;syx>1pF2}jkZ5<%NY)ihU_n)6 z#!zD=e*E1RJuTj#5a@CdSEBE(AuMgC%!t2HmS0(tkH;iBP*jk3wMIOB8Vq5TUdrFf z<7EkM?O@Npf3sBxbVZagl3nRTSo8>)QOu_}@3z*FPqMS6s338Am6+2|We98XRAvmV z;>=erDaNBq7g7jxt+Y0h%Mat((xx(Fr@K9$RMVXoSYu65K|=kT*S=biFCS8s*L{&& zA<(r#tln#TB%U1};ky zkBKj4n5J$>rgI;4(ojKSkgtI>%1CE>pURAPsa?$<4kgmJFQXL#U1moEIa4d01s9R` zN8VOz&Hkl_(&^WSYp5WRo+h5V$?43qx$M1$4a_zd92-x&hD}fibTtw++l8v8v(;`g z!~5}dEq-ZV`u2KVv$n^PRNI=y?z{|VmA^TX?5k-k!4$$Aemaut&(qkM2{NOT_gSrQ z<$l!fRBkgWNHp{pyVuo7XLA?I9oc?v+@%?OV(ELE3=Q%<7>S^ zE0r*iW>$9cLIsKAqFVh>h&c07atE;fD`#s5x5m?%Q*sj|(Dg|iRo!ao>|Jk}adoeY z78jpFKdyU8@Y?-4$%&M2md*y==*{ph5VMz?H`KbUOs1_)9VMtB;XP682iY{8O}HX6 z-0d1``mAI+E9&?$Yb>#DEYWvcBw@)GJ|G-Wm(B&ZZ z`KdL11S^$upGR+X1s`c))O&@ED3KGA?yt^aC(^%k1nc;T55dT`W3hg^Ck3yg;FEJ8_ zk!ft^7kMQH&(F_a)DXL}t;t1EL1MnyK=OA?W1r^9jQ20B_|cd3Y0+svG$hbSu5@Y`)>&-|c{b<;#p@Kx8)&@cg zq_ZF6p(^>C8nXzX|i!C(Bmq z*bW9gaU>sirn1nU5lWk=64>@35mZ*}uv;;eO{gTFyO^O6;QG?oi7b0JoE7gPTTVBl zw|?V641X*}s`!6lMu}!l#JlMTHnp0(b~AE)*B-d)d79kl}QFtePAlv5iEbJQiHx}PZkC7*iEacUngpb4uHKyB}}f?gc{vT@_*s2P-Ok393#KCNhrR|a0<$}ojMSM6j2nSN5uJdqjOix9eOWm$gCv#&y+t9^e133g3ob??ZGv6UNB>x&in zo+d#$Do8vPE$6Y!;VkzBnK8S39qO1`i@$x*K_SpJIM6_D_eo{*_R5UY1FKQHZwqCfz&UZ%A6L+qiXV}7@b$qn>%%J zRS0xV_cD;$H&R*l0C`l^`Z>_CRXX!D$J{z9NZ?aR{8oJm(7?w%`O2_cW+c!xzkz{7 zzer`(LuH1utyo_x!)1jN?ly&(lyrLVZ%Z+UC(6e+=e*M@>=)bS>KNMBERjGRF*=(KOOZA5}e` zuh>6PLj{SM-cH26-3T_^Q?>@h9e0~|ZAjpY>ZL0Lx*CertbV*oWy`+Hj7D4H%y)Vv zihcFsG*pntFLqKcojQUQJ0>$89T?Bf)lcRX@AxPLy2k!=B1xZ9S*)XcQdhWj%G7XX zGA}u=i-rmk`)4|lsS`%9qB(PTgGVg)>eeBJZ}VuT5a@ChW9Q!AQkm95W*o>UPM&Q_ z;bz~48Y)PvTckOjN0iJsu(6T$VsJH_RXZ;ldUD)ngSq1uk)(+nYrg4!A%|Ew`HP42}vsX3x zum-jU;*n%W^(L8ALg14$Z{z}C)`8E>XJ z)5h8D=%~6ybR^J~9U)c_2v1-wPRsMS;#iy(H+a*mjjlQ>NZj5hc8a~4z_uNe8H-km zJSeuSrS(`pN*G@+TiGr65pjt3JJ0$qs<3}jizP&c9gAH3<| z3-)wxP`W~(tF7o?9qcWRs*TK8`nU~UL+z+d!blwzB+kk2ILC&vLOD-r|M<>y!1_G2 z!@2Pafv%Eb?5uwu%4+AVX#KN8PdfklTg`FNG#wQrYJNA61tgJ?KzSa?g#zeT?WVT1 z>l}qZSAfV^{A(!VIT>*?#QnGFnwIbF932%T7K=A5zHJiO_+XjQzHJEgt--a3;)@gl zU588tvTbo9+dWJER%;eS(2A#5X`Y7VIx0xC7jMrCo=;>A5@kk@_kC$n%Sl>?%BvLu zU3J7rxa-l7KaPI*R+Lmfw?#(OQ3!N(62Dc! zUCC_FI+<}PE|wnMc*dM}=Vl!hB>LDI$%YllY;lInaGpPa?yr_#e|UP6LZIvCAp`k+ zB$@5V`I{F?7(nwJw$Ycb+N7g`gq_H!l$p#f<^0Vr7LK9s_Se&0o@`JEbd3|&Zu!s@ zmOMwE$F{g=dVQ{+zQlIDjtUa}#kJeSD}|-y+#j#^MbbeJ#^|SQ*C+(Ko{1J`-`o@y zJxyk`zu1>H)h6rH@~qZTLE>W`v72CQ3OhMS{#FZvBIuN+YxJ7Wmnj6ga4ag?!BL^q z-gd7ZwP>+2N<{+4pJG4Ao=>%Hr6cI6IfKmD>SO;wR`uKzJF@*xg%A>`Ac6HvY6cSM z!g?mPnhJYJ*dxO)TPlI?_waopj$~8;<5A(LPbE-60^h@0 zCeVfBU6sHy$8*ApB$Yq~32av^6X?QHp>LMaHOXas33vgrYsZa!jYazpn?Q`W3x=43rBh?feI4%t~di+4-^w|Yk~|F$?tpbNh= zsu`#t@kgmb!VDzPg~1 z+^!P%7sM|ycrB;|DoEfr9m@o|upU+=P(cFUqgW=;g>}6ufeI4;zcJ3>iq|rG(KS;_ zl14w4n!-L0W47;0l8x0Dn^s&O&LVG@BxBw$G<{w-T)goT|HO6mKSbZ>rAXh&Gfd7l zY0S>xMz%DaX7ck&V^_<%5$jcxOp&6tPbE-6qFJOHd8UsyO<(+91iE&1b0b9#XPB;x z`J2Gwy*{xd`88mP>G_*s49`zJDpZizo>Y?PPnVc}9v=4Bc_4wV#I7aCvL|ay^@=C| zMWBL&7b!uyoLgtu<91`!|6K5<`9!CmRm0G2QR^Uj(|c=M^Kh zrfoLOb4&Q^s8B&-Sw=DPI%t#W=C>jLL7;2fkYZ%g?aiiAXa6QpL1JoXF>-3hCewjtUhdrmYoqQ+>CY90$qtKT*=XM+f8NW{!O5QM4P#; zWZ8smrVhjZi$K@FXJRL_dpk^4^W-jL;@`jbASy_Vzv4_HXKgpF9`IiTx|$|9lfmUO zO$%no-8L};6(qI{a3-}cY&Vri|1SbvdTt|GRCR}GWg}UKj2WmPasPvXbU3li^wa6T z2z1TbX&}wAx0_0jmhbd20~I8+T?Uf8WSeR2nExWsRn*CeoV&io^oz@{$e4i&66LL( z$i0BgCgY0#BG7fcl_ROzb+gI)A6b!t8K@wU;q6F{z1nE1`Rcz2bZscqrt#(ei$GWEH9NAS?P}9r?_Pgppn}B9n|37j#!A!j&i_TA%b|fC zIlq2|>D8rxzcNtyn|N1#`TvK&mIYg!etvG`ZJ7+yfJuM1IH(}ee2g2}kT%X_&;N@+ z*OM)7YeQQ~z%Q6(lC!awFs0x|p_={VxJt;o>T3 zI@#Ie|NmSiMcS4ktv<{*)m)Rx?kp%pB9F~6oe3Gi_DwED9=Xgm4H5Ou>aU9m5`~wQ zB7a8AF&*vyUj(`yY%4{^&YWplJ@an@6(q1%s~!~+=<0T(6bUUk-BkGf-x;VNf&E}L z1J8VD<5FZ});!bQ5vdG+LzO@UiF+kWk@T1IP34-1>UH_=-#!Bp=&IpRiey(?WV%}R zZvqu0u&=FVAc3x-KTDFRn~O|VAO9Xrpn?RBMZ`Dy+-LQm(H-fV`FFHAcSXzcZkZ`* znjd>~(vgfUFvT>ta|ml9T7zTdmYbemkgWj{s30*k#F3<}pJa-6m(_-r2z1GI#ozt^ zv>&VMW$2M(dh^8{cWIa*UH_+*!Pdvh>T~xD{o}CSyiDjWXhUP#}h5a=>yIFNQ%*O*H5m2K_!9U;1Pn`r)i z_F4@UB(S9x71-mw^p6E&`RhuH6#`u&c8Qsjhc=jMyM>61hPx{3qff^1CZ@R>Do9|D zL(KVkTuA>DJeYSpKSd$XH6p=@4Dj4!dVV`pWRM=e%*8sy^HyypYN#NAJtr|g%6g;u zXYQfARIU*Ufv#?)jHE&QR@08Hvi4)a>|nF+f<%7lX^e&n64(Q@vRV?kg_#_a`Qz_? z3W2U6V%}ZCimj%SIrHv%#%8dUS~8#E<)fj31omXDtoq(h^@?kl!rz6qPzZE=IOj}? zuiIuSK412!>706GvT&nmX67J~@owHc?Lm`xo^}3}7b-~Lh*iuo zJ-$WTwIq&f-9kK(K$qR4V#L1NMw3JC!6Kv6=51PHt2o~2=sFKnkie0*Sj9uE;88Gt ze{S!)n<0U&{=Owh8}n*Y=MeeUz^~j5Eqq#EKJjH;Gb%{n8w63GxZ;iW&$&>3Yw#q6 zK-binCCK@kt4xpnkr~~tyw^@X4B_pr&NQQf1ilFoe-E2H^vO(r{_W}kg+N!0^Cd~Y zPm4`1hvoZ{Cvi4((C+Sh_0oULs33uFbj11$86nhasae0aXpxR%gC48g$k%P-O!U`q zhNBECtL6s+>AO!C^rz1AbX1Ty+QyCST{p#4teR{&9X$Q1L*2XjQZid1(53b=mT&D& z-N%2?6aSf_qk;tXSFEfqH0?qw*yrZIb5GP!K_aB08~Ktp&9vdRd`Fg*-htlzQ-J>z z%c~%PF6>2FS>@l*hOS(0$0yYusiT5K@w=tS^#QX?31ZzEE32nVThe!K&OEzXib9|Z zdr@LW?(Jr@aL;0V!MS)H6(q`?DMgO@%r>sgXO7MIoA|7C`DwjD)p$JeGT6Id{>1)7xuM8<#L@`^bfDY&rWWm zqk=?0n^L6Zzy+qax8xhh&qu4!IfokYh6Ra2pbPt2q7u-$BHggfi+}B3Pe%ob<+V!@ zpE3(g?yF_S!Ly}l9kILIu_xsf0$uo4)yiuAkz%x_pEuw8%tc293B1$9eLmGdzbxs% z&+RX$5a?3xLEbu!zFg3r)I7OG$B~Jv7}tDwZZxG7OJ_Lt5v$w)feI2vTAD=F)l5sm zWKX~SfH>Opnk{+rW{Zvlx^N6#uW3?FhLv3$b=o_@+%!%l(1l}aE2|$o zmKuDvnxmYy=%^r3v3hAzqC|wLL1TFy-~3}~XVYbKd;RFLrd z=0;|{O*YLuATydz=||^TN9+B{u2Tqf;hPsLE8~<%8j(Cs=X+M`s376Z-N?|kV@xTY zGQ-EOH{HK&sb2Nxa)m$_wku*inU-PHIwn&evS5kQ;vnI()s0lTKGw9+S!RSa45cl$ z?bBcPUaS!4!q!LZYdOS;ijfyjYM5W&I?Ij(dmqk<*%HVmOm-wwj||9~G%=hd<+3M^ znx0kgfuG1g0u?0eRy&fOuLoy&eG3-E^VVT>a$Kf%KVymhd#DX@Dl)^vuVy#4?5Pdu zxpcTk{XU&p^D{PN_U~REEk1P<#3OSsy;S_5)@Id09Tg--mnuwjmjI78&pHd@Lcbuo zspSc+aG3=Pfv#&JWB=%09t%FpjE62AY2GjSX-vCu`nL+UWNG4x#(CRzW3Mk2CV^Kr zG``cdCyQNLm~^jqx$&wSJp^H0+Mk{|b62zaJWI#_3o}%r{g0kB_WdhuPw;dd6(rg$ zDNI&WD(vB3q^rm5V*Xh}8!N&p#`= zveUsfIx0xC?ruZeyL|HSFmw{c zAMq@iv}(LLI&q6aplgB1$V__gu_`Ac%QKFe=7g9_ZP=otf<%JIaNYafV{J}G=>>6g zYV2K;!!4CS*ENxGz4TR&+8**eeh-bKKYBTmjUodTBqDm+knugQdXy|G&tt@;Sh{TT zI#NbF;gCRAn!OFFa`=*mPZOE(s7e$)INiDoE^3vLS8eWO{7r zCx5H=Lt|*EwpFxGO*bk8y7twxA!#czJ$}uUzg3?z(X^JSi#B@ndL0!c@K><1iU^OU ze@6OiH*8b_UH80f$lku2JkGC?8GD!Yqt-l1n_hjLjtUa^ce1kDXc((4Hz&|}huRW+ zF5&a)Q#(guINv`jzN&m){WQ+d`qvyn69+pHRFLTR(t&hc5uR1nD8I^V3D}@{^c_g^ z)wlCP0$rK=GZ!Der{&5y6NSs^XKn}YGW&QM*Z$EzLIj-q5 zqN&Hq6ATG-t;uj8C2sj;^^276eXdnLqxnboqZ6#ZF?1bj=RkORkF0^KLYPV%EPY)Y zcfK#J8(Gtg3KCtaJCNjDU9!pq$@e}%hP&E>&VA_R8*LQ=U4eZZ$N{}amPb)}RC_|- zXfvLK(#s1cm{CDOi?k<|?$yo8Jy-r#oxAa0lS)|+SI9Sa z4>sG=)vPnMoouC}g2ddFc4DS>;jCNd0|n8rwKF|Xw>^Ec%2pxJHQ}3hw`gz3+H+R6 zwW-}p(V%iIX~#09bySeJO6|zr*O&I)D&s2%{zvS_zN#7h(7l3=3K9*Q+mYUp@AtL+ zAb%@6p9<92o6vAm9fd$wnc8+F@bSrg5C8ZG!eM^}+W)&3oxQQHjtUaP9u^_j24(Gg z>L@er7pOsJHK{DHsBNT}kqiG9x*TrX5|6&K_ukzpe=D!at!dq|PPCr$2pwB}Y+qG^ z^=eM%E-Omsrw-9kLE_;}TjH7=-7xKWcahOt_oS0!%F({XA`}8$c(hhlPW#)_8~%l8 zNj64*(5M&*zjNKgK4~DU)~h&K`)ZztQ;B%C?R_y4U17UN>ss=?&(n9EXtNo4>9+pk zbySdebGHb;6dc{SRzvyT=k+pw zTDIA3ZT*SaIx0v^uU(S-PW@kuy=PPu%l`d65(F87fC@+s<}8?|sV)&bCJbP}EQ%sV zFe?}^;xP+~f&_C!%xQY2%N&n6=bUraV|u#IUH9Bw{uclB@XEFJ{7d%CNt>syu3 z;6!_#(O^^;`a`-RH{Y8n5a{~cRU2D6o>PCLj`yAS1azlEj~|z%16e96NK|O;Lvl7- z8{0nR#0~#gy6P2^O>Q{?fv!Gpyvda2<~_01`B+BFn|P~siJ~J!D1gWy~POQvY)&+ zu`r_#jrou(@9nc(AkZ~spbu%^&%+p4jgNjL4em|5?pr0Nxh_*tK_Z6w5Yt&tW3f(r z#A~i~9Q8R}C_9YK7YKCWx1iIFJKT%5kJ&5-)W}y+K|=56L&nXwH0IsoN1kudi^dh( zAy1CX69{yP-|o-(E7kN4-B_-2NbXnOm00YbseB0RX-dm=A@v5$QpRkKGhJw*Ro=(V zR~8)OZKv#>O zZe-)z93`eLCx-RgXfFMJBmRww`M>#FfDYG2n4LS0W_2zl2?V-) zez}o{?{bue?RiGI=_AZ#JB?^X?=VUPd?Kp-_FeJ#RAYpUFjU4Ekr*zEW883d!H__V3Y)OfZ0)eiV zuiZ(P)458IiTuc~MAnl0ZfnHz7BVVG9G&7$?tjcv=123{ZBju!^6f+lYoiMm2z0%k z;X$s3<|&;X^G~&C-z1{59Lu`zuOOp>L=SflGPrlXlCWl|Ml?ULj}*F(Wh2Iy76^2e zzvw~C4ta_xJxL?Z{BfD2+mB^&O`T*^kQg|~gKVyquUr_wpPcEn++;Q)gkFckeXDmoD$p>|VnbW8+ z6B6h$8oWsRYFUceleZacBTmVsD)(pOms^-oK_ck3*7ga_R&JE!Er1G>?#pZM^=7L^ z#0vzv)UIBn^0viFi~c;rV&o&))2%mCJcpZ6L86s58@K$~EM?k1vvIeSc`2`>z1ZB& ze+mS;PN#U0>OqT@5?gu3C~dWqX(M{Fhr8yQQ9;7S+lwSN%u9%d5;#tVQ-AVb@)bT<`)_u|`Gb%{5o$o~=3o@0i1-xBy&+J5}4Ub|= zVtxn&x(e!flS6MZlm~IVwbUllmCop=jVGqrsHh;3b5qOswm?bi%G(T${k&*OU=udI zyr)2*Yk!(IA%o{Dm%R9qubt&bW1Pd;jP~VJRFF6o>`iL7Oji~K@)p4O`PX zs)0bDtC}_={_)W{%3rs6hRvL6G|gOxC3Fr~Q9+{WG;gxVJXbk&muKwK-u!fPsm{Ld zh!zNRh3I{V_t#lUd?f#N?DoFG>>`mmr*^1vtp7Aj;jE+w6V!iB! z2n4!br~8mbL#8P=rt&jbyhjsyqn|5_-alSN1qt`YKBP|RG-XdVZ&_OBwxsn=+p>x$ zrU?YPTCMaUO_xkn{@%zlUe;_ydmgf3agpj`kBsGQ9U9QI}qek$I`JMx5nNls( zb(hx(1iCux)rixrlxKurCDUUE(cR^$s!t*}sHh+jJIa?_4`{8}XzRyoZ^^Xr_8~Dg z>eAx{0)ejJKZHVr{A~NxIZRQTOnSGG7y^-RZ^V zq^gAifv$_%JI`|w6_o+wct)qmNp$wEyQX>C%0{Rl5trdhzSpm)^f=8kZYL+vuDx!C z8Z9>o1iIee@+AvP1t@t_c*elQBpN-r1X=K@P(=la-kH8+!=wP^@;RPyzzwh zH4q7OwOHj#&i?hyIPw=i=Qo2AX}wmD$-L-|Dk?}+>gr1-yMHrg&E*+$cMqbIA_C<6 zlN$sAUBedmk{RnB8MWO8G{U#fAo_|_k<$ikP*FkRMGIdNobt$cbu7;~bY}pq;?PD8 z&Rr)E=)zvO_BQ;_{@RWw1LWB*YlZ$f61^|`kX=9XjhQd_@BBq(0yS8s$uW<`9zD9S zuddUDw5RNkS#8wa5BzDQHU=4fB+!-h*oT~uqKrM8@jG0N$|0LooT@f-@e>Gi z*;n@?mW?fxCKA7{TIa~D&8Hq}=m>v`3KHT~@_Kedw(?VmnlU9nAkfvXvmaSp+)Xhr z;~Bj-2C!WY#aThPGsV%t!y~mmM_z`ZPR#FPmgBtq+0lo#Ozm8f;+Q28 z6tDPCU(L~%#ZItiaup|mKo^deYO8WZ*JL(Z&#L=_JSbk_c;(~xoOXx%RGnQMd_{fH z#hs#pMB5qO74xb+5sxmAu_PX%M+BS9}`T2mim#j@-fOT|5Ov! zQ0R1rbrH;inL;O|2T@dz*qiG|Ms;tkEcM~P+FJSumS4)x)HFvV(1kS=I^B~i;cU>+ z>gJHtAc_hS3o`sjsYA7tJ1#t<)2l{oujfhg+xLM2fiA4N&3RS~1quAkYiqHN31>E==9B%A;&+9$ zGI*Y}C+CSq?D~zX#Be=OID<%FHIKH|

b+U(?87LCyY7pl~a{DAJWp?trPy0>{ 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 O+{8cvT{wyw#{UCWK9%MG diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/right_arm_actuator.xml b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/right_arm_actuator.xml deleted file mode 100644 index 9abf102..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/right_arm_actuator.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/shared.xml b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/shared.xml deleted file mode 100644 index dfbc37a..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/shared.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/table_tennis_env.xml b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/table_tennis_env.xml deleted file mode 100644 index f2432bb..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/table_tennis_env.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/table_tennis_env.py b/alr_envs/alr/mujoco/gym_table_tennis/envs/table_tennis_env.py deleted file mode 100644 index 9b16ae1..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/envs/table_tennis_env.py +++ /dev/null @@ -1,244 +0,0 @@ -import numpy as np -from gym import spaces -from gym.envs.robotics import robot_env, utils -# import xml.etree.ElementTree as ET -from alr_envs.alr.mujoco.gym_table_tennis.utils.rewards.hierarchical_reward import HierarchicalRewardTableTennis -import glfw -from alr_envs.alr.mujoco.gym_table_tennis.utils.experiment import ball_initialize -from pathlib import Path -import os - - -class TableTennisEnv(robot_env.RobotEnv): - """Class for Table Tennis environment. - """ - def __init__(self, n_substeps=1, - model_path=None, - initial_qpos=None, - initial_ball_state=None, - config=None, - reward_obj=None - ): - """Initializes a new mujoco based Table Tennis environment. - - Args: - model_path (string): path to the environments XML file - initial_qpos (dict): a dictionary of joint names and values that define the initial - n_actions: Number of joints - n_substeps (int): number of substeps the simulation runs on every call to step - scale (double): limit maximum change in position - initial_ball_state: to reset the ball state - """ - # self.config = config.config - if model_path is None: - path_cws = Path.cwd() - print(path_cws) - current_dir = Path(os.path.split(os.path.realpath(__file__))[0]) - table_tennis_env_xml_path = current_dir / "assets"/"table_tennis_env.xml" - model_path = str(table_tennis_env_xml_path) - self.config = config - action_space = True # self.config['trajectory']['args']['action_space'] - time_step = 0.002 # self.config['mujoco_sim_env']['args']["time_step"] - if initial_qpos is None: - initial_qpos = {"wam/base_yaw_joint_right": 1.5, - "wam/shoulder_pitch_joint_right": 1, - "wam/shoulder_yaw_joint_right": 0, - "wam/elbow_pitch_joint_right": 1, - "wam/wrist_yaw_joint_right": 1, - "wam/wrist_pitch_joint_right": 0, - "wam/palm_yaw_joint_right": 0} - # initial_qpos = [1.5, 1, 0, 1, 1, 0, 0] # self.config['robot_config']['args']['initial_qpos'] - - # TODO should read all configuration in config - assert initial_qpos is not None, "Must initialize the initial q position of robot arm" - n_actions = 7 - self.initial_qpos_value = np.array(list(initial_qpos.values())).copy() - # self.initial_qpos_value = np.array(initial_qpos) - # # change time step in .xml file - # tree = ET.parse(model_path) - # root = tree.getroot() - # for option in root.findall('option'): - # option.set("timestep", str(time_step)) - # - # tree.write(model_path) - - super(TableTennisEnv, self).__init__( - model_path=model_path, n_substeps=n_substeps, n_actions=n_actions, - initial_qpos=initial_qpos) - - if action_space: - self.action_space = spaces.Box(low=np.array([-2.6, -2.0, -2.8, -0.9, -4.8, -1.6, -2.2]), - high=np.array([2.6, 2.0, 2.8, 3.1, 1.3, 1.6, 2.2]), - dtype='float64') - else: - self.action_space = spaces.Box(low=np.array([-np.inf] * 7), - high=np.array([-np.inf] * 7), - dtype='float64') - self.scale = None - self.desired_pos = None - self.n_actions = n_actions - self.action = None - self.time_step = time_step - self._dt = time_step - self.paddle_center_pos = self.sim.data.get_site_xpos('wam/paddle_center') - if reward_obj is None: - self.reward_obj = HierarchicalRewardTableTennis() - else: - self.reward_obj = reward_obj - - if initial_ball_state is not None: - self.initial_ball_state = initial_ball_state - else: - self.initial_ball_state = ball_initialize(random=False) - self.target_ball_pos = self.sim.data.get_site_xpos("target_ball") - self.racket_center_pos = self.sim.data.get_site_xpos("wam/paddle_center") - - def close(self): - if self.viewer is not None: - glfw.destroy_window(self.viewer.window) - # self.viewer.window.close() - self.viewer = None - self._viewers = {} - - # GoalEnv methods - # ---------------------------- - def compute_reward(self, achieved_goal, goal, info): - # reset the reward, if action valid - # right_court_contact_obj = ["target_ball", "table_tennis_table_right_side"] - # right_court_contact_detector = self.reward_obj.contact_detection(self, right_court_contact_obj) - # if right_court_contact_detector: - # print("can detect the table ball contact") - self.reward_obj.total_reward = 0 - # Stage 1 Hitting - self.reward_obj.hitting(self) - # if not hitted, return the highest reward - if not self.reward_obj.goal_achievement: - # return self.reward_obj.highest_reward - return self.reward_obj.total_reward - # # Stage 2 Right Table Contact - # self.reward_obj.right_table_contact(self) - # if not self.reward_obj.goal_achievement: - # return self.reward_obj.highest_reward - # # Stage 2 Net Contact - # self.reward_obj.net_contact(self) - # if not self.reward_obj.goal_achievement: - # return self.reward_obj.highest_reward - # Stage 3 Opponent court Contact - # self.reward_obj.landing_on_opponent_court(self) - # if not self.reward_obj.goal_achievement: - # print("self.reward_obj.highest_reward: ", self.reward_obj.highest_reward) - # TODO - self.reward_obj.target_achievement(self) - # return self.reward_obj.highest_reward - return self.reward_obj.total_reward - - def _reset_sim(self): - self.sim.set_state(self.initial_state) - [initial_x, initial_y, initial_z, v_x, v_y, v_z] = self.initial_ball_state - self.sim.data.set_joint_qpos('tar:x', initial_x) - self.sim.data.set_joint_qpos('tar:y', initial_y) - self.sim.data.set_joint_qpos('tar:z', initial_z) - self.energy_corrected = True - self.give_reflection_reward = False - - # velocity is positive direction - self.sim.data.set_joint_qvel('tar:x', v_x) - self.sim.data.set_joint_qvel('tar:y', v_y) - self.sim.data.set_joint_qvel('tar:z', v_z) - - # Apply gravity compensation - if self.sim.data.qfrc_applied[:7] is not self.sim.data.qfrc_bias[:7]: - self.sim.data.qfrc_applied[:7] = self.sim.data.qfrc_bias[:7] - self.sim.forward() - return True - - def _env_setup(self, initial_qpos): - for name, value in initial_qpos.items(): - self.sim.data.set_joint_qpos(name, value) - - # Apply gravity compensation - if self.sim.data.qfrc_applied[:7] is not self.sim.data.qfrc_bias[:7]: - self.sim.data.qfrc_applied[:7] = self.sim.data.qfrc_bias[:7] - self.sim.forward() - - # Get the target position - self.initial_paddle_center_xpos = self.sim.data.get_site_xpos('wam/paddle_center').copy() - self.initial_paddle_center_vel = None # self.sim.get_site_ - - def _sample_goal(self): - goal = self.initial_paddle_center_xpos[:3] + self.np_random.uniform(-0.2, 0.2, size=3) - return goal.copy() - - def _get_obs(self): - - # positions of racket center - paddle_center_pos = self.sim.data.get_site_xpos('wam/paddle_center') - ball_pos = self.sim.data.get_site_xpos("target_ball") - - dt = self.sim.nsubsteps * self.sim.model.opt.timestep - paddle_center_velp = self.sim.data.get_site_xvelp('wam/paddle_center') * dt - robot_qpos, robot_qvel = utils.robot_get_obs(self.sim) - - wrist_state = robot_qpos[-3:] - wrist_vel = robot_qvel[-3:] * dt # change to a scalar if the gripper is made symmetric - - # achieved_goal = paddle_body_EE_pos - obs = np.concatenate([ - paddle_center_pos, paddle_center_velp, wrist_state, wrist_vel - ]) - - out_dict = { - 'observation': obs.copy(), - 'achieved_goal': paddle_center_pos.copy(), - 'desired_goal': self.goal.copy(), - 'q_pos': self.sim.data.qpos[:].copy(), - "ball_pos": ball_pos.copy(), - # "hitting_flag": self.reward_obj.hitting_flag - } - - return out_dict - - def _step_callback(self): - pass - - def _set_action(self, action): - # Apply gravity compensation - if self.sim.data.qfrc_applied[:7] is not self.sim.data.qfrc_bias[:7]: - self.sim.data.qfrc_applied[:7] = self.sim.data.qfrc_bias[:7] - # print("set action process running") - assert action.shape == (self.n_actions,) - self.action = action.copy() # ensure that we don't change the action outside of this scope - pos_ctrl = self.action[:] # limit maximum change in position - pos_ctrl = np.clip(pos_ctrl, self.action_space.low, self.action_space.high) - - # get desired trajectory - self.sim.data.qpos[:7] = pos_ctrl - self.sim.forward() - self.desired_pos = self.sim.data.get_site_xpos('wam/paddle_center').copy() - - self.sim.data.ctrl[:] = pos_ctrl - - def _is_success(self, achieved_goal, desired_goal): - pass - - -if __name__ == '__main__': - render_mode = "human" # "human" or "partial" or "final" - env = TableTennisEnv() - env.reset() - # env.render(mode=render_mode) - - for i in range(500): - # objective.load_result("/tmp/cma") - # test with random actions - ac = env.action_space.sample() - # ac[0] += np.pi/2 - obs, rew, d, info = env.step(ac) - env.render(mode=render_mode) - - print(rew) - - if d: - break - - env.close() diff --git a/alr_envs/alr/mujoco/gym_table_tennis/utils/__init__.py b/alr_envs/alr/mujoco/gym_table_tennis/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/alr_envs/alr/mujoco/gym_table_tennis/utils/experiment.py b/alr_envs/alr/mujoco/gym_table_tennis/utils/experiment.py deleted file mode 100644 index a106d68..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/utils/experiment.py +++ /dev/null @@ -1,83 +0,0 @@ -import numpy as np -from gym.utils import seeding -from alr_envs.alr.mujoco.gym_table_tennis.utils.util import read_yaml, read_json -from pathlib import Path - - -def ball_initialize(random=False, scale=False, context_range=None, scale_value=None): - if random: - if scale: - # if scale_value is None: - scale_value = context_scale_initialize(context_range) - v_x, v_y, v_z = [2.5, 2, 0.5] * scale_value - dx = 1 - dy = 0 - dz = 0.05 - else: - seed = None - np_random, seed = seeding.np_random(seed) - dx = np_random.uniform(-0.1, 0.1) - dy = np_random.uniform(-0.1, 0.1) - dz = np_random.uniform(-0.1, 0.1) - - v_x = np_random.uniform(1.7, 1.8) - v_y = np_random.uniform(0.7, 0.8) - v_z = np_random.uniform(0.1, 0.2) - # print(dx, dy, dz, v_x, v_y, v_z) - # else: - # dx = -0.1 - # dy = 0.05 - # dz = 0.05 - # v_x = 1.5 - # v_y = 0.7 - # v_z = 0.06 - # initial_x = -0.6 + dx - # initial_y = -0.3 + dy - # initial_z = 0.8 + dz - else: - if scale: - v_x, v_y, v_z = [2.5, 2, 0.5] * scale_value - else: - v_x = 2.5 - v_y = 2 - v_z = 0.5 - dx = 1 - dy = 0 - dz = 0.05 - - initial_x = 0 + dx - initial_y = -0.2 + dy - initial_z = 0.3 + dz - # print("initial ball state: ", initial_x, initial_y, initial_z, v_x, v_y, v_z) - initial_ball_state = np.array([initial_x, initial_y, initial_z, v_x, v_y, v_z]) - return initial_ball_state - - -def context_scale_initialize(range): - """ - - Returns: - - """ - low, high = range - scale = np.random.uniform(low, high, 1) - return scale - - -def config_handle_generation(config_file_path): - """Generate config handle for multiprocessing - - Args: - config_file_path: - - Returns: - - """ - cfg_fname = Path(config_file_path) - # .json and .yml file - if cfg_fname.suffix == ".json": - config = read_json(cfg_fname) - elif cfg_fname.suffix == ".yml": - config = read_yaml(cfg_fname) - - return config diff --git a/alr_envs/alr/mujoco/gym_table_tennis/utils/rewards/__init__.py b/alr_envs/alr/mujoco/gym_table_tennis/utils/rewards/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/alr_envs/alr/mujoco/gym_table_tennis/utils/rewards/hierarchical_reward.py b/alr_envs/alr/mujoco/gym_table_tennis/utils/rewards/hierarchical_reward.py deleted file mode 100644 index fe69104..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/utils/rewards/hierarchical_reward.py +++ /dev/null @@ -1,402 +0,0 @@ -import numpy as np -import logging - - -class HierarchicalRewardTableTennis(object): - """Class for hierarchical reward function for table tennis experiment. - - Return Highest Reward. - Reward = 0 - Step 1: Action Valid. Upper Bound 0 - [-∞, 0] - Reward += -1 * |hit_duration - hit_duration_threshold| * |hit_duration < hit_duration_threshold| * 10 - Step 2: Hitting. Upper Bound 2 - if hitting: - [0, 2] - Reward = 2 * (1 - tanh(|shortest_hitting_dist|)) - if not hitting: - [0, 0.2] - Reward = 2 * (1 - tanh(|shortest_hitting_dist|)) - Step 3: Target Point Achievement. Upper Bound 6 - [0, 4] - if table_contact_detector: - Reward += 1 - Reward += (1 - tanh(|shortest_hitting_dist|)) * 2 - if contact_coordinate[0] < 0: - Reward += 1 - else: - Reward += 0 - elif: - Reward += (1 - tanh(|shortest_hitting_dist|)) - """ - - def __init__(self): - self.reward = None - self.goal_achievement = False - self.total_reward = 0 - self.shortest_hitting_dist = 1000 - self.highest_reward = -1000 - self.lowest_corner_dist = 100 - self.right_court_contact_detector = False - self.table_contact_detector = False - self.floor_contact_detector = False - self.radius = 0.025 - self.min_ball_x_pos = 100 - self.hit_contact_detector = False - self.net_contact_detector = False - self.ratio = 1 - self.lowest_z = 100 - self.target_flag = False - self.dist_target_virtual = 100 - self.ball_z_pos_lowest = 100 - self.hitting_flag = False - self.hitting_time_point = None - self.ctxt_dim = None - self.context_range_bounds = None - # self.ctxt_out_of_range_punishment = None - # self.ctxt_in_side_of_range_punishment = None - # - # def check_where_invalid(self, ctxt, context_range_bounds, set_to_valid_region=False): - # idx_max = [] - # idx_min = [] - # for dim in range(self.ctxt_dim): - # min_dim = context_range_bounds[0][dim] - # max_dim = context_range_bounds[1][dim] - # idx_max_c = np.where(ctxt[:, dim] > max_dim)[0] - # idx_min_c = np.where(ctxt[:, dim] < min_dim)[0] - # if set_to_valid_region: - # if idx_max_c.shape[0] != 0: - # ctxt[idx_max_c, dim] = max_dim - # if idx_min_c.shape[0] != 0: - # ctxt[idx_min_c, dim] = min_dim - # idx_max.append(idx_max_c) - # idx_min.append(idx_min_c) - # return idx_max, idx_min, ctxt - - def check_valid(self, scale, context_range_bounds): - - min_dim = context_range_bounds[0][0] - max_dim = context_range_bounds[1][0] - valid = (scale < max_dim) and (scale > min_dim) - return valid - - @classmethod - def goal_distance(cls, goal_a, goal_b): - assert goal_a.shape == goal_b.shape - return np.linalg.norm(goal_a - goal_b, axis=-1) - - def refresh_highest_reward(self): - if self.total_reward >= self.highest_reward: - self.highest_reward = self.total_reward - - def duration_valid(self): - pass - - def huge_value_unstable(self): - self.total_reward += -10 - self.highest_reward = -1 - - def context_valid(self, context): - valid = self.check_valid(context.copy(), context_range_bounds=self.context_range_bounds) - # when using dirac punishments - if valid: - self.total_reward += 1 # If Action Valid and Context Valid, total_reward = 0 - else: - self.total_reward += 0 - self.refresh_highest_reward() - - - - # If in the ctxt, add 1, otherwise, 0 - - def action_valid(self, durations=None): - """Ensure the execution of the robot movement with parameters which are in a valid domain. - - Time should always be positive, - the joint position of the robot should be a subset of [−π, π]. - if all parameters are valid, the robot gets a zero score, - otherwise it gets a negative score proportional to how much it is beyond the valid parameter domain. - - Returns: - rewards: if valid, reward is equal to 0. - if not valid, reward is negative and proportional to the distance beyond the valid parameter domain - """ - assert durations.shape[0] == 2, "durations type should be np.array and the shape should be 2" - # pre_duration = durations[0] - hit_duration = durations[1] - # pre_duration_thres = 0.01 - hit_duration_thres = 1 - # self.goal_achievement = np.all( - # [(pre_duration > pre_duration_thres), (hit_duration > hit_duration_thres), (0.3 < pre_duration < 0.6)]) - self.goal_achievement = (hit_duration > hit_duration_thres) - if self.goal_achievement: - self.total_reward = -1 - self.goal_achievement = True - else: - # self.total_reward += -1 * ((np.abs(pre_duration - pre_duration_thres) * int( - # pre_duration < pre_duration_thres) + np.abs(hit_duration - hit_duration_thres) * int( - # hit_duration < hit_duration_thres)) * 10) - self.total_reward = -1 * ((np.abs(hit_duration - hit_duration_thres) * int( - hit_duration < hit_duration_thres)) * 10) - self.total_reward += -1 - self.goal_achievement = False - self.refresh_highest_reward() - - def motion_penalty(self, action, high_motion_penalty): - """Protects the robot from high acceleration and dangerous movement. - """ - if not high_motion_penalty: - reward_ctrl = - 0.05 * np.square(action).sum() - else: - reward_ctrl = - 0.075 * np.square(action).sum() - self.total_reward += reward_ctrl - self.refresh_highest_reward() - self.goal_achievement = True - - def hitting(self, env): # , target_ball_pos, racket_center_pos, hit_contact_detector=False - """Hitting reward calculation - - If racket successfully hit the ball, the reward +1 - Otherwise calculate the distance between the center of racket and the center of ball, - reward = tanh(r/dist) if dist<1 reward almost 2 , if dist >= 1 reward is between [0, 0.2] - - - Args: - env: - - Returns: - - """ - - hit_contact_obj = ["target_ball", "bat"] - target_ball_pos = env.target_ball_pos - racket_center_pos = env.racket_center_pos - # hit contact detection - # Record the hitting history - self.hitting_flag = False - if not self.hit_contact_detector: - self.hit_contact_detector = self.contact_detection(env, hit_contact_obj) - if self.hit_contact_detector: - print("First time detect hitting") - self.hitting_flag = True - if self.hit_contact_detector: - - # TODO - dist = self.goal_distance(target_ball_pos, racket_center_pos) - if dist < 0: - dist = 0 - # print("goal distance is:", dist) - if dist <= self.shortest_hitting_dist: - self.shortest_hitting_dist = dist - # print("shortest_hitting_dist is:", self.shortest_hitting_dist) - # Keep the shortest hitting distance. - dist_reward = 2 * (1 - np.tanh(np.abs(self.shortest_hitting_dist))) - - # TODO sparse - # dist_reward = 2 - - self.total_reward += dist_reward - self.goal_achievement = True - - # if self.hitting_time_point is not None and self.hitting_time_point > 600: - # self.total_reward += 1 - - else: - dist = self.goal_distance(target_ball_pos, racket_center_pos) - if dist <= self.shortest_hitting_dist: - self.shortest_hitting_dist = dist - dist_reward = 1 - np.tanh(self.shortest_hitting_dist) - reward = 0.2 * dist_reward # because it does not hit the ball, so multiply 0.2 - self.total_reward += reward - self.goal_achievement = False - - self.refresh_highest_reward() - - @classmethod - def relu(cls, x): - return np.maximum(0, x) - - # def right_table_contact(self, env): - # right_court_contact_obj = ["target_ball", "table_tennis_table_right_side"] - # if env.target_ball_pos[0] >= 0 and env.target_ball_pos[2] >= 0.7: - # # update right court contact detection - # if not self.right_court_contact_detector: - # self.right_court_contact_detector = self.contact_detection(env, right_court_contact_obj) - # if self.right_court_contact_detector: - # self.contact_x_pos = env.target_ball_pos[0] - # if self.right_court_contact_detector: - # self.total_reward += 1 - norm(0.685, 1).pdf(self.contact_x_pos) # x axis middle of right table - # self.goal_achievement = False - # else: - # self.total_reward += 1 - # self.goal_achievement = True - # # else: - # # self.total_reward += 0 - # # self.goal_achievement = False - # self.refresh_highest_reward() - - # def net_contact(self, env): - # net_contact_obj = ["target_ball", "table_tennis_net"] - # # net_contact_detector = self.contact_detection(env, net_contact_obj) - # # ball_x_pos = env.target_ball_pos[0] - # # if self.min_ball_x_pos >= ball_x_pos: - # # self.min_ball_x_pos = ball_x_pos - # # table_left_edge_x_pos = -1.37 - # # if np.abs(ball_x_pos) <= 0.01: # x threshold of net - # # if self.lowest_z >= env.target_ball_pos[2]: - # # self.lowest_z = env.target_ball_pos[2] - # # # construct a gaussian distribution of z - # # z_reward = 4 - norm(0, 0.1).pdf(self.lowest_z - 0.07625) # maximum 4 - # # self.total_reward += z_reward - # # self.total_reward += 2 - np.minimum(1, self.relu(np.abs(self.min_ball_x_pos))) - # if not self.net_contact_detector: - # self.net_contact_detector = self.contact_detection(env, net_contact_obj) - # if self.net_contact_detector: - # self.total_reward += 0 # very high cost - # self.goal_achievement = False - # else: - # self.total_reward += 1 - # self.goal_achievement = True - # self.refresh_highest_reward() - - # def landing_on_opponent_court(self, env): - # # Very sparse reward - # # don't contact the right side court - # # right_court_contact_obj = ["target_ball", "table_tennis_table_right_side"] - # # right_court_contact_detector = self.contact_detection(env, right_court_contact_obj) - # left_court_contact_obj = ["target_ball", "table_tennis_table_left_side"] - # # left_court_contact_detector = self.contact_detection(env, left_court_contact_obj) - # # record the contact history - # # if not self.right_court_contact_detector: - # # self.right_court_contact_detector = self.contact_detection(env, right_court_contact_obj) - # if not self.table_contact_detector: - # self.table_contact_detector = self.contact_detection(env, left_court_contact_obj) - # - # dist_left_up_corner = self.goal_distance(env.target_ball_pos, env.sim.data.get_site_xpos("left_up_corner")) - # dist_middle_up_corner = self.goal_distance(env.target_ball_pos, env.sim.data.get_site_xpos("middle_up_corner")) - # dist_left_down_corner = self.goal_distance(env.target_ball_pos, env.sim.data.get_site_xpos("left_down_corner")) - # dist_middle_down_corner = self.goal_distance(env.target_ball_pos, - # env.sim.data.get_site_xpos("middle_down_corner")) - # dist_array = np.array( - # [dist_left_up_corner, dist_middle_up_corner, dist_left_down_corner, dist_middle_down_corner]) - # dist_corner = np.amin(dist_array) - # if self.lowest_corner_dist >= dist_corner: - # self.lowest_corner_dist = dist_corner - # - # right_contact_cost = 1 - # left_contact_reward = 2 - # dist_left_table_reward = (2 - np.tanh(self.lowest_corner_dist)) - # # TODO Try multi dimensional gaussian distribution - # # contact only the left side court - # if self.right_court_contact_detector: - # self.total_reward += 0 - # self.goal_achievement = False - # if self.table_contact_detector: - # self.total_reward += left_contact_reward - # self.goal_achievement = False - # else: - # self.total_reward += dist_left_table_reward - # self.goal_achievement = False - # else: - # self.total_reward += right_contact_cost - # if self.table_contact_detector: - # self.total_reward += left_contact_reward - # self.goal_achievement = True - # else: - # self.total_reward += dist_left_table_reward - # self.goal_achievement = False - # self.refresh_highest_reward() - # # if self.left_court_contact_detector and not self.right_court_contact_detector: - # # self.total_reward += self.ratio * left_contact_reward - # # print("only left court reward return!!!!!!!!!") - # # print("contact only left court!!!!!!") - # # self.goal_achievement = True - # # # no contact with table - # # elif not self.right_court_contact_detector and not self.left_court_contact_detector: - # # self.total_reward += 0 + self.ratio * dist_left_table_reward - # # self.goal_achievement = False - # # # contact both side - # # elif self.right_court_contact_detector and self.left_court_contact_detector: - # # self.total_reward += self.ratio * (left_contact_reward - right_contact_cost) # cost of contact of right court - # # self.goal_achievement = False - # # # contact only the right side court - # # elif self.right_court_contact_detector and not self.left_court_contact_detector: - # # self.total_reward += 0 + self.ratio * ( - # # dist_left_table_reward - right_contact_cost) # cost of contact of right court - # # self.goal_achievement = False - - def target_achievement(self, env): - target_coordinate = np.array([-0.5, -0.5]) - # net_contact_obj = ["target_ball", "table_tennis_net"] - table_contact_obj = ["target_ball", "table_tennis_table"] - floor_contact_obj = ["target_ball", "floor"] - - if 0.78 < env.target_ball_pos[2] < 0.8: - dist_target_virtual = np.linalg.norm(env.target_ball_pos[:2] - target_coordinate) - if self.dist_target_virtual > dist_target_virtual: - self.dist_target_virtual = dist_target_virtual - if -0.07 < env.target_ball_pos[0] < 0.07 and env.sim.data.get_joint_qvel('tar:x') < 0: - if self.ball_z_pos_lowest > env.target_ball_pos[2]: - self.ball_z_pos_lowest = env.target_ball_pos[2].copy() - # if not self.net_contact_detector: - # self.net_contact_detector = self.contact_detection(env, net_contact_obj) - if not self.table_contact_detector: - self.table_contact_detector = self.contact_detection(env, table_contact_obj) - if not self.floor_contact_detector: - self.floor_contact_detector = self.contact_detection(env, floor_contact_obj) - if not self.target_flag: - # Table Contact Reward. - if self.table_contact_detector: - self.total_reward += 1 - # only update when the first contact because of the flag - contact_coordinate = env.target_ball_pos[:2].copy() - print("contact table ball coordinate: ", env.target_ball_pos) - logging.info("contact table ball coordinate: {}".format(env.target_ball_pos)) - dist_target = np.linalg.norm(contact_coordinate - target_coordinate) - self.total_reward += (1 - np.tanh(dist_target)) * 2 - self.target_flag = True - # Net Contact Reward. Precondition: Table Contact exits. - if contact_coordinate[0] < 0: - print("left table contact") - logging.info("~~~~~~~~~~~~~~~left table contact~~~~~~~~~~~~~~~") - self.total_reward += 1 - # TODO Z coordinate reward - # self.total_reward += np.maximum(np.tanh(self.ball_z_pos_lowest), 0) - self.goal_achievement = True - else: - print("right table contact") - logging.info("~~~~~~~~~~~~~~~right table contact~~~~~~~~~~~~~~~") - self.total_reward += 0 - self.goal_achievement = False - # if self.net_contact_detector: - # self.total_reward += 0 - # self.goal_achievement = False - # else: - # self.total_reward += 1 - # self.goal_achievement = False - # Floor Contact Reward. Precondition: Table Contact exits. - elif self.floor_contact_detector: - self.total_reward += (1 - np.tanh(self.dist_target_virtual)) - self.target_flag = True - self.goal_achievement = False - # No Contact of Floor or Table, flying - else: - pass - # else: - # print("Flag is True already") - self.refresh_highest_reward() - - def distance_to_target(self): - pass - - @classmethod - def contact_detection(cls, env, goal_contact): - for i in range(env.sim.data.ncon): - contact = env.sim.data.contact[i] - achieved_geom1_name = env.sim.model.geom_id2name(contact.geom1) - achieved_geom2_name = env.sim.model.geom_id2name(contact.geom2) - if np.all([(achieved_geom1_name in goal_contact), (achieved_geom2_name in goal_contact)]): - print("contact of " + achieved_geom1_name + " " + achieved_geom2_name) - return True - else: - return False diff --git a/alr_envs/alr/mujoco/gym_table_tennis/utils/rewards/rewards.py b/alr_envs/alr/mujoco/gym_table_tennis/utils/rewards/rewards.py deleted file mode 100644 index 6e6aa32..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/utils/rewards/rewards.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright 2017 The dm_control Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================ - -# """Soft indicator function evaluating whether a number is within bounds.""" -# -# from __future__ import absolute_import -# from __future__ import division -# from __future__ import print_function - -# Internal dependencies. -import numpy as np - -# The value returned by tolerance() at `margin` distance from `bounds` interval. -_DEFAULT_VALUE_AT_MARGIN = 0.1 - - -def _sigmoids(x, value_at_1, sigmoid): - """Returns 1 when `x` == 0, between 0 and 1 otherwise. - - Args: - x: A scalar or numpy array. - value_at_1: A float between 0 and 1 specifying the output when `x` == 1. - sigmoid: String, choice of sigmoid type. - - Returns: - A numpy array with values between 0.0 and 1.0. - - Raises: - ValueError: If not 0 < `value_at_1` < 1, except for `linear`, `cosine` and - `quadratic` sigmoids which allow `value_at_1` == 0. - ValueError: If `sigmoid` is of an unknown type. - """ - if sigmoid in ('cosine', 'linear', 'quadratic'): - if not 0 <= value_at_1 < 1: - raise ValueError('`value_at_1` must be nonnegative and smaller than 1, ' - 'got {}.'.format(value_at_1)) - else: - if not 0 < value_at_1 < 1: - raise ValueError('`value_at_1` must be strictly between 0 and 1, ' - 'got {}.'.format(value_at_1)) - - if sigmoid == 'gaussian': - scale = np.sqrt(-2 * np.log(value_at_1)) - return np.exp(-0.5 * (x*scale)**2) - - elif sigmoid == 'hyperbolic': - scale = np.arccosh(1/value_at_1) - return 1 / np.cosh(x*scale) - - elif sigmoid == 'long_tail': - scale = np.sqrt(1/value_at_1 - 1) - return 1 / ((x*scale)**2 + 1) - - elif sigmoid == 'cosine': - scale = np.arccos(2*value_at_1 - 1) / np.pi - scaled_x = x*scale - return np.where(abs(scaled_x) < 1, (1 + np.cos(np.pi*scaled_x))/2, 0.0) - - elif sigmoid == 'linear': - scale = 1-value_at_1 - scaled_x = x*scale - return np.where(abs(scaled_x) < 1, 1 - scaled_x, 0.0) - - elif sigmoid == 'quadratic': - scale = np.sqrt(1-value_at_1) - scaled_x = x*scale - return np.where(abs(scaled_x) < 1, 1 - scaled_x**2, 0.0) - - elif sigmoid == 'tanh_squared': - scale = np.arctanh(np.sqrt(1-value_at_1)) - return 1 - np.tanh(x*scale)**2 - - else: - raise ValueError('Unknown sigmoid type {!r}.'.format(sigmoid)) - - -def tolerance(x, bounds=(0.0, 0.0), margin=0.0, sigmoid='gaussian', - value_at_margin=_DEFAULT_VALUE_AT_MARGIN): - """Returns 1 when `x` falls inside the bounds, between 0 and 1 otherwise. - - Args: - x: A scalar or numpy array. - bounds: A tuple of floats specifying inclusive `(lower, upper)` bounds for - the target interval. These can be infinite if the interval is unbounded - at one or both ends, or they can be equal to one another if the target - value is exact. - margin: Float. Parameter that controls how steeply the output decreases as - `x` moves out-of-bounds. - * If `margin == 0` then the output will be 0 for all values of `x` - outside of `bounds`. - * If `margin > 0` then the output will decrease sigmoidally with - increasing distance from the nearest bound. - sigmoid: String, choice of sigmoid type. Valid values are: 'gaussian', - 'linear', 'hyperbolic', 'long_tail', 'cosine', 'tanh_squared'. - value_at_margin: A float between 0 and 1 specifying the output value when - the distance from `x` to the nearest bound is equal to `margin`. Ignored - if `margin == 0`. - - Returns: - A float or numpy array with values between 0.0 and 1.0. - - Raises: - ValueError: If `bounds[0] > bounds[1]`. - ValueError: If `margin` is negative. - """ - lower, upper = bounds - if lower > upper: - raise ValueError('Lower bound must be <= upper bound.') - if margin < 0: - raise ValueError('`margin` must be non-negative.') - - in_bounds = np.logical_and(lower <= x, x <= upper) - if margin == 0: - value = np.where(in_bounds, 1.0, 0.0) - else: - d = np.where(x < lower, lower - x, x - upper) / margin - value = np.where(in_bounds, 1.0, _sigmoids(d, value_at_margin, sigmoid)) - - return float(value) if np.isscalar(x) else value - - - - - diff --git a/alr_envs/alr/mujoco/gym_table_tennis/utils/util.py b/alr_envs/alr/mujoco/gym_table_tennis/utils/util.py deleted file mode 100644 index fa308e3..0000000 --- a/alr_envs/alr/mujoco/gym_table_tennis/utils/util.py +++ /dev/null @@ -1,49 +0,0 @@ -import json -import yaml -import xml.etree.ElementTree as ET -from collections import OrderedDict -from pathlib import Path - - -def read_json(fname): - fname = Path(fname) - with fname.open('rt') as handle: - return json.load(handle, object_hook=OrderedDict) - - -def write_json(content, fname): - fname = Path(fname) - with fname.open('wt') as handle: - json.dump(content, handle, indent=4, sort_keys=False) - - -def read_yaml(fname): - fname = Path(fname) - with fname.open('rt') as handle: - return yaml.load(handle, Loader=yaml.FullLoader) - - -def write_yaml(content, fname): - fname = Path(fname) - with fname.open('wt') as handle: - yaml.dump(content, handle) - - -def config_save(dir_path, config): - dir_path = Path(dir_path) - config_path_json = dir_path / "config.json" - config_path_yaml = dir_path / "config.yml" - # .json and .yml file,save 2 version of configuration. - write_json(config, config_path_json) - write_yaml(config, config_path_yaml) - - -def change_kp_in_xml(kp_list, - model_path="/home/zhou/slow/table_tennis_rl/simulation/gymTableTennis/gym_table_tennis/simple_reacher/robotics/assets/table_tennis/right_arm_actuator.xml"): - tree = ET.parse(model_path) - root = tree.getroot() - # for actuator in root.find("actuator"): - for position, kp in zip(root.iter('position'), kp_list): - position.set("kp", str(kp)) - tree.write(model_path) - diff --git a/alr_envs/alr/mujoco/table_tennis/__init__.py b/alr_envs/alr/mujoco/table_tennis/__init__.py deleted file mode 100644 index c5e6d2f..0000000 --- a/alr_envs/alr/mujoco/table_tennis/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .mp_wrapper import MPWrapper diff --git a/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py b/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py deleted file mode 100644 index 40e4252..0000000 --- a/alr_envs/alr/mujoco/table_tennis/mp_wrapper.py +++ /dev/null @@ -1,38 +0,0 @@ -from typing import Tuple, Union - -import numpy as np - -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - - @property - def context_mask(self) -> np.ndarray: - # TODO: @Max Filter observations correctly - return np.hstack([ - [False] * 7, # Joint Pos - [True] * 2, # Ball pos - [True] * 2 # goal pos - ]) - - @property - def start_pos(self): - return self.self.init_qpos_tt - - @property - def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.sim.data.qpos[:7].copy() - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.sim.data.qvel[:7].copy() - - @property - def goal_pos(self): - # TODO: @Max I think the default value of returning to the start is reasonable here - raise ValueError("Goal position is not available and has to be learnt based on the environment.") - - @property - def dt(self) -> Union[float, int]: - return self.env.dt diff --git a/alr_envs/alr/mujoco/table_tennis/tt_gym.py b/alr_envs/alr/mujoco/table_tennis/tt_gym.py deleted file mode 100644 index 33db936..0000000 --- a/alr_envs/alr/mujoco/table_tennis/tt_gym.py +++ /dev/null @@ -1,184 +0,0 @@ -import os - -import numpy as np -import mujoco_py -from gym import utils, spaces -from gym.envs.mujoco import MujocoEnv - -from alr_envs.alr.mujoco.table_tennis.tt_utils import ball_init -from alr_envs.alr.mujoco.table_tennis.tt_reward import TT_Reward - -#TODO: Check for simulation stability. Make sure the code runs even for sim crash - -MAX_EPISODE_STEPS = 1375 # (1.25 + 1.5) /0.002 -BALL_NAME_CONTACT = "target_ball_contact" -BALL_NAME = "target_ball" -TABLE_NAME = 'table_tennis_table' -FLOOR_NAME = 'floor' -PADDLE_CONTACT_1_NAME = 'bat' -PADDLE_CONTACT_2_NAME = 'bat_back' -RACKET_NAME = 'bat' -# CONTEXT_RANGE_BOUNDS_2DIM = np.array([[-1.2, -0.6], [-0.2, 0.6]]) -CONTEXT_RANGE_BOUNDS_2DIM = np.array([[-1.2, -0.6], [-0.2, 0.0]]) -CONTEXT_RANGE_BOUNDS_4DIM = np.array([[-1.35, -0.75, -1.25, -0.75], [-0.1, 0.75, -0.1, 0.75]]) - - -class TTEnvGym(MujocoEnv, utils.EzPickle): - - def __init__(self, ctxt_dim=2, fixed_goal=False): - model_path = os.path.join(os.path.dirname(__file__), "xml", 'table_tennis_env.xml') - - self.ctxt_dim = ctxt_dim - self.fixed_goal = fixed_goal - if ctxt_dim == 2: - self.context_range_bounds = CONTEXT_RANGE_BOUNDS_2DIM - if self.fixed_goal: - self.goal = np.array([-1, -0.1, 0]) - else: - self.goal = np.zeros(3) # 2 x,y + 1z - elif ctxt_dim == 4: - self.context_range_bounds = CONTEXT_RANGE_BOUNDS_4DIM - self.goal = np.zeros(3) - else: - raise ValueError("either 2 or 4 dimensional Contexts available") - - # has no effect as it is overwritten in init of super - # action_space_low = np.array([-2.6, -2.0, -2.8, -0.9, -4.8, -1.6, -2.2]) - # action_space_high = np.array([2.6, 2.0, 2.8, 3.1, 1.3, 1.6, 2.2]) - # self.action_space = spaces.Box(low=action_space_low, high=action_space_high, dtype='float64') - - self.time_steps = 0 - self.init_qpos_tt = np.array([0, 0, 0, 1.5, 0, 0, 1.5, 0, 0, 0]) - self.init_qvel_tt = np.zeros(10) - - self.reward_func = TT_Reward(self.ctxt_dim) - self.ball_landing_pos = None - self.hit_ball = False - self.ball_contact_after_hit = False - self._ids_set = False - super(TTEnvGym, self).__init__(model_path=model_path, frame_skip=1) - self.ball_id = self.sim.model._body_name2id[BALL_NAME] # find the proper -> not protected func. - self.ball_contact_id = self.sim.model._geom_name2id[BALL_NAME_CONTACT] - self.table_contact_id = self.sim.model._geom_name2id[TABLE_NAME] - self.floor_contact_id = self.sim.model._geom_name2id[FLOOR_NAME] - self.paddle_contact_id_1 = self.sim.model._geom_name2id[PADDLE_CONTACT_1_NAME] # check if we need both or only this - self.paddle_contact_id_2 = self.sim.model._geom_name2id[PADDLE_CONTACT_2_NAME] # check if we need both or only this - self.racket_id = self.sim.model._geom_name2id[RACKET_NAME] - - - def _set_ids(self): - self.ball_id = self.sim.model._body_name2id[BALL_NAME] # find the proper -> not protected func. - self.table_contact_id = self.sim.model._geom_name2id[TABLE_NAME] - self.floor_contact_id = self.sim.model._geom_name2id[FLOOR_NAME] - self.paddle_contact_id_1 = self.sim.model._geom_name2id[PADDLE_CONTACT_1_NAME] # check if we need both or only this - self.paddle_contact_id_2 = self.sim.model._geom_name2id[PADDLE_CONTACT_2_NAME] # check if we need both or only this - self.racket_id = self.sim.model._geom_name2id[RACKET_NAME] - self.ball_contact_id = self.sim.model._geom_name2id[BALL_NAME_CONTACT] - self._ids_set = True - - def _get_obs(self): - ball_pos = self.sim.data.body_xpos[self.ball_id][:2].copy() - goal_pos = self.goal[:2].copy() - obs = np.concatenate([self.sim.data.qpos[:7].copy(), # 7 joint positions - ball_pos, - goal_pos]) - return obs - - def sample_context(self): - return self.np_random.uniform(self.context_range_bounds[0], self.context_range_bounds[1], size=self.ctxt_dim) - - def reset_model(self): - self.set_state(self.init_qpos_tt, self.init_qvel_tt) # reset to initial sim state - self.time_steps = 0 - self.ball_landing_pos = None - self.hit_ball = False - self.ball_contact_after_hit = False - if self.fixed_goal: - self.goal = self.goal[:2] - else: - self.goal = self.sample_context()[:2] - if self.ctxt_dim == 2: - initial_ball_state = ball_init(random=False) # fixed velocity, fixed position - elif self.ctxt_dim == 4: - initial_ball_state = ball_init(random=False)#raise NotImplementedError - - self.sim.data.set_joint_qpos('tar:x', initial_ball_state[0]) - self.sim.data.set_joint_qpos('tar:y', initial_ball_state[1]) - self.sim.data.set_joint_qpos('tar:z', initial_ball_state[2]) - - self.sim.data.set_joint_qvel('tar:x', initial_ball_state[3]) - self.sim.data.set_joint_qvel('tar:y', initial_ball_state[4]) - self.sim.data.set_joint_qvel('tar:z', initial_ball_state[5]) - - z_extended_goal_pos = np.concatenate((self.goal[:2], [0.77])) - self.goal = z_extended_goal_pos - self.sim.model.body_pos[5] = self.goal[:3] # Desired Landing Position, Yellow - self.sim.model.body_pos[3] = np.array([0, 0, 0.5]) # Outgoing Ball Landing Position, Green - self.sim.model.body_pos[4] = np.array([0, 0, 0.5]) # Incoming Ball Landing Position, Red - self.sim.forward() - - self.reward_func.reset(self.goal) # reset the reward function - self.n_step = 0 - return self._get_obs() - - def _contact_checker(self, id_1, id_2): - for coni in range(0, self.sim.data.ncon): - con = self.sim.data.contact[coni] - collision = con.geom1 == id_1 and con.geom2 == id_2 - collision_trans = con.geom1 == id_2 and con.geom2 == id_1 - if collision or collision_trans: - return True - return False - - def step(self, action): - if not self._ids_set: - self._set_ids() - done = False - episode_end = False if self.time_steps + 1 < MAX_EPISODE_STEPS else True - if not self.hit_ball: - self.hit_ball = self._contact_checker(self.ball_contact_id, self.paddle_contact_id_1) # check for one side - if not self.hit_ball: - self.hit_ball = self._contact_checker(self.ball_contact_id, self.paddle_contact_id_2) # check for other side - if self.hit_ball: - if not self.ball_contact_after_hit: - if self._contact_checker(self.ball_contact_id, self.floor_contact_id): # first check contact with floor - self.ball_contact_after_hit = True - self.ball_landing_pos = self.sim.data.body_xpos[self.ball_id] - elif self._contact_checker(self.ball_contact_id, self.table_contact_id): # second check contact with table - self.ball_contact_after_hit = True - self.ball_landing_pos = self.sim.data.body_xpos[self.ball_id] - c_ball_pos = self.sim.data.body_xpos[self.ball_id] - racket_pos = self.sim.data.geom_xpos[self.racket_id] # TODO: use this to reach out the position of the paddle? - if self.ball_landing_pos is not None: - done = True - episode_end =True - reward = self.reward_func.get_reward(episode_end, c_ball_pos, racket_pos, self.hit_ball, self.ball_landing_pos) - self.time_steps += 1 - # gravity compensation on joints: - #action += self.sim.data.qfrc_bias[:7].copy() - try: - self.do_simulation(action, self.frame_skip) - except mujoco_py.MujocoException as e: - print('Simulation got unstable returning') - done = True - reward = -25 - ob = self._get_obs() - info = {"hit_ball": self.hit_ball, - "q_pos": np.copy(self.sim.data.qpos[:7]), - "ball_pos": np.copy(self.sim.data.qpos[7:])} - self.n_step += 1 - return ob, reward, done, info # might add some information here .... - - def set_context(self, context): - old_state = self.sim.get_state() - qpos = old_state.qpos.copy() - qvel = old_state.qvel.copy() - self.set_state(qpos, qvel) - self.goal = context - z_extended_goal_pos = np.concatenate((self.goal[:self.ctxt_dim], [0.77])) - if self.ctxt_dim == 4: - z_extended_goal_pos = np.concatenate((z_extended_goal_pos, [0.77])) - self.goal = z_extended_goal_pos - self.sim.model.body_pos[5] = self.goal[:3] # TODO: Missing: Setting the desired incomoing landing position - self.sim.forward() - return self._get_obs() diff --git a/alr_envs/alr/mujoco/table_tennis/tt_reward.py b/alr_envs/alr/mujoco/table_tennis/tt_reward.py deleted file mode 100644 index 0e1bebf..0000000 --- a/alr_envs/alr/mujoco/table_tennis/tt_reward.py +++ /dev/null @@ -1,48 +0,0 @@ -import numpy as np - - -class TT_Reward: - - def __init__(self, ctxt_dim): - self.ctxt_dim = ctxt_dim - self.c_goal = None # current desired landing point - self.c_ball_traj = [] - self.c_racket_traj = [] - self.constant = 8 - - def get_reward(self, episode_end, ball_position, racket_pos, hited_ball, ball_landing_pos): - self.c_ball_traj.append(ball_position.copy()) - self.c_racket_traj.append(racket_pos.copy()) - if not episode_end: - return 0 - else: - # # seems to work for episodic case - min_r_b_dist = np.min(np.linalg.norm(np.array(self.c_ball_traj) - np.array(self.c_racket_traj), axis=1)) - if not hited_ball: - return 0.2 * (1 - np.tanh(min_r_b_dist**2)) - else: - if ball_landing_pos is None: - min_b_des_b_dist = np.min(np.linalg.norm(np.array(self.c_ball_traj)[:,:2] - self.c_goal[:2], axis=1)) - return 2 * (1 - np.tanh(min_r_b_dist ** 2)) + (1 - np.tanh(min_b_des_b_dist**2)) - else: - min_b_des_b_land_dist = np.linalg.norm(self.c_goal[:2] - ball_landing_pos[:2]) - over_net_bonus = int(ball_landing_pos[0] < 0) - return 2 * (1 - np.tanh(min_r_b_dist ** 2)) + 4 * (1 - np.tanh(min_b_des_b_land_dist ** 2)) + over_net_bonus - - - # if not hited_ball: - # min_r_b_dist = 1 + np.min(np.linalg.norm(np.array(self.c_ball_traj) - np.array(self.c_racket_traj), axis=1)) - # return -min_r_b_dist - # else: - # if ball_landing_pos is None: - # dist_to_des_pos = 1-np.power(np.linalg.norm(self.c_goal - ball_position), 0.75)/self.constant - # else: - # dist_to_des_pos = 1-np.power(np.linalg.norm(self.c_goal - ball_landing_pos), 0.75)/self.constant - # if dist_to_des_pos < -0.2: - # dist_to_des_pos = -0.2 - # return -dist_to_des_pos - - def reset(self, goal): - self.c_goal = goal.copy() - self.c_ball_traj = [] - self.c_racket_traj = [] \ No newline at end of file diff --git a/alr_envs/alr/mujoco/table_tennis/tt_utils.py b/alr_envs/alr/mujoco/table_tennis/tt_utils.py deleted file mode 100644 index 04a1b97..0000000 --- a/alr_envs/alr/mujoco/table_tennis/tt_utils.py +++ /dev/null @@ -1,26 +0,0 @@ -import numpy as np - - -def ball_init(random=False, context_range=None): - if random: - dx = np.random.uniform(-0.1, 0.1) # TODO: clarify these numbers? - dy = np.random.uniform(-0.1, 0.1) # TODO: clarify these numbers? - dz = np.random.uniform(-0.1, 0.1) # TODO: clarify these numbers? - - v_x = np.random.uniform(1.7, 1.8) - v_y = np.random.uniform(0.7, 0.8) - v_z = np.random.uniform(0.1, 0.2) - else: - dx = 1 - dy = 0 - dz = 0.05 - - v_x = 2.5 - v_y = 2 - v_z = 0.5 - - initial_x = 0 + dx - 1.2 - initial_y = -0.2 + dy - 0.6 - initial_z = 0.3 + dz + 1.5 - initial_ball_state = np.array([initial_x, initial_y, initial_z, v_x, v_y, v_z]) - return initial_ball_state diff --git a/alr_envs/alr/mujoco/table_tennis/xml/include_7_motor_actuator.xml b/alr_envs/alr/mujoco/table_tennis/xml/include_7_motor_actuator.xml deleted file mode 100644 index ec94d96..0000000 --- a/alr_envs/alr/mujoco/table_tennis/xml/include_7_motor_actuator.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/alr_envs/alr/mujoco/table_tennis/xml/include_barrett_wam_7dof_right.xml b/alr_envs/alr/mujoco/table_tennis/xml/include_barrett_wam_7dof_right.xml deleted file mode 100644 index 7e04c28..0000000 --- a/alr_envs/alr/mujoco/table_tennis/xml/include_barrett_wam_7dof_right.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/alr_envs/alr/mujoco/table_tennis/xml/include_table.xml b/alr_envs/alr/mujoco/table_tennis/xml/include_table.xml deleted file mode 100644 index c313489..0000000 --- a/alr_envs/alr/mujoco/table_tennis/xml/include_table.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/alr_envs/alr/mujoco/table_tennis/xml/include_target_ball.xml b/alr_envs/alr/mujoco/table_tennis/xml/include_target_ball.xml deleted file mode 100644 index 19543e2..0000000 --- a/alr_envs/alr/mujoco/table_tennis/xml/include_target_ball.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/alr_envs/alr/mujoco/table_tennis/xml/right_arm_actuator.xml b/alr_envs/alr/mujoco/table_tennis/xml/right_arm_actuator.xml deleted file mode 100644 index 25d0366..0000000 --- a/alr_envs/alr/mujoco/table_tennis/xml/right_arm_actuator.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/alr_envs/alr/mujoco/table_tennis/xml/shared.xml b/alr_envs/alr/mujoco/table_tennis/xml/shared.xml deleted file mode 100644 index e349992..0000000 --- a/alr_envs/alr/mujoco/table_tennis/xml/shared.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/alr_envs/alr/mujoco/table_tennis/xml/table_tennis_env.xml b/alr_envs/alr/mujoco/table_tennis/xml/table_tennis_env.xml deleted file mode 100644 index 9609a6e..0000000 --- a/alr_envs/alr/mujoco/table_tennis/xml/table_tennis_env.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py b/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py deleted file mode 100644 index 63432a7..0000000 --- a/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Tuple, Union - -import numpy as np - -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper - - -class MPWrapper(RawInterfaceWrapper): - - @property - def context_mask(self): - return np.hstack([ - [False] * 17, - [True] # goal pos - ]) - - @property - def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.data.qpos[3:9].copy() - - @property - def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.data.qvel[3:9].copy() From 9b2c330ebfb1a53740326ce01f159f38e254487c Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 6 Jul 2022 09:18:41 +0200 Subject: [PATCH 063/104] mp wrapper beer pong --- alr_envs/alr/mujoco/beerpong/mp_wrapper.py | 42 ++++++++++++++++++++++ setup.py | 10 ++---- 2 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 alr_envs/alr/mujoco/beerpong/mp_wrapper.py diff --git a/alr_envs/alr/mujoco/beerpong/mp_wrapper.py b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py new file mode 100644 index 0000000..e69d4f9 --- /dev/null +++ b/alr_envs/alr/mujoco/beerpong/mp_wrapper.py @@ -0,0 +1,42 @@ +from typing import Union, Tuple + +import numpy as np + +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper + + +class MPWrapper(RawInterfaceWrapper): + + def get_context_mask(self): + return np.hstack([ + [False] * 7, # cos + [False] * 7, # sin + [False] * 7, # joint velocities + [False] * 3, # cup_goal_diff_final + [False] * 3, # cup_goal_diff_top + [True] * 2, # xy position of cup + [False] # env steps + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qpos[0:7].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[0:7].copy() + + # TODO: Fix this + def _episode_callback(self, action: np.ndarray, mp) -> Tuple[np.ndarray, Union[np.ndarray, None]]: + if mp.learn_tau: + self.env.env.release_step = action[0] / self.env.dt # Tau value + return action, None + else: + return action, None + + def set_context(self, context): + xyz = np.zeros(3) + xyz[:2] = context + xyz[-1] = 0.840 + self.env.env.model.body_pos[self.env.env.cup_table_id] = xyz + return self.get_observation_from_step(self.env.env._get_obs()) diff --git a/setup.py b/setup.py index 055ac81..e99b393 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from setuptools import setup # Environment-specific dependencies for dmc and metaworld extras = { "dmc": ["dm_control"], - "meta": ["mujoco_py<2.2,>=2.1, git+https://github.com/rlworkgroup/metaworld.git@master#egg=metaworld"], + "meta": ["metaworld @ git+https://github.com/rlworkgroup/metaworld.git@master#egg=metaworld"], "mujoco": ["mujoco==2.2.0", "imageio>=2.14.1"], } @@ -20,13 +20,7 @@ setup( packages=['alr_envs', 'alr_envs.alr', 'alr_envs.open_ai', 'alr_envs.dmc', 'alr_envs.meta', 'alr_envs.utils'], install_requires=[ 'gym', - 'PyQt5', - # 'matplotlib', - # 'mp_env_api @ git+https://github.com/ALRhub/motion_primitive_env_api.git', - # 'mp_env_api @ git+ssh://git@github.com/ALRhub/motion_primitive_env_api.git', - 'mujoco-py<2.1,>=2.0', - 'dm_control', - 'metaworld @ git+https://github.com/rlworkgroup/metaworld.git@master#egg=metaworld', + "mujoco_py<2.2,>=2.1", ], url='https://github.com/ALRhub/alr_envs/', # license='AGPL-3.0 license', From 78d48c43003efe5cca30b159c231da68fc48cc8f Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 6 Jul 2022 09:19:21 +0200 Subject: [PATCH 064/104] mp wrappers added --- alr_envs/alr/mujoco/ant_jump/mp_wrapper.py | 23 +++++++++++++++++++ .../alr/mujoco/walker_2d_jump/mp_wrapper.py | 23 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 alr_envs/alr/mujoco/ant_jump/mp_wrapper.py create mode 100644 alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py diff --git a/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py b/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py new file mode 100644 index 0000000..a481d6f --- /dev/null +++ b/alr_envs/alr/mujoco/ant_jump/mp_wrapper.py @@ -0,0 +1,23 @@ +from typing import Union, Tuple + +import numpy as np + +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper + + +class MPWrapper(RawInterfaceWrapper): + + @property + def context_mask(self): + return np.hstack([ + [False] * 111, # ant has 111 dimensional observation space !! + [True] # goal height + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray]: + return self.env.sim.data.qpos[7:15].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.sim.data.qvel[6:14].copy() diff --git a/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py b/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py new file mode 100644 index 0000000..63432a7 --- /dev/null +++ b/alr_envs/alr/mujoco/walker_2d_jump/mp_wrapper.py @@ -0,0 +1,23 @@ +from typing import Tuple, Union + +import numpy as np + +from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper + + +class MPWrapper(RawInterfaceWrapper): + + @property + def context_mask(self): + return np.hstack([ + [False] * 17, + [True] # goal pos + ]) + + @property + def current_pos(self) -> Union[float, int, np.ndarray]: + return self.env.data.qpos[3:9].copy() + + @property + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: + return self.env.data.qvel[3:9].copy() From 2706af0b77a688d55075fabc2f821a85e4066a65 Mon Sep 17 00:00:00 2001 From: Onur Date: Wed, 6 Jul 2022 11:29:04 +0200 Subject: [PATCH 065/104] refactored meshes, cleaned up init -- now with DMP -- --- alr_envs/alr/__init__.py | 230 +++++++----------- alr_envs/alr/mujoco/__init__.py | 5 +- .../assets/beerpong_wo_cup_big_table.xml | 2 +- .../assets}/meshes/wam/base_link_convex.stl | Bin .../assets}/meshes/wam/base_link_fine.stl | Bin .../wam/bhand_finger_dist_link_convex.stl | Bin .../wam/bhand_finger_dist_link_fine.stl | Bin .../wam/bhand_finger_med_link_convex.stl | Bin .../meshes/wam/bhand_finger_med_link_fine.stl | Bin ...nger_prox_link_convex_decomposition_p1.stl | Bin ...nger_prox_link_convex_decomposition_p2.stl | Bin ...nger_prox_link_convex_decomposition_p3.stl | Bin .../wam/bhand_finger_prox_link_fine.stl | Bin .../assets}/meshes/wam/bhand_palm_fine.stl | Bin ...hand_palm_link_convex_decomposition_p1.stl | Bin ...hand_palm_link_convex_decomposition_p2.stl | Bin ...hand_palm_link_convex_decomposition_p3.stl | Bin ...hand_palm_link_convex_decomposition_p4.stl | Bin .../{ => beerpong/assets}/meshes/wam/cup.stl | Bin .../assets}/meshes/wam/cup_split1.stl | Bin .../assets}/meshes/wam/cup_split10.stl | Bin .../assets}/meshes/wam/cup_split11.stl | Bin .../assets}/meshes/wam/cup_split12.stl | Bin .../assets}/meshes/wam/cup_split13.stl | Bin .../assets}/meshes/wam/cup_split14.stl | Bin .../assets}/meshes/wam/cup_split15.stl | Bin .../assets}/meshes/wam/cup_split16.stl | Bin .../assets}/meshes/wam/cup_split17.stl | Bin .../assets}/meshes/wam/cup_split18.stl | Bin .../assets}/meshes/wam/cup_split2.stl | Bin .../assets}/meshes/wam/cup_split3.stl | Bin .../assets}/meshes/wam/cup_split4.stl | Bin .../assets}/meshes/wam/cup_split5.stl | Bin .../assets}/meshes/wam/cup_split6.stl | Bin .../assets}/meshes/wam/cup_split7.stl | Bin .../assets}/meshes/wam/cup_split8.stl | Bin .../assets}/meshes/wam/cup_split9.stl | Bin .../assets}/meshes/wam/elbow_link_convex.stl | Bin .../assets}/meshes/wam/elbow_link_fine.stl | Bin .../forearm_link_convex_decomposition_p1.stl | Bin .../forearm_link_convex_decomposition_p2.stl | Bin .../assets}/meshes/wam/forearm_link_fine.stl | Bin .../shoulder_link_convex_decomposition_p1.stl | Bin .../shoulder_link_convex_decomposition_p2.stl | Bin .../shoulder_link_convex_decomposition_p3.stl | Bin .../assets}/meshes/wam/shoulder_link_fine.stl | Bin .../meshes/wam/shoulder_pitch_link_convex.stl | Bin .../meshes/wam/shoulder_pitch_link_fine.stl | Bin ...upper_arm_link_convex_decomposition_p1.stl | Bin ...upper_arm_link_convex_decomposition_p2.stl | Bin .../meshes/wam/upper_arm_link_fine.stl | Bin .../meshes/wam/wrist_palm_link_convex.stl | Bin .../meshes/wam/wrist_palm_link_fine.stl | Bin ...ist_pitch_link_convex_decomposition_p1.stl | Bin ...ist_pitch_link_convex_decomposition_p2.stl | Bin ...ist_pitch_link_convex_decomposition_p3.stl | Bin .../meshes/wam/wrist_pitch_link_fine.stl | Bin ...wrist_yaw_link_convex_decomposition_p1.stl | Bin ...wrist_yaw_link_convex_decomposition_p2.stl | Bin .../meshes/wam/wrist_yaw_link_fine.stl | Bin alr_envs/alr/mujoco/beerpong/beerpong.py | 29 +-- alr_envs/alr/mujoco/reacher/reacher.py | 2 +- alr_envs/black_box/black_box_wrapper.py | 2 +- alr_envs/utils/make_env_helpers.py | 1 - 64 files changed, 109 insertions(+), 162 deletions(-) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/base_link_convex.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/base_link_fine.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_finger_dist_link_convex.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_finger_dist_link_fine.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_finger_med_link_convex.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_finger_med_link_fine.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_finger_prox_link_convex_decomposition_p1.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_finger_prox_link_convex_decomposition_p2.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_finger_prox_link_convex_decomposition_p3.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_finger_prox_link_fine.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_palm_fine.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_palm_link_convex_decomposition_p1.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_palm_link_convex_decomposition_p2.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_palm_link_convex_decomposition_p3.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/bhand_palm_link_convex_decomposition_p4.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split1.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split10.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split11.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split12.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split13.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split14.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split15.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split16.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split17.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split18.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split2.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split3.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split4.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split5.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split6.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split7.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split8.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/cup_split9.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/elbow_link_convex.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/elbow_link_fine.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/forearm_link_convex_decomposition_p1.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/forearm_link_convex_decomposition_p2.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/forearm_link_fine.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/shoulder_link_convex_decomposition_p1.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/shoulder_link_convex_decomposition_p2.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/shoulder_link_convex_decomposition_p3.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/shoulder_link_fine.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/shoulder_pitch_link_convex.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/shoulder_pitch_link_fine.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/upper_arm_link_convex_decomposition_p1.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/upper_arm_link_convex_decomposition_p2.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/upper_arm_link_fine.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/wrist_palm_link_convex.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/wrist_palm_link_fine.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/wrist_pitch_link_convex_decomposition_p1.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/wrist_pitch_link_convex_decomposition_p2.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/wrist_pitch_link_convex_decomposition_p3.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/wrist_pitch_link_fine.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/wrist_yaw_link_convex_decomposition_p1.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/wrist_yaw_link_convex_decomposition_p2.stl (100%) rename alr_envs/alr/mujoco/{ => beerpong/assets}/meshes/wam/wrist_yaw_link_fine.stl (100%) diff --git a/alr_envs/alr/__init__.py b/alr_envs/alr/__init__.py index cdff3a1..1b7d378 100644 --- a/alr_envs/alr/__init__.py +++ b/alr_envs/alr/__init__.py @@ -3,14 +3,11 @@ from copy import deepcopy import numpy as np from gym import register -from alr_envs.alr.mujoco.table_tennis.tt_gym import MAX_EPISODE_STEPS from . import classic_control, mujoco from .classic_control.hole_reacher.hole_reacher import HoleReacherEnv from .classic_control.simple_reacher.simple_reacher import SimpleReacherEnv from .classic_control.viapoint_reacher.viapoint_reacher import ViaPointReacherEnv from .mujoco.ant_jump.ant_jump import MAX_EPISODE_STEPS_ANTJUMP -from .mujoco.ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv -from .mujoco.ball_in_a_cup.biac_pd import ALRBallInACupPDEnv from .mujoco.half_cheetah_jump.half_cheetah_jump import MAX_EPISODE_STEPS_HALFCHEETAHJUMP from .mujoco.hopper_jump.hopper_jump import MAX_EPISODE_STEPS_HOPPERJUMP from .mujoco.hopper_jump.hopper_jump_on_box import MAX_EPISODE_STEPS_HOPPERJUMPONBOX @@ -21,17 +18,14 @@ from .mujoco.walker_2d_jump.walker_2d_jump import MAX_EPISODE_STEPS_WALKERJUMP ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": []} -DEFAULT_BB_DICT = { +DEFAULT_BB_DICT_ProMP = { "name": 'EnvName', "wrappers": [], "trajectory_generator_kwargs": { 'trajectory_generator_type': 'promp' }, "phase_generator_kwargs": { - 'phase_generator_type': 'linear', - 'delay': 0, - 'learn_tau': False, - 'learn_delay': False + 'phase_generator_type': 'linear' }, "controller_kwargs": { 'controller_type': 'motor', @@ -45,6 +39,26 @@ DEFAULT_BB_DICT = { } } +DEFAULT_BB_DICT_DMP = { + "name": 'EnvName', + "wrappers": [], + "trajectory_generator_kwargs": { + 'trajectory_generator_type': 'dmp' + }, + "phase_generator_kwargs": { + 'phase_generator_type': 'exp' + }, + "controller_kwargs": { + 'controller_type': 'motor', + "p_gains": 1.0, + "d_gains": 0.1, + }, + "basis_generator_kwargs": { + 'basis_generator_type': 'rbf', + 'num_basis': 5 + } +} + # Classic Control ## Simple Reacher register( @@ -199,130 +213,83 @@ register( } ) -## Table Tennis -register(id='TableTennis2DCtxt-v0', - entry_point='alr_envs.alr.mujoco:TTEnvGym', - max_episode_steps=MAX_EPISODE_STEPS, - kwargs={'ctxt_dim': 2}) - -register(id='TableTennis4DCtxt-v0', - entry_point='alr_envs.alr.mujocco:TTEnvGym', - max_episode_steps=MAX_EPISODE_STEPS, - kwargs={'ctxt_dim': 4}) - register( id='BeerPong-v0', - entry_point='alr_envs.alr.mujoco:BeerBongEnv', + entry_point='alr_envs.alr.mujoco:BeerPongEnv', max_episode_steps=300, - kwargs={ - "frame_skip": 2 - } ) -register( - id='BeerPong-v1', - entry_point='alr_envs.alr.mujoco:BeerBongEnv', - max_episode_steps=300, - kwargs={ - "frame_skip": 2 - } -) - -# Here we use the same reward as in ALRBeerPong-v0, but now consider after the release, +# Here we use the same reward as in BeerPong-v0, but now consider after the release, # only one time step, i.e. we simulate until the end of th episode register( id='BeerPongStepBased-v0', - entry_point='alr_envs.alr.mujoco:BeerBongEnvStepBased', + entry_point='alr_envs.alr.mujoco:BeerPongEnvStepBasedEpisodicReward', max_episode_steps=300, - kwargs={ - "cup_goal_pos": [-0.3, -1.2], - "frame_skip": 2 - } ) # Beerpong with episodic reward, but fixed release time step register( id='BeerPongFixedRelease-v0', - entry_point='alr_envs.alr.mujoco:BeerBongEnvFixedReleaseStep', + entry_point='alr_envs.alr.mujoco:BeerPongEnvFixedReleaseStep', max_episode_steps=300, - kwargs={ - "cup_goal_pos": [-0.3, -1.2], - "frame_skip": 2 - } ) # Motion Primitive Environments ## Simple Reacher -_versions = ["SimpleReacher-v0", "SimpleReacher-v1", "LongSimpleReacher-v0", "LongSimpleReacher-v1"] +_versions = ["SimpleReacher-v0", "LongSimpleReacher-v0"] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}DMP-{_name[1]}' + kwargs_dict_simple_reacher_dmp = deepcopy(DEFAULT_BB_DICT_DMP) + kwargs_dict_simple_reacher_dmp['wrappers'].append(classic_control.simple_reacher.MPWrapper) + kwargs_dict_simple_reacher_dmp['controller_kwargs']['p_gains'] = 0.6 + kwargs_dict_simple_reacher_dmp['controller_kwargs']['d_gains'] = 0.075 + kwargs_dict_simple_reacher_dmp['trajectory_generator_kwargs']['weight_scale'] = 50 + kwargs_dict_simple_reacher_dmp['phase_generator_kwargs']['alpha_phase'] = 2 + kwargs_dict_simple_reacher_dmp['name'] = f"{_v}" register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_dmp_env_helper', - # max_episode_steps=1, - kwargs={ - "name": f"{_v}", - "wrappers": [classic_control.simple_reacher.MPWrapper], - "traj_gen_kwargs": { - "num_dof": 2 if "long" not in _v.lower() else 5, - "num_basis": 5, - "duration": 2, - "alpha_phase": 2, - "learn_goal": True, - "policy_type": "motor", - "weights_scale": 50, - "policy_kwargs": { - "p_gains": .6, - "d_gains": .075 - } - } - } + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + kwargs=kwargs_dict_simple_reacher_dmp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_simple_reacher_promp = deepcopy(DEFAULT_BB_DICT) + kwargs_dict_simple_reacher_promp = deepcopy(DEFAULT_BB_DICT_ProMP) kwargs_dict_simple_reacher_promp['wrappers'].append(classic_control.simple_reacher.MPWrapper) kwargs_dict_simple_reacher_promp['controller_kwargs']['p_gains'] = 0.6 kwargs_dict_simple_reacher_promp['controller_kwargs']['d_gains'] = 0.075 - kwargs_dict_simple_reacher_promp['name'] = _env_id + kwargs_dict_simple_reacher_promp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_simple_reacher_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) # Viapoint reacher +kwargs_dict_via_point_reacher_dmp = deepcopy(DEFAULT_BB_DICT_DMP) +kwargs_dict_via_point_reacher_dmp['wrappers'].append(classic_control.viapoint_reacher.MPWrapper) +kwargs_dict_via_point_reacher_dmp['controller_kwargs']['controller_type'] = 'velocity' +kwargs_dict_via_point_reacher_dmp['trajectory_generator_kwargs']['weight_scale'] = 50 +kwargs_dict_via_point_reacher_dmp['phase_generator_kwargs']['alpha_phase'] = 2 +kwargs_dict_via_point_reacher_dmp['name'] = "ViaPointReacher-v0" register( id='ViaPointReacherDMP-v0', - entry_point='alr_envs.utils.make_env_helpers:make_dmp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', # max_episode_steps=1, - kwargs={ - "name": "ViaPointReacher-v0", - "wrappers": [classic_control.viapoint_reacher.MPWrapper], - "traj_gen_kwargs": { - "num_dof": 5, - "num_basis": 5, - "duration": 2, - "learn_goal": True, - "alpha_phase": 2, - "policy_type": "velocity", - "weights_scale": 50, - } - } + kwargs=kwargs_dict_via_point_reacher_dmp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append("ViaPointReacherDMP-v0") -kwargs_dict_via_point_reacher_promp = deepcopy(DEFAULT_BB_DICT) +kwargs_dict_via_point_reacher_promp = deepcopy(DEFAULT_BB_DICT_ProMP) kwargs_dict_via_point_reacher_promp['wrappers'].append(classic_control.viapoint_reacher.MPWrapper) kwargs_dict_via_point_reacher_promp['controller_kwargs']['controller_type'] = 'velocity' -kwargs_dict_via_point_reacher_promp['name'] = "ViaPointReacherProMP-v0" +kwargs_dict_via_point_reacher_promp['name'] = "ViaPointReacher-v0" register( id="ViaPointReacherProMP-v0", - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_via_point_reacher_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ViaPointReacherProMP-v0") @@ -332,37 +299,30 @@ _versions = ["HoleReacher-v0"] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}DMP-{_name[1]}' + kwargs_dict_hole_reacher_dmp = deepcopy(DEFAULT_BB_DICT_DMP) + kwargs_dict_hole_reacher_dmp['wrappers'].append(classic_control.hole_reacher.MPWrapper) + kwargs_dict_hole_reacher_dmp['controller_kwargs']['controller_type'] = 'velocity' + # TODO: Before it was weight scale 50 and goal scale 0.1. We now only have weight scale and thus set it to 500. Check + kwargs_dict_hole_reacher_dmp['trajectory_generator_kwargs']['weight_scale'] = 500 + kwargs_dict_hole_reacher_dmp['phase_generator_kwargs']['alpha_phase'] = 2.5 + kwargs_dict_hole_reacher_dmp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_dmp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', # max_episode_steps=1, - kwargs={ - "name": f"HoleReacher-{_v}", - "wrappers": [classic_control.hole_reacher.MPWrapper], - "traj_gen_kwargs": { - "num_dof": 5, - "num_basis": 5, - "duration": 2, - "learn_goal": True, - "alpha_phase": 2.5, - "bandwidth_factor": 2, - "policy_type": "velocity", - "weights_scale": 50, - "goal_scale": 0.1 - } - } + kwargs=kwargs_dict_hole_reacher_dmp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_hole_reacher_promp = deepcopy(DEFAULT_BB_DICT) + kwargs_dict_hole_reacher_promp = deepcopy(DEFAULT_BB_DICT_ProMP) kwargs_dict_hole_reacher_promp['wrappers'].append(classic_control.hole_reacher.MPWrapper) kwargs_dict_hole_reacher_promp['trajectory_generator_kwargs']['weight_scale'] = 2 kwargs_dict_hole_reacher_promp['controller_kwargs']['controller_type'] = 'velocity' kwargs_dict_hole_reacher_promp['name'] = f"{_v}" register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_hole_reacher_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -372,36 +332,26 @@ _versions = ["Reacher5d-v0", "Reacher7d-v0", "Reacher5dSparse-v0", "Reacher7dSpa for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}DMP-{_name[1]}' + kwargs_dict_reacherNd_dmp = deepcopy(DEFAULT_BB_DICT_DMP) + kwargs_dict_reacherNd_dmp['wrappers'].append(mujoco.reacher.MPWrapper) + kwargs_dict_reacherNd_dmp['trajectory_generator_kwargs']['weight_scale'] = 5 + kwargs_dict_reacherNd_dmp['phase_generator_kwargs']['alpha_phase'] = 2 + kwargs_dict_reacherNd_dmp['basis_generator_kwargs']['num_basis'] = 2 + kwargs_dict_reacherNd_dmp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_dmp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', # max_episode_steps=1, - kwargs={ - "name": f"{_v}", - "wrappers": [mujoco.reacher.MPWrapper], - "traj_gen_kwargs": { - "num_dof": 5 if "long" not in _v.lower() else 7, - "num_basis": 2, - "duration": 4, - "alpha_phase": 2, - "learn_goal": True, - "policy_type": "motor", - "weights_scale": 5, - "policy_kwargs": { - "p_gains": 1, - "d_gains": 0.1 - } - } - } + kwargs=kwargs_dict_reacherNd_dmp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_alr_reacher_promp = deepcopy(DEFAULT_BB_DICT) + kwargs_dict_alr_reacher_promp = deepcopy(DEFAULT_BB_DICT_ProMP) kwargs_dict_alr_reacher_promp['wrappers'].append(mujoco.reacher.MPWrapper) kwargs_dict_alr_reacher_promp['controller_kwargs']['p_gains'] = 1 kwargs_dict_alr_reacher_promp['controller_kwargs']['d_gains'] = 0.1 - kwargs_dict_alr_reacher_promp['name'] = f"{_v}" + kwargs_dict_alr_reacher_promp['name'] = _v register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', @@ -415,14 +365,14 @@ _versions = ['BeerPong-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_bp_promp = deepcopy(DEFAULT_BB_DICT) + kwargs_dict_bp_promp = deepcopy(DEFAULT_BB_DICT_ProMP) kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.MPWrapper) kwargs_dict_bp_promp['phase_generator_kwargs']['learn_tau'] = True kwargs_dict_bp_promp['controller_kwargs']['p_gains'] = np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]) kwargs_dict_bp_promp['controller_kwargs']['d_gains'] = np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis'] = 2 kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis_zero_start'] = 2 - kwargs_dict_bp_promp['name'] = f"{_v}" + kwargs_dict_bp_promp['name'] = _v register( id=_env_id, entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', @@ -435,17 +385,17 @@ _versions = ["BeerPongStepBased-v0", "BeerPongFixedRelease-v0"] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_bp_promp = deepcopy(DEFAULT_BB_DICT) + kwargs_dict_bp_promp = deepcopy(DEFAULT_BB_DICT_ProMP) kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.MPWrapper) kwargs_dict_bp_promp['phase_generator_kwargs']['tau'] = 0.62 kwargs_dict_bp_promp['controller_kwargs']['p_gains'] = np.array([1.5, 5, 2.55, 3, 2., 2, 1.25]) kwargs_dict_bp_promp['controller_kwargs']['d_gains'] = np.array([0.02333333, 0.1, 0.0625, 0.08, 0.03, 0.03, 0.0125]) kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis'] = 2 kwargs_dict_bp_promp['basis_generator_kwargs']['num_basis_zero_start'] = 2 - kwargs_dict_bp_promp['name'] = f"{_v}" + kwargs_dict_bp_promp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_bp_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -460,12 +410,12 @@ _versions = ['ALRAntJump-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_ant_jump_promp = deepcopy(DEFAULT_BB_DICT) + kwargs_dict_ant_jump_promp = deepcopy(DEFAULT_BB_DICT_ProMP) kwargs_dict_ant_jump_promp['wrappers'].append(mujoco.ant_jump.MPWrapper) - kwargs_dict_ant_jump_promp['name'] = f"{_v}" + kwargs_dict_ant_jump_promp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_ant_jump_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -477,12 +427,12 @@ _versions = ['ALRHalfCheetahJump-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_halfcheetah_jump_promp = deepcopy(DEFAULT_BB_DICT) + kwargs_dict_halfcheetah_jump_promp = deepcopy(DEFAULT_BB_DICT_ProMP) kwargs_dict_halfcheetah_jump_promp['wrappers'].append(mujoco.half_cheetah_jump.MPWrapper) - kwargs_dict_halfcheetah_jump_promp['name'] = f"{_v}" + kwargs_dict_halfcheetah_jump_promp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_halfcheetah_jump_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -491,18 +441,18 @@ for _v in _versions: ## HopperJump -_versions = ['ALRHopperJump-v0', 'ALRHopperJumpRndmJointsDesPos-v0', 'ALRHopperJumpRndmJointsDesPosStepBased-v0', - 'ALRHopperJumpOnBox-v0', 'ALRHopperThrow-v0', 'ALRHopperThrowInBasket-v0'] +_versions = ['HopperJump-v0', 'HopperJumpSparse-v0', 'ALRHopperJumpOnBox-v0', 'ALRHopperThrow-v0', + 'ALRHopperThrowInBasket-v0'] # TODO: Check if all environments work with the same MPWrapper for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_hopper_jump_promp = deepcopy(DEFAULT_BB_DICT) + kwargs_dict_hopper_jump_promp = deepcopy(DEFAULT_BB_DICT_ProMP) kwargs_dict_hopper_jump_promp['wrappers'].append(mujoco.hopper_jump.MPWrapper) - kwargs_dict_hopper_jump_promp['name'] = f"{_v}" + kwargs_dict_hopper_jump_promp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_mp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_hopper_jump_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -515,12 +465,12 @@ _versions = ['ALRWalker2DJump-v0'] for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_walker2d_jump_promp = deepcopy(DEFAULT_BB_DICT) + kwargs_dict_walker2d_jump_promp = deepcopy(DEFAULT_BB_DICT_ProMP) kwargs_dict_walker2d_jump_promp['wrappers'].append(mujoco.walker_2d_jump.MPWrapper) - kwargs_dict_walker2d_jump_promp['name'] = f"{_v}" + kwargs_dict_walker2d_jump_promp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_walker2d_jump_promp ) ALL_ALR_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) diff --git a/alr_envs/alr/mujoco/__init__.py b/alr_envs/alr/mujoco/__init__.py index 906a9a5..6e40228 100644 --- a/alr_envs/alr/mujoco/__init__.py +++ b/alr_envs/alr/mujoco/__init__.py @@ -1,11 +1,8 @@ +from .beerpong.beerpong import BeerPongEnv, BeerPongEnvFixedReleaseStep, BeerPongEnvStepBasedEpisodicReward from .ant_jump.ant_jump import AntJumpEnv -from .ball_in_a_cup.ball_in_a_cup import ALRBallInACupEnv -from .ball_in_a_cup.biac_pd import ALRBallInACupPDEnv -from alr_envs.alr.mujoco.beerpong.beerpong import BeerPongEnv from .half_cheetah_jump.half_cheetah_jump import ALRHalfCheetahJumpEnv from .hopper_jump.hopper_jump_on_box import ALRHopperJumpOnBoxEnv from .hopper_throw.hopper_throw import ALRHopperThrowEnv from .hopper_throw.hopper_throw_in_basket import ALRHopperThrowInBasketEnv from .reacher.reacher import ReacherEnv -from .table_tennis.tt_gym import TTEnvGym from .walker_2d_jump.walker_2d_jump import ALRWalker2dJumpEnv diff --git a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml index 99df1d3..756e3d2 100644 --- a/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml +++ b/alr_envs/alr/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml @@ -1,5 +1,5 @@ - + diff --git a/alr_envs/envs/mujoco/beerpong/beerpong.py b/alr_envs/envs/mujoco/beerpong/beerpong.py index b49c180..60d442a 100644 --- a/alr_envs/envs/mujoco/beerpong/beerpong.py +++ b/alr_envs/envs/mujoco/beerpong/beerpong.py @@ -1,7 +1,6 @@ import os from typing import Optional -import mujoco_py.builder import numpy as np from gym import utils from gym.envs.mujoco import MujocoEnv @@ -50,9 +49,9 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): self.repeat_action = frame_skip # TODO: If accessing IDs is easier in the (new) official mujoco bindings, remove this self.model = None - self.site_id = lambda x: self.model.site_name2id(x) - self.body_id = lambda x: self.model.body_name2id(x) - self.geom_id = lambda x: self.model.geom_name2id(x) + self.geom_id = lambda x: self._mujoco_bindings.mj_name2id(self.model, + self._mujoco_bindings.mjtObj.mjOBJ_GEOM, + x) # for reward calculation self.dists = [] @@ -65,7 +64,7 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): self.ball_in_cup = False self.dist_ground_cup = -1 # distance floor to cup if first floor contact - MujocoEnv.__init__(self, self.xml_path, frame_skip=1, mujoco_bindings="mujoco_py") + MujocoEnv.__init__(self, model_path=self.xml_path, frame_skip=1, mujoco_bindings="mujoco") utils.EzPickle.__init__(self) @property @@ -100,13 +99,13 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): # TODO: Ask Max why we need to set the state twice. self.set_state(start_pos, init_vel) - start_pos[7::] = self.data.site_xpos[self.site_id("init_ball_pos"), :].copy() + start_pos[7::] = self.data.site("init_ball_pos").xpos.copy() self.set_state(start_pos, init_vel) xy = self.np_random.uniform(self._cup_pos_min, self._cup_pos_max) xyz = np.zeros(3) xyz[:2] = xy xyz[-1] = 0.840 - self.model.body_pos[self.body_id("cup_table")] = xyz + self.model.body("cup_table").pos[:] = xyz return self._get_obs() def step(self, a): @@ -117,10 +116,10 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): self.do_simulation(applied_action, self.frame_skip) # self.reward_function.check_contacts(self.sim) # I assume this is not important? if self._steps < self.release_step: - self.data.qpos[7::] = self.data.site_xpos[self.site_id("init_ball_pos"), :].copy() - self.data.qvel[7::] = self.data.site_xvelp[self.site_id("init_ball_pos"), :].copy() + self.data.qpos[7::] = self.data.site('init_ball_pos').xpos.copy() + self.data.qvel[7::] = self.data.sensor('init_ball_vel').data.copy() crash = False - except mujoco_py.builder.MujocoException: + except Exception as e: crash = True ob = self._get_obs() @@ -145,18 +144,18 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): return ob, reward, done, infos def _get_obs(self): - theta = self.data.qpos.flat[:7] - theta_dot = self.data.qvel.flat[:7] - ball_pos = self.data.get_body_xpos("ball").copy() - cup_goal_diff_final = ball_pos - self.data.get_site_xpos("cup_goal_final_table").copy() - cup_goal_diff_top = ball_pos - self.data.get_site_xpos("cup_goal_table").copy() + theta = self.data.qpos.flat[:7].copy() + theta_dot = self.data.qvel.flat[:7].copy() + ball_pos = self.data.qpos.flat[7:].copy() + cup_goal_diff_final = ball_pos - self.data.site("cup_goal_final_table").xpos.copy() + cup_goal_diff_top = ball_pos - self.data.site("cup_goal_table").xpos.copy() return np.concatenate([ np.cos(theta), np.sin(theta), theta_dot, cup_goal_diff_final, cup_goal_diff_top, - self.model.body_pos[self.body_id("cup_table")][:2].copy(), + self.model.body("cup_table").pos[:2].copy(), # [self._steps], # Use TimeAwareObservation Wrapper instead .... ]) @@ -165,10 +164,10 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): return super(BeerPongEnv, self).dt * self.repeat_action def _get_reward(self, action): - goal_pos = self.data.get_site_xpos("cup_goal_table") - ball_pos = self.data.get_body_xpos("ball") - ball_vel = self.data.get_body_xvelp("ball") - goal_final_pos = self.data.get_site_xpos("cup_goal_final_table") + goal_pos = self.data.site("cup_goal_table").xpos + goal_final_pos = self.data.site("cup_goal_final_table").xpos + ball_pos = self.data.qpos.flat[7:].copy() + ball_vel = self.data.qvel.flat[7:].copy() self._check_contacts() self.dists.append(np.linalg.norm(goal_pos - ball_pos)) diff --git a/alr_envs/envs/mujoco/beerpong/mp_wrapper.py b/alr_envs/envs/mujoco/beerpong/mp_wrapper.py index 5b53e77..22c50f7 100644 --- a/alr_envs/envs/mujoco/beerpong/mp_wrapper.py +++ b/alr_envs/envs/mujoco/beerpong/mp_wrapper.py @@ -21,16 +21,16 @@ class MPWrapper(RawInterfaceWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.data.qpos[0:7].copy() + return self.data.qpos[0:7].copy() @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.data.qvel[0:7].copy() + return self.data.qvel[0:7].copy() # TODO: Fix this def _episode_callback(self, action: np.ndarray, mp) -> Tuple[np.ndarray, Union[np.ndarray, None]]: if mp.learn_tau: - self.env.env.release_step = action[0] / self.env.dt # Tau value + self.release_step = action[0] / self.dt # Tau value return action, None else: return action, None @@ -39,5 +39,5 @@ class MPWrapper(RawInterfaceWrapper): xyz = np.zeros(3) xyz[:2] = context xyz[-1] = 0.840 - self.env.env.model.body_pos[self.env.env.cup_table_id] = xyz - return self.get_observation_from_step(self.env.env._get_obs()) + self.model.body_pos[self.cup_table_id] = xyz + return self.get_observation_from_step(self.get_obs()) diff --git a/alr_envs/envs/mujoco/half_cheetah_jump/half_cheetah_jump.py b/alr_envs/envs/mujoco/half_cheetah_jump/half_cheetah_jump.py index 7916d0c..3d948ac 100644 --- a/alr_envs/envs/mujoco/half_cheetah_jump/half_cheetah_jump.py +++ b/alr_envs/envs/mujoco/half_cheetah_jump/half_cheetah_jump.py @@ -2,7 +2,7 @@ import os from typing import Tuple, Union, Optional from gym.core import ObsType -from gym.envs.mujoco.half_cheetah_v3 import HalfCheetahEnv +from gym.envs.mujoco.half_cheetah_v4 import HalfCheetahEnv import numpy as np MAX_EPISODE_STEPS_HALFCHEETAHJUMP = 100 @@ -27,8 +27,11 @@ class HalfCheetahJumpEnv(HalfCheetahEnv): self.goal = 0 self.context = context xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) - super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, reset_noise_scale, - exclude_current_positions_from_observation) + super().__init__(xml_file=xml_file, + forward_reward_weight=forward_reward_weight, + ctrl_cost_weight=ctrl_cost_weight, + reset_noise_scale=reset_noise_scale, + exclude_current_positions_from_observation=exclude_current_positions_from_observation) def step(self, action): @@ -74,6 +77,7 @@ class HalfCheetahJumpEnv(HalfCheetahEnv): # overwrite reset_model to make it deterministic def reset_model(self): + # TODO remove if not needed! noise_low = -self._reset_noise_scale noise_high = self._reset_noise_scale diff --git a/alr_envs/envs/mujoco/half_cheetah_jump/mp_wrapper.py b/alr_envs/envs/mujoco/half_cheetah_jump/mp_wrapper.py index 298bf53..9681b3a 100644 --- a/alr_envs/envs/mujoco/half_cheetah_jump/mp_wrapper.py +++ b/alr_envs/envs/mujoco/half_cheetah_jump/mp_wrapper.py @@ -15,8 +15,8 @@ class MPWrapper(RawInterfaceWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.sim.data.qpos[3:9].copy() + return self.data.qpos[3:9].copy() @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.sim.data.qvel[3:9].copy() + return self.data.qvel[3:9].copy() diff --git a/alr_envs/envs/mujoco/hopper_jump/hopper_jump.py b/alr_envs/envs/mujoco/hopper_jump/hopper_jump.py index 74643f3..5a334a2 100644 --- a/alr_envs/envs/mujoco/hopper_jump/hopper_jump.py +++ b/alr_envs/envs/mujoco/hopper_jump/hopper_jump.py @@ -2,8 +2,7 @@ import copy import os import numpy as np -from gym.envs.mujoco.hopper_v3 import HopperEnv - +from gym.envs.mujoco.hopper_v4 import HopperEnv MAX_EPISODE_STEPS_HOPPERJUMP = 250 @@ -50,9 +49,16 @@ class HopperJumpEnv(HopperEnv): self.contact_dist = None xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) - super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, - healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, - exclude_current_positions_from_observation) + super().__init__(xml_file=xml_file, + forward_reward_weight=forward_reward_weight, + ctrl_cost_weight=ctrl_cost_weight, + healthy_reward=healthy_reward, + terminate_when_unhealthy=terminate_when_unhealthy, + healthy_state_range=healthy_state_range, + healthy_z_range=healthy_z_range, + healthy_angle_range=healthy_angle_range, + reset_noise_scale=reset_noise_scale, + exclude_current_positions_from_observation=exclude_current_positions_from_observation) # increase initial height self.init_qpos[1] = 1.5 @@ -67,7 +73,8 @@ class HopperJumpEnv(HopperEnv): self.do_simulation(action, self.frame_skip) height_after = self.get_body_com("torso")[2] - site_pos_after = self.data.get_site_xpos('foot_site') + #site_pos_after = self.data.get_site_xpos('foot_site') + site_pos_after = self.data.site('foot_site').xpos self.max_height = max(height_after, self.max_height) has_floor_contact = self._is_floor_foot_contact() if not self.contact_with_floor else False @@ -111,7 +118,8 @@ class HopperJumpEnv(HopperEnv): return observation, reward, done, info def _get_obs(self): - goal_dist = self.data.get_site_xpos('foot_site') - self.goal + # goal_dist = self.data.get_site_xpos('foot_site') - self.goal + goal_dist = self.data.site('foot_site').xpos - self.goal return np.concatenate((super(HopperJumpEnv, self)._get_obs(), goal_dist.copy(), self.goal[:1])) def reset_model(self): @@ -119,7 +127,8 @@ class HopperJumpEnv(HopperEnv): # self.goal = self.np_random.uniform(0.3, 1.35, 1)[0] self.goal = np.concatenate([self.np_random.uniform(0.3, 1.35, 1), np.zeros(2, )]) - self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = self.goal + # self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = self.goal + self.data.body('goal_site_body').xpos[:] = np.copy(self.goal) self.max_height = 0 self._steps = 0 @@ -153,8 +162,15 @@ class HopperJumpEnv(HopperEnv): return observation def _is_floor_foot_contact(self): - floor_geom_id = self.model.geom_name2id('floor') - foot_geom_id = self.model.geom_name2id('foot_geom') + # floor_geom_id = self.model.geom_name2id('floor') + # foot_geom_id = self.model.geom_name2id('foot_geom') + # TODO: do this properly over a sensor in the xml file, see dmc hopper + floor_geom_id = self._mujoco_bindings.mj_name2id(self.model, + self._mujoco_bindings.mjtObj.mjOBJ_GEOM, + 'floor') + foot_geom_id = self._mujoco_bindings.mj_name2id(self.model, + self._mujoco_bindings.mjtObj.mjOBJ_GEOM, + 'foot_geom') for i in range(self.data.ncon): contact = self.data.contact[i] collision = contact.geom1 == floor_geom_id and contact.geom2 == foot_geom_id @@ -163,7 +179,7 @@ class HopperJumpEnv(HopperEnv): return True return False - +# TODO is that needed? if so test it class HopperJumpStepEnv(HopperJumpEnv): def __init__(self, @@ -193,7 +209,7 @@ class HopperJumpStepEnv(HopperJumpEnv): self.do_simulation(action, self.frame_skip) height_after = self.get_body_com("torso")[2] - site_pos_after = self.data.get_site_xpos('foot_site') + site_pos_after = self.data.site('foot_site').xpos.copy() self.max_height = max(height_after, self.max_height) ctrl_cost = self.control_cost(action) diff --git a/alr_envs/envs/mujoco/hopper_jump/hopper_jump_on_box.py b/alr_envs/envs/mujoco/hopper_jump/hopper_jump_on_box.py index 845edaa..e184723 100644 --- a/alr_envs/envs/mujoco/hopper_jump/hopper_jump_on_box.py +++ b/alr_envs/envs/mujoco/hopper_jump/hopper_jump_on_box.py @@ -1,4 +1,4 @@ -from gym.envs.mujoco.hopper_v3 import HopperEnv +from gym.envs.mujoco.hopper_v4 import HopperEnv import numpy as np import os @@ -46,7 +46,7 @@ class HopperJumpOnBoxEnv(HopperEnv): foot_pos = self.get_body_com("foot") self.max_height = max(height_after, self.max_height) - vx, vz, vangle = self.sim.data.qvel[0:3] + vx, vz, vangle = self.data.qvel[0:3] s = self.state_vector() fell_over = not (np.isfinite(s).all() and (np.abs(s[2:]) < 100).all() and (height_after > .7)) @@ -67,7 +67,8 @@ class HopperJumpOnBoxEnv(HopperEnv): is_on_box_y = True # is y always true because he can only move in x and z direction? is_on_box_z = box_height - 0.02 <= foot_pos[2] <= box_height + 0.02 is_on_box = is_on_box_x and is_on_box_y and is_on_box_z - if is_on_box: self.hopper_on_box = True + if is_on_box: + self.hopper_on_box = True ctrl_cost = self.control_cost(action) @@ -133,9 +134,8 @@ class HopperJumpOnBoxEnv(HopperEnv): self.current_step = 0 self.hopper_on_box = False if self.context: - box_id = self.sim.model.body_name2id("box") self.box_x = self.np_random.uniform(1, 3, 1) - self.sim.model.body_pos[box_id] = [self.box_x, 0, 0] + self.model.body("box").pos = [self.box_x[0], 0, 0] return super().reset() # overwrite reset_model to make it deterministic diff --git a/alr_envs/envs/mujoco/hopper_jump/mp_wrapper.py b/alr_envs/envs/mujoco/hopper_jump/mp_wrapper.py index 8e91bea..0f5e8a8 100644 --- a/alr_envs/envs/mujoco/hopper_jump/mp_wrapper.py +++ b/alr_envs/envs/mujoco/hopper_jump/mp_wrapper.py @@ -20,8 +20,8 @@ class MPWrapper(RawInterfaceWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.sim.data.qpos[3:6].copy() + return self.data.qpos[3:6].copy() @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.sim.data.qvel[3:6].copy() + return self.data.qvel[3:6].copy() diff --git a/alr_envs/envs/mujoco/hopper_throw/hopper_throw.py b/alr_envs/envs/mujoco/hopper_throw/hopper_throw.py index c2bda19..3b2ce46 100644 --- a/alr_envs/envs/mujoco/hopper_throw/hopper_throw.py +++ b/alr_envs/envs/mujoco/hopper_throw/hopper_throw.py @@ -1,7 +1,7 @@ import os from typing import Optional -from gym.envs.mujoco.hopper_v3 import HopperEnv +from gym.envs.mujoco.hopper_v4 import HopperEnv import numpy as np MAX_EPISODE_STEPS_HOPPERTHROW = 250 @@ -36,9 +36,16 @@ class HopperThrowEnv(HopperEnv): self.max_episode_steps = max_episode_steps self.context = context self.goal = 0 - super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, - healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, - exclude_current_positions_from_observation) + super().__init__(xml_file=xml_file, + forward_reward_weight=forward_reward_weight, + ctrl_cost_weight=ctrl_cost_weight, + healthy_reward=healthy_reward, + terminate_when_unhealthy=terminate_when_unhealthy, + healthy_angle_range=healthy_state_range, + healthy_z_range=healthy_z_range, + healthy_state_range=healthy_angle_range, + reset_noise_scale=reset_noise_scale, + exclude_current_positions_from_observation=exclude_current_positions_from_observation) def step(self, action): self.current_step += 1 diff --git a/alr_envs/envs/mujoco/hopper_throw/hopper_throw_in_basket.py b/alr_envs/envs/mujoco/hopper_throw/hopper_throw_in_basket.py index b1fa3ef..fb46809 100644 --- a/alr_envs/envs/mujoco/hopper_throw/hopper_throw_in_basket.py +++ b/alr_envs/envs/mujoco/hopper_throw/hopper_throw_in_basket.py @@ -1,7 +1,7 @@ import os from typing import Optional -from gym.envs.mujoco.hopper_v3 import HopperEnv +from gym.envs.mujoco.hopper_v4 import HopperEnv import numpy as np @@ -44,9 +44,16 @@ class HopperThrowInBasketEnv(HopperEnv): self.penalty = penalty self.basket_x = 5 xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) - super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, - healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, - exclude_current_positions_from_observation) + super().__init__(xml_file=xml_file, + forward_reward_weight=forward_reward_weight, + ctrl_cost_weight=ctrl_cost_weight, + healthy_reward=healthy_reward, + terminate_when_unhealthy=terminate_when_unhealthy, + healthy_state_range=healthy_state_range, + healthy_z_range=healthy_z_range, + healthy_angle_range=healthy_angle_range, + reset_noise_scale=reset_noise_scale, + exclude_current_positions_from_observation=exclude_current_positions_from_observation) def step(self, action): @@ -109,13 +116,13 @@ class HopperThrowInBasketEnv(HopperEnv): self.current_step = 0 self.ball_in_basket = False if self.context: - basket_id = self.sim.model.body_name2id("basket_ground") - self.basket_x = self.np_random.uniform(3, 7, 1) - self.sim.model.body_pos[basket_id] = [self.basket_x, 0, 0] + self.basket_x = self.np_random.uniform(low=3, high=7, size=1) + self.model.body("basket_ground").pos[:] = [self.basket_x[0], 0, 0] return super().reset() # overwrite reset_model to make it deterministic def reset_model(self): + # Todo remove if not needed! noise_low = -self._reset_noise_scale noise_high = self._reset_noise_scale diff --git a/alr_envs/envs/mujoco/hopper_throw/mp_wrapper.py b/alr_envs/envs/mujoco/hopper_throw/mp_wrapper.py index 78c2f51..247668f 100644 --- a/alr_envs/envs/mujoco/hopper_throw/mp_wrapper.py +++ b/alr_envs/envs/mujoco/hopper_throw/mp_wrapper.py @@ -16,8 +16,8 @@ class MPWrapper(RawInterfaceWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.data.qpos[3:6].copy() + return self.data.qpos[3:6].copy() @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.data.qvel[3:6].copy() + return self.data.qvel[3:6].copy() diff --git a/alr_envs/envs/mujoco/reacher/mp_wrapper.py b/alr_envs/envs/mujoco/reacher/mp_wrapper.py index 2ef7c78..1c1e2f1 100644 --- a/alr_envs/envs/mujoco/reacher/mp_wrapper.py +++ b/alr_envs/envs/mujoco/reacher/mp_wrapper.py @@ -10,18 +10,18 @@ class MPWrapper(RawInterfaceWrapper): @property def context_mask(self): - return np.concatenate([[False] * self.env.n_links, # cos - [False] * self.env.n_links, # sin + return np.concatenate([[False] * self.n_links, # cos + [False] * self.n_links, # sin [True] * 2, # goal position - [False] * self.env.n_links, # angular velocity + [False] * self.n_links, # angular velocity [False] * 3, # goal distance # [False], # step ]) @property def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.data.qpos.flat[:self.env.n_links] + return self.data.qpos.flat[:self.n_links] @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.data.qvel.flat[:self.env.n_links] + return self.data.qvel.flat[:self.n_links] diff --git a/alr_envs/envs/mujoco/reacher/reacher.py b/alr_envs/envs/mujoco/reacher/reacher.py index 3ebc6e8..3d52be7 100644 --- a/alr_envs/envs/mujoco/reacher/reacher.py +++ b/alr_envs/envs/mujoco/reacher/reacher.py @@ -23,7 +23,10 @@ class ReacherEnv(MujocoEnv, utils.EzPickle): file_name = f'reacher_{n_links}links.xml' - MujocoEnv.__init__(self, os.path.join(os.path.dirname(__file__), "assets", file_name), 2) + MujocoEnv.__init__(self, + model_path=os.path.join(os.path.dirname(__file__), "assets", file_name), + frame_skip=2, + mujoco_bindings="mujoco") def step(self, action): self._steps += 1 diff --git a/alr_envs/envs/mujoco/walker_2d_jump/mp_wrapper.py b/alr_envs/envs/mujoco/walker_2d_jump/mp_wrapper.py index 63432a7..f91d494 100644 --- a/alr_envs/envs/mujoco/walker_2d_jump/mp_wrapper.py +++ b/alr_envs/envs/mujoco/walker_2d_jump/mp_wrapper.py @@ -16,8 +16,8 @@ class MPWrapper(RawInterfaceWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray]: - return self.env.data.qpos[3:9].copy() + return self.data.qpos[3:9].copy() @property def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: - return self.env.data.qvel[3:9].copy() + return self.data.qvel[3:9].copy() diff --git a/alr_envs/envs/mujoco/walker_2d_jump/walker_2d_jump.py b/alr_envs/envs/mujoco/walker_2d_jump/walker_2d_jump.py index 76cb688..dadf8fd 100644 --- a/alr_envs/envs/mujoco/walker_2d_jump/walker_2d_jump.py +++ b/alr_envs/envs/mujoco/walker_2d_jump/walker_2d_jump.py @@ -1,7 +1,7 @@ import os from typing import Optional -from gym.envs.mujoco.walker2d_v3 import Walker2dEnv +from gym.envs.mujoco.walker2d_v4 import Walker2dEnv import numpy as np MAX_EPISODE_STEPS_WALKERJUMP = 300 @@ -36,9 +36,15 @@ class Walker2dJumpEnv(Walker2dEnv): self._penalty = penalty self.goal = 0 xml_file = os.path.join(os.path.dirname(__file__), "assets", xml_file) - super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, - healthy_z_range, healthy_angle_range, reset_noise_scale, - exclude_current_positions_from_observation) + super().__init__(xml_file=xml_file, + forward_reward_weight=forward_reward_weight, + ctrl_cost_weight=ctrl_cost_weight, + healthy_reward=healthy_reward, + terminate_when_unhealthy=terminate_when_unhealthy, + healthy_z_range=healthy_z_range, + healthy_angle_range=healthy_angle_range, + reset_noise_scale=reset_noise_scale, + exclude_current_positions_from_observation=exclude_current_positions_from_observation) def step(self, action): self.current_step += 1 From 26cc1136f61d139e4194e996461ec8bbfe6cdcef Mon Sep 17 00:00:00 2001 From: philipp Date: Wed, 13 Jul 2022 13:34:28 +0200 Subject: [PATCH 084/104] added todo for contact detection in beer pong --- alr_envs/envs/mujoco/beerpong/beerpong.py | 1 + 1 file changed, 1 insertion(+) diff --git a/alr_envs/envs/mujoco/beerpong/beerpong.py b/alr_envs/envs/mujoco/beerpong/beerpong.py index 60d442a..2ec0387 100644 --- a/alr_envs/envs/mujoco/beerpong/beerpong.py +++ b/alr_envs/envs/mujoco/beerpong/beerpong.py @@ -217,6 +217,7 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): return reward, infos def _check_contacts(self): + #TODO proper contact detection using sensors? if not self.ball_table_contact: self.ball_table_contact = self._check_collision({self.geom_id("ball_geom")}, {self.geom_id("table_contact_geom")}) From 53bbe34b5d7d8a5679998c50c74a7efeea7dc3dd Mon Sep 17 00:00:00 2001 From: philipp Date: Wed, 13 Jul 2022 13:47:58 +0200 Subject: [PATCH 085/104] removed mujoco-py from install_requires --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 02dc453..92d7225 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,6 @@ setup( extras_require=extras, install_requires=[ 'gym>=0.24.0', - "mujoco_py<2.2,>=2.1", ], packages=[package for package in find_packages() if package.startswith("alr_envs")], # packages=['alr_envs', 'alr_envs.envs', 'alr_envs.open_ai', 'alr_envs.dmc', 'alr_envs.meta', 'alr_envs.utils'], From 8d1c1b44bf3cfac82fdee6f1b94e30f80d41a9d4 Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 13 Jul 2022 15:10:43 +0200 Subject: [PATCH 086/104] renaming to fancy_gym --- README.md | 49 +++--- .../deprecated_needs_gym_robotics/__init__.py | 0 {alr_envs => fancy_gym}/__init__.py | 11 +- .../black_box/__init__.py | 0 .../black_box/black_box_wrapper.py | 35 +--- .../black_box/controller}/__init__.py | 0 .../black_box/controller/base_controller.py | 0 .../controller/meta_world_controller.py | 2 +- .../black_box/controller/pd_controller.py | 2 +- .../black_box/controller/pos_controller.py | 2 +- .../black_box/controller/vel_controller.py | 2 +- .../black_box/factory}/__init__.py | 0 .../factory/basis_generator_factory.py | 0 .../black_box/factory/controller_factory.py | 8 +- .../factory/phase_generator_factory.py | 0 .../factory/trajectory_generator_factory.py | 7 +- .../black_box/raw_interface_wrapper.py | 6 +- {alr_envs => fancy_gym}/dmc/README.MD | 0 {alr_envs => fancy_gym}/dmc/__init__.py | 28 +-- {alr_envs => fancy_gym}/dmc/dmc_wrapper.py | 2 +- .../dmc/manipulation/__init__.py | 0 .../dmc/manipulation/reach_site/__init__.py | 0 .../dmc/manipulation/reach_site/mp_wrapper.py | 2 +- {alr_envs => fancy_gym}/dmc/suite/__init__.py | 0 .../dmc/suite/ball_in_cup/__init__.py | 0 .../dmc/suite/ball_in_cup/mp_wrapper.py | 2 +- .../dmc/suite/cartpole/__init__.py | 2 +- .../dmc/suite/cartpole/mp_wrapper.py | 2 +- .../dmc/suite/reacher/__init__.py | 0 .../dmc/suite/reacher/mp_wrapper.py | 2 +- {alr_envs => fancy_gym}/envs/__init__.py | 165 +++++++++--------- .../envs/classic_control/README.MD | 0 .../envs/classic_control/__init__.py | 0 .../classic_control/base_reacher}/__init__.py | 0 .../base_reacher/base_reacher.py | 2 +- .../base_reacher/base_reacher_direct.py | 6 +- .../base_reacher/base_reacher_torque.py | 6 +- .../classic_control/hole_reacher/__init__.py | 0 .../hole_reacher/hole_reacher.py | 11 +- .../hole_reacher/hr_dist_vel_acc_reward.py | 0 .../hole_reacher/hr_simple_reward.py | 0 .../hole_reacher/hr_unbounded_reward.py | 0 .../hole_reacher/mp_wrapper.py | 2 +- .../simple_reacher/__init__.py | 0 .../simple_reacher/mp_wrapper.py | 2 +- .../simple_reacher/simple_reacher.py | 2 +- .../envs/classic_control/utils.py | 3 - .../viapoint_reacher/__init__.py | 0 .../viapoint_reacher/mp_wrapper.py | 2 +- .../viapoint_reacher/viapoint_reacher.py | 4 +- {alr_envs => fancy_gym}/envs/mujoco/README.MD | 0 .../envs/mujoco/__init__.py | 4 +- .../envs/mujoco/ant_jump/__init__.py | 0 .../envs/mujoco/ant_jump/ant_jump.py | 2 +- .../envs/mujoco/ant_jump/assets/ant.xml | 0 .../envs/mujoco/ant_jump/mp_wrapper.py | 2 +- .../envs/mujoco/beerpong/__init__.py | 0 .../envs/mujoco/beerpong/assets/beerpong.xml | 0 .../beerpong/assets/beerpong_wo_cup.xml | 0 .../assets/beerpong_wo_cup_big_table.xml | 0 .../assets/meshes/wam/base_link_convex.stl | Bin .../assets/meshes/wam/base_link_fine.stl | Bin .../wam/bhand_finger_dist_link_convex.stl | Bin .../wam/bhand_finger_dist_link_fine.stl | Bin .../wam/bhand_finger_med_link_convex.stl | Bin .../meshes/wam/bhand_finger_med_link_fine.stl | Bin ...nger_prox_link_convex_decomposition_p1.stl | Bin ...nger_prox_link_convex_decomposition_p2.stl | Bin ...nger_prox_link_convex_decomposition_p3.stl | Bin .../wam/bhand_finger_prox_link_fine.stl | Bin .../assets/meshes/wam/bhand_palm_fine.stl | Bin ...hand_palm_link_convex_decomposition_p1.stl | Bin ...hand_palm_link_convex_decomposition_p2.stl | Bin ...hand_palm_link_convex_decomposition_p3.stl | Bin ...hand_palm_link_convex_decomposition_p4.stl | Bin .../mujoco/beerpong/assets/meshes/wam/cup.stl | Bin .../beerpong/assets/meshes/wam/cup_split1.stl | Bin .../assets/meshes/wam/cup_split10.stl | Bin .../assets/meshes/wam/cup_split11.stl | Bin .../assets/meshes/wam/cup_split12.stl | Bin .../assets/meshes/wam/cup_split13.stl | Bin .../assets/meshes/wam/cup_split14.stl | Bin .../assets/meshes/wam/cup_split15.stl | Bin .../assets/meshes/wam/cup_split16.stl | Bin .../assets/meshes/wam/cup_split17.stl | Bin .../assets/meshes/wam/cup_split18.stl | Bin .../beerpong/assets/meshes/wam/cup_split2.stl | Bin .../beerpong/assets/meshes/wam/cup_split3.stl | Bin .../beerpong/assets/meshes/wam/cup_split4.stl | Bin .../beerpong/assets/meshes/wam/cup_split5.stl | Bin .../beerpong/assets/meshes/wam/cup_split6.stl | Bin .../beerpong/assets/meshes/wam/cup_split7.stl | Bin .../beerpong/assets/meshes/wam/cup_split8.stl | Bin .../beerpong/assets/meshes/wam/cup_split9.stl | Bin .../assets/meshes/wam/elbow_link_convex.stl | Bin .../assets/meshes/wam/elbow_link_fine.stl | Bin .../forearm_link_convex_decomposition_p1.stl | Bin .../forearm_link_convex_decomposition_p2.stl | Bin .../assets/meshes/wam/forearm_link_fine.stl | Bin .../shoulder_link_convex_decomposition_p1.stl | Bin .../shoulder_link_convex_decomposition_p2.stl | Bin .../shoulder_link_convex_decomposition_p3.stl | Bin .../assets/meshes/wam/shoulder_link_fine.stl | Bin .../meshes/wam/shoulder_pitch_link_convex.stl | Bin .../meshes/wam/shoulder_pitch_link_fine.stl | Bin ...upper_arm_link_convex_decomposition_p1.stl | Bin ...upper_arm_link_convex_decomposition_p2.stl | Bin .../assets/meshes/wam/upper_arm_link_fine.stl | Bin .../meshes/wam/wrist_palm_link_convex.stl | Bin .../meshes/wam/wrist_palm_link_fine.stl | Bin ...ist_pitch_link_convex_decomposition_p1.stl | Bin ...ist_pitch_link_convex_decomposition_p2.stl | Bin ...ist_pitch_link_convex_decomposition_p3.stl | Bin .../meshes/wam/wrist_pitch_link_fine.stl | Bin ...wrist_yaw_link_convex_decomposition_p1.stl | Bin ...wrist_yaw_link_convex_decomposition_p2.stl | Bin .../assets/meshes/wam/wrist_yaw_link_fine.stl | Bin .../envs/mujoco/beerpong/beerpong.py | 27 ++- .../mujoco/beerpong/deprecated}/__init__.py | 0 .../mujoco/beerpong/deprecated/beerpong.py | 14 +- .../deprecated/beerpong_reward_staged.py | 0 .../envs/mujoco/beerpong/mp_wrapper.py | 2 +- .../envs/mujoco/half_cheetah_jump/__init__.py | 0 .../half_cheetah_jump/assets/cheetah.xml | 0 .../half_cheetah_jump/half_cheetah_jump.py | 4 +- .../mujoco/half_cheetah_jump/mp_wrapper.py | 2 +- .../envs/mujoco/hopper_jump/__init__.py | 0 .../mujoco/hopper_jump/assets/hopper_jump.xml | 0 .../hopper_jump/assets/hopper_jump_on_box.xml | 0 .../envs/mujoco/hopper_jump/hopper_jump.py | 11 +- .../mujoco/hopper_jump/hopper_jump_on_box.py | 4 +- .../envs/mujoco/hopper_jump/mp_wrapper.py | 2 +- .../envs/mujoco/hopper_throw/__init__.py | 0 .../hopper_throw/assets/hopper_throw.xml | 0 .../assets/hopper_throw_in_basket.xml | 0 .../envs/mujoco/hopper_throw/hopper_throw.py | 2 +- .../hopper_throw/hopper_throw_in_basket.py | 3 +- .../envs/mujoco/hopper_throw/mp_wrapper.py | 2 +- .../envs/mujoco/reacher/__init__.py | 0 .../mujoco/reacher/assets/reacher_5links.xml | 0 .../mujoco/reacher/assets/reacher_7links.xml | 0 .../envs/mujoco/reacher/mp_wrapper.py | 3 +- .../envs/mujoco/reacher/reacher.py | 16 +- .../envs/mujoco/walker_2d_jump/__init__.py | 0 .../mujoco/walker_2d_jump/assets/walker2d.xml | 0 .../envs/mujoco/walker_2d_jump/mp_wrapper.py | 2 +- .../mujoco/walker_2d_jump/walker_2d_jump.py | 2 +- .../examples}/__init__.py | 0 .../examples/examples_dmc.py | 20 +-- .../examples/examples_general.py | 6 +- .../examples/examples_metaworld.py | 20 +-- .../examples/examples_movement_primitives.py | 26 +-- .../examples/examples_open_ai.py | 8 +- .../examples/pd_control_gain_tuning.py | 5 +- {alr_envs => fancy_gym}/meta/README.MD | 0 {alr_envs => fancy_gym}/meta/__init__.py | 8 +- .../meta/base_metaworld_mp_wrapper.py | 2 +- .../meta/goal_change_mp_wrapper.py | 6 +- .../goal_endeffector_change_mp_wrapper.py | 6 +- .../meta/goal_object_change_mp_wrapper.py | 6 +- .../meta/object_change_mp_wrapper.py | 6 +- {alr_envs => fancy_gym}/open_ai/README.MD | 0 {alr_envs => fancy_gym}/open_ai/__init__.py | 25 +-- .../__init__.py | 0 .../robotics/__init__.py | 0 .../robotics/fetch/__init__.py | 0 .../robotics/fetch/mp_wrapper.py | 2 +- .../open_ai/mujoco/__init__.py | 0 .../open_ai/mujoco/reacher_v2/__init__.py | 0 .../open_ai/mujoco/reacher_v2/mp_wrapper.py | 2 +- {alr_envs => fancy_gym}/utils/__init__.py | 0 .../utils/make_env_helpers.py | 22 +-- .../utils/time_aware_observation.py | 3 +- {alr_envs => fancy_gym}/utils/utils.py | 0 setup.py | 8 +- test/test_custom.py | 10 +- test/test_dmc.py | 9 +- test/test_gym.py | 10 +- test/test_metaworld.py | 10 +- 179 files changed, 332 insertions(+), 361 deletions(-) delete mode 100644 alr_envs/open_ai/deprecated_needs_gym_robotics/__init__.py rename {alr_envs => fancy_gym}/__init__.py (66%) rename __init__.py => fancy_gym/black_box/__init__.py (100%) rename {alr_envs => fancy_gym}/black_box/black_box_wrapper.py (86%) rename {alr_envs/black_box => fancy_gym/black_box/controller}/__init__.py (100%) rename {alr_envs => fancy_gym}/black_box/controller/base_controller.py (100%) rename {alr_envs => fancy_gym}/black_box/controller/meta_world_controller.py (92%) rename {alr_envs => fancy_gym}/black_box/controller/pd_controller.py (93%) rename {alr_envs => fancy_gym}/black_box/controller/pos_controller.py (76%) rename {alr_envs => fancy_gym}/black_box/controller/vel_controller.py (76%) rename {alr_envs/black_box/controller => fancy_gym/black_box/factory}/__init__.py (100%) rename {alr_envs => fancy_gym}/black_box/factory/basis_generator_factory.py (100%) rename {alr_envs => fancy_gym}/black_box/factory/controller_factory.py (67%) rename {alr_envs => fancy_gym}/black_box/factory/phase_generator_factory.py (100%) rename {alr_envs => fancy_gym}/black_box/factory/trajectory_generator_factory.py (99%) rename {alr_envs => fancy_gym}/black_box/raw_interface_wrapper.py (95%) rename {alr_envs => fancy_gym}/dmc/README.MD (100%) rename {alr_envs => fancy_gym}/dmc/__init__.py (90%) rename {alr_envs => fancy_gym}/dmc/dmc_wrapper.py (100%) rename {alr_envs => fancy_gym}/dmc/manipulation/__init__.py (100%) rename {alr_envs => fancy_gym}/dmc/manipulation/reach_site/__init__.py (100%) rename {alr_envs => fancy_gym}/dmc/manipulation/reach_site/mp_wrapper.py (94%) rename {alr_envs => fancy_gym}/dmc/suite/__init__.py (100%) rename {alr_envs => fancy_gym}/dmc/suite/ball_in_cup/__init__.py (100%) rename {alr_envs => fancy_gym}/dmc/suite/ball_in_cup/mp_wrapper.py (93%) rename {alr_envs => fancy_gym}/dmc/suite/cartpole/__init__.py (100%) rename {alr_envs => fancy_gym}/dmc/suite/cartpole/mp_wrapper.py (94%) rename {alr_envs => fancy_gym}/dmc/suite/reacher/__init__.py (100%) rename {alr_envs => fancy_gym}/dmc/suite/reacher/mp_wrapper.py (92%) rename {alr_envs => fancy_gym}/envs/__init__.py (79%) rename {alr_envs => fancy_gym}/envs/classic_control/README.MD (100%) rename {alr_envs => fancy_gym}/envs/classic_control/__init__.py (100%) rename {alr_envs/black_box/factory => fancy_gym/envs/classic_control/base_reacher}/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/classic_control/base_reacher/base_reacher.py (98%) rename {alr_envs => fancy_gym}/envs/classic_control/base_reacher/base_reacher_direct.py (92%) rename {alr_envs => fancy_gym}/envs/classic_control/base_reacher/base_reacher_torque.py (92%) rename {alr_envs => fancy_gym}/envs/classic_control/hole_reacher/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/classic_control/hole_reacher/hole_reacher.py (95%) rename {alr_envs => fancy_gym}/envs/classic_control/hole_reacher/hr_dist_vel_acc_reward.py (100%) rename {alr_envs => fancy_gym}/envs/classic_control/hole_reacher/hr_simple_reward.py (100%) rename {alr_envs => fancy_gym}/envs/classic_control/hole_reacher/hr_unbounded_reward.py (100%) rename {alr_envs => fancy_gym}/envs/classic_control/hole_reacher/mp_wrapper.py (91%) rename {alr_envs => fancy_gym}/envs/classic_control/simple_reacher/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/classic_control/simple_reacher/mp_wrapper.py (90%) rename {alr_envs => fancy_gym}/envs/classic_control/simple_reacher/simple_reacher.py (97%) rename {alr_envs => fancy_gym}/envs/classic_control/utils.py (96%) rename {alr_envs => fancy_gym}/envs/classic_control/viapoint_reacher/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/classic_control/viapoint_reacher/mp_wrapper.py (91%) rename {alr_envs => fancy_gym}/envs/classic_control/viapoint_reacher/viapoint_reacher.py (98%) rename {alr_envs => fancy_gym}/envs/mujoco/README.MD (100%) rename {alr_envs => fancy_gym}/envs/mujoco/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/mujoco/ant_jump/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/mujoco/ant_jump/ant_jump.py (99%) rename {alr_envs => fancy_gym}/envs/mujoco/ant_jump/assets/ant.xml (100%) rename {alr_envs => fancy_gym}/envs/mujoco/ant_jump/mp_wrapper.py (87%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/beerpong.xml (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/beerpong_wo_cup.xml (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/base_link_convex.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/base_link_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_dist_link_convex.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_dist_link_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_med_link_convex.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_med_link_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p1.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p2.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p3.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p1.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p2.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p3.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p4.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split1.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split10.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split11.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split12.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split13.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split14.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split15.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split16.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split17.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split18.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split2.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split3.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split4.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split5.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split6.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split7.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split8.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/cup_split9.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/elbow_link_convex.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/elbow_link_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_convex_decomposition_p1.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_convex_decomposition_p2.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p1.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p2.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p3.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/shoulder_pitch_link_convex.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/shoulder_pitch_link_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_convex_decomposition_p1.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_convex_decomposition_p2.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/wrist_palm_link_convex.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/wrist_palm_link_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p1.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p2.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p3.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_convex_decomposition_p1.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_convex_decomposition_p2.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_fine.stl (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/beerpong.py (94%) rename {alr_envs/envs/classic_control/base_reacher => fancy_gym/envs/mujoco/beerpong/deprecated}/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/deprecated/beerpong.py (94%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/deprecated/beerpong_reward_staged.py (100%) rename {alr_envs => fancy_gym}/envs/mujoco/beerpong/mp_wrapper.py (94%) rename {alr_envs => fancy_gym}/envs/mujoco/half_cheetah_jump/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/mujoco/half_cheetah_jump/assets/cheetah.xml (100%) rename {alr_envs => fancy_gym}/envs/mujoco/half_cheetah_jump/half_cheetah_jump.py (98%) rename {alr_envs => fancy_gym}/envs/mujoco/half_cheetah_jump/mp_wrapper.py (86%) rename {alr_envs => fancy_gym}/envs/mujoco/hopper_jump/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/mujoco/hopper_jump/assets/hopper_jump.xml (100%) rename {alr_envs => fancy_gym}/envs/mujoco/hopper_jump/assets/hopper_jump_on_box.xml (100%) rename {alr_envs => fancy_gym}/envs/mujoco/hopper_jump/hopper_jump.py (98%) rename {alr_envs => fancy_gym}/envs/mujoco/hopper_jump/hopper_jump_on_box.py (99%) rename {alr_envs => fancy_gym}/envs/mujoco/hopper_jump/mp_wrapper.py (90%) rename {alr_envs => fancy_gym}/envs/mujoco/hopper_throw/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/mujoco/hopper_throw/assets/hopper_throw.xml (100%) rename {alr_envs => fancy_gym}/envs/mujoco/hopper_throw/assets/hopper_throw_in_basket.xml (100%) rename {alr_envs => fancy_gym}/envs/mujoco/hopper_throw/hopper_throw.py (100%) rename {alr_envs => fancy_gym}/envs/mujoco/hopper_throw/hopper_throw_in_basket.py (99%) rename {alr_envs => fancy_gym}/envs/mujoco/hopper_throw/mp_wrapper.py (86%) rename {alr_envs => fancy_gym}/envs/mujoco/reacher/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/mujoco/reacher/assets/reacher_5links.xml (100%) rename {alr_envs => fancy_gym}/envs/mujoco/reacher/assets/reacher_7links.xml (100%) rename {alr_envs => fancy_gym}/envs/mujoco/reacher/mp_wrapper.py (90%) rename {alr_envs => fancy_gym}/envs/mujoco/reacher/reacher.py (88%) rename {alr_envs => fancy_gym}/envs/mujoco/walker_2d_jump/__init__.py (100%) rename {alr_envs => fancy_gym}/envs/mujoco/walker_2d_jump/assets/walker2d.xml (100%) rename {alr_envs => fancy_gym}/envs/mujoco/walker_2d_jump/mp_wrapper.py (86%) rename {alr_envs => fancy_gym}/envs/mujoco/walker_2d_jump/walker_2d_jump.py (100%) rename {alr_envs/envs/mujoco/beerpong/deprecated => fancy_gym/examples}/__init__.py (100%) rename {alr_envs => fancy_gym}/examples/examples_dmc.py (87%) rename {alr_envs => fancy_gym}/examples/examples_general.py (95%) rename {alr_envs => fancy_gym}/examples/examples_metaworld.py (88%) rename {alr_envs => fancy_gym}/examples/examples_movement_primitives.py (86%) rename {alr_envs => fancy_gym}/examples/examples_open_ai.py (74%) rename {alr_envs => fancy_gym}/examples/pd_control_gain_tuning.py (94%) rename {alr_envs => fancy_gym}/meta/README.MD (100%) rename {alr_envs => fancy_gym}/meta/__init__.py (93%) rename {alr_envs => fancy_gym}/meta/base_metaworld_mp_wrapper.py (90%) rename {alr_envs => fancy_gym}/meta/goal_change_mp_wrapper.py (94%) rename {alr_envs => fancy_gym}/meta/goal_endeffector_change_mp_wrapper.py (94%) rename {alr_envs => fancy_gym}/meta/goal_object_change_mp_wrapper.py (94%) rename {alr_envs => fancy_gym}/meta/object_change_mp_wrapper.py (94%) rename {alr_envs => fancy_gym}/open_ai/README.MD (100%) rename {alr_envs => fancy_gym}/open_ai/__init__.py (77%) rename {alr_envs/examples => fancy_gym/open_ai/deprecated_needs_gym_robotics}/__init__.py (100%) rename {alr_envs => fancy_gym}/open_ai/deprecated_needs_gym_robotics/robotics/__init__.py (100%) rename {alr_envs => fancy_gym}/open_ai/deprecated_needs_gym_robotics/robotics/fetch/__init__.py (100%) rename {alr_envs => fancy_gym}/open_ai/deprecated_needs_gym_robotics/robotics/fetch/mp_wrapper.py (96%) rename {alr_envs => fancy_gym}/open_ai/mujoco/__init__.py (100%) rename {alr_envs => fancy_gym}/open_ai/mujoco/reacher_v2/__init__.py (100%) rename {alr_envs => fancy_gym}/open_ai/mujoco/reacher_v2/mp_wrapper.py (89%) rename {alr_envs => fancy_gym}/utils/__init__.py (100%) rename {alr_envs => fancy_gym}/utils/make_env_helpers.py (94%) rename {alr_envs => fancy_gym}/utils/time_aware_observation.py (99%) rename {alr_envs => fancy_gym}/utils/utils.py (100%) diff --git a/README.md b/README.md index 5d267a3..85249fb 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,12 @@ -## ALR Robotics Control Environments +## Fancy Gym -This project offers a large variety of reinforcement learning environments under the unifying interface of [OpenAI gym](https://gym.openai.com/). -We provide support (under the OpenAI interface) for the benchmark suites +Fancy gym offers a large variety of reinforcement learning environments under the unifying interface +of [OpenAI gym](https://gym.openai.com/). We provide support (under the OpenAI interface) for the benchmark suites [DeepMind Control](https://deepmind.com/research/publications/2020/dm-control-Software-and-Tasks-for-Continuous-Control) -(DMC) and [Metaworld](https://meta-world.github.io/). -Custom (Mujoco) gym environments can be created according -to [this guide](https://www.gymlibrary.ml/content/environment_creation/). -Unlike existing libraries, we additionally support to control agents with movement primitives, such as -Dynamic Movement Primitives (DMPs) and Probabilistic Movement Primitives (ProMP, we only consider the mean usually). +(DMC) and [Metaworld](https://meta-world.github.io/). Custom (Mujoco) gym environments can be created according +to [this guide](https://www.gymlibrary.ml/content/environment_creation/). Unlike existing libraries, we additionally +support to control agents with movement primitives, such as Dynamic Movement Primitives (DMPs) and Probabilistic +Movement Primitives (ProMP, we only consider the mean usually). ## Movement Primitive Environments (Episode-Based/Black-Box Environments) @@ -59,14 +58,14 @@ pip install -e . ## Using the framework -We prepared [multiple examples](alr_envs/examples/), please have a look there for more specific examples. +We prepared [multiple examples](fancy_gym/examples/), please have a look there for more specific examples. ### Step-wise environments ```python -import alr_envs +import fancy_gym -env = alr_envs.make('HoleReacher-v0', seed=1) +env = fancy_gym.make('HoleReacher-v0', seed=1) state = env.reset() for i in range(1000): @@ -85,9 +84,9 @@ Existing MP tasks can be created the same way as above. Just keep in mind, calli trajectory. ```python -import alr_envs +import fancy_gym -env = alr_envs.make('HoleReacherProMP-v0', seed=1) +env = fancy_gym.make('HoleReacherProMP-v0', seed=1) # render() can be called once in the beginning with all necessary arguments. To turn it of again just call render(None). env.render() @@ -104,19 +103,19 @@ To show all available environments, we provide some additional convenience. Each keys `DMP` and `ProMP` that store a list of available environment names. ```python -import alr_envs +import fancy_gym print("Custom MP tasks:") -print(alr_envs.ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS) +print(fancy_gym.ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS) print("OpenAI Gym MP tasks:") -print(alr_envs.ALL_GYM_MOTION_PRIMITIVE_ENVIRONMENTS) +print(fancy_gym.ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS) print("Deepmind Control MP tasks:") -print(alr_envs.ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS) +print(fancy_gym.ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS) print("MetaWorld MP tasks:") -print(alr_envs.ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS) +print(fancy_gym.ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS) ``` ### How to create a new MP task @@ -181,12 +180,12 @@ class MPWrapper(MPEnvWrapper): ``` -If you created a new task wrapper, feel free to open a PR, so we can integrate it for others to use as well. -Without the integration the task can still be used. A rough outline can be shown here, for more details we recommend -having a look at the [examples](alr_envs/examples/). +If you created a new task wrapper, feel free to open a PR, so we can integrate it for others to use as well. Without the +integration the task can still be used. A rough outline can be shown here, for more details we recommend having a look +at the [examples](fancy_gym/examples/). ```python -import alr_envs +import fancy_gym # Base environment name, according to structure of above example base_env_id = "ball_in_cup-catch" @@ -194,12 +193,12 @@ base_env_id = "ball_in_cup-catch" # Replace this wrapper with the custom wrapper for your environment by inheriting from the MPEnvWrapper. # You can also add other gym.Wrappers in case they are needed, # e.g. gym.wrappers.FlattenObservation for dict observations -wrappers = [alr_envs.dmc.suite.ball_in_cup.MPWrapper] +wrappers = [fancy_gym.dmc.suite.ball_in_cup.MPWrapper] mp_kwargs = {...} kwargs = {...} -env = alr_envs.make_dmp_env(base_env_id, wrappers=wrappers, seed=1, mp_kwargs=mp_kwargs, **kwargs) +env = fancy_gym.make_dmp_env(base_env_id, wrappers=wrappers, seed=1, mp_kwargs=mp_kwargs, **kwargs) # OR for a deterministic ProMP (other traj_gen_kwargs are required): -# env = alr_envs.make_promp_env(base_env, wrappers=wrappers, seed=seed, traj_gen_kwargs=mp_args) +# env = fancy_gym.make_promp_env(base_env, wrappers=wrappers, seed=seed, traj_gen_kwargs=mp_args) rewards = 0 obs = env.reset() diff --git a/alr_envs/open_ai/deprecated_needs_gym_robotics/__init__.py b/alr_envs/open_ai/deprecated_needs_gym_robotics/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/alr_envs/__init__.py b/fancy_gym/__init__.py similarity index 66% rename from alr_envs/__init__.py rename to fancy_gym/__init__.py index d63a656..457e3b1 100644 --- a/alr_envs/__init__.py +++ b/fancy_gym/__init__.py @@ -1,14 +1,13 @@ -from alr_envs import dmc, meta, open_ai -from alr_envs.utils.make_env_helpers import make, make_bb, make_rank - +from fancy_gym import dmc, meta, open_ai +from fancy_gym.utils.make_env_helpers import make, make_bb, make_rank +from .dmc import ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS # Convenience function for all MP environments from .envs import ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS -from .dmc import ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS from .meta import ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS -from .open_ai import ALL_GYM_MOTION_PRIMITIVE_ENVIRONMENTS +from .open_ai import ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS ALL_MOVEMENT_PRIMITIVE_ENVIRONMENTS = { key: value + ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS[key] + - ALL_GYM_MOTION_PRIMITIVE_ENVIRONMENTS[key] + + ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS[key] + ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS[key] for key, value in ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items()} diff --git a/__init__.py b/fancy_gym/black_box/__init__.py similarity index 100% rename from __init__.py rename to fancy_gym/black_box/__init__.py diff --git a/alr_envs/black_box/black_box_wrapper.py b/fancy_gym/black_box/black_box_wrapper.py similarity index 86% rename from alr_envs/black_box/black_box_wrapper.py rename to fancy_gym/black_box/black_box_wrapper.py index 6050740..6358778 100644 --- a/alr_envs/black_box/black_box_wrapper.py +++ b/fancy_gym/black_box/black_box_wrapper.py @@ -1,4 +1,5 @@ import os + os.environ["MUJOCO_GL"] = "egl" from typing import Tuple, Optional @@ -8,9 +9,9 @@ import numpy as np from gym import spaces from mp_pytorch.mp.mp_interfaces import MPInterface -from alr_envs.black_box.controller.base_controller import BaseController -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper -from alr_envs.utils.utils import get_numpy +from fancy_gym.black_box.controller.base_controller import BaseController +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.utils.utils import get_numpy class BlackBoxWrapper(gym.ObservationWrapper): @@ -77,12 +78,10 @@ class BlackBoxWrapper(gym.ObservationWrapper): def get_trajectory(self, action: np.ndarray) -> Tuple: clipped_params = np.clip(action, self.traj_gen_action_space.low, self.traj_gen_action_space.high) self.traj_gen.set_params(clipped_params) - # TODO: Bruce said DMP, ProMP, ProDMP can have 0 bc_time for sequencing - # TODO Check with Bruce for replanning + # TODO: is this correct for replanning? Do we need to adjust anything here? self.traj_gen.set_boundary_conditions( bc_time=np.array(0) if not self.do_replanning else np.array([self.current_traj_steps * self.dt]), bc_pos=self.current_pos, bc_vel=self.current_vel) - # TODO: is this correct for replanning? Do we need to adjust anything here? self.traj_gen.set_duration(None if self.learn_sub_trajectories else np.array([self.duration]), np.array([self.dt])) traj_dict = self.traj_gen.get_trajs(get_pos=True, get_vel=True) @@ -99,9 +98,9 @@ class BlackBoxWrapper(gym.ObservationWrapper): def _get_action_space(self): """ - This function can be used to modify the action space for considering actions which are not learned via motion + This function can be used to modify the action space for considering actions which are not learned via movement primitives. E.g. ball releasing time for the beer pong task. By default, it is the parameter space of the - motion primitive. + movement primitive. Only needs to be overwritten if the action space needs to be modified. """ try: @@ -138,7 +137,6 @@ class BlackBoxWrapper(gym.ObservationWrapper): for t, (pos, vel) in enumerate(zip(trajectory, velocity)): step_action = self.tracking_controller.get_action(pos, vel, self.current_pos, self.current_vel) c_action = np.clip(step_action, self.env.action_space.low, self.env.action_space.high) - # print('step/clipped action ratio: ', step_action/c_action) obs, c_reward, done, info = self.env.step(c_action) rewards[t] = c_reward @@ -176,26 +174,7 @@ class BlackBoxWrapper(gym.ObservationWrapper): """Only set render options here, such that they can be used during the rollout. This only needs to be called once""" self.render_kwargs = kwargs - # self.env.render(mode=self.render_mode, **self.render_kwargs) - # self.env.render(**self.render_kwargs) def reset(self, *, seed: Optional[int] = None, return_info: bool = False, options: Optional[dict] = None): self.current_traj_steps = 0 return super(BlackBoxWrapper, self).reset() - - def plot_trajs(self, des_trajs, des_vels): - import matplotlib.pyplot as plt - import matplotlib - matplotlib.use('TkAgg') - pos_fig = plt.figure('positions') - vel_fig = plt.figure('velocities') - for i in range(des_trajs.shape[1]): - plt.figure(pos_fig.number) - plt.subplot(des_trajs.shape[1], 1, i + 1) - plt.plot(np.ones(des_trajs.shape[0]) * self.current_pos[i]) - plt.plot(des_trajs[:, i]) - - plt.figure(vel_fig.number) - plt.subplot(des_vels.shape[1], 1, i + 1) - plt.plot(np.ones(des_trajs.shape[0]) * self.current_vel[i]) - plt.plot(des_vels[:, i]) diff --git a/alr_envs/black_box/__init__.py b/fancy_gym/black_box/controller/__init__.py similarity index 100% rename from alr_envs/black_box/__init__.py rename to fancy_gym/black_box/controller/__init__.py diff --git a/alr_envs/black_box/controller/base_controller.py b/fancy_gym/black_box/controller/base_controller.py similarity index 100% rename from alr_envs/black_box/controller/base_controller.py rename to fancy_gym/black_box/controller/base_controller.py diff --git a/alr_envs/black_box/controller/meta_world_controller.py b/fancy_gym/black_box/controller/meta_world_controller.py similarity index 92% rename from alr_envs/black_box/controller/meta_world_controller.py rename to fancy_gym/black_box/controller/meta_world_controller.py index 3781f15..efd8983 100644 --- a/alr_envs/black_box/controller/meta_world_controller.py +++ b/fancy_gym/black_box/controller/meta_world_controller.py @@ -1,6 +1,6 @@ import numpy as np -from alr_envs.black_box.controller.base_controller import BaseController +from fancy_gym.black_box.controller.base_controller import BaseController class MetaWorldController(BaseController): diff --git a/alr_envs/black_box/controller/pd_controller.py b/fancy_gym/black_box/controller/pd_controller.py similarity index 93% rename from alr_envs/black_box/controller/pd_controller.py rename to fancy_gym/black_box/controller/pd_controller.py index ab21444..35203d8 100644 --- a/alr_envs/black_box/controller/pd_controller.py +++ b/fancy_gym/black_box/controller/pd_controller.py @@ -1,6 +1,6 @@ from typing import Union, Tuple -from alr_envs.black_box.controller.base_controller import BaseController +from fancy_gym.black_box.controller.base_controller import BaseController class PDController(BaseController): diff --git a/alr_envs/black_box/controller/pos_controller.py b/fancy_gym/black_box/controller/pos_controller.py similarity index 76% rename from alr_envs/black_box/controller/pos_controller.py rename to fancy_gym/black_box/controller/pos_controller.py index 3f3526a..517187d 100644 --- a/alr_envs/black_box/controller/pos_controller.py +++ b/fancy_gym/black_box/controller/pos_controller.py @@ -1,4 +1,4 @@ -from alr_envs.black_box.controller.base_controller import BaseController +from fancy_gym.black_box.controller.base_controller import BaseController class PosController(BaseController): diff --git a/alr_envs/black_box/controller/vel_controller.py b/fancy_gym/black_box/controller/vel_controller.py similarity index 76% rename from alr_envs/black_box/controller/vel_controller.py rename to fancy_gym/black_box/controller/vel_controller.py index 2134207..b26d9ba 100644 --- a/alr_envs/black_box/controller/vel_controller.py +++ b/fancy_gym/black_box/controller/vel_controller.py @@ -1,4 +1,4 @@ -from alr_envs.black_box.controller.base_controller import BaseController +from fancy_gym.black_box.controller.base_controller import BaseController class VelController(BaseController): diff --git a/alr_envs/black_box/controller/__init__.py b/fancy_gym/black_box/factory/__init__.py similarity index 100% rename from alr_envs/black_box/controller/__init__.py rename to fancy_gym/black_box/factory/__init__.py diff --git a/alr_envs/black_box/factory/basis_generator_factory.py b/fancy_gym/black_box/factory/basis_generator_factory.py similarity index 100% rename from alr_envs/black_box/factory/basis_generator_factory.py rename to fancy_gym/black_box/factory/basis_generator_factory.py diff --git a/alr_envs/black_box/factory/controller_factory.py b/fancy_gym/black_box/factory/controller_factory.py similarity index 67% rename from alr_envs/black_box/factory/controller_factory.py rename to fancy_gym/black_box/factory/controller_factory.py index a1d068b..8b2d865 100644 --- a/alr_envs/black_box/factory/controller_factory.py +++ b/fancy_gym/black_box/factory/controller_factory.py @@ -1,7 +1,7 @@ -from alr_envs.black_box.controller.meta_world_controller import MetaWorldController -from alr_envs.black_box.controller.pd_controller import PDController -from alr_envs.black_box.controller.vel_controller import VelController -from alr_envs.black_box.controller.pos_controller import PosController +from fancy_gym.black_box.controller.meta_world_controller import MetaWorldController +from fancy_gym.black_box.controller.pd_controller import PDController +from fancy_gym.black_box.controller.pos_controller import PosController +from fancy_gym.black_box.controller.vel_controller import VelController ALL_TYPES = ["motor", "velocity", "position", "metaworld"] diff --git a/alr_envs/black_box/factory/phase_generator_factory.py b/fancy_gym/black_box/factory/phase_generator_factory.py similarity index 100% rename from alr_envs/black_box/factory/phase_generator_factory.py rename to fancy_gym/black_box/factory/phase_generator_factory.py diff --git a/alr_envs/black_box/factory/trajectory_generator_factory.py b/fancy_gym/black_box/factory/trajectory_generator_factory.py similarity index 99% rename from alr_envs/black_box/factory/trajectory_generator_factory.py rename to fancy_gym/black_box/factory/trajectory_generator_factory.py index 784513e..f7ca6e2 100644 --- a/alr_envs/black_box/factory/trajectory_generator_factory.py +++ b/fancy_gym/black_box/factory/trajectory_generator_factory.py @@ -1,8 +1,7 @@ -from mp_pytorch.mp.dmp import DMP -from mp_pytorch.mp.promp import ProMP -from mp_pytorch.mp.idmp import IDMP - from mp_pytorch.basis_gn.basis_generator import BasisGenerator +from mp_pytorch.mp.dmp import DMP +from mp_pytorch.mp.idmp import IDMP +from mp_pytorch.mp.promp import ProMP ALL_TYPES = ["promp", "dmp", "idmp"] diff --git a/alr_envs/black_box/raw_interface_wrapper.py b/fancy_gym/black_box/raw_interface_wrapper.py similarity index 95% rename from alr_envs/black_box/raw_interface_wrapper.py rename to fancy_gym/black_box/raw_interface_wrapper.py index ef93fdf..2342a3c 100644 --- a/alr_envs/black_box/raw_interface_wrapper.py +++ b/fancy_gym/black_box/raw_interface_wrapper.py @@ -1,9 +1,9 @@ -from typing import Union, Tuple -from mp_pytorch.mp.mp_interfaces import MPInterface from abc import abstractmethod +from typing import Union, Tuple import gym import numpy as np +from mp_pytorch.mp.mp_interfaces import MPInterface class RawInterfaceWrapper(gym.Wrapper): @@ -55,7 +55,7 @@ class RawInterfaceWrapper(gym.Wrapper): def episode_callback(self, action: np.ndarray, traj_gen: MPInterface) -> Tuple[ np.ndarray, Union[np.ndarray, None]]: """ - Used to extract the parameters for the motion primitive and other parameters from an action array which might + Used to extract the parameters for the movement primitive and other parameters from an action array which might include other actions like ball releasing time for the beer pong environment. This only needs to be overwritten if the action space is modified. Args: diff --git a/alr_envs/dmc/README.MD b/fancy_gym/dmc/README.MD similarity index 100% rename from alr_envs/dmc/README.MD rename to fancy_gym/dmc/README.MD diff --git a/alr_envs/dmc/__init__.py b/fancy_gym/dmc/__init__.py similarity index 90% rename from alr_envs/dmc/__init__.py rename to fancy_gym/dmc/__init__.py index c1e24eb..22ae47f 100644 --- a/alr_envs/dmc/__init__.py +++ b/fancy_gym/dmc/__init__.py @@ -56,7 +56,7 @@ kwargs_dict_bic_dmp['phase_generator_kwargs']['alpha_phase'] = 2 kwargs_dict_bic_dmp['trajectory_generator_kwargs']['weight_scale'] = 10 # TODO: weight scale 1, but goal scale 0.1 register( id=f'dmc_ball_in_cup-catch_dmp-v0', - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_bic_dmp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append("dmc_ball_in_cup-catch_dmp-v0") @@ -66,7 +66,7 @@ kwargs_dict_bic_promp['name'] = f"dmc:ball_in_cup-catch" kwargs_dict_bic_promp['wrappers'].append(suite.ball_in_cup.MPWrapper) register( id=f'dmc_ball_in_cup-catch_promp-v0', - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_bic_promp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append("dmc_ball_in_cup-catch_promp-v0") @@ -80,7 +80,7 @@ kwargs_dict_reacher_easy_dmp['phase_generator_kwargs']['alpha_phase'] = 2 kwargs_dict_reacher_easy_dmp['trajectory_generator_kwargs']['weight_scale'] = 500 register( id=f'dmc_reacher-easy_dmp-v0', - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_bic_dmp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append("dmc_reacher-easy_dmp-v0") @@ -91,7 +91,7 @@ kwargs_dict_reacher_easy_promp['wrappers'].append(suite.reacher.MPWrapper) kwargs_dict_reacher_easy_promp['trajectory_generator_kwargs']['weight_scale'] = 0.2 register( id=f'dmc_reacher-easy_promp-v0', - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_reacher_easy_promp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append("dmc_reacher-easy_promp-v0") @@ -105,7 +105,7 @@ kwargs_dict_reacher_hard_dmp['phase_generator_kwargs']['alpha_phase'] = 2 kwargs_dict_reacher_hard_dmp['trajectory_generator_kwargs']['weight_scale'] = 500 register( id=f'dmc_reacher-hard_dmp-v0', - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_reacher_hard_dmp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append("dmc_reacher-hard_dmp-v0") @@ -116,7 +116,7 @@ kwargs_dict_reacher_hard_promp['wrappers'].append(suite.reacher.MPWrapper) kwargs_dict_reacher_hard_promp['trajectory_generator_kwargs']['weight_scale'] = 0.2 register( id=f'dmc_reacher-hard_promp-v0', - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_reacher_hard_promp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append("dmc_reacher-hard_promp-v0") @@ -136,7 +136,7 @@ for _task in _dmc_cartpole_tasks: kwargs_dict_cartpole_dmp['controller_kwargs']['d_gains'] = 10 register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_cartpole_dmp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) @@ -150,7 +150,7 @@ for _task in _dmc_cartpole_tasks: kwargs_dict_cartpole_promp['trajectory_generator_kwargs']['weight_scale'] = 0.2 register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_cartpole_promp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -167,7 +167,7 @@ kwargs_dict_cartpole2poles_dmp['controller_kwargs']['d_gains'] = 10 _env_id = f'dmc_cartpole-two_poles_dmp-v0' register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_cartpole2poles_dmp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) @@ -181,7 +181,7 @@ kwargs_dict_cartpole2poles_promp['trajectory_generator_kwargs']['weight_scale'] _env_id = f'dmc_cartpole-two_poles_promp-v0' register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_cartpole2poles_promp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -198,7 +198,7 @@ kwargs_dict_cartpole3poles_dmp['controller_kwargs']['d_gains'] = 10 _env_id = f'dmc_cartpole-three_poles_dmp-v0' register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_cartpole3poles_dmp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) @@ -212,7 +212,7 @@ kwargs_dict_cartpole3poles_promp['trajectory_generator_kwargs']['weight_scale'] _env_id = f'dmc_cartpole-three_poles_promp-v0' register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_cartpole3poles_promp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -227,7 +227,7 @@ kwargs_dict_mani_reach_site_features_dmp['trajectory_generator_kwargs']['weight_ kwargs_dict_mani_reach_site_features_dmp['controller_kwargs']['controller_type'] = 'velocity' register( id=f'dmc_manipulation-reach_site_dmp-v0', - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_mani_reach_site_features_dmp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append("dmc_manipulation-reach_site_dmp-v0") @@ -239,7 +239,7 @@ kwargs_dict_mani_reach_site_features_promp['trajectory_generator_kwargs']['weigh kwargs_dict_mani_reach_site_features_promp['controller_kwargs']['controller_type'] = 'velocity' register( id=f'dmc_manipulation-reach_site_promp-v0', - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_mani_reach_site_features_promp ) ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append("dmc_manipulation-reach_site_promp-v0") diff --git a/alr_envs/dmc/dmc_wrapper.py b/fancy_gym/dmc/dmc_wrapper.py similarity index 100% rename from alr_envs/dmc/dmc_wrapper.py rename to fancy_gym/dmc/dmc_wrapper.py index 59f7793..b1522c3 100644 --- a/alr_envs/dmc/dmc_wrapper.py +++ b/fancy_gym/dmc/dmc_wrapper.py @@ -5,9 +5,9 @@ import collections from collections.abc import MutableMapping from typing import Any, Dict, Tuple, Optional, Union, Callable -from dm_control import composer import gym import numpy as np +from dm_control import composer from dm_control.rl import control from dm_env import specs from gym import spaces diff --git a/alr_envs/dmc/manipulation/__init__.py b/fancy_gym/dmc/manipulation/__init__.py similarity index 100% rename from alr_envs/dmc/manipulation/__init__.py rename to fancy_gym/dmc/manipulation/__init__.py diff --git a/alr_envs/dmc/manipulation/reach_site/__init__.py b/fancy_gym/dmc/manipulation/reach_site/__init__.py similarity index 100% rename from alr_envs/dmc/manipulation/reach_site/__init__.py rename to fancy_gym/dmc/manipulation/reach_site/__init__.py diff --git a/alr_envs/dmc/manipulation/reach_site/mp_wrapper.py b/fancy_gym/dmc/manipulation/reach_site/mp_wrapper.py similarity index 94% rename from alr_envs/dmc/manipulation/reach_site/mp_wrapper.py rename to fancy_gym/dmc/manipulation/reach_site/mp_wrapper.py index d918edc..f64ac4a 100644 --- a/alr_envs/dmc/manipulation/reach_site/mp_wrapper.py +++ b/fancy_gym/dmc/manipulation/reach_site/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/dmc/suite/__init__.py b/fancy_gym/dmc/suite/__init__.py similarity index 100% rename from alr_envs/dmc/suite/__init__.py rename to fancy_gym/dmc/suite/__init__.py diff --git a/alr_envs/dmc/suite/ball_in_cup/__init__.py b/fancy_gym/dmc/suite/ball_in_cup/__init__.py similarity index 100% rename from alr_envs/dmc/suite/ball_in_cup/__init__.py rename to fancy_gym/dmc/suite/ball_in_cup/__init__.py diff --git a/alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py b/fancy_gym/dmc/suite/ball_in_cup/mp_wrapper.py similarity index 93% rename from alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py rename to fancy_gym/dmc/suite/ball_in_cup/mp_wrapper.py index b3f882e..dc6a539 100644 --- a/alr_envs/dmc/suite/ball_in_cup/mp_wrapper.py +++ b/fancy_gym/dmc/suite/ball_in_cup/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/dmc/suite/cartpole/__init__.py b/fancy_gym/dmc/suite/cartpole/__init__.py similarity index 100% rename from alr_envs/dmc/suite/cartpole/__init__.py rename to fancy_gym/dmc/suite/cartpole/__init__.py index c5f9bee..8867457 100644 --- a/alr_envs/dmc/suite/cartpole/__init__.py +++ b/fancy_gym/dmc/suite/cartpole/__init__.py @@ -1,3 +1,3 @@ from .mp_wrapper import MPWrapper -from .mp_wrapper import TwoPolesMPWrapper from .mp_wrapper import ThreePolesMPWrapper +from .mp_wrapper import TwoPolesMPWrapper diff --git a/alr_envs/dmc/suite/cartpole/mp_wrapper.py b/fancy_gym/dmc/suite/cartpole/mp_wrapper.py similarity index 94% rename from alr_envs/dmc/suite/cartpole/mp_wrapper.py rename to fancy_gym/dmc/suite/cartpole/mp_wrapper.py index 6cc0687..7edd51f 100644 --- a/alr_envs/dmc/suite/cartpole/mp_wrapper.py +++ b/fancy_gym/dmc/suite/cartpole/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/dmc/suite/reacher/__init__.py b/fancy_gym/dmc/suite/reacher/__init__.py similarity index 100% rename from alr_envs/dmc/suite/reacher/__init__.py rename to fancy_gym/dmc/suite/reacher/__init__.py diff --git a/alr_envs/dmc/suite/reacher/mp_wrapper.py b/fancy_gym/dmc/suite/reacher/mp_wrapper.py similarity index 92% rename from alr_envs/dmc/suite/reacher/mp_wrapper.py rename to fancy_gym/dmc/suite/reacher/mp_wrapper.py index 82e4da8..5ac52e5 100644 --- a/alr_envs/dmc/suite/reacher/mp_wrapper.py +++ b/fancy_gym/dmc/suite/reacher/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/envs/__init__.py b/fancy_gym/envs/__init__.py similarity index 79% rename from alr_envs/envs/__init__.py rename to fancy_gym/envs/__init__.py index cb2d3ee..f75d884 100644 --- a/alr_envs/envs/__init__.py +++ b/fancy_gym/envs/__init__.py @@ -8,13 +8,13 @@ from .classic_control.hole_reacher.hole_reacher import HoleReacherEnv from .classic_control.simple_reacher.simple_reacher import SimpleReacherEnv from .classic_control.viapoint_reacher.viapoint_reacher import ViaPointReacherEnv from .mujoco.ant_jump.ant_jump import MAX_EPISODE_STEPS_ANTJUMP +from .mujoco.beerpong.beerpong import MAX_EPISODE_STEPS_BEERPONG from .mujoco.half_cheetah_jump.half_cheetah_jump import MAX_EPISODE_STEPS_HALFCHEETAHJUMP from .mujoco.hopper_jump.hopper_jump import MAX_EPISODE_STEPS_HOPPERJUMP from .mujoco.hopper_jump.hopper_jump_on_box import MAX_EPISODE_STEPS_HOPPERJUMPONBOX from .mujoco.hopper_throw.hopper_throw import MAX_EPISODE_STEPS_HOPPERTHROW from .mujoco.hopper_throw.hopper_throw_in_basket import MAX_EPISODE_STEPS_HOPPERTHROWINBASKET -from .mujoco.beerpong.beerpong import MAX_EPISODE_STEPS_BEERPONG -from .mujoco.reacher.reacher import ReacherEnv +from .mujoco.reacher.reacher import ReacherEnv, MAX_EPISODE_STEPS_REACHER from .mujoco.walker_2d_jump.walker_2d_jump import MAX_EPISODE_STEPS_WALKERJUMP ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": []} @@ -64,7 +64,7 @@ DEFAULT_BB_DICT_DMP = { ## Simple Reacher register( id='SimpleReacher-v0', - entry_point='alr_envs.envs.classic_control:SimpleReacherEnv', + entry_point='fancy_gym.envs.classic_control:SimpleReacherEnv', max_episode_steps=200, kwargs={ "n_links": 2, @@ -73,7 +73,7 @@ register( register( id='LongSimpleReacher-v0', - entry_point='alr_envs.envs.classic_control:SimpleReacherEnv', + entry_point='fancy_gym.envs.classic_control:SimpleReacherEnv', max_episode_steps=200, kwargs={ "n_links": 5, @@ -84,7 +84,7 @@ register( register( id='ViaPointReacher-v0', - entry_point='alr_envs.envs.classic_control:ViaPointReacherEnv', + entry_point='fancy_gym.envs.classic_control:ViaPointReacherEnv', max_episode_steps=200, kwargs={ "n_links": 5, @@ -96,7 +96,7 @@ register( ## Hole Reacher register( id='HoleReacher-v0', - entry_point='alr_envs.envs.classic_control:HoleReacherEnv', + entry_point='fancy_gym.envs.classic_control:HoleReacherEnv', max_episode_steps=200, kwargs={ "n_links": 5, @@ -112,12 +112,12 @@ register( # Mujoco -## Reacher +## Mujoco Reacher for _dims in [5, 7]: register( id=f'Reacher{_dims}d-v0', - entry_point='alr_envs.envs.mujoco:ReacherEnv', - max_episode_steps=200, + entry_point='fancy_gym.envs.mujoco:ReacherEnv', + max_episode_steps=MAX_EPISODE_STEPS_REACHER, kwargs={ "n_links": _dims, } @@ -125,17 +125,18 @@ for _dims in [5, 7]: register( id=f'Reacher{_dims}dSparse-v0', - entry_point='alr_envs.envs.mujoco:ReacherEnv', - max_episode_steps=200, + entry_point='fancy_gym.envs.mujoco:ReacherEnv', + max_episode_steps=MAX_EPISODE_STEPS_REACHER, kwargs={ "sparse": True, + 'reward_weight': 200, "n_links": _dims, } ) register( id='HopperJumpSparse-v0', - entry_point='alr_envs.envs.mujoco:HopperJumpEnv', + entry_point='fancy_gym.envs.mujoco:HopperJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ "sparse": True, @@ -144,7 +145,7 @@ register( register( id='HopperJump-v0', - entry_point='alr_envs.envs.mujoco:HopperJumpEnv', + entry_point='fancy_gym.envs.mujoco:HopperJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ "sparse": False, @@ -156,43 +157,43 @@ register( register( id='AntJump-v0', - entry_point='alr_envs.envs.mujoco:AntJumpEnv', + entry_point='fancy_gym.envs.mujoco:AntJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_ANTJUMP, ) register( id='HalfCheetahJump-v0', - entry_point='alr_envs.envs.mujoco:HalfCheetahJumpEnv', + entry_point='fancy_gym.envs.mujoco:HalfCheetahJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HALFCHEETAHJUMP, ) register( id='HopperJumpOnBox-v0', - entry_point='alr_envs.envs.mujoco:HopperJumpOnBoxEnv', + entry_point='fancy_gym.envs.mujoco:HopperJumpOnBoxEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMPONBOX, ) register( - id='ALRHopperThrow-v0', - entry_point='alr_envs.envs.mujoco:HopperThrowEnv', + id='HopperThrow-v0', + entry_point='fancy_gym.envs.mujoco:HopperThrowEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROW, ) register( - id='ALRHopperThrowInBasket-v0', - entry_point='alr_envs.envs.mujoco:HopperThrowInBasketEnv', + id='HopperThrowInBasket-v0', + entry_point='fancy_gym.envs.mujoco:HopperThrowInBasketEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, ) register( - id='ALRWalker2DJump-v0', - entry_point='alr_envs.envs.mujoco:Walker2dJumpEnv', + id='Walker2DJump-v0', + entry_point='fancy_gym.envs.mujoco:Walker2dJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_WALKERJUMP, ) register( id='BeerPong-v0', - entry_point='alr_envs.envs.mujoco:BeerPongEnv', + entry_point='fancy_gym.envs.mujoco:BeerPongEnv', max_episode_steps=MAX_EPISODE_STEPS_BEERPONG, ) @@ -200,18 +201,18 @@ register( # only one time step, i.e. we simulate until the end of th episode register( id='BeerPongStepBased-v0', - entry_point='alr_envs.envs.mujoco:BeerPongEnvStepBasedEpisodicReward', + entry_point='fancy_gym.envs.mujoco:BeerPongEnvStepBasedEpisodicReward', max_episode_steps=MAX_EPISODE_STEPS_BEERPONG, ) # Beerpong with episodic reward, but fixed release time step register( id='BeerPongFixedRelease-v0', - entry_point='alr_envs.envs.mujoco:BeerPongEnvFixedReleaseStep', + entry_point='fancy_gym.envs.mujoco:BeerPongEnvFixedReleaseStep', max_episode_steps=MAX_EPISODE_STEPS_BEERPONG, ) -# Motion Primitive Environments +# movement Primitive Environments ## Simple Reacher _versions = ["SimpleReacher-v0", "LongSimpleReacher-v0"] @@ -227,7 +228,7 @@ for _v in _versions: kwargs_dict_simple_reacher_dmp['name'] = f"{_v}" register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_simple_reacher_dmp ) ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) @@ -240,7 +241,7 @@ for _v in _versions: kwargs_dict_simple_reacher_promp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_simple_reacher_promp ) ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -254,7 +255,7 @@ kwargs_dict_via_point_reacher_dmp['phase_generator_kwargs']['alpha_phase'] = 2 kwargs_dict_via_point_reacher_dmp['name'] = "ViaPointReacher-v0" register( id='ViaPointReacherDMP-v0', - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', # max_episode_steps=1, kwargs=kwargs_dict_via_point_reacher_dmp ) @@ -266,7 +267,7 @@ kwargs_dict_via_point_reacher_promp['controller_kwargs']['controller_type'] = 'v kwargs_dict_via_point_reacher_promp['name'] = "ViaPointReacher-v0" register( id="ViaPointReacherProMP-v0", - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_via_point_reacher_promp ) ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ViaPointReacherProMP-v0") @@ -285,7 +286,7 @@ for _v in _versions: kwargs_dict_hole_reacher_dmp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', # max_episode_steps=1, kwargs=kwargs_dict_hole_reacher_dmp ) @@ -299,7 +300,7 @@ for _v in _versions: kwargs_dict_hole_reacher_promp['name'] = f"{_v}" register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_hole_reacher_promp ) ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -309,30 +310,26 @@ _versions = ["Reacher5d-v0", "Reacher7d-v0", "Reacher5dSparse-v0", "Reacher7dSpa for _v in _versions: _name = _v.split("-") _env_id = f'{_name[0]}DMP-{_name[1]}' - kwargs_dict_reacherNd_dmp = deepcopy(DEFAULT_BB_DICT_DMP) - kwargs_dict_reacherNd_dmp['wrappers'].append(mujoco.reacher.MPWrapper) - kwargs_dict_reacherNd_dmp['trajectory_generator_kwargs']['weight_scale'] = 5 - kwargs_dict_reacherNd_dmp['phase_generator_kwargs']['alpha_phase'] = 2 - kwargs_dict_reacherNd_dmp['basis_generator_kwargs']['num_basis'] = 2 - kwargs_dict_reacherNd_dmp['name'] = _v + kwargs_dict_reacher_dmp = deepcopy(DEFAULT_BB_DICT_DMP) + kwargs_dict_reacher_dmp['wrappers'].append(mujoco.reacher.MPWrapper) + kwargs_dict_reacher_dmp['phase_generator_kwargs']['alpha_phase'] = 2 + kwargs_dict_reacher_dmp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', # max_episode_steps=1, - kwargs=kwargs_dict_reacherNd_dmp + kwargs=kwargs_dict_reacher_dmp ) ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' - kwargs_dict_alr_reacher_promp = deepcopy(DEFAULT_BB_DICT_ProMP) - kwargs_dict_alr_reacher_promp['wrappers'].append(mujoco.reacher.MPWrapper) - kwargs_dict_alr_reacher_promp['controller_kwargs']['p_gains'] = 1 - kwargs_dict_alr_reacher_promp['controller_kwargs']['d_gains'] = 0.1 - kwargs_dict_alr_reacher_promp['name'] = _v + kwargs_dict_reacher_promp = deepcopy(DEFAULT_BB_DICT_ProMP) + kwargs_dict_reacher_promp['wrappers'].append(mujoco.reacher.MPWrapper) + kwargs_dict_reacher_promp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', - kwargs=kwargs_dict_alr_reacher_promp + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', + kwargs=kwargs_dict_reacher_promp ) ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -352,7 +349,7 @@ for _v in _versions: kwargs_dict_bp_promp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_bp_promp ) ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -372,7 +369,7 @@ for _v in _versions: kwargs_dict_bp_promp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_bp_promp ) ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -384,7 +381,7 @@ for _v in _versions: # ######################################################################################################################## # # ## AntJump -# _versions = ['ALRAntJump-v0'] +# _versions = ['AntJump-v0'] # for _v in _versions: # _name = _v.split("-") # _env_id = f'{_name[0]}ProMP-{_name[1]}' @@ -393,7 +390,7 @@ for _v in _versions: # kwargs_dict_ant_jump_promp['name'] = _v # register( # id=_env_id, -# entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', +# entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', # kwargs=kwargs_dict_ant_jump_promp # ) # ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -401,7 +398,7 @@ for _v in _versions: # ######################################################################################################################## # # ## HalfCheetahJump -# _versions = ['ALRHalfCheetahJump-v0'] +# _versions = ['HalfCheetahJump-v0'] # for _v in _versions: # _name = _v.split("-") # _env_id = f'{_name[0]}ProMP-{_name[1]}' @@ -410,7 +407,7 @@ for _v in _versions: # kwargs_dict_halfcheetah_jump_promp['name'] = _v # register( # id=_env_id, -# entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', +# entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', # kwargs=kwargs_dict_halfcheetah_jump_promp # ) # ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -420,7 +417,7 @@ for _v in _versions: ## HopperJump _versions = ['HopperJump-v0', 'HopperJumpSparse-v0', - # 'ALRHopperJumpOnBox-v0', 'ALRHopperThrow-v0', 'ALRHopperThrowInBasket-v0' + # 'HopperJumpOnBox-v0', 'HopperThrow-v0', 'HopperThrowInBasket-v0' ] # TODO: Check if all environments work with the same MPWrapper for _v in _versions: @@ -431,7 +428,7 @@ for _v in _versions: kwargs_dict_hopper_jump_promp['name'] = _v register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_hopper_jump_promp ) ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -440,7 +437,7 @@ for _v in _versions: # # # ## Walker2DJump -# _versions = ['ALRWalker2DJump-v0'] +# _versions = ['Walker2DJump-v0'] # for _v in _versions: # _name = _v.split("-") # _env_id = f'{_name[0]}ProMP-{_name[1]}' @@ -449,7 +446,7 @@ for _v in _versions: # kwargs_dict_walker2d_jump_promp['name'] = _v # register( # id=_env_id, -# entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', +# entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', # kwargs=kwargs_dict_walker2d_jump_promp # ) # ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -458,7 +455,7 @@ for _v in _versions: """ register( id='SimpleReacher-v1', - entry_point='alr_envs.envs.classic_control:SimpleReacherEnv', + entry_point='fancy_gym.envs.classic_control:SimpleReacherEnv', max_episode_steps=200, kwargs={ "n_links": 2, @@ -468,7 +465,7 @@ register( register( id='LongSimpleReacher-v1', - entry_point='alr_envs.envs.classic_control:SimpleReacherEnv', + entry_point='fancy_gym.envs.classic_control:SimpleReacherEnv', max_episode_steps=200, kwargs={ "n_links": 5, @@ -477,7 +474,7 @@ register( ) register( id='HoleReacher-v1', - entry_point='alr_envs.envs.classic_control:HoleReacherEnv', + entry_point='fancy_gym.envs.classic_control:HoleReacherEnv', max_episode_steps=200, kwargs={ "n_links": 5, @@ -492,7 +489,7 @@ register( ) register( id='HoleReacher-v2', - entry_point='alr_envs.envs.classic_control:HoleReacherEnv', + entry_point='fancy_gym.envs.classic_control:HoleReacherEnv', max_episode_steps=200, kwargs={ "n_links": 5, @@ -508,8 +505,8 @@ register( # CtxtFree are v0, Contextual are v1 register( - id='ALRAntJump-v0', - entry_point='alr_envs.envs.mujoco:AntJumpEnv', + id='AntJump-v0', + entry_point='fancy_gym.envs.mujoco:AntJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_ANTJUMP, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_ANTJUMP, @@ -518,8 +515,8 @@ register( ) # CtxtFree are v0, Contextual are v1 register( - id='ALRHalfCheetahJump-v0', - entry_point='alr_envs.envs.mujoco:HalfCheetahJumpEnv', + id='HalfCheetahJump-v0', + entry_point='fancy_gym.envs.mujoco:HalfCheetahJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HALFCHEETAHJUMP, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HALFCHEETAHJUMP, @@ -527,8 +524,8 @@ register( } ) register( - id='ALRHopperJump-v0', - entry_point='alr_envs.envs.mujoco:HopperJumpEnv', + id='HopperJump-v0', + entry_point='fancy_gym.envs.mujoco:HopperJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMP, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMP, @@ -546,26 +543,26 @@ for i in _vs: _env_id = f'ALRReacher{i}-v0' register( id=_env_id, - entry_point='alr_envs.envs.mujoco:ReacherEnv', + entry_point='fancy_gym.envs.mujoco:ReacherEnv', max_episode_steps=200, kwargs={ "steps_before_reward": 0, "n_links": 5, "balance": False, - 'ctrl_cost_weight': i + '_ctrl_cost_weight': i } ) _env_id = f'ALRReacherSparse{i}-v0' register( id=_env_id, - entry_point='alr_envs.envs.mujoco:ReacherEnv', + entry_point='fancy_gym.envs.mujoco:ReacherEnv', max_episode_steps=200, kwargs={ "steps_before_reward": 200, "n_links": 5, "balance": False, - 'ctrl_cost_weight': i + '_ctrl_cost_weight': i } ) _vs = np.arange(101).tolist() + [1e-5, 5e-5, 1e-4, 5e-4, 1e-3, 5e-3, 1e-2, 5e-2, 1e-1, 5e-1] @@ -573,7 +570,7 @@ for i in _vs: _env_id = f'ALRReacher{i}ProMP-v0' register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_promp_env_helper', kwargs={ "name": f"{_env_id.replace('ProMP', '')}", "wrappers": [mujoco.reacher.MPWrapper], @@ -596,7 +593,7 @@ for i in _vs: _env_id = f'ALRReacherSparse{i}ProMP-v0' register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_promp_env_helper', kwargs={ "name": f"{_env_id.replace('ProMP', '')}", "wrappers": [mujoco.reacher.MPWrapper], @@ -617,8 +614,8 @@ for i in _vs: ) register( - id='ALRHopperJumpOnBox-v0', - entry_point='alr_envs.envs.mujoco:HopperJumpOnBoxEnv', + id='HopperJumpOnBox-v0', + entry_point='fancy_gym.envs.mujoco:HopperJumpOnBoxEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERJUMPONBOX, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HOPPERJUMPONBOX, @@ -626,8 +623,8 @@ for i in _vs: } ) register( - id='ALRHopperThrow-v0', - entry_point='alr_envs.envs.mujoco:HopperThrowEnv', + id='HopperThrow-v0', + entry_point='fancy_gym.envs.mujoco:HopperThrowEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROW, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROW, @@ -635,8 +632,8 @@ for i in _vs: } ) register( - id='ALRHopperThrowInBasket-v0', - entry_point='alr_envs.envs.mujoco:HopperThrowInBasketEnv', + id='HopperThrowInBasket-v0', + entry_point='fancy_gym.envs.mujoco:HopperThrowInBasketEnv', max_episode_steps=MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_HOPPERTHROWINBASKET, @@ -644,8 +641,8 @@ for i in _vs: } ) register( - id='ALRWalker2DJump-v0', - entry_point='alr_envs.envs.mujoco:Walker2dJumpEnv', + id='Walker2DJump-v0', + entry_point='fancy_gym.envs.mujoco:Walker2dJumpEnv', max_episode_steps=MAX_EPISODE_STEPS_WALKERJUMP, kwargs={ "max_episode_steps": MAX_EPISODE_STEPS_WALKERJUMP, @@ -653,13 +650,13 @@ for i in _vs: } ) register(id='TableTennis2DCtxt-v1', - entry_point='alr_envs.envs.mujoco:TTEnvGym', + entry_point='fancy_gym.envs.mujoco:TTEnvGym', max_episode_steps=MAX_EPISODE_STEPS, kwargs={'ctxt_dim': 2, 'fixed_goal': True}) register( - id='ALRBeerPong-v0', - entry_point='alr_envs.envs.mujoco:ALRBeerBongEnv', + id='BeerPong-v0', + entry_point='fancy_gym.envs.mujoco:BeerBongEnv', max_episode_steps=300, kwargs={ "rndm_goal": False, diff --git a/alr_envs/envs/classic_control/README.MD b/fancy_gym/envs/classic_control/README.MD similarity index 100% rename from alr_envs/envs/classic_control/README.MD rename to fancy_gym/envs/classic_control/README.MD diff --git a/alr_envs/envs/classic_control/__init__.py b/fancy_gym/envs/classic_control/__init__.py similarity index 100% rename from alr_envs/envs/classic_control/__init__.py rename to fancy_gym/envs/classic_control/__init__.py diff --git a/alr_envs/black_box/factory/__init__.py b/fancy_gym/envs/classic_control/base_reacher/__init__.py similarity index 100% rename from alr_envs/black_box/factory/__init__.py rename to fancy_gym/envs/classic_control/base_reacher/__init__.py diff --git a/alr_envs/envs/classic_control/base_reacher/base_reacher.py b/fancy_gym/envs/classic_control/base_reacher/base_reacher.py similarity index 98% rename from alr_envs/envs/classic_control/base_reacher/base_reacher.py rename to fancy_gym/envs/classic_control/base_reacher/base_reacher.py index f9186d8..abfe2ca 100644 --- a/alr_envs/envs/classic_control/base_reacher/base_reacher.py +++ b/fancy_gym/envs/classic_control/base_reacher/base_reacher.py @@ -7,7 +7,7 @@ from gym import spaces from gym.core import ObsType from gym.utils import seeding -from alr_envs.envs.classic_control.utils import intersect +from fancy_gym.envs.classic_control.utils import intersect class BaseReacherEnv(gym.Env, ABC): diff --git a/alr_envs/envs/classic_control/base_reacher/base_reacher_direct.py b/fancy_gym/envs/classic_control/base_reacher/base_reacher_direct.py similarity index 92% rename from alr_envs/envs/classic_control/base_reacher/base_reacher_direct.py rename to fancy_gym/envs/classic_control/base_reacher/base_reacher_direct.py index 05cff5b..0e44033 100644 --- a/alr_envs/envs/classic_control/base_reacher/base_reacher_direct.py +++ b/fancy_gym/envs/classic_control/base_reacher/base_reacher_direct.py @@ -1,14 +1,16 @@ from abc import ABC -from gym import spaces import numpy as np -from alr_envs.envs.classic_control.base_reacher.base_reacher import BaseReacherEnv +from gym import spaces + +from fancy_gym.envs.classic_control.base_reacher.base_reacher import BaseReacherEnv class BaseReacherDirectEnv(BaseReacherEnv, ABC): """ Base class for directly controlled reaching environments """ + def __init__(self, n_links: int, random_start: bool = True, allow_self_collision: bool = False): super().__init__(n_links, random_start, allow_self_collision) diff --git a/alr_envs/envs/classic_control/base_reacher/base_reacher_torque.py b/fancy_gym/envs/classic_control/base_reacher/base_reacher_torque.py similarity index 92% rename from alr_envs/envs/classic_control/base_reacher/base_reacher_torque.py rename to fancy_gym/envs/classic_control/base_reacher/base_reacher_torque.py index 469d8a3..79f3005 100644 --- a/alr_envs/envs/classic_control/base_reacher/base_reacher_torque.py +++ b/fancy_gym/envs/classic_control/base_reacher/base_reacher_torque.py @@ -1,14 +1,16 @@ from abc import ABC -from gym import spaces import numpy as np -from alr_envs.envs.classic_control.base_reacher.base_reacher import BaseReacherEnv +from gym import spaces + +from fancy_gym.envs.classic_control.base_reacher.base_reacher import BaseReacherEnv class BaseReacherTorqueEnv(BaseReacherEnv, ABC): """ Base class for torque controlled reaching environments """ + def __init__(self, n_links: int, random_start: bool = True, allow_self_collision: bool = False): super().__init__(n_links, random_start, allow_self_collision) diff --git a/alr_envs/envs/classic_control/hole_reacher/__init__.py b/fancy_gym/envs/classic_control/hole_reacher/__init__.py similarity index 100% rename from alr_envs/envs/classic_control/hole_reacher/__init__.py rename to fancy_gym/envs/classic_control/hole_reacher/__init__.py diff --git a/alr_envs/envs/classic_control/hole_reacher/hole_reacher.py b/fancy_gym/envs/classic_control/hole_reacher/hole_reacher.py similarity index 95% rename from alr_envs/envs/classic_control/hole_reacher/hole_reacher.py rename to fancy_gym/envs/classic_control/hole_reacher/hole_reacher.py index 0bd0e5c..5563ea6 100644 --- a/alr_envs/envs/classic_control/hole_reacher/hole_reacher.py +++ b/fancy_gym/envs/classic_control/hole_reacher/hole_reacher.py @@ -6,7 +6,9 @@ import numpy as np from gym.core import ObsType from matplotlib import patches -from alr_envs.envs.classic_control.base_reacher.base_reacher_direct import BaseReacherDirectEnv +from fancy_gym.envs.classic_control.base_reacher.base_reacher_direct import BaseReacherDirectEnv + +MAX_EPISODE_STEPS_HOLEREACHER = 200 class HoleReacherEnv(BaseReacherDirectEnv): @@ -41,13 +43,13 @@ class HoleReacherEnv(BaseReacherDirectEnv): self.observation_space = gym.spaces.Box(low=-state_bound, high=state_bound, shape=state_bound.shape) if rew_fct == "simple": - from alr_envs.envs.classic_control.hole_reacher.hr_simple_reward import HolereacherReward + from fancy_gym.envs.classic_control.hole_reacher.hr_simple_reward import HolereacherReward self.reward_function = HolereacherReward(allow_self_collision, allow_wall_collision, collision_penalty) elif rew_fct == "vel_acc": - from alr_envs.envs.classic_control.hole_reacher.hr_dist_vel_acc_reward import HolereacherReward + from fancy_gym.envs.classic_control.hole_reacher.hr_dist_vel_acc_reward import HolereacherReward self.reward_function = HolereacherReward(allow_self_collision, allow_wall_collision, collision_penalty) elif rew_fct == "unbounded": - from alr_envs.envs.classic_control.hole_reacher.hr_unbounded_reward import HolereacherReward + from fancy_gym.envs.classic_control.hole_reacher.hr_unbounded_reward import HolereacherReward self.reward_function = HolereacherReward(allow_self_collision, allow_wall_collision) else: raise ValueError("Unknown reward function {}".format(rew_fct)) @@ -224,7 +226,6 @@ class HoleReacherEnv(BaseReacherDirectEnv): if __name__ == "__main__": - import time env = HoleReacherEnv(5) env.reset() diff --git a/alr_envs/envs/classic_control/hole_reacher/hr_dist_vel_acc_reward.py b/fancy_gym/envs/classic_control/hole_reacher/hr_dist_vel_acc_reward.py similarity index 100% rename from alr_envs/envs/classic_control/hole_reacher/hr_dist_vel_acc_reward.py rename to fancy_gym/envs/classic_control/hole_reacher/hr_dist_vel_acc_reward.py diff --git a/alr_envs/envs/classic_control/hole_reacher/hr_simple_reward.py b/fancy_gym/envs/classic_control/hole_reacher/hr_simple_reward.py similarity index 100% rename from alr_envs/envs/classic_control/hole_reacher/hr_simple_reward.py rename to fancy_gym/envs/classic_control/hole_reacher/hr_simple_reward.py diff --git a/alr_envs/envs/classic_control/hole_reacher/hr_unbounded_reward.py b/fancy_gym/envs/classic_control/hole_reacher/hr_unbounded_reward.py similarity index 100% rename from alr_envs/envs/classic_control/hole_reacher/hr_unbounded_reward.py rename to fancy_gym/envs/classic_control/hole_reacher/hr_unbounded_reward.py diff --git a/alr_envs/envs/classic_control/hole_reacher/mp_wrapper.py b/fancy_gym/envs/classic_control/hole_reacher/mp_wrapper.py similarity index 91% rename from alr_envs/envs/classic_control/hole_reacher/mp_wrapper.py rename to fancy_gym/envs/classic_control/hole_reacher/mp_wrapper.py index 00a5eb8..d160b5c 100644 --- a/alr_envs/envs/classic_control/hole_reacher/mp_wrapper.py +++ b/fancy_gym/envs/classic_control/hole_reacher/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/envs/classic_control/simple_reacher/__init__.py b/fancy_gym/envs/classic_control/simple_reacher/__init__.py similarity index 100% rename from alr_envs/envs/classic_control/simple_reacher/__init__.py rename to fancy_gym/envs/classic_control/simple_reacher/__init__.py diff --git a/alr_envs/envs/classic_control/simple_reacher/mp_wrapper.py b/fancy_gym/envs/classic_control/simple_reacher/mp_wrapper.py similarity index 90% rename from alr_envs/envs/classic_control/simple_reacher/mp_wrapper.py rename to fancy_gym/envs/classic_control/simple_reacher/mp_wrapper.py index 3fa12d8..6d1fda1 100644 --- a/alr_envs/envs/classic_control/simple_reacher/mp_wrapper.py +++ b/fancy_gym/envs/classic_control/simple_reacher/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/envs/classic_control/simple_reacher/simple_reacher.py b/fancy_gym/envs/classic_control/simple_reacher/simple_reacher.py similarity index 97% rename from alr_envs/envs/classic_control/simple_reacher/simple_reacher.py rename to fancy_gym/envs/classic_control/simple_reacher/simple_reacher.py index 8c6f8d5..9b03147 100644 --- a/alr_envs/envs/classic_control/simple_reacher/simple_reacher.py +++ b/fancy_gym/envs/classic_control/simple_reacher/simple_reacher.py @@ -5,7 +5,7 @@ import numpy as np from gym import spaces from gym.core import ObsType -from alr_envs.envs.classic_control.base_reacher.base_reacher_torque import BaseReacherTorqueEnv +from fancy_gym.envs.classic_control.base_reacher.base_reacher_torque import BaseReacherTorqueEnv class SimpleReacherEnv(BaseReacherTorqueEnv): diff --git a/alr_envs/envs/classic_control/utils.py b/fancy_gym/envs/classic_control/utils.py similarity index 96% rename from alr_envs/envs/classic_control/utils.py rename to fancy_gym/envs/classic_control/utils.py index b557a0a..ea378d1 100644 --- a/alr_envs/envs/classic_control/utils.py +++ b/fancy_gym/envs/classic_control/utils.py @@ -1,6 +1,3 @@ -import numpy as np - - def ccw(A, B, C): return (C[1] - A[1]) * (B[0] - A[0]) - (B[1] - A[1]) * (C[0] - A[0]) > 1e-12 diff --git a/alr_envs/envs/classic_control/viapoint_reacher/__init__.py b/fancy_gym/envs/classic_control/viapoint_reacher/__init__.py similarity index 100% rename from alr_envs/envs/classic_control/viapoint_reacher/__init__.py rename to fancy_gym/envs/classic_control/viapoint_reacher/__init__.py diff --git a/alr_envs/envs/classic_control/viapoint_reacher/mp_wrapper.py b/fancy_gym/envs/classic_control/viapoint_reacher/mp_wrapper.py similarity index 91% rename from alr_envs/envs/classic_control/viapoint_reacher/mp_wrapper.py rename to fancy_gym/envs/classic_control/viapoint_reacher/mp_wrapper.py index d152f3b..47da749 100644 --- a/alr_envs/envs/classic_control/viapoint_reacher/mp_wrapper.py +++ b/fancy_gym/envs/classic_control/viapoint_reacher/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/envs/classic_control/viapoint_reacher/viapoint_reacher.py b/fancy_gym/envs/classic_control/viapoint_reacher/viapoint_reacher.py similarity index 98% rename from alr_envs/envs/classic_control/viapoint_reacher/viapoint_reacher.py rename to fancy_gym/envs/classic_control/viapoint_reacher/viapoint_reacher.py index 9266721..f3412ac 100644 --- a/alr_envs/envs/classic_control/viapoint_reacher/viapoint_reacher.py +++ b/fancy_gym/envs/classic_control/viapoint_reacher/viapoint_reacher.py @@ -4,9 +4,8 @@ import gym import matplotlib.pyplot as plt import numpy as np from gym.core import ObsType -from gym.utils import seeding -from alr_envs.envs.classic_control.base_reacher.base_reacher_direct import BaseReacherDirectEnv +from fancy_gym.envs.classic_control.base_reacher.base_reacher_direct import BaseReacherDirectEnv class ViaPointReacherEnv(BaseReacherDirectEnv): @@ -187,7 +186,6 @@ class ViaPointReacherEnv(BaseReacherDirectEnv): if __name__ == "__main__": - import time env = ViaPointReacherEnv(5) env.reset() diff --git a/alr_envs/envs/mujoco/README.MD b/fancy_gym/envs/mujoco/README.MD similarity index 100% rename from alr_envs/envs/mujoco/README.MD rename to fancy_gym/envs/mujoco/README.MD diff --git a/alr_envs/envs/mujoco/__init__.py b/fancy_gym/envs/mujoco/__init__.py similarity index 100% rename from alr_envs/envs/mujoco/__init__.py rename to fancy_gym/envs/mujoco/__init__.py index 1d0cf76..b283b60 100644 --- a/alr_envs/envs/mujoco/__init__.py +++ b/fancy_gym/envs/mujoco/__init__.py @@ -1,9 +1,9 @@ -from .beerpong.beerpong import BeerPongEnv, BeerPongEnvFixedReleaseStep, BeerPongEnvStepBasedEpisodicReward from .ant_jump.ant_jump import AntJumpEnv +from .beerpong.beerpong import BeerPongEnv, BeerPongEnvFixedReleaseStep, BeerPongEnvStepBasedEpisodicReward from .half_cheetah_jump.half_cheetah_jump import HalfCheetahJumpEnv +from .hopper_jump.hopper_jump import HopperJumpEnv from .hopper_jump.hopper_jump_on_box import HopperJumpOnBoxEnv from .hopper_throw.hopper_throw import HopperThrowEnv from .hopper_throw.hopper_throw_in_basket import HopperThrowInBasketEnv from .reacher.reacher import ReacherEnv from .walker_2d_jump.walker_2d_jump import Walker2dJumpEnv -from .hopper_jump.hopper_jump import HopperJumpEnv diff --git a/alr_envs/envs/mujoco/ant_jump/__init__.py b/fancy_gym/envs/mujoco/ant_jump/__init__.py similarity index 100% rename from alr_envs/envs/mujoco/ant_jump/__init__.py rename to fancy_gym/envs/mujoco/ant_jump/__init__.py diff --git a/alr_envs/envs/mujoco/ant_jump/ant_jump.py b/fancy_gym/envs/mujoco/ant_jump/ant_jump.py similarity index 99% rename from alr_envs/envs/mujoco/ant_jump/ant_jump.py rename to fancy_gym/envs/mujoco/ant_jump/ant_jump.py index 7c00225..9311ae1 100644 --- a/alr_envs/envs/mujoco/ant_jump/ant_jump.py +++ b/fancy_gym/envs/mujoco/ant_jump/ant_jump.py @@ -17,7 +17,7 @@ class AntJumpEnv(AntEnv): """ Initialization changes to normal Ant: - healthy_reward: 1.0 -> 0.01 -> 0.0 no healthy reward needed - Paul and Marc - - ctrl_cost_weight 0.5 -> 0.0 + - _ctrl_cost_weight 0.5 -> 0.0 - contact_cost_weight: 5e-4 -> 0.0 - healthy_z_range: (0.2, 1.0) -> (0.3, float('inf')) !!!!! Does that make sense, limiting height? """ diff --git a/alr_envs/envs/mujoco/ant_jump/assets/ant.xml b/fancy_gym/envs/mujoco/ant_jump/assets/ant.xml similarity index 100% rename from alr_envs/envs/mujoco/ant_jump/assets/ant.xml rename to fancy_gym/envs/mujoco/ant_jump/assets/ant.xml diff --git a/alr_envs/envs/mujoco/ant_jump/mp_wrapper.py b/fancy_gym/envs/mujoco/ant_jump/mp_wrapper.py similarity index 87% rename from alr_envs/envs/mujoco/ant_jump/mp_wrapper.py rename to fancy_gym/envs/mujoco/ant_jump/mp_wrapper.py index c1dfbde..2f2eb76 100644 --- a/alr_envs/envs/mujoco/ant_jump/mp_wrapper.py +++ b/fancy_gym/envs/mujoco/ant_jump/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Union, Tuple import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/envs/mujoco/beerpong/__init__.py b/fancy_gym/envs/mujoco/beerpong/__init__.py similarity index 100% rename from alr_envs/envs/mujoco/beerpong/__init__.py rename to fancy_gym/envs/mujoco/beerpong/__init__.py diff --git a/alr_envs/envs/mujoco/beerpong/assets/beerpong.xml b/fancy_gym/envs/mujoco/beerpong/assets/beerpong.xml similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/beerpong.xml rename to fancy_gym/envs/mujoco/beerpong/assets/beerpong.xml diff --git a/alr_envs/envs/mujoco/beerpong/assets/beerpong_wo_cup.xml b/fancy_gym/envs/mujoco/beerpong/assets/beerpong_wo_cup.xml similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/beerpong_wo_cup.xml rename to fancy_gym/envs/mujoco/beerpong/assets/beerpong_wo_cup.xml diff --git a/alr_envs/envs/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml b/fancy_gym/envs/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml rename to fancy_gym/envs/mujoco/beerpong/assets/beerpong_wo_cup_big_table.xml diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/base_link_convex.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/base_link_convex.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/base_link_convex.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/base_link_convex.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/base_link_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/base_link_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/base_link_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/base_link_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_dist_link_convex.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_dist_link_convex.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_dist_link_convex.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_dist_link_convex.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_dist_link_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_dist_link_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_dist_link_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_dist_link_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_med_link_convex.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_med_link_convex.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_med_link_convex.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_med_link_convex.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_med_link_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_med_link_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_med_link_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_med_link_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p1.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p1.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p1.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p1.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p2.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p2.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p2.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p2.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p3.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p3.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p3.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_convex_decomposition_p3.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_finger_prox_link_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p1.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p1.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p1.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p1.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p2.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p2.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p2.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p2.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p3.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p3.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p3.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p3.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p4.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p4.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p4.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/bhand_palm_link_convex_decomposition_p4.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split1.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split1.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split1.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split1.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split10.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split10.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split10.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split10.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split11.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split11.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split11.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split11.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split12.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split12.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split12.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split12.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split13.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split13.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split13.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split13.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split14.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split14.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split14.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split14.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split15.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split15.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split15.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split15.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split16.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split16.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split16.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split16.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split17.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split17.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split17.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split17.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split18.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split18.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split18.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split18.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split2.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split2.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split2.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split2.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split3.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split3.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split3.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split3.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split4.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split4.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split4.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split4.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split5.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split5.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split5.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split5.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split6.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split6.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split6.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split6.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split7.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split7.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split7.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split7.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split8.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split8.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split8.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split8.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split9.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split9.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/cup_split9.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/cup_split9.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/elbow_link_convex.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/elbow_link_convex.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/elbow_link_convex.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/elbow_link_convex.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/elbow_link_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/elbow_link_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/elbow_link_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/elbow_link_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_convex_decomposition_p1.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_convex_decomposition_p1.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_convex_decomposition_p1.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_convex_decomposition_p1.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_convex_decomposition_p2.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_convex_decomposition_p2.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_convex_decomposition_p2.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_convex_decomposition_p2.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/forearm_link_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p1.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p1.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p1.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p1.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p2.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p2.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p2.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p2.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p3.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p3.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p3.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_convex_decomposition_p3.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/shoulder_link_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/shoulder_pitch_link_convex.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/shoulder_pitch_link_convex.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/shoulder_pitch_link_convex.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/shoulder_pitch_link_convex.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/shoulder_pitch_link_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/shoulder_pitch_link_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/shoulder_pitch_link_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/shoulder_pitch_link_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_convex_decomposition_p1.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_convex_decomposition_p1.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_convex_decomposition_p1.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_convex_decomposition_p1.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_convex_decomposition_p2.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_convex_decomposition_p2.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_convex_decomposition_p2.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_convex_decomposition_p2.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/upper_arm_link_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_palm_link_convex.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_palm_link_convex.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_palm_link_convex.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_palm_link_convex.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_palm_link_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_palm_link_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_palm_link_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_palm_link_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p1.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p1.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p1.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p1.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p2.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p2.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p2.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p2.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p3.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p3.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p3.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_convex_decomposition_p3.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_pitch_link_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_convex_decomposition_p1.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_convex_decomposition_p1.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_convex_decomposition_p1.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_convex_decomposition_p1.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_convex_decomposition_p2.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_convex_decomposition_p2.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_convex_decomposition_p2.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_convex_decomposition_p2.stl diff --git a/alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_fine.stl b/fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_fine.stl similarity index 100% rename from alr_envs/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_fine.stl rename to fancy_gym/envs/mujoco/beerpong/assets/meshes/wam/wrist_yaw_link_fine.stl diff --git a/alr_envs/envs/mujoco/beerpong/beerpong.py b/fancy_gym/envs/mujoco/beerpong/beerpong.py similarity index 94% rename from alr_envs/envs/mujoco/beerpong/beerpong.py rename to fancy_gym/envs/mujoco/beerpong/beerpong.py index bacdd4d..9fcfdd8 100644 --- a/alr_envs/envs/mujoco/beerpong/beerpong.py +++ b/fancy_gym/envs/mujoco/beerpong/beerpong.py @@ -32,13 +32,12 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): def __init__(self): self._steps = 0 # Small Context -> Easier. Todo: Should we do different versions? - # self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", - # "beerpong_wo_cup" + ".xml") + # self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", "beerpong_wo_cup.xml") # self._cup_pos_min = np.array([-0.32, -2.2]) # self._cup_pos_max = np.array([0.32, -1.2]) self.xml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets", - "beerpong_wo_cup_big_table" + ".xml") + "beerpong_wo_cup_big_table.xml") self._cup_pos_min = np.array([-1.42, -4.05]) self._cup_pos_max = np.array([1.42, -1.25]) @@ -127,7 +126,7 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): if not crash: reward, reward_infos = self._get_reward(applied_action) - is_collided = reward_infos['is_collided'] # TODO: Remove if self collision does not make a difference + is_collided = reward_infos['is_collided'] # TODO: Remove if self collision does not make a difference done = is_collided self._steps += 1 else: @@ -182,7 +181,7 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): # Is this needed? # self._is_collided = self._check_collision_with_itself([self.geom_id(name) for name in CUP_COLLISION_OBJ]) - if self._steps == MAX_EPISODE_STEPS_BEERPONG-1: # or self._is_collided: + if self._steps == MAX_EPISODE_STEPS_BEERPONG - 1: # or self._is_collided: min_dist = np.min(self.dists) final_dist = self.dists_final[-1] if self.ball_ground_contact_first: @@ -218,7 +217,7 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): return reward, infos def _check_contacts(self): - #TODO proper contact detection using sensors? + # TODO proper contact detection using sensors? if not self.ball_table_contact: self.ball_table_contact = self._check_collision({self.geom_id("ball_geom")}, {self.geom_id("table_contact_geom")}) @@ -237,9 +236,9 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): self.ball_ground_contact_first = self._check_collision({self.geom_id("ball_geom")}, {self.geom_id("ground")}) - # Checks if id_set1 has a collision with id_set2 - def _check_collision(self, id_set_1, id_set_2): + def _check_collision(self, id_set_1, id_set_2=None): """ + Checks if id_set1 has a collision with id_set2. If id_set_2 is set to None, it will check for a collision with itself (id_set_1). """ collision_id_set = id_set_2 - id_set_1 if id_set_2 is not None else id_set_1 @@ -279,19 +278,19 @@ class BeerPongEnvStepBasedEpisodicReward(BeerPongEnv): return ob, reward, done, infos -# class ALRBeerBongEnvStepBased(ALRBeerBongEnv): +# class BeerBongEnvStepBased(BeerBongEnv): # def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): # super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) # self.release_step = 62 # empirically evaluated for frame_skip=2! # # def step(self, a): # if self._steps < self.release_step: -# return super(ALRBeerBongEnvStepBased, self).step(a) +# return super(BeerBongEnvStepBased, self).step(a) # else: # reward = 0 # done = False # while not done: -# sub_ob, sub_reward, done, sub_infos = super(ALRBeerBongEnvStepBased, self).step(np.zeros(a.shape)) +# sub_ob, sub_reward, done, sub_infos = super(BeerBongEnvStepBased, self).step(np.zeros(a.shape)) # if not done or sub_infos['sim_crash']: # reward += sub_reward # else: @@ -315,9 +314,9 @@ class BeerPongEnvStepBasedEpisodicReward(BeerPongEnv): if __name__ == "__main__": env = BeerPongEnv() env.seed(0) - # env = ALRBeerBongEnvStepBased(frame_skip=2) - # env = ALRBeerBongEnvStepBasedEpisodicReward(frame_skip=2) - # env = ALRBeerBongEnvFixedReleaseStep(frame_skip=2) + # env = BeerBongEnvStepBased(frame_skip=2) + # env = BeerBongEnvStepBasedEpisodicReward(frame_skip=2) + # env = BeerBongEnvFixedReleaseStep(frame_skip=2) import time env.reset() diff --git a/alr_envs/envs/classic_control/base_reacher/__init__.py b/fancy_gym/envs/mujoco/beerpong/deprecated/__init__.py similarity index 100% rename from alr_envs/envs/classic_control/base_reacher/__init__.py rename to fancy_gym/envs/mujoco/beerpong/deprecated/__init__.py diff --git a/alr_envs/envs/mujoco/beerpong/deprecated/beerpong.py b/fancy_gym/envs/mujoco/beerpong/deprecated/beerpong.py similarity index 94% rename from alr_envs/envs/mujoco/beerpong/deprecated/beerpong.py rename to fancy_gym/envs/mujoco/beerpong/deprecated/beerpong.py index 9006842..015e887 100644 --- a/alr_envs/envs/mujoco/beerpong/deprecated/beerpong.py +++ b/fancy_gym/envs/mujoco/beerpong/deprecated/beerpong.py @@ -5,7 +5,7 @@ import numpy as np from gym import utils from gym.envs.mujoco import MujocoEnv -from alr_envs.envs.mujoco.beerpong.deprecated.beerpong_reward_staged import BeerPongReward +from fancy_gym.envs.mujoco.beerpong.deprecated.beerpong_reward_staged import BeerPongReward class BeerPongEnv(MujocoEnv, utils.EzPickle): @@ -155,19 +155,19 @@ class BeerPongEnvStepBasedEpisodicReward(BeerPongEnv): return ob, reward, done, infos -# class BeerBongEnvStepBased(ALRBeerBongEnv): +# class BeerBongEnvStepBased(BeerBongEnv): # def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): # super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) # self.release_step = 62 # empirically evaluated for frame_skip=2! # # def step(self, a): # if self._steps < self.release_step: -# return super(ALRBeerBongEnvStepBased, self).step(a) +# return super(BeerBongEnvStepBased, self).step(a) # else: # reward = 0 # done = False # while not done: -# sub_ob, sub_reward, done, sub_infos = super(ALRBeerBongEnvStepBased, self).step(np.zeros(a.shape)) +# sub_ob, sub_reward, done, sub_infos = super(BeerBongEnvStepBased, self).step(np.zeros(a.shape)) # if not done or sub_infos['sim_crash']: # reward += sub_reward # else: @@ -191,9 +191,9 @@ class BeerPongEnvStepBasedEpisodicReward(BeerPongEnv): if __name__ == "__main__": env = BeerPongEnv(frame_skip=2) env.seed(0) - # env = ALRBeerBongEnvStepBased(frame_skip=2) - # env = ALRBeerBongEnvStepBasedEpisodicReward(frame_skip=2) - # env = ALRBeerBongEnvFixedReleaseStep(frame_skip=2) + # env = BeerBongEnvStepBased(frame_skip=2) + # env = BeerBongEnvStepBasedEpisodicReward(frame_skip=2) + # env = BeerBongEnvFixedReleaseStep(frame_skip=2) import time env.reset() diff --git a/alr_envs/envs/mujoco/beerpong/deprecated/beerpong_reward_staged.py b/fancy_gym/envs/mujoco/beerpong/deprecated/beerpong_reward_staged.py similarity index 100% rename from alr_envs/envs/mujoco/beerpong/deprecated/beerpong_reward_staged.py rename to fancy_gym/envs/mujoco/beerpong/deprecated/beerpong_reward_staged.py diff --git a/alr_envs/envs/mujoco/beerpong/mp_wrapper.py b/fancy_gym/envs/mujoco/beerpong/mp_wrapper.py similarity index 94% rename from alr_envs/envs/mujoco/beerpong/mp_wrapper.py rename to fancy_gym/envs/mujoco/beerpong/mp_wrapper.py index c4a83de..b5e6687 100644 --- a/alr_envs/envs/mujoco/beerpong/mp_wrapper.py +++ b/fancy_gym/envs/mujoco/beerpong/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Union, Tuple import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/envs/mujoco/half_cheetah_jump/__init__.py b/fancy_gym/envs/mujoco/half_cheetah_jump/__init__.py similarity index 100% rename from alr_envs/envs/mujoco/half_cheetah_jump/__init__.py rename to fancy_gym/envs/mujoco/half_cheetah_jump/__init__.py diff --git a/alr_envs/envs/mujoco/half_cheetah_jump/assets/cheetah.xml b/fancy_gym/envs/mujoco/half_cheetah_jump/assets/cheetah.xml similarity index 100% rename from alr_envs/envs/mujoco/half_cheetah_jump/assets/cheetah.xml rename to fancy_gym/envs/mujoco/half_cheetah_jump/assets/cheetah.xml diff --git a/alr_envs/envs/mujoco/half_cheetah_jump/half_cheetah_jump.py b/fancy_gym/envs/mujoco/half_cheetah_jump/half_cheetah_jump.py similarity index 98% rename from alr_envs/envs/mujoco/half_cheetah_jump/half_cheetah_jump.py rename to fancy_gym/envs/mujoco/half_cheetah_jump/half_cheetah_jump.py index 3d948ac..e0a5982 100644 --- a/alr_envs/envs/mujoco/half_cheetah_jump/half_cheetah_jump.py +++ b/fancy_gym/envs/mujoco/half_cheetah_jump/half_cheetah_jump.py @@ -1,16 +1,16 @@ import os from typing import Tuple, Union, Optional +import numpy as np from gym.core import ObsType from gym.envs.mujoco.half_cheetah_v4 import HalfCheetahEnv -import numpy as np MAX_EPISODE_STEPS_HALFCHEETAHJUMP = 100 class HalfCheetahJumpEnv(HalfCheetahEnv): """ - ctrl_cost_weight 0.1 -> 0.0 + _ctrl_cost_weight 0.1 -> 0.0 """ def __init__(self, diff --git a/alr_envs/envs/mujoco/half_cheetah_jump/mp_wrapper.py b/fancy_gym/envs/mujoco/half_cheetah_jump/mp_wrapper.py similarity index 86% rename from alr_envs/envs/mujoco/half_cheetah_jump/mp_wrapper.py rename to fancy_gym/envs/mujoco/half_cheetah_jump/mp_wrapper.py index 9681b3a..11b169b 100644 --- a/alr_envs/envs/mujoco/half_cheetah_jump/mp_wrapper.py +++ b/fancy_gym/envs/mujoco/half_cheetah_jump/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/envs/mujoco/hopper_jump/__init__.py b/fancy_gym/envs/mujoco/hopper_jump/__init__.py similarity index 100% rename from alr_envs/envs/mujoco/hopper_jump/__init__.py rename to fancy_gym/envs/mujoco/hopper_jump/__init__.py diff --git a/alr_envs/envs/mujoco/hopper_jump/assets/hopper_jump.xml b/fancy_gym/envs/mujoco/hopper_jump/assets/hopper_jump.xml similarity index 100% rename from alr_envs/envs/mujoco/hopper_jump/assets/hopper_jump.xml rename to fancy_gym/envs/mujoco/hopper_jump/assets/hopper_jump.xml diff --git a/alr_envs/envs/mujoco/hopper_jump/assets/hopper_jump_on_box.xml b/fancy_gym/envs/mujoco/hopper_jump/assets/hopper_jump_on_box.xml similarity index 100% rename from alr_envs/envs/mujoco/hopper_jump/assets/hopper_jump_on_box.xml rename to fancy_gym/envs/mujoco/hopper_jump/assets/hopper_jump_on_box.xml diff --git a/alr_envs/envs/mujoco/hopper_jump/hopper_jump.py b/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py similarity index 98% rename from alr_envs/envs/mujoco/hopper_jump/hopper_jump.py rename to fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py index 5a334a2..329ea89 100644 --- a/alr_envs/envs/mujoco/hopper_jump/hopper_jump.py +++ b/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py @@ -1,8 +1,8 @@ -import copy import os import numpy as np from gym.envs.mujoco.hopper_v4 import HopperEnv + MAX_EPISODE_STEPS_HOPPERJUMP = 250 @@ -111,7 +111,7 @@ class HopperJumpEnv(HopperEnv): goal=self.goal[:1], goal_dist=goal_dist, height_rew=self.max_height, - healthy_reward=self.healthy_reward * 2, + healthy_reward=self.healthy_reward, healthy=self.is_healthy, contact_dist=self.contact_dist or 0 ) @@ -132,14 +132,11 @@ class HopperJumpEnv(HopperEnv): self.max_height = 0 self._steps = 0 - noise_low = -np.zeros(self.model.nq) + noise_low = np.zeros(self.model.nq) noise_low[3] = -0.5 noise_low[4] = -0.2 - noise_low[5] = 0 noise_high = np.zeros(self.model.nq) - noise_high[3] = 0 - noise_high[4] = 0 noise_high[5] = 0.785 qpos = ( @@ -159,6 +156,8 @@ class HopperJumpEnv(HopperEnv): self.init_floor_contact = False self.contact_dist = None + self.data.geom() + return observation def _is_floor_foot_contact(self): diff --git a/alr_envs/envs/mujoco/hopper_jump/hopper_jump_on_box.py b/fancy_gym/envs/mujoco/hopper_jump/hopper_jump_on_box.py similarity index 99% rename from alr_envs/envs/mujoco/hopper_jump/hopper_jump_on_box.py rename to fancy_gym/envs/mujoco/hopper_jump/hopper_jump_on_box.py index e184723..f9834bd 100644 --- a/alr_envs/envs/mujoco/hopper_jump/hopper_jump_on_box.py +++ b/fancy_gym/envs/mujoco/hopper_jump/hopper_jump_on_box.py @@ -1,7 +1,7 @@ -from gym.envs.mujoco.hopper_v4 import HopperEnv +import os import numpy as np -import os +from gym.envs.mujoco.hopper_v4 import HopperEnv MAX_EPISODE_STEPS_HOPPERJUMPONBOX = 250 diff --git a/alr_envs/envs/mujoco/hopper_jump/mp_wrapper.py b/fancy_gym/envs/mujoco/hopper_jump/mp_wrapper.py similarity index 90% rename from alr_envs/envs/mujoco/hopper_jump/mp_wrapper.py rename to fancy_gym/envs/mujoco/hopper_jump/mp_wrapper.py index 0f5e8a8..d46fa92 100644 --- a/alr_envs/envs/mujoco/hopper_jump/mp_wrapper.py +++ b/fancy_gym/envs/mujoco/hopper_jump/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Union, Tuple import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/envs/mujoco/hopper_throw/__init__.py b/fancy_gym/envs/mujoco/hopper_throw/__init__.py similarity index 100% rename from alr_envs/envs/mujoco/hopper_throw/__init__.py rename to fancy_gym/envs/mujoco/hopper_throw/__init__.py diff --git a/alr_envs/envs/mujoco/hopper_throw/assets/hopper_throw.xml b/fancy_gym/envs/mujoco/hopper_throw/assets/hopper_throw.xml similarity index 100% rename from alr_envs/envs/mujoco/hopper_throw/assets/hopper_throw.xml rename to fancy_gym/envs/mujoco/hopper_throw/assets/hopper_throw.xml diff --git a/alr_envs/envs/mujoco/hopper_throw/assets/hopper_throw_in_basket.xml b/fancy_gym/envs/mujoco/hopper_throw/assets/hopper_throw_in_basket.xml similarity index 100% rename from alr_envs/envs/mujoco/hopper_throw/assets/hopper_throw_in_basket.xml rename to fancy_gym/envs/mujoco/hopper_throw/assets/hopper_throw_in_basket.xml diff --git a/alr_envs/envs/mujoco/hopper_throw/hopper_throw.py b/fancy_gym/envs/mujoco/hopper_throw/hopper_throw.py similarity index 100% rename from alr_envs/envs/mujoco/hopper_throw/hopper_throw.py rename to fancy_gym/envs/mujoco/hopper_throw/hopper_throw.py index 3b2ce46..e69cea6 100644 --- a/alr_envs/envs/mujoco/hopper_throw/hopper_throw.py +++ b/fancy_gym/envs/mujoco/hopper_throw/hopper_throw.py @@ -1,8 +1,8 @@ import os from typing import Optional -from gym.envs.mujoco.hopper_v4 import HopperEnv import numpy as np +from gym.envs.mujoco.hopper_v4 import HopperEnv MAX_EPISODE_STEPS_HOPPERTHROW = 250 diff --git a/alr_envs/envs/mujoco/hopper_throw/hopper_throw_in_basket.py b/fancy_gym/envs/mujoco/hopper_throw/hopper_throw_in_basket.py similarity index 99% rename from alr_envs/envs/mujoco/hopper_throw/hopper_throw_in_basket.py rename to fancy_gym/envs/mujoco/hopper_throw/hopper_throw_in_basket.py index fb46809..76ef861 100644 --- a/alr_envs/envs/mujoco/hopper_throw/hopper_throw_in_basket.py +++ b/fancy_gym/envs/mujoco/hopper_throw/hopper_throw_in_basket.py @@ -1,9 +1,8 @@ import os from typing import Optional -from gym.envs.mujoco.hopper_v4 import HopperEnv - import numpy as np +from gym.envs.mujoco.hopper_v4 import HopperEnv MAX_EPISODE_STEPS_HOPPERTHROWINBASKET = 250 diff --git a/alr_envs/envs/mujoco/hopper_throw/mp_wrapper.py b/fancy_gym/envs/mujoco/hopper_throw/mp_wrapper.py similarity index 86% rename from alr_envs/envs/mujoco/hopper_throw/mp_wrapper.py rename to fancy_gym/envs/mujoco/hopper_throw/mp_wrapper.py index 247668f..cad680a 100644 --- a/alr_envs/envs/mujoco/hopper_throw/mp_wrapper.py +++ b/fancy_gym/envs/mujoco/hopper_throw/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/envs/mujoco/reacher/__init__.py b/fancy_gym/envs/mujoco/reacher/__init__.py similarity index 100% rename from alr_envs/envs/mujoco/reacher/__init__.py rename to fancy_gym/envs/mujoco/reacher/__init__.py diff --git a/alr_envs/envs/mujoco/reacher/assets/reacher_5links.xml b/fancy_gym/envs/mujoco/reacher/assets/reacher_5links.xml similarity index 100% rename from alr_envs/envs/mujoco/reacher/assets/reacher_5links.xml rename to fancy_gym/envs/mujoco/reacher/assets/reacher_5links.xml diff --git a/alr_envs/envs/mujoco/reacher/assets/reacher_7links.xml b/fancy_gym/envs/mujoco/reacher/assets/reacher_7links.xml similarity index 100% rename from alr_envs/envs/mujoco/reacher/assets/reacher_7links.xml rename to fancy_gym/envs/mujoco/reacher/assets/reacher_7links.xml diff --git a/alr_envs/envs/mujoco/reacher/mp_wrapper.py b/fancy_gym/envs/mujoco/reacher/mp_wrapper.py similarity index 90% rename from alr_envs/envs/mujoco/reacher/mp_wrapper.py rename to fancy_gym/envs/mujoco/reacher/mp_wrapper.py index 1c1e2f1..0464640 100644 --- a/alr_envs/envs/mujoco/reacher/mp_wrapper.py +++ b/fancy_gym/envs/mujoco/reacher/mp_wrapper.py @@ -1,9 +1,8 @@ from typing import Union, Tuple -import gym import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/envs/mujoco/reacher/reacher.py b/fancy_gym/envs/mujoco/reacher/reacher.py similarity index 88% rename from alr_envs/envs/mujoco/reacher/reacher.py rename to fancy_gym/envs/mujoco/reacher/reacher.py index 3d52be7..ccd0073 100644 --- a/alr_envs/envs/mujoco/reacher/reacher.py +++ b/fancy_gym/envs/mujoco/reacher/reacher.py @@ -4,22 +4,24 @@ import numpy as np from gym import utils from gym.envs.mujoco import MujocoEnv +MAX_EPISODE_STEPS_REACHER = 200 + class ReacherEnv(MujocoEnv, utils.EzPickle): """ More general version of the gym mujoco Reacher environment """ - def __init__(self, sparse: bool = False, n_links: int = 5, ctrl_cost_weight: int = 1): + def __init__(self, sparse: bool = False, n_links: int = 5, reward_weight: float = 1, ctrl_cost_weight: float = 1): utils.EzPickle.__init__(**locals()) self._steps = 0 self.n_links = n_links - self.ctrl_cost_weight = ctrl_cost_weight - self.sparse = sparse - self.reward_weight = 1 if not sparse else 200 + + self._ctrl_cost_weight = ctrl_cost_weight + self._reward_weight = reward_weight file_name = f'reacher_{n_links}links.xml' @@ -31,7 +33,7 @@ class ReacherEnv(MujocoEnv, utils.EzPickle): def step(self, action): self._steps += 1 - is_reward = not self.sparse or (self.sparse and self._steps == 200) + is_reward = not self.sparse or (self.sparse and self._steps == MAX_EPISODE_STEPS_REACHER) reward_dist = 0.0 angular_vel = 0.0 @@ -39,7 +41,7 @@ class ReacherEnv(MujocoEnv, utils.EzPickle): reward_dist = self.distance_reward() angular_vel = self.velocity_reward() - reward_ctrl = -self.ctrl_cost_weight * np.square(action).sum() + reward_ctrl = -self._ctrl_cost_weight * np.square(action).sum() reward = reward_dist + reward_ctrl + angular_vel self.do_simulation(action, self.frame_skip) @@ -58,7 +60,7 @@ class ReacherEnv(MujocoEnv, utils.EzPickle): def distance_reward(self): vec = self.get_body_com("fingertip") - self.get_body_com("target") - return -self.reward_weight * np.linalg.norm(vec) + return -self._reward_weight * np.linalg.norm(vec) def velocity_reward(self): return -10 * np.square(self.data.qvel.flat[:self.n_links]).sum() if self.sparse else 0.0 diff --git a/alr_envs/envs/mujoco/walker_2d_jump/__init__.py b/fancy_gym/envs/mujoco/walker_2d_jump/__init__.py similarity index 100% rename from alr_envs/envs/mujoco/walker_2d_jump/__init__.py rename to fancy_gym/envs/mujoco/walker_2d_jump/__init__.py diff --git a/alr_envs/envs/mujoco/walker_2d_jump/assets/walker2d.xml b/fancy_gym/envs/mujoco/walker_2d_jump/assets/walker2d.xml similarity index 100% rename from alr_envs/envs/mujoco/walker_2d_jump/assets/walker2d.xml rename to fancy_gym/envs/mujoco/walker_2d_jump/assets/walker2d.xml diff --git a/alr_envs/envs/mujoco/walker_2d_jump/mp_wrapper.py b/fancy_gym/envs/mujoco/walker_2d_jump/mp_wrapper.py similarity index 86% rename from alr_envs/envs/mujoco/walker_2d_jump/mp_wrapper.py rename to fancy_gym/envs/mujoco/walker_2d_jump/mp_wrapper.py index f91d494..d55e9d2 100644 --- a/alr_envs/envs/mujoco/walker_2d_jump/mp_wrapper.py +++ b/fancy_gym/envs/mujoco/walker_2d_jump/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/envs/mujoco/walker_2d_jump/walker_2d_jump.py b/fancy_gym/envs/mujoco/walker_2d_jump/walker_2d_jump.py similarity index 100% rename from alr_envs/envs/mujoco/walker_2d_jump/walker_2d_jump.py rename to fancy_gym/envs/mujoco/walker_2d_jump/walker_2d_jump.py index dadf8fd..ed663d2 100644 --- a/alr_envs/envs/mujoco/walker_2d_jump/walker_2d_jump.py +++ b/fancy_gym/envs/mujoco/walker_2d_jump/walker_2d_jump.py @@ -1,8 +1,8 @@ import os from typing import Optional -from gym.envs.mujoco.walker2d_v4 import Walker2dEnv import numpy as np +from gym.envs.mujoco.walker2d_v4 import Walker2dEnv MAX_EPISODE_STEPS_WALKERJUMP = 300 diff --git a/alr_envs/envs/mujoco/beerpong/deprecated/__init__.py b/fancy_gym/examples/__init__.py similarity index 100% rename from alr_envs/envs/mujoco/beerpong/deprecated/__init__.py rename to fancy_gym/examples/__init__.py diff --git a/alr_envs/examples/examples_dmc.py b/fancy_gym/examples/examples_dmc.py similarity index 87% rename from alr_envs/examples/examples_dmc.py rename to fancy_gym/examples/examples_dmc.py index 2d2c8fe..75648b7 100644 --- a/alr_envs/examples/examples_dmc.py +++ b/fancy_gym/examples/examples_dmc.py @@ -1,4 +1,4 @@ -import alr_envs +import fancy_gym def example_dmc(env_id="dmc:fish-swim", seed=1, iterations=1000, render=True): @@ -16,7 +16,7 @@ def example_dmc(env_id="dmc:fish-swim", seed=1, iterations=1000, render=True): Returns: """ - env = alr_envs.make(env_id, seed) + env = fancy_gym.make(env_id, seed) rewards = 0 obs = env.reset() print("observation shape:", env.observation_space.shape) @@ -40,12 +40,12 @@ def example_dmc(env_id="dmc:fish-swim", seed=1, iterations=1000, render=True): def example_custom_dmc_and_mp(seed=1, iterations=1, render=True): """ - Example for running a custom motion primitive based environments. + Example for running a custom movement primitive based environments. Our already registered environments follow the same structure. - Hence, this also allows to adjust hyperparameters of the motion primitives. + Hence, this also allows to adjust hyperparameters of the movement primitives. Yet, we recommend the method above if you are just interested in chaining those parameters for existing tasks. We appreciate PRs for custom environments (especially MP wrappers of existing tasks) - for our repo: https://github.com/ALRhub/alr_envs/ + for our repo: https://github.com/ALRhub/fancy_gym/ Args: seed: seed for deterministic behaviour iterations: Number of rollout steps to run @@ -60,7 +60,7 @@ def example_custom_dmc_and_mp(seed=1, iterations=1, render=True): # Replace this wrapper with the custom wrapper for your environment by inheriting from the RawInterfaceWrapper. # You can also add other gym.Wrappers in case they are needed. - wrappers = [alr_envs.dmc.suite.ball_in_cup.MPWrapper] + wrappers = [fancy_gym.dmc.suite.ball_in_cup.MPWrapper] # # For a ProMP trajectory_generator_kwargs = {'trajectory_generator_type': 'promp'} phase_generator_kwargs = {'phase_generator_type': 'linear'} @@ -83,10 +83,10 @@ def example_custom_dmc_and_mp(seed=1, iterations=1, render=True): # basis_generator_kwargs = {'basis_generator_type': 'rbf', # 'num_basis': 5 # } - env = alr_envs.make_bb(env_id=base_env_id, wrappers=wrappers, black_box_kwargs={}, - traj_gen_kwargs=trajectory_generator_kwargs, controller_kwargs=controller_kwargs, - phase_kwargs=phase_generator_kwargs, basis_kwargs=basis_generator_kwargs, - seed=seed) + env = fancy_gym.make_bb(env_id=base_env_id, wrappers=wrappers, black_box_kwargs={}, + traj_gen_kwargs=trajectory_generator_kwargs, controller_kwargs=controller_kwargs, + phase_kwargs=phase_generator_kwargs, basis_kwargs=basis_generator_kwargs, + seed=seed) # This renders the full MP trajectory # It is only required to call render() once in the beginning, which renders every consecutive trajectory. diff --git a/alr_envs/examples/examples_general.py b/fancy_gym/examples/examples_general.py similarity index 95% rename from alr_envs/examples/examples_general.py rename to fancy_gym/examples/examples_general.py index 33c2740..1a89e30 100644 --- a/alr_envs/examples/examples_general.py +++ b/fancy_gym/examples/examples_general.py @@ -3,7 +3,7 @@ from collections import defaultdict import gym import numpy as np -import alr_envs +import fancy_gym def example_general(env_id="Pendulum-v1", seed=1, iterations=1000, render=True): @@ -21,7 +21,7 @@ def example_general(env_id="Pendulum-v1", seed=1, iterations=1000, render=True): """ - env = alr_envs.make(env_id, seed) + env = fancy_gym.make(env_id, seed) rewards = 0 obs = env.reset() print("Observation shape: ", env.observation_space.shape) @@ -56,7 +56,7 @@ def example_async(env_id="HoleReacher-v0", n_cpu=4, seed=int('533D', 16), n_samp Returns: Tuple of (obs, reward, done, info) with type np.ndarray """ - env = gym.vector.AsyncVectorEnv([alr_envs.make_rank(env_id, seed, i) for i in range(n_cpu)]) + env = gym.vector.AsyncVectorEnv([fancy_gym.make_rank(env_id, seed, i) for i in range(n_cpu)]) # OR # envs = gym.vector.AsyncVectorEnv([make_env(env_id, seed + i) for i in range(n_cpu)]) diff --git a/alr_envs/examples/examples_metaworld.py b/fancy_gym/examples/examples_metaworld.py similarity index 88% rename from alr_envs/examples/examples_metaworld.py rename to fancy_gym/examples/examples_metaworld.py index aa6820e..0fa7066 100644 --- a/alr_envs/examples/examples_metaworld.py +++ b/fancy_gym/examples/examples_metaworld.py @@ -1,4 +1,4 @@ -import alr_envs +import fancy_gym def example_dmc(env_id="fish-swim", seed=1, iterations=1000, render=True): @@ -17,7 +17,7 @@ def example_dmc(env_id="fish-swim", seed=1, iterations=1000, render=True): Returns: """ - env = alr_envs.make(env_id, seed) + env = fancy_gym.make(env_id, seed) rewards = 0 obs = env.reset() print("observation shape:", env.observation_space.shape) @@ -42,12 +42,12 @@ def example_dmc(env_id="fish-swim", seed=1, iterations=1000, render=True): def example_custom_dmc_and_mp(seed=1, iterations=1, render=True): """ - Example for running a custom motion primitive based environments. + Example for running a custom movement primitive based environments. Our already registered environments follow the same structure. - Hence, this also allows to adjust hyperparameters of the motion primitives. + Hence, this also allows to adjust hyperparameters of the movement primitives. Yet, we recommend the method above if you are just interested in chaining those parameters for existing tasks. We appreciate PRs for custom environments (especially MP wrappers of existing tasks) - for our repo: https://github.com/ALRhub/alr_envs/ + for our repo: https://github.com/ALRhub/fancy_gym/ Args: seed: seed for deterministic behaviour (TODO: currently not working due to an issue in MetaWorld code) iterations: Number of rollout steps to run @@ -62,7 +62,7 @@ def example_custom_dmc_and_mp(seed=1, iterations=1, render=True): # Replace this wrapper with the custom wrapper for your environment by inheriting from the RawInterfaceWrapper. # You can also add other gym.Wrappers in case they are needed. - wrappers = [alr_envs.meta.goal_object_change_mp_wrapper.MPWrapper] + wrappers = [fancy_gym.meta.goal_object_change_mp_wrapper.MPWrapper] # # For a ProMP # trajectory_generator_kwargs = {'trajectory_generator_type': 'promp'} # phase_generator_kwargs = {'phase_generator_type': 'linear'} @@ -80,10 +80,10 @@ def example_custom_dmc_and_mp(seed=1, iterations=1, render=True): basis_generator_kwargs = {'basis_generator_type': 'rbf', 'num_basis': 5 } - env = alr_envs.make_bb(env_id=base_env_id, wrappers=wrappers, black_box_kwargs={}, - traj_gen_kwargs=trajectory_generator_kwargs, controller_kwargs=controller_kwargs, - phase_kwargs=phase_generator_kwargs, basis_kwargs=basis_generator_kwargs, - seed=seed) + env = fancy_gym.make_bb(env_id=base_env_id, wrappers=wrappers, black_box_kwargs={}, + traj_gen_kwargs=trajectory_generator_kwargs, controller_kwargs=controller_kwargs, + phase_kwargs=phase_generator_kwargs, basis_kwargs=basis_generator_kwargs, + seed=seed) # This renders the full MP trajectory # It is only required to call render() once in the beginning, which renders every consecutive trajectory. diff --git a/alr_envs/examples/examples_movement_primitives.py b/fancy_gym/examples/examples_movement_primitives.py similarity index 86% rename from alr_envs/examples/examples_movement_primitives.py rename to fancy_gym/examples/examples_movement_primitives.py index 49b4ee0..22e95ac 100644 --- a/alr_envs/examples/examples_movement_primitives.py +++ b/fancy_gym/examples/examples_movement_primitives.py @@ -1,4 +1,4 @@ -import alr_envs +import fancy_gym def example_mp(env_name="HoleReacherProMP-v0", seed=1, iterations=1, render=True): @@ -15,7 +15,7 @@ def example_mp(env_name="HoleReacherProMP-v0", seed=1, iterations=1, render=True """ # Equivalent to gym, we have a make function which can be used to create environments. # It takes care of seeding and enables the use of a variety of external environments using the gym interface. - env = alr_envs.make(env_name, seed) + env = fancy_gym.make(env_name, seed) returns = 0 # env.render(mode=None) @@ -52,7 +52,7 @@ def example_mp(env_name="HoleReacherProMP-v0", seed=1, iterations=1, render=True def example_custom_mp(env_name="Reacher5dProMP-v0", seed=1, iterations=1, render=True): """ - Example for running a motion primitive based environment, which is already registered + Example for running a movement primitive based environment, which is already registered Args: env_name: DMP env_id seed: seed for deterministic behaviour @@ -64,8 +64,8 @@ def example_custom_mp(env_name="Reacher5dProMP-v0", seed=1, iterations=1, render """ # Changing the arguments of the black box env is possible by providing them to gym as with all kwargs. # E.g. here for way to many basis functions - env = alr_envs.make(env_name, seed, basis_generator_kwargs={'num_basis': 1000}) - # env = alr_envs.make(env_name, seed) + env = fancy_gym.make(env_name, seed, basis_generator_kwargs={'num_basis': 1000}) + # env = fancy_gym.make(env_name, seed) # mp_dict.update({'black_box_kwargs': {'learn_sub_trajectories': True}}) # mp_dict.update({'black_box_kwargs': {'do_replanning': lambda pos, vel, t: lambda t: t % 100}}) @@ -91,12 +91,12 @@ def example_custom_mp(env_name="Reacher5dProMP-v0", seed=1, iterations=1, render def example_fully_custom_mp(seed=1, iterations=1, render=True): """ - Example for running a custom motion primitive based environments. + Example for running a custom movement primitive based environments. Our already registered environments follow the same structure. - Hence, this also allows to adjust hyperparameters of the motion primitives. + Hence, this also allows to adjust hyperparameters of the movement primitives. Yet, we recommend the method above if you are just interested in changing those parameters for existing tasks. We appreciate PRs for custom environments (especially MP wrappers of existing tasks) - for our repo: https://github.com/ALRhub/alr_envs/ + for our repo: https://github.com/ALRhub/fancy_gym/ Args: seed: seed iterations: Number of rollout steps to run @@ -110,7 +110,7 @@ def example_fully_custom_mp(seed=1, iterations=1, render=True): # Replace this wrapper with the custom wrapper for your environment by inheriting from the RawInterfaceWrapper. # You can also add other gym.Wrappers in case they are needed. - wrappers = [alr_envs.envs.classic_control.hole_reacher.MPWrapper] + wrappers = [fancy_gym.envs.classic_control.hole_reacher.MPWrapper] # # For a ProMP # trajectory_generator_kwargs = {'trajectory_generator_type': 'promp', @@ -131,10 +131,10 @@ def example_fully_custom_mp(seed=1, iterations=1, render=True): basis_generator_kwargs = {'basis_generator_type': 'rbf', 'num_basis': 5 } - env = alr_envs.make_bb(env_id=base_env_id, wrappers=wrappers, black_box_kwargs={}, - traj_gen_kwargs=trajectory_generator_kwargs, controller_kwargs=controller_kwargs, - phase_kwargs=phase_generator_kwargs, basis_kwargs=basis_generator_kwargs, - seed=seed) + env = fancy_gym.make_bb(env_id=base_env_id, wrappers=wrappers, black_box_kwargs={}, + traj_gen_kwargs=trajectory_generator_kwargs, controller_kwargs=controller_kwargs, + phase_kwargs=phase_generator_kwargs, basis_kwargs=basis_generator_kwargs, + seed=seed) if render: env.render(mode="human") diff --git a/alr_envs/examples/examples_open_ai.py b/fancy_gym/examples/examples_open_ai.py similarity index 74% rename from alr_envs/examples/examples_open_ai.py rename to fancy_gym/examples/examples_open_ai.py index fad3847..a4a162d 100644 --- a/alr_envs/examples/examples_open_ai.py +++ b/fancy_gym/examples/examples_open_ai.py @@ -1,10 +1,10 @@ -import alr_envs +import fancy_gym def example_mp(env_name, seed=1, render=True): """ - Example for running a motion primitive based version of a OpenAI-gym environment, which is already registered. - For more information on motion primitive specific stuff, look at the traj_gen examples. + Example for running a movement primitive based version of a OpenAI-gym environment, which is already registered. + For more information on movement primitive specific stuff, look at the traj_gen examples. Args: env_name: ProMP env_id seed: seed @@ -13,7 +13,7 @@ def example_mp(env_name, seed=1, render=True): """ # While in this case gym.make() is possible to use as well, we recommend our custom make env function. - env = alr_envs.make(env_name, seed) + env = fancy_gym.make(env_name, seed) returns = 0 obs = env.reset() diff --git a/alr_envs/examples/pd_control_gain_tuning.py b/fancy_gym/examples/pd_control_gain_tuning.py similarity index 94% rename from alr_envs/examples/pd_control_gain_tuning.py rename to fancy_gym/examples/pd_control_gain_tuning.py index 8a74e6a..407bfa1 100644 --- a/alr_envs/examples/pd_control_gain_tuning.py +++ b/fancy_gym/examples/pd_control_gain_tuning.py @@ -1,16 +1,17 @@ from collections import OrderedDict import numpy as np -import alr_envs from matplotlib import pyplot as plt +import fancy_gym + # This might work for some environments, however, please verify either way the correct trajectory information # for your environment are extracted below SEED = 1 env_id = "Reacher5dProMP-v0" -env = alr_envs.make(env_id, seed=SEED, controller_kwargs={'p_gains': 0.05, 'd_gains': 0.05}).env +env = fancy_gym.make(env_id, seed=SEED, controller_kwargs={'p_gains': 0.05, 'd_gains': 0.05}).env env.action_space.seed(SEED) # Plot difference between real trajectory and target MP trajectory diff --git a/alr_envs/meta/README.MD b/fancy_gym/meta/README.MD similarity index 100% rename from alr_envs/meta/README.MD rename to fancy_gym/meta/README.MD diff --git a/alr_envs/meta/__init__.py b/fancy_gym/meta/__init__.py similarity index 93% rename from alr_envs/meta/__init__.py rename to fancy_gym/meta/__init__.py index fcc87cc..04438f4 100644 --- a/alr_envs/meta/__init__.py +++ b/fancy_gym/meta/__init__.py @@ -40,7 +40,7 @@ for _task in _goal_change_envs: register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_goal_change_promp ) ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -55,7 +55,7 @@ for _task in _object_change_envs: kwargs_dict_object_change_promp['name'] = f'metaworld:{_task}' register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_object_change_promp ) ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -81,7 +81,7 @@ for _task in _goal_and_object_change_envs: register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_goal_and_object_change_promp ) ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) @@ -97,7 +97,7 @@ for _task in _goal_and_endeffector_change_envs: register( id=_env_id, - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_goal_and_endeffector_change_promp ) ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) diff --git a/alr_envs/meta/base_metaworld_mp_wrapper.py b/fancy_gym/meta/base_metaworld_mp_wrapper.py similarity index 90% rename from alr_envs/meta/base_metaworld_mp_wrapper.py rename to fancy_gym/meta/base_metaworld_mp_wrapper.py index d2af07d..ae800ff 100644 --- a/alr_envs/meta/base_metaworld_mp_wrapper.py +++ b/fancy_gym/meta/base_metaworld_mp_wrapper.py @@ -3,7 +3,7 @@ from typing import Tuple, Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class BaseMetaworldMPWrapper(RawInterfaceWrapper, ABC): diff --git a/alr_envs/meta/goal_change_mp_wrapper.py b/fancy_gym/meta/goal_change_mp_wrapper.py similarity index 94% rename from alr_envs/meta/goal_change_mp_wrapper.py rename to fancy_gym/meta/goal_change_mp_wrapper.py index 5580eae..a8eabb5 100644 --- a/alr_envs/meta/goal_change_mp_wrapper.py +++ b/fancy_gym/meta/goal_change_mp_wrapper.py @@ -1,6 +1,6 @@ import numpy as np -from alr_envs.meta.base_metaworld_mp_wrapper import BaseMetaworldMPWrapper +from fancy_gym.meta.base_metaworld_mp_wrapper import BaseMetaworldMPWrapper class MPWrapper(BaseMetaworldMPWrapper): @@ -10,8 +10,8 @@ class MPWrapper(BaseMetaworldMPWrapper): You can verify this by executing the code below for your environment id and check if the output is non-zero at the same indices. ```python - import alr_envs - env = alr_envs.make(env_id, 1) + import fancy_gym + env = fancy_gym.make(env_id, 1) print(env.reset() - env.reset()) array([ 0. , 0. , 0. , 0. , 0, 0 , 0 , 0. , 0. , 0. , diff --git a/alr_envs/meta/goal_endeffector_change_mp_wrapper.py b/fancy_gym/meta/goal_endeffector_change_mp_wrapper.py similarity index 94% rename from alr_envs/meta/goal_endeffector_change_mp_wrapper.py rename to fancy_gym/meta/goal_endeffector_change_mp_wrapper.py index baa5789..c299597 100644 --- a/alr_envs/meta/goal_endeffector_change_mp_wrapper.py +++ b/fancy_gym/meta/goal_endeffector_change_mp_wrapper.py @@ -1,6 +1,6 @@ import numpy as np -from alr_envs.meta.base_metaworld_mp_wrapper import BaseMetaworldMPWrapper +from fancy_gym.meta.base_metaworld_mp_wrapper import BaseMetaworldMPWrapper class MPWrapper(BaseMetaworldMPWrapper): @@ -10,8 +10,8 @@ class MPWrapper(BaseMetaworldMPWrapper): You can verify this by executing the code below for your environment id and check if the output is non-zero at the same indices. ```python - import alr_envs - env = alr_envs.make(env_id, 1) + import fancy_gym + env = fancy_gym.make(env_id, 1) print(env.reset() - env.reset()) array([ !=0 , !=0 , !=0 , 0. , 0., 0. , 0. , 0. , 0. , 0. , diff --git a/alr_envs/meta/goal_object_change_mp_wrapper.py b/fancy_gym/meta/goal_object_change_mp_wrapper.py similarity index 94% rename from alr_envs/meta/goal_object_change_mp_wrapper.py rename to fancy_gym/meta/goal_object_change_mp_wrapper.py index dcc0777..ae667a6 100644 --- a/alr_envs/meta/goal_object_change_mp_wrapper.py +++ b/fancy_gym/meta/goal_object_change_mp_wrapper.py @@ -1,6 +1,6 @@ import numpy as np -from alr_envs.meta.base_metaworld_mp_wrapper import BaseMetaworldMPWrapper +from fancy_gym.meta.base_metaworld_mp_wrapper import BaseMetaworldMPWrapper class MPWrapper(BaseMetaworldMPWrapper): @@ -10,8 +10,8 @@ class MPWrapper(BaseMetaworldMPWrapper): You can verify this by executing the code below for your environment id and check if the output is non-zero at the same indices. ```python - import alr_envs - env = alr_envs.make(env_id, 1) + import fancy_gym + env = fancy_gym.make(env_id, 1) print(env.reset() - env.reset()) array([ 0. , 0. , 0. , 0. , !=0, !=0 , !=0 , 0. , 0. , 0. , diff --git a/alr_envs/meta/object_change_mp_wrapper.py b/fancy_gym/meta/object_change_mp_wrapper.py similarity index 94% rename from alr_envs/meta/object_change_mp_wrapper.py rename to fancy_gym/meta/object_change_mp_wrapper.py index f2daec7..6faecc9 100644 --- a/alr_envs/meta/object_change_mp_wrapper.py +++ b/fancy_gym/meta/object_change_mp_wrapper.py @@ -1,6 +1,6 @@ import numpy as np -from alr_envs.meta.base_metaworld_mp_wrapper import BaseMetaworldMPWrapper +from fancy_gym.meta.base_metaworld_mp_wrapper import BaseMetaworldMPWrapper class MPWrapper(BaseMetaworldMPWrapper): @@ -10,8 +10,8 @@ class MPWrapper(BaseMetaworldMPWrapper): You can verify this by executing the code below for your environment id and check if the output is non-zero at the same indices. ```python - import alr_envs - env = alr_envs.make(env_id, 1) + import fancy_gym + env = fancy_gym.make(env_id, 1) print(env.reset() - env.reset()) array([ 0. , 0. , 0. , 0. , !=0 , !=0 , !=0 , 0. , 0. , 0. , diff --git a/alr_envs/open_ai/README.MD b/fancy_gym/open_ai/README.MD similarity index 100% rename from alr_envs/open_ai/README.MD rename to fancy_gym/open_ai/README.MD diff --git a/alr_envs/open_ai/__init__.py b/fancy_gym/open_ai/__init__.py similarity index 77% rename from alr_envs/open_ai/__init__.py rename to fancy_gym/open_ai/__init__.py index 4542aae..3e0b770 100644 --- a/alr_envs/open_ai/__init__.py +++ b/fancy_gym/open_ai/__init__.py @@ -1,10 +1,11 @@ -from gym import register from copy import deepcopy +from gym import register + from . import mujoco from .deprecated_needs_gym_robotics import robotics -ALL_GYM_MOTION_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": []} +ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": []} DEFAULT_BB_DICT_ProMP = { "name": 'EnvName', @@ -35,17 +36,17 @@ kwargs_dict_reacher_promp['name'] = "Reacher-v2" kwargs_dict_reacher_promp['wrappers'].append(mujoco.reacher_v2.MPWrapper) register( id='ReacherProMP-v2', - entry_point='alr_envs.utils.make_env_helpers:make_bb_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_reacher_promp ) -ALL_GYM_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ReacherProMP-v2") +ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ReacherProMP-v2") """ The Fetch environments are not supported by gym anymore. A new repository (gym_robotics) is supporting the environments. However, the usage and so on needs to be checked register( id='FetchSlideDenseProMP-v1', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_promp_env_helper', kwargs={ "name": "gym.envs.robotics:FetchSlideDense-v1", "wrappers": [FlattenObservation, robotics.fetch.MPWrapper], @@ -59,11 +60,11 @@ register( } } ) -ALL_GYM_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("FetchSlideDenseProMP-v1") +ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append("FetchSlideDenseProMP-v1") register( id='FetchSlideProMP-v1', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_promp_env_helper', kwargs={ "name": "gym.envs.robotics:FetchSlide-v1", "wrappers": [FlattenObservation, robotics.fetch.MPWrapper], @@ -77,11 +78,11 @@ register( } } ) -ALL_GYM_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("FetchSlideProMP-v1") +ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append("FetchSlideProMP-v1") register( id='FetchReachDenseProMP-v1', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_promp_env_helper', kwargs={ "name": "gym.envs.robotics:FetchReachDense-v1", "wrappers": [FlattenObservation, robotics.fetch.MPWrapper], @@ -95,11 +96,11 @@ register( } } ) -ALL_GYM_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("FetchReachDenseProMP-v1") +ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append("FetchReachDenseProMP-v1") register( id='FetchReachProMP-v1', - entry_point='alr_envs.utils.make_env_helpers:make_promp_env_helper', + entry_point='fancy_gym.utils.make_env_helpers:make_promp_env_helper', kwargs={ "name": "gym.envs.robotics:FetchReach-v1", "wrappers": [FlattenObservation, robotics.fetch.MPWrapper], @@ -113,5 +114,5 @@ register( } } ) -ALL_GYM_MOTION_PRIMITIVE_ENVIRONMENTS["ProMP"].append("FetchReachProMP-v1") +ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append("FetchReachProMP-v1") """ diff --git a/alr_envs/examples/__init__.py b/fancy_gym/open_ai/deprecated_needs_gym_robotics/__init__.py similarity index 100% rename from alr_envs/examples/__init__.py rename to fancy_gym/open_ai/deprecated_needs_gym_robotics/__init__.py diff --git a/alr_envs/open_ai/deprecated_needs_gym_robotics/robotics/__init__.py b/fancy_gym/open_ai/deprecated_needs_gym_robotics/robotics/__init__.py similarity index 100% rename from alr_envs/open_ai/deprecated_needs_gym_robotics/robotics/__init__.py rename to fancy_gym/open_ai/deprecated_needs_gym_robotics/robotics/__init__.py diff --git a/alr_envs/open_ai/deprecated_needs_gym_robotics/robotics/fetch/__init__.py b/fancy_gym/open_ai/deprecated_needs_gym_robotics/robotics/fetch/__init__.py similarity index 100% rename from alr_envs/open_ai/deprecated_needs_gym_robotics/robotics/fetch/__init__.py rename to fancy_gym/open_ai/deprecated_needs_gym_robotics/robotics/fetch/__init__.py diff --git a/alr_envs/open_ai/deprecated_needs_gym_robotics/robotics/fetch/mp_wrapper.py b/fancy_gym/open_ai/deprecated_needs_gym_robotics/robotics/fetch/mp_wrapper.py similarity index 96% rename from alr_envs/open_ai/deprecated_needs_gym_robotics/robotics/fetch/mp_wrapper.py rename to fancy_gym/open_ai/deprecated_needs_gym_robotics/robotics/fetch/mp_wrapper.py index 331aa40..e96698a 100644 --- a/alr_envs/open_ai/deprecated_needs_gym_robotics/robotics/fetch/mp_wrapper.py +++ b/fancy_gym/open_ai/deprecated_needs_gym_robotics/robotics/fetch/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/open_ai/mujoco/__init__.py b/fancy_gym/open_ai/mujoco/__init__.py similarity index 100% rename from alr_envs/open_ai/mujoco/__init__.py rename to fancy_gym/open_ai/mujoco/__init__.py diff --git a/alr_envs/open_ai/mujoco/reacher_v2/__init__.py b/fancy_gym/open_ai/mujoco/reacher_v2/__init__.py similarity index 100% rename from alr_envs/open_ai/mujoco/reacher_v2/__init__.py rename to fancy_gym/open_ai/mujoco/reacher_v2/__init__.py diff --git a/alr_envs/open_ai/mujoco/reacher_v2/mp_wrapper.py b/fancy_gym/open_ai/mujoco/reacher_v2/mp_wrapper.py similarity index 89% rename from alr_envs/open_ai/mujoco/reacher_v2/mp_wrapper.py rename to fancy_gym/open_ai/mujoco/reacher_v2/mp_wrapper.py index 5833f6c..b2fa04c 100644 --- a/alr_envs/open_ai/mujoco/reacher_v2/mp_wrapper.py +++ b/fancy_gym/open_ai/mujoco/reacher_v2/mp_wrapper.py @@ -2,7 +2,7 @@ from typing import Union import numpy as np -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper class MPWrapper(RawInterfaceWrapper): diff --git a/alr_envs/utils/__init__.py b/fancy_gym/utils/__init__.py similarity index 100% rename from alr_envs/utils/__init__.py rename to fancy_gym/utils/__init__.py diff --git a/alr_envs/utils/make_env_helpers.py b/fancy_gym/utils/make_env_helpers.py similarity index 94% rename from alr_envs/utils/make_env_helpers.py rename to fancy_gym/utils/make_env_helpers.py index f88cfcc..0f832ae 100644 --- a/alr_envs/utils/make_env_helpers.py +++ b/fancy_gym/utils/make_env_helpers.py @@ -21,15 +21,15 @@ except Exception: # catch Exception due to Mujoco-py pass -import alr_envs -from alr_envs.black_box.black_box_wrapper import BlackBoxWrapper -from alr_envs.black_box.factory.basis_generator_factory import get_basis_generator -from alr_envs.black_box.factory.controller_factory import get_controller -from alr_envs.black_box.factory.phase_generator_factory import get_phase_generator -from alr_envs.black_box.factory.trajectory_generator_factory import get_trajectory_generator -from alr_envs.black_box.raw_interface_wrapper import RawInterfaceWrapper -from alr_envs.utils.time_aware_observation import TimeAwareObservation -from alr_envs.utils.utils import nested_update +import fancy_gym +from fancy_gym.black_box.black_box_wrapper import BlackBoxWrapper +from fancy_gym.black_box.factory.basis_generator_factory import get_basis_generator +from fancy_gym.black_box.factory.controller_factory import get_controller +from fancy_gym.black_box.factory.phase_generator_factory import get_phase_generator +from fancy_gym.black_box.factory.trajectory_generator_factory import get_trajectory_generator +from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper +from fancy_gym.utils.time_aware_observation import TimeAwareObservation +from fancy_gym.utils.utils import nested_update def make_rank(env_id: str, seed: int, rank: int = 0, return_callable=True, **kwargs): @@ -264,7 +264,7 @@ def make_dmc( register( id=gym_id, - entry_point='alr_envs.dmc.dmc_wrapper:DMCWrapper', + entry_point='fancy_gym.dmc.dmc_wrapper:DMCWrapper', kwargs={'env': lambda: env}, max_episode_steps=max_episode_steps, ) @@ -316,7 +316,7 @@ def make_gym(env_id, seed, **kwargs): kwargs = all_kwargs # Add seed to kwargs for bb environments to pass seed to step environments - all_bb_envs = sum(alr_envs.ALL_MOVEMENT_PRIMITIVE_ENVIRONMENTS.values(), []) + all_bb_envs = sum(fancy_gym.ALL_MOVEMENT_PRIMITIVE_ENVIRONMENTS.values(), []) if env_id in all_bb_envs: kwargs.update({"seed": seed}) diff --git a/alr_envs/utils/time_aware_observation.py b/fancy_gym/utils/time_aware_observation.py similarity index 99% rename from alr_envs/utils/time_aware_observation.py rename to fancy_gym/utils/time_aware_observation.py index 92a7e9d..4fa0d74 100644 --- a/alr_envs/utils/time_aware_observation.py +++ b/fancy_gym/utils/time_aware_observation.py @@ -5,9 +5,8 @@ Copyright (c) 2016 OpenAI (https://openai.com) Wrapper for adding time aware observations to environment observation. """ -import numpy as np - import gym +import numpy as np from gym.spaces import Box diff --git a/alr_envs/utils/utils.py b/fancy_gym/utils/utils.py similarity index 100% rename from alr_envs/utils/utils.py rename to fancy_gym/utils/utils.py diff --git a/setup.py b/setup.py index 92d7225..b8627dc 100644 --- a/setup.py +++ b/setup.py @@ -29,15 +29,15 @@ setup( install_requires=[ 'gym>=0.24.0', ], - packages=[package for package in find_packages() if package.startswith("alr_envs")], - # packages=['alr_envs', 'alr_envs.envs', 'alr_envs.open_ai', 'alr_envs.dmc', 'alr_envs.meta', 'alr_envs.utils'], + packages=[package for package in find_packages() if package.startswith("fancy_gym")], + # packages=['fancy_gym', 'fancy_gym.envs', 'fancy_gym.open_ai', 'fancy_gym.dmc', 'fancy_gym.meta', 'fancy_gym.utils'], package_data={ - "alr_envs": [ + "fancy_gym": [ "envs/mujoco/*/assets/*.xml", ] }, python_requires=">=3.6", - url='https://github.com/ALRhub/alr_envs/', + url='https://github.com/ALRhub/fancy_gym/', # license='AGPL-3.0 license', author_email='', description='Simple Gym: Aggregating interface for various RL environments with support for Black Box approaches.' diff --git a/test/test_custom.py b/test/test_custom.py index c3d71f8..65633f8 100644 --- a/test/test_custom.py +++ b/test/test_custom.py @@ -3,11 +3,11 @@ import unittest import gym import numpy as np -import alr_envs # noqa -from alr_envs.utils.make_env_helpers import make +import fancy_gym # noqa +from fancy_gym.utils.make_env_helpers import make CUSTOM_IDS = [spec.id for spec in gym.envs.registry.all() if - "alr_envs" in spec.entry_point and 'make_bb_env_helper' not in spec.entry_point] + "fancy_gym" in spec.entry_point and 'make_bb_env_helper' not in spec.entry_point] SEED = 1 @@ -101,7 +101,7 @@ class TestCustomEnvironments(unittest.TestCase): def test_bb_functionality(self): """Tests that black box environments run without errors using random actions.""" - for traj_gen, env_ids in alr_envs.ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): + for traj_gen, env_ids in fancy_gym.ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): with self.subTest(msg=traj_gen): for id in env_ids: with self.subTest(msg=id): @@ -109,7 +109,7 @@ class TestCustomEnvironments(unittest.TestCase): def test_bb_determinism(self): """Tests that for black box environment identical seeds produce identical trajectories.""" - for traj_gen, env_ids in alr_envs.ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): + for traj_gen, env_ids in fancy_gym.ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): with self.subTest(msg=traj_gen): self._run_env_determinism(env_ids) diff --git a/test/test_dmc.py b/test/test_dmc.py index 4a67ecd..0800a67 100644 --- a/test/test_dmc.py +++ b/test/test_dmc.py @@ -2,11 +2,10 @@ import unittest import gym import numpy as np - from dm_control import suite, manipulation -import alr_envs -from alr_envs import make +import fancy_gym +from fancy_gym import make SUITE_IDS = [f'dmc:{env}-{task}' for env, task in suite.ALL_TASKS if env != "lqr"] MANIPULATION_IDS = [f'dmc:manipulation-{task}' for task in manipulation.ALL if task.endswith('_features')] @@ -114,7 +113,7 @@ class TestDMCEnvironments(unittest.TestCase): def test_bb_functionality(self): """Tests that black box environments run without errors using random actions.""" - for traj_gen, env_ids in alr_envs.ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): + for traj_gen, env_ids in fancy_gym.ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): with self.subTest(msg=traj_gen): for id in env_ids: with self.subTest(msg=id): @@ -122,7 +121,7 @@ class TestDMCEnvironments(unittest.TestCase): def test_bb_determinism(self): """Tests that for black box environment identical seeds produce identical trajectories.""" - for traj_gen, env_ids in alr_envs.ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): + for traj_gen, env_ids in fancy_gym.ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): with self.subTest(msg=traj_gen): self._run_env_determinism(env_ids) diff --git a/test/test_gym.py b/test/test_gym.py index 4aff70d..c8252d0 100644 --- a/test/test_gym.py +++ b/test/test_gym.py @@ -3,11 +3,11 @@ import unittest import gym import numpy as np -import alr_envs -from alr_envs import make +import fancy_gym +from fancy_gym import make GYM_IDS = [spec.id for spec in gym.envs.registry.all() if - "alr_envs" not in spec.entry_point and 'make_bb_env_helper' not in spec.entry_point] + "fancy_gym" not in spec.entry_point and 'make_bb_env_helper' not in spec.entry_point] SEED = 1 @@ -101,7 +101,7 @@ class TestGymEnvironments(unittest.TestCase): def test_bb_functionality(self): """Tests that black box environments run without errors using random actions.""" - for traj_gen, env_ids in alr_envs.ALL_GYM_MOTION_PRIMITIVE_ENVIRONMENTS.items(): + for traj_gen, env_ids in fancy_gym.ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): with self.subTest(msg=traj_gen): for id in env_ids: with self.subTest(msg=id): @@ -109,7 +109,7 @@ class TestGymEnvironments(unittest.TestCase): def test_bb_determinism(self): """Tests that for black box environment identical seeds produce identical trajectories.""" - for traj_gen, env_ids in alr_envs.ALL_GYM_MOTION_PRIMITIVE_ENVIRONMENTS.items(): + for traj_gen, env_ids in fancy_gym.ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): with self.subTest(msg=traj_gen): self._run_env_determinism(env_ids) diff --git a/test/test_metaworld.py b/test/test_metaworld.py index 2f7af22..f10d54a 100644 --- a/test/test_metaworld.py +++ b/test/test_metaworld.py @@ -2,11 +2,11 @@ import unittest import gym import numpy as np - -import alr_envs -from alr_envs import make from metaworld.envs import ALL_V2_ENVIRONMENTS_GOAL_OBSERVABLE +import fancy_gym +from fancy_gym import make + METAWORLD_IDS = [f'metaworld:{env.split("-goal-observable")[0]}' for env, _ in ALL_V2_ENVIRONMENTS_GOAL_OBSERVABLE.items()] SEED = 1 @@ -102,7 +102,7 @@ class TestMetaWorldEnvironments(unittest.TestCase): def test_bb_functionality(self): """Tests that black box environments run without errors using random actions.""" - for traj_gen, env_ids in alr_envs.ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): + for traj_gen, env_ids in fancy_gym.ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): with self.subTest(msg=traj_gen): for id in env_ids: with self.subTest(msg=id): @@ -110,7 +110,7 @@ class TestMetaWorldEnvironments(unittest.TestCase): def test_bb_determinism(self): """Tests that for black box environment identical seeds produce identical trajectories.""" - for traj_gen, env_ids in alr_envs.ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): + for traj_gen, env_ids in fancy_gym.ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): with self.subTest(msg=traj_gen): self._run_env_determinism(env_ids) From c96802564e476ae5109a7b83fd12285e37caa961 Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 13 Jul 2022 16:01:48 +0200 Subject: [PATCH 087/104] beerpong.py done flag fixed --- README.md | 6 +- fancy_gym/__init__.py | 4 +- fancy_gym/envs/__init__.py | 30 +++---- fancy_gym/envs/mujoco/beerpong/beerpong.py | 83 ++----------------- fancy_gym/envs/mujoco/beerpong/mp_wrapper.py | 4 +- .../envs/mujoco/hopper_jump/hopper_jump.py | 2 - test/{test_custom.py => test_fancy.py} | 4 +- 7 files changed, 30 insertions(+), 103 deletions(-) rename test/{test_custom.py => test_fancy.py} (95%) diff --git a/README.md b/README.md index 85249fb..086c447 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Fancy Gym +# Fancy Gym Fancy gym offers a large variety of reinforcement learning environments under the unifying interface of [OpenAI gym](https://gym.openai.com/). We provide support (under the OpenAI interface) for the benchmark suites @@ -65,7 +65,7 @@ We prepared [multiple examples](fancy_gym/examples/), please have a look there f ```python import fancy_gym -env = fancy_gym.make('HoleReacher-v0', seed=1) +env = fancy_gym.make('Reacher5d-v0', seed=1) state = env.reset() for i in range(1000): @@ -106,7 +106,7 @@ keys `DMP` and `ProMP` that store a list of available environment names. import fancy_gym print("Custom MP tasks:") -print(fancy_gym.ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS) +print(fancy_gym.ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS) print("OpenAI Gym MP tasks:") print(fancy_gym.ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS) diff --git a/fancy_gym/__init__.py b/fancy_gym/__init__.py index 457e3b1..f6f690a 100644 --- a/fancy_gym/__init__.py +++ b/fancy_gym/__init__.py @@ -2,7 +2,7 @@ from fancy_gym import dmc, meta, open_ai from fancy_gym.utils.make_env_helpers import make, make_bb, make_rank from .dmc import ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS # Convenience function for all MP environments -from .envs import ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS +from .envs import ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS from .meta import ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS from .open_ai import ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS @@ -10,4 +10,4 @@ ALL_MOVEMENT_PRIMITIVE_ENVIRONMENTS = { key: value + ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS[key] + ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS[key] + ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS[key] - for key, value in ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items()} + for key, value in ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items()} diff --git a/fancy_gym/envs/__init__.py b/fancy_gym/envs/__init__.py index f75d884..f6c7bc7 100644 --- a/fancy_gym/envs/__init__.py +++ b/fancy_gym/envs/__init__.py @@ -17,7 +17,7 @@ from .mujoco.hopper_throw.hopper_throw_in_basket import MAX_EPISODE_STEPS_HOPPER from .mujoco.reacher.reacher import ReacherEnv, MAX_EPISODE_STEPS_REACHER from .mujoco.walker_2d_jump.walker_2d_jump import MAX_EPISODE_STEPS_WALKERJUMP -ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": []} +ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": []} DEFAULT_BB_DICT_ProMP = { "name": 'EnvName', @@ -231,7 +231,7 @@ for _v in _versions: entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_simple_reacher_dmp ) - ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) + ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_simple_reacher_promp = deepcopy(DEFAULT_BB_DICT_ProMP) @@ -244,7 +244,7 @@ for _v in _versions: entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_simple_reacher_promp ) - ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) # Viapoint reacher kwargs_dict_via_point_reacher_dmp = deepcopy(DEFAULT_BB_DICT_DMP) @@ -259,7 +259,7 @@ register( # max_episode_steps=1, kwargs=kwargs_dict_via_point_reacher_dmp ) -ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append("ViaPointReacherDMP-v0") +ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append("ViaPointReacherDMP-v0") kwargs_dict_via_point_reacher_promp = deepcopy(DEFAULT_BB_DICT_ProMP) kwargs_dict_via_point_reacher_promp['wrappers'].append(classic_control.viapoint_reacher.MPWrapper) @@ -270,7 +270,7 @@ register( entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_via_point_reacher_promp ) -ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ViaPointReacherProMP-v0") +ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append("ViaPointReacherProMP-v0") ## Hole Reacher _versions = ["HoleReacher-v0"] @@ -290,7 +290,7 @@ for _v in _versions: # max_episode_steps=1, kwargs=kwargs_dict_hole_reacher_dmp ) - ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) + ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_hole_reacher_promp = deepcopy(DEFAULT_BB_DICT_ProMP) @@ -303,7 +303,7 @@ for _v in _versions: entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_hole_reacher_promp ) - ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) ## ReacherNd _versions = ["Reacher5d-v0", "Reacher7d-v0", "Reacher5dSparse-v0", "Reacher7dSparse-v0"] @@ -320,7 +320,7 @@ for _v in _versions: # max_episode_steps=1, kwargs=kwargs_dict_reacher_dmp ) - ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) + ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["DMP"].append(_env_id) _env_id = f'{_name[0]}ProMP-{_name[1]}' kwargs_dict_reacher_promp = deepcopy(DEFAULT_BB_DICT_ProMP) @@ -331,7 +331,7 @@ for _v in _versions: entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_reacher_promp ) - ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) ######################################################################################################################## ## Beerpong ProMP @@ -352,7 +352,7 @@ for _v in _versions: entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_bp_promp ) - ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) ### BP with Fixed release _versions = ["BeerPongStepBased-v0", "BeerPongFixedRelease-v0"] @@ -372,7 +372,7 @@ for _v in _versions: entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_bp_promp ) - ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) ######################################################################################################################## ## Table Tennis needs to be fixed according to Zhou's implementation @@ -393,7 +393,7 @@ for _v in _versions: # entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', # kwargs=kwargs_dict_ant_jump_promp # ) -# ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) +# ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) # # ######################################################################################################################## # @@ -410,7 +410,7 @@ for _v in _versions: # entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', # kwargs=kwargs_dict_halfcheetah_jump_promp # ) -# ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) +# ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) # # ######################################################################################################################## @@ -431,7 +431,7 @@ for _v in _versions: entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', kwargs=kwargs_dict_hopper_jump_promp ) - ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) + ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) # ######################################################################################################################## # @@ -449,7 +449,7 @@ for _v in _versions: # entry_point='fancy_gym.utils.make_env_helpers:make_bb_env_helper', # kwargs=kwargs_dict_walker2d_jump_promp # ) -# ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) +# ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) ### Depricated, we will not provide non random starts anymore """ diff --git a/fancy_gym/envs/mujoco/beerpong/beerpong.py b/fancy_gym/envs/mujoco/beerpong/beerpong.py index 9fcfdd8..368425d 100644 --- a/fancy_gym/envs/mujoco/beerpong/beerpong.py +++ b/fancy_gym/envs/mujoco/beerpong/beerpong.py @@ -6,6 +6,7 @@ from gym import utils from gym.envs.mujoco import MujocoEnv MAX_EPISODE_STEPS_BEERPONG = 300 +FIXED_RELEASE_STEP = 62 # empirically evaluated for frame_skip=2! # XML Variables ROBOT_COLLISION_OBJ = ["wrist_palm_link_convex_geom", @@ -44,7 +45,7 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): self._start_pos = np.array([0.0, 1.35, 0.0, 1.18, 0.0, -0.786, -1.59]) self._start_vel = np.zeros(7) - self.release_step = 100 # time step of ball release + self.release_step = FIXED_RELEASE_STEP self.repeat_action = 2 # TODO: If accessing IDs is easier in the (new) official mujoco bindings, remove this @@ -250,86 +251,16 @@ class BeerPongEnv(MujocoEnv, utils.EzPickle): return False -class BeerPongEnvFixedReleaseStep(BeerPongEnv): - def __init__(self): - super().__init__() - self.release_step = 62 # empirically evaluated for frame_skip=2! - - class BeerPongEnvStepBasedEpisodicReward(BeerPongEnv): - def __init__(self): - super().__init__() - self.release_step = 62 # empirically evaluated for frame_skip=2! def step(self, a): - if self._steps < self.release_step: + if self._steps < FIXED_RELEASE_STEP: return super(BeerPongEnvStepBasedEpisodicReward, self).step(a) else: reward = 0 - done = False - while not done: - sub_ob, sub_reward, done, sub_infos = super(BeerPongEnvStepBasedEpisodicReward, self).step( + done = True + while self._steps < MAX_EPISODE_STEPS_BEERPONG: + obs, sub_reward, done, infos = super(BeerPongEnvStepBasedEpisodicReward, self).step( np.zeros(a.shape)) reward += sub_reward - infos = sub_infos - ob = sub_ob - ob[-1] = self.release_step + 1 # Since we simulate until the end of the episode, PPO does not see the - # internal steps and thus, the observation also needs to be set correctly - return ob, reward, done, infos - - -# class BeerBongEnvStepBased(BeerBongEnv): -# def __init__(self, frame_skip=1, apply_gravity_comp=True, noisy=False, rndm_goal=False, cup_goal_pos=None): -# super().__init__(frame_skip, apply_gravity_comp, noisy, rndm_goal, cup_goal_pos) -# self.release_step = 62 # empirically evaluated for frame_skip=2! -# -# def step(self, a): -# if self._steps < self.release_step: -# return super(BeerBongEnvStepBased, self).step(a) -# else: -# reward = 0 -# done = False -# while not done: -# sub_ob, sub_reward, done, sub_infos = super(BeerBongEnvStepBased, self).step(np.zeros(a.shape)) -# if not done or sub_infos['sim_crash']: -# reward += sub_reward -# else: -# ball_pos = self.sim.data.body_xpos[self.sim.model._body_name2id["ball"]].copy() -# cup_goal_dist_final = np.linalg.norm(ball_pos - self.sim.data.site_xpos[ -# self.sim.model._site_name2id["cup_goal_final_table"]].copy()) -# cup_goal_dist_top = np.linalg.norm(ball_pos - self.sim.data.site_xpos[ -# self.sim.model._site_name2id["cup_goal_table"]].copy()) -# if sub_infos['success']: -# dist_rew = -cup_goal_dist_final ** 2 -# else: -# dist_rew = -0.5 * cup_goal_dist_final ** 2 - cup_goal_dist_top ** 2 -# reward = reward - sub_infos['action_cost'] + dist_rew -# infos = sub_infos -# ob = sub_ob -# ob[-1] = self.release_step + 1 # Since we simulate until the end of the episode, PPO does not see the -# # internal steps and thus, the observation also needs to be set correctly -# return ob, reward, done, infos - - -if __name__ == "__main__": - env = BeerPongEnv() - env.seed(0) - # env = BeerBongEnvStepBased(frame_skip=2) - # env = BeerBongEnvStepBasedEpisodicReward(frame_skip=2) - # env = BeerBongEnvFixedReleaseStep(frame_skip=2) - import time - - env.reset() - env.render("human") - for i in range(600): - # ac = 10 * env.action_space.sample() - ac = 0.05 * np.ones(7) - obs, rew, d, info = env.step(ac) - env.render("human") - - if d: - print('reward:', rew) - print('RESETTING') - env.reset() - time.sleep(1) - env.close() + return obs, reward, done, infos diff --git a/fancy_gym/envs/mujoco/beerpong/mp_wrapper.py b/fancy_gym/envs/mujoco/beerpong/mp_wrapper.py index b5e6687..8988f5a 100644 --- a/fancy_gym/envs/mujoco/beerpong/mp_wrapper.py +++ b/fancy_gym/envs/mujoco/beerpong/mp_wrapper.py @@ -31,9 +31,7 @@ class MPWrapper(RawInterfaceWrapper): def episode_callback(self, action: np.ndarray, mp) -> Tuple[np.ndarray, Union[np.ndarray, None]]: if mp.learn_tau: self.release_step = action[0] / self.dt # Tau value - return action, None - else: - return action, None + return action, None def set_context(self, context): xyz = np.zeros(3) diff --git a/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py b/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py index 329ea89..22e706a 100644 --- a/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py +++ b/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py @@ -156,8 +156,6 @@ class HopperJumpEnv(HopperEnv): self.init_floor_contact = False self.contact_dist = None - self.data.geom() - return observation def _is_floor_foot_contact(self): diff --git a/test/test_custom.py b/test/test_fancy.py similarity index 95% rename from test/test_custom.py rename to test/test_fancy.py index 65633f8..d4890cc 100644 --- a/test/test_custom.py +++ b/test/test_fancy.py @@ -101,7 +101,7 @@ class TestCustomEnvironments(unittest.TestCase): def test_bb_functionality(self): """Tests that black box environments run without errors using random actions.""" - for traj_gen, env_ids in fancy_gym.ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): + for traj_gen, env_ids in fancy_gym.ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): with self.subTest(msg=traj_gen): for id in env_ids: with self.subTest(msg=id): @@ -109,7 +109,7 @@ class TestCustomEnvironments(unittest.TestCase): def test_bb_determinism(self): """Tests that for black box environment identical seeds produce identical trajectories.""" - for traj_gen, env_ids in fancy_gym.ALL_ALR_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): + for traj_gen, env_ids in fancy_gym.ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS.items(): with self.subTest(msg=traj_gen): self._run_env_determinism(env_ids) From f70f3eeb9a682d276366c73f613172477096e6ee Mon Sep 17 00:00:00 2001 From: Onur Date: Wed, 13 Jul 2022 16:16:07 +0200 Subject: [PATCH 088/104] adjust register for BP --- fancy_gym/envs/__init__.py | 19 ++++++++----------- fancy_gym/envs/mujoco/__init__.py | 2 +- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/fancy_gym/envs/__init__.py b/fancy_gym/envs/__init__.py index f6c7bc7..9f0299e 100644 --- a/fancy_gym/envs/__init__.py +++ b/fancy_gym/envs/__init__.py @@ -8,7 +8,7 @@ from .classic_control.hole_reacher.hole_reacher import HoleReacherEnv from .classic_control.simple_reacher.simple_reacher import SimpleReacherEnv from .classic_control.viapoint_reacher.viapoint_reacher import ViaPointReacherEnv from .mujoco.ant_jump.ant_jump import MAX_EPISODE_STEPS_ANTJUMP -from .mujoco.beerpong.beerpong import MAX_EPISODE_STEPS_BEERPONG +from .mujoco.beerpong.beerpong import MAX_EPISODE_STEPS_BEERPONG, FIXED_RELEASE_STEP from .mujoco.half_cheetah_jump.half_cheetah_jump import MAX_EPISODE_STEPS_HALFCHEETAHJUMP from .mujoco.hopper_jump.hopper_jump import MAX_EPISODE_STEPS_HOPPERJUMP from .mujoco.hopper_jump.hopper_jump_on_box import MAX_EPISODE_STEPS_HOPPERJUMPONBOX @@ -202,15 +202,9 @@ register( register( id='BeerPongStepBased-v0', entry_point='fancy_gym.envs.mujoco:BeerPongEnvStepBasedEpisodicReward', - max_episode_steps=MAX_EPISODE_STEPS_BEERPONG, + max_episode_steps=FIXED_RELEASE_STEP, ) -# Beerpong with episodic reward, but fixed release time step -register( - id='BeerPongFixedRelease-v0', - entry_point='fancy_gym.envs.mujoco:BeerPongEnvFixedReleaseStep', - max_episode_steps=MAX_EPISODE_STEPS_BEERPONG, -) # movement Primitive Environments @@ -355,10 +349,13 @@ for _v in _versions: ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS["ProMP"].append(_env_id) ### BP with Fixed release -_versions = ["BeerPongStepBased-v0", "BeerPongFixedRelease-v0"] +_versions = ["BeerPongStepBased-v0", 'BeerPong-v0'] for _v in _versions: - _name = _v.split("-") - _env_id = f'{_name[0]}ProMP-{_name[1]}' + if _v != 'BeerPong-v0': + _name = _v.split("-") + _env_id = f'{_name[0]}ProMP-{_name[1]}' + else: + _env_id = 'BeerPongFixedReleaseProMP-v0' kwargs_dict_bp_promp = deepcopy(DEFAULT_BB_DICT_ProMP) kwargs_dict_bp_promp['wrappers'].append(mujoco.beerpong.MPWrapper) kwargs_dict_bp_promp['phase_generator_kwargs']['tau'] = 0.62 diff --git a/fancy_gym/envs/mujoco/__init__.py b/fancy_gym/envs/mujoco/__init__.py index b283b60..840691f 100644 --- a/fancy_gym/envs/mujoco/__init__.py +++ b/fancy_gym/envs/mujoco/__init__.py @@ -1,5 +1,5 @@ from .ant_jump.ant_jump import AntJumpEnv -from .beerpong.beerpong import BeerPongEnv, BeerPongEnvFixedReleaseStep, BeerPongEnvStepBasedEpisodicReward +from .beerpong.beerpong import BeerPongEnv, BeerPongEnvStepBasedEpisodicReward from .half_cheetah_jump.half_cheetah_jump import HalfCheetahJumpEnv from .hopper_jump.hopper_jump import HopperJumpEnv from .hopper_jump.hopper_jump_on_box import HopperJumpOnBoxEnv From 2e6094982e6ce89223a3fd31b336f56ba3e3b09f Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 13 Jul 2022 16:52:24 +0200 Subject: [PATCH 089/104] readme udpated --- README.md | 200 ++++++++++--------- fancy_gym/black_box/black_box_wrapper.py | 4 - fancy_gym/black_box/raw_interface_wrapper.py | 7 +- setup.py | 5 +- 4 files changed, 115 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 086c447..f1506d3 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,27 @@ # Fancy Gym -Fancy gym offers a large variety of reinforcement learning environments under the unifying interface -of [OpenAI gym](https://gym.openai.com/). We provide support (under the OpenAI interface) for the benchmark suites +`fancy_gym` offers a large variety of reinforcement learning environments under the unifying interface +of [OpenAI gym](https://gym.openai.com/). We provide support (under the OpenAI gym interface) for the benchmark suites [DeepMind Control](https://deepmind.com/research/publications/2020/dm-control-Software-and-Tasks-for-Continuous-Control) -(DMC) and [Metaworld](https://meta-world.github.io/). Custom (Mujoco) gym environments can be created according -to [this guide](https://www.gymlibrary.ml/content/environment_creation/). Unlike existing libraries, we additionally -support to control agents with movement primitives, such as Dynamic Movement Primitives (DMPs) and Probabilistic -Movement Primitives (ProMP, we only consider the mean usually). +(DMC) and [Metaworld](https://meta-world.github.io/). If those are not sufficient and you want to create your own custom +gym environments, use [this guide](https://www.gymlibrary.ml/content/environment_creation/). We highly appreciate it, if +you would then submit a PR for this environment to become part of `fancy_gym`. +In comparison to existing libraries, we additionally support to control agents with movement primitives, such as Dynamic +Movement Primitives (DMPs) and Probabilistic Movement Primitives (ProMP). ## Movement Primitive Environments (Episode-Based/Black-Box Environments) Unlike step-based environments, movement primitive (MP) environments are closer related to stochastic search, black-box -optimization, and methods that are often used in traditional robotics and control. -MP environments are episode-based and always execute a full trajectory, which is generated by a trajectory generator, -such as a Dynamic Movement Primitive (DMP) or a Probabilistic Movement Primitive (ProMP). -The generated trajectory is translated into individual step-wise actions by a trajectory tracking controller. -The exact choice of controller is, however, dependent on the type of environment. -We currently support position, velocity, and PD-Controllers for position, velocity, and torque control, respectively -as well as a special controller for the MetaWorld control suite. -The goal of all MP environments is still to learn a optimal policy. Yet, an action -represents the parametrization of the motion primitives to generate a suitable trajectory. Additionally, in this -framework we support all of this also for the contextual setting, i.e. we expose a subset of the observation space -as a single context in the beginning of the episode. This requires to predict a new action/MP parametrization for each -context. -All environments provide next to the cumulative episode reward all collected information from each -step as part of the info dictionary. This information is, however, mainly meant for debugging as well as logging -and not for training. - -|Key| Description| -|---|---| -`trajectory`| Generated trajectory from MP -`step_actions`| Step-wise executed action based on controller output -`step_observations`| Step-wise intermediate observations -`step_rewards`| Step-wise rewards -`trajectory_length`| Total number of environment interactions -`other`| All other information from the underlying environment are returned as a list with length `trajectory_length` maintaining the original key. In case some information are not provided every time step, the missing values are filled with `None`. +optimization, and methods that are often used in traditional robotics and control. MP environments are typically +episode-based and execute a full trajectory, which is generated by a trajectory generator, such as a Dynamic Movement +Primitive (DMP) or a Probabilistic Movement Primitive (ProMP). The generated trajectory is translated into individual +step-wise actions by a trajectory tracking controller. The exact choice of controller is, however, dependent on the type +of environment. We currently support position, velocity, and PD-Controllers for position, velocity, and torque control, +respectively as well as a special controller for the MetaWorld control suite. +The goal of all MP environments is still to learn an optimal policy. Yet, an action represents the parametrization of +the motion primitives to generate a suitable trajectory. Additionally, in this framework we support all of this also for +the contextual setting, i.e. we expose the context space - a subset of the observation space - in the beginning of the +episode. This requires to predict a new action/MP parametrization for each context. ## Installation @@ -53,128 +40,158 @@ cd alr_envs 3. Install with ```bash -pip install -e . +pip install -e . ``` -## Using the framework +In case you want to use dm_control oder metaworld, you can install them by specifying extras -We prepared [multiple examples](fancy_gym/examples/), please have a look there for more specific examples. +```bash +pip install -e .[dmc, metaworld] +``` -### Step-wise environments +> **Note:** +> While our library already fully supports the new mujoco bindings, metaworld still relies on +> [mujoco_py](https://github.com/openai/mujoco-py), hence make sure to have mujoco 2.1 installed beforehand. + +## How to use Fancy Gym + +We will only show the basics here and prepared [multiple examples](fancy_gym/examples/) for a more detailed look. + +### Step-wise Environments ```python import fancy_gym env = fancy_gym.make('Reacher5d-v0', seed=1) -state = env.reset() +obs = env.reset() for i in range(1000): - state, reward, done, info = env.step(env.action_space.sample()) + action = env.action_space.sample() + obs, reward, done, info = env.step(action) if i % 5 == 0: env.render() if done: - state = env.reset() + obs = env.reset() ``` -For Deepmind control tasks we expect the `env_id` to be specified as `domain_name-task_name` or for manipulation tasks -as `manipulation-environment_name`. All other environments can be created based on their original name. +When using `dm_control` tasks we expect the `env_id` to be specified as `dmc:domain_name-task_name` or for manipulation +tasks as `dmc:manipulation-environment_name`. For `metaworld` tasks, we require the structure `metaworld:env_id-v2`, our +custom tasks and standard gym environments can be created without prefixes. -Existing MP tasks can be created the same way as above. Just keep in mind, calling `step()` always executs a full -trajectory. +### Black-box Environments + +All environments provide by default the cumulative episode reward, this can however be changed if necessary. Optionally, +each environment returns all collected information from each step as part of the infos. This information is, however, +mainly meant for debugging as well as logging and not for training. + +|Key| Description|Type +|---|---|---| +`positions`| Generated trajectory from MP | Optional +`velocities`| Generated trajectory from MP | Optional +`step_actions`| Step-wise executed action based on controller output | Optional +`step_observations`| Step-wise intermediate observations | Optional +`step_rewards`| Step-wise rewards | Optional +`trajectory_length`| Total number of environment interactions | Always +`other`| All other information from the underlying environment are returned as a list with length `trajectory_length` maintaining the original key. In case some information are not provided every time step, the missing values are filled with `None`. | Always + +Existing MP tasks can be created the same way as above. Just keep in mind, calling `step()` executes a full trajectory. + +> **Note:** +> Currently, we are also in the process of enabling replanning as well as learning of sub-trajectories. +> This allows to split the episode into multiple trajectories and is a hybrid setting between step-based and +> black-box leaning. +> While this is already implemented, it is still in beta and requires further testing. +> Feel free to try it and open an issue with any problems that occur. ```python import fancy_gym -env = fancy_gym.make('HoleReacherProMP-v0', seed=1) -# render() can be called once in the beginning with all necessary arguments. To turn it of again just call render(None). -env.render() +env = fancy_gym.make('Reacher5dProMP-v0', seed=1) +# render() can be called once in the beginning with all necessary arguments. +# To turn it of again just call render() without any arguments. +env.render(mode='human') -state = env.reset() +# This returns the context information, not the full state observation +obs = env.reset() for i in range(5): - state, reward, done, info = env.step(env.action_space.sample()) + action = env.action_space.sample() + obs, reward, done, info = env.step(action) - # Not really necessary as the environments resets itself after each trajectory anyway. - state = env.reset() + # Done is always True as we are working on the episode level, hence we always reset() + obs = env.reset() ``` -To show all available environments, we provide some additional convenience. Each value will return a dictionary with two -keys `DMP` and `ProMP` that store a list of available environment names. +To show all available environments, we provide some additional convenience variables. All of them return a dictionary +with two keys `DMP` and `ProMP` that store a list of available environment ids. ```python import fancy_gym -print("Custom MP tasks:") +print("Fancy Black-box tasks:") print(fancy_gym.ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS) -print("OpenAI Gym MP tasks:") +print("OpenAI Gym Black-box tasks:") print(fancy_gym.ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS) -print("Deepmind Control MP tasks:") +print("Deepmind Control Black-box tasks:") print(fancy_gym.ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS) -print("MetaWorld MP tasks:") +print("MetaWorld Black-box tasks:") print(fancy_gym.ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS) ``` ### How to create a new MP task In case a required task is not supported yet in the MP framework, it can be created relatively easy. For the task at -hand, the following interface needs to be implemented. +hand, the following [interface](fancy_gym/black_box/raw_interface_wrapper.py) needs to be implemented. ```python +from abc import abstractmethod +from typing import Union, Tuple + +import gym import numpy as np -from mp_env_api import MPEnvWrapper -class MPWrapper(MPEnvWrapper): +class RawInterfaceWrapper(gym.Wrapper): @property - def active_obs(self): + def context_mask(self) -> np.ndarray: """ - Returns boolean mask for each substate in the full observation. - It determines whether the observation is returned for the contextual case or not. - This effectively allows to filter unwanted or unnecessary observations from the full step-based case. - E.g. Velocities starting at 0 are only changing after the first action. Given we only receive the first - observation, the velocities are not necessary in the observation for the MP task. + Returns boolean mask of the same shape as the observation space. + It determines whether the observation is returned for the contextual case or not. + This effectively allows to filter unwanted or unnecessary observations from the full step-based case. + E.g. Velocities starting at 0 are only changing after the first action. Given we only receive the + context/part of the first observation, the velocities are not necessary in the observation for the task. + Returns: + bool array representing the indices of the observations + """ - return np.ones(self.observation_space.shape, dtype=bool) + return np.ones(self.env.observation_space.shape[0], dtype=bool) @property - def current_vel(self): + @abstractmethod + def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: """ - Returns the current velocity of the action/control dimension. + Returns the current position of the action/control dimension. The dimensionality has to match the action/control dimension. - This is not required when exclusively using position control, - it should, however, be implemented regardless. - E.g. The joint velocities that are directly or indirectly controlled by the action. - """ - raise NotImplementedError() - - @property - def current_pos(self): - """ - Returns the current position of the action/control dimension. - The dimensionality has to match the action/control dimension. - This is not required when exclusively using velocity control, + This is not required when exclusively using velocity control, it should, however, be implemented regardless. E.g. The joint positions that are directly or indirectly controlled by the action. """ raise NotImplementedError() @property - def goal_pos(self): + @abstractmethod + def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: """ - Returns a predefined final position of the action/control dimension. - This is only required for the DMP and is most of the time learned instead. - """ - raise NotImplementedError() - - @property - def dt(self): - """ - Returns the time between two simulated steps of the environment + Returns the current velocity of the action/control dimension. + The dimensionality has to match the action/control dimension. + This is not required when exclusively using position control, + it should, however, be implemented regardless. + E.g. The joint velocities that are directly or indirectly controlled by the action. """ raise NotImplementedError() @@ -190,15 +207,12 @@ import fancy_gym # Base environment name, according to structure of above example base_env_id = "ball_in_cup-catch" -# Replace this wrapper with the custom wrapper for your environment by inheriting from the MPEnvWrapper. +# Replace this wrapper with the custom wrapper for your environment by inheriting from the RawInferfaceWrapper. # You can also add other gym.Wrappers in case they are needed, # e.g. gym.wrappers.FlattenObservation for dict observations wrappers = [fancy_gym.dmc.suite.ball_in_cup.MPWrapper] -mp_kwargs = {...} kwargs = {...} -env = fancy_gym.make_dmp_env(base_env_id, wrappers=wrappers, seed=1, mp_kwargs=mp_kwargs, **kwargs) -# OR for a deterministic ProMP (other traj_gen_kwargs are required): -# env = fancy_gym.make_promp_env(base_env, wrappers=wrappers, seed=seed, traj_gen_kwargs=mp_args) +env = fancy_gym.make_bb(base_env_id, wrappers=wrappers, seed=0, **kwargs) rewards = 0 obs = env.reset() diff --git a/fancy_gym/black_box/black_box_wrapper.py b/fancy_gym/black_box/black_box_wrapper.py index 6358778..fb2bbbf 100644 --- a/fancy_gym/black_box/black_box_wrapper.py +++ b/fancy_gym/black_box/black_box_wrapper.py @@ -1,7 +1,3 @@ -import os - -os.environ["MUJOCO_GL"] = "egl" - from typing import Tuple, Optional import gym diff --git a/fancy_gym/black_box/raw_interface_wrapper.py b/fancy_gym/black_box/raw_interface_wrapper.py index 2342a3c..7b2e996 100644 --- a/fancy_gym/black_box/raw_interface_wrapper.py +++ b/fancy_gym/black_box/raw_interface_wrapper.py @@ -9,10 +9,13 @@ from mp_pytorch.mp.mp_interfaces import MPInterface class RawInterfaceWrapper(gym.Wrapper): @property - @abstractmethod def context_mask(self) -> np.ndarray: """ - This function defines the contexts. The contexts are defined as specific observations. + Returns boolean mask of the same shape as the observation space. + It determines whether the observation is returned for the contextual case or not. + This effectively allows to filter unwanted or unnecessary observations from the full step-based case. + E.g. Velocities starting at 0 are only changing after the first action. Given we only receive the + context/part of the first observation, the velocities are not necessary in the observation for the task. Returns: bool array representing the indices of the observations diff --git a/setup.py b/setup.py index b8627dc..7fb73fe 100644 --- a/setup.py +++ b/setup.py @@ -5,8 +5,8 @@ from setuptools import setup, find_packages # Environment-specific dependencies for dmc and metaworld extras = { "dmc": ["dm_control==1.0.1"], - "meta": ["metaworld @ git+https://github.com/rlworkgroup/metaworld.git@master#egg=metaworld"], - "mujoco": ["mujoco==2.2.0", "imageio>=2.14.1"], + "metaworld": ["metaworld @ git+https://github.com/rlworkgroup/metaworld.git@master#egg=metaworld", + 'mujoco-py<2.2,>=2.1'], } # All dependencies @@ -28,6 +28,7 @@ setup( extras_require=extras, install_requires=[ 'gym>=0.24.0', + 'mujoco==2.2.0', ], packages=[package for package in find_packages() if package.startswith("fancy_gym")], # packages=['fancy_gym', 'fancy_gym.envs', 'fancy_gym.open_ai', 'fancy_gym.dmc', 'fancy_gym.meta', 'fancy_gym.utils'], From 96dfb7fc5fe6d3db652c78db9ea3c7e4b336edd1 Mon Sep 17 00:00:00 2001 From: ottofabian Date: Thu, 14 Jul 2022 08:25:25 +0200 Subject: [PATCH 090/104] Update setup.py --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 7fb73fe..28440e6 100644 --- a/setup.py +++ b/setup.py @@ -37,9 +37,9 @@ setup( "envs/mujoco/*/assets/*.xml", ] }, - python_requires=">=3.6", + python_requires=">=3.7", url='https://github.com/ALRhub/fancy_gym/', # license='AGPL-3.0 license', author_email='', - description='Simple Gym: Aggregating interface for various RL environments with support for Black Box approaches.' + description='Fancy Gym: Unifying interface for various RL benchmarks with support for Black Box approaches.' ) From 55c5d1f89e6a8e466d0a625e0391eb6c586cf1cb Mon Sep 17 00:00:00 2001 From: ottofabian Date: Thu, 14 Jul 2022 09:39:54 +0200 Subject: [PATCH 091/104] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f1506d3..25cb6d8 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,13 @@ episode. This requires to predict a new action/MP parametrization for each conte 1. Clone the repository ```bash -git clone git@github.com:ALRhub/alr_envs.git +git clone git@github.com:ALRhub/fancy_gym.git ``` 2. Go to the folder ```bash -cd alr_envs +cd fancy_gym ``` 3. Install with From 2283f4416cc86936114a613c70164f233139012d Mon Sep 17 00:00:00 2001 From: ottofabian Date: Thu, 14 Jul 2022 09:45:35 +0200 Subject: [PATCH 092/104] Update setup.py --- setup.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 28440e6..340e3f2 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from setuptools import setup, find_packages # Environment-specific dependencies for dmc and metaworld extras = { - "dmc": ["dm_control==1.0.1"], + "dmc": ["dm_control>=1.0.1"], "metaworld": ["metaworld @ git+https://github.com/rlworkgroup/metaworld.git@master#egg=metaworld", 'mujoco-py<2.2,>=2.1'], } @@ -14,11 +14,11 @@ all_groups = set(extras.keys()) extras["all"] = list(set(itertools.chain.from_iterable(map(lambda group: extras[group], all_groups)))) setup( - author='Fabian Otto, Onur Celik, Marcel Sandermann, Maximilian Huettenrauch', - name='simple_gym', - version='0.1', + author='Fabian Otto, Onur Celik', + name='fancy_gym', + version='0.2', classifiers=[ - # Python 3.6 is minimally supported (only with basic gym environments and API) + # Python 3.7 is minimally supported "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", @@ -29,9 +29,9 @@ setup( install_requires=[ 'gym>=0.24.0', 'mujoco==2.2.0', + 'mp_pytorch @ git+https://github.com/ALRhub/MP_PyTorch.git@master' ], packages=[package for package in find_packages() if package.startswith("fancy_gym")], - # packages=['fancy_gym', 'fancy_gym.envs', 'fancy_gym.open_ai', 'fancy_gym.dmc', 'fancy_gym.meta', 'fancy_gym.utils'], package_data={ "fancy_gym": [ "envs/mujoco/*/assets/*.xml", From 855dba7fdefb4ed22cc01ae142826803f6e8f0aa Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 14 Jul 2022 11:54:38 +0200 Subject: [PATCH 093/104] fixed setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 340e3f2..3f67e1a 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ setup( install_requires=[ 'gym>=0.24.0', 'mujoco==2.2.0', - 'mp_pytorch @ git+https://github.com/ALRhub/MP_PyTorch.git@master' + 'mp_pytorch @ git+https://github.com/ALRhub/MP_PyTorch.git@main' ], packages=[package for package in find_packages() if package.startswith("fancy_gym")], package_data={ From 84386fd8e4abb5317fe845bdf69d41428a96a50f Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 14 Jul 2022 15:19:39 +0200 Subject: [PATCH 094/104] fixed imports --- .../black_box/factory/basis_generator_factory.py | 9 +++++---- .../black_box/factory/phase_generator_factory.py | 13 ++++++++----- .../factory/trajectory_generator_factory.py | 8 +++----- fancy_gym/utils/make_env_helpers.py | 9 ++++----- setup.py | 3 +-- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/fancy_gym/black_box/factory/basis_generator_factory.py b/fancy_gym/black_box/factory/basis_generator_factory.py index 610ad20..4601953 100644 --- a/fancy_gym/black_box/factory/basis_generator_factory.py +++ b/fancy_gym/black_box/factory/basis_generator_factory.py @@ -1,5 +1,5 @@ -from mp_pytorch import PhaseGenerator, NormalizedRBFBasisGenerator, ZeroStartNormalizedRBFBasisGenerator -from mp_pytorch.basis_gn.rhytmic_basis import RhythmicBasisGenerator +from mp_pytorch.basis_gn import NormalizedRBFBasisGenerator, ZeroPaddingNormalizedRBFBasisGenerator +from mp_pytorch.phase_gn import PhaseGenerator ALL_TYPES = ["rbf", "zero_rbf", "rhythmic"] @@ -9,9 +9,10 @@ def get_basis_generator(basis_generator_type: str, phase_generator: PhaseGenerat if basis_generator_type == "rbf": return NormalizedRBFBasisGenerator(phase_generator, **kwargs) elif basis_generator_type == "zero_rbf": - return ZeroStartNormalizedRBFBasisGenerator(phase_generator, **kwargs) + return ZeroPaddingNormalizedRBFBasisGenerator(phase_generator, **kwargs) elif basis_generator_type == "rhythmic": - return RhythmicBasisGenerator(phase_generator, **kwargs) + raise NotImplementedError() + # return RhythmicBasisGenerator(phase_generator, **kwargs) else: raise ValueError(f"Specified basis generator type {basis_generator_type} not supported, " f"please choose one of {ALL_TYPES}.") diff --git a/fancy_gym/black_box/factory/phase_generator_factory.py b/fancy_gym/black_box/factory/phase_generator_factory.py index ca0dd84..67e17f8 100644 --- a/fancy_gym/black_box/factory/phase_generator_factory.py +++ b/fancy_gym/black_box/factory/phase_generator_factory.py @@ -1,6 +1,7 @@ -from mp_pytorch import LinearPhaseGenerator, ExpDecayPhaseGenerator -from mp_pytorch.phase_gn.rhythmic_phase_generator import RhythmicPhaseGenerator -from mp_pytorch.phase_gn.smooth_phase_generator import SmoothPhaseGenerator +from mp_pytorch.phase_gn import LinearPhaseGenerator, ExpDecayPhaseGenerator + +# from mp_pytorch.phase_gn.rhythmic_phase_generator import RhythmicPhaseGenerator +# from mp_pytorch.phase_gn.smooth_phase_generator import SmoothPhaseGenerator ALL_TYPES = ["linear", "exp", "rhythmic", "smooth"] @@ -12,9 +13,11 @@ def get_phase_generator(phase_generator_type, **kwargs): elif phase_generator_type == "exp": return ExpDecayPhaseGenerator(**kwargs) elif phase_generator_type == "rhythmic": - return RhythmicPhaseGenerator(**kwargs) + raise NotImplementedError() + # return RhythmicPhaseGenerator(**kwargs) elif phase_generator_type == "smooth": - return SmoothPhaseGenerator(**kwargs) + raise NotImplementedError() + # return SmoothPhaseGenerator(**kwargs) else: raise ValueError(f"Specified phase generator type {phase_generator_type} not supported, " f"please choose one of {ALL_TYPES}.") diff --git a/fancy_gym/black_box/factory/trajectory_generator_factory.py b/fancy_gym/black_box/factory/trajectory_generator_factory.py index f7ca6e2..2b93a6c 100644 --- a/fancy_gym/black_box/factory/trajectory_generator_factory.py +++ b/fancy_gym/black_box/factory/trajectory_generator_factory.py @@ -1,7 +1,5 @@ -from mp_pytorch.basis_gn.basis_generator import BasisGenerator -from mp_pytorch.mp.dmp import DMP -from mp_pytorch.mp.idmp import IDMP -from mp_pytorch.mp.promp import ProMP +from mp_pytorch.basis_gn import BasisGenerator +from mp_pytorch.mp import ProDMP, DMP, ProMP ALL_TYPES = ["promp", "dmp", "idmp"] @@ -15,7 +13,7 @@ def get_trajectory_generator( elif trajectory_generator_type == "dmp": return DMP(basis_generator, action_dim, **kwargs) elif trajectory_generator_type == 'idmp': - return IDMP(basis_generator, action_dim, **kwargs) + return ProDMP(basis_generator, action_dim, **kwargs) else: raise ValueError(f"Specified movement primitive type {trajectory_generator_type} not supported, " f"please choose one of {ALL_TYPES}.") diff --git a/fancy_gym/utils/make_env_helpers.py b/fancy_gym/utils/make_env_helpers.py index 0f832ae..b0bfe8b 100644 --- a/fancy_gym/utils/make_env_helpers.py +++ b/fancy_gym/utils/make_env_helpers.py @@ -10,15 +10,14 @@ import numpy as np from gym.envs.registration import register, registry try: - from dm_control import suite, manipulation, composer - from dm_control.rl import control + from dm_control import suite, manipulation except ImportError: pass try: import metaworld except Exception: - # catch Exception due to Mujoco-py + # catch Exception as Import error does not catch missing mujoco-py pass import fancy_gym @@ -227,7 +226,7 @@ def make_bb_env_helper(**kwargs): def make_dmc( - env_id: Union[str, composer.Environment, control.Environment], + env_id: str, seed: int = None, visualize_reward: bool = True, time_limit: Union[None, float] = None, @@ -274,7 +273,7 @@ def make_dmc( return env -def make_metaworld(env_id, seed, **kwargs): +def make_metaworld(env_id: str, seed: int, **kwargs): if env_id not in metaworld.ML1.ENV_NAMES: raise ValueError(f'Specified environment "{env_id}" not present in metaworld ML1.') diff --git a/setup.py b/setup.py index 3f67e1a..3d428e2 100644 --- a/setup.py +++ b/setup.py @@ -27,8 +27,7 @@ setup( ], extras_require=extras, install_requires=[ - 'gym>=0.24.0', - 'mujoco==2.2.0', + 'gym[mujoco]>=0.24.0', 'mp_pytorch @ git+https://github.com/ALRhub/MP_PyTorch.git@main' ], packages=[package for package in find_packages() if package.startswith("fancy_gym")], From e311ee137a35adc235b770741ddb403648ef1117 Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 14 Jul 2022 17:43:27 +0200 Subject: [PATCH 095/104] minor bug fixes --- fancy_gym/black_box/black_box_wrapper.py | 8 ++++---- .../black_box/factory/trajectory_generator_factory.py | 4 +++- fancy_gym/envs/__init__.py | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/fancy_gym/black_box/black_box_wrapper.py b/fancy_gym/black_box/black_box_wrapper.py index fb2bbbf..df2206a 100644 --- a/fancy_gym/black_box/black_box_wrapper.py +++ b/fancy_gym/black_box/black_box_wrapper.py @@ -50,7 +50,7 @@ class BlackBoxWrapper(gym.ObservationWrapper): self.tracking_controller = tracking_controller # self.time_steps = np.linspace(0, self.duration, self.traj_steps) # self.traj_gen.set_mp_times(self.time_steps) - self.traj_gen.set_duration(np.array([self.duration]), np.array([self.dt])) + self.traj_gen.set_duration(self.duration - self.dt, self.dt) # reward computation self.reward_aggregation = reward_aggregation @@ -78,8 +78,8 @@ class BlackBoxWrapper(gym.ObservationWrapper): self.traj_gen.set_boundary_conditions( bc_time=np.array(0) if not self.do_replanning else np.array([self.current_traj_steps * self.dt]), bc_pos=self.current_pos, bc_vel=self.current_vel) - self.traj_gen.set_duration(None if self.learn_sub_trajectories else np.array([self.duration]), - np.array([self.dt])) + # TODO remove the - self.dt after Bruces fix. + self.traj_gen.set_duration(None if self.learn_sub_trajectories else self.duration - self.dt, self.dt) traj_dict = self.traj_gen.get_trajs(get_pos=True, get_vel=True) trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] @@ -87,7 +87,7 @@ class BlackBoxWrapper(gym.ObservationWrapper): def _get_traj_gen_action_space(self): """This function can be used to set up an individual space for the parameters of the traj_gen.""" - min_action_bounds, max_action_bounds = self.traj_gen.get_param_bounds() + min_action_bounds, max_action_bounds = self.traj_gen.get_params_bounds().t() action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), dtype=self.env.action_space.dtype) return action_space diff --git a/fancy_gym/black_box/factory/trajectory_generator_factory.py b/fancy_gym/black_box/factory/trajectory_generator_factory.py index 2b93a6c..5a36fdd 100644 --- a/fancy_gym/black_box/factory/trajectory_generator_factory.py +++ b/fancy_gym/black_box/factory/trajectory_generator_factory.py @@ -12,7 +12,9 @@ def get_trajectory_generator( return ProMP(basis_generator, action_dim, **kwargs) elif trajectory_generator_type == "dmp": return DMP(basis_generator, action_dim, **kwargs) - elif trajectory_generator_type == 'idmp': + elif trajectory_generator_type == 'prodmp': + from mp_pytorch.basis_gn import ProDMPBasisGenerator + assert isinstance(basis_generator, ProDMPBasisGenerator) return ProDMP(basis_generator, action_dim, **kwargs) else: raise ValueError(f"Specified movement primitive type {trajectory_generator_type} not supported, " diff --git a/fancy_gym/envs/__init__.py b/fancy_gym/envs/__init__.py index 9f0299e..ddd9c68 100644 --- a/fancy_gym/envs/__init__.py +++ b/fancy_gym/envs/__init__.py @@ -126,7 +126,7 @@ for _dims in [5, 7]: register( id=f'Reacher{_dims}dSparse-v0', entry_point='fancy_gym.envs.mujoco:ReacherEnv', - max_episode_steps=MAX_EPISODE_STEPS_REACHER, + max_episode_steps=5, kwargs={ "sparse": True, 'reward_weight': 200, From 50d44b2989f46af9cc69170f76f5121fc3dbfbcd Mon Sep 17 00:00:00 2001 From: Fabian Date: Fri, 15 Jul 2022 09:07:37 +0200 Subject: [PATCH 096/104] reverted debug change for reacher --- fancy_gym/envs/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fancy_gym/envs/__init__.py b/fancy_gym/envs/__init__.py index ddd9c68..a00570c 100644 --- a/fancy_gym/envs/__init__.py +++ b/fancy_gym/envs/__init__.py @@ -126,7 +126,7 @@ for _dims in [5, 7]: register( id=f'Reacher{_dims}dSparse-v0', entry_point='fancy_gym.envs.mujoco:ReacherEnv', - max_episode_steps=5, + max_episode_steps=200, kwargs={ "sparse": True, 'reward_weight': 200, From 3341cc6f731ffd6f49c9eb7db45a894922733e68 Mon Sep 17 00:00:00 2001 From: Onur Date: Tue, 19 Jul 2022 12:17:02 +0200 Subject: [PATCH 097/104] fix body pos set bug in hj --- fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py b/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py index 22e706a..63f40c8 100644 --- a/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py +++ b/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py @@ -128,7 +128,7 @@ class HopperJumpEnv(HopperEnv): # self.goal = self.np_random.uniform(0.3, 1.35, 1)[0] self.goal = np.concatenate([self.np_random.uniform(0.3, 1.35, 1), np.zeros(2, )]) # self.sim.model.body_pos[self.sim.model.body_name2id('goal_site_body')] = self.goal - self.data.body('goal_site_body').xpos[:] = np.copy(self.goal) + self.model.body('goal_site_body').pos[:] = np.copy(self.goal) self.max_height = 0 self._steps = 0 From ce795669a99a788233d7d9761f314b523dcc690d Mon Sep 17 00:00:00 2001 From: Fabian Date: Mon, 25 Jul 2022 11:18:05 +0200 Subject: [PATCH 098/104] minor bug fixes --- fancy_gym/black_box/black_box_wrapper.py | 6 +++--- fancy_gym/utils/make_env_helpers.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fancy_gym/black_box/black_box_wrapper.py b/fancy_gym/black_box/black_box_wrapper.py index df2206a..f7cfb4e 100644 --- a/fancy_gym/black_box/black_box_wrapper.py +++ b/fancy_gym/black_box/black_box_wrapper.py @@ -158,12 +158,12 @@ class BlackBoxWrapper(gym.ObservationWrapper): if self.verbose >= 2: infos['positions'] = trajectory infos['velocities'] = velocity - infos['step_actions'] = actions[:t + 1] + infos['step_actions'] = actions[:t] infos['step_observations'] = observations[:t + 1] - infos['step_rewards'] = rewards[:t + 1] + infos['step_rewards'] = rewards[:t] infos['trajectory_length'] = t + 1 - trajectory_return = self.reward_aggregation(rewards[:t + 1]) + trajectory_return = self.reward_aggregation(rewards[:t]) return self.observation(obs), trajectory_return, done, infos def render(self, **kwargs): diff --git a/fancy_gym/utils/make_env_helpers.py b/fancy_gym/utils/make_env_helpers.py index b0bfe8b..e4537e6 100644 --- a/fancy_gym/utils/make_env_helpers.py +++ b/fancy_gym/utils/make_env_helpers.py @@ -148,9 +148,9 @@ def make_bb( raise ValueError('Cannot used sub-trajectory learning and replanning together.') # add time_step observation when replanning - if (learn_sub_trajs or do_replanning) and not any(issubclass(w, TimeAwareObservation) for w in kwargs['wrappers']): + if (learn_sub_trajs or do_replanning) and not any(issubclass(w, TimeAwareObservation) for w in wrappers): # Add as first wrapper in order to alter observation - kwargs['wrappers'].insert(0, TimeAwareObservation) + wrappers.insert(0, TimeAwareObservation) env = _make_wrapped_env(env_id=env_id, wrappers=wrappers, seed=seed, **kwargs) From 4aacd71ed36cfa11cd8d272bbfb0eec7cb3dcd8c Mon Sep 17 00:00:00 2001 From: Fabian Date: Tue, 26 Jul 2022 10:33:59 +0200 Subject: [PATCH 099/104] minor bug fixes --- fancy_gym/black_box/black_box_wrapper.py | 41 +++++++++++++---------- fancy_gym/utils/time_aware_observation.py | 5 +-- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/fancy_gym/black_box/black_box_wrapper.py b/fancy_gym/black_box/black_box_wrapper.py index f7cfb4e..fb7328c 100644 --- a/fancy_gym/black_box/black_box_wrapper.py +++ b/fancy_gym/black_box/black_box_wrapper.py @@ -75,19 +75,24 @@ class BlackBoxWrapper(gym.ObservationWrapper): clipped_params = np.clip(action, self.traj_gen_action_space.low, self.traj_gen_action_space.high) self.traj_gen.set_params(clipped_params) # TODO: is this correct for replanning? Do we need to adjust anything here? - self.traj_gen.set_boundary_conditions( - bc_time=np.array(0) if not self.do_replanning else np.array([self.current_traj_steps * self.dt]), - bc_pos=self.current_pos, bc_vel=self.current_vel) - # TODO remove the - self.dt after Bruces fix. + bc_time = np.array(0 if not self.do_replanning else self.current_traj_steps * self.dt) + self.traj_gen.set_boundary_conditions(bc_time, self.current_pos, self.current_vel) + # TODO: remove the - self.dt after Bruces fix. self.traj_gen.set_duration(None if self.learn_sub_trajectories else self.duration - self.dt, self.dt) - traj_dict = self.traj_gen.get_trajs(get_pos=True, get_vel=True) - trajectory_tensor, velocity_tensor = traj_dict['pos'], traj_dict['vel'] + # traj_dict = self.traj_gen.get_trajs(get_pos=True, get_vel=True) + trajectory = get_numpy(self.traj_gen.get_traj_pos()) + velocity = get_numpy(self.traj_gen.get_traj_vel()) - return get_numpy(trajectory_tensor), get_numpy(velocity_tensor) + if self.do_replanning: + # Remove first part of trajectory as this is already over + trajectory = trajectory[self.current_traj_steps:] + velocity = velocity[self.current_traj_steps:] + + return trajectory, velocity def _get_traj_gen_action_space(self): """This function can be used to set up an individual space for the parameters of the traj_gen.""" - min_action_bounds, max_action_bounds = self.traj_gen.get_params_bounds().t() + min_action_bounds, max_action_bounds = self.traj_gen.get_params_bounds() action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), dtype=self.env.action_space.dtype) return action_space @@ -105,13 +110,13 @@ class BlackBoxWrapper(gym.ObservationWrapper): return self._get_traj_gen_action_space() def _get_observation_space(self): - mask = self.env.context_mask - if not self.return_context_observation: + if self.return_context_observation: + mask = self.env.context_mask # return full observation - mask = np.ones_like(mask, dtype=bool) - min_obs_bound = self.env.observation_space.low[mask] - max_obs_bound = self.env.observation_space.high[mask] - return spaces.Box(low=min_obs_bound, high=max_obs_bound, dtype=self.env.observation_space.dtype) + min_obs_bound = self.env.observation_space.low[mask] + max_obs_bound = self.env.observation_space.high[mask] + return spaces.Box(low=min_obs_bound, high=max_obs_bound, dtype=self.env.observation_space.dtype) + return self.env.observation_space def step(self, action: np.ndarray): """ This function generates a trajectory based on a MP and then does the usual loop over reset and step""" @@ -152,18 +157,18 @@ class BlackBoxWrapper(gym.ObservationWrapper): t + 1 + self.current_traj_steps): break - infos.update({k: v[:t + 1] for k, v in infos.items()}) + infos.update({k: v[:t] for k, v in infos.items()}) self.current_traj_steps += t + 1 if self.verbose >= 2: infos['positions'] = trajectory infos['velocities'] = velocity - infos['step_actions'] = actions[:t] + infos['step_actions'] = actions[:t + 1] infos['step_observations'] = observations[:t + 1] - infos['step_rewards'] = rewards[:t] + infos['step_rewards'] = rewards[:t + 1] infos['trajectory_length'] = t + 1 - trajectory_return = self.reward_aggregation(rewards[:t]) + trajectory_return = self.reward_aggregation(rewards[:t + 1]) return self.observation(obs), trajectory_return, done, infos def render(self, **kwargs): diff --git a/fancy_gym/utils/time_aware_observation.py b/fancy_gym/utils/time_aware_observation.py index 4fa0d74..b2cbc78 100644 --- a/fancy_gym/utils/time_aware_observation.py +++ b/fancy_gym/utils/time_aware_observation.py @@ -40,9 +40,10 @@ class TimeAwareObservation(gym.ObservationWrapper): high = np.append(self.observation_space.high, 1.0) self.observation_space = Box(low, high, dtype=self.observation_space.dtype) self.t = 0 + self._max_episode_steps = env.spec.max_episode_steps def observation(self, observation): - """Adds to the observation with the current time step. + """Adds to the observation with the current time step normalized with max steps. Args: observation: The observation to add the time step to @@ -50,7 +51,7 @@ class TimeAwareObservation(gym.ObservationWrapper): Returns: The observation with the time step appended to """ - return np.append(observation, self.t/self.env.spec.max_episode_steps) + return np.append(observation, self.t / self._max_episode_steps) def step(self, action): """Steps through the environment, incrementing the time step. From 623adaacd8471cb8fd5e22b639e6eb995606401b Mon Sep 17 00:00:00 2001 From: ottofabian Date: Tue, 26 Jul 2022 10:48:19 +0200 Subject: [PATCH 100/104] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3d428e2..9c539da 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ setup( ], extras_require=extras, install_requires=[ - 'gym[mujoco]>=0.24.0', + 'gym[mujoco]<0.25.0,>=0.24.0', 'mp_pytorch @ git+https://github.com/ALRhub/MP_PyTorch.git@main' ], packages=[package for package in find_packages() if package.startswith("fancy_gym")], From 7957632eb058fb90a79d47525363b5abb01b54ce Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 27 Jul 2022 16:34:35 +0200 Subject: [PATCH 101/104] minor bug fixes --- fancy_gym/black_box/black_box_wrapper.py | 19 ++++++++++--------- fancy_gym/utils/make_env_helpers.py | 7 ++++++- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/fancy_gym/black_box/black_box_wrapper.py b/fancy_gym/black_box/black_box_wrapper.py index fb7328c..65b61ca 100644 --- a/fancy_gym/black_box/black_box_wrapper.py +++ b/fancy_gym/black_box/black_box_wrapper.py @@ -67,26 +67,27 @@ class BlackBoxWrapper(gym.ObservationWrapper): def observation(self, observation): # return context space if we are - obs = observation[self.env.context_mask] if self.return_context_observation else observation + if self.return_context_observation: + observation = observation[self.env.context_mask] # cast dtype because metaworld returns incorrect that throws gym error - return obs.astype(self.observation_space.dtype) + return observation.astype(self.observation_space.dtype) def get_trajectory(self, action: np.ndarray) -> Tuple: clipped_params = np.clip(action, self.traj_gen_action_space.low, self.traj_gen_action_space.high) self.traj_gen.set_params(clipped_params) - # TODO: is this correct for replanning? Do we need to adjust anything here? bc_time = np.array(0 if not self.do_replanning else self.current_traj_steps * self.dt) + # TODO we could think about initializing with the previous desired value in order to have a smooth transition + # at least from the planning point of view. self.traj_gen.set_boundary_conditions(bc_time, self.current_pos, self.current_vel) - # TODO: remove the - self.dt after Bruces fix. - self.traj_gen.set_duration(None if self.learn_sub_trajectories else self.duration - self.dt, self.dt) + duration = None if self.learn_sub_trajectories else self.duration + self.traj_gen.set_duration(duration, self.dt) # traj_dict = self.traj_gen.get_trajs(get_pos=True, get_vel=True) trajectory = get_numpy(self.traj_gen.get_traj_pos()) velocity = get_numpy(self.traj_gen.get_traj_vel()) - if self.do_replanning: - # Remove first part of trajectory as this is already over - trajectory = trajectory[self.current_traj_steps:] - velocity = velocity[self.current_traj_steps:] + # Remove first element of trajectory as this is the current position and velocity + trajectory = trajectory[1:] + velocity = velocity[1:] return trajectory, velocity diff --git a/fancy_gym/utils/make_env_helpers.py b/fancy_gym/utils/make_env_helpers.py index e4537e6..5221423 100644 --- a/fancy_gym/utils/make_env_helpers.py +++ b/fancy_gym/utils/make_env_helpers.py @@ -1,3 +1,4 @@ +import logging import re import uuid from collections.abc import MutableMapping @@ -310,7 +311,11 @@ def make_gym(env_id, seed, **kwargs): """ # Getting the existing keywords to allow for nested dict updates for BB envs # gym only allows for non nested updates. - all_kwargs = deepcopy(registry.get(env_id).kwargs) + try: + all_kwargs = deepcopy(registry.get(env_id).kwargs) + except AttributeError as e: + logging.error(f'The gym environment with id {env_id} could not been found.') + raise e nested_update(all_kwargs, kwargs) kwargs = all_kwargs From b3762fb09925166cfe505ca777a2d0ca8308c4d9 Mon Sep 17 00:00:00 2001 From: ottofabian Date: Thu, 28 Jul 2022 10:08:11 +0200 Subject: [PATCH 102/104] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3d428e2..9c539da 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ setup( ], extras_require=extras, install_requires=[ - 'gym[mujoco]>=0.24.0', + 'gym[mujoco]<0.25.0,>=0.24.0', 'mp_pytorch @ git+https://github.com/ALRhub/MP_PyTorch.git@main' ], packages=[package for package in find_packages() if package.startswith("fancy_gym")], From 491abece229d0b67ced7d28c2289de27a7a25aa0 Mon Sep 17 00:00:00 2001 From: ottofabian Date: Mon, 8 Aug 2022 08:21:28 +0200 Subject: [PATCH 103/104] Update black_box_wrapper.py --- fancy_gym/black_box/black_box_wrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fancy_gym/black_box/black_box_wrapper.py b/fancy_gym/black_box/black_box_wrapper.py index df2206a..119d923 100644 --- a/fancy_gym/black_box/black_box_wrapper.py +++ b/fancy_gym/black_box/black_box_wrapper.py @@ -87,7 +87,7 @@ class BlackBoxWrapper(gym.ObservationWrapper): def _get_traj_gen_action_space(self): """This function can be used to set up an individual space for the parameters of the traj_gen.""" - min_action_bounds, max_action_bounds = self.traj_gen.get_params_bounds().t() + min_action_bounds, max_action_bounds = self.traj_gen.get_params_bounds() action_space = gym.spaces.Box(low=min_action_bounds.numpy(), high=max_action_bounds.numpy(), dtype=self.env.action_space.dtype) return action_space From bdea3badfffbe13b021b4bae7588ab2f24cdb8a3 Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 18 Aug 2022 09:04:38 +0200 Subject: [PATCH 104/104] updated for gym 0.25.1 --- fancy_gym/black_box/black_box_wrapper.py | 4 +- fancy_gym/black_box/raw_interface_wrapper.py | 7 +- fancy_gym/envs/__init__.py | 2 +- .../base_reacher/base_reacher.py | 23 +-- .../base_reacher/base_reacher_direct.py | 4 +- .../base_reacher/base_reacher_torque.py | 4 +- .../envs/mujoco/hopper_jump/hopper_jump.py | 150 +++++++++--------- .../envs/mujoco/hopper_jump/mp_wrapper.py | 2 +- fancy_gym/meta/base_metaworld_mp_wrapper.py | 3 +- setup.py | 4 +- 10 files changed, 93 insertions(+), 110 deletions(-) diff --git a/fancy_gym/black_box/black_box_wrapper.py b/fancy_gym/black_box/black_box_wrapper.py index 65b61ca..4e3b160 100644 --- a/fancy_gym/black_box/black_box_wrapper.py +++ b/fancy_gym/black_box/black_box_wrapper.py @@ -86,8 +86,8 @@ class BlackBoxWrapper(gym.ObservationWrapper): velocity = get_numpy(self.traj_gen.get_traj_vel()) # Remove first element of trajectory as this is the current position and velocity - trajectory = trajectory[1:] - velocity = velocity[1:] + # trajectory = trajectory[1:] + # velocity = velocity[1:] return trajectory, velocity diff --git a/fancy_gym/black_box/raw_interface_wrapper.py b/fancy_gym/black_box/raw_interface_wrapper.py index 7b2e996..02945a1 100644 --- a/fancy_gym/black_box/raw_interface_wrapper.py +++ b/fancy_gym/black_box/raw_interface_wrapper.py @@ -1,4 +1,3 @@ -from abc import abstractmethod from typing import Union, Tuple import gym @@ -23,7 +22,6 @@ class RawInterfaceWrapper(gym.Wrapper): return np.ones(self.env.observation_space.shape[0], dtype=bool) @property - @abstractmethod def current_pos(self) -> Union[float, int, np.ndarray, Tuple]: """ Returns the current position of the action/control dimension. @@ -32,10 +30,9 @@ class RawInterfaceWrapper(gym.Wrapper): it should, however, be implemented regardless. E.g. The joint positions that are directly or indirectly controlled by the action. """ - raise NotImplementedError() + raise NotImplementedError @property - @abstractmethod def current_vel(self) -> Union[float, int, np.ndarray, Tuple]: """ Returns the current velocity of the action/control dimension. @@ -44,7 +41,7 @@ class RawInterfaceWrapper(gym.Wrapper): it should, however, be implemented regardless. E.g. The joint velocities that are directly or indirectly controlled by the action. """ - raise NotImplementedError() + raise NotImplementedError @property def dt(self) -> float: diff --git a/fancy_gym/envs/__init__.py b/fancy_gym/envs/__init__.py index a00570c..9f0299e 100644 --- a/fancy_gym/envs/__init__.py +++ b/fancy_gym/envs/__init__.py @@ -126,7 +126,7 @@ for _dims in [5, 7]: register( id=f'Reacher{_dims}dSparse-v0', entry_point='fancy_gym.envs.mujoco:ReacherEnv', - max_episode_steps=200, + max_episode_steps=MAX_EPISODE_STEPS_REACHER, kwargs={ "sparse": True, 'reward_weight': 200, diff --git a/fancy_gym/envs/classic_control/base_reacher/base_reacher.py b/fancy_gym/envs/classic_control/base_reacher/base_reacher.py index abfe2ca..f2ba135 100644 --- a/fancy_gym/envs/classic_control/base_reacher/base_reacher.py +++ b/fancy_gym/envs/classic_control/base_reacher/base_reacher.py @@ -1,4 +1,3 @@ -from abc import ABC, abstractmethod from typing import Union, Tuple, Optional import gym @@ -10,7 +9,7 @@ from gym.utils import seeding from fancy_gym.envs.classic_control.utils import intersect -class BaseReacherEnv(gym.Env, ABC): +class BaseReacherEnv(gym.Env): """ Base class for all reaching environments. """ @@ -87,13 +86,6 @@ class BaseReacherEnv(gym.Env, ABC): return self._get_obs().copy() - @abstractmethod - def step(self, action: np.ndarray): - """ - A single step with action in angular velocity space - """ - raise NotImplementedError - def _update_joints(self): """ update joints to get new end-effector position. The other links are only required for rendering. @@ -120,27 +112,24 @@ class BaseReacherEnv(gym.Env, ABC): return True return False - @abstractmethod def _get_reward(self, action: np.ndarray) -> (float, dict): - pass + raise NotImplementedError - @abstractmethod def _get_obs(self) -> np.ndarray: - pass + raise NotImplementedError - @abstractmethod def _check_collisions(self) -> bool: - pass + raise NotImplementedError - @abstractmethod def _terminate(self, info) -> bool: - return False + raise NotImplementedError def seed(self, seed=None): self.np_random, seed = seeding.np_random(seed) return [seed] def close(self): + super(BaseReacherEnv, self).close() del self.fig @property diff --git a/fancy_gym/envs/classic_control/base_reacher/base_reacher_direct.py b/fancy_gym/envs/classic_control/base_reacher/base_reacher_direct.py index 0e44033..ab21b39 100644 --- a/fancy_gym/envs/classic_control/base_reacher/base_reacher_direct.py +++ b/fancy_gym/envs/classic_control/base_reacher/base_reacher_direct.py @@ -1,12 +1,10 @@ -from abc import ABC - import numpy as np from gym import spaces from fancy_gym.envs.classic_control.base_reacher.base_reacher import BaseReacherEnv -class BaseReacherDirectEnv(BaseReacherEnv, ABC): +class BaseReacherDirectEnv(BaseReacherEnv): """ Base class for directly controlled reaching environments """ diff --git a/fancy_gym/envs/classic_control/base_reacher/base_reacher_torque.py b/fancy_gym/envs/classic_control/base_reacher/base_reacher_torque.py index 79f3005..7364948 100644 --- a/fancy_gym/envs/classic_control/base_reacher/base_reacher_torque.py +++ b/fancy_gym/envs/classic_control/base_reacher/base_reacher_torque.py @@ -1,12 +1,10 @@ -from abc import ABC - import numpy as np from gym import spaces from fancy_gym.envs.classic_control.base_reacher.base_reacher import BaseReacherEnv -class BaseReacherTorqueEnv(BaseReacherEnv, ABC): +class BaseReacherTorqueEnv(BaseReacherEnv): """ Base class for torque controlled reaching environments """ diff --git a/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py b/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py index 63f40c8..da9ac4d 100644 --- a/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py +++ b/fancy_gym/envs/mujoco/hopper_jump/hopper_jump.py @@ -98,7 +98,7 @@ class HopperJumpEnv(HopperEnv): if not self.sparse or (self.sparse and self._steps >= MAX_EPISODE_STEPS_HOPPERJUMP): healthy_reward = self.healthy_reward distance_reward = -goal_dist * self._dist_weight - height_reward = (self.max_height if self.sparse else self.get_body_com("torso")[2]) * self._height_weight + height_reward = (self.max_height if self.sparse else height_after) * self._height_weight contact_reward = -(self.contact_dist or 5) * self._contact_weight rewards = self._forward_reward_weight * (distance_reward + height_reward + contact_reward + healthy_reward) @@ -123,7 +123,7 @@ class HopperJumpEnv(HopperEnv): return np.concatenate((super(HopperJumpEnv, self)._get_obs(), goal_dist.copy(), self.goal[:1])) def reset_model(self): - super(HopperJumpEnv, self).reset_model() + # super(HopperJumpEnv, self).reset_model() # self.goal = self.np_random.uniform(0.3, 1.35, 1)[0] self.goal = np.concatenate([self.np_random.uniform(0.3, 1.35, 1), np.zeros(2, )]) @@ -176,76 +176,76 @@ class HopperJumpEnv(HopperEnv): return True return False -# TODO is that needed? if so test it -class HopperJumpStepEnv(HopperJumpEnv): - - def __init__(self, - xml_file='hopper_jump.xml', - forward_reward_weight=1.0, - ctrl_cost_weight=1e-3, - healthy_reward=1.0, - height_weight=3, - dist_weight=3, - terminate_when_unhealthy=False, - healthy_state_range=(-100.0, 100.0), - healthy_z_range=(0.5, float('inf')), - healthy_angle_range=(-float('inf'), float('inf')), - reset_noise_scale=5e-3, - exclude_current_positions_from_observation=False - ): - - self._height_weight = height_weight - self._dist_weight = dist_weight - super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, - healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, - exclude_current_positions_from_observation) - - def step(self, action): - self._steps += 1 - - self.do_simulation(action, self.frame_skip) - - height_after = self.get_body_com("torso")[2] - site_pos_after = self.data.site('foot_site').xpos.copy() - self.max_height = max(height_after, self.max_height) - - ctrl_cost = self.control_cost(action) - healthy_reward = self.healthy_reward - height_reward = self._height_weight * height_after - goal_dist = np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0])) - goal_dist_reward = -self._dist_weight * goal_dist - dist_reward = self._forward_reward_weight * (goal_dist_reward + height_reward) - - rewards = dist_reward + healthy_reward - costs = ctrl_cost - done = False - - # This is only for logging the distance to goal when first having the contact - has_floor_contact = self._is_floor_foot_contact() if not self.contact_with_floor else False - - if not self.init_floor_contact: - self.init_floor_contact = has_floor_contact - if self.init_floor_contact and not self.has_left_floor: - self.has_left_floor = not has_floor_contact - if not self.contact_with_floor and self.has_left_floor: - self.contact_with_floor = has_floor_contact - - if self.contact_dist is None and self.contact_with_floor: - self.contact_dist = goal_dist - - ############################################################## - - observation = self._get_obs() - reward = rewards - costs - info = { - 'height': height_after, - 'x_pos': site_pos_after, - 'max_height': copy.copy(self.max_height), - 'goal': copy.copy(self.goal), - 'goal_dist': goal_dist, - 'height_rew': height_reward, - 'healthy_reward': healthy_reward, - 'healthy': copy.copy(self.is_healthy), - 'contact_dist': copy.copy(self.contact_dist) or 0 - } - return observation, reward, done, info +# # TODO is that needed? if so test it +# class HopperJumpStepEnv(HopperJumpEnv): +# +# def __init__(self, +# xml_file='hopper_jump.xml', +# forward_reward_weight=1.0, +# ctrl_cost_weight=1e-3, +# healthy_reward=1.0, +# height_weight=3, +# dist_weight=3, +# terminate_when_unhealthy=False, +# healthy_state_range=(-100.0, 100.0), +# healthy_z_range=(0.5, float('inf')), +# healthy_angle_range=(-float('inf'), float('inf')), +# reset_noise_scale=5e-3, +# exclude_current_positions_from_observation=False +# ): +# +# self._height_weight = height_weight +# self._dist_weight = dist_weight +# super().__init__(xml_file, forward_reward_weight, ctrl_cost_weight, healthy_reward, terminate_when_unhealthy, +# healthy_state_range, healthy_z_range, healthy_angle_range, reset_noise_scale, +# exclude_current_positions_from_observation) +# +# def step(self, action): +# self._steps += 1 +# +# self.do_simulation(action, self.frame_skip) +# +# height_after = self.get_body_com("torso")[2] +# site_pos_after = self.data.site('foot_site').xpos.copy() +# self.max_height = max(height_after, self.max_height) +# +# ctrl_cost = self.control_cost(action) +# healthy_reward = self.healthy_reward +# height_reward = self._height_weight * height_after +# goal_dist = np.linalg.norm(site_pos_after - np.array([self.goal, 0, 0])) +# goal_dist_reward = -self._dist_weight * goal_dist +# dist_reward = self._forward_reward_weight * (goal_dist_reward + height_reward) +# +# rewards = dist_reward + healthy_reward +# costs = ctrl_cost +# done = False +# +# # This is only for logging the distance to goal when first having the contact +# has_floor_contact = self._is_floor_foot_contact() if not self.contact_with_floor else False +# +# if not self.init_floor_contact: +# self.init_floor_contact = has_floor_contact +# if self.init_floor_contact and not self.has_left_floor: +# self.has_left_floor = not has_floor_contact +# if not self.contact_with_floor and self.has_left_floor: +# self.contact_with_floor = has_floor_contact +# +# if self.contact_dist is None and self.contact_with_floor: +# self.contact_dist = goal_dist +# +# ############################################################## +# +# observation = self._get_obs() +# reward = rewards - costs +# info = { +# 'height': height_after, +# 'x_pos': site_pos_after, +# 'max_height': copy.copy(self.max_height), +# 'goal': copy.copy(self.goal), +# 'goal_dist': goal_dist, +# 'height_rew': height_reward, +# 'healthy_reward': healthy_reward, +# 'healthy': copy.copy(self.is_healthy), +# 'contact_dist': copy.copy(self.contact_dist) or 0 +# } +# return observation, reward, done, info diff --git a/fancy_gym/envs/mujoco/hopper_jump/mp_wrapper.py b/fancy_gym/envs/mujoco/hopper_jump/mp_wrapper.py index d46fa92..ed95b3d 100644 --- a/fancy_gym/envs/mujoco/hopper_jump/mp_wrapper.py +++ b/fancy_gym/envs/mujoco/hopper_jump/mp_wrapper.py @@ -14,7 +14,7 @@ class MPWrapper(RawInterfaceWrapper): [False] * (2 + int(not self.exclude_current_positions_from_observation)), # position [True] * 3, # set to true if randomize initial pos [False] * 6, # velocity - [True] * 3, # goal distance + [False] * 3, # goal distance [True] # goal ]) diff --git a/fancy_gym/meta/base_metaworld_mp_wrapper.py b/fancy_gym/meta/base_metaworld_mp_wrapper.py index ae800ff..4029e28 100644 --- a/fancy_gym/meta/base_metaworld_mp_wrapper.py +++ b/fancy_gym/meta/base_metaworld_mp_wrapper.py @@ -1,4 +1,3 @@ -from abc import ABC from typing import Tuple, Union import numpy as np @@ -6,7 +5,7 @@ import numpy as np from fancy_gym.black_box.raw_interface_wrapper import RawInterfaceWrapper -class BaseMetaworldMPWrapper(RawInterfaceWrapper, ABC): +class BaseMetaworldMPWrapper(RawInterfaceWrapper): @property def current_pos(self) -> Union[float, int, np.ndarray]: r_close = self.env.data.get_joint_qpos("r_close") diff --git a/setup.py b/setup.py index 9c539da..1148e85 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,9 @@ from setuptools import setup, find_packages extras = { "dmc": ["dm_control>=1.0.1"], "metaworld": ["metaworld @ git+https://github.com/rlworkgroup/metaworld.git@master#egg=metaworld", - 'mujoco-py<2.2,>=2.1'], + 'mujoco-py<2.2,>=2.1', + 'scipy' + ], } # All dependencies

F)FIVll2 z>=O~9uhyN#V>BDF_DU63?PvI01w1c|4uLkOay89{BcIQ>?X!EblJYO4)py%zZ`Bw%28N%v<%M_l&K-(C9n2jW=xgKlGzy>Hq)$ diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/upper_arm_link_fine.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/upper_arm_link_fine.stl deleted file mode 100644 index 76353ae570a9dec25fd75b80ffa45a19da5f310e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 615684 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 z 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 K4K2#B?MFQjkK^9RUNC1&VARq{VkdrH$EJBb) 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 diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_pitch_link_convex_decomposition_p2.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/wrist_pitch_link_convex_decomposition_p2.stl deleted file mode 100644 index d00cac16e816a761e692145057ff1d707aa86853..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34284 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�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

{CzVacUwYRpnS6b7pm2 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 diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_palm_link_convex_decomposition_p4.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/bhand_palm_link_convex_decomposition_p4.stl deleted file mode 100644 index 8448a3f2c08bf9f3b27288f059c311910be7d057..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6884 zcmeHLU5Hjy6g?%F6frOlG9*Z0SkqX@;6VBPDJ5z%HjES0gE$ll_99dd25I*`XpQ7g z5mHtVJ>*+|6BX2Vy+ja$1m#PO6#8aFq`ky|f_B$A-`d~0^L_V1@AtwCd+t5^ti9J> zXPB`H|%6Uq>6|9vp?4Xa|qMZ3oivmk&4f3otkecJq#rWMIeZ9gHFmj>1f|1IGKy z_N5OzyWlbSMdyXR>6hVT=AC05j3N(?0tW4Xv2JcEeSTrErE|f)Ghj}l4v?}@Mvp0M_ zu0FUnnf&2|w-qB!#iRZ3BOBV77qN?Xd-bjXKT|n|`*lsS`1Z*ho}WD)|MKb9m2E4Q z=3%j4yL}88jopiTI_xeUJbd=T)&rianN9a3FO7yg*1xhk8F9y>xxpvrDE?P0hTxf|5s_c+MS}S=oH|(-&JGetxtG zHDInA$@+#e+M|*}u9z*N?P4JQ?1`bT>`P8pR0cd~`@w}6qQo}woEyFwwYID}3z43`KYLBj8Y8R&i#BNN~ixgQyc$#s;0anc4FYYt|;d&zx8Tk z*9(!?F4rAAm@V*VJD1hGB{lc4BVOc`jcTZkIw6bVH7Gf?yLps(u;U;?dIJNG*H)~N zEL902WK`zi`i<)30Tz5tHadm{PNaY2D%j_Wyz^Z~s%E_; zUym{j**|i-fvv$9a{&X{((d#}%MbZFckTRO`o&jMUWu#}JgD%@7PSW-{EkzM!fvU` zP(0W+K8A-@P`!b{Xv5s};}`aJ*`0HHt!3U*LGiF?Jw{6~j1xp9?AmFdH!5b12nECE zfoRJyL?wn7;yHJEE}32)p&o5fqIG9P$d2kTxYOaR9^k59ZQ#+nbFzXGp{-zeWPEiygT;$T7&{{D zsstXg1}$EUV(jpy#xNdFhzz47lAiTQcAcy4QD9N~IXe#C(+=E9FR{J^rgeSL4#lYM zQQ(Ifg-wNnUD{pU!onBb`#1{kxmLVK;jX55Tr1@m;vrF0_o#mL=-)-FdsIKJ*bSgv z@>Z@yb{u%n8y_0_v(zgz7Jb5EyF?UXozG8bY23Gf|-n+A~Yv%_rl|TE) zDZ`)cdD17--lMQn>%L1oc;rq?*7dO_WH+$Aq`F51&Y*Vgkg(Z5V6(4O_b6~x-J`<) deV`290aZOgPt`pNoJfbWKA64t-7egt{sRJlv@rkx diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/elbow_link_convex.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/elbow_link_convex.stl deleted file mode 100644 index b34963ddcb5643d9f3e002f36b3a71d28d02e1b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16484 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 F{{s>bC9?nk diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/forearm_link_convex_decomposition_p1.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/forearm_link_convex_decomposition_p1.stl deleted file mode 100644 index e6aa6b688d8ac9918178db0e4218341710d3b740..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33484 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 diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/forearm_link_convex_decomposition_p2.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/forearm_link_convex_decomposition_p2.stl deleted file mode 100644 index 667902ecb3262a730276a1d8b83f8e026032800c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 205484 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 S>v9zNPS_IOD)O(a&G3J^lq0VI diff --git a/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/forearm_link_fine.stl b/alr_envs/alr/mujoco/gym_table_tennis/envs/assets/meshes/forearm_link_fine.stl deleted file mode 100644 index ed66bbba022ab3286ece979f85726a8f4b992326..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 154484 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