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/tinyspace.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
# It is encouraged to implement your own Space classes or use existing ones from external libraries.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Space:
|
|
9
|
+
"""A minimal implementation of the Space class for TinySim."""
|
|
10
|
+
|
|
11
|
+
def sample(self) -> Any:
|
|
12
|
+
"""Randomly sample an element from this space."""
|
|
13
|
+
raise NotImplementedError
|
|
14
|
+
|
|
15
|
+
def contains(self, x: Any) -> bool:
|
|
16
|
+
"""Return boolean specifying if x is a valid member of this space."""
|
|
17
|
+
raise NotImplementedError
|
|
18
|
+
|
|
19
|
+
def __contains__(self, x: Any) -> bool:
|
|
20
|
+
return self.contains(x)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Discrete(Space):
|
|
24
|
+
"""A discrete space in TinySim."""
|
|
25
|
+
|
|
26
|
+
def __init__(self, n: int):
|
|
27
|
+
assert n >= 0, "n (number of elements) must be non-negative"
|
|
28
|
+
self.n = n
|
|
29
|
+
|
|
30
|
+
def sample(self) -> int:
|
|
31
|
+
return np.random.randint(0, self.n)
|
|
32
|
+
|
|
33
|
+
def contains(self, x: Any) -> bool:
|
|
34
|
+
return isinstance(x, int) and 0 <= x < self.n
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Box(Space):
|
|
38
|
+
"""A box space in TinySim."""
|
|
39
|
+
|
|
40
|
+
def __init__(self, low: float, high: float, shape: tuple, dtype=np.float32):
|
|
41
|
+
self.low = np.full(shape, low, dtype=dtype)
|
|
42
|
+
self.high = np.full(shape, high, dtype=dtype)
|
|
43
|
+
self.shape = shape
|
|
44
|
+
self.dtype = dtype
|
|
45
|
+
|
|
46
|
+
def sample(self) -> Any:
|
|
47
|
+
return np.random.uniform(self.low, self.high, self.shape)
|
|
48
|
+
|
|
49
|
+
def contains(self, x: Any) -> bool:
|
|
50
|
+
x = np.array(x)
|
|
51
|
+
return (
|
|
52
|
+
x.shape == self.shape and np.all(x >= self.low) and np.all(x <= self.high)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Dict(Space):
|
|
57
|
+
"""A dictionary space in TinySim."""
|
|
58
|
+
|
|
59
|
+
def __init__(self, spaces: dict):
|
|
60
|
+
self.spaces = spaces
|
|
61
|
+
|
|
62
|
+
def sample(self) -> dict:
|
|
63
|
+
return {key: space.sample() for key, space in self.spaces.items()}
|
|
64
|
+
|
|
65
|
+
def contains(self, x: Any) -> bool:
|
|
66
|
+
if isinstance(x, dict) and x.keys() == self.spaces.keys():
|
|
67
|
+
return all(x[key] in self.spaces[key] for key in self.spaces.keys())
|
|
68
|
+
return False
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import math
|
|
3
|
-
import numpy as np
|
|
4
3
|
from pathlib import Path
|
|
5
|
-
from .. import SimEnvironment
|
|
6
4
|
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from .. import SimEnvironment
|
|
8
|
+
from ..tinyspace import Box
|
|
7
9
|
|
|
8
10
|
try:
|
|
9
11
|
with open(Path(__file__).parent / "track_0.json", "r") as f:
|
|
@@ -104,6 +106,9 @@ def collides(cx, cy):
|
|
|
104
106
|
class TopDownDrivingEnv(SimEnvironment):
|
|
105
107
|
def __init__(self, num_envs: int = 1):
|
|
106
108
|
self.num_envs = num_envs
|
|
109
|
+
|
|
110
|
+
# throttle, steer
|
|
111
|
+
self.action_space = Box(low=-1.0, high=1.0, shape=(num_envs, 2))
|
|
107
112
|
self.reset()
|
|
108
113
|
|
|
109
114
|
def reset(self):
|
|
@@ -125,24 +130,18 @@ class TopDownDrivingEnv(SimEnvironment):
|
|
|
125
130
|
}
|
|
126
131
|
|
|
127
132
|
def step(self, action, dt=0.02):
|
|
128
|
-
|
|
129
|
-
steer = action.get("steer", 0.0)
|
|
130
|
-
|
|
131
|
-
if np.isscalar(throttle) and np.isscalar(steer):
|
|
132
|
-
throttle = np.full(self.num_envs, throttle, dtype=np.float32)
|
|
133
|
-
steer = np.full(self.num_envs, steer, dtype=np.float32)
|
|
134
|
-
elif isinstance(throttle, np.ndarray) and isinstance(steer, np.ndarray):
|
|
135
|
-
throttle = np.asarray(throttle, dtype=np.float32)
|
|
136
|
-
steer = np.asarray(steer, dtype=np.float32)
|
|
137
|
-
if throttle.shape[0] != self.num_envs or steer.shape[0] != self.num_envs:
|
|
138
|
-
raise ValueError(
|
|
139
|
-
f"Expected actions of shape ({self.num_envs},), got {throttle.shape} and {steer.shape}"
|
|
140
|
-
)
|
|
141
|
-
else:
|
|
133
|
+
if not isinstance(action, np.ndarray):
|
|
142
134
|
raise ValueError(
|
|
143
135
|
"Inputs throttle and steer must both be either scalars or numpy arrays."
|
|
144
136
|
)
|
|
145
137
|
|
|
138
|
+
throttle = action[:, 0].astype(np.float32)
|
|
139
|
+
steer = action[:, 1].astype(np.float32)
|
|
140
|
+
if throttle.shape[0] != self.num_envs or steer.shape[0] != self.num_envs:
|
|
141
|
+
raise ValueError(
|
|
142
|
+
f"Expected actions of shape ({self.num_envs},), got {throttle.shape} and {steer.shape}"
|
|
143
|
+
)
|
|
144
|
+
|
|
146
145
|
self.velocity += throttle * ACCELERATION * dt
|
|
147
146
|
self.velocity = np.clip(self.velocity, 0.0, MAX_VEL)
|
|
148
147
|
self.angle -= steer * TURN_SPEED * dt
|
|
@@ -171,8 +170,7 @@ class TopDownDrivingEnv(SimEnvironment):
|
|
|
171
170
|
reward = self.prev_dist - dist
|
|
172
171
|
reached = dist <= CHECKPOINT_RADIUS
|
|
173
172
|
|
|
174
|
-
|
|
175
|
-
reward += np.where(reached, bonus, 0.0)
|
|
173
|
+
reward += np.where(reached, 1.0, 0.0)
|
|
176
174
|
self.checkpoint_idx = np.where(
|
|
177
175
|
reached, self.checkpoint_idx + 1, self.checkpoint_idx
|
|
178
176
|
)
|
tinysim/topdown_driving/tk.py
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
|
-
import asyncio
|
|
2
1
|
import math
|
|
2
|
+
|
|
3
3
|
from . import (
|
|
4
|
-
TopDownDrivingEnv,
|
|
5
4
|
CAR_LENGTH,
|
|
6
5
|
CAR_WIDTH,
|
|
7
|
-
LOCAL_WALLS,
|
|
8
6
|
CHECKPOINTS,
|
|
7
|
+
LOCAL_WALLS,
|
|
9
8
|
RAY_COUNT,
|
|
10
9
|
RAY_SPREAD,
|
|
10
|
+
TopDownDrivingEnv,
|
|
11
11
|
)
|
|
12
12
|
|
|
13
13
|
try:
|
|
14
14
|
import tkinter as tk
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
from .._tk_base import TkBaseFrontend
|
|
16
17
|
except ImportError:
|
|
17
18
|
raise ImportError("tkinter is required for MountainCarTkFrontend")
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
CHECKPOINT_RADIUS = 0.85
|
|
21
22
|
COLOR_MAP = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]
|
|
22
|
-
|
|
23
|
+
CANVAS_W, CANVAS_H = 800, 600
|
|
23
24
|
xs, ys = [], []
|
|
24
25
|
|
|
25
26
|
for x, y, w, h, rot in LOCAL_WALLS:
|
|
@@ -30,8 +31,6 @@ for x, y, w, h, rot in LOCAL_WALLS:
|
|
|
30
31
|
|
|
31
32
|
min_x, max_x = min(xs), max(xs)
|
|
32
33
|
min_y, max_y = min(ys), max(ys)
|
|
33
|
-
|
|
34
|
-
CANVAS_W, CANVAS_H = 800, 600
|
|
35
34
|
scale = min((CANVAS_W - 2) / (max_x - min_x), (CANVAS_H - 2) / (max_y - min_y))
|
|
36
35
|
offset_x = -min_x * scale
|
|
37
36
|
offset_y = max_y * scale
|
|
@@ -53,33 +52,14 @@ def world_to_screen(x, y):
|
|
|
53
52
|
return x * scale + offset_x, -y * scale + offset_y
|
|
54
53
|
|
|
55
54
|
|
|
56
|
-
class TopDownDrivingTkFrontend(
|
|
55
|
+
class TopDownDrivingTkFrontend(TkBaseFrontend):
|
|
57
56
|
|
|
58
|
-
def __init__(self, viewport_size=(800, 600), sim_env=
|
|
59
|
-
super().__init__()
|
|
60
|
-
if sim_env is None:
|
|
61
|
-
sim_env = TopDownDrivingEnv()
|
|
62
|
-
self.sim_env = sim_env
|
|
57
|
+
def __init__(self, viewport_size=(800, 600), sim_env=TopDownDrivingEnv()):
|
|
58
|
+
super().__init__(sim_env)
|
|
63
59
|
self._viewport_size = viewport_size
|
|
64
60
|
self.show_rays = False
|
|
65
|
-
|
|
66
61
|
self.keys = set()
|
|
67
62
|
|
|
68
|
-
async def step(self, action, dt=0.02):
|
|
69
|
-
state = self.sim_env.step(action)
|
|
70
|
-
|
|
71
|
-
if self._root:
|
|
72
|
-
self._root.after(0, lambda s=state: self._draw_state(self.sim_env))
|
|
73
|
-
|
|
74
|
-
await asyncio.sleep(dt)
|
|
75
|
-
return state
|
|
76
|
-
|
|
77
|
-
async def reset(self):
|
|
78
|
-
state = self.sim_env.reset()
|
|
79
|
-
if self._canvas:
|
|
80
|
-
self._draw_state(self.sim_env)
|
|
81
|
-
return state
|
|
82
|
-
|
|
83
63
|
def _create_window(self, root):
|
|
84
64
|
w, h = self._viewport_size
|
|
85
65
|
root.title("Top Down Driving")
|
|
@@ -94,7 +74,6 @@ class TopDownDrivingTkFrontend(_tk_base.TkBaseFrontend):
|
|
|
94
74
|
r = CHECKPOINT_RADIUS * scale
|
|
95
75
|
for i, (x, y) in enumerate(CHECKPOINTS):
|
|
96
76
|
sx, sy = world_to_screen(x, y)
|
|
97
|
-
|
|
98
77
|
canvas.create_oval(
|
|
99
78
|
sx - r,
|
|
100
79
|
sy - r,
|
|
@@ -115,26 +94,24 @@ class TopDownDrivingTkFrontend(_tk_base.TkBaseFrontend):
|
|
|
115
94
|
self.bring_to_front(root)
|
|
116
95
|
self._root = root
|
|
117
96
|
self._canvas = canvas
|
|
118
|
-
self._draw_state(
|
|
97
|
+
self._draw_state()
|
|
119
98
|
self._pump()
|
|
120
99
|
root.mainloop()
|
|
121
100
|
|
|
122
|
-
def _draw_state(self,
|
|
101
|
+
def _draw_state(self, state=None):
|
|
102
|
+
sim_env = self.sim_env
|
|
123
103
|
if not self._canvas:
|
|
124
104
|
return
|
|
125
105
|
|
|
126
106
|
c = self._canvas
|
|
127
107
|
c.delete("car")
|
|
128
108
|
c.delete("ray")
|
|
129
|
-
|
|
130
|
-
xs = sim_env.x
|
|
131
|
-
ys = sim_env.y
|
|
109
|
+
xs, ys = sim_env.x, sim_env.y
|
|
132
110
|
angles = sim_env.angle
|
|
133
111
|
n = len(xs)
|
|
134
112
|
|
|
135
113
|
for i in range(n):
|
|
136
114
|
cx, cy = world_to_screen(xs[i], ys[i])
|
|
137
|
-
|
|
138
115
|
pts = rotated_rect(
|
|
139
116
|
cx,
|
|
140
117
|
cy,
|
|
@@ -160,7 +137,6 @@ class TopDownDrivingTkFrontend(_tk_base.TkBaseFrontend):
|
|
|
160
137
|
for i in range(n):
|
|
161
138
|
ox, oy = xs[i], ys[i]
|
|
162
139
|
base = angles[i]
|
|
163
|
-
|
|
164
140
|
sx1, sy1 = world_to_screen(ox, oy)
|
|
165
141
|
|
|
166
142
|
for r_idx, dist in enumerate(sim_env.rays[i]):
|
|
@@ -168,7 +144,6 @@ class TopDownDrivingTkFrontend(_tk_base.TkBaseFrontend):
|
|
|
168
144
|
x2 = ox + math.cos(a) * dist
|
|
169
145
|
y2 = oy + math.sin(a) * dist
|
|
170
146
|
sx2, sy2 = world_to_screen(x2, y2)
|
|
171
|
-
|
|
172
147
|
c.create_line(
|
|
173
148
|
sx1,
|
|
174
149
|
sy1,
|