lookout-config 1.15.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.
@@ -0,0 +1,74 @@
1
+ # IMPORTANT
2
+ # After changing this file, run `python3 -m lookout_config.generate_schemas`
3
+ # To re-generate the json schemas
4
+ import yaml
5
+ import os
6
+ from typing import Any
7
+ from pathlib import Path
8
+
9
+ from lookout_config.types import (
10
+ LookoutConfig,
11
+ Mode,
12
+ LogLevel,
13
+ Network,
14
+ GeolocationMode,
15
+ Point,
16
+ Polygon,
17
+ CameraExtended,
18
+ PositioningSystem,
19
+ )
20
+ from lookout_config.helpers import YamlDumper
21
+
22
+
23
+ LOOKOUT_CONFIG_FILE_NAME = "lookout.yml"
24
+ LOOKOUT_SCHEMA_URL = "https://greenroom-robotics.github.io/lookout/schemas/lookout.schema.json"
25
+
26
+
27
+ def find_config() -> Path:
28
+ """Returns the path to the .config/greenroom directory"""
29
+ return Path.home().joinpath(".config/greenroom")
30
+
31
+
32
+ def get_path():
33
+ return find_config() / LOOKOUT_CONFIG_FILE_NAME
34
+
35
+
36
+ def parse(config: dict[str, Any]) -> LookoutConfig:
37
+ return LookoutConfig(**config or {})
38
+
39
+
40
+ def read() -> LookoutConfig:
41
+ path = get_path()
42
+ with open(path) as stream:
43
+ return parse(yaml.safe_load(stream))
44
+
45
+
46
+ def write(config: LookoutConfig):
47
+ path = get_path()
48
+ # Make the parent dir if it doesn't exist
49
+ os.makedirs(path.parent, exist_ok=True)
50
+ json_string = config.model_dump(mode="json")
51
+ with open(path, "w") as stream:
52
+ print(f"Writing: {path}")
53
+ headers = f"# yaml-language-server: $schema={LOOKOUT_SCHEMA_URL}"
54
+ data = "\n".join([headers, yaml.dump(json_string, Dumper=YamlDumper, sort_keys=True)])
55
+ stream.write(data)
56
+
57
+
58
+ __all__ = [
59
+ "find_config",
60
+ "get_path",
61
+ "parse",
62
+ "read",
63
+ "write",
64
+ "LOOKOUT_SCHEMA_URL",
65
+ "LookoutConfig",
66
+ "Mode",
67
+ "LogLevel",
68
+ "Network",
69
+ "GeolocationMode",
70
+ "Point",
71
+ "Polygon",
72
+ "CameraExtended",
73
+ "PositioningSystem",
74
+ ]
@@ -0,0 +1,16 @@
1
+ import os
2
+ from pathlib import Path
3
+ import json
4
+ from lookout_config import LookoutConfig
5
+
6
+
7
+ def generate_schemas():
8
+ """Generates the schemas for the config files"""
9
+ SCHEMAS_PATH = Path(os.path.dirname(__file__)) / "schemas"
10
+ with open(SCHEMAS_PATH / "lookout.schema.json", "w") as f:
11
+ main_model_schema = LookoutConfig.model_json_schema()
12
+ json.dump(main_model_schema, f, indent=2)
13
+
14
+
15
+ if __name__ == "__main__":
16
+ generate_schemas()
@@ -0,0 +1,83 @@
1
+ from lookout_config import LookoutConfig
2
+ from greenstream_config import Offsets, get_cameras_urdf
3
+ from gr_urchin import URDF, Joint, Material, Link, xyz_rpy_to_matrix, Visual, Mesh, Geometry, Box
4
+ from math import radians
5
+
6
+
7
+ def joint_from_offsets(offsets: Offsets, parent: str, child: str) -> Joint:
8
+ return Joint(
9
+ name=f"{parent}_to_{child}",
10
+ parent=parent,
11
+ child=child,
12
+ joint_type="fixed",
13
+ origin=xyz_rpy_to_matrix(
14
+ [
15
+ offsets.forward or 0.0,
16
+ offsets.left or 0.0,
17
+ offsets.up or 0.0,
18
+ offsets.roll or 0.0,
19
+ offsets.pitch or 0.0,
20
+ offsets.yaw or 0.0,
21
+ ]
22
+ ),
23
+ )
24
+
25
+
26
+ def generate_urdf(
27
+ config: LookoutConfig,
28
+ add_optical_frame: bool = True,
29
+ ):
30
+ mesh_path = f"package://lookout_bringup/meshes/{config.offsets.name}"
31
+ file_path = f"/tmp/vessel_{config.mode.value}.urdf"
32
+ camera_links, camera_joints = get_cameras_urdf(config.cameras, add_optical_frame) # type: ignore
33
+
34
+ urdf = URDF(
35
+ name="origins",
36
+ materials=[
37
+ Material(name="grey", color=[0.75, 0.75, 0.75, 0.6]),
38
+ Material(name="blue", color=[0, 0.12, 0.25, 0.9]),
39
+ ],
40
+ links=[
41
+ Link(name="ins", inertial=None, visuals=None, collisions=None),
42
+ Link(
43
+ name="waterline",
44
+ visuals=[
45
+ Visual(
46
+ name="waterline",
47
+ geometry=Geometry(box=Box([10.0, 10.0, 0.01])),
48
+ material=Material(name="blue"),
49
+ )
50
+ ],
51
+ inertial=None,
52
+ collisions=None,
53
+ ),
54
+ Link(
55
+ name="base_link",
56
+ visuals=[
57
+ Visual(
58
+ name="visual",
59
+ geometry=Geometry(
60
+ mesh=Mesh(filename=mesh_path, combine=False, lazy_filename=mesh_path)
61
+ ),
62
+ origin=xyz_rpy_to_matrix([0, 0, 0, radians(-90), 0, 0]),
63
+ material=Material(name="grey"),
64
+ ),
65
+ ],
66
+ inertial=None,
67
+ collisions=None,
68
+ ),
69
+ *camera_links,
70
+ ],
71
+ joints=[
72
+ joint_from_offsets(config.offsets.baselink_to_ins, "base_link", "ins"),
73
+ joint_from_offsets(config.offsets.baselink_to_waterline, "base_link", "waterline"),
74
+ *camera_joints,
75
+ ],
76
+ )
77
+
78
+ urdf.save(file_path)
79
+
80
+ with open(file_path) as infp:
81
+ robot_description = infp.read()
82
+
83
+ return robot_description
@@ -0,0 +1,18 @@
1
+ import yaml
2
+
3
+
4
+ class YamlDumper(yaml.Dumper):
5
+ """
6
+ A YAML dumpler that show lists on the same line if they do not contain dicts or list
7
+ """
8
+
9
+ def represent_sequence(self, tag, sequence, flow_style=None):
10
+ if isinstance(sequence, list) and all(
11
+ [not isinstance(item, (dict, list)) for item in sequence]
12
+ ):
13
+ flow_style = True
14
+ return super().represent_sequence(tag, sequence, flow_style)
15
+
16
+ def represent_mapping(self, tag, mapping, flow_style=None):
17
+ flow_style = False
18
+ return super().represent_mapping(tag, mapping, flow_style)
@@ -0,0 +1,69 @@
1
+ # Generated by 'python3 -m parameter_persistence.generate_models'
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import List, Optional
6
+
7
+ from pydantic import BaseModel, Field
8
+
9
+
10
+ class WebBridgeParameters(BaseModel):
11
+ address: Optional[str] = Field(
12
+ None, description="The host address to bind the WebSocket server to"
13
+ )
14
+ asset_uri_allowlist: Optional[List[str]] = Field(
15
+ None,
16
+ description="List of regular expressions (ECMAScript) of whitelisted parameter names.",
17
+ )
18
+ capabilities: Optional[List[str]] = Field(None, description="Server capabilities")
19
+ certfile: Optional[str] = Field(None, description="Path to the certificate to use for TLS")
20
+ client_topic_whitelist: Optional[List[str]] = Field(
21
+ None,
22
+ description="List of regular expressions (ECMAScript) of whitelisted parameter names.",
23
+ )
24
+ disable_load_message: Optional[bool] = Field(
25
+ None,
26
+ description="Do not publish as loaned message when publishing a client message",
27
+ )
28
+ include_hidden: Optional[bool] = Field(None, description="Include hidden topics and services")
29
+ keyfile: Optional[str] = Field(None, description="Path to the private key to use for TLS")
30
+ max_qos_depth: Optional[int] = Field(
31
+ None, description="Maximum depth used for the QoS profile of subscriptions."
32
+ )
33
+ min_qos_depth: Optional[int] = Field(
34
+ None, description="Minimum depth used for the QoS profile of subscriptions."
35
+ )
36
+ param_whitelist: Optional[List[str]] = Field(
37
+ None,
38
+ description="List of regular expressions (ECMAScript) of whitelisted parameter names.",
39
+ )
40
+ port: Optional[int] = Field(None, description="The TCP port to bind the WebSocket server to")
41
+ send_buffer_limit: Optional[int] = Field(
42
+ None,
43
+ description="Connection send buffer limit in bytes. Messages will be dropped when a connection's send buffer reaches this limit to avoid a queue of outdated messages building up.",
44
+ )
45
+ service_whitelist: Optional[List[str]] = Field(
46
+ None,
47
+ description="List of regular expressions (ECMAScript) of whitelisted service names.",
48
+ )
49
+ tls: Optional[bool] = Field(
50
+ None, description="Use Transport Layer Security for encrypted communication"
51
+ )
52
+ topic_whitelist: Optional[List[str]] = Field(
53
+ None,
54
+ description="List of regular expressions (ECMAScript) of whitelisted topic names.",
55
+ )
56
+ use_compression: Optional[bool] = Field(
57
+ None,
58
+ description="Use websocket compression (permessage-deflate). Suited for connections with smaller bandwidth, at the cost of additional CPU load.",
59
+ )
60
+
61
+
62
+ class LookoutGreenstreamBringupParameters(BaseModel):
63
+ launch_package: Optional[str] = Field(None, description="")
64
+ launch_executable: Optional[str] = Field(None, description="")
65
+
66
+
67
+ class LaunchParameters(BaseModel):
68
+ web_bridge: Optional[WebBridgeParameters] = None
69
+ lookout_greenstream_bringup: Optional[LookoutGreenstreamBringupParameters] = None
@@ -0,0 +1,445 @@
1
+ {
2
+ "$defs": {
3
+ "CameraExtended": {
4
+ "properties": {
5
+ "name": {
6
+ "title": "Name",
7
+ "type": "string"
8
+ },
9
+ "order": {
10
+ "title": "Order",
11
+ "type": "integer"
12
+ },
13
+ "type": {
14
+ "default": "color",
15
+ "title": "Type",
16
+ "type": "string"
17
+ },
18
+ "ptz": {
19
+ "default": false,
20
+ "title": "Ptz",
21
+ "type": "boolean"
22
+ },
23
+ "camera_offsets": {
24
+ "anyOf": [
25
+ {
26
+ "$ref": "#/$defs/Offsets"
27
+ },
28
+ {
29
+ "type": "null"
30
+ }
31
+ ],
32
+ "default": null
33
+ },
34
+ "ptz_offsets": {
35
+ "default": [],
36
+ "items": {
37
+ "$ref": "#/$defs/PTZOffsets"
38
+ },
39
+ "title": "Ptz Offsets",
40
+ "type": "array"
41
+ },
42
+ "ignore_regions": {
43
+ "items": {
44
+ "$ref": "#/$defs/Polygon"
45
+ },
46
+ "title": "Ignore Regions",
47
+ "type": "array"
48
+ }
49
+ },
50
+ "required": [
51
+ "name",
52
+ "order"
53
+ ],
54
+ "title": "CameraExtended",
55
+ "type": "object"
56
+ },
57
+ "GeolocationMode": {
58
+ "enum": [
59
+ "none",
60
+ "relative_bearing",
61
+ "absolute_bearing",
62
+ "range_bearing"
63
+ ],
64
+ "title": "GeolocationMode",
65
+ "type": "string"
66
+ },
67
+ "LogLevel": {
68
+ "enum": [
69
+ "info",
70
+ "debug"
71
+ ],
72
+ "title": "LogLevel",
73
+ "type": "string"
74
+ },
75
+ "Mode": {
76
+ "enum": [
77
+ "simulator",
78
+ "hardware",
79
+ "stubs",
80
+ "rosbag"
81
+ ],
82
+ "title": "Mode",
83
+ "type": "string"
84
+ },
85
+ "Network": {
86
+ "enum": [
87
+ "shared",
88
+ "host"
89
+ ],
90
+ "title": "Network",
91
+ "type": "string"
92
+ },
93
+ "Offsets": {
94
+ "properties": {
95
+ "roll": {
96
+ "anyOf": [
97
+ {
98
+ "type": "number"
99
+ },
100
+ {
101
+ "type": "null"
102
+ }
103
+ ],
104
+ "default": null,
105
+ "title": "Roll"
106
+ },
107
+ "pitch": {
108
+ "anyOf": [
109
+ {
110
+ "type": "number"
111
+ },
112
+ {
113
+ "type": "null"
114
+ }
115
+ ],
116
+ "default": null,
117
+ "title": "Pitch"
118
+ },
119
+ "yaw": {
120
+ "anyOf": [
121
+ {
122
+ "type": "number"
123
+ },
124
+ {
125
+ "type": "null"
126
+ }
127
+ ],
128
+ "default": null,
129
+ "title": "Yaw"
130
+ },
131
+ "forward": {
132
+ "anyOf": [
133
+ {
134
+ "type": "number"
135
+ },
136
+ {
137
+ "type": "null"
138
+ }
139
+ ],
140
+ "default": null,
141
+ "title": "Forward"
142
+ },
143
+ "left": {
144
+ "anyOf": [
145
+ {
146
+ "type": "number"
147
+ },
148
+ {
149
+ "type": "null"
150
+ }
151
+ ],
152
+ "default": null,
153
+ "title": "Left"
154
+ },
155
+ "up": {
156
+ "anyOf": [
157
+ {
158
+ "type": "number"
159
+ },
160
+ {
161
+ "type": "null"
162
+ }
163
+ ],
164
+ "default": null,
165
+ "title": "Up"
166
+ }
167
+ },
168
+ "title": "Offsets",
169
+ "type": "object"
170
+ },
171
+ "PTZOffsets": {
172
+ "properties": {
173
+ "roll": {
174
+ "anyOf": [
175
+ {
176
+ "type": "number"
177
+ },
178
+ {
179
+ "type": "null"
180
+ }
181
+ ],
182
+ "default": null,
183
+ "title": "Roll"
184
+ },
185
+ "pitch": {
186
+ "anyOf": [
187
+ {
188
+ "type": "number"
189
+ },
190
+ {
191
+ "type": "null"
192
+ }
193
+ ],
194
+ "default": null,
195
+ "title": "Pitch"
196
+ },
197
+ "yaw": {
198
+ "anyOf": [
199
+ {
200
+ "type": "number"
201
+ },
202
+ {
203
+ "type": "null"
204
+ }
205
+ ],
206
+ "default": null,
207
+ "title": "Yaw"
208
+ },
209
+ "forward": {
210
+ "anyOf": [
211
+ {
212
+ "type": "number"
213
+ },
214
+ {
215
+ "type": "null"
216
+ }
217
+ ],
218
+ "default": null,
219
+ "title": "Forward"
220
+ },
221
+ "left": {
222
+ "anyOf": [
223
+ {
224
+ "type": "number"
225
+ },
226
+ {
227
+ "type": "null"
228
+ }
229
+ ],
230
+ "default": null,
231
+ "title": "Left"
232
+ },
233
+ "up": {
234
+ "anyOf": [
235
+ {
236
+ "type": "number"
237
+ },
238
+ {
239
+ "type": "null"
240
+ }
241
+ ],
242
+ "default": null,
243
+ "title": "Up"
244
+ },
245
+ "type": {
246
+ "enum": [
247
+ "pan",
248
+ "tilt"
249
+ ],
250
+ "title": "Type",
251
+ "type": "string"
252
+ }
253
+ },
254
+ "required": [
255
+ "type"
256
+ ],
257
+ "title": "PTZOffsets",
258
+ "type": "object"
259
+ },
260
+ "Point": {
261
+ "properties": {
262
+ "x": {
263
+ "title": "X",
264
+ "type": "integer"
265
+ },
266
+ "y": {
267
+ "title": "Y",
268
+ "type": "integer"
269
+ }
270
+ },
271
+ "required": [
272
+ "x",
273
+ "y"
274
+ ],
275
+ "title": "Point",
276
+ "type": "object"
277
+ },
278
+ "Polygon": {
279
+ "properties": {
280
+ "points": {
281
+ "items": {
282
+ "$ref": "#/$defs/Point"
283
+ },
284
+ "title": "Points",
285
+ "type": "array"
286
+ }
287
+ },
288
+ "required": [
289
+ "points"
290
+ ],
291
+ "title": "Polygon",
292
+ "type": "object"
293
+ },
294
+ "PositioningSystem": {
295
+ "enum": [
296
+ "none",
297
+ "septentrio_ins",
298
+ "advanced_navigation_ins",
299
+ "nmea_2000_sat_compass",
300
+ "nmea_2000_compass",
301
+ "nmea_0183_sat_compass",
302
+ "nmea_0183_compass"
303
+ ],
304
+ "title": "PositioningSystem",
305
+ "type": "string"
306
+ },
307
+ "VesselOffsets": {
308
+ "properties": {
309
+ "name": {
310
+ "title": "Name",
311
+ "type": "string"
312
+ },
313
+ "baselink_to_ins": {
314
+ "$ref": "#/$defs/Offsets"
315
+ },
316
+ "baselink_to_waterline": {
317
+ "$ref": "#/$defs/Offsets"
318
+ }
319
+ },
320
+ "required": [
321
+ "name",
322
+ "baselink_to_ins",
323
+ "baselink_to_waterline"
324
+ ],
325
+ "title": "VesselOffsets",
326
+ "type": "object"
327
+ }
328
+ },
329
+ "properties": {
330
+ "ros_domain_id": {
331
+ "default": 0,
332
+ "description": "ROS domain ID for the vessel. This only applies if 'simple_discovery' is true.",
333
+ "title": "Ros Domain Id",
334
+ "type": "integer"
335
+ },
336
+ "namespace_vessel": {
337
+ "default": "vessel_1",
338
+ "title": "Namespace Vessel",
339
+ "type": "string"
340
+ },
341
+ "gama_vessel": {
342
+ "default": false,
343
+ "title": "Gama Vessel",
344
+ "type": "boolean"
345
+ },
346
+ "mode": {
347
+ "$ref": "#/$defs/Mode",
348
+ "default": "hardware"
349
+ },
350
+ "log_level": {
351
+ "$ref": "#/$defs/LogLevel",
352
+ "default": "info"
353
+ },
354
+ "cameras": {
355
+ "items": {
356
+ "$ref": "#/$defs/CameraExtended"
357
+ },
358
+ "title": "Cameras",
359
+ "type": "array"
360
+ },
361
+ "network": {
362
+ "$ref": "#/$defs/Network",
363
+ "default": "host"
364
+ },
365
+ "gpu": {
366
+ "default": true,
367
+ "title": "Gpu",
368
+ "type": "boolean"
369
+ },
370
+ "geolocation_mode": {
371
+ "$ref": "#/$defs/GeolocationMode",
372
+ "default": "none"
373
+ },
374
+ "positioning_system": {
375
+ "$ref": "#/$defs/PositioningSystem",
376
+ "default": "none"
377
+ },
378
+ "offsets": {
379
+ "$ref": "#/$defs/VesselOffsets",
380
+ "default": {
381
+ "name": "mars.stl",
382
+ "baselink_to_ins": {
383
+ "forward": 1.416,
384
+ "left": 0.153,
385
+ "pitch": null,
386
+ "roll": null,
387
+ "up": 0.184,
388
+ "yaw": null
389
+ },
390
+ "baselink_to_waterline": {
391
+ "forward": null,
392
+ "left": null,
393
+ "pitch": null,
394
+ "roll": null,
395
+ "up": 0.3,
396
+ "yaw": null
397
+ }
398
+ }
399
+ },
400
+ "components": {
401
+ "title": "Components"
402
+ },
403
+ "prod": {
404
+ "default": true,
405
+ "title": "Prod",
406
+ "type": "boolean"
407
+ },
408
+ "log_directory": {
409
+ "default": "~/greenroom/lookout/logs",
410
+ "title": "Log Directory",
411
+ "type": "string"
412
+ },
413
+ "recording_directory": {
414
+ "default": "~/greenroom/lookout/recordings",
415
+ "title": "Recording Directory",
416
+ "type": "string"
417
+ },
418
+ "with_discovery_server": {
419
+ "default": true,
420
+ "description": "Run the discovery server. It will bind to 0.0.0.0:11811",
421
+ "title": "With Discovery Server",
422
+ "type": "boolean"
423
+ },
424
+ "simple_discovery": {
425
+ "default": false,
426
+ "description": "Use simple discovery. This should NOT be used in production due to performance issues.",
427
+ "title": "Simple Discovery",
428
+ "type": "boolean"
429
+ },
430
+ "discovery_server_ip": {
431
+ "default": "0.0.0.0",
432
+ "description": "IP/host/interface of the discovery server. Assumes port of 11811",
433
+ "title": "Discovery Server Ip",
434
+ "type": "string"
435
+ },
436
+ "own_ip": {
437
+ "default": "0.0.0.0",
438
+ "description": "IP/host/interface address of the primary network interface. This is where DDS traffic will route to.",
439
+ "title": "Own Ip",
440
+ "type": "string"
441
+ }
442
+ },
443
+ "title": "LookoutConfig",
444
+ "type": "object"
445
+ }
@@ -0,0 +1,3 @@
1
+ def test_lookout_config():
2
+ # TODO: Add tests
3
+ assert True is True
@@ -0,0 +1,146 @@
1
+ # Updates here should also be made to:
2
+ # * lookout_interfaces/msg/Config.msg
3
+ # * lookout_config_manager/mappers.py
4
+
5
+ from typing import Optional, Any
6
+ from enum import Enum
7
+ from pydantic import BaseModel, field_validator, ConfigDict
8
+ from pydantic.fields import Field
9
+
10
+ from greenstream_config.types import Camera, Offsets
11
+
12
+
13
+ class Mode(str, Enum):
14
+ SIMULATOR = "simulator"
15
+ HARDWARE = "hardware"
16
+ STUBS = "stubs"
17
+ ROSBAG = "rosbag"
18
+
19
+ def __str__(self):
20
+ return self.value
21
+
22
+
23
+ class PositioningSystem(str, Enum):
24
+ NONE = "none"
25
+ SEPTENTRIO_INS = "septentrio_ins"
26
+ ADNAV_INS = "advanced_navigation_ins"
27
+ NMEA_2000_SAT_COMPASS = "nmea_2000_sat_compass"
28
+ NMEA_2000_COMPASS = "nmea_2000_compass"
29
+ NMEA_0183_SAT_COMPASS = "nmea_0183_sat_compass"
30
+ NMEA_0183_COMPASS = "nmea_0183_compass"
31
+
32
+ def __str__(self):
33
+ return self.value
34
+
35
+
36
+ class LogLevel(str, Enum):
37
+ INFO = "info"
38
+ DEBUG = "debug"
39
+
40
+ def __str__(self):
41
+ return self.value
42
+
43
+
44
+ class Network(str, Enum):
45
+ SHARED = "shared"
46
+ HOST = "host"
47
+
48
+ def __str__(self):
49
+ return self.value
50
+
51
+
52
+ class GeolocationMode(str, Enum):
53
+ NONE = "none"
54
+ RELATIVE_BEARING = "relative_bearing"
55
+ ABSOLUTE_BEARING = "absolute_bearing"
56
+ RANGE_BEARING = "range_bearing"
57
+
58
+ def __str__(self):
59
+ return self.value
60
+
61
+
62
+ class Point(BaseModel):
63
+ x: int
64
+ y: int
65
+
66
+ def __eq__(self, other):
67
+ if isinstance(other, Point):
68
+ return self.x == other.x and self.y == other.y
69
+ return False
70
+
71
+
72
+ class Polygon(BaseModel):
73
+ points: list[Point]
74
+
75
+
76
+ class CameraExtended(Camera):
77
+ ignore_regions: list[Polygon] = Field(default_factory=list)
78
+
79
+ @field_validator("ignore_regions")
80
+ def check_polygon(cls, ignore_regions):
81
+ if ignore_regions:
82
+ for polygon in ignore_regions:
83
+ if len(polygon.points) < 4: # 3 points for a triangle, 1 to close the polygon
84
+ raise ValueError("Polygon must have at least 3 sides (4 points)")
85
+ if polygon.points[0] != polygon.points[-1]:
86
+ raise ValueError("Polygon must close. Must have same start and end point")
87
+ return ignore_regions
88
+
89
+
90
+ class VesselOffsets(BaseModel):
91
+ name: str
92
+ baselink_to_ins: Offsets
93
+ baselink_to_waterline: Offsets
94
+
95
+
96
+ class LookoutConfig(BaseModel):
97
+ # So enum values are written and read to the yml correctly
98
+ model_config = ConfigDict(
99
+ use_enum_values=False,
100
+ json_encoders={
101
+ Mode: lambda v: v.value,
102
+ LogLevel: lambda v: v.value,
103
+ Network: lambda v: v.value,
104
+ GeolocationMode: lambda v: v.value,
105
+ PositioningSystem: lambda v: v.value,
106
+ },
107
+ )
108
+ ros_domain_id: int = Field(
109
+ default=0,
110
+ description="ROS domain ID for the vessel. This only applies if 'simple_discovery' is true.",
111
+ )
112
+ namespace_vessel: str = "vessel_1"
113
+ gama_vessel: bool = False
114
+ mode: Mode = Mode.HARDWARE
115
+ log_level: LogLevel = LogLevel.INFO
116
+ cameras: list[CameraExtended] = Field(default_factory=list)
117
+ network: Network = Network.HOST
118
+ gpu: bool = True
119
+ geolocation_mode: GeolocationMode = GeolocationMode.NONE
120
+ positioning_system: PositioningSystem = PositioningSystem.NONE
121
+ offsets: VesselOffsets = VesselOffsets(
122
+ name="mars.stl",
123
+ baselink_to_ins=Offsets(forward=1.4160, left=0.153, up=0.184),
124
+ baselink_to_waterline=Offsets(
125
+ up=0.3,
126
+ ),
127
+ )
128
+ components: Any = Field(default_factory=dict)
129
+ prod: bool = True
130
+ log_directory: str = "~/greenroom/lookout/logs"
131
+ recording_directory: str = "~/greenroom/lookout/recordings"
132
+ with_discovery_server: bool = Field(
133
+ default=True, description="Run the discovery server. It will bind to 0.0.0.0:11811"
134
+ )
135
+ simple_discovery: bool = Field(
136
+ default=False,
137
+ description="Use simple discovery. This should NOT be used in production due to performance issues.",
138
+ )
139
+ discovery_server_ip: str = Field(
140
+ default="0.0.0.0",
141
+ description="IP/host/interface of the discovery server. Assumes port of 11811",
142
+ )
143
+ own_ip: str = Field(
144
+ default="0.0.0.0",
145
+ description="IP/host/interface address of the primary network interface. This is where DDS traffic will route to.",
146
+ )
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.2
2
+ Name: lookout_config
3
+ Version: 1.15.1
4
+ Summary: A library for reading / writing Lookout config files
5
+ Home-page: https://github.com/Greenroom-Robotics/lookout
6
+ Author: Greenroom Robotics
7
+ Author-email: team@greenroomrobotics.com
8
+ Maintainer: David Revay
9
+ Maintainer-email: david.revay@greenroomrobotics.com
10
+ License: Copyright (C) 2023, Greenroom Robotics
11
+ Keywords: colcon
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Plugins
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Topic :: Software Development :: Build Tools
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: setuptools
19
+ Requires-Dist: dacite
20
+ Requires-Dist: PyYAML
21
+ Requires-Dist: dc-schema
22
+ Requires-Dist: greenstream-config==3.10.1
23
+ Requires-Dist: gr-urchin
24
+
25
+ # Lookout Config
26
+
27
+ Lookout Config is used to load config stored inside the `~/.config/greenroom` folder.
28
+
29
+ ## Install
30
+
31
+ * `pip install -e ./packages/lookout_config`
32
+ * or...
33
+ * `pip install lookout_config` (Public on [PyPi](https://pypi.org/project/lookout-config/))
34
+
35
+ ## Usage
36
+
37
+ ### Reading config
38
+
39
+ ```python
40
+ from lookout_config import read
41
+
42
+ config = read()
43
+ ```
44
+
45
+ ### Writing config
46
+
47
+ ```python
48
+ from lookout_config import write, LookoutConfig
49
+
50
+ config = LookoutConfig()
51
+
52
+ write(config)
53
+
54
+ ```
55
+
56
+ ### Generating schemas
57
+
58
+ After changing the dataclasses, you can generate the schemas with:
59
+
60
+ ```bash
61
+ python3 -m lookout_config.generate_schemas
62
+ ```
@@ -0,0 +1,13 @@
1
+ lookout_config/__init__.py,sha256=3D-vqwfTPSuvLVBo4wiYQglpPUm4Fj6Y5MYGIS-e0fI,1738
2
+ lookout_config/generate_schemas.py,sha256=yFNvrZ6gie1tnTM_1TO8_wBa0lFHJAABSI3ZAZqw_Wg,457
3
+ lookout_config/generate_urdf.py,sha256=O5n0hNsRJwTgQnWdPZIg_LgpxlDQOzWv5IccjT7yDS4,2719
4
+ lookout_config/helpers.py,sha256=3GkGRPDzQ67I5srwcWoI8PI1dgrWvTsUwA8-yRUttLM,603
5
+ lookout_config/launch_parameters.py,sha256=wvLXQMPi7D3ExesyvSNLPYEb2WChj9YTslnvQYPsXbk,3033
6
+ lookout_config/types.py,sha256=o--5Mo7ADSCv5k240oyiA-sJDA5BLd6nx5RGzFZFygo,4325
7
+ lookout_config/schemas/lookout.schema.json,sha256=eH6i8OW-9jBBEusm4qMaACV7fujtrqw1_Bm5YwuQNxw,9390
8
+ lookout_config/test/lookout_config_test.py,sha256=TdOzIEWnyrckhmK7OtShtoWwSAP8QDCiKalNhvScd2U,73
9
+ lookout_config-1.15.1.dist-info/METADATA,sha256=Ij7EiKJ5hzyvI-QGafkWPiSBufKxPSRbQcvI6ROtaG4,1442
10
+ lookout_config-1.15.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
11
+ lookout_config-1.15.1.dist-info/top_level.txt,sha256=IiZRgJhNrNL87uLMQm9lQRrMCqJnTOl7aYlA7zRSYyg,15
12
+ lookout_config-1.15.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
13
+ lookout_config-1.15.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.8.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ lookout_config
@@ -0,0 +1 @@
1
+