composabl-cli-dev 0.19.1.dev1__cp310-cp310-macosx_11_0_arm64.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.
Potentially problematic release.
This version of composabl-cli-dev might be problematic. Click here for more details.
- composabl_cli/__init__.py +9 -0
- composabl_cli/cli/__init__.cpython-310-darwin.so +0 -0
- composabl_cli/cli/cli.cpython-310-darwin.so +0 -0
- composabl_cli/cli/cli_agent.cpython-310-darwin.so +0 -0
- composabl_cli/cli/cli_benchmark.cpython-310-darwin.so +0 -0
- composabl_cli/cli/cli_debug.cpython-310-darwin.so +0 -0
- composabl_cli/cli/cli_historian.cpython-310-darwin.so +0 -0
- composabl_cli/cli/cli_job.cpython-310-darwin.so +0 -0
- composabl_cli/cli/cli_main.cpython-310-darwin.so +0 -0
- composabl_cli/cli/cli_perceptor.cpython-310-darwin.so +0 -0
- composabl_cli/cli/cli_selector.cpython-310-darwin.so +0 -0
- composabl_cli/cli/cli_sim.cpython-310-darwin.so +0 -0
- composabl_cli/cli/cli_skill.cpython-310-darwin.so +0 -0
- composabl_cli/cli/cli_version.cpython-310-darwin.so +0 -0
- composabl_cli/k8s/k8s_train.cpython-310-darwin.so +0 -0
- composabl_cli/k8s/util.cpython-310-darwin.so +0 -0
- composabl_cli/main/agent.cpython-310-darwin.so +0 -0
- composabl_cli/main/perceptor.cpython-310-darwin.so +0 -0
- composabl_cli/main/selector.cpython-310-darwin.so +0 -0
- composabl_cli/main/sim.cpython-310-darwin.so +0 -0
- composabl_cli/main/skill.cpython-310-darwin.so +0 -0
- composabl_cli/template/agent_composabl/agent.py +90 -0
- composabl_cli/template/agent_docker/agent.py +99 -0
- composabl_cli/template/agent_local/agent.py +96 -0
- composabl_cli/template/perceptor/README.md +67 -0
- composabl_cli/template/perceptor/pyproject.toml +15 -0
- composabl_cli/template/perceptor/{{NAME_MODULE}}/__init__.py +3 -0
- composabl_cli/template/perceptor/{{NAME_MODULE}}/perceptor.py +34 -0
- composabl_cli/template/selector_controller/README.md +67 -0
- composabl_cli/template/selector_controller/pyproject.toml +12 -0
- composabl_cli/template/selector_controller/{{NAME_MODULE}}/__init__.py +3 -0
- composabl_cli/template/selector_controller/{{NAME_MODULE}}/controller.py +52 -0
- composabl_cli/template/selector_teacher/README.md +67 -0
- composabl_cli/template/selector_teacher/pyproject.toml +12 -0
- composabl_cli/template/selector_teacher/{{NAME_MODULE}}/__init__.py +3 -0
- composabl_cli/template/selector_teacher/{{NAME_MODULE}}/teacher.py +70 -0
- composabl_cli/template/sim/README.md +39 -0
- composabl_cli/template/sim/pyproject.toml +20 -0
- composabl_cli/template/sim/{{NAME_MODULE}}/__init__.py +3 -0
- composabl_cli/template/sim/{{NAME_MODULE}}/sim.py +253 -0
- composabl_cli/template/sim/{{NAME_MODULE}}/sim_impl.py +115 -0
- composabl_cli/template/sim_docker/Dockerfile +45 -0
- composabl_cli/template/sim_docker/README.md +17 -0
- composabl_cli/template/sim_docker/docker/sim-start.sh +14 -0
- composabl_cli/template/sim_docker/main.py +55 -0
- composabl_cli/template/sim_docker/module/README.md +39 -0
- composabl_cli/template/sim_docker/module/pyproject.toml +20 -0
- composabl_cli/template/sim_docker/module/{{NAME_MODULE}}/__init__.py +3 -0
- composabl_cli/template/sim_docker/module/{{NAME_MODULE}}/sim.py +253 -0
- composabl_cli/template/sim_docker/module/{{NAME_MODULE}}/sim_impl.py +115 -0
- composabl_cli/template/skill_controller/README.md +67 -0
- composabl_cli/template/skill_controller/pyproject.toml +12 -0
- composabl_cli/template/skill_controller/{{NAME_MODULE}}/__init__.py +3 -0
- composabl_cli/template/skill_controller/{{NAME_MODULE}}/controller.py +40 -0
- composabl_cli/template/skill_coordinated_population/README.md +67 -0
- composabl_cli/template/skill_coordinated_population/pyproject.toml +12 -0
- composabl_cli/template/skill_coordinated_population/{{NAME_MODULE}}/__init__.py +3 -0
- composabl_cli/template/skill_coordinated_population/{{NAME_MODULE}}/coach.py +70 -0
- composabl_cli/template/skill_coordinated_set/README.md +67 -0
- composabl_cli/template/skill_coordinated_set/pyproject.toml +12 -0
- composabl_cli/template/skill_coordinated_set/{{NAME_MODULE}}/__init__.py +3 -0
- composabl_cli/template/skill_coordinated_set/{{NAME_MODULE}}/coach.py +70 -0
- composabl_cli/template/skill_teacher/README.md +67 -0
- composabl_cli/template/skill_teacher/pyproject.toml +12 -0
- composabl_cli/template/skill_teacher/{{NAME_MODULE}}/__init__.py +3 -0
- composabl_cli/template/skill_teacher/{{NAME_MODULE}}/teacher.py +70 -0
- composabl_cli_dev-0.19.1.dev1.dist-info/METADATA +49 -0
- composabl_cli_dev-0.19.1.dev1.dist-info/RECORD +71 -0
- composabl_cli_dev-0.19.1.dev1.dist-info/WHEEL +5 -0
- composabl_cli_dev-0.19.1.dev1.dist-info/entry_points.txt +2 -0
- composabl_cli_dev-0.19.1.dev1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "{{NAME}}"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "{{DESCRIPTION}}"
|
|
5
|
+
authors = [{ name = "John Doe", email = "john.doe@composabl.com" }]
|
|
6
|
+
dependencies = [
|
|
7
|
+
"composabl-core"
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
[composabl]
|
|
11
|
+
type = "sim"
|
|
12
|
+
entrypoint = "{{NAME_MODULE}}.sim_impl:SimImpl"
|
|
13
|
+
dependencies_system = [] # include additional apt-get packages to be installed
|
|
14
|
+
|
|
15
|
+
# Include additional data files
|
|
16
|
+
[tool.setuptools.packages.find]
|
|
17
|
+
where = ["{{NAME_MODULE}}"]
|
|
18
|
+
|
|
19
|
+
[tool.setuptools.package-data]
|
|
20
|
+
"*" = ["*.json", "*.pkl"]
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# Copyright (C) Composabl, Inc - All Rights Reserved
|
|
2
|
+
# Unauthorized copying of this file, via any medium is strictly prohibited
|
|
3
|
+
# Proprietary and confidential
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
import random
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
import gymnasium as gym
|
|
10
|
+
import numpy as np
|
|
11
|
+
from composabl_core.agent.scenario import Scenario
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Env(gym.Env):
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self.obs_space_constraints = {
|
|
17
|
+
"x": {"low": -400, "high": 400},
|
|
18
|
+
"x_speed": {"low": -100, "high": 100},
|
|
19
|
+
"y": {"low": 0, "high": 1000},
|
|
20
|
+
"y_speed": {"low": -1000, "high": 1000},
|
|
21
|
+
"angle": {"low": -3.15 * 2, "high": 3.15 * 2},
|
|
22
|
+
"angle_speed": {"low": -3, "high": 3},
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
deg_to_rad = 0.01745329
|
|
26
|
+
self.max_gimble = 20 * deg_to_rad
|
|
27
|
+
self.min_gimble = -self.max_gimble
|
|
28
|
+
|
|
29
|
+
self.action_constraints = {
|
|
30
|
+
"angle": {"low": self.min_gimble, "high": self.max_gimble},
|
|
31
|
+
"thrust": {"low": 0.4, "high": 1},
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
low_list = [x["low"] for x in self.obs_space_constraints.values()]
|
|
35
|
+
high_list = [x["high"] for x in self.obs_space_constraints.values()]
|
|
36
|
+
|
|
37
|
+
self.sensor_space = gym.spaces.Box(
|
|
38
|
+
low=np.array(low_list), high=np.array(high_list)
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
low_act_list = [x["low"] for x in self.action_constraints.values()]
|
|
42
|
+
high_act_list = [x["high"] for x in self.action_constraints.values()]
|
|
43
|
+
|
|
44
|
+
self.action_space = gym.spaces.Box(
|
|
45
|
+
low=np.array(low_act_list), high=np.array(high_act_list)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
self.state_models = {}
|
|
49
|
+
self.reward_models = {}
|
|
50
|
+
self.scenario: Scenario = None
|
|
51
|
+
|
|
52
|
+
self.x_obs0 = 0
|
|
53
|
+
self.x_speed0 = 0
|
|
54
|
+
self.y_obs0 = 1000
|
|
55
|
+
self.y_speed0 = -80
|
|
56
|
+
self.angle0 = -np.pi / 2
|
|
57
|
+
self.ang_speed0 = 0
|
|
58
|
+
|
|
59
|
+
def starship_simulation(self, x, u):
|
|
60
|
+
g = 9.8
|
|
61
|
+
m = 100000 # kg
|
|
62
|
+
min_thrust = 880 * 1000 # N
|
|
63
|
+
max_thrust = 1 * 2210 * 1000 # kN
|
|
64
|
+
|
|
65
|
+
length = 50 # m
|
|
66
|
+
width = 10
|
|
67
|
+
|
|
68
|
+
# Inertia for a uniform density rod
|
|
69
|
+
I = (1 / 12) * m * length**2
|
|
70
|
+
|
|
71
|
+
deg_to_rad = 0.01745329
|
|
72
|
+
|
|
73
|
+
max_gimble = 20 * deg_to_rad
|
|
74
|
+
min_gimble = -max_gimble
|
|
75
|
+
|
|
76
|
+
theta = x[4]
|
|
77
|
+
|
|
78
|
+
thrust = u[0]
|
|
79
|
+
thrust_angle = u[1]
|
|
80
|
+
|
|
81
|
+
# Horizontal force
|
|
82
|
+
F_x = max_thrust * thrust * math.sin(thrust_angle + theta)
|
|
83
|
+
x_dot = x[1]
|
|
84
|
+
x_dotdot = (F_x) / m
|
|
85
|
+
|
|
86
|
+
# Vertical force
|
|
87
|
+
F_y = max_thrust * thrust * math.cos(thrust_angle + theta)
|
|
88
|
+
y_dot = x[3]
|
|
89
|
+
y_dotdot = (F_y) / m - g
|
|
90
|
+
|
|
91
|
+
# Torque
|
|
92
|
+
T = -length / 2 * max_thrust * thrust * math.sin(thrust_angle)
|
|
93
|
+
theta_dot = x[5]
|
|
94
|
+
theta_dotdot = T / I
|
|
95
|
+
|
|
96
|
+
return [x_dot, x_dotdot, y_dot, y_dotdot, theta_dot, theta_dotdot]
|
|
97
|
+
|
|
98
|
+
def reset(
|
|
99
|
+
self,
|
|
100
|
+
*,
|
|
101
|
+
seed: Optional[int] = None,
|
|
102
|
+
options: Optional[dict] = None,
|
|
103
|
+
x_obs0: float = 0,
|
|
104
|
+
x_speed0: float = 0,
|
|
105
|
+
y_obs0: float = 1000,
|
|
106
|
+
y_speed0: float = -80,
|
|
107
|
+
angle0: float = -np.pi / 2,
|
|
108
|
+
ang_speed0: float = 0
|
|
109
|
+
):
|
|
110
|
+
"""
|
|
111
|
+
# x[0] = x position (m)
|
|
112
|
+
# x[1] = x velocity (m/)
|
|
113
|
+
# x[2] = y position (m)
|
|
114
|
+
# x[3] = y velocity (m/s)
|
|
115
|
+
# x[4] = angle (rad)
|
|
116
|
+
# x[5] = angular velocity (rad/s)
|
|
117
|
+
|
|
118
|
+
# u[0] = thrust (percent)
|
|
119
|
+
# u[1] = thrust angle (rad)
|
|
120
|
+
|
|
121
|
+
"""
|
|
122
|
+
super().reset(seed=seed)
|
|
123
|
+
self.cnt = 0
|
|
124
|
+
self.min_thrust = 880 * 1000 # N
|
|
125
|
+
self.max_thrust = 1 * 2210 * 1000 # kN
|
|
126
|
+
|
|
127
|
+
# Define scenario in the simulation ******
|
|
128
|
+
if isinstance(self.scenario, Scenario):
|
|
129
|
+
sample = self.scenario.sample()
|
|
130
|
+
|
|
131
|
+
for key in list(sample.keys()):
|
|
132
|
+
setattr(self, key, sample[key])
|
|
133
|
+
|
|
134
|
+
# Set the number of steps and the timestep (dt)
|
|
135
|
+
steps = 400
|
|
136
|
+
self.t_step = 0.04
|
|
137
|
+
self.cnt = 0
|
|
138
|
+
|
|
139
|
+
self.x = np.zeros((steps + 1, 6))
|
|
140
|
+
self.u = np.zeros((steps + 1, 2))
|
|
141
|
+
|
|
142
|
+
self.x[0, :] = [
|
|
143
|
+
self.x_obs0,
|
|
144
|
+
self.x_speed0,
|
|
145
|
+
self.y_obs0,
|
|
146
|
+
self.y_speed0,
|
|
147
|
+
self.angle0,
|
|
148
|
+
self.ang_speed0,
|
|
149
|
+
]
|
|
150
|
+
self.x[steps - 1, :] = [0, 0, 0, 0, 0, 0]
|
|
151
|
+
|
|
152
|
+
self.x_obs = self.x[self.cnt, 0]
|
|
153
|
+
self.x_speed = self.x[self.cnt, 1]
|
|
154
|
+
self.y_obs = self.x[self.cnt, 2]
|
|
155
|
+
self.y_speed = self.x[self.cnt, 3]
|
|
156
|
+
self.angle = self.x[self.cnt, 4]
|
|
157
|
+
self.ang_speed = self.x[self.cnt, 5]
|
|
158
|
+
|
|
159
|
+
self.t = 0.4
|
|
160
|
+
self.a = 0
|
|
161
|
+
self.reward_value = 0
|
|
162
|
+
|
|
163
|
+
self.obs = {
|
|
164
|
+
"x": self.x_obs,
|
|
165
|
+
"x_speed": self.x_speed,
|
|
166
|
+
"y": self.y_obs,
|
|
167
|
+
"y_speed": self.y_speed,
|
|
168
|
+
"angle": self.angle,
|
|
169
|
+
"angle_speed": self.ang_speed,
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
self.obs = np.array(list(self.obs.values()))
|
|
173
|
+
info = {}
|
|
174
|
+
return self.obs, info
|
|
175
|
+
|
|
176
|
+
def set_scenario(self, scenario):
|
|
177
|
+
self.scenario = scenario
|
|
178
|
+
|
|
179
|
+
def step(self, action):
|
|
180
|
+
terminated = False
|
|
181
|
+
discount = 0
|
|
182
|
+
reward = 0
|
|
183
|
+
|
|
184
|
+
def sumsqr(lt):
|
|
185
|
+
v = sum([x**2 for x in lt])
|
|
186
|
+
return v
|
|
187
|
+
|
|
188
|
+
angle = action[0]
|
|
189
|
+
thrust = action[1]
|
|
190
|
+
|
|
191
|
+
actuator_noise = 0
|
|
192
|
+
self.t = thrust + random.uniform(
|
|
193
|
+
-actuator_noise * thrust, actuator_noise * thrust
|
|
194
|
+
)
|
|
195
|
+
self.a = angle + random.uniform(-actuator_noise * angle, actuator_noise * angle)
|
|
196
|
+
|
|
197
|
+
self.t = np.clip(self.t, 0.4, 1)
|
|
198
|
+
self.a = np.clip(self.a, self.min_gimble, self.max_gimble)
|
|
199
|
+
|
|
200
|
+
# update u
|
|
201
|
+
self.u[self.cnt, 0] = self.t
|
|
202
|
+
self.u[self.cnt, 1] = self.a
|
|
203
|
+
|
|
204
|
+
res = self.starship_simulation(self.x[self.cnt, :], self.u[self.cnt, :])
|
|
205
|
+
res = [v * self.t_step for v in res]
|
|
206
|
+
|
|
207
|
+
self.x[self.cnt + 1, :] = [
|
|
208
|
+
sum(value) for value in zip(self.x[self.cnt, :], res)
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
# Increase time
|
|
212
|
+
self.cnt += 1
|
|
213
|
+
# update values
|
|
214
|
+
self.x_obs = self.x[self.cnt, 0]
|
|
215
|
+
self.x_speed = self.x[self.cnt, 1]
|
|
216
|
+
self.y_obs = self.x[self.cnt, 2]
|
|
217
|
+
self.y_speed = self.x[self.cnt, 3]
|
|
218
|
+
self.angle = self.x[self.cnt, 4]
|
|
219
|
+
self.ang_speed = self.x[self.cnt, 5]
|
|
220
|
+
|
|
221
|
+
# update obs with new state values
|
|
222
|
+
self.obs = {
|
|
223
|
+
"x": self.x_obs,
|
|
224
|
+
"x_speed": self.x_speed,
|
|
225
|
+
"y": self.y_obs,
|
|
226
|
+
"y_speed": self.y_speed,
|
|
227
|
+
"angle": self.angle,
|
|
228
|
+
"angle_speed": self.ang_speed,
|
|
229
|
+
}
|
|
230
|
+
# add noise
|
|
231
|
+
for key in list(self.obs.keys()):
|
|
232
|
+
val = float(self.obs[key])
|
|
233
|
+
sensor_noise = 0.0
|
|
234
|
+
self.obs[key] = val + random.uniform(
|
|
235
|
+
-val * sensor_noise, val * sensor_noise
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
# end the simulation
|
|
239
|
+
if self.y_obs < 0:
|
|
240
|
+
terminated = True
|
|
241
|
+
elif (
|
|
242
|
+
not self.obs_space_constraints["x"]["low"]
|
|
243
|
+
<= self.x_obs
|
|
244
|
+
<= self.obs_space_constraints["x"]["high"]
|
|
245
|
+
):
|
|
246
|
+
terminated = True
|
|
247
|
+
|
|
248
|
+
self.obs = np.array(list(self.obs.values()))
|
|
249
|
+
info = {}
|
|
250
|
+
return self.obs, reward, terminated, False, info
|
|
251
|
+
|
|
252
|
+
def render(self, mode="auto"):
|
|
253
|
+
pass
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Copyright (C) Composabl, Inc - All Rights Reserved
|
|
2
|
+
# Unauthorized copying of this file, via any medium is strictly prohibited
|
|
3
|
+
# Proprietary and confidential
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, SupportsFloat, Tuple
|
|
6
|
+
|
|
7
|
+
import composabl_core.utils.logger as logger_util
|
|
8
|
+
import gymnasium as gym
|
|
9
|
+
from composabl_core.agent.scenario import Scenario
|
|
10
|
+
from composabl_core.networking.sim.server_composabl import ServerComposabl
|
|
11
|
+
from gymnasium.envs.registration import EnvSpec
|
|
12
|
+
|
|
13
|
+
from .sim import Env
|
|
14
|
+
|
|
15
|
+
logger = logger_util.get_logger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SimImpl(ServerComposabl):
|
|
19
|
+
def __init__(self):
|
|
20
|
+
self.env = Env()
|
|
21
|
+
|
|
22
|
+
async def make(self, env_id: str, env_init: dict) -> EnvSpec:
|
|
23
|
+
"""
|
|
24
|
+
Make the environment
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
- env_id (str): Environment ID
|
|
28
|
+
- env_init (dict): Environment Initialization
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
- EnvSpec: Environment Specification
|
|
32
|
+
"""
|
|
33
|
+
spec = {"id": "starship", "max_episode_steps": 400}
|
|
34
|
+
return spec
|
|
35
|
+
|
|
36
|
+
async def sensor_space_info(self) -> gym.Space:
|
|
37
|
+
"""
|
|
38
|
+
Get the sensor space information
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
- Space: Sensor Space in Gymnasium Specification
|
|
42
|
+
"""
|
|
43
|
+
return self.env.sensor_space
|
|
44
|
+
|
|
45
|
+
async def action_space_info(self) -> gym.Space:
|
|
46
|
+
"""
|
|
47
|
+
Get the action space information
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
- Space: Action Space in Gymnasium Specification
|
|
51
|
+
"""
|
|
52
|
+
return self.env.action_space
|
|
53
|
+
|
|
54
|
+
async def action_space_sample(self) -> Any:
|
|
55
|
+
"""
|
|
56
|
+
Get the action space sample
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
- List[Any]: A list of samples
|
|
60
|
+
"""
|
|
61
|
+
return self.env.action_space.sample()
|
|
62
|
+
|
|
63
|
+
async def reset(self) -> Tuple[Any, Dict[str, Any]]:
|
|
64
|
+
"""
|
|
65
|
+
Reset the environment
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
- Tuple[Any, Dict[str, Any]]: The observation and the info
|
|
69
|
+
"""
|
|
70
|
+
sensors, info = self.env.reset()
|
|
71
|
+
return sensors, info
|
|
72
|
+
|
|
73
|
+
async def step(
|
|
74
|
+
self, action
|
|
75
|
+
) -> Tuple[Any, SupportsFloat, bool, bool, Dict[str, Any]]:
|
|
76
|
+
"""
|
|
77
|
+
Step the environment
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
- action: The action to take
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
- Tuple[Any, SupportsFloat, bool, bool, Dict[str, Any]]: The observation, reward, is_truncated, is_done, info
|
|
84
|
+
"""
|
|
85
|
+
return self.env.step(action)
|
|
86
|
+
|
|
87
|
+
async def close(self):
|
|
88
|
+
"""
|
|
89
|
+
Close the environment
|
|
90
|
+
"""
|
|
91
|
+
self.env.close()
|
|
92
|
+
|
|
93
|
+
async def set_scenario(self, scenario):
|
|
94
|
+
"""
|
|
95
|
+
Set the scenario
|
|
96
|
+
"""
|
|
97
|
+
self.env.scenario = scenario
|
|
98
|
+
|
|
99
|
+
async def get_scenario(self):
|
|
100
|
+
"""
|
|
101
|
+
Get the scenario
|
|
102
|
+
"""
|
|
103
|
+
if self.env.scenario is None:
|
|
104
|
+
return Scenario({"dummy": 0})
|
|
105
|
+
|
|
106
|
+
return self.env.scenario
|
|
107
|
+
|
|
108
|
+
async def get_render(self):
|
|
109
|
+
"""
|
|
110
|
+
Get the render
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
- render_mode: The render mode
|
|
114
|
+
"""
|
|
115
|
+
return self.env.get_render_frame()
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# README
|
|
2
|
+
|
|
3
|
+
This is a template for creating a new Perceptor. A Perceptor is a component that is responsible for processing data and returning a result. This can be used for example in a Machine Learning model, where the Perceptor is responsible for processing the data and returning the prediction.
|
|
4
|
+
|
|
5
|
+
## Tree Structure
|
|
6
|
+
|
|
7
|
+
The template is structured as follows:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
my-perceptor/ # Root folder
|
|
11
|
+
├── my_perceptor/ # Main package folder
|
|
12
|
+
│ ├── __init__.py # Package init file
|
|
13
|
+
│ └── perceptor.py # Main perceptor file
|
|
14
|
+
├── pyproject.toml # Project configuration, containing [composabl]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## PyProject [composabl] Section
|
|
18
|
+
|
|
19
|
+
We add the `[composabl]` section to the `pyproject.toml` file to specify the type of component we are creating as well as its entrypoint. This is used by the Composabl CLI to determine the type of
|
|
20
|
+
component and how to handle it.
|
|
21
|
+
|
|
22
|
+
Example:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
[composabl]
|
|
26
|
+
type = "teacher"
|
|
27
|
+
entrypoint = "my_perceptor.perceptor:MyPerceptor"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Development
|
|
31
|
+
|
|
32
|
+
To work on the Perceptor, you can simply create a temporary file or main file that starts up and executes the `compute` method of the portable Perceptor. Example, we can create a `test.py` file with:
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from composabl_perceptor_my_perceptor.perceptor import MyPerceptor
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def start():
|
|
39
|
+
p = MyPerceptor()
|
|
40
|
+
res = await t.compute(None, [1.0])
|
|
41
|
+
print(res)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if __name__ == "__main__":
|
|
45
|
+
import asyncio
|
|
46
|
+
|
|
47
|
+
asyncio.run(start())
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Which we can then run with
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Install the module
|
|
54
|
+
pip install -e my-perceptor
|
|
55
|
+
|
|
56
|
+
# Run the test file
|
|
57
|
+
python my-perceptor/test.py
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Preparing for Upload
|
|
61
|
+
|
|
62
|
+
Once we are ready for uploading, we can create a `.tar.gz` file that contains the version. This can be done with the following command:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Tar GZ the plugin
|
|
66
|
+
tar -czvf my-perceptor-0.0.1.tar.gz my-perceptor
|
|
67
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "{{NAME}}"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "{{DESCRIPTION}}"
|
|
5
|
+
authors = [{ name = "John Doe", email = "john.doe@composabl.com" }]
|
|
6
|
+
dependencies = [
|
|
7
|
+
"composabl-core{{COMPOSABL_DEV}}{{COMPOSABL_CORE_VERSION}}",
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
[composabl]
|
|
11
|
+
type = "skill-controller"
|
|
12
|
+
entrypoint = "{{NAME_MODULE}}.controller:Controller"
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Copyright (C) Composabl, Inc - All Rights Reserved
|
|
2
|
+
# Unauthorized copying of this file, via any medium is strictly prohibited
|
|
3
|
+
# Proprietary and confidential
|
|
4
|
+
|
|
5
|
+
from random import randint
|
|
6
|
+
from typing import Dict, List
|
|
7
|
+
|
|
8
|
+
from composabl_core import SkillController
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Controller(SkillController):
|
|
12
|
+
"""
|
|
13
|
+
We start at 10 reward and count down to 0 the goal is that the agent stays
|
|
14
|
+
above or equal to 0 this means it learned to cound +1 each time
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, *args, **kwargs):
|
|
18
|
+
self.past_obs = None
|
|
19
|
+
self.counter = 10
|
|
20
|
+
self.sensor_name = "counter"
|
|
21
|
+
|
|
22
|
+
async def compute_action(self, transformed_sensors: Dict, action) -> List[float]:
|
|
23
|
+
# generate a random action between -5 and 5
|
|
24
|
+
action = [randint(-5, 5)]
|
|
25
|
+
return action
|
|
26
|
+
|
|
27
|
+
async def compute_success_criteria(self, transformed_sensors: Dict, action) -> bool:
|
|
28
|
+
return bool(transformed_sensors[self.sensor_name] >= 10)
|
|
29
|
+
|
|
30
|
+
async def compute_termination(self, transformed_sensors: Dict, action) -> bool:
|
|
31
|
+
return bool(transformed_sensors[self.sensor_name] <= -10)
|
|
32
|
+
|
|
33
|
+
async def transform_sensors(self, sensors, action) -> str:
|
|
34
|
+
return sensors
|
|
35
|
+
|
|
36
|
+
async def transform_action(self, transformed_sensors: Dict, action) -> float:
|
|
37
|
+
return action
|
|
38
|
+
|
|
39
|
+
async def filtered_sensor_space(self) -> List[str]:
|
|
40
|
+
return ["counter"]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# README
|
|
2
|
+
|
|
3
|
+
This is a template for creating a new Perceptor. A Perceptor is a component that is responsible for processing data and returning a result. This can be used for example in a Machine Learning model, where the Perceptor is responsible for processing the data and returning the prediction.
|
|
4
|
+
|
|
5
|
+
## Tree Structure
|
|
6
|
+
|
|
7
|
+
The template is structured as follows:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
my-perceptor/ # Root folder
|
|
11
|
+
├── my_perceptor/ # Main package folder
|
|
12
|
+
│ ├── __init__.py # Package init file
|
|
13
|
+
│ └── perceptor.py # Main perceptor file
|
|
14
|
+
├── pyproject.toml # Project configuration, containing [composabl]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## PyProject [composabl] Section
|
|
18
|
+
|
|
19
|
+
We add the `[composabl]` section to the `pyproject.toml` file to specify the type of component we are creating as well as its entrypoint. This is used by the Composabl CLI to determine the type of
|
|
20
|
+
component and how to handle it.
|
|
21
|
+
|
|
22
|
+
Example:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
[composabl]
|
|
26
|
+
type = "teacher"
|
|
27
|
+
entrypoint = "my_perceptor.perceptor:MyPerceptor"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Development
|
|
31
|
+
|
|
32
|
+
To work on the Perceptor, you can simply create a temporary file or main file that starts up and executes the `compute` method of the portable Perceptor. Example, we can create a `test.py` file with:
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from composabl_perceptor_my_perceptor.perceptor import MyPerceptor
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def start():
|
|
39
|
+
p = MyPerceptor()
|
|
40
|
+
res = await t.compute(None, [1.0])
|
|
41
|
+
print(res)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if __name__ == "__main__":
|
|
45
|
+
import asyncio
|
|
46
|
+
|
|
47
|
+
asyncio.run(start())
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Which we can then run with
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Install the module
|
|
54
|
+
pip install -e my-perceptor
|
|
55
|
+
|
|
56
|
+
# Run the test file
|
|
57
|
+
python my-perceptor/test.py
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Preparing for Upload
|
|
61
|
+
|
|
62
|
+
Once we are ready for uploading, we can create a `.tar.gz` file that contains the version. This can be done with the following command:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Tar GZ the plugin
|
|
66
|
+
tar -czvf my-perceptor-0.0.1.tar.gz my-perceptor
|
|
67
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "{{NAME}}"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "{{DESCRIPTION}}"
|
|
5
|
+
authors = [{ name = "John Doe", email = "john.doe@composabl.com" }]
|
|
6
|
+
dependencies = [
|
|
7
|
+
"composabl-core{{COMPOSABL_DEV}}{{COMPOSABL_CORE_VERSION}}",
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
[composabl]
|
|
11
|
+
type = "skill-coordinated-population"
|
|
12
|
+
entrypoint = "{{NAME_MODULE}}.coach:Coach"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Copyright (C) Composabl, Inc - All Rights Reserved
|
|
2
|
+
# Unauthorized copying of this file, via any medium is strictly prohibited
|
|
3
|
+
# Proprietary and confidential
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from typing import Dict, List
|
|
7
|
+
|
|
8
|
+
from composabl_core.agent.skill.skill_coach import SkillCoach
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Coach(SkillCoach):
|
|
12
|
+
"""
|
|
13
|
+
We start at 10 reward and count down to 0 the goal is that the agent stays
|
|
14
|
+
above or equal to 0 this means it learned to cound +1 each time
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, *args, **kwargs):
|
|
18
|
+
self.past_obs = None
|
|
19
|
+
self.counter = 10
|
|
20
|
+
self.sensor_name = "counter"
|
|
21
|
+
|
|
22
|
+
async def compute_reward(self, transformed_sensors: Dict, action, sim_reward):
|
|
23
|
+
"""
|
|
24
|
+
The reward increases the closer it gets to 10, but decreases the
|
|
25
|
+
further it gets from 10 it decreases faster the further it gets
|
|
26
|
+
note: we do this through a piecewise function, where the reward is
|
|
27
|
+
100 if the counter is 10 and 0 if the counter is 0 everything above
|
|
28
|
+
10 gets a steep decrease and everything below 10 gets a small increase
|
|
29
|
+
ASCII of the Piecewise Graph
|
|
30
|
+
***********
|
|
31
|
+
***** ***
|
|
32
|
+
*** **
|
|
33
|
+
** **
|
|
34
|
+
*** **
|
|
35
|
+
* *
|
|
36
|
+
**
|
|
37
|
+
*
|
|
38
|
+
*
|
|
39
|
+
*
|
|
40
|
+
"""
|
|
41
|
+
counter = transformed_sensors[self.sensor_name]
|
|
42
|
+
|
|
43
|
+
# Small build up if < 10
|
|
44
|
+
# given by e^(counter - 10) + 100
|
|
45
|
+
if counter < 10:
|
|
46
|
+
return math.exp(counter - 10) + 100
|
|
47
|
+
# else steep decent after max reward
|
|
48
|
+
# given by -2 * e^(-|counter - 10|) + 100
|
|
49
|
+
else:
|
|
50
|
+
return -2 * math.exp(-abs(counter - 10)) + 100
|
|
51
|
+
|
|
52
|
+
async def compute_action_mask(
|
|
53
|
+
self, transformed_sensors: Dict, action
|
|
54
|
+
) -> List[bool]:
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
async def compute_success_criteria(self, transformed_sensors: Dict, action) -> bool:
|
|
58
|
+
return bool(transformed_sensors[self.sensor_name] >= 10)
|
|
59
|
+
|
|
60
|
+
async def compute_termination(self, transformed_sensors: Dict, action) -> bool:
|
|
61
|
+
return bool(transformed_sensors[self.sensor_name] <= -10)
|
|
62
|
+
|
|
63
|
+
async def transform_sensors(self, sensors, action) -> str:
|
|
64
|
+
return sensors
|
|
65
|
+
|
|
66
|
+
async def transform_action(self, transformed_sensors: Dict, action) -> float:
|
|
67
|
+
return action
|
|
68
|
+
|
|
69
|
+
async def filtered_sensor_space(self) -> List[str]:
|
|
70
|
+
return ["counter"]
|