Skip to content

Commit

Permalink
Merge pull request #218 from MyoHub/dev
Browse files Browse the repository at this point in the history
2.6.0 release
  • Loading branch information
Vittorio-Caggiano authored Sep 1, 2024
2 parents ec185ab + e2db072 commit eadafef
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 20 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
# if: ${{ runner.os == 'macOS' }}
# run: |
# brew install --cask xquartz
# brew install hdf5
# brew install hdf5
# export CPATH="/opt/homebrew/include/"
# export HDF5_DIR=/opt/homebrew/
# pip3 install h5py --only-binary h5py
Expand All @@ -97,9 +97,13 @@ jobs:
if: ${{ runner.os == 'Linux' }}
run: python3 -m mujoco.render_test

- name: Run Test environment
- name: Test myoapi
run: |
conda activate $CONDA_DEFAULT_ENV
python3 -m myosuite.tests.test_myoapi
- name: Run Test environment
run: |
python3 -m myosuite.tests.test_myo
- name: Install ffmpeg
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Test your installation using the following command (this will return also a list
``` bash
python -m myosuite.tests.test_myo
```


You can also visualize the environments with random controls using the command below:
``` bash
Expand All @@ -57,7 +57,10 @@ python -m myosuite.utils.examine_env --env_name myoElbowPose1D6MRandom-v0
mjpython -m myosuite.utils.examine_env --env_name myoElbowPose1D6MRandom-v0
```


It is possible to take advantage of the latest MyoSkeleton. Once added (follow the instructions prompted by `python myosuite_init.py`), run:
``` bash
python myosuite/utils/examine_sim.py -s myosuite/simhive/myo_model/myoskeleton/myoskeleton.xml
```

## Examples
It is possible to create and interface with MyoSuite environments just like any other OpenAI gym environments. For example, to use the `myoElbowPose1D6MRandom-v0` environment, it is possible simply to run: [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1zFuNLsrmx42vT4oV8RbnEWtkSJ1xajEo)
Expand All @@ -74,7 +77,7 @@ for _ in range(1000):
env.close()
```

You can find our [tutorials](https://github.com/myohub/myosuite/tree/main/docs/source/tutorials#tutorials) on the general features and the **ICRA2023 Colab Tutorial** [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1KGqZgSYgKXF-vaYC33GR9llDsIW9Rp-q) **ICRA2024 Colab Tutorial** [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1JwxE7o6Z3bqCT4ewELacJ-Z1SV8xFhKK#scrollTo=QDppGIzHB9Zu)
You can find our [tutorials](https://github.com/myohub/myosuite/tree/main/docs/source/tutorials#tutorials) on the general features and the **ICRA2023 Colab Tutorial** [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1KGqZgSYgKXF-vaYC33GR9llDsIW9Rp-q) **ICRA2024 Colab Tutorial** [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1JwxE7o6Z3bqCT4ewELacJ-Z1SV8xFhKK#scrollTo=QDppGIzHB9Zu)
on how to load MyoSuite models/tasks, train them, and visualize their outcome. Also, you can find [baselines](https://github.com/myohub/myosuite/tree/main/myosuite/agents) to test some pre-trained policies.


Expand Down
22 changes: 11 additions & 11 deletions myosuite/envs/myo/myochallenge/bimanual_v0.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def _setup(self,

# check whether the object experience force over max force
self.over_max = False
self.max_force = max_force
self.max_force = 0

self.touch_history = []

Expand Down Expand Up @@ -177,7 +177,8 @@ def get_obs_dict(self, sim):

current_force = sim.data.sensordata[0]
if current_force > self.max_force:
self.over_max = True
self.max_force = current_force
obs_dict['max_force'] = np.array([self.max_force])

obs_vec = self._obj_label_to_obs(touching_objects)
obs_dict["touching_body"] = obs_vec
Expand Down Expand Up @@ -236,7 +237,8 @@ def get_reward_dict(self, obs_dict):
("pass_err", pass_dist + np.log(pass_dist + 1e-3)),
# Must keys
("sparse", 0),
("solved", self.check_solve(goal_dis)),
("goal_dist", goal_dis),
("solved", goal_dis < self.proximity_th),
("done", False),
)
)
Expand All @@ -258,12 +260,6 @@ def step(self, a, **kwargs):
- self.sim.model.actuator_ctrlrange[robotic_act_ind, 0]) / 2.0)
return super().step(processed_controls, **kwargs)

def check_solve(self, goal_dis):
if goal_dis > 0.01:
return False
if self.over_max == True:
return False
return True

def get_metrics(self, paths, successful_steps=5):
"""
Expand All @@ -280,15 +276,19 @@ def get_metrics(self, paths, successful_steps=5):
num_success += 1
score = num_success / num_paths

times = np.mean([np.round(p['env_infos']['obs_dict']['time'][-1], 2) for p in paths])
times = np.mean([np.round(p['env_infos']['obs_dict']['time'][-1], 5) for p in paths])
max_force = np.mean([np.round(p['env_infos']['obs_dict']['max_force'][-1], 5) for p in paths])
goal_dist = np.mean([np.mean(p['env_infos']['rwd_dict']['goal_dist']) for p in paths])

# average activations over entire trajectory (can be shorter than horizon, if done) realized
effort = -1.0 * np.mean([np.mean(p['env_infos']['rwd_dict']['act_reg']) for p in paths])
effort = -1.0 * np.mean([np.mean(p['env_infos']['rwd_dict']['act']) for p in paths])

metrics = {
'score': score,
'time': times,
'effort': effort,
'peak force': max_force,
'goal dist': goal_dist,
}
return metrics

Expand Down
6 changes: 3 additions & 3 deletions myosuite/envs/obs_vec_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ def obsdict2obsvec(self, obs_dict, ordered_obs_keys):
if not self.initialized:
self.initialize(obs_dict, ordered_obs_keys)

# recover vec
obsvec = np.zeros(0)
obs_list = [np.zeros(0)]
for key in self.ordered_obs_keys:
obsvec = np.concatenate([obsvec, obs_dict[key].ravel()]) # ravel helps with images
obs_list.append(obs_dict[key].ravel()) # ravel helps with images
obsvec = np.concatenate(obs_list, dtype=np.float32)

# cache
t = obs_dict['time']
Expand Down
25 changes: 25 additions & 0 deletions myosuite/tests/test_myoapi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

from pathlib import Path
from unittest.mock import patch

from myosuite_init import fetch_simhive

my_file = Path("/path/to/file")

@patch('builtins.input', side_effect=['no'])
def test_no_myoapi(mock_input):
print("mock_input", mock_input.side_effect)
fetch_simhive()
assert not Path("myosuite/simhive/myo_model/myoskeleton/myoskeleton.xml").exists()

@patch('builtins.input', side_effect=['yes'])
def test_yes_myoapi(mock_input):
print("mock_input", mock_input.side_effect)
fetch_simhive()
assert Path("myosuite/simhive/myo_model/myoskeleton/myoskeleton.xml").exists()

test_no_myoapi()
test_yes_myoapi()



2 changes: 1 addition & 1 deletion myosuite/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version_tuple__ = (2, 5, 0)
__version_tuple__ = (2, 6, 0)
113 changes: 113 additions & 0 deletions myosuite_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import os
import shutil
from os.path import expanduser

import git

curr_dir = os.path.dirname(os.path.abspath(__file__))
simhive_path = os.path.join(curr_dir, 'myosuite', 'simhive')


# from myosuite.utils.import_utils import fetch_git

def fetch_git(repo_url, commit_hash, clone_directory, clone_path=None):
"""
fetch git repo using provided details
"""
if clone_path is None:
clone_path = os.path.join(expanduser("~"), ".myosuite")
clone_directory = os.path.join(clone_path, clone_directory)

try:
# Create the clone directory if it doesn't exist
os.makedirs(clone_directory, exist_ok=True)

# Clone the repository to the specified path
if not os.path.exists(os.path.join(clone_directory,'.git')):
repo = git.Repo.clone_from(repo_url, clone_directory)
print(f"{repo_url} cloned at {clone_directory}")
else:
repo = git.Repo(clone_directory)
origin = repo.remote('origin')
origin.fetch()

# Check out the specific commit if not already
current_commit_hash = repo.head.commit.hexsha
if current_commit_hash != commit_hash:
repo.git.checkout(commit_hash)
print(f"{repo_url}@{commit_hash} fetched at {clone_directory}")
except git.GitCommandError as e:
print(f"Error: {e}")

return clone_directory


def clean_simhive():
"""
Remove cached simhive if it exists
"""
print("MyoSuite:> Clearing SimHive ...")
api_path = os.path.join(simhive_path, 'myo_model')
if os.path.exists(api_path):
shutil.rmtree(api_path)
else:
print("MyoSuite:> SimHive/myo_model directory does not exist.")
print("MyoSuite:> SimHive cleared")


def accept_license():
prompt = """
A permissive license for non-commercial scientific research is available.
You can review the license at: https://github.com/myolab/myo_model/blob/main/LICENSE
Do you accept the terms of the license? (yes/no):
"""
response = input(prompt).strip().lower()

if response == 'yes':
print("Thank you for accepting the license. You may proceed.")
return True
elif response == 'no':
print("You have rejected the license terms. Exiting...")
return False
else:
print("Invalid input. Please enter 'yes' or 'no'.")
return accept_license() # Recursively prompt again for valid input


def fetch_simhive():
"""
fetch a copy of simhive
"""
print("MyoSuite:> Initializing...")

# Mark the SimHive version (ToDo: Remove this when commits hashes are auto fetched from submodules)
__version__ = "2.5.0"

# Inform user about API
if accept_license():
# Proceed with the rest of the code
print("MyoSuite:> License accepted. Proceeding initialization ...")
else:
# Exit or handle the rejection case
print("MyoSuite:> License rejected. Exiting")
return

# Fetch SimHive
print("MyoSuite:> Downloading simulation assets (upto ~100MBs)")
fetch_git(repo_url="https://github.com/myolab/myo_model.git",
commit_hash="619b1a876113e91a302b9baeaad6c2341e12ac81",
clone_directory="myo_model",
clone_path=simhive_path)


# mark successful creation of simhive
filename = os.path.join(simhive_path, "simhive-version")
with open(filename, 'w') as file:
file.write(__version__)

print("MyoSuite:> Successfully Initialized.")


if __name__ == "__main__":
fetch_simhive()
6 changes: 6 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,10 @@ def package_files(directory):
packages=find_packages(exclude=("myosuite.agents")),
python_requires=">=3.8",
install_requires=fetch_requirements(),
entry_points={
'console_scripts': [
'myoapi_init = myosuite_init:fetch_simhive',
'myoapi_clean = myosuite_init:clean_simhive',
],
},
)

0 comments on commit eadafef

Please sign in to comment.