sierra-research 1.3.11__py3-none-any.whl → 1.5.0__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.
Files changed (254) hide show
  1. sierra/__init__.py +3 -3
  2. sierra/core/__init__.py +3 -3
  3. sierra/core/batchroot.py +223 -0
  4. sierra/core/cmdline.py +681 -1057
  5. sierra/core/compare.py +11 -0
  6. sierra/core/config.py +96 -88
  7. sierra/core/engine.py +306 -0
  8. sierra/core/execenv.py +380 -0
  9. sierra/core/expdef.py +11 -0
  10. sierra/core/experiment/__init__.py +1 -0
  11. sierra/core/experiment/bindings.py +150 -101
  12. sierra/core/experiment/definition.py +414 -245
  13. sierra/core/experiment/spec.py +83 -85
  14. sierra/core/exproot.py +44 -0
  15. sierra/core/generators/__init__.py +10 -0
  16. sierra/core/generators/experiment.py +528 -0
  17. sierra/core/generators/generator_factory.py +138 -137
  18. sierra/core/graphs/__init__.py +23 -0
  19. sierra/core/graphs/bcbridge.py +94 -0
  20. sierra/core/graphs/heatmap.py +245 -324
  21. sierra/core/graphs/pathset.py +27 -0
  22. sierra/core/graphs/schema.py +77 -0
  23. sierra/core/graphs/stacked_line.py +341 -0
  24. sierra/core/graphs/summary_line.py +506 -0
  25. sierra/core/logging.py +3 -2
  26. sierra/core/models/__init__.py +3 -1
  27. sierra/core/models/info.py +19 -0
  28. sierra/core/models/interface.py +52 -122
  29. sierra/core/pipeline/__init__.py +2 -5
  30. sierra/core/pipeline/pipeline.py +228 -126
  31. sierra/core/pipeline/stage1/__init__.py +10 -0
  32. sierra/core/pipeline/stage1/pipeline_stage1.py +45 -31
  33. sierra/core/pipeline/stage2/__init__.py +10 -0
  34. sierra/core/pipeline/stage2/pipeline_stage2.py +8 -11
  35. sierra/core/pipeline/stage2/runner.py +401 -0
  36. sierra/core/pipeline/stage3/__init__.py +12 -0
  37. sierra/core/pipeline/stage3/gather.py +321 -0
  38. sierra/core/pipeline/stage3/pipeline_stage3.py +37 -84
  39. sierra/core/pipeline/stage4/__init__.py +12 -2
  40. sierra/core/pipeline/stage4/pipeline_stage4.py +36 -354
  41. sierra/core/pipeline/stage5/__init__.py +12 -0
  42. sierra/core/pipeline/stage5/pipeline_stage5.py +33 -208
  43. sierra/core/pipeline/yaml.py +48 -0
  44. sierra/core/plugin.py +529 -62
  45. sierra/core/proc.py +11 -0
  46. sierra/core/prod.py +11 -0
  47. sierra/core/ros1/__init__.py +5 -1
  48. sierra/core/ros1/callbacks.py +22 -21
  49. sierra/core/ros1/cmdline.py +59 -88
  50. sierra/core/ros1/generators.py +159 -175
  51. sierra/core/ros1/variables/__init__.py +3 -0
  52. sierra/core/ros1/variables/exp_setup.py +122 -116
  53. sierra/core/startup.py +106 -76
  54. sierra/core/stat_kernels.py +4 -5
  55. sierra/core/storage.py +13 -32
  56. sierra/core/trampoline.py +30 -0
  57. sierra/core/types.py +116 -71
  58. sierra/core/utils.py +103 -106
  59. sierra/core/variables/__init__.py +1 -1
  60. sierra/core/variables/base_variable.py +12 -17
  61. sierra/core/variables/batch_criteria.py +387 -481
  62. sierra/core/variables/builtin.py +135 -0
  63. sierra/core/variables/exp_setup.py +19 -39
  64. sierra/core/variables/population_size.py +72 -76
  65. sierra/core/variables/variable_density.py +44 -68
  66. sierra/core/vector.py +1 -1
  67. sierra/main.py +256 -88
  68. sierra/plugins/__init__.py +119 -0
  69. sierra/plugins/compare/__init__.py +14 -0
  70. sierra/plugins/compare/graphs/__init__.py +19 -0
  71. sierra/plugins/compare/graphs/cmdline.py +120 -0
  72. sierra/plugins/compare/graphs/comparator.py +291 -0
  73. sierra/plugins/compare/graphs/inter_controller.py +531 -0
  74. sierra/plugins/compare/graphs/inter_scenario.py +297 -0
  75. sierra/plugins/compare/graphs/namecalc.py +53 -0
  76. sierra/plugins/compare/graphs/outputroot.py +73 -0
  77. sierra/plugins/compare/graphs/plugin.py +147 -0
  78. sierra/plugins/compare/graphs/preprocess.py +172 -0
  79. sierra/plugins/compare/graphs/schema.py +37 -0
  80. sierra/plugins/engine/__init__.py +14 -0
  81. sierra/plugins/engine/argos/__init__.py +18 -0
  82. sierra/plugins/{platform → engine}/argos/cmdline.py +144 -151
  83. sierra/plugins/{platform/argos/variables → engine/argos/generators}/__init__.py +5 -0
  84. sierra/plugins/engine/argos/generators/engine.py +394 -0
  85. sierra/plugins/engine/argos/plugin.py +393 -0
  86. sierra/plugins/{platform/argos/generators → engine/argos/variables}/__init__.py +5 -0
  87. sierra/plugins/engine/argos/variables/arena_shape.py +183 -0
  88. sierra/plugins/engine/argos/variables/cameras.py +240 -0
  89. sierra/plugins/engine/argos/variables/constant_density.py +112 -0
  90. sierra/plugins/engine/argos/variables/exp_setup.py +82 -0
  91. sierra/plugins/{platform → engine}/argos/variables/physics_engines.py +83 -87
  92. sierra/plugins/engine/argos/variables/population_constant_density.py +178 -0
  93. sierra/plugins/engine/argos/variables/population_size.py +115 -0
  94. sierra/plugins/engine/argos/variables/population_variable_density.py +123 -0
  95. sierra/plugins/engine/argos/variables/rendering.py +108 -0
  96. sierra/plugins/engine/ros1gazebo/__init__.py +18 -0
  97. sierra/plugins/engine/ros1gazebo/cmdline.py +175 -0
  98. sierra/plugins/{platform/ros1robot → engine/ros1gazebo}/generators/__init__.py +5 -0
  99. sierra/plugins/engine/ros1gazebo/generators/engine.py +125 -0
  100. sierra/plugins/engine/ros1gazebo/plugin.py +404 -0
  101. sierra/plugins/engine/ros1gazebo/variables/__init__.py +15 -0
  102. sierra/plugins/engine/ros1gazebo/variables/population_size.py +214 -0
  103. sierra/plugins/engine/ros1robot/__init__.py +18 -0
  104. sierra/plugins/engine/ros1robot/cmdline.py +159 -0
  105. sierra/plugins/{platform/ros1gazebo → engine/ros1robot}/generators/__init__.py +4 -0
  106. sierra/plugins/engine/ros1robot/generators/engine.py +95 -0
  107. sierra/plugins/engine/ros1robot/plugin.py +410 -0
  108. sierra/plugins/{hpc/local → engine/ros1robot/variables}/__init__.py +5 -0
  109. sierra/plugins/engine/ros1robot/variables/population_size.py +146 -0
  110. sierra/plugins/execenv/__init__.py +11 -0
  111. sierra/plugins/execenv/hpc/__init__.py +18 -0
  112. sierra/plugins/execenv/hpc/adhoc/__init__.py +18 -0
  113. sierra/plugins/execenv/hpc/adhoc/cmdline.py +30 -0
  114. sierra/plugins/execenv/hpc/adhoc/plugin.py +131 -0
  115. sierra/plugins/execenv/hpc/cmdline.py +137 -0
  116. sierra/plugins/execenv/hpc/local/__init__.py +18 -0
  117. sierra/plugins/execenv/hpc/local/cmdline.py +31 -0
  118. sierra/plugins/execenv/hpc/local/plugin.py +145 -0
  119. sierra/plugins/execenv/hpc/pbs/__init__.py +18 -0
  120. sierra/plugins/execenv/hpc/pbs/cmdline.py +30 -0
  121. sierra/plugins/execenv/hpc/pbs/plugin.py +121 -0
  122. sierra/plugins/execenv/hpc/slurm/__init__.py +18 -0
  123. sierra/plugins/execenv/hpc/slurm/cmdline.py +30 -0
  124. sierra/plugins/execenv/hpc/slurm/plugin.py +133 -0
  125. sierra/plugins/execenv/prefectserver/__init__.py +18 -0
  126. sierra/plugins/execenv/prefectserver/cmdline.py +66 -0
  127. sierra/plugins/execenv/prefectserver/dockerremote/__init__.py +18 -0
  128. sierra/plugins/execenv/prefectserver/dockerremote/cmdline.py +66 -0
  129. sierra/plugins/execenv/prefectserver/dockerremote/plugin.py +132 -0
  130. sierra/plugins/execenv/prefectserver/flow.py +66 -0
  131. sierra/plugins/execenv/prefectserver/local/__init__.py +18 -0
  132. sierra/plugins/execenv/prefectserver/local/cmdline.py +29 -0
  133. sierra/plugins/execenv/prefectserver/local/plugin.py +133 -0
  134. sierra/plugins/{hpc/adhoc → execenv/robot}/__init__.py +1 -0
  135. sierra/plugins/execenv/robot/turtlebot3/__init__.py +18 -0
  136. sierra/plugins/execenv/robot/turtlebot3/plugin.py +204 -0
  137. sierra/plugins/expdef/__init__.py +14 -0
  138. sierra/plugins/expdef/json/__init__.py +14 -0
  139. sierra/plugins/expdef/json/plugin.py +504 -0
  140. sierra/plugins/expdef/xml/__init__.py +14 -0
  141. sierra/plugins/expdef/xml/plugin.py +386 -0
  142. sierra/{core/hpc → plugins/proc}/__init__.py +1 -1
  143. sierra/plugins/proc/collate/__init__.py +15 -0
  144. sierra/plugins/proc/collate/cmdline.py +47 -0
  145. sierra/plugins/proc/collate/plugin.py +271 -0
  146. sierra/plugins/proc/compress/__init__.py +18 -0
  147. sierra/plugins/proc/compress/cmdline.py +47 -0
  148. sierra/plugins/proc/compress/plugin.py +123 -0
  149. sierra/plugins/proc/decompress/__init__.py +18 -0
  150. sierra/plugins/proc/decompress/plugin.py +96 -0
  151. sierra/plugins/proc/imagize/__init__.py +15 -0
  152. sierra/plugins/proc/imagize/cmdline.py +49 -0
  153. sierra/plugins/proc/imagize/plugin.py +270 -0
  154. sierra/plugins/proc/modelrunner/__init__.py +16 -0
  155. sierra/plugins/proc/modelrunner/plugin.py +250 -0
  156. sierra/plugins/proc/statistics/__init__.py +15 -0
  157. sierra/plugins/proc/statistics/cmdline.py +64 -0
  158. sierra/plugins/proc/statistics/plugin.py +390 -0
  159. sierra/plugins/{hpc → prod}/__init__.py +1 -0
  160. sierra/plugins/prod/graphs/__init__.py +18 -0
  161. sierra/plugins/prod/graphs/cmdline.py +269 -0
  162. sierra/plugins/prod/graphs/collate.py +279 -0
  163. sierra/plugins/prod/graphs/inter/__init__.py +13 -0
  164. sierra/plugins/prod/graphs/inter/generate.py +83 -0
  165. sierra/plugins/prod/graphs/inter/heatmap.py +86 -0
  166. sierra/plugins/prod/graphs/inter/line.py +134 -0
  167. sierra/plugins/prod/graphs/intra/__init__.py +15 -0
  168. sierra/plugins/prod/graphs/intra/generate.py +202 -0
  169. sierra/plugins/prod/graphs/intra/heatmap.py +74 -0
  170. sierra/plugins/prod/graphs/intra/line.py +114 -0
  171. sierra/plugins/prod/graphs/plugin.py +103 -0
  172. sierra/plugins/prod/graphs/targets.py +63 -0
  173. sierra/plugins/prod/render/__init__.py +18 -0
  174. sierra/plugins/prod/render/cmdline.py +72 -0
  175. sierra/plugins/prod/render/plugin.py +282 -0
  176. sierra/plugins/storage/__init__.py +5 -0
  177. sierra/plugins/storage/arrow/__init__.py +18 -0
  178. sierra/plugins/storage/arrow/plugin.py +38 -0
  179. sierra/plugins/storage/csv/__init__.py +9 -0
  180. sierra/plugins/storage/csv/plugin.py +12 -5
  181. sierra/version.py +3 -2
  182. sierra_research-1.5.0.dist-info/METADATA +238 -0
  183. sierra_research-1.5.0.dist-info/RECORD +186 -0
  184. {sierra_research-1.3.11.dist-info → sierra_research-1.5.0.dist-info}/WHEEL +1 -2
  185. sierra/core/experiment/xml.py +0 -454
  186. sierra/core/generators/controller_generator_parser.py +0 -34
  187. sierra/core/generators/exp_creator.py +0 -351
  188. sierra/core/generators/exp_generators.py +0 -142
  189. sierra/core/graphs/scatterplot2D.py +0 -109
  190. sierra/core/graphs/stacked_line_graph.py +0 -251
  191. sierra/core/graphs/stacked_surface_graph.py +0 -220
  192. sierra/core/graphs/summary_line_graph.py +0 -371
  193. sierra/core/hpc/cmdline.py +0 -142
  194. sierra/core/models/graphs.py +0 -87
  195. sierra/core/pipeline/stage2/exp_runner.py +0 -286
  196. sierra/core/pipeline/stage3/imagizer.py +0 -149
  197. sierra/core/pipeline/stage3/run_collator.py +0 -317
  198. sierra/core/pipeline/stage3/statistics_calculator.py +0 -478
  199. sierra/core/pipeline/stage4/graph_collator.py +0 -320
  200. sierra/core/pipeline/stage4/inter_exp_graph_generator.py +0 -240
  201. sierra/core/pipeline/stage4/intra_exp_graph_generator.py +0 -317
  202. sierra/core/pipeline/stage4/model_runner.py +0 -168
  203. sierra/core/pipeline/stage4/rendering.py +0 -283
  204. sierra/core/pipeline/stage4/yaml_config_loader.py +0 -103
  205. sierra/core/pipeline/stage5/inter_scenario_comparator.py +0 -328
  206. sierra/core/pipeline/stage5/intra_scenario_comparator.py +0 -989
  207. sierra/core/platform.py +0 -493
  208. sierra/core/plugin_manager.py +0 -369
  209. sierra/core/root_dirpath_generator.py +0 -241
  210. sierra/plugins/hpc/adhoc/plugin.py +0 -125
  211. sierra/plugins/hpc/local/plugin.py +0 -81
  212. sierra/plugins/hpc/pbs/__init__.py +0 -9
  213. sierra/plugins/hpc/pbs/plugin.py +0 -126
  214. sierra/plugins/hpc/slurm/__init__.py +0 -9
  215. sierra/plugins/hpc/slurm/plugin.py +0 -130
  216. sierra/plugins/platform/__init__.py +0 -9
  217. sierra/plugins/platform/argos/__init__.py +0 -9
  218. sierra/plugins/platform/argos/generators/platform_generators.py +0 -383
  219. sierra/plugins/platform/argos/plugin.py +0 -337
  220. sierra/plugins/platform/argos/variables/arena_shape.py +0 -145
  221. sierra/plugins/platform/argos/variables/cameras.py +0 -243
  222. sierra/plugins/platform/argos/variables/constant_density.py +0 -136
  223. sierra/plugins/platform/argos/variables/exp_setup.py +0 -113
  224. sierra/plugins/platform/argos/variables/population_constant_density.py +0 -175
  225. sierra/plugins/platform/argos/variables/population_size.py +0 -102
  226. sierra/plugins/platform/argos/variables/population_variable_density.py +0 -132
  227. sierra/plugins/platform/argos/variables/rendering.py +0 -104
  228. sierra/plugins/platform/ros1gazebo/__init__.py +0 -9
  229. sierra/plugins/platform/ros1gazebo/cmdline.py +0 -213
  230. sierra/plugins/platform/ros1gazebo/generators/platform_generators.py +0 -137
  231. sierra/plugins/platform/ros1gazebo/plugin.py +0 -335
  232. sierra/plugins/platform/ros1gazebo/variables/__init__.py +0 -10
  233. sierra/plugins/platform/ros1gazebo/variables/population_size.py +0 -204
  234. sierra/plugins/platform/ros1robot/__init__.py +0 -9
  235. sierra/plugins/platform/ros1robot/cmdline.py +0 -175
  236. sierra/plugins/platform/ros1robot/generators/platform_generators.py +0 -112
  237. sierra/plugins/platform/ros1robot/plugin.py +0 -373
  238. sierra/plugins/platform/ros1robot/variables/__init__.py +0 -10
  239. sierra/plugins/platform/ros1robot/variables/population_size.py +0 -146
  240. sierra/plugins/robot/__init__.py +0 -9
  241. sierra/plugins/robot/turtlebot3/__init__.py +0 -9
  242. sierra/plugins/robot/turtlebot3/plugin.py +0 -194
  243. sierra_research-1.3.11.data/data/share/man/man1/sierra-cli.1 +0 -2349
  244. sierra_research-1.3.11.data/data/share/man/man7/sierra-examples.7 +0 -508
  245. sierra_research-1.3.11.data/data/share/man/man7/sierra-exec-envs.7 +0 -331
  246. sierra_research-1.3.11.data/data/share/man/man7/sierra-glossary.7 +0 -285
  247. sierra_research-1.3.11.data/data/share/man/man7/sierra-platforms.7 +0 -358
  248. sierra_research-1.3.11.data/data/share/man/man7/sierra-usage.7 +0 -729
  249. sierra_research-1.3.11.data/data/share/man/man7/sierra.7 +0 -78
  250. sierra_research-1.3.11.dist-info/METADATA +0 -492
  251. sierra_research-1.3.11.dist-info/RECORD +0 -133
  252. sierra_research-1.3.11.dist-info/top_level.txt +0 -1
  253. {sierra_research-1.3.11.dist-info → sierra_research-1.5.0.dist-info}/entry_points.txt +0 -0
  254. {sierra_research-1.3.11.dist-info → sierra_research-1.5.0.dist-info/licenses}/LICENSE +0 -0
@@ -1,175 +0,0 @@
1
- # Copyright 2021 John Harwell, All rights reserved.
2
- #
3
- # SPDX-License-Identifier: MIT
4
- #
5
- """
6
- Command line parsing and validation for the :term:`ROS1+robot` platform.
7
- """
8
-
9
- # Core packages
10
- import typing as tp
11
- import argparse
12
-
13
- # 3rd party packages
14
-
15
- # Project packages
16
- from sierra.core import types, ros1, config
17
- import sierra.core.cmdline as cmd
18
-
19
-
20
- class PlatformCmdline(cmd.BaseCmdline):
21
- """Defines :term:`ROS1` extensions to :class:`~sierra.core.cmdline.CoreCmdline`.
22
-
23
- """
24
-
25
- def __init__(self,
26
- parents: tp.Optional[tp.List[argparse.ArgumentParser]],
27
- stages: tp.List[int]) -> None:
28
-
29
- if parents is not None:
30
- self.parser = argparse.ArgumentParser(parents=parents,
31
- add_help=False,
32
- allow_abbrev=False)
33
- else:
34
- self.parser = argparse.ArgumentParser(add_help=False,
35
- allow_abbrev=False)
36
-
37
- self.scaffold_cli()
38
- self.init_cli(stages)
39
-
40
- def scaffold_cli(self) -> None:
41
- self.multistage = self.parser.add_argument_group('Multi-stage options',
42
- 'Options which are used in multiple pipeline stages')
43
- self.stage1 = self.parser.add_argument_group('Stage1: Experiment generation')
44
- self.stage2 = self.parser.add_argument_group('Stage2: Experiment execution'
45
- 'For running real robot experiments')
46
-
47
- def init_cli(self, stages: tp.List[int]) -> None:
48
- if -1 in stages:
49
- self.init_multistage()
50
-
51
- if 1 in stages:
52
- self.init_stage1()
53
-
54
- if 2 in stages:
55
- self.init_stage2()
56
-
57
- def init_multistage(self) -> None:
58
- self.multistage.add_argument("--skip-online-check",
59
- help="""
60
-
61
- If passed, then the usual 'is this robot
62
- online' checks will be skipped.
63
-
64
- """ + self.stage_usage_doc([1, 2]),
65
- action='store_true')
66
-
67
- self.multistage.add_argument("--online-check-method",
68
- choices=['ping+ssh', 'nc+ssh'],
69
- help="""
70
-
71
- How SIERRA should check if a given robot is
72
- online. Valid values:
73
-
74
- - ``ping+ssh`` - First, verify that you can
75
- ping each the hostname/IP associated with
76
- each robot. Second, verify that
77
- passwordless ssh to the hostname/IP
78
- works. This is the most common option.
79
-
80
- - ``nc+ssh`` - First, verify that an ssh
81
- connection exists from the SIERRA host
82
- machine to the robot on the specified
83
- port using netcat. Second, verify that
84
- passwordless ssh to the robot on the
85
- specified port works. This is useful when
86
- connecting to the robots through a
87
- reverse SSH tunnel, which can be
88
- necessary if the robots don't have a
89
- fixed IP address and cannot be addressed
90
- by FQDN (looking at you eduroam...).
91
-
92
- """,
93
- default='ping+ssh')
94
-
95
- def init_stage1(self) -> None:
96
- self.stage1.add_argument("--skip-sync",
97
- help="""
98
-
99
- If passed, then the generated experiment will not
100
- be synced to robots. This is useful when:
101
-
102
- - You are developing your :term:`Project` and
103
- just want to check locally if the experiment
104
- is being generated properly.
105
-
106
- - You have a lot of robots and/or the network
107
- connection from the SIERRA host machine to
108
- the robots is slow, and copying the
109
- experiment multiple times as you tweak
110
- parameters takes a long time.
111
-
112
- """ + self.stage_usage_doc([1]),
113
- action='store_true')
114
-
115
- def init_stage2(self) -> None:
116
- self.stage2.add_argument("--exec-inter-run-pause",
117
- metavar="SECONDS",
118
- help="""
119
-
120
- How long to pause between :term:`Experimental
121
- Runs <Experimental Run>`, giving you time to
122
- reset the environment, move robots, etc.
123
-
124
- """ + self.stage_usage_doc([2]),
125
- type=int,
126
- default=config.kROS['inter_run_pause'])
127
-
128
- self.stage2.add_argument("--exec-resume",
129
- help="""
130
-
131
- Resume a batch experiment that was
132
- killed/stopped/etc last time SIERRA was
133
- run.
134
-
135
- """ + self.stage_usage_doc([2]),
136
- action='store_true',
137
- default=False)
138
-
139
- @staticmethod
140
- def cmdopts_update(cli_args, cmdopts: types.Cmdopts) -> None:
141
- """Update cmdopts with ROS1+robot-specific cmdline options.
142
-
143
- """
144
- ros1.cmdline.ROSCmdline.cmdopts_update(cli_args, cmdopts)
145
- updates = {
146
- # Multistage
147
- 'exec_jobs_per_node': 1, # (1 job/robot)
148
- 'skip_online_check': cli_args.skip_online_check,
149
- 'online_check_method': cli_args.online_check_method,
150
-
151
- # stage 1
152
- 'skip_sync': cli_args.skip_sync,
153
-
154
- # stage 2
155
- 'exec_resume': cli_args.exec_resume,
156
- 'exec_inter_run_pause': cli_args.exec_inter_run_pause
157
- }
158
-
159
- cmdopts.update(updates)
160
-
161
-
162
- class CmdlineValidator(ros1.cmdline.ROSCmdlineValidator):
163
- """
164
- Stub implementation.
165
- """
166
-
167
-
168
- def sphinx_cmdline_stage1():
169
- parent = ros1.cmdline.ROSCmdline([1]).parser
170
- return PlatformCmdline([parent], [1]).parser
171
-
172
-
173
- def sphinx_cmdline_stage2():
174
- parent = ros1.cmdline.ROSCmdline([2]).parser
175
- return PlatformCmdline([parent], [2]).parser
@@ -1,112 +0,0 @@
1
- # Copyright 2021 John Harwell, All rights reserved.
2
- #
3
- # SPDX-License-Identifier: MIT
4
- """Classes for generating common XML modifications to :term:`ROS1` input files.
5
-
6
- I.e., changes which are platform-specific, but applicable to all projects using
7
- ROS with a real robot execution environment.
8
-
9
- """
10
- # Core packages
11
- import logging
12
- import pathlib
13
-
14
- # 3rd party packages
15
- import yaml
16
-
17
- # Project packages
18
- from sierra.core.experiment import spec, xml, definition
19
- from sierra.core import types, ros1, config, utils
20
-
21
-
22
- class PlatformExpDefGenerator(ros1.generators.ROSExpDefGenerator):
23
- """
24
- Init the object.
25
-
26
- Attributes:
27
-
28
- controller: The controller used for the experiment.
29
- cmdopts: Dictionary of parsed cmdline parameters.
30
- """
31
-
32
- def __init__(self,
33
- exp_spec: spec.ExperimentSpec,
34
- controller: str,
35
- cmdopts: types.Cmdopts,
36
- **kwargs) -> None:
37
- super().__init__(exp_spec, controller, cmdopts, **kwargs)
38
-
39
- self.logger = logging.getLogger(__name__)
40
-
41
- def generate(self) -> definition.XMLExpDef:
42
- exp_def = super().generate()
43
-
44
- self.logger.debug("Writing separate <master> launch file")
45
- exp_def.write_config.add({
46
- 'src_parent': '.',
47
- 'src_tag': 'master',
48
- 'opath_leaf': '_master' + config.kROS['launch_file_ext'],
49
- 'create_tags': None,
50
- 'rename_to': 'launch',
51
- 'dest_parent': None
52
- })
53
-
54
- # Add <robot> tag
55
- if not exp_def.has_tag("./robot"):
56
- exp_def.tag_add(".",
57
- "robot",
58
- {})
59
- if not exp_def.has_tag("./robot/group/[@ns='sierra']"):
60
- exp_def.tag_add("./robot",
61
- "group",
62
- {
63
- 'ns': 'sierra'
64
- })
65
-
66
- return exp_def
67
-
68
-
69
- class PlatformExpRunDefUniqueGenerator(ros1.generators.ROSExpRunDefUniqueGenerator):
70
- def __init__(self,
71
- *args,
72
- **kwargs) -> None:
73
- ros1.generators.ROSExpRunDefUniqueGenerator.__init__(
74
- self, *args, **kwargs)
75
-
76
- def generate(self, exp_def: definition.XMLExpDef):
77
- exp_def = super().generate(exp_def)
78
- main_path = pathlib.Path(self.cmdopts['project_config_root'],
79
- config.kYAML.main)
80
-
81
- with utils.utf8open(main_path) as f:
82
- main_config = yaml.load(f, yaml.FullLoader)
83
-
84
- n_robots = utils.get_n_robots(main_config,
85
- self.cmdopts,
86
- self.launch_stem_path.parent,
87
- exp_def)
88
-
89
- for i in range(0, n_robots):
90
- prefix = main_config['ros']['robots'][self.cmdopts['robot']]['prefix']
91
- exp_def.write_config.add({
92
- 'src_parent': "./robot",
93
- 'src_tag': f"group/[@ns='{prefix}{i}']",
94
- 'opath_leaf': f'_robot{i}' + config.kROS['launch_file_ext'],
95
- 'create_tags': [xml.TagAdd.as_root('launch', {})],
96
- 'dest_parent': ".",
97
- 'rename_to': None,
98
- 'child_grafts': ["./robot/group/[@ns='sierra']"]
99
- })
100
-
101
- self.generate_random(exp_def)
102
- self.generate_paramfile(exp_def)
103
-
104
- return exp_def
105
-
106
-
107
- __api__ = [
108
- 'PlatformExpDefGenerator',
109
- 'PlatformExpRunDefUniqueGenerator'
110
-
111
-
112
- ]
@@ -1,373 +0,0 @@
1
- # Copyright 2021 John Harwell, All rights reserved.
2
- #
3
- # SPDX-License-Identifier: MIT
4
-
5
- # Core packages
6
- import argparse
7
- import logging
8
- import typing as tp
9
- import os
10
- import subprocess
11
- import pwd
12
- import pathlib
13
-
14
- # 3rd party packages
15
- import implements
16
- import yaml
17
-
18
- # Project packages
19
- from sierra.plugins.platform.ros1robot import cmdline
20
- from sierra.core import platform, config, ros1, types, utils
21
- from sierra.core.experiment import bindings, definition, xml
22
- import sierra.core.variables.batch_criteria as bc
23
-
24
-
25
- class CmdlineParserGenerator():
26
- def __call__(self) -> argparse.ArgumentParser:
27
- parent1 = ros1.cmdline.ROSCmdline([-1, 1, 2, 3, 4, 5]).parser
28
- return cmdline.PlatformCmdline(parents=[parent1],
29
- stages=[-1, 1, 2, 3, 4, 5]).parser
30
-
31
-
32
- @implements.implements(bindings.IParsedCmdlineConfigurer)
33
- class ParsedCmdlineConfigurer():
34
- def __init__(self, exec_env: str) -> None:
35
- self.exec_env = exec_env
36
- self.logger = logging.getLogger('platform.ros1robot')
37
-
38
- def __call__(self, args: argparse.Namespace) -> None:
39
- if args.nodefile is None:
40
- assert 'SIERRA_NODEFILE' in os.environ,\
41
- ("Non-ros1robot environment detected: --nodefile not "
42
- "passed and 'SIERRA_NODEFILE' not found")
43
- args.nodefile = os.environ['SIERRA_NODEFILE']
44
-
45
- assert utils.path_exists(args.nodefile), \
46
- f"SIERRA_NODEFILE '{args.nodefile}' does not exist"
47
- self.logger.info("Using '%s' as robot hostnames file", args.nodefile)
48
-
49
- assert not args.platform_vc,\
50
- "Platform visual capture not supported on ros1robot"
51
-
52
-
53
- @implements.implements(bindings.IExpRunShellCmdsGenerator)
54
- class ExpRunShellCmdsGenerator():
55
- def __init__(self,
56
- cmdopts: types.Cmdopts,
57
- criteria: bc.BatchCriteria,
58
- n_robots: int,
59
- exp_num: int) -> None:
60
- self.cmdopts = cmdopts
61
- self.n_robots = n_robots
62
- self.exp_num = exp_num
63
- self.criteria = criteria
64
- self.logger = logging.getLogger('platform.ros1robot')
65
-
66
- def pre_run_cmds(self,
67
- host: str,
68
- input_fpath: pathlib.Path,
69
- run_num: int) -> tp.List[types.ShellCmdSpec]:
70
-
71
- master_ip = platform.get_local_ip()
72
- port = config.kROS['port_base'] + self.exp_num
73
- master_uri = f'http://{master_ip}:{port}'
74
-
75
- ros_master = types.ShellCmdSpec(cmd=f'export ROS_MASTER_URI={master_uri};',
76
- shell=True,
77
- env=True,
78
- wait=True)
79
-
80
- if host == 'master':
81
- if self.cmdopts['no_master_node']:
82
- return []
83
- else:
84
- return [ros_master]
85
-
86
- main_path = os.path.join(self.cmdopts['project_config_root'],
87
- config.kYAML.main)
88
-
89
- main_config = yaml.load(utils.utf8open(main_path), yaml.FullLoader)
90
-
91
- self.logger.debug("Generating pre-exec cmds for run%s slaves: %d robots",
92
- run_num,
93
- self.n_robots)
94
-
95
- script_yaml = main_config['ros']['robots'][self.cmdopts['robot']]
96
- script_file = script_yaml.get('setup_script', "$HOME/.bashrc")
97
-
98
- ros_setup = types.ShellCmdSpec(cmd=f'. {script_file};',
99
- shell=True,
100
- wait=True,
101
- env=True)
102
-
103
- return [ros_setup, ros_master]
104
-
105
- def exec_run_cmds(self,
106
- host: str,
107
- input_fpath: pathlib.Path,
108
- run_num: int) -> tp.List[types.ShellCmdSpec]:
109
- if host == 'master':
110
- return self._exec_run_cmds_master(host, input_fpath, run_num)
111
- else:
112
- return self._exec_run_cmds_slave(host, input_fpath, run_num)
113
-
114
- def _exec_run_cmds_master(self,
115
- host: str,
116
- input_fpath: pathlib.Path,
117
- run_num: int) -> tp.List[types.ShellCmdSpec]:
118
-
119
- if self.cmdopts['no_master_node']:
120
- return []
121
-
122
- self.logger.debug("Generating exec cmds for run%s master",
123
- run_num)
124
-
125
- # ROS master node
126
- exp_dirname = self.criteria.gen_exp_names(self.cmdopts)[self.exp_num]
127
- exp_template_path = utils.exp_template_path(self.cmdopts,
128
- self.criteria.batch_input_root,
129
- exp_dirname)
130
- cmd = '{0} --wait {1}_run{2}_master{3};'
131
-
132
- cmd = cmd.format(config.kROS['launch_cmd'],
133
- str(exp_template_path),
134
- run_num,
135
- config.kROS['launch_file_ext'])
136
-
137
- # --wait tells roslaunch to wait for the configured master to come up
138
- # before launch the "master" code.
139
- #
140
- # 2022/02/28: -p (apparently) tells roslaunch not to CONNECT to a master
141
- # at the specified ort, but to LAUNCH a new master at the specified
142
- # port. This is not really documented well.
143
-
144
- master_node = types.ShellCmdSpec(cmd=cmd, shell=True, wait=True)
145
-
146
- return [master_node]
147
-
148
- def _exec_run_cmds_slave(self,
149
- host: str,
150
- input_fpath: pathlib.Path,
151
- run_num: int) -> tp.List[types.ShellCmdSpec]:
152
-
153
- self.logger.debug("Generating exec cmds for run%s slaves: %d robots",
154
- run_num,
155
- self.n_robots)
156
-
157
- nodes = platform.ExecEnvChecker.parse_nodefile(self.cmdopts['nodefile'])
158
-
159
- if len(nodes) < self.n_robots:
160
- self.logger.critical(("Need %d hosts to correctly generate launch "
161
- "cmds for run%s with %d robots; %d available"),
162
- self.n_robots,
163
- run_num,
164
- self.n_robots,
165
- len(nodes))
166
-
167
- ret = [] # type: tp.List[types.ShellCmdSpec]
168
- for i in range(0, self.n_robots):
169
- # --wait tells roslaunch to wait for the configured master to
170
- # come up before launch the robot code.
171
- cmd = '{0} --wait {1}_robot{2}{3} '
172
- cmd = cmd.format(config.kROS['launch_cmd'],
173
- input_fpath,
174
- i,
175
- config.kROS['launch_file_ext'])
176
- ret.extend([types.ShellCmdSpec(cmd=cmd, shell=True, wait=True)])
177
- return ret
178
-
179
- def post_run_cmds(self, host: str) -> tp.List[types.ShellCmdSpec]:
180
- if host == 'master':
181
- return []
182
- else:
183
- return [
184
- types.ShellCmdSpec(
185
- # Can't use killall, because that returns non-zero if things
186
- # are cleaned up nicely.
187
- cmd='if pgrep roslaunch; then pkill roslaunch; fi;',
188
- shell=True,
189
- wait=True
190
- )
191
- ]
192
-
193
-
194
- @implements.implements(bindings.IExpShellCmdsGenerator)
195
- class ExpShellCmdsGenerator():
196
- def __init__(self,
197
- cmdopts: types.Cmdopts,
198
- exp_num: int) -> None:
199
- self.cmdopts = cmdopts
200
- self.exp_num = exp_num
201
- self.logger = logging.getLogger('platform.ros1robot')
202
-
203
- def pre_exp_cmds(self) -> tp.List[types.ShellCmdSpec]:
204
- local_ip = platform.get_local_ip()
205
- port = config.kROS['port_base'] + self.exp_num
206
- master_uri = f'http://{local_ip}:{port}'
207
-
208
- self.logger.info("Using ROS_MASTER_URI=%s", master_uri)
209
-
210
- return[
211
- types.ShellCmdSpec(
212
- # roscore will run on the SIERRA host machine.
213
- cmd=f'export ROS_MASTER_URI={master_uri}',
214
- shell=True,
215
- env=True,
216
- wait=True),
217
- types.ShellCmdSpec(
218
- # Each exppperiment gets their own roscore. Because each roscore
219
- # has a different port, this prevents any robots from
220
- # pre-emptively starting the next experiment before the rest of
221
- # the robots have finished the current one.
222
- cmd=f'roscore -p {port} & ',
223
- shell=True,
224
- wait=False)
225
- ]
226
-
227
- def exec_exp_cmds(self, exec_opts: types.StrDict) -> tp.List[types.ShellCmdSpec]:
228
- return []
229
-
230
- def post_exp_cmds(self) -> tp.List[types.ShellCmdSpec]:
231
- # Cleanup roscore processes on the SIERRA host machine which are still
232
- # active because they don't know how to clean up after themselves.
233
- return [types.ShellCmdSpec(cmd='killall rosmaster;',
234
- shell=True,
235
- wait=True),
236
- types.ShellCmdSpec(cmd='killall roscore;',
237
- shell=True,
238
- wait=True),
239
- types.ShellCmdSpec(cmd='killall rosout;',
240
- shell=True,
241
- wait=True)]
242
-
243
-
244
- @implements.implements(bindings.IExpConfigurer)
245
- class ExpConfigurer():
246
- def __init__(self, cmdopts: types.Cmdopts) -> None:
247
- self.cmdopts = cmdopts
248
- self.logger = logging.getLogger('platform.ros1robot')
249
-
250
- def cmdfile_paradigm(self) -> str:
251
- return 'per-run'
252
-
253
- def for_exp_run(self,
254
- exp_input_root: pathlib.Path,
255
- run_output_root: pathlib.Path) -> None:
256
- pass
257
-
258
- def for_exp(self, exp_input_root: pathlib.Path) -> None:
259
- if self.cmdopts['skip_sync']:
260
- self.logger.info("Skipping syncing experiment inputs -> robots")
261
- return
262
- else:
263
- self.logger.info("Syncing experiment inputs -> robots")
264
-
265
- checker = platform.ExecEnvChecker(self.cmdopts)
266
- nodes = checker.parse_nodefile(self.cmdopts['nodefile'])
267
-
268
- # Use parallel ssh, rsync to push each experiment to all robots in
269
- # parallel--takes O(M*N) operation and makes it O(N) more or less.
270
- pssh_base = 'parallel-ssh'
271
- prsync_base = 'parallel-rsync'
272
-
273
- for node in nodes:
274
- remote_login = node.login
275
- remote_port = node.port
276
- remote_hostname = node.hostname
277
- current_username = pwd.getpwuid(os.getuid())[0]
278
-
279
- if not self.cmdopts['skip_online_check']:
280
- checker.check_connectivity(remote_login,
281
- remote_hostname,
282
- remote_port,
283
- self.cmdopts['robot'])
284
-
285
- pssh_base += f' -H {remote_login}@{remote_hostname}:{remote_port}'
286
- prsync_base += f' -H {remote_login}@{remote_hostname}:{remote_port}'
287
-
288
- # In case the user is different on the remote machine than this one,
289
- # and the location of the generated experiment is under /home.
290
- robot_input_root = str(exp_input_root).replace(current_username,
291
- remote_login)
292
-
293
- mkdir_cmd = (f"{pssh_base} "
294
- f"-O StrictHostKeyChecking=no "
295
- f"mkdir -p {robot_input_root}")
296
-
297
- rsync_cmd = (f"{prsync_base} "
298
- f"-avz "
299
- f"-O StrictHostKeyChecking=no "
300
- f"{exp_input_root}/ "
301
- f"{robot_input_root}/")
302
- try:
303
- self.logger.trace("Running mkdir: %s", mkdir_cmd) # type: ignore
304
- res = subprocess.run(mkdir_cmd,
305
- shell=True,
306
- check=True,
307
- stdout=subprocess.PIPE,
308
- stderr=subprocess.PIPE)
309
- self.logger.trace("Running rsync: %s", rsync_cmd) # type: ignore
310
- res = subprocess.run(rsync_cmd,
311
- shell=True,
312
- check=True,
313
- stdout=subprocess.PIPE,
314
- stderr=subprocess.PIPE)
315
- except subprocess.CalledProcessError:
316
- self.logger.fatal("Unable to sync %s with %s: stdout=%s,stderr=%s",
317
- exp_input_root,
318
- robot_input_root,
319
- res.stdout.decode('utf-8'),
320
- res.stderr.decode('utf-8'))
321
- raise
322
-
323
-
324
- @ implements.implements(bindings.IExecEnvChecker)
325
- class ExecEnvChecker():
326
- def __init__(self, cmdopts: types.Cmdopts) -> None:
327
- pass
328
-
329
- def __call__(self) -> None:
330
- keys = ['ROS_DISTRO', 'ROS_VERSION']
331
-
332
- for k in keys:
333
- assert k in os.environ, \
334
- "Non-ROS1+robot environment detected: '{0}' not found".format(
335
- k)
336
-
337
- # Check ROS distro
338
- assert os.environ['ROS_DISTRO'] in ['kinetic', 'noetic'],\
339
- "SIERRA only supports ROS1 kinetic,noetic"
340
-
341
- # Check ROS version
342
- assert os.environ['ROS_VERSION'] == "1",\
343
- "Wrong ROS version: This plugin is for ROS1"
344
-
345
-
346
- def population_size_from_pickle(adds_def: tp.Union[xml.AttrChangeSet,
347
- xml.TagAddList],
348
- main_config: types.YAMLDict,
349
- cmdopts: types.Cmdopts) -> int:
350
- return ros1.callbacks.population_size_from_pickle(adds_def,
351
- main_config,
352
- cmdopts)
353
-
354
-
355
- def population_size_from_def(exp_def: definition.XMLExpDef,
356
- main_config: types.YAMLDict,
357
- cmdopts: types.Cmdopts) -> int:
358
- return ros1.callbacks.population_size_from_def(exp_def,
359
- main_config,
360
- cmdopts)
361
-
362
-
363
- def robot_prefix_extract(main_config: types.YAMLDict,
364
- cmdopts: types.Cmdopts) -> str:
365
- return ros1.callbacks.robot_prefix_extract(main_config, cmdopts)
366
-
367
-
368
- def pre_exp_diagnostics(cmdopts: types.Cmdopts,
369
- logger: logging.Logger) -> None:
370
- s = "batch_exp_root='%s',runs/exp=%s"
371
- logger.info(s,
372
- cmdopts['batch_root'],
373
- cmdopts['n_runs'])
@@ -1,10 +0,0 @@
1
- # Copyright 2021 John Harwell, All rights reserved.
2
- #
3
- # SPDX-License-Identifier: MIT
4
-
5
- # Core packages
6
-
7
- # 3rd party packages
8
-
9
- # Project packages
10
- from sierra.core.ros1.variables import exp_setup