composabl-cli-dev 0.18.6.dev15__cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.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.

Files changed (71) hide show
  1. composabl_cli/__init__.py +9 -0
  2. composabl_cli/cli/__init__.cpython-312-aarch64-linux-gnu.so +0 -0
  3. composabl_cli/cli/cli.cpython-312-aarch64-linux-gnu.so +0 -0
  4. composabl_cli/cli/cli_agent.cpython-312-aarch64-linux-gnu.so +0 -0
  5. composabl_cli/cli/cli_benchmark.cpython-312-aarch64-linux-gnu.so +0 -0
  6. composabl_cli/cli/cli_debug.cpython-312-aarch64-linux-gnu.so +0 -0
  7. composabl_cli/cli/cli_historian.cpython-312-aarch64-linux-gnu.so +0 -0
  8. composabl_cli/cli/cli_job.cpython-312-aarch64-linux-gnu.so +0 -0
  9. composabl_cli/cli/cli_main.cpython-312-aarch64-linux-gnu.so +0 -0
  10. composabl_cli/cli/cli_perceptor.cpython-312-aarch64-linux-gnu.so +0 -0
  11. composabl_cli/cli/cli_selector.cpython-312-aarch64-linux-gnu.so +0 -0
  12. composabl_cli/cli/cli_sim.cpython-312-aarch64-linux-gnu.so +0 -0
  13. composabl_cli/cli/cli_skill.cpython-312-aarch64-linux-gnu.so +0 -0
  14. composabl_cli/cli/cli_version.cpython-312-aarch64-linux-gnu.so +0 -0
  15. composabl_cli/k8s/k8s_train.cpython-312-aarch64-linux-gnu.so +0 -0
  16. composabl_cli/k8s/util.cpython-312-aarch64-linux-gnu.so +0 -0
  17. composabl_cli/main/agent.cpython-312-aarch64-linux-gnu.so +0 -0
  18. composabl_cli/main/perceptor.cpython-312-aarch64-linux-gnu.so +0 -0
  19. composabl_cli/main/selector.cpython-312-aarch64-linux-gnu.so +0 -0
  20. composabl_cli/main/sim.cpython-312-aarch64-linux-gnu.so +0 -0
  21. composabl_cli/main/skill.cpython-312-aarch64-linux-gnu.so +0 -0
  22. composabl_cli/template/agent_composabl/agent.py +90 -0
  23. composabl_cli/template/agent_docker/agent.py +99 -0
  24. composabl_cli/template/agent_local/agent.py +96 -0
  25. composabl_cli/template/perceptor/README.md +67 -0
  26. composabl_cli/template/perceptor/pyproject.toml +15 -0
  27. composabl_cli/template/perceptor/{{NAME_MODULE}}/__init__.py +3 -0
  28. composabl_cli/template/perceptor/{{NAME_MODULE}}/perceptor.py +34 -0
  29. composabl_cli/template/selector_controller/README.md +67 -0
  30. composabl_cli/template/selector_controller/pyproject.toml +12 -0
  31. composabl_cli/template/selector_controller/{{NAME_MODULE}}/__init__.py +3 -0
  32. composabl_cli/template/selector_controller/{{NAME_MODULE}}/controller.py +52 -0
  33. composabl_cli/template/selector_teacher/README.md +67 -0
  34. composabl_cli/template/selector_teacher/pyproject.toml +12 -0
  35. composabl_cli/template/selector_teacher/{{NAME_MODULE}}/__init__.py +3 -0
  36. composabl_cli/template/selector_teacher/{{NAME_MODULE}}/teacher.py +70 -0
  37. composabl_cli/template/sim/README.md +39 -0
  38. composabl_cli/template/sim/pyproject.toml +20 -0
  39. composabl_cli/template/sim/{{NAME_MODULE}}/__init__.py +3 -0
  40. composabl_cli/template/sim/{{NAME_MODULE}}/sim.py +253 -0
  41. composabl_cli/template/sim/{{NAME_MODULE}}/sim_impl.py +115 -0
  42. composabl_cli/template/sim_docker/Dockerfile +45 -0
  43. composabl_cli/template/sim_docker/README.md +17 -0
  44. composabl_cli/template/sim_docker/docker/sim-start.sh +14 -0
  45. composabl_cli/template/sim_docker/main.py +55 -0
  46. composabl_cli/template/sim_docker/module/README.md +39 -0
  47. composabl_cli/template/sim_docker/module/pyproject.toml +20 -0
  48. composabl_cli/template/sim_docker/module/{{NAME_MODULE}}/__init__.py +3 -0
  49. composabl_cli/template/sim_docker/module/{{NAME_MODULE}}/sim.py +253 -0
  50. composabl_cli/template/sim_docker/module/{{NAME_MODULE}}/sim_impl.py +115 -0
  51. composabl_cli/template/skill_controller/README.md +67 -0
  52. composabl_cli/template/skill_controller/pyproject.toml +12 -0
  53. composabl_cli/template/skill_controller/{{NAME_MODULE}}/__init__.py +3 -0
  54. composabl_cli/template/skill_controller/{{NAME_MODULE}}/controller.py +40 -0
  55. composabl_cli/template/skill_coordinated_population/README.md +67 -0
  56. composabl_cli/template/skill_coordinated_population/pyproject.toml +12 -0
  57. composabl_cli/template/skill_coordinated_population/{{NAME_MODULE}}/__init__.py +3 -0
  58. composabl_cli/template/skill_coordinated_population/{{NAME_MODULE}}/coach.py +70 -0
  59. composabl_cli/template/skill_coordinated_set/README.md +67 -0
  60. composabl_cli/template/skill_coordinated_set/pyproject.toml +12 -0
  61. composabl_cli/template/skill_coordinated_set/{{NAME_MODULE}}/__init__.py +3 -0
  62. composabl_cli/template/skill_coordinated_set/{{NAME_MODULE}}/coach.py +70 -0
  63. composabl_cli/template/skill_teacher/README.md +67 -0
  64. composabl_cli/template/skill_teacher/pyproject.toml +12 -0
  65. composabl_cli/template/skill_teacher/{{NAME_MODULE}}/__init__.py +3 -0
  66. composabl_cli/template/skill_teacher/{{NAME_MODULE}}/teacher.py +70 -0
  67. composabl_cli_dev-0.18.6.dev15.dist-info/METADATA +49 -0
  68. composabl_cli_dev-0.18.6.dev15.dist-info/RECORD +71 -0
  69. composabl_cli_dev-0.18.6.dev15.dist-info/WHEEL +6 -0
  70. composabl_cli_dev-0.18.6.dev15.dist-info/entry_points.txt +2 -0
  71. composabl_cli_dev-0.18.6.dev15.dist-info/top_level.txt +1 -0
@@ -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"
8
+ ]
9
+
10
+ [composabl]
11
+ type = "selector-teacher"
12
+ entrypoint = "{{NAME_MODULE}}.teacher:Teacher"
@@ -0,0 +1,3 @@
1
+ # Copyright (C) Composabl, Inc - All Rights Reserved
2
+ # Unauthorized copying of this file, via any medium is strictly prohibited
3
+ # Proprietary and confidential
@@ -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 import SkillTeacher
9
+
10
+
11
+ class Teacher(SkillTeacher):
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"]
@@ -0,0 +1,39 @@
1
+ # README
2
+
3
+ ## Tree Structure
4
+
5
+ The template is structured as follows:
6
+
7
+ ```bash
8
+ my-sim/ # Root folder
9
+ ├── my_sim/ # Main package folder
10
+ │ ├── __init__.py # Package init file
11
+ │ ├── sim_impl.py # Sim Implementation
12
+ │ └── sim.py # Sim Itself
13
+ ├── pyproject.toml # Project configuration, containing [composabl]
14
+ ```
15
+
16
+ ## PyProject [composabl] Section
17
+
18
+ We add the `[composabl]` section to the `pyproject.toml` file to specify the sim we are creating as well as its entrypoint. This is used by the Composabl Sim Container to determine how to start the sim.
19
+
20
+ Example:
21
+
22
+ ```toml
23
+ [composabl]
24
+ type = "sim"
25
+ entrypoint = "my_sim.sim_impl:MySimImpl"
26
+ ```
27
+
28
+ ## Development
29
+
30
+ To work on the Sim, you can simply run `composabl sim run <folder>`. This will do the same but locally.
31
+
32
+ ## Preparing for Upload
33
+
34
+ Once we are ready for uploading, we can create a `.zip` file that contains the version and is prefixed with `composabl-sim-`. This can be done with the following command:
35
+
36
+ ```bash
37
+ # Zip the Sim
38
+ zip -r composabl-sim-demo-0.0.1.zip sim-demo/
39
+ ```
@@ -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{{COMPOSABL_DEV}}{{COMPOSABL_CORE_VERSION}}",
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,3 @@
1
+ # Copyright (C) Composabl, Inc - All Rights Reserved
2
+ # Unauthorized copying of this file, via any medium is strictly prohibited
3
+ # Proprietary and confidential
@@ -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,45 @@
1
+ ######################################################
2
+ # Composabl Image
3
+ ######################################################
4
+ FROM python:3.11-slim
5
+
6
+ # Set working directory
7
+ WORKDIR /opt/composabl
8
+
9
+ # ######################################################
10
+ # Install Dependencies
11
+ # ######################################################
12
+ RUN apt update; apt install -y unzip tree
13
+
14
+ # ######################################################
15
+ # Make `python3` available as `python`
16
+ # ######################################################
17
+ RUN ln -s /usr/bin/python3 /usr/bin/python
18
+
19
+ # ######################################################
20
+ # Install Composabl
21
+ # ######################################################
22
+ RUN pip install composabl-core
23
+
24
+ # ######################################################
25
+ # Install Python Module
26
+ # ######################################################
27
+ COPY module/ /opt/composabl/sim/
28
+ RUN pip install /opt/composabl/sim/
29
+
30
+ # ######################################################
31
+ # Install Composabl Code and Docker scripts
32
+ # ######################################################
33
+ # Copy over the scripts
34
+ COPY docker /docker
35
+ RUN chmod +x /docker/*.sh
36
+
37
+ # Copy over the main startup file
38
+ # this file takes care of starting the Composabl server
39
+ COPY *.py /opt/composabl/
40
+
41
+ # ######################################################
42
+ # Define run
43
+ # ######################################################
44
+ EXPOSE 1337
45
+ CMD ["/docker/sim-start.sh", "/opt/composabl/sim"]
@@ -0,0 +1,17 @@
1
+ # README
2
+
3
+ This is an example of how to build a composabl suitable container yourself for full control.
4
+
5
+ ### Build the Sim
6
+
7
+ To build the sim wrapper, run the following command:
8
+
9
+ ```bash
10
+ docker build -t composabl/sim-demo .
11
+ ```
12
+
13
+ ### Run the Sim
14
+
15
+ ```bash
16
+ docker run --rm -it -p 1337:1337 composabl/sim-demo
17
+ ```
@@ -0,0 +1,14 @@
1
+ #!/bin/bash -e
2
+ ################################################################################
3
+ ## File: sim-start.sh
4
+ ## Desc: Start the Composabl Sim Wrapper
5
+ ################################################################################
6
+ PATH_SIM=${1:-/composabl/sim}
7
+ SIM_CONFIG_JSON=${2:-"{}"}
8
+
9
+ HOST=${HOST:-"0.0.0.0"}
10
+ PORT=${PORT:-"1337"}
11
+
12
+ # Start the Sim Client Wrapper
13
+ echo "$0: Starting the Sim Wrapper"
14
+ python3 /opt/composabl/main.py --path $PATH_SIM --config $SIM_CONFIG_JSON --port $PORT --host $HOST
@@ -0,0 +1,55 @@
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 argparse
6
+ import os
7
+ from typing import Optional
8
+
9
+ from composabl_core.networking.sim.server import make_from_sim_path
10
+
11
+
12
+ async def _run(
13
+ path: Optional[str] = "./",
14
+ host: Optional[str] = "0.0.0.0",
15
+ port: Optional[int] = 1337,
16
+ protocol: Optional[str] = "grpc",
17
+ config: Optional[dict] = {},
18
+ ):
19
+ """
20
+ Try to run the sim situated in the given location
21
+ """
22
+ path_abs = os.path.abspath(path)
23
+
24
+ print(f"Running sim from path: {path_abs}")
25
+ print(f"Params: {path}, {host}, {port}, {protocol}, {config}")
26
+
27
+ server = make_from_sim_path(path, host, port, config=config, protocol=protocol)
28
+ print(f"Running on {host}:{port}")
29
+
30
+ try:
31
+ await server.start()
32
+ except KeyboardInterrupt:
33
+ print("KeyboardInterrupt, Gracefully stopping the server")
34
+ except Exception as e:
35
+ print(f"Unknown error: {e}, Gracefully stopping the server")
36
+ finally:
37
+ print("Stopping the server")
38
+ if server is not None:
39
+ await server.stop()
40
+
41
+
42
+ if __name__ == "__main__":
43
+ parser = argparse.ArgumentParser()
44
+ parser.add_argument("--path", type=str, default="./")
45
+ parser.add_argument("--host", type=str, default="0.0.0.0")
46
+ parser.add_argument("--port", type=int, default=1337)
47
+ parser.add_argument("--protocol", type=str, default="grpc")
48
+ parser.add_argument("--config", type=str, default="{}")
49
+ args = parser.parse_args()
50
+
51
+ config_parsed = eval(args.config)
52
+
53
+ import asyncio
54
+
55
+ asyncio.run(_run(args.path, args.host, args.port, args.protocol, config_parsed))
@@ -0,0 +1,39 @@
1
+ # README
2
+
3
+ ## Tree Structure
4
+
5
+ The template is structured as follows:
6
+
7
+ ```bash
8
+ my-sim/ # Root folder
9
+ ├── my_sim/ # Main package folder
10
+ │ ├── __init__.py # Package init file
11
+ │ ├── sim_impl.py # Sim Implementation
12
+ │ └── sim.py # Sim Itself
13
+ ├── pyproject.toml # Project configuration, containing [composabl]
14
+ ```
15
+
16
+ ## PyProject [composabl] Section
17
+
18
+ We add the `[composabl]` section to the `pyproject.toml` file to specify the sim we are creating as well as its entrypoint. This is used by the Composabl Sim Container to determine how to start the sim.
19
+
20
+ Example:
21
+
22
+ ```toml
23
+ [composabl]
24
+ type = "sim"
25
+ entrypoint = "my_sim.sim_impl:MySimImpl"
26
+ ```
27
+
28
+ ## Development
29
+
30
+ To work on the Sim, you can simply run `composabl sim run <folder>`. This will do the same but locally.
31
+
32
+ ## Preparing for Upload
33
+
34
+ Once we are ready for uploading, we can create a `.zip` file that contains the version and is prefixed with `composabl-sim-`. This can be done with the following command:
35
+
36
+ ```bash
37
+ # Zip the Sim
38
+ zip -r composabl-sim-demo-0.0.1.zip sim-demo/
39
+ ```