Spaces:
Sleeping
Sleeping
Multiple randomized dynamic objects. A pusher that activates mid-simulation. Full support for parameterized object count and rendering.
Browse files- assets/tray.xml +24 -11
- tray_sim.py +30 -8
assets/tray.xml
CHANGED
|
@@ -1,13 +1,26 @@
|
|
| 1 |
<mujoco model="tray_sim">
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
</mujoco>
|
|
|
|
| 1 |
<mujoco model="tray_sim">
|
| 2 |
+
<compiler angle="degree" coordinate="local" />
|
| 3 |
+
<option gravity="0 0 -9.81" />
|
| 4 |
+
<size njmax="1000" nconmax="500" />
|
| 5 |
+
<worldbody>
|
| 6 |
+
<!-- Static tray -->
|
| 7 |
+
<body name="tray" pos="0 0 0">
|
| 8 |
+
<geom type="box" size="0.3 0.3 0.02" rgba="0.5 0.5 0.5 1"/>
|
| 9 |
+
</body>
|
| 10 |
+
|
| 11 |
+
<!-- Dynamic objects (all with free joints) -->
|
| 12 |
+
<!-- You can randomize and selectively activate them in Python -->
|
| 13 |
+
{% for i in range(10) %}
|
| 14 |
+
<body name="obj{{ i }}" pos="0 0 0.1">
|
| 15 |
+
<geom type="box" size="0.015 0.015 0.015" rgba="{{ 0.1 * i }} {{ 0.2 + 0.05 * i }} {{ 0.7 - 0.05 * i }} 1" />
|
| 16 |
+
<joint type="free" />
|
| 17 |
+
</body>
|
| 18 |
+
{% endfor %}
|
| 19 |
+
|
| 20 |
+
<!-- Pusher -->
|
| 21 |
+
<body name="pusher" pos="0.3 -0.3 0.05">
|
| 22 |
+
<geom type="box" size="0.02 0.02 0.02" rgba="0 0 0 1"/>
|
| 23 |
+
<joint type="free"/>
|
| 24 |
+
</body>
|
| 25 |
+
</worldbody>
|
| 26 |
</mujoco>
|
tray_sim.py
CHANGED
|
@@ -5,21 +5,43 @@ import os
|
|
| 5 |
import tempfile
|
| 6 |
|
| 7 |
MODEL_PATH = "assets/tray.xml"
|
|
|
|
|
|
|
|
|
|
| 8 |
|
| 9 |
-
|
|
|
|
| 10 |
np.random.seed(seed)
|
| 11 |
model = mujoco.MjModel.from_xml_path(MODEL_PATH)
|
| 12 |
data = mujoco.MjData(model)
|
| 13 |
|
| 14 |
-
#
|
| 15 |
-
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
-
#
|
| 19 |
-
|
|
|
|
| 20 |
|
|
|
|
|
|
|
| 21 |
frames = []
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
mujoco.mj_step(model, data)
|
| 24 |
renderer.update_scene(data)
|
| 25 |
img = renderer.render()
|
|
@@ -27,7 +49,7 @@ def run_tray_simulation(seed=0):
|
|
| 27 |
|
| 28 |
renderer.close()
|
| 29 |
|
| 30 |
-
# Save
|
| 31 |
gif_path = os.path.join(tempfile.gettempdir(), f"tray_sim_{seed}.gif")
|
| 32 |
imageio.mimsave(gif_path, frames, fps=20)
|
| 33 |
return gif_path
|
|
|
|
| 5 |
import tempfile
|
| 6 |
|
| 7 |
MODEL_PATH = "assets/tray.xml"
|
| 8 |
+
N_OBJECTS = 5 # number of dynamic blocks to randomize
|
| 9 |
+
PUSH_START_STEP = 50
|
| 10 |
+
SIM_STEPS = 200
|
| 11 |
|
| 12 |
+
|
| 13 |
+
def run_tray_simulation(seed=0, num_objects=N_OBJECTS):
|
| 14 |
np.random.seed(seed)
|
| 15 |
model = mujoco.MjModel.from_xml_path(MODEL_PATH)
|
| 16 |
data = mujoco.MjData(model)
|
| 17 |
|
| 18 |
+
# Object initialization
|
| 19 |
+
for i in range(num_objects):
|
| 20 |
+
obj_start = i * 7 # 7 DOF per free joint body
|
| 21 |
+
pos = np.random.uniform(low=[-0.1, -0.1, 0.05], high=[0.1, 0.1, 0.15])
|
| 22 |
+
quat = [1, 0, 0, 0] # no rotation
|
| 23 |
+
data.qpos[obj_start:obj_start+3] = pos
|
| 24 |
+
data.qpos[obj_start+3:obj_start+7] = quat
|
| 25 |
+
data.qvel[i*6:i*6+6] = 0
|
| 26 |
|
| 27 |
+
# Locate pusher DOF index (last one in qpos if you have 10 objects)
|
| 28 |
+
pusher_idx = num_objects * 7
|
| 29 |
+
pusher_vel_idx = num_objects * 6
|
| 30 |
|
| 31 |
+
# Renderer
|
| 32 |
+
renderer = mujoco.Renderer(model, width=640, height=640)
|
| 33 |
frames = []
|
| 34 |
+
|
| 35 |
+
keyframes = {0: None, 25: None, 50: None, 200: None}
|
| 36 |
+
|
| 37 |
+
for t in range(SIM_STEPS):
|
| 38 |
+
if t == PUSH_START_STEP:
|
| 39 |
+
# Activate pusher
|
| 40 |
+
data.qvel[pusher_vel_idx:pusher_vel_idx+3] = [-0.05, 0.05, 0.0] # toward center
|
| 41 |
+
|
| 42 |
+
if t in keyframes:
|
| 43 |
+
imageio.imwrite(f"/tmp/frame_{t}.png", img)
|
| 44 |
+
|
| 45 |
mujoco.mj_step(model, data)
|
| 46 |
renderer.update_scene(data)
|
| 47 |
img = renderer.render()
|
|
|
|
| 49 |
|
| 50 |
renderer.close()
|
| 51 |
|
| 52 |
+
# Save to GIF
|
| 53 |
gif_path = os.path.join(tempfile.gettempdir(), f"tray_sim_{seed}.gif")
|
| 54 |
imageio.mimsave(gif_path, frames, fps=20)
|
| 55 |
return gif_path
|