tinysim 0.0.4__py3-none-any.whl → 0.0.5__py3-none-any.whl
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.
- tinysim/__init__.py +7 -2
- tinysim/_tk_base.py +20 -2
- tinysim/_widget_base.py +41 -0
- tinysim/flappy/__init__.py +5 -3
- tinysim/flappy/tk.py +10 -34
- tinysim/flappy/widget.py +9 -38
- tinysim/frogger/__init__.py +21 -4
- tinysim/frogger/tk.py +12 -28
- tinysim/frogger/widget.py +8 -37
- tinysim/mountain_car/__init__.py +17 -12
- tinysim/mountain_car/tk.py +9 -27
- tinysim/mountain_car/widget.py +8 -37
- tinysim/tinyspace.py +68 -0
- tinysim/topdown_driving/__init__.py +16 -18
- tinysim/topdown_driving/tk.py +13 -38
- tinysim/topdown_driving/track_0.json +1 -753
- tinysim/topdown_driving/widget.py +8 -42
- {tinysim-0.0.4.dist-info → tinysim-0.0.5.dist-info}/METADATA +5 -6
- {tinysim-0.0.4.dist-info → tinysim-0.0.5.dist-info}/RECORD +35 -35
- {tinysim-0.0.4.dist-info → tinysim-0.0.5.dist-info}/WHEEL +1 -1
- tinysim_mujoco/gl_viewer.py +36 -11
- tinysim_mujoco/manipulation/__init__.py +19 -5
- tinysim_mujoco/manipulation/push_env.py +268 -0
- tinysim_mujoco/manipulation/push_env_cam.py +274 -0
- tinysim_mujoco/manipulation/xmls/panda.xml +59 -16
- tinysim_mujoco/manipulation/xmls/scene.xml +0 -3
- tinysim_mujoco/manipulation/xmls/table.xml +17 -13
- tinysim_mujoco/notebook_viewer.py +3 -6
- tinysim_mujoco/unitree_a1/__init__.py +7 -10
- tinysim_warp/__init__.py +108 -0
- tinysim_warp/cart_pole/__init__.py +44 -200
- tinysim_warp/quadruped/__init__.py +23 -160
- tinysim_warp/simple_quadruped/__init__.py +20 -91
- tinysim_warp/simple_quadruped/simple_quadruped.urdf +0 -9
- tinysim/simple_amr/__init__.py +0 -0
- tinysim/simple_amr/example_maps.py +0 -121
- tinysim/simple_amr/sim.js +0 -430
- tinysim/simple_amr/styles.css +0 -54
- tinysim/simple_amr/widget.py +0 -73
- {tinysim-0.0.4.dist-info → tinysim-0.0.5.dist-info}/top_level.txt +0 -0
tinysim_warp/__init__.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
import warp as wp
|
|
7
|
+
import warp.sim.render
|
|
8
|
+
except ImportError:
|
|
9
|
+
raise ImportError(
|
|
10
|
+
"Warp is not installed. Install using `pip install tinysim[warp]`"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class WarpBaseEnv(ABC):
|
|
15
|
+
def __init__(self, use_cuda_graph=False, headless=False, num_envs=1, fps=60):
|
|
16
|
+
self.try_use_cuda_graph = use_cuda_graph
|
|
17
|
+
self.headless = headless
|
|
18
|
+
self.num_envs = num_envs
|
|
19
|
+
|
|
20
|
+
self.fps = fps
|
|
21
|
+
self.sim_time = 0.0
|
|
22
|
+
self.frame_dt = 1.0 / fps
|
|
23
|
+
self.sim_substeps = 10 # todo: make configurable
|
|
24
|
+
self.sim_dt = self.frame_dt / self.sim_substeps
|
|
25
|
+
self.num_envs = num_envs
|
|
26
|
+
self.env_offsets = self.comp_env_offsets()
|
|
27
|
+
self.model = self.build_model()
|
|
28
|
+
self.integrator = self.solver()
|
|
29
|
+
|
|
30
|
+
self.renderer = wp.sim.render.SimRendererOpenGL(
|
|
31
|
+
self.model, "viewer", headless=headless
|
|
32
|
+
)
|
|
33
|
+
self.state_0 = self.model.state()
|
|
34
|
+
self.state_1 = self.model.state()
|
|
35
|
+
wp.sim.eval_fk(
|
|
36
|
+
self.model, self.state_0.joint_q, self.state_0.joint_qd, None, self.state_0
|
|
37
|
+
)
|
|
38
|
+
self.capture_graph()
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def build_model(self):
|
|
42
|
+
raise NotImplementedError("build_model() must be implemented in subclass.")
|
|
43
|
+
|
|
44
|
+
@abstractmethod
|
|
45
|
+
def solver(self):
|
|
46
|
+
raise NotImplementedError("solver() must be implemented in subclass.")
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def apply_actions(self, actions):
|
|
50
|
+
raise NotImplementedError("apply_actions() must be implemented in subclass.")
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
def get_obs(self):
|
|
54
|
+
raise NotImplementedError("get_obs() must be implemented in subclass.")
|
|
55
|
+
|
|
56
|
+
def comp_env_offsets(self, offset=(5.0, 0.0, 0.0)):
|
|
57
|
+
offset = np.array(offset, dtype=float)
|
|
58
|
+
axis = np.nonzero(offset)[0]
|
|
59
|
+
axis = axis[0] if len(axis) else 0
|
|
60
|
+
t = np.arange(self.num_envs) * offset[axis]
|
|
61
|
+
offsets = np.zeros((self.num_envs, 3))
|
|
62
|
+
offsets[:, axis] = t - t.mean()
|
|
63
|
+
return offsets
|
|
64
|
+
|
|
65
|
+
def capture_graph(self):
|
|
66
|
+
# CUDA graph
|
|
67
|
+
self.use_cuda_graph = (
|
|
68
|
+
self.try_use_cuda_graph
|
|
69
|
+
and wp.get_device().is_cuda
|
|
70
|
+
and wp.is_mempool_enabled(wp.get_device())
|
|
71
|
+
)
|
|
72
|
+
if self.try_use_cuda_graph and not self.use_cuda_graph:
|
|
73
|
+
raise Warning("""Unable to enable CUDA graph capture.
|
|
74
|
+
Please verify that Warp is using CUDA and that the memory pool is enabled.
|
|
75
|
+
""")
|
|
76
|
+
|
|
77
|
+
if self.use_cuda_graph:
|
|
78
|
+
with wp.ScopedCapture() as capture:
|
|
79
|
+
self.simulate()
|
|
80
|
+
self.graph = capture.graph
|
|
81
|
+
|
|
82
|
+
def simulate(self):
|
|
83
|
+
for _ in range(self.sim_substeps):
|
|
84
|
+
self.state_0.clear_forces()
|
|
85
|
+
wp.sim.collide(self.model, self.state_0)
|
|
86
|
+
self.integrator.simulate(
|
|
87
|
+
self.model, self.state_0, self.state_1, self.sim_dt
|
|
88
|
+
)
|
|
89
|
+
self.state_0, self.state_1 = self.state_1, self.state_0
|
|
90
|
+
|
|
91
|
+
def step(self, actions):
|
|
92
|
+
self.apply_actions(actions)
|
|
93
|
+
|
|
94
|
+
if self.use_cuda_graph:
|
|
95
|
+
wp.capture_launch(self.graph)
|
|
96
|
+
else:
|
|
97
|
+
self.simulate()
|
|
98
|
+
|
|
99
|
+
self.sim_time += self.frame_dt
|
|
100
|
+
return self.get_obs()
|
|
101
|
+
|
|
102
|
+
def render(self):
|
|
103
|
+
self.renderer.begin_frame(self.sim_time)
|
|
104
|
+
self.renderer.render(self.state_0)
|
|
105
|
+
self.renderer.end_frame()
|
|
106
|
+
|
|
107
|
+
def reset(self, **kwargs):
|
|
108
|
+
raise NotImplementedError("reset() must be implemented in subclass.")
|
|
@@ -1,94 +1,67 @@
|
|
|
1
|
-
# written by: Matthew Taylor
|
|
2
|
-
# source: https://github.com/MatthewAndreTaylor/WarpSimBalance
|
|
3
|
-
|
|
4
|
-
try:
|
|
5
|
-
import warp as wp
|
|
6
|
-
import warp.sim.render
|
|
7
|
-
except ImportError:
|
|
8
|
-
raise ImportError(
|
|
9
|
-
"Warp is not installed. Install using `pip install tinysim[warp]`"
|
|
10
|
-
)
|
|
11
|
-
|
|
12
1
|
import numpy as np
|
|
2
|
+
import warp as wp
|
|
13
3
|
|
|
4
|
+
from tinysim_warp import WarpBaseEnv
|
|
14
5
|
|
|
15
|
-
|
|
16
|
-
env_offset = np.array(env_offset, dtype=float)
|
|
17
|
-
axis = np.nonzero(env_offset)[0]
|
|
18
|
-
axis = axis[0] if len(axis) else 0
|
|
19
|
-
env_offsets = np.zeros((num_envs, 3))
|
|
20
|
-
env_offsets[:, axis] = np.arange(num_envs) * env_offset[axis]
|
|
21
|
-
env_offsets -= env_offsets.mean(axis=0)
|
|
22
|
-
env_offsets[:, 1] = 0.0
|
|
23
|
-
return env_offsets
|
|
24
|
-
|
|
6
|
+
quat_id = wp.quat_identity()
|
|
25
7
|
|
|
26
|
-
class CartPoleBaseEnv:
|
|
27
|
-
def __init__(self, use_cuda_graph=False, headless=False, num_envs=3):
|
|
28
|
-
self.actions = np.array([0.0, 0.5, -0.5])
|
|
29
|
-
self.num_envs = num_envs
|
|
30
8
|
|
|
31
|
-
|
|
32
|
-
self.frame_dt = 1.0 / fps
|
|
33
|
-
self.sim_substeps = 10
|
|
34
|
-
self.sim_dt = self.frame_dt / self.sim_substeps
|
|
9
|
+
class CartPoleBaseEnv(WarpBaseEnv):
|
|
35
10
|
|
|
36
|
-
|
|
11
|
+
actions = np.array([0.0, 0.5, -0.5])
|
|
37
12
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
13
|
+
def build_model(self):
|
|
14
|
+
builder = wp.sim.ModelBuilder()
|
|
15
|
+
for i in range(self.num_envs):
|
|
16
|
+
builder.add_builder(
|
|
17
|
+
self.create_cartpole(),
|
|
18
|
+
xform=wp.transform(self.env_offsets[i], quat_id),
|
|
19
|
+
)
|
|
42
20
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
21
|
+
model = builder.finalize()
|
|
22
|
+
model.joint_attach_ke = 1000.0
|
|
23
|
+
model.joint_attach_kd = 1.0
|
|
24
|
+
self.joint_act_np = np.zeros(model.joint_dof_count, dtype=np.float32)
|
|
25
|
+
self.joint_act_wp = wp.array(
|
|
26
|
+
self.joint_act_np, dtype=float, device=wp.get_device()
|
|
48
27
|
)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
self.simulate()
|
|
52
|
-
self.graph = capture.graph
|
|
53
|
-
|
|
54
|
-
self.step(actions=[1] * self.num_envs)
|
|
28
|
+
model.joint_act = self.joint_act_wp
|
|
29
|
+
return model
|
|
55
30
|
|
|
56
31
|
def create_cartpole(self):
|
|
57
32
|
"""Create cartpole system using pure Python/Warp API"""
|
|
58
33
|
builder = wp.sim.ModelBuilder(gravity=-0.3)
|
|
59
|
-
pole_size = wp.vec3(0.04, 1.0, 0.06)
|
|
60
34
|
cart_body = builder.add_body(
|
|
61
|
-
origin=wp.transform(wp.vec3(0.0, 2.0, 0.0),
|
|
35
|
+
origin=wp.transform(wp.vec3(0.0, 2.0, 0.0), quat_id), m=1.0
|
|
62
36
|
)
|
|
63
37
|
builder.add_shape_sphere(body=cart_body, radius=0.1, density=100.0)
|
|
38
|
+
|
|
39
|
+
# Start angled pole
|
|
64
40
|
pole_body = builder.add_body(
|
|
65
|
-
origin=wp.transform(wp.vec3(0.0, 2.5, 0.0),
|
|
41
|
+
origin=wp.transform(wp.vec3(0.0, 2.5, 0.0), quat_id), m=0.01
|
|
66
42
|
)
|
|
43
|
+
pole_size = wp.vec3(0.04, 1.0, 0.06)
|
|
67
44
|
builder.add_shape_box(
|
|
68
45
|
body=pole_body,
|
|
69
|
-
pos=wp.vec3(0.0, 0.0, 0.0),
|
|
70
46
|
hx=pole_size[0] / 2.0,
|
|
71
47
|
hy=pole_size[1] / 2.0,
|
|
72
48
|
hz=pole_size[2] / 2.0,
|
|
73
49
|
density=50.0,
|
|
74
50
|
)
|
|
51
|
+
# Joint starts with a small initial angle
|
|
52
|
+
q = wp.quat_from_axis_angle(wp.vec3(0.0, 0.0, 1.0), 0.01)
|
|
75
53
|
builder.add_joint_revolute(
|
|
76
54
|
parent=cart_body,
|
|
77
55
|
child=pole_body,
|
|
78
56
|
axis=wp.vec3(0.0, 0.0, 1.0), # rotation around Z-axis
|
|
79
|
-
|
|
80
|
-
child_xform=wp.transform(
|
|
81
|
-
wp.vec3(0.0, -0.5, 0.0), wp.quat_identity()
|
|
82
|
-
), # joint at pole base
|
|
57
|
+
child_xform=wp.transform(wp.vec3(0.0, -0.5, 0.0), q),
|
|
83
58
|
limit_ke=1.0e4,
|
|
84
59
|
limit_kd=1.0e1,
|
|
85
60
|
)
|
|
86
61
|
builder.add_joint_prismatic(
|
|
87
62
|
parent=-1,
|
|
88
63
|
child=cart_body,
|
|
89
|
-
|
|
90
|
-
parent_xform=wp.transform(wp.vec3(0.0, 2.0, 0.0), wp.quat_identity()),
|
|
91
|
-
child_xform=wp.transform(wp.vec3(0.0, 0.0, 0.0), wp.quat_identity()),
|
|
64
|
+
parent_xform=wp.transform(wp.vec3(0.0, 2.0, 0.0), quat_id),
|
|
92
65
|
limit_lower=-5.0,
|
|
93
66
|
limit_upper=5.0,
|
|
94
67
|
limit_ke=1.0e4,
|
|
@@ -99,7 +72,10 @@ class CartPoleBaseEnv:
|
|
|
99
72
|
)
|
|
100
73
|
return builder
|
|
101
74
|
|
|
102
|
-
def
|
|
75
|
+
def solver(self):
|
|
76
|
+
return wp.sim.SemiImplicitIntegrator()
|
|
77
|
+
|
|
78
|
+
def apply_actions(self, actions):
|
|
103
79
|
if len(actions) != self.num_envs:
|
|
104
80
|
raise ValueError("Length of actions must match number of environments.")
|
|
105
81
|
|
|
@@ -108,152 +84,20 @@ class CartPoleBaseEnv:
|
|
|
108
84
|
act[dof_indices] = self.actions[actions]
|
|
109
85
|
wp.copy(self.model.joint_act, wp.array(act, dtype=wp.float32))
|
|
110
86
|
|
|
111
|
-
def is_fallen(self, pole_quat):
|
|
112
|
-
qw = float(np.clip(pole_quat[3], -1.0, 1.0))
|
|
113
|
-
tilt = 2.0 * np.arccos(qw) # radians, in [0, pi]
|
|
114
|
-
max_tilt = np.deg2rad(90.0)
|
|
115
|
-
return tilt > max_tilt
|
|
116
|
-
|
|
117
|
-
def step(self, actions):
|
|
118
|
-
"""Apply action and step the simulation for one environment timestep.
|
|
119
|
-
|
|
120
|
-
Returns (observation, reward, terminated)
|
|
121
|
-
"""
|
|
122
|
-
self.set_cart_trajectory(actions)
|
|
123
|
-
if self.use_cuda_graph:
|
|
124
|
-
wp.capture_launch(self.graph)
|
|
125
|
-
else:
|
|
126
|
-
self.simulate()
|
|
127
|
-
|
|
128
|
-
self.sim_time += self.frame_dt
|
|
129
|
-
obs = self.get_state_vector()
|
|
130
|
-
pole_quat = obs[1:5]
|
|
131
|
-
terminated = self.is_fallen(pole_quat)
|
|
132
|
-
return obs, 1.0, terminated
|
|
133
|
-
|
|
134
|
-
def simulate(self):
|
|
135
|
-
for _ in range(self.sim_substeps):
|
|
136
|
-
self.state.clear_forces()
|
|
137
|
-
self.state = self.integrator.simulate(
|
|
138
|
-
self.model, self.state, self.state, self.sim_dt
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
def reset(self):
|
|
142
|
-
self.initialize()
|
|
143
|
-
return self.step(actions=[1] * self.num_envs)
|
|
144
|
-
|
|
145
|
-
def initialize(self):
|
|
146
|
-
self.sim_time = 0.0
|
|
147
|
-
builder = wp.sim.ModelBuilder()
|
|
148
|
-
offsets = compute_env_offsets(self.num_envs)
|
|
149
|
-
|
|
150
|
-
for i in range(self.num_envs):
|
|
151
|
-
builder.add_builder(
|
|
152
|
-
self.create_cartpole(),
|
|
153
|
-
xform=wp.transform(offsets[i], wp.quat_identity()),
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
self.model = builder.finalize()
|
|
157
|
-
self.model.joint_attach_ke = 1000.0
|
|
158
|
-
self.model.joint_attach_kd = 1.0
|
|
159
|
-
self.state = self.model.state()
|
|
160
|
-
|
|
161
|
-
wp.sim.eval_fk(
|
|
162
|
-
self.model, self.model.joint_q, self.model.joint_qd, None, self.state
|
|
163
|
-
)
|
|
164
|
-
self.joint_act_np = np.zeros(self.model.joint_dof_count, dtype=np.float32)
|
|
165
|
-
self.joint_act_wp = wp.array(
|
|
166
|
-
self.joint_act_np, dtype=float, device=wp.get_device()
|
|
167
|
-
)
|
|
168
|
-
self.model.joint_act = self.joint_act_wp
|
|
169
|
-
|
|
170
|
-
def render(self):
|
|
171
|
-
self.renderer.begin_frame(self.sim_time)
|
|
172
|
-
self.renderer.render(self.state)
|
|
173
|
-
self.renderer.end_frame()
|
|
174
|
-
|
|
175
87
|
def get_state_vector(self):
|
|
176
|
-
cart_id = 0
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
# convert transforms to numpy
|
|
180
|
-
body_q = self.state.body_q.numpy()
|
|
181
|
-
body_qd = self.state.body_qd.numpy()
|
|
182
|
-
|
|
183
|
-
# --- Cart ---
|
|
88
|
+
cart_id, pole_id = 0, 1 # body indices
|
|
89
|
+
body_q = self.state_0.body_q.numpy()
|
|
90
|
+
body_qd = self.state_0.body_qd.numpy()
|
|
184
91
|
cart_pos = body_q[cart_id] # [px, py, pz, qx, qy, qz, qw]
|
|
185
|
-
# cart_pos = cart_pos[[0, 2]]
|
|
186
|
-
cart_pos = cart_pos[[0]]
|
|
187
|
-
|
|
188
|
-
# --- Pole ---
|
|
92
|
+
cart_pos = cart_pos[[0]] # cart_pos = cart_pos[[0, 2]]
|
|
189
93
|
pole_quat = body_q[pole_id][3:] # quaternion part
|
|
190
94
|
pole_vel = body_qd[pole_id][3:] # angular velocity part
|
|
191
|
-
|
|
192
95
|
return np.concatenate([cart_pos, pole_quat, pole_vel])
|
|
193
96
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
parser.add_argument(
|
|
202
|
-
"--device", type=str, default=None, help="Override the default Warp device."
|
|
203
|
-
)
|
|
204
|
-
parser.add_argument(
|
|
205
|
-
"--num-frames", type=int, default=1200, help="Total number of frames."
|
|
206
|
-
)
|
|
207
|
-
parser.add_argument(
|
|
208
|
-
"--manual-control", action="store_true", help="Enable manual control."
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
args = parser.parse_known_args()[0]
|
|
212
|
-
|
|
213
|
-
if args.manual_control:
|
|
214
|
-
print("Manual control enabled")
|
|
215
|
-
import keyboard
|
|
216
|
-
|
|
217
|
-
with wp.ScopedDevice(args.device):
|
|
218
|
-
example = CartPoleBaseEnv(use_cuda_graph=True)
|
|
219
|
-
|
|
220
|
-
terminated = False
|
|
221
|
-
check_terminated = True
|
|
222
|
-
|
|
223
|
-
for i in range(args.num_frames):
|
|
224
|
-
if args.manual_control:
|
|
225
|
-
# Manual control logic
|
|
226
|
-
if keyboard.is_pressed("k"):
|
|
227
|
-
action = 2
|
|
228
|
-
elif keyboard.is_pressed("l"):
|
|
229
|
-
action = 1
|
|
230
|
-
else:
|
|
231
|
-
action = 0
|
|
232
|
-
|
|
233
|
-
else:
|
|
234
|
-
# Example control signals
|
|
235
|
-
if i < 200:
|
|
236
|
-
action = 0
|
|
237
|
-
elif i < 255: # 260
|
|
238
|
-
action = 2
|
|
239
|
-
else:
|
|
240
|
-
action = 0
|
|
241
|
-
|
|
242
|
-
obs, reward, terminated = example.step(actions=[action] * example.num_envs)
|
|
243
|
-
# print(f"Step {i}")
|
|
244
|
-
|
|
245
|
-
if check_terminated and terminated:
|
|
246
|
-
print("Pole fallen")
|
|
247
|
-
check_terminated = False
|
|
248
|
-
|
|
249
|
-
example.render()
|
|
250
|
-
|
|
251
|
-
# print("State Vector:", obs)
|
|
252
|
-
# print("Reward:", reward)
|
|
253
|
-
# print("Terminated:", terminated)
|
|
254
|
-
|
|
255
|
-
state = example.reset()
|
|
256
|
-
print("Reset State Vector:", state)
|
|
257
|
-
example.render()
|
|
258
|
-
|
|
259
|
-
example.renderer.save()
|
|
97
|
+
def get_obs(self):
|
|
98
|
+
obs = self.get_state_vector()
|
|
99
|
+
pole_quat = obs[1:5]
|
|
100
|
+
qw = float(np.clip(pole_quat[3], -1.0, 1.0))
|
|
101
|
+
tilt = 2.0 * np.arccos(qw) # radians, in [0, pi]
|
|
102
|
+
max_tilt = np.deg2rad(90.0)
|
|
103
|
+
return obs, 1.0, tilt > max_tilt
|
|
@@ -1,37 +1,21 @@
|
|
|
1
|
-
import
|
|
2
|
-
import os
|
|
1
|
+
import pathlib
|
|
3
2
|
|
|
4
3
|
import numpy as np
|
|
4
|
+
import warp as wp
|
|
5
|
+
import warp.examples
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
import warp as wp
|
|
8
|
-
import warp.examples
|
|
9
|
-
import warp.sim.render
|
|
10
|
-
except ImportError:
|
|
11
|
-
raise ImportError(
|
|
12
|
-
"Warp is not installed. Install using `pip install tinysim[warp]`"
|
|
13
|
-
)
|
|
7
|
+
from tinysim_warp import WarpBaseEnv
|
|
14
8
|
|
|
15
9
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
axis = axis[0] if len(axis) else 0
|
|
20
|
-
env_offsets = np.zeros((num_envs, 3))
|
|
21
|
-
env_offsets[:, axis] = np.arange(num_envs) * env_offset[axis]
|
|
22
|
-
env_offsets -= env_offsets.mean(axis=0)
|
|
23
|
-
env_offsets[:, 1] = 0.0
|
|
24
|
-
return env_offsets
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class RobotDogBaseEnv:
|
|
28
|
-
def __init__(self, use_cuda_graph=False, headless=False, num_envs=8):
|
|
10
|
+
class RobotDogBaseEnv(WarpBaseEnv):
|
|
11
|
+
def build_model(self):
|
|
12
|
+
builder = wp.sim.ModelBuilder()
|
|
29
13
|
articulation_builder = wp.sim.ModelBuilder()
|
|
30
|
-
rot_x = wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), -
|
|
31
|
-
rot_y = wp.quat_from_axis_angle(wp.vec3(0.0, 1.0, 0.0),
|
|
14
|
+
rot_x = wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), -np.pi * 0.5)
|
|
15
|
+
rot_y = wp.quat_from_axis_angle(wp.vec3(0.0, 1.0, 0.0), np.pi * 0.5)
|
|
32
16
|
xform = wp.transform(wp.vec3(0.0, 0.65, 0.0), rot_y * rot_x)
|
|
33
17
|
wp.sim.parse_urdf(
|
|
34
|
-
|
|
18
|
+
str(pathlib.Path(warp.examples.get_asset_directory()) / "quadruped.urdf"),
|
|
35
19
|
articulation_builder,
|
|
36
20
|
xform=xform,
|
|
37
21
|
floating=True,
|
|
@@ -47,21 +31,10 @@ class RobotDogBaseEnv:
|
|
|
47
31
|
limit_kd=1.0e1,
|
|
48
32
|
)
|
|
49
33
|
|
|
50
|
-
builder = wp.sim.ModelBuilder()
|
|
51
|
-
|
|
52
|
-
self.sim_time = 0.0
|
|
53
|
-
fps = 100
|
|
54
|
-
self.frame_dt = 1.0 / fps
|
|
55
|
-
|
|
56
|
-
self.sim_substeps = 10
|
|
57
|
-
self.sim_dt = self.frame_dt / self.sim_substeps
|
|
58
|
-
|
|
59
|
-
self.num_envs = num_envs
|
|
60
|
-
offsets = compute_env_offsets(self.num_envs)
|
|
61
|
-
|
|
62
34
|
for i in range(self.num_envs):
|
|
63
35
|
builder.add_builder(
|
|
64
|
-
articulation_builder,
|
|
36
|
+
articulation_builder,
|
|
37
|
+
xform=wp.transform(self.env_offsets[i], wp.quat_identity()),
|
|
65
38
|
)
|
|
66
39
|
builder.joint_q[-12:] = [0.2, 0.4, -0.6, -0.2, -0.4, 0.6, -0.2, 0.4, -0.6, 0.2, -0.4, 0.6] # fmt: skip
|
|
67
40
|
builder.joint_act[-12:] = [0.2, 0.4, -0.6, -0.2, -0.4, 0.6, -0.2, 0.4, -0.6, 0.2, -0.4, 0.6] # fmt: skip
|
|
@@ -69,50 +42,18 @@ class RobotDogBaseEnv:
|
|
|
69
42
|
builder.joint_axis_mode
|
|
70
43
|
)
|
|
71
44
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
self.model.joint_attach_kd = 200.0
|
|
77
|
-
self.use_tile_gemm = False
|
|
78
|
-
self.fuse_cholesky = False
|
|
45
|
+
model = builder.finalize()
|
|
46
|
+
model.joint_attach_ke = 16000.0
|
|
47
|
+
model.joint_attach_kd = 200.0
|
|
48
|
+
return model
|
|
79
49
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
fuse_cholesky=self.fuse_cholesky,
|
|
50
|
+
def solver(self):
|
|
51
|
+
return wp.sim.FeatherstoneIntegrator(
|
|
52
|
+
self.model, use_tile_gemm=False, fuse_cholesky=False
|
|
84
53
|
)
|
|
85
54
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
)
|
|
89
|
-
self.state_0 = self.model.state()
|
|
90
|
-
self.state_1 = self.model.state()
|
|
91
|
-
|
|
92
|
-
wp.sim.eval_fk(
|
|
93
|
-
self.model, self.model.joint_q, self.model.joint_qd, None, self.state_0
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
self.use_cuda_graph = (
|
|
97
|
-
use_cuda_graph
|
|
98
|
-
and wp.get_device().is_cuda
|
|
99
|
-
and wp.is_mempool_enabled(wp.get_device())
|
|
100
|
-
)
|
|
101
|
-
if self.use_cuda_graph:
|
|
102
|
-
with wp.ScopedCapture() as capture:
|
|
103
|
-
self.simulate()
|
|
104
|
-
self.graph = capture.graph
|
|
105
|
-
|
|
106
|
-
def simulate(self):
|
|
107
|
-
for _ in range(self.sim_substeps):
|
|
108
|
-
self.state_0.clear_forces()
|
|
109
|
-
wp.sim.collide(self.model, self.state_0)
|
|
110
|
-
self.integrator.simulate(
|
|
111
|
-
self.model, self.state_0, self.state_1, self.sim_dt
|
|
112
|
-
)
|
|
113
|
-
self.state_0, self.state_1 = self.state_1, self.state_0
|
|
114
|
-
|
|
115
|
-
def set_leg_poses(self, actions):
|
|
55
|
+
def apply_actions(self, actions):
|
|
56
|
+
# Set the target positions for all legs
|
|
116
57
|
action_space_size = 12 * self.num_envs
|
|
117
58
|
if len(actions) != action_space_size:
|
|
118
59
|
raise ValueError(
|
|
@@ -121,83 +62,5 @@ class RobotDogBaseEnv:
|
|
|
121
62
|
|
|
122
63
|
wp.copy(self.model.joint_act, wp.array(actions, dtype=wp.float32))
|
|
123
64
|
|
|
124
|
-
def
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if self.use_cuda_graph:
|
|
128
|
-
wp.capture_launch(self.graph)
|
|
129
|
-
else:
|
|
130
|
-
self.simulate()
|
|
131
|
-
self.sim_time += self.frame_dt
|
|
132
|
-
|
|
133
|
-
def render(self):
|
|
134
|
-
self.renderer.begin_frame(self.sim_time)
|
|
135
|
-
self.renderer.render(self.state_0)
|
|
136
|
-
self.renderer.end_frame()
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if __name__ == "__main__":
|
|
140
|
-
import argparse
|
|
141
|
-
|
|
142
|
-
parser = argparse.ArgumentParser(
|
|
143
|
-
formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
|
144
|
-
)
|
|
145
|
-
parser.add_argument(
|
|
146
|
-
"--device", type=str, default=None, help="Override the default Warp device."
|
|
147
|
-
)
|
|
148
|
-
parser.add_argument(
|
|
149
|
-
"--num-frames", type=int, default=300, help="Total number of frames."
|
|
150
|
-
)
|
|
151
|
-
parser.add_argument(
|
|
152
|
-
"--num-envs",
|
|
153
|
-
type=int,
|
|
154
|
-
default=3,
|
|
155
|
-
help="Total number of simulated environments.",
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
args = parser.parse_known_args()[0]
|
|
159
|
-
|
|
160
|
-
with wp.ScopedDevice(args.device):
|
|
161
|
-
example = RobotDogBaseEnv(num_envs=args.num_envs)
|
|
162
|
-
# [
|
|
163
|
-
# (front right leg out),
|
|
164
|
-
# (front right leg forward),
|
|
165
|
-
# (front right forearm forward),
|
|
166
|
-
|
|
167
|
-
# (front left leg out),
|
|
168
|
-
# (front left leg forward),
|
|
169
|
-
# (front left forearm forward),
|
|
170
|
-
|
|
171
|
-
# (back right leg out),
|
|
172
|
-
# (back right leg forward),
|
|
173
|
-
# (back right forearm forward),
|
|
174
|
-
|
|
175
|
-
# (back left leg out),
|
|
176
|
-
# (back left leg forward),
|
|
177
|
-
# (back left forearm forward),
|
|
178
|
-
# ]
|
|
179
|
-
# left and right directions are reversed
|
|
180
|
-
|
|
181
|
-
actions = [0.2, 0.4, -0.6, -0.2, -0.4, 0.6, -0.2, 0.4, -0.6, 0.2, -0.4, 0.6] * args.num_envs # fmt: skip
|
|
182
|
-
|
|
183
|
-
for i in range(args.num_frames):
|
|
184
|
-
example.step(actions)
|
|
185
|
-
example.render()
|
|
186
|
-
|
|
187
|
-
if i % 10 == 0:
|
|
188
|
-
# Stretch the right leg to the side
|
|
189
|
-
# actions[0] += 0.1
|
|
190
|
-
|
|
191
|
-
# Stretch the right leg forward
|
|
192
|
-
actions[1] += 0.1
|
|
193
|
-
|
|
194
|
-
# Strecth the forearm foward
|
|
195
|
-
# actions[2] += 0.1
|
|
196
|
-
|
|
197
|
-
# Stretch the left leg forward
|
|
198
|
-
actions[4] -= 0.1
|
|
199
|
-
|
|
200
|
-
# Back right leg backwards
|
|
201
|
-
# actions[7] += 0.1
|
|
202
|
-
|
|
203
|
-
example.renderer.save()
|
|
65
|
+
def get_obs(self):
|
|
66
|
+
return
|