lookout-config 1.0.2__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,96 @@
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 dataclasses import dataclass, field
7
+ from enum import Enum
8
+ from dacite import from_dict, Config
9
+ from typing import Optional, Any, List, Annotated
10
+ from dc_schema import SchemaAnnotation
11
+ from dataclasses import asdict
12
+ from pathlib import Path
13
+ from greenstream_config.types import CameraOverride
14
+
15
+
16
+ LOOKOUT_CONFIG_FILE_NAME = "lookout.yml"
17
+ LOOKOUT_SCHEMA_URL = "https://greenroom-robotics.github.io/lookout/schemas/lookout.schema.json"
18
+
19
+
20
+ def join_lines(*lines: str) -> str:
21
+ return "\n".join(lines)
22
+
23
+
24
+ class Mode(str, Enum):
25
+ SIMULATOR = "simulator"
26
+ HARDWARE = "hardware"
27
+ STUBS = "stubs"
28
+ ROSBAG = "rosbag"
29
+
30
+
31
+ class LogLevel(str, Enum):
32
+ INFO = "info"
33
+ DEBUG = "debug"
34
+
35
+
36
+ class Network(str, Enum):
37
+ SHARED = "shared"
38
+ HOST = "host"
39
+
40
+
41
+ @dataclass
42
+ class LookoutConfig:
43
+ ros_domain_id: int = 0
44
+ namespace_vessel: str = "vessel"
45
+ gama_vessel: bool = False
46
+ mode: Mode = Mode.STUBS
47
+ log_level: LogLevel = LogLevel.INFO
48
+ camera_overrides: Optional[List[Optional[CameraOverride]]] = None
49
+ network: Network = Network.HOST
50
+ gpu: bool = False
51
+
52
+
53
+ def find_config() -> Path:
54
+ """Returns the path to the .config/greenroom directory"""
55
+ return Path.home().joinpath(".config/greenroom")
56
+
57
+
58
+ def dacite_to_dict(obj: Any):
59
+ def dict_factory(data: Any):
60
+ def convert_value(obj: Any):
61
+ if isinstance(obj, Enum):
62
+ return obj.value
63
+ return obj
64
+
65
+ return {k: convert_value(v) for k, v in data}
66
+
67
+ return asdict(obj, dict_factory=dict_factory)
68
+
69
+
70
+ def get_path():
71
+ return find_config() / LOOKOUT_CONFIG_FILE_NAME
72
+
73
+
74
+ def parse(config: dict[str, Any]) -> LookoutConfig:
75
+ return from_dict(
76
+ LookoutConfig,
77
+ config,
78
+ config=Config(cast=[LogLevel, Mode, Network]),
79
+ )
80
+
81
+
82
+ def read() -> LookoutConfig:
83
+ path = get_path()
84
+ with open(path) as stream:
85
+ return parse(yaml.safe_load(stream))
86
+
87
+
88
+ def write(config: LookoutConfig):
89
+ path = get_path()
90
+ # Make the parent dir if it doesn't exist
91
+ os.makedirs(path.parent, exist_ok=True)
92
+ with open(path, "w") as stream:
93
+ print(f"Writing: {path}")
94
+ headers = f"# yaml-language-server: $schema={LOOKOUT_SCHEMA_URL}"
95
+ data = "\n".join([headers, yaml.dump(dacite_to_dict(config))])
96
+ stream.write(data)
@@ -0,0 +1,190 @@
1
+ from typing import List
2
+ from greenstream_config import Camera, Offsets
3
+ from lookout_config import Mode
4
+ from math import radians
5
+
6
+
7
+ def generate_cameras_armidale(mode: Mode, namespace: str):
8
+ # !! IMPORTANT !!
9
+ # Changes here should probably be made in gama also
10
+
11
+ k_intrinsic = [1097.44852, 0.0, 992.544475, 0.0, 1101.33980, 552.247413, 0.0, 0.0, 1.0]
12
+ # Distortion parameters are broken in foxglove :(
13
+ # distortion_parameters = [
14
+ # -0.388772321,
15
+ # 0.194568646,
16
+ # -0.000662550588,
17
+ # 0.000224063281,
18
+ # -0.0503775800,
19
+ # ]
20
+
21
+ cameras: List[Camera] = [
22
+ Camera(
23
+ name="port",
24
+ type="color",
25
+ order=0,
26
+ elements=[
27
+ "rtspsrc location=rtsp://admin:@192.168.2.21:554/live/0/MAIN latency=10",
28
+ "rtph264depay",
29
+ "h264parse",
30
+ "avdec_h264",
31
+ "videoconvert",
32
+ ],
33
+ pixel_height=1080,
34
+ pixel_width=1920,
35
+ sensor_height_mm=2.21,
36
+ sensor_width_mm=3.92,
37
+ fov=125.0,
38
+ camera_frame_topic="perception/frames/port_color",
39
+ camera_info_topic="sensors/cameras/port_color/camera_info",
40
+ camera_info_ext_topic="sensors/cameras/port_color/camera_info_ext",
41
+ k_intrinsic=k_intrinsic,
42
+ # distortion_parameters=distortion_parameters,
43
+ offsets=Offsets(
44
+ roll=0.0,
45
+ pitch=radians(20.0),
46
+ yaw=radians(45.0),
47
+ forward=2.275,
48
+ left=2.850,
49
+ up=-0.155,
50
+ ),
51
+ ),
52
+ Camera(
53
+ name="bow",
54
+ type="color",
55
+ order=1,
56
+ elements=[
57
+ "rtspsrc location=rtsp://admin:@192.168.2.22:554/live/0/MAIN latency=10",
58
+ "rtph264depay",
59
+ "h264parse",
60
+ "avdec_h264",
61
+ "videoconvert",
62
+ ],
63
+ pixel_height=1080,
64
+ pixel_width=1920,
65
+ sensor_height_mm=2.21,
66
+ sensor_width_mm=3.92,
67
+ fov=125.0,
68
+ camera_frame_topic="perception/frames/bow_color",
69
+ camera_info_topic="sensors/cameras/bow_color/camera_info",
70
+ camera_info_ext_topic="sensors/cameras/bow_color/camera_info_ext",
71
+ k_intrinsic=k_intrinsic,
72
+ # distortion_parameters=distortion_parameters,
73
+ offsets=Offsets(
74
+ roll=radians(2.0),
75
+ pitch=radians(6.0),
76
+ yaw=0.0,
77
+ forward=3.190,
78
+ left=0.015,
79
+ up=-0.205,
80
+ ),
81
+ ),
82
+ Camera(
83
+ name="stbd",
84
+ type="color",
85
+ order=2,
86
+ elements=[
87
+ "rtspsrc location=rtsp://admin:@192.168.2.23:554/live/0/MAIN latency=10",
88
+ "rtph264depay",
89
+ "h264parse",
90
+ "avdec_h264",
91
+ "videoconvert",
92
+ ],
93
+ pixel_height=1080,
94
+ pixel_width=1920,
95
+ sensor_height_mm=2.21,
96
+ sensor_width_mm=3.92,
97
+ fov=125.0,
98
+ camera_frame_topic="perception/frames/stbd_color",
99
+ camera_info_topic="sensors/cameras/stbd_color/camera_info",
100
+ camera_info_ext_topic="sensors/cameras/stbd_color/camera_info_ext",
101
+ k_intrinsic=k_intrinsic,
102
+ # distortion_parameters=distortion_parameters,
103
+ offsets=Offsets(
104
+ roll=0.0,
105
+ pitch=radians(20.0),
106
+ yaw=radians(-45.0),
107
+ forward=2.275,
108
+ left=-2.850,
109
+ up=-0.155,
110
+ ),
111
+ ),
112
+ Camera(
113
+ name="stern_port",
114
+ type="color",
115
+ order=3,
116
+ elements=[
117
+ "rtspsrc location=rtsp://admin:@192.168.2.24:554/live/0/MAIN latency=10",
118
+ "rtph264depay",
119
+ "h264parse",
120
+ "avdec_h264",
121
+ "videoconvert",
122
+ ],
123
+ pixel_height=1080,
124
+ pixel_width=1920,
125
+ sensor_height_mm=2.21,
126
+ sensor_width_mm=3.92,
127
+ fov=125.0,
128
+ camera_frame_topic="perception/frames/stern_port_color",
129
+ camera_info_topic="sensors/cameras/stern_port_color/camera_info",
130
+ camera_info_ext_topic="sensors/cameras/stern_port_color/camera_info_ext",
131
+ k_intrinsic=k_intrinsic,
132
+ # distortion_parameters=distortion_parameters,
133
+ offsets=Offsets(
134
+ roll=0.0,
135
+ pitch=radians(20.0),
136
+ yaw=radians(135.0),
137
+ forward=-4.980,
138
+ left=2.850,
139
+ up=-0.155,
140
+ ),
141
+ ),
142
+ Camera(
143
+ name="stern_stbd",
144
+ type="color",
145
+ order=4,
146
+ elements=[
147
+ "rtspsrc location=rtsp://admin:@192.168.2.25:554/live/0/MAIN latency=10",
148
+ "rtph264depay",
149
+ "h264parse",
150
+ "avdec_h264",
151
+ "videoconvert",
152
+ ],
153
+ pixel_height=1080,
154
+ pixel_width=1920,
155
+ sensor_height_mm=2.21,
156
+ sensor_width_mm=3.92,
157
+ fov=125.0,
158
+ camera_frame_topic="perception/frames/stern_stbd_color",
159
+ camera_info_topic="sensors/cameras/stern_stbd_color/camera_info",
160
+ camera_info_ext_topic="sensors/cameras/stern_stbd_color/camera_info_ext",
161
+ k_intrinsic=k_intrinsic,
162
+ # distortion_parameters=distortion_parameters,
163
+ offsets=Offsets(
164
+ roll=0.0,
165
+ pitch=radians(20.0),
166
+ yaw=radians(-135.0),
167
+ forward=-4.980,
168
+ left=-2.850,
169
+ up=-0.155,
170
+ ),
171
+ ),
172
+ ]
173
+
174
+ if mode == Mode.STUBS:
175
+ for camera in cameras:
176
+ camera.elements = [
177
+ "videotestsrc pattern=ball",
178
+ "video/x-raw, format=RGB,width=1920,height=1080",
179
+ ]
180
+ elif mode == Mode.SIMULATOR or mode == Mode.ROSBAG:
181
+ for camera in cameras:
182
+ camera.elements = [
183
+ f"rosimagesrc ros-topic=sensors/cameras/{camera.name}_{camera.type}/image_raw ros-name='gst_rosimagesrc_{camera.name}_{camera.type}' ros-namespace='{namespace}'"
184
+ ]
185
+
186
+ return cameras
187
+
188
+
189
+ def generate_cameras(mode: Mode, namespace: str):
190
+ return generate_cameras_armidale(mode, namespace)
@@ -0,0 +1,16 @@
1
+ import os
2
+ from pathlib import Path
3
+ import json
4
+ from dc_schema import get_schema
5
+ from lookout_config import LookoutConfig
6
+
7
+
8
+ def generate_schemas():
9
+ """Generates the schemas for the config files"""
10
+ SCHEMAS_PATH = Path(os.path.dirname(__file__)) / "schemas"
11
+ with open(SCHEMAS_PATH / "lookout.schema.json", "w") as f:
12
+ json.dump(get_schema(LookoutConfig), f, indent=2)
13
+
14
+
15
+ if __name__ == "__main__":
16
+ generate_schemas()
@@ -0,0 +1,84 @@
1
+ from typing import List
2
+ from lookout_config import LookoutConfig
3
+ from greenstream_config import Camera, Offsets, get_cameras_urdf
4
+ from gr_urchin import URDF, Joint, Material, Link, xyz_rpy_to_matrix, Visual, Mesh, Geometry
5
+ from math import radians
6
+
7
+
8
+ def generate_urdf(
9
+ config: LookoutConfig,
10
+ cameras: List[Camera],
11
+ ins_offset: Offsets,
12
+ mesh_path: str,
13
+ waterline=0.0, # meters between the waterline and the base_link
14
+ add_optical_frame: bool = True,
15
+ ):
16
+
17
+ file_path = f"/tmp/vessel_{config.mode.value}.urdf"
18
+
19
+ # generate links and joints for all vessel cameras
20
+ camera_links, camera_joints = get_cameras_urdf(
21
+ cameras, config.camera_overrides if config.camera_overrides else [None], add_optical_frame
22
+ )
23
+
24
+ urdf = URDF(
25
+ name="origins",
26
+ materials=[
27
+ Material(name="grey", color=[0.75, 0.75, 0.75, 1]),
28
+ Material(name="blue", color=[0, 0, 1, 1]),
29
+ ],
30
+ links=[
31
+ Link(name="ins_link", inertial=None, visuals=None, collisions=None),
32
+ Link(name="waterline_link", inertial=None, visuals=None, collisions=None),
33
+ Link(
34
+ name="base_link",
35
+ inertial=None,
36
+ visuals=[
37
+ Visual(
38
+ name="visual",
39
+ geometry=Geometry(
40
+ mesh=Mesh(filename=mesh_path, combine=False, lazy_filename=mesh_path)
41
+ ),
42
+ origin=xyz_rpy_to_matrix([0, 0, 0, radians(-90), 0, 0]),
43
+ material=Material(name="grey"),
44
+ )
45
+ ],
46
+ collisions=None,
47
+ ),
48
+ *camera_links,
49
+ ],
50
+ joints=[
51
+ Joint(
52
+ name="base_to_ins",
53
+ parent="base_link",
54
+ child="ins_link",
55
+ joint_type="fixed",
56
+ origin=xyz_rpy_to_matrix(
57
+ [
58
+ ins_offset.forward,
59
+ ins_offset.left,
60
+ ins_offset.up,
61
+ ins_offset.roll,
62
+ ins_offset.pitch,
63
+ ins_offset.yaw,
64
+ ]
65
+ ),
66
+ ),
67
+ Joint(
68
+ name="base_to_waterline",
69
+ parent="base_link",
70
+ child="waterline_link",
71
+ joint_type="fixed",
72
+ origin=xyz_rpy_to_matrix([0, 0, -waterline, 0, 0, 0]),
73
+ ),
74
+ *camera_joints,
75
+ ],
76
+ )
77
+
78
+ urdf.save(file_path)
79
+
80
+ # stringify urdf response for robot description
81
+ with open(file_path) as infp:
82
+ robot_description = infp.read()
83
+
84
+ return robot_description
@@ -0,0 +1,139 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "title": "LookoutConfig",
5
+ "properties": {
6
+ "ros_domain_id": {
7
+ "type": "integer",
8
+ "default": 0
9
+ },
10
+ "namespace_vessel": {
11
+ "type": "string",
12
+ "default": "vessel"
13
+ },
14
+ "gama_vessel": {
15
+ "type": "boolean",
16
+ "default": false
17
+ },
18
+ "mode": {
19
+ "allOf": [
20
+ {
21
+ "$ref": "#/$defs/Mode"
22
+ }
23
+ ],
24
+ "default": "stubs"
25
+ },
26
+ "log_level": {
27
+ "allOf": [
28
+ {
29
+ "$ref": "#/$defs/LogLevel"
30
+ }
31
+ ],
32
+ "default": "info"
33
+ },
34
+ "greenstream": {
35
+ "allOf": [
36
+ {
37
+ "$ref": "#/$defs/Greenstream"
38
+ }
39
+ ]
40
+ },
41
+ "network": {
42
+ "allOf": [
43
+ {
44
+ "$ref": "#/$defs/Network"
45
+ }
46
+ ],
47
+ "default": "host"
48
+ }
49
+ },
50
+ "$defs": {
51
+ "Mode": {
52
+ "title": "Mode",
53
+ "enum": [
54
+ "simulator",
55
+ "hardware",
56
+ "stubs"
57
+ ]
58
+ },
59
+ "LogLevel": {
60
+ "title": "LogLevel",
61
+ "enum": [
62
+ "info",
63
+ "debug"
64
+ ]
65
+ },
66
+ "Pipeline": {
67
+ "type": "object",
68
+ "title": "Pipeline",
69
+ "properties": {
70
+ "name": {
71
+ "type": "string"
72
+ },
73
+ "order": {
74
+ "anyOf": [
75
+ {
76
+ "type": "integer"
77
+ },
78
+ {
79
+ "type": "null"
80
+ }
81
+ ]
82
+ },
83
+ "elements": {
84
+ "type": "array",
85
+ "items": {
86
+ "type": "string"
87
+ }
88
+ }
89
+ },
90
+ "required": [
91
+ "name",
92
+ "order",
93
+ "elements"
94
+ ]
95
+ },
96
+ "Greenstream": {
97
+ "type": "object",
98
+ "title": "Greenstream",
99
+ "properties": {
100
+ "pipeline_overrides": {
101
+ "anyOf": [
102
+ {
103
+ "type": "array",
104
+ "items": {
105
+ "anyOf": [
106
+ {
107
+ "allOf": [
108
+ {
109
+ "$ref": "#/$defs/Pipeline"
110
+ }
111
+ ]
112
+ },
113
+ {
114
+ "type": "null"
115
+ }
116
+ ]
117
+ }
118
+ },
119
+ {
120
+ "type": "null"
121
+ }
122
+ ],
123
+ "default": null,
124
+ "description": "A list of greenstream pipelines.\nThese will only take affect if the the mode is 'hardware'\n\nSet these to 'null' to ignore the override.",
125
+ "examples": [
126
+ "- null\n- name: bow\n elements:\n - v4l2src\n - video/x-raw, format=RGB,width=1280,height=720"
127
+ ]
128
+ }
129
+ }
130
+ },
131
+ "Network": {
132
+ "title": "Network",
133
+ "enum": [
134
+ "shared",
135
+ "host"
136
+ ]
137
+ }
138
+ }
139
+ }
@@ -0,0 +1,3 @@
1
+ def test_lookout_config():
2
+ # TODO: Add tests
3
+ assert True is True
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.1
2
+ Name: lookout_config
3
+ Version: 1.0.2
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 ==2.13.2
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 ./libs/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,11 @@
1
+ lookout_config/__init__.py,sha256=UtYJZvu6j8Zkm5GGTS10E33hZbE-NCG5ACtexvGoQRE,2438
2
+ lookout_config/generate_cameras.py,sha256=XUvKlirk7rYlMOHm8V3QcmGRYccgN1tLXII2NIO6B70,6529
3
+ lookout_config/generate_schemas.py,sha256=NvE79GwkazdMBAdz-tWu7hB6lBmALaMnq2pvGB9garM,436
4
+ lookout_config/generate_urdf.py,sha256=wMZ15pSwORgEguMHApKSTIYMEQAv5geY4LM5wf8_z8A,2762
5
+ lookout_config/schemas/lookout.schema.json,sha256=HwgQWsrKwiJF8HeTm0JPIGoIMrsWKbmYtp8aO_1QccI,2769
6
+ lookout_config/test/lookout_config_test.py,sha256=TdOzIEWnyrckhmK7OtShtoWwSAP8QDCiKalNhvScd2U,73
7
+ lookout_config-1.0.2.dist-info/METADATA,sha256=DcKy92LLcV8D02Lhjhc2ngiTNEQlYWM1EFCDAbz05wg,1438
8
+ lookout_config-1.0.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
9
+ lookout_config-1.0.2.dist-info/top_level.txt,sha256=IiZRgJhNrNL87uLMQm9lQRrMCqJnTOl7aYlA7zRSYyg,15
10
+ lookout_config-1.0.2.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
11
+ lookout_config-1.0.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.43.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ lookout_config
@@ -0,0 +1 @@
1
+