autoverse-cli 0.28.1__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 (51) hide show
  1. autoverse_cli-0.28.1.dist-info/METADATA +91 -0
  2. autoverse_cli-0.28.1.dist-info/RECORD +51 -0
  3. autoverse_cli-0.28.1.dist-info/WHEEL +5 -0
  4. autoverse_cli-0.28.1.dist-info/entry_points.txt +2 -0
  5. autoverse_cli-0.28.1.dist-info/licenses/LICENSE +33 -0
  6. autoverse_cli-0.28.1.dist-info/top_level.txt +1 -0
  7. avrs/__init__.py +0 -0
  8. avrs/app_version.py +24 -0
  9. avrs/argparse_help.py +30 -0
  10. avrs/avrs.py +183 -0
  11. avrs/can_tool.py +192 -0
  12. avrs/can_tool_util.py +190 -0
  13. avrs/cfg.py +78 -0
  14. avrs/launcher.py +256 -0
  15. avrs/launcher_util.py +203 -0
  16. avrs/race_cloud.py +506 -0
  17. avrs/race_cloud_bridge_can.py +100 -0
  18. avrs/race_cloud_cfg_util.py +310 -0
  19. avrs/race_cloud_fwd_api.py +49 -0
  20. avrs/race_cloud_util.py +384 -0
  21. avrs/requests/change_camera.py +24 -0
  22. avrs/requests/code_booz.py +69 -0
  23. avrs/requests/demo.py +19 -0
  24. avrs/requests/dump_sim_config.py +14 -0
  25. avrs/requests/environment.py +46 -0
  26. avrs/requests/fault_injection.py +186 -0
  27. avrs/requests/get_object_config.py +18 -0
  28. avrs/requests/get_web_viz_meta.py +11 -0
  29. avrs/requests/leaderboard.py +74 -0
  30. avrs/requests/list_sim_objects.py +26 -0
  31. avrs/requests/log_path.py +28 -0
  32. avrs/requests/misc.py +70 -0
  33. avrs/requests/move_to_landmark.py +16 -0
  34. avrs/requests/npc.py +289 -0
  35. avrs/requests/race_control.py +48 -0
  36. avrs/requests/request.py +61 -0
  37. avrs/requests/reset_to_track.py +21 -0
  38. avrs/requests/rest_request.py +45 -0
  39. avrs/requests/restart.py +12 -0
  40. avrs/requests/scenario_control.py +43 -0
  41. avrs/requests/spawn_object.py +44 -0
  42. avrs/requests/teleport.py +40 -0
  43. avrs/requests/toggle_hud.py +11 -0
  44. avrs/requests/vd.py +64 -0
  45. avrs/requests/vehicle_input.py +21 -0
  46. avrs/requests/vehicle_replay.py +454 -0
  47. avrs/shell_completion.py +121 -0
  48. avrs/simconfig.py +75 -0
  49. avrs/simconfig_util.py +170 -0
  50. avrs/tests.py +9 -0
  51. avrs/util.py +13 -0
@@ -0,0 +1,310 @@
1
+ import os
2
+ import glob
3
+ import json
4
+ import base64
5
+ import logging
6
+ import datetime
7
+
8
+ from avrs.simconfig_util import *
9
+
10
+ # these corresond to what SimConfigFiles sets in its init
11
+ # and should autospawns configured
12
+ # todo: we could parse these from simconfig.json's environments
13
+ # inside SimConfigFiles instead of doing it manually
14
+ EXPECTED_ENV_NAMES = [
15
+ "yas",
16
+ "adrome",
17
+ "suzuka",
18
+ "yasnorth"
19
+ ]
20
+
21
+ def get_payload(cfg_object, payload_name):
22
+ for p in cfg_object['payloads']:
23
+ if p['typeName'].lower() == payload_name.lower():
24
+ return p
25
+ return None
26
+
27
+ def clear_autospawns():
28
+ logger = logging.getLogger('avrs')
29
+ sim_path = os.environ.get('AVRS_INSTALL_PATH',
30
+ os.path.join(os.environ['HOME'], 'autoverse-linux'))
31
+ sim_saved = os.path.join(sim_path, 'Linux', 'Autoverse', 'Saved')
32
+ logger.info('clearing autospawns from sim saved at {}'.format(sim_saved))
33
+
34
+ cfg_files = SimConfigFiles(sim_saved)
35
+
36
+ cfg_ok, msg = cfg_files.validate()
37
+ if not cfg_ok:
38
+ logger.error(msg)
39
+ return
40
+
41
+ # also remove all configs from Objects dir
42
+ files = glob.glob(os.path.join(sim_saved, 'Objects/*'))
43
+ for f in files:
44
+ # do not remove default !!
45
+ if 'Eav24_default' in f:
46
+ logger.info('not removing {} because it is the default'.format(f))
47
+ else:
48
+ logger.info('removing object config: {}'.format(f))
49
+ os.remove(f)
50
+
51
+
52
+ for ee in EXPECTED_ENV_NAMES:
53
+ cfg_files.files[ee]['autoSpawnObjects'] = []
54
+
55
+ # keep the default!
56
+ cfg_files.files['main']['objectTemplatePaths'] = ['Objects/Eav24_default.json']
57
+
58
+ # we want splitscreen in cloud
59
+ cfg_files.files['main']['bEnableSplitscreen'] = True
60
+
61
+ cfg_files.save()
62
+
63
+ def register_received_vehicle(team_name, slot, cfg_data, bsu_vcan, kistler_vcan, badenia_vcan):
64
+ logger = logging.getLogger('avrs')
65
+ logger.info('registering received vehicle in slot {} for team {}'.format(slot, team_name))
66
+
67
+ cfg_string = base64.b64decode(cfg_data)
68
+ cfg_object = json.loads(cfg_string.decode('utf-8'))
69
+
70
+ # ensure replay for recording is enabled
71
+ logger.info('ensuring replay component is enabled')
72
+ replay = get_payload(cfg_object, 'WheeledVehicleReplayIpd')
73
+ replay['bEnabled'] = True
74
+ replay['body']['bEnableRecording'] = True
75
+
76
+ # ensure perception is disabled
77
+ eav24 = get_payload(cfg_object, 'Eav24Initializer')
78
+ if eav24 is None:
79
+ return (False, 'no eav24 payload found')
80
+
81
+ logger.info('disabling perception for received vehicle config')
82
+ eav24['body']['bLidarEnabled'] = False
83
+ eav24['body']['bCameraEnabled'] = False
84
+ eav24['body']['bRadarEnabled'] = False
85
+ eav24['body']['bPublishGroundTruth'] = False
86
+ eav24['body']['bPublishInputs'] = False
87
+ eav24['body']['bRenderHudInWorld'] = True
88
+
89
+ # do not disable HUD
90
+ #logger.info('disabling hud for received vehicle config')
91
+ eav24['body']['bHudEnabled'] = True
92
+
93
+ logger.info('setting primary vcan to: {}, secondary to: {}, and <unused> to: {}'.format(
94
+ bsu_vcan, kistler_vcan, badenia_vcan))
95
+ eav24['body']['primaryCanName'] = bsu_vcan
96
+ eav24['body']['secondaryCanName'] = kistler_vcan
97
+
98
+ eav24['body']['badeniaCanName'] = badenia_vcan
99
+
100
+ # limit can rates to conserve resources
101
+
102
+ if eav24["body"]["canReceiveRate"] > 10000:
103
+ logger.info("can rx was > 10000. clamping")
104
+ eav24["body"]["canReceiveRate"] = 10000
105
+
106
+ if eav24["body"]["canLowSendRate"] > 10:
107
+ logger.info("can tx low was > 10. clamping")
108
+ eav24["body"]["canLowSendRate"] = 10
109
+
110
+ if eav24["body"]["canMedSendRate"] > 100:
111
+ logger.info("can tx med was > 100. clamping")
112
+ eav24["body"]["canMedSendRate"] = 100
113
+
114
+ if eav24["body"]["canHighSendRate"] > 500:
115
+ logger.info("can tx high was > 500. clamping")
116
+ eav24["body"]["canHighSendRate"] = 500
117
+
118
+ # clamp vectornav rates
119
+
120
+ vn = get_payload(cfg_object, "VectornavIpd")
121
+ if vn.get("body", {}).get("sensorDesc", {}).get("namedDataStreams", {}).get("CommonGroup", {}).get("rateHz", 0) > 100:
122
+ logger.info("vn CommonGroup rate was > 100. clamping")
123
+ vn["body"]["sensorDesc"]["namedDataStreams"]["CommonGroup"]["rateHz"] = 100
124
+
125
+ if vn.get("body", {}).get("sensorDesc", {}).get("namedDataStreams", {}).get("GpsGroup", {}).get("rateHz", 0) > 10:
126
+ logger.info("vn GpsGroup rate was > 10. clamping")
127
+ vn["body"]["sensorDesc"]["namedDataStreams"]["GpsGroup"]["rateHz"] = 10
128
+
129
+ if vn.get("body", {}).get("sensorDesc", {}).get("namedDataStreams", {}).get("Gps2Group", {}).get("rateHz", 0) > 10:
130
+ logger.info("vn Gps2Group rate was > 10. clamping")
131
+ vn["body"]["sensorDesc"]["namedDataStreams"]["Gps2Group"]["rateHz"] = 10
132
+
133
+ if vn.get("body", {}).get("sensorDesc", {}).get("namedDataStreams", {}).get("ImuGroup", {}).get("rateHz", 0) > 150:
134
+ logger.info("vn ImuGroup rate was > 150. clamping")
135
+ vn["body"]["sensorDesc"]["namedDataStreams"]["ImuGroup"]["rateHz"] = 150
136
+
137
+ if vn.get("body", {}).get("sensorDesc", {}).get("namedDataStreams", {}).get("AttitudeGroup", {}).get("rateHz", 0) > 100:
138
+ logger.info("vn AttitudeGroup rate was > 100. clamping")
139
+ vn["body"]["sensorDesc"]["namedDataStreams"]["AttitudeGroup"]["rateHz"] = 100
140
+
141
+ if vn.get("body", {}).get("sensorDesc", {}).get("namedDataStreams", {}).get("Tii", {}).get("rateHz", 0) > 100:
142
+ logger.info("vn Tii rate was > 100. clamping")
143
+ vn["body"]["sensorDesc"]["namedDataStreams"]["Tii"]["rateHz"] = 100
144
+
145
+ if vn.get("body", {}).get("sensorDesc", {}).get("namedDataStreams", {}).get("NavSatFix", {}).get("rateHz", 0) > 10:
146
+ logger.info("vn NavSatFix rate was > 10. clamping")
147
+ vn["body"]["sensorDesc"]["namedDataStreams"]["NavSatFix"]["rateHz"] = 10
148
+
149
+ ros2 = get_payload(cfg_object, 'Ros2')
150
+ if ros2 is None:
151
+ logger.info('no ros2 payload found. adding with domain id {}'.format(slot))
152
+ # need to add a ros2 payload for domain id
153
+ cfg_object['payloads'].append({
154
+ 'typeName': 'Ros2',
155
+ 'body': {
156
+ 'domainId': slot
157
+ }
158
+ })
159
+ else:
160
+ logger.info('found Ros2 payload OK'.format())
161
+ logger.info('setting ros2 domain id to {}'.format(slot))
162
+ ros2['body']['domainId'] = slot
163
+
164
+ # auto add display widget
165
+ wtc = get_payload(cfg_object, 'WorldTextComponent')
166
+ if wtc is None:
167
+ logger.info('no WorldTextComponent payload found. adding')
168
+ cfg_object['payloads'].append({
169
+ 'typeName': 'WorldTextComponent',
170
+ 'body': {
171
+
172
+ }
173
+ })
174
+ else:
175
+ logger.info('found WorldTextComponent payload. ensuring it is enabled')
176
+ wtc['bEnabled'] = True
177
+
178
+ # auto add / enable ground truth payload
179
+ gtc = get_payload(cfg_object, 'GroundTruthSensor')
180
+ if gtc is None:
181
+ logger.info('no GroundTruthSensor payload found. adding')
182
+ cfg_object['payloads'].append({
183
+ 'typeName': 'GroundTruthSensor',
184
+ 'body': {
185
+ 'myGroundTruthDsd': {
186
+ 'streamName': 'ground_truth',
187
+ 'rateHz': 50.0
188
+ },
189
+ 'opponentGroundTruthDsd': {
190
+ 'streamName': 'v2v_ground_truth',
191
+ 'rateHz': 50.0
192
+ },
193
+ 'bUseOpponentRelativeRotation': False
194
+ }
195
+ })
196
+ else:
197
+ logger.info('found GroundTruthSensor payload. ensuring it is enabled')
198
+ gtc['bEnabled'] = True
199
+
200
+ # limit gt rates
201
+
202
+ gtc = get_payload(cfg_object, 'GroundTruthSensor')
203
+ if gtc["body"]["myGroundTruthDsd"]["rateHz"] > 100:
204
+ logger.info("myGroundTruthDsd rate was > 100. clamping")
205
+ gtc["body"]["myGroundTruthDsd"]["rateHz"] = 100
206
+
207
+ if gtc["body"]["opponentGroundTruthDsd"]["rateHz"] > 100:
208
+ logger.info("opponentGroundTruthDsd rate was > 100. clamping")
209
+ gtc["body"]["opponentGroundTruthDsd"]["rateHz"] = 100
210
+
211
+
212
+ # do not allow default object name (collision)
213
+ if cfg_object['name'] == 'eav24':
214
+ logger.info('setting vehicle name from default to team name: {}'.format(team_name))
215
+ cfg_object['name'] = team_name
216
+ object_spec_name = 'eav24_{}'.format(team_name)
217
+ cfg_object['specName'] = object_spec_name
218
+
219
+ # also need to edit the yas_marina_env.json to have autospawn for this config
220
+ sim_path = os.environ.get('AVRS_INSTALL_PATH',
221
+ os.path.join(os.environ['HOME'], 'autoverse-linux'))
222
+ sim_saved = os.path.join(sim_path, 'Linux', 'Autoverse', 'Saved')
223
+ cfg_files = SimConfigFiles(sim_saved)
224
+
225
+ cfg_ok, msg = cfg_files.validate()
226
+ if not cfg_ok:
227
+ print(msg)
228
+ return
229
+
230
+ start_landmark = 'PitsSlot{}'.format(slot + 1)
231
+
232
+ for ee in EXPECTED_ENV_NAMES:
233
+ entry_exists = False
234
+
235
+ # we want logging on for all environments
236
+ cfg_files.files[ee]['bAutoRecordVehicles'] = True
237
+
238
+ for i in cfg_files.files[ee]['autoSpawnObjects']:
239
+ if 'objectSpec' in i and i['objectSpec'] == cfg_object['specName']:
240
+ entry_exists = True
241
+ logger.info('config is already in auto spawn list')
242
+
243
+ if not entry_exists:
244
+ logger.info('config is not in auto spawn list. adding')
245
+ cfg_files.files[ee]['autoSpawnObjects'].append({
246
+ 'bShouldSpawn': True,
247
+ 'objectType': 'Eav24',
248
+ 'objectSpec': cfg_object['specName'],
249
+ 'bSpawnAtLandmark': True,
250
+ 'spawnLandmarkName': start_landmark
251
+ })
252
+
253
+ # also need to add the object template to main sim config
254
+
255
+ new_cfg_name = 'eav24_{}.json'.format(object_spec_name)
256
+ cfg_files.files['main']['objectTemplatePaths'].append(os.path.join('Objects', new_cfg_name))
257
+ logger.info('saving config file: {}'.format(new_cfg_name))
258
+ cfg_files.save()
259
+
260
+ target_path = os.path.join(sim_saved, 'Objects', new_cfg_name)
261
+ with open(target_path, 'w', encoding='utf-8') as f:
262
+ json.dump(cfg_object, f, ensure_ascii=False, indent=4)
263
+ backup_path = os.path.join(os.environ['HOME'], 'team_configs')
264
+ if not os.path.exists(backup_path):
265
+ os.mkdir(backup_path)
266
+ date_time = datetime.datetime.now(datetime.timezone.utc).strftime("%Y_%m_%d_%H_%M_%S")
267
+ backup_path = os.path.join(backup_path, '{}_{}'.format(date_time,new_cfg_name))
268
+ with open(backup_path, 'w', encoding='utf-8') as f:
269
+ json.dump(cfg_object, f, ensure_ascii=False, indent=4)
270
+
271
+ def prepare_vehicle_cfg(cfg_path):
272
+ logger = logging.getLogger('avrs')
273
+ #print('preparing config for transmission: {}'.format(cfg_path))
274
+
275
+ if not os.path.isfile(cfg_path):
276
+ return (False, '{} is not a valid file'.format(cfg_path), None, None, None)
277
+
278
+ cfg_object = {}
279
+ with open(cfg_path, 'r', encoding='utf-8') as f:
280
+ cfg_object = json.load(f)
281
+
282
+
283
+ # obtain desired CAN names to start cannelloni
284
+ eav24 = get_payload(cfg_object, 'Eav24Initializer')
285
+ if eav24 is None:
286
+ return (False, 'no eav24 payload found', None, None, None)
287
+
288
+
289
+
290
+ bsu_vcan = eav24['body'].get('primaryCanName', '')
291
+ if bsu_vcan == '':
292
+ logger.info('primaryCanName key not found, trying old bsuCanName')
293
+ bsu_vcan = eav24['body'].get('bsuCanName', '')
294
+ kistler_vcan = eav24['body'].get('secondaryCanName', '')
295
+ if kistler_vcan == '':
296
+ logger.info('secondaryCanName key not found, trying old kistlerCanName')
297
+ kistler_vcan = eav24['body'].get('kistlerCanName', '')
298
+ badenia_vcan = 'unused'
299
+
300
+ if bsu_vcan == '':
301
+ logger.error('could not find either primaryCanName or bsuCanName')
302
+ if kistler_vcan == '':
303
+ logger.error('could not find either secondaryCanName or kistlerCanName')
304
+
305
+ logger.info('detected vcan names from sent config: bsu {}, kistler {}, badenia {}'.format(
306
+ bsu_vcan, kistler_vcan, badenia_vcan))
307
+
308
+ cfg_data = base64.b64encode(json.dumps(cfg_object).encode('utf-8')).decode('utf-8')
309
+ return (True, cfg_data, bsu_vcan, kistler_vcan, badenia_vcan)
310
+
@@ -0,0 +1,49 @@
1
+ import argparse
2
+ import json
3
+ import re
4
+ import threading
5
+ import http
6
+ from http import HTTPStatus
7
+ from http.server import BaseHTTPRequestHandler, HTTPServer
8
+
9
+ # https://gist.github.com/dfrankow/f91aefd683ece8e696c26e183d696c29
10
+
11
+ class ApiForwardHandler(BaseHTTPRequestHandler):
12
+ def __init__(self, target_port):
13
+ self.target_port = target_port
14
+
15
+ # allows to be passed to the HTTPServer ctor
16
+ def __call__(self, *args, **kwargs):
17
+ """Handle a request."""
18
+ super().__init__(*args, **kwargs)
19
+
20
+ def do_POST(self):
21
+
22
+ length = int(self.headers.get('content-length'))
23
+ rfile_str = self.rfile.read(length).decode('utf8')
24
+ sim_response = self.get_fwd_response(rfile_str)
25
+ try:
26
+ print("{} : {}".format(self.client_address, rfile_str))
27
+ except:
28
+ pass
29
+ self.send_response(HTTPStatus.OK)
30
+ self.send_header("Content-Type", "application/json")
31
+ self.end_headers()
32
+ self.wfile.write(sim_response.encode('utf-8'))
33
+ self.end_headers()
34
+
35
+ def get_fwd_response(self, body):
36
+ connection = http.client.HTTPConnection('localhost', self.target_port, timeout=3)
37
+ headers = {
38
+ 'Content-type': 'application/json',
39
+ }
40
+ #body = json.dumps(body).encode('utf-8') # already a string here
41
+ connection.request('POST', '/post', body, headers)
42
+ response = connection.getresponse()
43
+ response_string = ''
44
+ if response.status != 200:
45
+ pass
46
+ else:
47
+ response_string = response.read().decode('utf-8')
48
+ return response_string
49
+