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.
- lookout_config/__init__.py +74 -0
- lookout_config/generate_schemas.py +16 -0
- lookout_config/generate_urdf.py +83 -0
- lookout_config/helpers.py +18 -0
- lookout_config/launch_parameters.py +69 -0
- lookout_config/schemas/lookout.schema.json +445 -0
- lookout_config/test/lookout_config_test.py +3 -0
- lookout_config/types.py +146 -0
- lookout_config-1.15.1.dist-info/METADATA +62 -0
- lookout_config-1.15.1.dist-info/RECORD +13 -0
- lookout_config-1.15.1.dist-info/WHEEL +5 -0
- lookout_config-1.15.1.dist-info/top_level.txt +1 -0
- lookout_config-1.15.1.dist-info/zip-safe +1 -0
@@ -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
|
+
}
|
lookout_config/types.py
ADDED
@@ -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 @@
|
|
1
|
+
lookout_config
|
@@ -0,0 +1 @@
|
|
1
|
+
|