mujoco-toolbox 0.1.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Michael Gross
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,186 @@
1
+ Metadata-Version: 2.3
2
+ Name: mujoco-toolbox
3
+ Version: 0.1.8
4
+ Summary: A modern package to handle MuJoCo environments
5
+ License: MIT
6
+ Keywords: MuJoCo,robotics,simulation,toolbox,wrapper
7
+ Author: MGross21
8
+ Author-email: MGross21@TODO.com
9
+ Requires-Python: >=3.10
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Topic :: Software Development :: Libraries
15
+ Provides-Extra: dev
16
+ Requires-Dist: ffmpeg
17
+ Requires-Dist: ipywidgets
18
+ Requires-Dist: matplotlib
19
+ Requires-Dist: mediapy
20
+ Requires-Dist: mujoco
21
+ Requires-Dist: mypy ; extra == "dev"
22
+ Requires-Dist: numpy
23
+ Requires-Dist: pytest ; extra == "dev"
24
+ Requires-Dist: pyyaml
25
+ Requires-Dist: ruff ; extra == "dev"
26
+ Requires-Dist: scipy
27
+ Requires-Dist: screeninfo
28
+ Requires-Dist: tqdm
29
+ Requires-Dist: trimesh
30
+ Project-URL: Documentation, https://github.com/MGross21/mujoco-toolbox
31
+ Project-URL: Homepage, https://github.com/MGross21/mujoco-toolbox
32
+ Project-URL: Repository, https://github.com/MGross21/mujoco-toolbox
33
+ Project-URL: bug-tracker, https://github.com/MGross21/mujoco-toolbox/issues
34
+ Description-Content-Type: text/markdown
35
+
36
+ ![Build](https://github.com/MGross21/mujoco-toolbox/actions/workflows/ci.yml/badge.svg)
37
+ ![Python](https://img.shields.io/badge/python-3.10%20|%203.11%20|%203.12%20|%203.13-blue)
38
+ ![License](https://img.shields.io/github/license/MGross21/mujoco-toolbox)
39
+ [![PyPI](https://github.com/MGross21/mujoco-toolbox/actions/workflows/publish.yml/badge.svg)](https://github.com/MGross21/mujoco-toolbox/actions/workflows/publish.yml)
40
+
41
+ # Mujoco Toolbox
42
+
43
+ Streamlines the MuJoCo Physics Simulator
44
+
45
+ ## PyPI Package
46
+
47
+ ```bash
48
+ pip install -U mujoco-toolbox
49
+ ```
50
+
51
+ ## For Local Install
52
+
53
+ *Navigate to the Directory that you wish to place the package*
54
+
55
+ <details>
56
+ <summary><b>JUPYTER NOTEBOOK</b></summary>
57
+ </br>
58
+ *Place Commands Inside Cell*
59
+
60
+ One-Time Install:
61
+
62
+ ```python
63
+ !git clone https://github.com/MGross21/mujoco-toolbox
64
+ !pip install -U ./mujoco-toolbox
65
+ ```
66
+
67
+ Check for Updates:
68
+
69
+ ```python
70
+ !git pull origin main
71
+ ```
72
+
73
+ Install/Check for Updates:
74
+
75
+ ```python
76
+ folder = "mujoco-toolbox"
77
+ repo_url = f"https://github.com/MGross21/{folder}"
78
+
79
+ !if [ -d "{folder}" ]; then cd {folder} && git pull && cd ..; else git clone {repo_url}; fi
80
+ !pip install -U ./{folder}
81
+ ```
82
+
83
+ </details>
84
+ </br>
85
+
86
+ <details>
87
+ <summary><b>BASH WINDOW</b></summary>
88
+ </br>
89
+ One-Time Install:
90
+
91
+ ```bash
92
+ git clone https://github.com/MGross21/mujoco-toolbox
93
+ pip install -U ./mujoco-toolbox
94
+ ```
95
+
96
+ Check for Updates:
97
+ ```bash
98
+ git pull origin main
99
+ ```
100
+
101
+ Install/Check for Updates:
102
+
103
+ ```bash
104
+ REPO_DIR="mujoco-toolbox"
105
+ REPO_URL="https://github.com/MGross21/mujoco-toolbox"
106
+
107
+ if [ -d "$REPO_DIR" ]; then
108
+ cd "$REPO_DIR" && git fetch origin && git pull origin main
109
+ else
110
+ git clone $REPO_URL
111
+ cd "$REPO_DIR"
112
+ fi
113
+
114
+ pip install -U ./mujoco-toolbox
115
+ ```
116
+
117
+ </details>
118
+
119
+ ## Extra Packages
120
+
121
+ <details>
122
+ <summary><b>FFMPEG</b></summary>
123
+
124
+ </br>
125
+
126
+ *Required for [mediapy](https://google.github.io/mediapy/mediapy.html) dependency*
127
+
128
+ **Windows**
129
+
130
+ ```bash
131
+ winget install ffmpeg
132
+ ffmpeg -version
133
+ ```
134
+
135
+ **Linux**
136
+
137
+ ```bash
138
+ sudo apt update && sudo apt install ffmpeg
139
+ ffmpeg -version
140
+ ```
141
+
142
+ **MacOS**
143
+
144
+ *Using Homebrew*
145
+
146
+ ```bash
147
+ brew install ffmpeg
148
+ ffmpeg -version
149
+ ```
150
+
151
+ *Using MacPorts*
152
+
153
+ ```bash
154
+ sudo port install ffmpeg
155
+ ffmpeg -version
156
+ ```
157
+
158
+ </details>
159
+
160
+ ## To Run in Scripts
161
+
162
+ ```python
163
+ import mujoco_toolbox as mjtb
164
+ from mujoco_toolbox import Wrapper
165
+
166
+ # Optional Global Variables
167
+ mjtb.VERBOSITY = True # Additional Performance and Debugging Print Statements (Default=False)
168
+ mjtb.CAPTURE_PARAMETERS = "all" # MjData Simulation Parameters (Default = ['time', 'qpos', 'qvel', 'act', 'qacc', 'xpos', 'xquat', 'xmat', 'ctrl', 'sensordata'])
169
+
170
+ # Example Code
171
+ Wrapper("path/to/your/xml").runSim(render=True).renderMedia()
172
+ ```
173
+
174
+ ## Pre-Made Controllers
175
+
176
+ ```python
177
+ import mujoco_toolbox as mjtb
178
+
179
+ mjtb.sineController(m,d,**kwargs)
180
+ mjtb.cosineController(m,d,**kwargs)
181
+ mjtb.stepController(m,d,**kwargs)
182
+ mjtb.randomController(m,d,**kwargs)
183
+
184
+ # Wrapper can use custom controllers as well!
185
+ ```
186
+
@@ -0,0 +1,150 @@
1
+ ![Build](https://github.com/MGross21/mujoco-toolbox/actions/workflows/ci.yml/badge.svg)
2
+ ![Python](https://img.shields.io/badge/python-3.10%20|%203.11%20|%203.12%20|%203.13-blue)
3
+ ![License](https://img.shields.io/github/license/MGross21/mujoco-toolbox)
4
+ [![PyPI](https://github.com/MGross21/mujoco-toolbox/actions/workflows/publish.yml/badge.svg)](https://github.com/MGross21/mujoco-toolbox/actions/workflows/publish.yml)
5
+
6
+ # Mujoco Toolbox
7
+
8
+ Streamlines the MuJoCo Physics Simulator
9
+
10
+ ## PyPI Package
11
+
12
+ ```bash
13
+ pip install -U mujoco-toolbox
14
+ ```
15
+
16
+ ## For Local Install
17
+
18
+ *Navigate to the Directory that you wish to place the package*
19
+
20
+ <details>
21
+ <summary><b>JUPYTER NOTEBOOK</b></summary>
22
+ </br>
23
+ *Place Commands Inside Cell*
24
+
25
+ One-Time Install:
26
+
27
+ ```python
28
+ !git clone https://github.com/MGross21/mujoco-toolbox
29
+ !pip install -U ./mujoco-toolbox
30
+ ```
31
+
32
+ Check for Updates:
33
+
34
+ ```python
35
+ !git pull origin main
36
+ ```
37
+
38
+ Install/Check for Updates:
39
+
40
+ ```python
41
+ folder = "mujoco-toolbox"
42
+ repo_url = f"https://github.com/MGross21/{folder}"
43
+
44
+ !if [ -d "{folder}" ]; then cd {folder} && git pull && cd ..; else git clone {repo_url}; fi
45
+ !pip install -U ./{folder}
46
+ ```
47
+
48
+ </details>
49
+ </br>
50
+
51
+ <details>
52
+ <summary><b>BASH WINDOW</b></summary>
53
+ </br>
54
+ One-Time Install:
55
+
56
+ ```bash
57
+ git clone https://github.com/MGross21/mujoco-toolbox
58
+ pip install -U ./mujoco-toolbox
59
+ ```
60
+
61
+ Check for Updates:
62
+ ```bash
63
+ git pull origin main
64
+ ```
65
+
66
+ Install/Check for Updates:
67
+
68
+ ```bash
69
+ REPO_DIR="mujoco-toolbox"
70
+ REPO_URL="https://github.com/MGross21/mujoco-toolbox"
71
+
72
+ if [ -d "$REPO_DIR" ]; then
73
+ cd "$REPO_DIR" && git fetch origin && git pull origin main
74
+ else
75
+ git clone $REPO_URL
76
+ cd "$REPO_DIR"
77
+ fi
78
+
79
+ pip install -U ./mujoco-toolbox
80
+ ```
81
+
82
+ </details>
83
+
84
+ ## Extra Packages
85
+
86
+ <details>
87
+ <summary><b>FFMPEG</b></summary>
88
+
89
+ </br>
90
+
91
+ *Required for [mediapy](https://google.github.io/mediapy/mediapy.html) dependency*
92
+
93
+ **Windows**
94
+
95
+ ```bash
96
+ winget install ffmpeg
97
+ ffmpeg -version
98
+ ```
99
+
100
+ **Linux**
101
+
102
+ ```bash
103
+ sudo apt update && sudo apt install ffmpeg
104
+ ffmpeg -version
105
+ ```
106
+
107
+ **MacOS**
108
+
109
+ *Using Homebrew*
110
+
111
+ ```bash
112
+ brew install ffmpeg
113
+ ffmpeg -version
114
+ ```
115
+
116
+ *Using MacPorts*
117
+
118
+ ```bash
119
+ sudo port install ffmpeg
120
+ ffmpeg -version
121
+ ```
122
+
123
+ </details>
124
+
125
+ ## To Run in Scripts
126
+
127
+ ```python
128
+ import mujoco_toolbox as mjtb
129
+ from mujoco_toolbox import Wrapper
130
+
131
+ # Optional Global Variables
132
+ mjtb.VERBOSITY = True # Additional Performance and Debugging Print Statements (Default=False)
133
+ mjtb.CAPTURE_PARAMETERS = "all" # MjData Simulation Parameters (Default = ['time', 'qpos', 'qvel', 'act', 'qacc', 'xpos', 'xquat', 'xmat', 'ctrl', 'sensordata'])
134
+
135
+ # Example Code
136
+ Wrapper("path/to/your/xml").runSim(render=True).renderMedia()
137
+ ```
138
+
139
+ ## Pre-Made Controllers
140
+
141
+ ```python
142
+ import mujoco_toolbox as mjtb
143
+
144
+ mjtb.sineController(m,d,**kwargs)
145
+ mjtb.cosineController(m,d,**kwargs)
146
+ mjtb.stepController(m,d,**kwargs)
147
+ mjtb.randomController(m,d,**kwargs)
148
+
149
+ # Wrapper can use custom controllers as well!
150
+ ```
@@ -0,0 +1,131 @@
1
+ from numpy import cos, pi, random, sin
2
+
3
+
4
+ def _apply_control(model, data, value, joint=None, axis=None, delay=0):
5
+ """Common helper function for controller logic to reduce redundancy.
6
+
7
+ Args:
8
+ model: MuJoCo model.
9
+ data: MuJoCo data.
10
+ value: Control value to apply.
11
+ joint (list[int], optional): Joints to apply control to.
12
+ axis (int, optional): Axis to apply control to.
13
+ delay (float, optional): Delay before applying control.
14
+ """
15
+ # Don't apply control until after delay
16
+ if data.time < delay:
17
+ return
18
+
19
+ # Determine targets if not explicitly provided
20
+ if joint is None and axis is None:
21
+ joint = range(model.nu)
22
+
23
+ # Apply control to joints or specific axis
24
+ if joint is not None and model.nu > 0:
25
+ for j in joint:
26
+ data.ctrl[j] = value
27
+ elif axis is not None:
28
+ data.qpos[axis] = value
29
+
30
+
31
+ def stepController(model, data, **kwargs):
32
+ """A step controller for the simulation.
33
+
34
+ Args:
35
+ amplitude (float): The amplitude of the step signal (default=1).
36
+ joint (list[int]): The joints to apply the step signal to (default=all).
37
+ axis (int): The axis to apply the step signal to (default=None).
38
+ delay (float): The delay before applying the step signal (default=0).
39
+
40
+ Returns:
41
+ None
42
+ """
43
+ amplitude = kwargs.get("amplitude", 1)
44
+ joint = kwargs.get("joint", None)
45
+ axis = kwargs.get("axis", None)
46
+ delay = kwargs.get("delay", 0)
47
+
48
+ if delay < 0:
49
+ raise ValueError("Delay must be non-negative.")
50
+ if joint is not None and axis is not None:
51
+ raise ValueError("Cannot specify both 'joint' and 'axis'.")
52
+
53
+ _apply_control(model, data, amplitude, joint=joint, axis=axis, delay=delay)
54
+
55
+
56
+ def sineController(model, data, **kwargs):
57
+ """A simple sine wave controller for the simulation.
58
+
59
+ Args:
60
+ amplitude (float): The amplitude of the sine wave (default=1).
61
+ frequency (float): The frequency of the sine wave (default=1).
62
+ phase (float): The phase shift of the sine wave (default=0).
63
+ joint (list[int]): The joint to apply the sine wave to (default=all).
64
+ delay (float): The delay before applying the sine wave (default=0).
65
+
66
+ Returns:
67
+ None
68
+ """
69
+ amplitude = kwargs.get("amplitude", 1)
70
+ frequency = kwargs.get("frequency", 1)
71
+ phase = kwargs.get("phase", 0)
72
+ joint = kwargs.get("joint", None)
73
+ delay = kwargs.get("delay", 0)
74
+
75
+ if delay < 0:
76
+ raise ValueError("Delay must be non-negative.")
77
+
78
+ value = amplitude * sin(2 * pi * frequency * data.time + phase)
79
+ _apply_control(model, data, value, joint=joint, delay=delay)
80
+
81
+
82
+ def cosineController(model, data, **kwargs):
83
+ """A simple cosine wave controller for the simulation.
84
+
85
+ Args:
86
+ amplitude (float): The amplitude of the cosine wave (default=1).
87
+ frequency (float): The frequency of the cosine wave (default=1).
88
+ phase (float): The phase shift of the cosine wave (default=0).
89
+ joint (list[int]): The joint to apply the cosine wave to (default=all).
90
+ delay (float): The delay before applying the cosine wave (default=0).
91
+
92
+ Returns:
93
+ None
94
+ """
95
+ amplitude = kwargs.get("amplitude", 1)
96
+ frequency = kwargs.get("frequency", 1)
97
+ phase = kwargs.get("phase", 0)
98
+ joint = kwargs.get("joint", None)
99
+ delay = kwargs.get("delay", 0)
100
+
101
+ if delay < 0:
102
+ raise ValueError("Delay must be non-negative.")
103
+
104
+ value = amplitude * cos(2 * pi * frequency * data.time + phase)
105
+ _apply_control(model, data, value, joint=joint, delay=delay)
106
+
107
+
108
+ def randomController(model, data, **kwargs):
109
+ """A random controller for the simulation.
110
+
111
+ Args:
112
+ amplitude (float): The maximum amplitude of the random signal (default=1).
113
+ joint (list[int]): The joints to apply the random signal to (default=all).
114
+ axis (int): The axis to apply the random signal to (default=None).
115
+ delay (float): The delay before applying the random signal (default=0).
116
+
117
+ Returns:
118
+ None
119
+ """
120
+ amplitude = kwargs.get("amplitude", 1)
121
+ joint = kwargs.get("joint", None)
122
+ axis = kwargs.get("axis", None)
123
+ delay = kwargs.get("delay", 0)
124
+
125
+ if delay < 0:
126
+ raise ValueError("Delay must be non-negative.")
127
+ if joint is not None and axis is not None:
128
+ raise ValueError("Cannot specify both 'joint' and 'axis'.")
129
+
130
+ value = amplitude * random.rand()
131
+ _apply_control(model, data, value, joint=joint, axis=axis, delay=delay)
@@ -0,0 +1,53 @@
1
+ from functools import wraps
2
+ from sys import platform
3
+ from time import time
4
+
5
+
6
+ def timer(func):
7
+ @wraps(func)
8
+ def time_wrapper(*args, **kwargs):
9
+ start_time = time()
10
+ result = func(*args, **kwargs)
11
+ end_time = time()
12
+ total_time = end_time - start_time
13
+
14
+ from . import VERBOSITY
15
+
16
+ if VERBOSITY:
17
+ print(f"Function '{func.__name__}' took {total_time:.4f} seconds")
18
+ return result
19
+
20
+ return time_wrapper
21
+
22
+
23
+ def print_warning(*args) -> None:
24
+ """
25
+ Prints the first argument as an orange warning message and prints the other arguments in regular text, all on the same line.
26
+
27
+ Args:
28
+ *args: First argument is printed as an orange warning, other arguments are printed normally.
29
+ """
30
+ if args:
31
+ # Make sure the first argument is printed with the 'WARNING:' prefix and in orange
32
+ message = f"WARNING: {args[0]}"
33
+
34
+ # Check if we're on Windows or a Unix-like system for color support
35
+ if platform.startswith("win"):
36
+ try:
37
+ from colorama import Fore, Style, init
38
+
39
+ init() # Initialize colorama
40
+ print(
41
+ f"{Fore.YELLOW}{message}{Style.RESET_ALL}", end=" "
42
+ ) # Yellow color for warning
43
+ print(
44
+ *args[1:], end=""
45
+ ) # No newline, print all args separated by spaces
46
+ except ImportError:
47
+ # If colorama is not available, print without color
48
+ print(message, end=" ")
49
+ print(*args[1:], end="")
50
+ else:
51
+ # ANSI escape code for orange (for Unix-like systems)
52
+ print(f"\033[38;5;214m{message}\033[0m", end=" ") # Orange ANSI escape code
53
+ print(*args[1:], end="") # No newline, print all args separated by spaces