diff --git a/.gitignore b/.gitignore index 86d23eef7..a66cc400b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ MUJOCO_LOG.TXT ## ------------------- benchmark/mujoco_menagerie/ +benchmark/myo_sim ## Created directories diff --git a/benchmark/benchmark.py b/benchmark/benchmark.py index f2f93d3b8..bf5ff3fd0 100644 --- a/benchmark/benchmark.py +++ b/benchmark/benchmark.py @@ -107,6 +107,17 @@ class Humanoid(benchmark.BenchmarkSuite): njmax = 64 +class MyoArm(benchmark.BenchmarkSuite): + """MyoArm.""" + + path = "myo_sim/arm/myoarm.xml" + params = benchmark.BenchmarkSuite.params + ("step.euler",) + batch_size = 8192 + nconmax = 16 + njmax = 48 + overrides = {"opt.ccd_iterations": 50} # default 35 is too low + + class ThreeHumanoids(benchmark.BenchmarkSuite): """Three MuJoCo humanoids on an infinite plane. @@ -130,4 +141,5 @@ class ThreeHumanoids(benchmark.BenchmarkSuite): Cloth.setup_cache = lambda s: benchmark.BenchmarkSuite.setup_cache(s) FrankaEmikaPanda.setup_cache = lambda s: benchmark.BenchmarkSuite.setup_cache(s) Humanoid.setup_cache = lambda s: benchmark.BenchmarkSuite.setup_cache(s) +MyoArm.setup_cache = lambda s: benchmark.BenchmarkSuite.setup_cache(s) ThreeHumanoids.setup_cache = lambda s: benchmark.BenchmarkSuite.setup_cache(s) diff --git a/benchmark/myosim/README.md b/benchmark/myosim/README.md new file mode 100644 index 000000000..f6eb617c9 --- /dev/null +++ b/benchmark/myosim/README.md @@ -0,0 +1,12 @@ +# Benchmark musculoskeletal environment from MyoSim + +[MyoSim](https://github.com/MyoHub/myo_sim) + +- [MyoArm](https://github.com/MyoHub/myo_sim/tree/main/arm) + + +## Get MyoSim from GitHub + +```bash +python get_myosim.py +``` \ No newline at end of file diff --git a/benchmark/myosim/get_myosim.py b/benchmark/myosim/get_myosim.py new file mode 100644 index 000000000..c33fa581e --- /dev/null +++ b/benchmark/myosim/get_myosim.py @@ -0,0 +1,68 @@ +# Copyright 2025 The Newton Developers +# +# 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. +# ============================================================================== + +"""Get MyoSim from GitHub.""" + +import subprocess +import sys +from typing import Sequence + +from absl import app +from etils import epath + +_MYOSIM_PATH = epath.Path(__file__).parent.parent / "myo_sim" + +_MYOSIM_COMMIT_SHA = "33f3ded946f55adbdcf963c99999587aadaf975f" + + +# TODO(team): shared utility with benchmark/kitchen/populate_scene._clone? +def _clone(repo_url: str, target_path: str, commit_sha: str) -> None: + """Clone a git repo with progress bar.""" + process = subprocess.Popen( + ["git", "clone", "--progress", repo_url, target_path], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ) + + while True: + # Read output line by line. + if not process.stderr.readline() and process.poll() is not None: + break + + if process.returncode != 0: + raise subprocess.CalledProcessError(process.returncode, ["git", "clone"]) + + # checkout specific commit + print(f"Checking out commit {commit_sha}") + subprocess.run(["git", "-C", target_path, "checkout", commit_sha], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + +def main(argv: Sequence[str]): + """Ensure MyoSim exists, downloading it if necessary.""" + print(f"myosim path: {_MYOSIM_PATH}") + if not _MYOSIM_PATH.exists(): + print("MyoSim not found. Downloading...") + + try: + _clone("https://github.com/MyoHub/myo_sim.git", str(_MYOSIM_PATH), _MYOSIM_COMMIT_SHA) + print("Successfully downloaded MyoSim") + except subprocess.CalledProcessError as e: + print(f"Error downloading MyoSim: {e}", file=sys.stderr) + raise + + +if __name__ == "__main__": + app.run(main) diff --git a/mujoco_warp/_src/benchmark.py b/mujoco_warp/_src/benchmark.py index 30f444a47..1754b3384 100644 --- a/mujoco_warp/_src/benchmark.py +++ b/mujoco_warp/_src/benchmark.py @@ -210,6 +210,7 @@ class BenchmarkSuite: sample_time = 0 repeat = 1 replay = "" + overrides = {} def setup_cache(self): module = importlib.import_module(self.__module__) @@ -237,6 +238,7 @@ def setup_cache(self): free_before = wp.get_device().free_memory m = io.put_model(mjm) + io.override_model(m, self.overrides) d = io.put_data(mjm, mjd, self.batch_size, self.nconmax, self.njmax) free_after = wp.get_device().free_memory