Author SHA1 Message Date
Onur aa652e3610 Merge pull request #87 from kayendns/airhockey-off-screen-rendering
Implemented render_mode 'rgb_array' for AirHockeyEnv
2023-12-22 10:09:28 +01:00
Onur fa54dbb149 Merge pull request #91 from JuliusJacobitz/fix_readme_07_12_23
add render_mode to examples in README to make them work again
2023-12-22 10:07:54 +01:00
Onur 3d44454d62 Merge pull request #89 from Thifhi/airhockey-airhockit2023
Implement AirHocKIT 2023 environments
2023-12-22 10:02:56 +01:00
dodox 18c17ff130 Add calls to env.render() to README 2023-12-13 16:08:49 +01:00
JuliusJacobitz 5201937ac8 add render_mode to examples in README to make them work again 2023-12-07 15:53:55 +01:00
Mustafa Enes Batur 86abbe0d97 Pass noise as parameter 2023-12-06 19:47:00 +01:00
Mustafa Enes Batur fde5e33be6 Add noise 2023-12-03 22:37:08 +01:00
Dominik Roth aeecf65f02 Ensure MujocoViewer opens on .render() for render_mode human 2023-11-27 13:18:41 +01:00
Mustafa Enes Batur 6afb5880db Implement AirHocKIT 2023 environments 2023-11-26 22:35:39 +01:00
Kayen 0b4e729a49 incorporated human render_mode gym spec + optimized keyword arguments 2023-11-26 21:50:11 +01:00
Kayen deaca46d87 added rgb_array render mode for off-screen rendering 2023-11-25 23:34:24 +01:00
Hongyi Zhou dbd3caebb3 Merge pull request #84 from ALRhub/pypi-package 2023-11-24 12:50:23 +01:00
Hongyi Zhou f6b56d5b0f Merge pull request #85 from ALRhub/81_fix_docs_mp 2023-11-24 10:41:03 +01:00
dodox c0e55b3f48 Merge remote-tracking branch 'original/pypi-package' into pypi-package 2023-11-23 21:16:53 +01:00
dodox beaf5df2fc Bring to parity with dev-branch 2023-11-23 21:14:11 +01:00
dodox 13e6a3b53a Merge branch '81_fix_docs_mp' into pypi-package 2023-11-23 20:56:55 +01:00
Dominik Roth 99ab2344ad Merge branch 'master' into pypi-package 2023-11-21 20:08:35 +01:00
dodox 74bede4ba3 fixed typo 2023-10-29 17:38:38 +01:00
dodox fae7c887ce Version Increment 2023-10-29 17:29:22 +01:00
dodox 0d3336b8d9 Made check for wether tagged commit is on master more robust 2023-10-29 17:28:45 +01:00
dodox 06e6c64e49 Version increment 2023-10-29 17:23:44 +01:00
dodox 9d1d925179 Require tagged commits to be on master for package to be published 2023-10-29 17:21:13 +01:00
dodox da5592124e Fix issue with trigger 2023-10-29 17:14:58 +01:00
dodox e32f836a3c Version increment 2023-10-29 17:02:12 +01:00
dodox bbd964ed80 Use full URLs for links in README (wont work on PyPI otherwise) 2023-10-29 16:50:02 +01:00
dodox f024613800 Prevent fallback to setup.py when building package 2023-10-29 16:02:10 +01:00
dodox 4a9ea368b8 fix typo in publish-to-test-pypi.yml 2023-10-29 14:39:02 +01:00
dodox 3c7df90810 Ensure we only react to push onto master; disable via if clause 2023-10-29 14:37:30 +01:00
dodox 707ec08808 Disable push to reakl PyPI for initial test 2023-10-29 14:21:08 +01:00
dodox 11a46889d9 Decrement version (we will start with 01.0 on PyPI) 2023-10-29 14:11:47 +01:00
dodox be250bee5e Add action to publish to real PyPI 2023-10-29 14:11:25 +01:00
dodox 049e45cb09 Print warning when setup.py is still used. 2023-10-23 14:51:21 +02:00
dodox af636164a8 Version bump and update setup.py 2023-10-23 14:34:43 +02:00
dodox d138c3c1f1 README: Minor improvements 2023-10-23 14:28:26 +02:00
dodox b277ed6477 Adding forward looking statements to README (Install instructions based on PyPI package) 2023-10-23 14:24:50 +02:00
dodox b183c002ef Provide setup.py as fallback (again) 2023-10-23 14:14:11 +02:00
dodox 5e63a72882 Version bump (to test Github Action) 2023-10-14 12:40:58 +02:00
dodox 0b240b9eb4 Define Github Action for test-PyPI publication 2023-10-14 12:24:04 +02:00
dodox a7031ce3b9 Version dump 2023-10-12 17:58:11 +02:00
dodox 4051a13324 README: GitHub ignores custom font-size; reverting to using h1 2023-10-12 17:47:34 +02:00
dodox ebb0e00675 Minor changes to pyproject.toml 2023-10-12 17:11:19 +02:00
dodox 6fea48f6c1 Increment version 2023-10-12 17:04:03 +02:00
dodox 4107704d9a Fix install instructions (look in both Test-PyPI & PyPI) 2023-10-12 17:03:34 +02:00
dodox a50d1788b1 PyPI does not support GitHub-Flavored Markdown. Using HTML-Code for
emojis now...
2023-10-12 16:54:45 +02:00
dodox 9538c999a0 Make sure the icon is always loaded from GitHub
So it is also visible on PyPI
2023-10-12 16:46:45 +02:00
dodox b0b58675b2 Don't try to export metaworld envs, if metaworld is not installed 2023-10-12 15:53:41 +02:00
dodox 9565f7972f removed typo 2023-10-12 15:48:19 +02:00
dodox 3f0c7b7302 Removing setup.py (built pipeline prefered it over pyproject.toml causing issues)
setup.py remains avaible on the legacy branch.
2023-10-12 15:37:39 +02:00
dodox 0c93280796 Improve handling of missing Metaworld 2023-10-12 15:34:36 +02:00
dodox a5b10e11a3 Allow gymnasium==0.26.0 2023-10-12 15:34:10 +02:00
dodox 894982f77f Fix typos in setup.py 2023-10-12 15:30:11 +02:00
dodox 95a6b9cf2c README: Minor cosmetic changes 2023-10-12 14:56:02 +02:00
dodox 6528c5d5b9 Update README (Test-PyPI and dependency changes) 2023-10-12 14:55:15 +02:00
dodox ce779bc6fb Make mujoco (modern version) a required dependency 2023-10-12 14:55:00 +02:00
dodox b6c67b1adc The pyproject.toml now actually works 2023-10-12 13:04:16 +02:00
dodox ee573788fc Fix: pyproject.toml license needs to point to file 2023-10-12 12:55:32 +02:00
dodox a5a29176cb Add 'all' as an optional installation to the toml 2023-10-12 12:47:37 +02:00
dodox d10ea23b4c Added Code of Conduct and Contributing guidelines to the MANIFEST 2023-10-12 12:41:55 +02:00
dodox 180b86771d Merge branch 'master' into pypi-package 2023-10-12 12:39:05 +02:00
dodox 10038f5d73 We need to use a MANIFEST rto insure inclusion of our *.stl and *.xml files 2023-10-12 12:34:55 +02:00
dodox 7a0f446406 Switching to pyproject.toml; setup.py will remain for backwards compat 2023-10-12 12:34:37 +02:00
18 changed files with 694 additions and 141 deletions
+52
View File
@@ -0,0 +1,52 @@
name: Publish Python package to PyPI
on:
push:
tags:
- '*'
jobs:
publish:
name: Publish to PyPI
runs-on: ubuntu-latest
if: false && startsWith(github.ref, 'refs/tags/') # Only run on tagged commits
steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0 # This fetches all history for all branches and tags
- name: Verify tag is on master branch
run: |
TAG_IS_ON_MASTER=$(git branch -r --contains ${{ github.ref }} | grep 'origin/master')
if [ -z "$TAG_IS_ON_MASTER" ]; then
echo "Tag is not on the master branch. Cancelling the workflow."
exit 1
fi
echo "Tag is on the master branch. Proceeding with the workflow."
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Install pypa/build/setuptools/twine
run: >-
python3 -m
pip install
build setuptools twine
--user
- name: Prevent fallback onto setup.py
run: rm setup.py
- name: Build a binary wheel and a source tarball
run: python3 -m build
- name: Publish to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: twine upload dist/*
@@ -0,0 +1,52 @@
name: Publish Python package to TestPyPI
on:
push:
tags:
- '*'
jobs:
publish:
name: Publish to TestPyPI
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/') # Only run on tagged commits
steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0 # This fetches all history for all branches and tags
- name: Verify tag is on master branch
run: |
TAG_IS_ON_MASTER=$(git branch -r --contains ${{ github.ref }} | grep 'origin/master')
if [ -z "$TAG_IS_ON_MASTER" ]; then
echo "Tag is not on the master branch. Cancelling the workflow."
exit 1
fi
echo "Tag is on the master branch. Proceeding with the workflow."
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Install pypa/build/setuptools/twine
run: >-
python3 -m
pip install
build setuptools twine
--user
- name: Prevent fallback onto setup.py
run: rm setup.py
- name: Build a binary wheel and a source tarball
run: python3 -m build
- name: Publish to TestPyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.TEST_PYPI_TOKEN }}
run: twine upload --repository-url https://test.pypi.org/legacy/ dist/*
+14
View File
@@ -0,0 +1,14 @@
# Include the README
include README.md
# Include the license, Code of Conduct and Contributing guidelines
include LICENSE
include CODE_OF_CONDUCT.md
include CONTRIBUTING.md
# Include stl and xml files from the fancy_gym/envs/mujoco directory
recursive-include fancy_gym/envs/mujoco *.stl
recursive-include fancy_gym/envs/mujoco *.xml
# Also shipping the most important part of fancy gym
include icon.svg
+64 -36
View File
@@ -1,12 +1,12 @@
<h1 align="center"> <h1 align="center">
<br> <br>
<img src='./icon.svg' width="250px"> <img src='https://raw.githubusercontent.com/ALRhub/fancy_gym/master/icon.svg' width="250px">
<br><br> <br><br>
<b>Fancy Gym</b> <b>Fancy Gym</b>
<br><br> <br><br>
</h1> </h1>
| :exclamation: Fancy Gym has recently received a major refactor, which also updated many of the used dependencies to current versions. The update has brought some breaking changes. If you want to access the old version, check out the [legacy branch](https://github.com/ALRhub/fancy_gym/tree/legacy). Find out more about what changed [here](https://github.com/ALRhub/fancy_gym/pull/75). | | &#x2757; Fancy Gym has recently received a major refactor, which also updated many of the used dependencies to current versions. The update has brought some breaking changes. If you want to access the old version, check out the [legacy branch](https://github.com/ALRhub/fancy_gym/tree/legacy). Find out more about what changed [here](https://github.com/ALRhub/fancy_gym/pull/75). |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
Built upon the foundation of [Gymnasium](https://gymnasium.farama.org/) (a maintained fork of OpenAIs renowned Gym library) `fancy_gym` offers a comprehensive collection of reinforcement learning environments. Built upon the foundation of [Gymnasium](https://gymnasium.farama.org/) (a maintained fork of OpenAIs renowned Gym library) `fancy_gym` offers a comprehensive collection of reinforcement learning environments.
@@ -33,57 +33,88 @@ While the overarching objective of MP environments remains the learning of an op
## Installation ## Installation
1. Clone the repository We recommend installing `fancy_gym` into a virtual environment as provided by [venv](https://docs.python.org/3/library/venv.html). 3rd party alternatives to venv like [Poetry](https://python-poetry.org/) or [Conda](https://docs.conda.io/en/latest/) can also be used.
### Installation from PyPI (recommended)
Install `fancy_gym` via
```bash ```bash
git clone git@github.com:ALRhub/fancy_gym.git pip install fancy_gym
```
2. Go to the folder
```bash
cd fancy_gym
```
3. Install with
```bash
pip install -e .
``` ```
We have a few optional dependencies. If you also want to install those use We have a few optional dependencies. If you also want to install those use
```bash ```bash
pip install -e '.[all]' # to install all optional dependencies # to install all optional dependencies
pip install -e '.[dmc,metaworld,box2d,mujoco,mujoco-legacy,jax,testing]' # or choose only those you want pip install 'fancy_gym[all]'
# or choose only those you want
pip install 'fancy_gym[dmc,box2d,mujoco-legacy,jax,testing]'
```
Pip can not automatically install up-to-date versions of metaworld, since they are not avaible on PyPI yet.
Install metaworld via
```bash
pip install metaworld@git+https://github.com/Farama-Foundation/Metaworld.git@d155d0051630bb365ea6a824e02c66c068947439#egg=metaworld
```
### Installation from master
1. Clone the repository
```bash
git clone git@github.com:ALRhub/fancy_gym.git
```
2. Go to the folder
```bash
cd fancy_gym
```
3. Install with
```bash
pip install -e .
```
We have a few optional dependencies. If you also want to install those use
```bash
# to install all optional dependencies
pip install -e '.[all]'
# or choose only those you want
pip install -e '.[dmc,box2d,mujoco-legacy,jax,testing]'
```
Metaworld has to be installed manually with
```bash
pip install metaworld@git+https://github.com/Farama-Foundation/Metaworld.git@d155d0051630bb365ea6a824e02c66c068947439#egg=metaworld
``` ```
## How to use Fancy Gym ## How to use Fancy Gym
We will only show the basics here and prepared [multiple examples](fancy_gym/examples/) for a more detailed look. We will only show the basics here and prepared [multiple examples](https://github.com/ALRhub/fancy_gym/tree/master/fancy_gym/examples/) for a more detailed look.
### Step-Based Environments ### Step-Based Environments
Regular step based environments added by Fancy Gym are added into the `fancy/` namespace. Regular step based environments added by Fancy Gym are added into the `fancy/` namespace.
| :exclamation: Legacy versions of Fancy Gym used `fancy_gym.make(...)`. This is no longer supported and will raise an Exception on new versions. | | &#x2757; Legacy versions of Fancy Gym used `fancy_gym.make(...)`. This is no longer supported and will raise an Exception on new versions. |
| ----------------------------------------------------------------------------------------------------------------------------------------------- | | ----------------------------------------------------------------------------------------------------------------------------------------------- |
```python ```python
import gymnasium as gym import gymnasium as gym
import fancy_gym import fancy_gym
env = gym.make('fancy/Reacher5d-v0') env = gym.make('fancy/Reacher5d-v0', render_mode='human')
# or env = gym.make('metaworld/reach-v2') # fancy_gym allows access to all metaworld ML1 tasks via the metaworld/ NS # or env = gym.make('metaworld/reach-v2', render_mode='human') # fancy_gym allows access to all metaworld ML1 tasks via the metaworld/ NS
# or env = gym.make('dm_control/ball_in_cup-catch-v0') # or env = gym.make('dm_control/ball_in_cup-catch-v0', render_mode='human')
# or env = gym.make('Reacher-v2') # or env = gym.make('Reacher-v2', render_mode='human')
observation = env.reset(seed=1) observation = env.reset(seed=1)
env.render()
for i in range(1000): for i in range(1000):
action = env.action_space.sample() action = env.action_space.sample()
observation, reward, terminated, truncated, info = env.step(action) observation, reward, terminated, truncated, info = env.step(action)
if i % 5 == 0:
env.render()
if terminated or truncated: if terminated or truncated:
observation, info = env.reset() observation, info = env.reset()
@@ -117,17 +148,14 @@ Just keep in mind, calling `step()` executes a full trajectory.
import gymnasium as gym import gymnasium as gym
import fancy_gym import fancy_gym
env = gym.make('fancy_ProMP/Reacher5d-v0') env = gym.make('fancy_ProMP/Reacher5d-v0', render_mode="human")
# or env = gym.make('metaworld_ProDMP/reach-v2') # or env = gym.make('metaworld_ProDMP/reach-v2', render_mode="human")
# or env = gym.make('dm_control_DMP/ball_in_cup-catch-v0') # or env = gym.make('dm_control_DMP/ball_in_cup-catch-v0', render_mode="human")
# or env = gym.make('gym_ProMP/Reacher-v2') # mp versions of envs added directly by gymnasium are in the gym_<MP-type> NS # or env = gym.make('gym_ProMP/Reacher-v2', render_mode="human") # mp versions of envs added directly by gymnasium are in the gym_<MP-type> NS
# 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')
# This returns the context information, not the full state observation # This returns the context information, not the full state observation
observation, info = env.reset(seed=1) observation, info = env.reset(seed=1)
env.render()
for i in range(5): for i in range(5):
action = env.action_space.sample() action = env.action_space.sample()
@@ -165,7 +193,7 @@ print(fancy_gym.MOVEMENT_PRIMITIVE_ENVIRONMENTS_FOR_NS['<my_custom_namespace>'])
### How to create a new MP task ### 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 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](fancy_gym/black_box/raw_interface_wrapper.py) needs to be implemented. hand, the following [interface](https://github.com/ALRhub/fancy_gym/tree/master/fancy_gym/black_box/raw_interface_wrapper.py) needs to be implemented.
```python ```python
from abc import abstractmethod from abc import abstractmethod
@@ -251,7 +279,7 @@ class RawInterfaceWrapper(gym.Wrapper):
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 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 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/). at the [examples](https://github.com/ALRhub/fancy_gym/tree/master/fancy_gym/examples/).
If the step-based is already registered with gym, you can simply do the following: If the step-based is already registered with gym, you can simply do the following:
+4 -1
View File
@@ -6,7 +6,10 @@ from .envs.registry import ALL_MOVEMENT_PRIMITIVE_ENVIRONMENTS, MOVEMENT_PRIMITI
ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS = MOVEMENT_PRIMITIVE_ENVIRONMENTS_FOR_NS['dm_control'] ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS = MOVEMENT_PRIMITIVE_ENVIRONMENTS_FOR_NS['dm_control']
ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS = MOVEMENT_PRIMITIVE_ENVIRONMENTS_FOR_NS['fancy'] ALL_FANCY_MOVEMENT_PRIMITIVE_ENVIRONMENTS = MOVEMENT_PRIMITIVE_ENVIRONMENTS_FOR_NS['fancy']
ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS = MOVEMENT_PRIMITIVE_ENVIRONMENTS_FOR_NS['metaworld'] if 'metaworld' in MOVEMENT_PRIMITIVE_ENVIRONMENTS_FOR_NS:
ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS = MOVEMENT_PRIMITIVE_ENVIRONMENTS_FOR_NS['metaworld']
else:
ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS = 'Metaworld is not installed.'
ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS = MOVEMENT_PRIMITIVE_ENVIRONMENTS_FOR_NS['gym'] ALL_GYM_MOVEMENT_PRIMITIVE_ENVIRONMENTS = MOVEMENT_PRIMITIVE_ENVIRONMENTS_FOR_NS['gym']
+1 -1
View File
@@ -291,7 +291,7 @@ register(
) )
# Air Hockey environments # Air Hockey environments
for env_mode in ["7dof-hit", "7dof-defend", "3dof-hit", "3dof-defend"]: for env_mode in ["7dof-hit", "7dof-defend", "3dof-hit", "3dof-defend", "7dof-hit-airhockit2023", "7dof-defend-airhockit2023"]:
register( register(
id=f'fancy/AirHockey-{env_mode}-v0', id=f'fancy/AirHockey-{env_mode}-v0',
entry_point='fancy_gym.envs.mujoco:AirHockeyEnv', entry_point='fancy_gym.envs.mujoco:AirHockeyEnv',
@@ -8,9 +8,9 @@ from fancy_gym.envs.mujoco.air_hockey.utils import robot_to_world
from mushroom_rl.core import Environment from mushroom_rl.core import Environment
class AirHockeyEnv(Environment): class AirHockeyEnv(Environment):
metadata = {"render_modes": ["human"], "render_fps": 50} metadata = {"render_modes": ["human", "rgb_array"], "render_fps": 50}
def __init__(self, env_mode=None, interpolation_order=3, render_mode=None, **kwargs): def __init__(self, env_mode=None, interpolation_order=3, render_mode=None, width=1920, height=1080, **kwargs):
""" """
Environment Constructor Environment Constructor
@@ -30,7 +30,10 @@ class AirHockeyEnv(Environment):
"7dof-defend": position.IiwaPositionDefend, "7dof-defend": position.IiwaPositionDefend,
"3dof-hit": position.PlanarPositionHit, "3dof-hit": position.PlanarPositionHit,
"3dof-defend": position.PlanarPositionDefend "3dof-defend": position.PlanarPositionDefend,
"7dof-hit-airhockit2023": position.IiwaPositionHitAirhocKIT2023,
"7dof-defend-airhockit2023": position.IiwaPositionDefendAirhocKIT2023,
} }
if env_mode not in env_dict: if env_mode not in env_dict:
@@ -39,37 +42,53 @@ class AirHockeyEnv(Environment):
if env_mode == "tournament" and type(interpolation_order) != tuple: if env_mode == "tournament" and type(interpolation_order) != tuple:
interpolation_order = (interpolation_order, interpolation_order) interpolation_order = (interpolation_order, interpolation_order)
self.render_mode = render_mode
self.render_human_active = False
# Determine headless mode based on render_mode
headless = self.render_mode == 'rgb_array'
# Prepare viewer_params
viewer_params = kwargs.get('viewer_params', {})
viewer_params.update({'headless': headless, 'width': width, 'height': height})
kwargs['viewer_params'] = viewer_params
self.base_env = env_dict[env_mode](interpolation_order=interpolation_order, **kwargs) self.base_env = env_dict[env_mode](interpolation_order=interpolation_order, **kwargs)
self.env_name = env_mode self.env_name = env_mode
self.env_info = self.base_env.env_info self.env_info = self.base_env.env_info
single_robot_obs_size = len(self.base_env.info.observation_space.low)
if env_mode == "tournament":
self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(2,single_robot_obs_size), dtype=np.float64)
else:
self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(single_robot_obs_size,), dtype=np.float64)
robot_info = self.env_info["robot"]
if env_mode != "tournament": if hasattr(self.base_env, "wrapper_obs_space") and hasattr(self.base_env, "wrapper_act_space"):
if interpolation_order in [1, 2]: self.observation_space = self.base_env.wrapper_obs_space
self.action_space = spaces.Box(low=robot_info["joint_pos_limit"][0], high=robot_info["joint_pos_limit"][1]) self.action_space = self.base_env.wrapper_act_space
if interpolation_order in [3, 4, -1]:
self.action_space = spaces.Box(low=np.vstack([robot_info["joint_pos_limit"][0], robot_info["joint_vel_limit"][0]]),
high=np.vstack([robot_info["joint_pos_limit"][1], robot_info["joint_vel_limit"][1]]))
if interpolation_order in [5]:
self.action_space = spaces.Box(low=np.vstack([robot_info["joint_pos_limit"][0], robot_info["joint_vel_limit"][0], robot_info["joint_acc_limit"][0]]),
high=np.vstack([robot_info["joint_pos_limit"][1], robot_info["joint_vel_limit"][1], robot_info["joint_acc_limit"][1]]))
else: else:
acts = [None, None] single_robot_obs_size = len(self.base_env.info.observation_space.low)
for i in range(2): if env_mode == "tournament":
if interpolation_order[i] in [1, 2]: self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(2,single_robot_obs_size), dtype=np.float64)
acts[i] = spaces.Box(low=robot_info["joint_pos_limit"][0], high=robot_info["joint_pos_limit"][1]) else:
if interpolation_order[i] in [3, 4, -1]: self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(single_robot_obs_size,), dtype=np.float64)
acts[i] = spaces.Box(low=np.vstack([robot_info["joint_pos_limit"][0], robot_info["joint_vel_limit"][0]]), robot_info = self.env_info["robot"]
high=np.vstack([robot_info["joint_pos_limit"][1], robot_info["joint_vel_limit"][1]]))
if interpolation_order[i] in [5]: if env_mode != "tournament":
acts[i] = spaces.Box(low=np.vstack([robot_info["joint_pos_limit"][0], robot_info["joint_vel_limit"][0], robot_info["joint_acc_limit"][0]]), if interpolation_order in [1, 2]:
high=np.vstack([robot_info["joint_pos_limit"][1], robot_info["joint_vel_limit"][1], robot_info["joint_acc_limit"][1]])) self.action_space = spaces.Box(low=robot_info["joint_pos_limit"][0], high=robot_info["joint_pos_limit"][1])
self.action_space = spaces.Tuple((acts[0], acts[1])) if interpolation_order in [3, 4, -1]:
self.action_space = spaces.Box(low=np.vstack([robot_info["joint_pos_limit"][0], robot_info["joint_vel_limit"][0]]),
high=np.vstack([robot_info["joint_pos_limit"][1], robot_info["joint_vel_limit"][1]]))
if interpolation_order in [5]:
self.action_space = spaces.Box(low=np.vstack([robot_info["joint_pos_limit"][0], robot_info["joint_vel_limit"][0], robot_info["joint_acc_limit"][0]]),
high=np.vstack([robot_info["joint_pos_limit"][1], robot_info["joint_vel_limit"][1], robot_info["joint_acc_limit"][1]]))
else:
acts = [None, None]
for i in range(2):
if interpolation_order[i] in [1, 2]:
acts[i] = spaces.Box(low=robot_info["joint_pos_limit"][0], high=robot_info["joint_pos_limit"][1])
if interpolation_order[i] in [3, 4, -1]:
acts[i] = spaces.Box(low=np.vstack([robot_info["joint_pos_limit"][0], robot_info["joint_vel_limit"][0]]),
high=np.vstack([robot_info["joint_pos_limit"][1], robot_info["joint_vel_limit"][1]]))
if interpolation_order[i] in [5]:
acts[i] = spaces.Box(low=np.vstack([robot_info["joint_pos_limit"][0], robot_info["joint_vel_limit"][0], robot_info["joint_acc_limit"][0]]),
high=np.vstack([robot_info["joint_pos_limit"][1], robot_info["joint_vel_limit"][1], robot_info["joint_acc_limit"][1]]))
self.action_space = spaces.Tuple((acts[0], acts[1]))
constraint_list = constraints.ConstraintList() constraint_list = constraints.ConstraintList()
constraint_list.add(constraints.JointPositionConstraint(self.env_info)) constraint_list.add(constraints.JointPositionConstraint(self.env_info))
@@ -81,9 +100,6 @@ class AirHockeyEnv(Environment):
self.env_info['constraints'] = constraint_list self.env_info['constraints'] = constraint_list
self.env_info['env_name'] = self.env_name self.env_info['env_name'] = self.env_name
self.render_mode = render_mode
self.render_human_active = False
super().__init__(self.base_env.info) super().__init__(self.base_env.info)
def step(self, action): def step(self, action):
@@ -118,7 +134,13 @@ class AirHockeyEnv(Environment):
return obs, reward, done, False, info return obs, reward, done, False, info
def render(self): def render(self):
self.render_human_active = True if self.render_mode == 'rgb_array':
return self.base_env.render(record = True)
elif self.render_mode == 'human':
self.render_human_active = True
self.base_env.render()
else:
raise ValueError(f"Unsupported render mode: '{self.render_mode}'")
def reset(self, seed=None, options={}): def reset(self, seed=None, options={}):
self.base_env.seed(seed) self.base_env.seed(seed)
@@ -261,10 +261,14 @@ class PlanarPositionDefend(PositionControlPlanar, three_dof.AirHockeyDefend):
class IiwaPositionHit(PositionControlIIWA, seven_dof.AirHockeyHit): class IiwaPositionHit(PositionControlIIWA, seven_dof.AirHockeyHit):
pass pass
class IiwaPositionHitAirhocKIT2023(PositionControlIIWA, seven_dof.AirHockeyHitAirhocKIT2023):
pass
class IiwaPositionDefend(PositionControlIIWA, seven_dof.AirHockeyDefend): class IiwaPositionDefend(PositionControlIIWA, seven_dof.AirHockeyDefend):
pass pass
class IiwaPositionDefendAirhocKIT2023(PositionControlIIWA, seven_dof.AirHockeyDefendAirhocKIT2023):
pass
class IiwaPositionTournament(PositionControlIIWA, seven_dof.AirHockeyTournament): class IiwaPositionTournament(PositionControlIIWA, seven_dof.AirHockeyTournament):
pass pass
@@ -1,4 +1,4 @@
from .env_base import AirHockeyBase from .env_base import AirHockeyBase
from .tournament import AirHockeyTournament from .tournament import AirHockeyTournament
from .hit import AirHockeyHit from .hit import AirHockeyHit, AirHockeyHitAirhocKIT2023
from .defend import AirHockeyDefend from .defend import AirHockeyDefend, AirHockeyDefendAirhocKIT2023
@@ -0,0 +1,114 @@
import numpy as np
from gymnasium import spaces
from fancy_gym.envs.mujoco.air_hockey.seven_dof.env_single import AirHockeySingle
from fancy_gym.envs.mujoco.air_hockey.utils import inverse_kinematics, forward_kinematics, jacobian
class AirhocKIT2023BaseEnv(AirHockeySingle):
def __init__(self, noise=False, **kwargs):
super().__init__(**kwargs)
obs_low = np.hstack([[-np.inf] * 37])
obs_high = np.hstack([[np.inf] * 37])
self.wrapper_obs_space = spaces.Box(low=obs_low, high=obs_high, dtype=np.float64)
self.wrapper_act_space = spaces.Box(low=np.repeat(-100., 6), high=np.repeat(100., 6))
self.noise = noise
# We don't need puck yaw observations
def filter_obs(self, obs):
obs = np.hstack([obs[0:2], obs[3:5], obs[6:12], obs[13:19], obs[20:]])
return obs
def add_noise(self, obs):
if not self.noise:
return
obs[self.env_info["puck_pos_ids"]] += np.random.normal(0, 0.001, 3)
obs[self.env_info["puck_vel_ids"]] += np.random.normal(0, 0.1, 3)
def reset(self):
self.last_acceleration = np.repeat(0., 6)
obs = super().reset()
self.add_noise(obs)
self.interp_pos = obs[self.env_info["joint_pos_ids"]][:-1]
self.interp_vel = obs[self.env_info["joint_vel_ids"]][:-1]
self.last_planned_world_pos = self._fk(self.interp_pos)
obs = np.hstack([
obs, self.interp_pos, self.interp_vel, self.last_acceleration, self.last_planned_world_pos
])
return self.filter_obs(obs)
def step(self, action):
action /= 10
new_vel = self.interp_vel + action
jerk = 2 * (new_vel - self.interp_vel - self.last_acceleration * 0.02) / (0.02 ** 2)
new_pos = self.interp_pos + self.interp_vel * 0.02 + (1/2) * self.last_acceleration * (0.02 ** 2) + (1/6) * jerk * (0.02 ** 3)
abs_action = np.vstack([np.hstack([new_pos, 0]), np.hstack([new_vel, 0])])
self.interp_pos = new_pos
self.interp_vel = new_vel
self.last_acceleration += jerk * 0.02
obs, rew, done, info = super().step(abs_action)
self.add_noise(obs)
self.last_planned_world_pos = self._fk(self.interp_pos)
obs = np.hstack([
obs, self.interp_pos, self.interp_vel, self.last_acceleration, self.last_planned_world_pos
])
fatal_rew = self.check_fatal(obs)
if fatal_rew != 0:
return self.filter_obs(obs), fatal_rew, True, info
return self.filter_obs(obs), rew, done, info
def check_constraints(self, constraint_values):
fatal_rew = 0
j_pos_constr = constraint_values["joint_pos_constr"]
if j_pos_constr.max() > 0:
fatal_rew += j_pos_constr.max()
j_vel_constr = constraint_values["joint_vel_constr"]
if j_vel_constr.max() > 0:
fatal_rew += j_vel_constr.max()
ee_constr = constraint_values["ee_constr"]
if ee_constr.max() > 0:
fatal_rew += ee_constr.max()
link_constr = constraint_values["link_constr"]
if link_constr.max() > 0:
fatal_rew += link_constr.max()
return -fatal_rew
def check_fatal(self, obs):
fatal_rew = 0
q = obs[self.env_info["joint_pos_ids"]]
qd = obs[self.env_info["joint_vel_ids"]]
constraint_values_obs = self.env_info["constraints"].fun(q, qd)
fatal_rew += self.check_constraints(constraint_values_obs)
return -fatal_rew
def _fk(self, pos):
res, _ = forward_kinematics(self.env_info["robot"]["robot_model"],
self.env_info["robot"]["robot_data"], pos)
return res.astype(np.float32)
def _ik(self, world_pos, init_q=None):
success, pos = inverse_kinematics(self.env_info["robot"]["robot_model"],
self.env_info["robot"]["robot_data"],
world_pos,
initial_q=init_q)
pos = pos.astype(np.float32)
assert success
return pos
def _jacobian(self, pos):
return jacobian(self.env_info["robot"]["robot_model"],
self.env_info["robot"]["robot_data"],
pos).astype(np.float32)
@@ -1,6 +1,7 @@
import numpy as np import numpy as np
from fancy_gym.envs.mujoco.air_hockey.seven_dof.env_single import AirHockeySingle from fancy_gym.envs.mujoco.air_hockey.seven_dof.env_single import AirHockeySingle
from fancy_gym.envs.mujoco.air_hockey.seven_dof.airhockit_base_env import AirhocKIT2023BaseEnv
class AirHockeyDefend(AirHockeySingle): class AirHockeyDefend(AirHockeySingle):
@@ -10,9 +11,7 @@ class AirHockeyDefend(AirHockeySingle):
""" """
def __init__(self, gamma=0.99, horizon=500, viewer_params={}): def __init__(self, gamma=0.99, horizon=500, viewer_params={}):
self.init_velocity_range = (1, 3) self.init_velocity_range = (1, 3)
self.start_range = np.array([[0.29, 0.65], [-0.4, 0.4]]) # Table Frame self.start_range = np.array([[0.29, 0.65], [-0.4, 0.4]]) # Table Frame
self.init_ee_range = np.array([[0.60, 1.25], [-0.4, 0.4]]) # Robot Frame
super().__init__(gamma=gamma, horizon=horizon, viewer_params=viewer_params) super().__init__(gamma=gamma, horizon=horizon, viewer_params=viewer_params)
def setup(self, obs): def setup(self, obs):
@@ -32,7 +31,7 @@ class AirHockeyDefend(AirHockeySingle):
self._write_data("puck_y_vel", puck_vel[1]) self._write_data("puck_y_vel", puck_vel[1])
self._write_data("puck_yaw_vel", puck_vel[2]) self._write_data("puck_yaw_vel", puck_vel[2])
super(AirHockeyDefend, self).setup(obs) super().setup(obs)
def reward(self, state, action, next_state, absorbing): def reward(self, state, action, next_state, absorbing):
return 0 return 0
@@ -46,6 +45,98 @@ class AirHockeyDefend(AirHockeySingle):
return True return True
return super().is_absorbing(state) return super().is_absorbing(state)
class AirHockeyDefendAirhocKIT2023(AirhocKIT2023BaseEnv):
def __init__(self, gamma=0.99, horizon=200, viewer_params={}, **kwargs):
super().__init__(gamma=gamma, horizon=horizon, viewer_params=viewer_params, **kwargs)
self.init_velocity_range = (1, 3)
self.start_range = np.array([[0.4, 0.75], [-0.4, 0.4]]) # Table Frame
self._setup_metrics()
def setup(self, obs):
self._setup_metrics()
puck_pos = np.random.rand(2) * (self.start_range[:, 1] - self.start_range[:, 0]) + self.start_range[:, 0]
lin_vel = np.random.uniform(self.init_velocity_range[0], self.init_velocity_range[1])
angle = np.random.uniform(-0.5, 0.5)
puck_vel = np.zeros(3)
puck_vel[0] = -np.cos(angle) * lin_vel
puck_vel[1] = np.sin(angle) * lin_vel
puck_vel[2] = np.random.uniform(-10, 10)
self._write_data("puck_x_pos", puck_pos[0])
self._write_data("puck_y_pos", puck_pos[1])
self._write_data("puck_x_vel", puck_vel[0])
self._write_data("puck_y_vel", puck_vel[1])
self._write_data("puck_yaw_vel", puck_vel[2])
super().setup(obs)
def reset(self, *args):
obs = super().reset()
self.hit_step_flag = False
self.hit_step = False
self.received_hit_reward = False
self.give_reward_next = False
return obs
def _setup_metrics(self):
self.episode_steps = 0
self.has_hit = False
def _simulation_post_step(self):
if not self.has_hit:
self.has_hit = self._check_collision("puck", "robot_1/ee")
super()._simulation_post_step()
def _step_finalize(self):
self.episode_steps += 1
return super()._step_finalize()
def reward(self, state, action, next_state, absorbing):
puck_pos, puck_vel = self.get_puck(next_state)
ee_pos, _ = self.get_ee()
rew = 0.01
if -0.7 < puck_pos[0] <= -0.2 and np.linalg.norm(puck_vel[:2]) < 0.1:
assert absorbing
rew += 70
if self.has_hit and not self.hit_step_flag:
self.hit_step_flag = True
self.hit_step = True
else:
self.hit_step = False
f = lambda puck_vel: 30 + 100 * (100 ** (-0.25 * np.linalg.norm(puck_vel[:2])))
if not self.give_reward_next and not self.received_hit_reward and self.hit_step and ee_pos[0] < puck_pos[0]:
self.hit_this_step = True
if np.linalg.norm(puck_vel[:2]) < 0.1:
return rew + f(puck_vel)
self.give_reward_next = True
return rew
if not self.received_hit_reward and self.give_reward_next:
self.received_hit_reward = True
if puck_vel[0] >= -0.2:
return rew + f(puck_vel)
return rew
else:
return rew
def is_absorbing(self, obs):
puck_pos, puck_vel = self.get_puck(obs)
# If puck is over the middle line and moving towards opponent
if puck_pos[0] > 0 and puck_vel[0] > 0:
return True
if self.episode_steps == self._mdp_info.horizon:
return True
if np.linalg.norm(puck_vel[:2]) < 0.1:
return True
return super().is_absorbing(obs)
if __name__ == '__main__': if __name__ == '__main__':
env = AirHockeyDefend() env = AirHockeyDefend()
@@ -1,6 +1,7 @@
import numpy as np import numpy as np
from fancy_gym.envs.mujoco.air_hockey.seven_dof.env_single import AirHockeySingle from fancy_gym.envs.mujoco.air_hockey.seven_dof.env_single import AirHockeySingle
from fancy_gym.envs.mujoco.air_hockey.seven_dof.airhockit_base_env import AirhocKIT2023BaseEnv
class AirHockeyHit(AirHockeySingle): class AirHockeyHit(AirHockeySingle):
@@ -14,9 +15,6 @@ class AirHockeyHit(AirHockeySingle):
opponent_agent(Agent, None): Agent which controls the opponent opponent_agent(Agent, None): Agent which controls the opponent
moving_init(bool, False): If true, initialize the puck with inital velocity. moving_init(bool, False): If true, initialize the puck with inital velocity.
""" """
self.hit_range = np.array([[-0.65, -0.25], [-0.4, 0.4]]) # Table Frame
self.init_velocity_range = (0, 0.5) # Table Frame
super().__init__(gamma=gamma, horizon=horizon, viewer_params=viewer_params) super().__init__(gamma=gamma, horizon=horizon, viewer_params=viewer_params)
self.moving_init = moving_init self.moving_init = moving_init
@@ -58,6 +56,93 @@ class AirHockeyHit(AirHockeySingle):
return True return True
return super(AirHockeyHit, self).is_absorbing(obs) return super(AirHockeyHit, self).is_absorbing(obs)
class AirHockeyHitAirhocKIT2023(AirhocKIT2023BaseEnv):
def __init__(self, gamma=0.99, horizon=500, moving_init=True, viewer_params={}, **kwargs):
super().__init__(gamma=gamma, horizon=horizon, viewer_params=viewer_params, **kwargs)
self.moving_init = moving_init
hit_width = self.env_info['table']['width'] / 2 - self.env_info['puck']['radius'] - \
self.env_info['mallet']['radius'] * 2
self.hit_range = np.array([[-0.7, -0.2], [-hit_width, hit_width]]) # Table Frame
self.init_velocity_range = (0, 0.5) # Table Frame
self.init_ee_range = np.array([[0.60, 1.25], [-0.4, 0.4]]) # Robot Frame
self._setup_metrics()
def reset(self, *args):
obs = super().reset()
self.last_ee_pos = self.last_planned_world_pos.copy()
self.last_ee_pos[0] -= 1.51
return obs
def setup(self, obs):
self._setup_metrics()
puck_pos = np.random.rand(2) * (self.hit_range[:, 1] - self.hit_range[:, 0]) + self.hit_range[:, 0]
self._write_data("puck_x_pos", puck_pos[0])
self._write_data("puck_y_pos", puck_pos[1])
if self.moving_init:
lin_vel = np.random.uniform(self.init_velocity_range[0], self.init_velocity_range[1])
angle = np.random.uniform(-np.pi / 2 - 0.1, np.pi / 2 + 0.1)
puck_vel = np.zeros(3)
puck_vel[0] = -np.cos(angle) * lin_vel
puck_vel[1] = np.sin(angle) * lin_vel
puck_vel[2] = np.random.uniform(-2, 2)
self._write_data("puck_x_vel", puck_vel[0])
self._write_data("puck_y_vel", puck_vel[1])
self._write_data("puck_yaw_vel", puck_vel[2])
super().setup(obs)
def _setup_metrics(self):
self.episode_steps = 0
self.has_scored = False
def _step_finalize(self):
cur_obs = self._create_observation(self.obs_helper._build_obs(self._data))
puck_pos, _ = self.get_puck(cur_obs) # world frame [x, y, z] and [x', y', z']
if not self.has_scored:
boundary = np.array([self.env_info['table']['length'], self.env_info['table']['width']]) / 2
self.has_scored = np.any(np.abs(puck_pos[:2]) > boundary) and puck_pos[0] > 0
self.episode_steps += 1
return super()._step_finalize()
def reward(self, state, action, next_state, absorbing):
rew = 0
puck_pos, puck_vel = self.get_puck(next_state)
ee_pos, _ = self.get_ee()
ee_vel = (ee_pos - self.last_ee_pos) / 0.02
self.last_ee_pos = ee_pos
if puck_vel[0] < 0.25 and puck_pos[0] < 0:
ee_puck_dir = (puck_pos - ee_pos)[:2]
ee_puck_dir = ee_puck_dir / np.linalg.norm(ee_puck_dir)
rew += 1 * max(0, np.dot(ee_puck_dir, ee_vel[:2]))
else:
rew += 10 * np.linalg.norm(puck_vel[:2])
if self.has_scored:
rew += 2000 + 5000 * np.linalg.norm(puck_vel[:2])
return rew
def is_absorbing(self, obs):
puck_pos, puck_vel = self.get_puck(obs)
# Stop if the puck bounces back on the opponents wall
if puck_pos[0] > 0 and puck_vel[0] < 0:
return True
if self.has_scored:
return True
if self.episode_steps == self._mdp_info.horizon:
return True
return super().is_absorbing(obs)
if __name__ == '__main__': if __name__ == '__main__':
env = AirHockeyHit(moving_init=True) env = AirHockeyHit(moving_init=True)
+54 -47
View File
@@ -7,56 +7,63 @@ from ..envs.registry import register
from . import goal_object_change_mp_wrapper, goal_change_mp_wrapper, goal_endeffector_change_mp_wrapper, \ from . import goal_object_change_mp_wrapper, goal_change_mp_wrapper, goal_endeffector_change_mp_wrapper, \
object_change_mp_wrapper object_change_mp_wrapper
from . import metaworld_adapter try:
import metaworld
except ModuleNotFoundError:
print('[FANCY GYM] Metaworld not avaible.')
else:
# Will only get executed, if import succeeds
metaworld_adapter.register_all_ML1() from . import metaworld_adapter
ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": [], "ProDMP": []} metaworld_adapter.register_all_ML1()
# MetaWorld ALL_METAWORLD_MOVEMENT_PRIMITIVE_ENVIRONMENTS = {"DMP": [], "ProMP": [], "ProDMP": []}
_goal_change_envs = ["assembly-v2", "pick-out-of-hole-v2", "plate-slide-v2", "plate-slide-back-v2",
"plate-slide-side-v2", "plate-slide-back-side-v2"]
for _task in _goal_change_envs:
register(
id=f'metaworld/{_task}',
register_step_based=False,
mp_wrapper=goal_change_mp_wrapper.MPWrapper,
add_mp_types=['ProMP', 'ProDMP'],
)
_object_change_envs = ["bin-picking-v2", "hammer-v2", "sweep-into-v2"] # MetaWorld
for _task in _object_change_envs: _goal_change_envs = ["assembly-v2", "pick-out-of-hole-v2", "plate-slide-v2", "plate-slide-back-v2",
register( "plate-slide-side-v2", "plate-slide-back-side-v2"]
id=f'metaworld/{_task}', for _task in _goal_change_envs:
register_step_based=False, register(
mp_wrapper=object_change_mp_wrapper.MPWrapper, id=f'metaworld/{_task}',
add_mp_types=['ProMP', 'ProDMP'], register_step_based=False,
) mp_wrapper=goal_change_mp_wrapper.MPWrapper,
add_mp_types=['ProMP', 'ProDMP'],
)
_goal_and_object_change_envs = ["box-close-v2", "button-press-v2", "button-press-wall-v2", "button-press-topdown-v2", _object_change_envs = ["bin-picking-v2", "hammer-v2", "sweep-into-v2"]
"button-press-topdown-wall-v2", "coffee-button-v2", "coffee-pull-v2", for _task in _object_change_envs:
"coffee-push-v2", "dial-turn-v2", "disassemble-v2", "door-close-v2", register(
"door-lock-v2", "door-open-v2", "door-unlock-v2", "hand-insert-v2", id=f'metaworld/{_task}',
"drawer-close-v2", "drawer-open-v2", "faucet-open-v2", "faucet-close-v2", register_step_based=False,
"handle-press-side-v2", "handle-press-v2", "handle-pull-side-v2", mp_wrapper=object_change_mp_wrapper.MPWrapper,
"handle-pull-v2", "lever-pull-v2", "peg-insert-side-v2", "pick-place-wall-v2", add_mp_types=['ProMP', 'ProDMP'],
"reach-v2", "push-back-v2", "push-v2", "pick-place-v2", "peg-unplug-side-v2", )
"soccer-v2", "stick-push-v2", "stick-pull-v2", "push-wall-v2", "reach-wall-v2",
"shelf-place-v2", "sweep-v2", "window-open-v2", "window-close-v2"
]
for _task in _goal_and_object_change_envs:
register(
id=f'metaworld/{_task}',
register_step_based=False,
mp_wrapper=goal_object_change_mp_wrapper.MPWrapper,
add_mp_types=['ProMP', 'ProDMP'],
)
_goal_and_endeffector_change_envs = ["basketball-v2"] _goal_and_object_change_envs = ["box-close-v2", "button-press-v2", "button-press-wall-v2", "button-press-topdown-v2",
for _task in _goal_and_endeffector_change_envs: "button-press-topdown-wall-v2", "coffee-button-v2", "coffee-pull-v2",
register( "coffee-push-v2", "dial-turn-v2", "disassemble-v2", "door-close-v2",
id=f'metaworld/{_task}', "door-lock-v2", "door-open-v2", "door-unlock-v2", "hand-insert-v2",
register_step_based=False, "drawer-close-v2", "drawer-open-v2", "faucet-open-v2", "faucet-close-v2",
mp_wrapper=goal_endeffector_change_mp_wrapper.MPWrapper, "handle-press-side-v2", "handle-press-v2", "handle-pull-side-v2",
add_mp_types=['ProMP', 'ProDMP'], "handle-pull-v2", "lever-pull-v2", "peg-insert-side-v2", "pick-place-wall-v2",
) "reach-v2", "push-back-v2", "push-v2", "pick-place-v2", "peg-unplug-side-v2",
"soccer-v2", "stick-push-v2", "stick-pull-v2", "push-wall-v2", "reach-wall-v2",
"shelf-place-v2", "sweep-v2", "window-open-v2", "window-close-v2"
]
for _task in _goal_and_object_change_envs:
register(
id=f'metaworld/{_task}',
register_step_based=False,
mp_wrapper=goal_object_change_mp_wrapper.MPWrapper,
add_mp_types=['ProMP', 'ProDMP'],
)
_goal_and_endeffector_change_envs = ["basketball-v2"]
for _task in _goal_and_endeffector_change_envs:
register(
id=f'metaworld/{_task}',
register_step_based=False,
mp_wrapper=goal_endeffector_change_mp_wrapper.MPWrapper,
add_mp_types=['ProMP', 'ProDMP'],
)
+1 -5
View File
@@ -11,11 +11,7 @@ import numpy as np
from fancy_gym.utils.env_compatibility import EnvCompatibility from fancy_gym.utils.env_compatibility import EnvCompatibility
try: import metaworld
import metaworld
except Exception:
print('[FANCY GYM] Metaworld not avaible')
class FixMetaworldHasIncorrectObsSpaceWrapper(gym.Wrapper, gym.utils.RecordConstructorArgs): class FixMetaworldHasIncorrectObsSpaceWrapper(gym.Wrapper, gym.utils.RecordConstructorArgs):
def __init__(self, env: gym.Env): def __init__(self, env: gym.Env):
+79
View File
@@ -0,0 +1,79 @@
[project]
name = "fancy_gym"
version = "0.1.4"
description = "Fancy Gym: Unifying interface for various RL benchmarks with support for Black Box approaches."
readme = "README.md"
authors = [
{name = "Fabian Otto", email = "fabian.otto@uni-tuebingen.de"},
{name = "Onur Celik", email = "celik@kit.edu"},
{name = "Dominik Roth", email = "fancy_gym@dominik-roth.eu"},
{name = "Hongyi Zhou", email = "hongyi.zhou@kit.edu"}
]
license = { text = "MIT License" }
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Operating System :: OS Independent",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11"
]
dependencies = [
"mp_pytorch<=0.1.3",
"mujoco==2.3.3",
"gymnasium[mujoco]>=0.26.0"
]
requires-python = ">=3.7"
[project.urls]
"Homepage" = "https://github.com/ALRhub/fancy_gym/"
#"Documentation" = "https://github.com/ALRhub/fancy_gym/"
"Bug Tracker" = "https://github.com/ALRhub/fancy_gym/issues"
#"Repository" = "https://github.com/ALRhub/fancy_gym/"
[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"
[project.optional-dependencies]
dmc = ["shimmy[dm-control]", "Shimmy==1.0.0"]
# PyPi does not allow external dependencies. Metaworld will have to be installed manually until Farama publishes up-to-date version of metaworld on PyPi.
#metaworld = ["metaworld @ git+https://github.com/Farama-Foundation/Metaworld.git@d155d0051630bb365ea6a824e02c66c068947439#egg=metaworld"]
box2d = ["gymnasium[box2d]>=0.26.0"]
mujoco-legacy = ["mujoco-py>=2.1,<2.2", "cython<3"]
jax = ["jax>=0.4.0", "jaxlib>=0.4.0"]
all = [
# include all the optional dependencies
"shimmy[dm-control]",
"Shimmy==1.0.0",
#"metaworld @ git+https://github.com/Farama-Foundation/Metaworld.git@d155d0051630bb365ea6a824e02c66c068947439#egg=metaworld",
"mujoco==2.3.3",
"gymnasium[box2d,mujoco]>=0.26.0",
"mujoco-py>=2.1,<2.2",
"cython<3",
"jax>=0.4.0",
"jaxlib>=0.4.0"
]
testing = [
"pytest",
# include all the optional dependencies as well
"shimmy[dm-control]",
"Shimmy==1.0.0",
#"metaworld @ git+https://github.com/Farama-Foundation/Metaworld.git@d155d0051630bb365ea6a824e02c66c068947439#egg=metaworld",
"mujoco==2.3.3",
"gymnasium[box2d,mujoco]>=0.26.0",
"mujoco-py>=2.1,<2.2",
"cython<3",
"jax>=0.4.0",
"jaxlib>=0.4.0"
]
+9 -5
View File
@@ -1,15 +1,17 @@
# We still provide a setup.py for backwards compatability.
# But the pyproject.toml should be prefered.
import itertools import itertools
from pathlib import Path from pathlib import Path
from typing import List from typing import List
from setuptools import setup, find_packages from setuptools import setup, find_packages
print('[!] You are currently installing/building fancy_gym via setup.py. This is only provided for backwards-compatability. Please use the pyproject.toml instead.')
# Environment-specific dependencies for dmc and metaworld # Environment-specific dependencies for dmc and metaworld
extras = { extras = {
'dmc': ['shimmy[dm-control]', 'Shimmy==1.0.0'], 'dmc': ['shimmy[dm-control]', 'Shimmy==1.0.0'],
'metaworld': ['mujoco==2.3.3', 'metaworld @ git+https://github.com/Farama-Foundation/Metaworld.git@d155d0051630bb365ea6a824e02c66c068947439#egg=metaworld'],
'box2d': ['gymnasium[box2d]>=0.26.0'], 'box2d': ['gymnasium[box2d]>=0.26.0'],
'mujoco': ['mujoco==2.3.3', 'gymnasium[mujoco]>0.26.0'],
'mujoco-legacy': ['mujoco-py >=2.1,<2.2', 'cython<3'], 'mujoco-legacy': ['mujoco-py >=2.1,<2.2', 'cython<3'],
'jax': ["jax >=0.4.0", "jaxlib >=0.4.0"], 'jax': ["jax >=0.4.0", "jaxlib >=0.4.0"],
'mushroom-rl': ['mushroom-rl'], 'mushroom-rl': ['mushroom-rl'],
@@ -36,7 +38,7 @@ def find_package_data(extensions_to_include: List[str]) -> List[str]:
setup( setup(
author='Fabian Otto, Onur Celik, Dominik Roth, Hongyi Zhou', author='Fabian Otto, Onur Celik, Dominik Roth, Hongyi Zhou',
name='fancy_gym', name='fancy_gym',
version='1.0', version='0.1.0',
classifiers=[ classifiers=[
'Development Status :: 4 - Beta', 'Development Status :: 4 - Beta',
'Intended Audience :: Science/Research', 'Intended Audience :: Science/Research',
@@ -49,11 +51,13 @@ setup(
'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
], ],
extras_require=extras, extras_require=extras,
install_requires=[ install_requires=[
'gymnasium>=0.26.0', 'mp_pytorch<=0.1.3',
'mp_pytorch<=0.1.3' 'mujoco==2.3.3',
'gymnasium[mujoco]>=0.26.0'
], ],
packages=[package for package in find_packages( packages=[package for package in find_packages(
) if package.startswith("fancy_gym")], ) if package.startswith("fancy_gym")],
+3 -1
View File
@@ -12,7 +12,9 @@ GYM_IDS = [spec.id for spec in gym.envs.registry.values() if
not isinstance(spec.entry_point, Callable) and not isinstance(spec.entry_point, Callable) and
"fancy_gym" 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
and 'jax' not in spec.id.lower() and 'jax' not in spec.id.lower()
and 'jax' not in spec.id.lower() and 'shimmy' not in spec.id.lower()
and 'ale_py' not in spec.id.lower()
and 'tabular' not in spec.id.lower()
and not re.match(r'GymV2.Environment', spec.id) and not re.match(r'GymV2.Environment', spec.id)
] ]
GYM_MP_IDS = fancy_gym.ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS['all'] GYM_MP_IDS = fancy_gym.ALL_DMC_MOVEMENT_PRIMITIVE_ENVIRONMENTS['all']
+1 -1
View File
@@ -103,7 +103,7 @@ def test_verbosity(mp_type: str, env_wrap: Tuple[str, Type[RawInterfaceWrapper]]
env_step = make(env_id) env_step = make(env_id)
env_step.reset() env_step.reset()
_obs, _reward, _terminated, _truncated, info = env.step(env.action_space.sample()) _obs, _reward, _terminated, _truncated, info = env_step.step(env_step.action_space.sample())
info_keys_step = info.keys() info_keys_step = info.keys()
assert all(e in info_keys for e in info_keys_step) assert all(e in info_keys for e in info_keys_step)