dynos-sentry-domain 0.1.2__tar.gz

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,169 @@
1
+ Metadata-Version: 2.1
2
+ Name: dynos-sentry-domain
3
+ Version: 0.1.2
4
+ Summary: Public Sentry-vehicle survey domain for DYNOS
5
+ License: Apache-2.0
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: dynos-client>=0.1.2
9
+
10
+ # dynos-sentry-domain
11
+
12
+ The Sentry-AUV survey vocabulary for DYNOS. Mostly `Zone`, `Coordinate`, `survey`,
13
+ `goto`, `full_coverage_of`. Importing this package gives you the words to use
14
+ when constructing goals for a Sentry mission.
15
+
16
+ The package is backend-agnostic. It only declares the public domain. The
17
+ hardware extensions (thrusters, weights, descent sequencing, control modes)
18
+ live behind the backend boundary and are not shipped on PyPI; the planner knows
19
+ about them when it runs, but your code never references them.
20
+
21
+ Treat this repository like a static API for Sentry. `dynos-client` lets you
22
+ talk to a backend, `dynos-sentry-domain` gives you the words to use. You
23
+ usually install both together.
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ pip install dynos-sentry-domain
29
+ ```
30
+
31
+ Pulls in `dynos-client` (and `dynos-core`) transitively.
32
+
33
+ ## Concepts
34
+
35
+ A short refresher of `dynos-core`:
36
+
37
+ - Symbolic state is a set of named facts (fluents) about typed objects.
38
+ `at(wp_end)` and `phase_at_depth()` are atoms; the current world is the set
39
+ of atoms that are true now.
40
+ - Goals are states not commands. You tell the system *what should be true*; the
41
+ planner derives the action sequence that makes it true.
42
+ - Transitions are action schemas. `survey(zone)` is the symbolic side; the
43
+ executable side is on the backend.
44
+
45
+ ### `Zone`
46
+
47
+ A polygonal survey region. The planner expands `full_coverage_of(zone)` into
48
+ per-trackline `fly_trackline(...)` actions using the zone's geometry — you do
49
+ not enumerate the tracklines yourself.
50
+
51
+ | Field | Description | Example |
52
+ |--------------------|--------------------------------------------|-------------------------------------------|
53
+ | `vertices` | Polygon corners as `[lon, lat]` | `[[-70.67, 41.52], [-70.66, 41.52], ...]` |
54
+ | `coordinate_frame` | Currently only `"geographic"` is supported | `"geographic"` |
55
+ | `altitude` | Survey depth (m) | `65.0` |
56
+ | `speed` | Vehicle speed (m/s) | `1.0` |
57
+ | `coverage_width` | Sensor swath width (m) | `170.0` (multibeam), `5.0` (camera) |
58
+ | `robot_width` | Vehicle width (m) | `0.5` |
59
+ | `envelope` | Altitude tolerance (m) | `20.0` |
60
+
61
+ ### `Coordinate`
62
+
63
+ A named waypoint. The planner uses it as a goto target.
64
+
65
+ ```python
66
+ Coordinate(name="wp_end", latitude=41.525, longitude=-70.66, coordinate_frame="geographic")
67
+ ```
68
+
69
+ ### Lifecycle phases
70
+
71
+ Sentry missions have lifecycle predicates that goals usually combine with the
72
+ survey or goto goal so the vehicle ends up in a known state when the plan
73
+ finishes:
74
+
75
+ - `phase_at_depth()`: vehicle is at operating depth.
76
+ - `phase_ascending()`: vehicle is ascending after the mission.
77
+ - `phase_surface()`: vehicle is at the surface.
78
+
79
+ These predicates are visible to the planner as goal terms. You typically
80
+ reference them as **strings** in `dynos call goal` or as bare term-builder
81
+ calls in Python (e.g. `phase_ascending()`); the backend resolves them
82
+ server-side.
83
+
84
+ ## 60-second example: a single-zone survey
85
+
86
+ ```python
87
+ from dynos_client import RemoteOrchestrator
88
+ from dynos_sentry.sentry import Zone, full_coverage_of
89
+
90
+ orch = RemoteOrchestrator.from_config(timeout_s=3600)
91
+
92
+ site_alpha = Zone("site_alpha",
93
+ coordinate_frame="geographic",
94
+ vertices=[[-70.67, 41.52], [-70.66, 41.52],
95
+ [-70.66, 41.525], [-70.67, 41.525]],
96
+ altitude=70.0,
97
+ envelope=20.0,
98
+ speed=0.8,
99
+ coverage_width=170.0,
100
+ robot_width=0.5,
101
+ )
102
+ orch.create_object(site_alpha)
103
+ orch.set_goal([full_coverage_of(site_alpha), "phase_ascending()"])
104
+ orch.execute_plan()
105
+ ```
106
+
107
+ CLI equivalent (using a `zone.json` file):
108
+
109
+ ```bash
110
+ dynos call create zone.json
111
+ dynos call goal "full_coverage_of(site_alpha)" "phase_ascending()"
112
+ dynos call plan # optional: print the action sequence
113
+ dynos call execute # synchronous; will time out the CLI for long surveys
114
+ ```
115
+
116
+ After it finishes, pull a GeoJSON of the executed survey for inspection:
117
+
118
+ ```bash
119
+ dynos call geojson -o survey.geojson
120
+ ```
121
+
122
+ ## Goto: a goal, not a primitive
123
+
124
+ "Go to a waypoint" in DYNOS is a goal, not a command. You declare the world
125
+ state you want (like `at(wp_end) & phase_at_depth()`) and the planner derives
126
+ the prerequisite sequence (takeover, descent setup, the descent itself). There
127
+ is deliberately no "just go" button: routing through the planner is what keeps
128
+ the symbolic world consistent and what makes replanning on failure work.
129
+
130
+ ```python
131
+ from dynos_sentry.sentry import Coordinate
132
+
133
+ orch.create_object(Coordinate(name="wp_end", latitude=41.525, longitude=-70.66,
134
+ coordinate_frame="geographic"))
135
+ orch.set_goal(["at(wp_end)", "phase_at_depth()"])
136
+ orch.execute_plan()
137
+ ```
138
+
139
+ `dynos call plan` will show something like `takeover_control, setup_descent, descent_sequence(target=wp_end)`.
140
+
141
+ ## Public API
142
+
143
+ | Symbol | Purpose |
144
+ |--------------------------|-----------------------------------------------------------------------------------|
145
+ | `Zone` | The polygonal survey region (object type with `ValueField` descriptors). |
146
+ | `Coordinate` | A named waypoint (object type). |
147
+ | `survey` | Transition for surveying a zone (used as a building block of `full_coverage_of`). |
148
+ | `goto` | Transition for moving between coordinates. |
149
+ | `full_coverage_of(zone)` | Goal-side fluent: "this zone has been fully surveyed." Use this in `set_goal`. |
150
+ | `SurveyParams` | Parameter dataclass for `survey`. |
151
+ | `CoordinateGotoParams` | Parameter dataclass for `goto`. |
152
+
153
+ Lifecycle phase predicates (`phase_at_depth`, `phase_ascending`,
154
+ `phase_surface`) are reachable via goal strings; the backend resolves them.
155
+
156
+ ## What is intentionally not exposed
157
+
158
+ Hardware fluents (`Thruster`, `Servo`, `controller_survey`,
159
+ `bottom_follow_configured`, ...) and internal transitions (`takeover_control`,
160
+ `descent_sequence`, ...) live in the backend extension layer, not here. They
161
+ are stripped from the public release; user code must not depend on them. If you
162
+ find yourself wanting one, the right move is usually to phrase it as a goal
163
+ that the planner can satisfy, or to file an issue describing the use case.
164
+
165
+ ## Next
166
+
167
+ For a complete worked example with a custom action and an end-to-end mission,
168
+ see `dynos-adaptive-resampling`. For the cross-package install / login /
169
+ first-survey walkthrough, see `user_guide.md`.
@@ -0,0 +1,160 @@
1
+ # dynos-sentry-domain
2
+
3
+ The Sentry-AUV survey vocabulary for DYNOS. Mostly `Zone`, `Coordinate`, `survey`,
4
+ `goto`, `full_coverage_of`. Importing this package gives you the words to use
5
+ when constructing goals for a Sentry mission.
6
+
7
+ The package is backend-agnostic. It only declares the public domain. The
8
+ hardware extensions (thrusters, weights, descent sequencing, control modes)
9
+ live behind the backend boundary and are not shipped on PyPI; the planner knows
10
+ about them when it runs, but your code never references them.
11
+
12
+ Treat this repository like a static API for Sentry. `dynos-client` lets you
13
+ talk to a backend, `dynos-sentry-domain` gives you the words to use. You
14
+ usually install both together.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ pip install dynos-sentry-domain
20
+ ```
21
+
22
+ Pulls in `dynos-client` (and `dynos-core`) transitively.
23
+
24
+ ## Concepts
25
+
26
+ A short refresher of `dynos-core`:
27
+
28
+ - Symbolic state is a set of named facts (fluents) about typed objects.
29
+ `at(wp_end)` and `phase_at_depth()` are atoms; the current world is the set
30
+ of atoms that are true now.
31
+ - Goals are states not commands. You tell the system *what should be true*; the
32
+ planner derives the action sequence that makes it true.
33
+ - Transitions are action schemas. `survey(zone)` is the symbolic side; the
34
+ executable side is on the backend.
35
+
36
+ ### `Zone`
37
+
38
+ A polygonal survey region. The planner expands `full_coverage_of(zone)` into
39
+ per-trackline `fly_trackline(...)` actions using the zone's geometry — you do
40
+ not enumerate the tracklines yourself.
41
+
42
+ | Field | Description | Example |
43
+ |--------------------|--------------------------------------------|-------------------------------------------|
44
+ | `vertices` | Polygon corners as `[lon, lat]` | `[[-70.67, 41.52], [-70.66, 41.52], ...]` |
45
+ | `coordinate_frame` | Currently only `"geographic"` is supported | `"geographic"` |
46
+ | `altitude` | Survey depth (m) | `65.0` |
47
+ | `speed` | Vehicle speed (m/s) | `1.0` |
48
+ | `coverage_width` | Sensor swath width (m) | `170.0` (multibeam), `5.0` (camera) |
49
+ | `robot_width` | Vehicle width (m) | `0.5` |
50
+ | `envelope` | Altitude tolerance (m) | `20.0` |
51
+
52
+ ### `Coordinate`
53
+
54
+ A named waypoint. The planner uses it as a goto target.
55
+
56
+ ```python
57
+ Coordinate(name="wp_end", latitude=41.525, longitude=-70.66, coordinate_frame="geographic")
58
+ ```
59
+
60
+ ### Lifecycle phases
61
+
62
+ Sentry missions have lifecycle predicates that goals usually combine with the
63
+ survey or goto goal so the vehicle ends up in a known state when the plan
64
+ finishes:
65
+
66
+ - `phase_at_depth()`: vehicle is at operating depth.
67
+ - `phase_ascending()`: vehicle is ascending after the mission.
68
+ - `phase_surface()`: vehicle is at the surface.
69
+
70
+ These predicates are visible to the planner as goal terms. You typically
71
+ reference them as **strings** in `dynos call goal` or as bare term-builder
72
+ calls in Python (e.g. `phase_ascending()`); the backend resolves them
73
+ server-side.
74
+
75
+ ## 60-second example: a single-zone survey
76
+
77
+ ```python
78
+ from dynos_client import RemoteOrchestrator
79
+ from dynos_sentry.sentry import Zone, full_coverage_of
80
+
81
+ orch = RemoteOrchestrator.from_config(timeout_s=3600)
82
+
83
+ site_alpha = Zone("site_alpha",
84
+ coordinate_frame="geographic",
85
+ vertices=[[-70.67, 41.52], [-70.66, 41.52],
86
+ [-70.66, 41.525], [-70.67, 41.525]],
87
+ altitude=70.0,
88
+ envelope=20.0,
89
+ speed=0.8,
90
+ coverage_width=170.0,
91
+ robot_width=0.5,
92
+ )
93
+ orch.create_object(site_alpha)
94
+ orch.set_goal([full_coverage_of(site_alpha), "phase_ascending()"])
95
+ orch.execute_plan()
96
+ ```
97
+
98
+ CLI equivalent (using a `zone.json` file):
99
+
100
+ ```bash
101
+ dynos call create zone.json
102
+ dynos call goal "full_coverage_of(site_alpha)" "phase_ascending()"
103
+ dynos call plan # optional: print the action sequence
104
+ dynos call execute # synchronous; will time out the CLI for long surveys
105
+ ```
106
+
107
+ After it finishes, pull a GeoJSON of the executed survey for inspection:
108
+
109
+ ```bash
110
+ dynos call geojson -o survey.geojson
111
+ ```
112
+
113
+ ## Goto: a goal, not a primitive
114
+
115
+ "Go to a waypoint" in DYNOS is a goal, not a command. You declare the world
116
+ state you want (like `at(wp_end) & phase_at_depth()`) and the planner derives
117
+ the prerequisite sequence (takeover, descent setup, the descent itself). There
118
+ is deliberately no "just go" button: routing through the planner is what keeps
119
+ the symbolic world consistent and what makes replanning on failure work.
120
+
121
+ ```python
122
+ from dynos_sentry.sentry import Coordinate
123
+
124
+ orch.create_object(Coordinate(name="wp_end", latitude=41.525, longitude=-70.66,
125
+ coordinate_frame="geographic"))
126
+ orch.set_goal(["at(wp_end)", "phase_at_depth()"])
127
+ orch.execute_plan()
128
+ ```
129
+
130
+ `dynos call plan` will show something like `takeover_control, setup_descent, descent_sequence(target=wp_end)`.
131
+
132
+ ## Public API
133
+
134
+ | Symbol | Purpose |
135
+ |--------------------------|-----------------------------------------------------------------------------------|
136
+ | `Zone` | The polygonal survey region (object type with `ValueField` descriptors). |
137
+ | `Coordinate` | A named waypoint (object type). |
138
+ | `survey` | Transition for surveying a zone (used as a building block of `full_coverage_of`). |
139
+ | `goto` | Transition for moving between coordinates. |
140
+ | `full_coverage_of(zone)` | Goal-side fluent: "this zone has been fully surveyed." Use this in `set_goal`. |
141
+ | `SurveyParams` | Parameter dataclass for `survey`. |
142
+ | `CoordinateGotoParams` | Parameter dataclass for `goto`. |
143
+
144
+ Lifecycle phase predicates (`phase_at_depth`, `phase_ascending`,
145
+ `phase_surface`) are reachable via goal strings; the backend resolves them.
146
+
147
+ ## What is intentionally not exposed
148
+
149
+ Hardware fluents (`Thruster`, `Servo`, `controller_survey`,
150
+ `bottom_follow_configured`, ...) and internal transitions (`takeover_control`,
151
+ `descent_sequence`, ...) live in the backend extension layer, not here. They
152
+ are stripped from the public release; user code must not depend on them. If you
153
+ find yourself wanting one, the right move is usually to phrase it as a goal
154
+ that the planner can satisfy, or to file an issue describing the use case.
155
+
156
+ ## Next
157
+
158
+ For a complete worked example with a custom action and an end-to-end mission,
159
+ see `dynos-adaptive-resampling`. For the cross-package install / login /
160
+ first-survey walkthrough, see `user_guide.md`.
@@ -0,0 +1,15 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "dynos-sentry-domain"
7
+ version = "0.1.2"
8
+ description = "Public Sentry-vehicle survey domain for DYNOS"
9
+ readme = "README.md"
10
+ license = { text = "Apache-2.0" }
11
+ requires-python = ">=3.8"
12
+ dependencies = ["dynos-client>=0.1.2"]
13
+
14
+ [tool.setuptools.packages.find]
15
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,8 @@
1
+ """
2
+ Public-facing Sentry domain information. The backend expands
3
+ this with many more actions that aren't useful/safe for the scientist (like
4
+ being able to manipulate communication power channels) and other configurations
5
+ that don't change (like maximum depth).
6
+
7
+ You can treat this repository like a static Sentry API.
8
+ """
@@ -0,0 +1,86 @@
1
+ """Public survey domain: types and transitions for survey zone planning.
2
+
3
+ This module contains the symbols that external collaborators need to
4
+ define survey zones, create waypoints, and navigate between them. It
5
+ has no references to vehicle hardware, mission lifecycle phases, or
6
+ internal survey expansion steps.
7
+
8
+ Collaborators should import from dynos_sentry.sentry (the facade),
9
+ not from this module directly.
10
+ """
11
+
12
+ from dynos_client.domain import (
13
+ ObjectType,
14
+ Transition,
15
+ TransitionParams,
16
+ ValueField,
17
+ make_new_fluent,
18
+ )
19
+
20
+ """
21
+ ObjectTypes: abstract things we can interact with in the world.
22
+
23
+ For this, that's a Zone (set of coordinates defining a space that we might want
24
+ to survey) and a Coordinate.
25
+ """
26
+
27
+ class Zone(ObjectType):
28
+ """A 2D survey polygon with coverage parameters."""
29
+
30
+ coordinate_frame = ValueField(str) # "geographic" | "local_enu"
31
+ altitude = ValueField(float) # survey altitude in meters
32
+ envelope = ValueField(float) # altitude envelope tolerance
33
+ speed = ValueField(float) # survey speed in m/s
34
+ coverage_width = ValueField(float) # swath width for coverage planning
35
+ robot_width = ValueField(float) # vehicle width for coverage planning
36
+ vertices = ValueField(list) # list of Coordinate or (lat, lon) tuples
37
+ angle = ValueField(float) # survey-line angle in degrees (0 = north)
38
+ pattern = ValueField(str) # route pattern: Boustrophedon, Snake, Spiral
39
+
40
+
41
+ class Coordinate(ObjectType):
42
+ """A geographic or local-ENU waypoint."""
43
+
44
+ latitude = ValueField(float)
45
+ longitude = ValueField(float)
46
+ coordinate_frame = ValueField(str) # "geographic" | "local_enu"
47
+
48
+
49
+ """
50
+ Fluents: things that can be true or false, forming part of a state and
51
+ represented in a first-order logic format.
52
+ """
53
+
54
+ # Survey goal
55
+ full_coverage_of = make_new_fluent(zone=Zone)
56
+
57
+
58
+ """
59
+ Transitions and Transition Parameters: Transitions are things the robot can
60
+ do to modify the environment; they have parameters that the backend can access
61
+ later (so we can talk about 'do a survey' but then also figure out the zones
62
+ that that relates to)
63
+ """
64
+
65
+ class SurveyParams(TransitionParams):
66
+ zone: Zone
67
+
68
+
69
+ class CoordinateGotoParams(TransitionParams):
70
+ """Parameters for the goto transition: two waypoints defining the leg."""
71
+
72
+ start: Coordinate
73
+ end: Coordinate
74
+
75
+
76
+ # survey: expand a zone into tracklines.
77
+ survey = Transition(
78
+ params_type=SurveyParams,
79
+ )
80
+
81
+ # goto: navigate between two coordinates. Used directly for point-to-point
82
+ # navigation, and internally by the survey script for transit legs between
83
+ # tracklines.
84
+ goto = Transition(
85
+ params_type=CoordinateGotoParams,
86
+ )
@@ -0,0 +1 @@
1
+ # Vehicle internals are not included in the public distribution.
@@ -0,0 +1,22 @@
1
+ """
2
+ Sentry Domain (public subset).
3
+ """
4
+ from dynos_sentry._survey import ( # noqa: F401
5
+ Coordinate,
6
+ CoordinateGotoParams,
7
+ SurveyParams,
8
+ Zone,
9
+ full_coverage_of,
10
+ goto,
11
+ survey,
12
+ )
13
+
14
+ __all__ = [
15
+ "Coordinate",
16
+ "CoordinateGotoParams",
17
+ "SurveyParams",
18
+ "Zone",
19
+ "full_coverage_of",
20
+ "goto",
21
+ "survey",
22
+ ]
@@ -0,0 +1,169 @@
1
+ Metadata-Version: 2.1
2
+ Name: dynos-sentry-domain
3
+ Version: 0.1.2
4
+ Summary: Public Sentry-vehicle survey domain for DYNOS
5
+ License: Apache-2.0
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: dynos-client>=0.1.2
9
+
10
+ # dynos-sentry-domain
11
+
12
+ The Sentry-AUV survey vocabulary for DYNOS. Mostly `Zone`, `Coordinate`, `survey`,
13
+ `goto`, `full_coverage_of`. Importing this package gives you the words to use
14
+ when constructing goals for a Sentry mission.
15
+
16
+ The package is backend-agnostic. It only declares the public domain. The
17
+ hardware extensions (thrusters, weights, descent sequencing, control modes)
18
+ live behind the backend boundary and are not shipped on PyPI; the planner knows
19
+ about them when it runs, but your code never references them.
20
+
21
+ Treat this repository like a static API for Sentry. `dynos-client` lets you
22
+ talk to a backend, `dynos-sentry-domain` gives you the words to use. You
23
+ usually install both together.
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ pip install dynos-sentry-domain
29
+ ```
30
+
31
+ Pulls in `dynos-client` (and `dynos-core`) transitively.
32
+
33
+ ## Concepts
34
+
35
+ A short refresher of `dynos-core`:
36
+
37
+ - Symbolic state is a set of named facts (fluents) about typed objects.
38
+ `at(wp_end)` and `phase_at_depth()` are atoms; the current world is the set
39
+ of atoms that are true now.
40
+ - Goals are states not commands. You tell the system *what should be true*; the
41
+ planner derives the action sequence that makes it true.
42
+ - Transitions are action schemas. `survey(zone)` is the symbolic side; the
43
+ executable side is on the backend.
44
+
45
+ ### `Zone`
46
+
47
+ A polygonal survey region. The planner expands `full_coverage_of(zone)` into
48
+ per-trackline `fly_trackline(...)` actions using the zone's geometry — you do
49
+ not enumerate the tracklines yourself.
50
+
51
+ | Field | Description | Example |
52
+ |--------------------|--------------------------------------------|-------------------------------------------|
53
+ | `vertices` | Polygon corners as `[lon, lat]` | `[[-70.67, 41.52], [-70.66, 41.52], ...]` |
54
+ | `coordinate_frame` | Currently only `"geographic"` is supported | `"geographic"` |
55
+ | `altitude` | Survey depth (m) | `65.0` |
56
+ | `speed` | Vehicle speed (m/s) | `1.0` |
57
+ | `coverage_width` | Sensor swath width (m) | `170.0` (multibeam), `5.0` (camera) |
58
+ | `robot_width` | Vehicle width (m) | `0.5` |
59
+ | `envelope` | Altitude tolerance (m) | `20.0` |
60
+
61
+ ### `Coordinate`
62
+
63
+ A named waypoint. The planner uses it as a goto target.
64
+
65
+ ```python
66
+ Coordinate(name="wp_end", latitude=41.525, longitude=-70.66, coordinate_frame="geographic")
67
+ ```
68
+
69
+ ### Lifecycle phases
70
+
71
+ Sentry missions have lifecycle predicates that goals usually combine with the
72
+ survey or goto goal so the vehicle ends up in a known state when the plan
73
+ finishes:
74
+
75
+ - `phase_at_depth()`: vehicle is at operating depth.
76
+ - `phase_ascending()`: vehicle is ascending after the mission.
77
+ - `phase_surface()`: vehicle is at the surface.
78
+
79
+ These predicates are visible to the planner as goal terms. You typically
80
+ reference them as **strings** in `dynos call goal` or as bare term-builder
81
+ calls in Python (e.g. `phase_ascending()`); the backend resolves them
82
+ server-side.
83
+
84
+ ## 60-second example: a single-zone survey
85
+
86
+ ```python
87
+ from dynos_client import RemoteOrchestrator
88
+ from dynos_sentry.sentry import Zone, full_coverage_of
89
+
90
+ orch = RemoteOrchestrator.from_config(timeout_s=3600)
91
+
92
+ site_alpha = Zone("site_alpha",
93
+ coordinate_frame="geographic",
94
+ vertices=[[-70.67, 41.52], [-70.66, 41.52],
95
+ [-70.66, 41.525], [-70.67, 41.525]],
96
+ altitude=70.0,
97
+ envelope=20.0,
98
+ speed=0.8,
99
+ coverage_width=170.0,
100
+ robot_width=0.5,
101
+ )
102
+ orch.create_object(site_alpha)
103
+ orch.set_goal([full_coverage_of(site_alpha), "phase_ascending()"])
104
+ orch.execute_plan()
105
+ ```
106
+
107
+ CLI equivalent (using a `zone.json` file):
108
+
109
+ ```bash
110
+ dynos call create zone.json
111
+ dynos call goal "full_coverage_of(site_alpha)" "phase_ascending()"
112
+ dynos call plan # optional: print the action sequence
113
+ dynos call execute # synchronous; will time out the CLI for long surveys
114
+ ```
115
+
116
+ After it finishes, pull a GeoJSON of the executed survey for inspection:
117
+
118
+ ```bash
119
+ dynos call geojson -o survey.geojson
120
+ ```
121
+
122
+ ## Goto: a goal, not a primitive
123
+
124
+ "Go to a waypoint" in DYNOS is a goal, not a command. You declare the world
125
+ state you want (like `at(wp_end) & phase_at_depth()`) and the planner derives
126
+ the prerequisite sequence (takeover, descent setup, the descent itself). There
127
+ is deliberately no "just go" button: routing through the planner is what keeps
128
+ the symbolic world consistent and what makes replanning on failure work.
129
+
130
+ ```python
131
+ from dynos_sentry.sentry import Coordinate
132
+
133
+ orch.create_object(Coordinate(name="wp_end", latitude=41.525, longitude=-70.66,
134
+ coordinate_frame="geographic"))
135
+ orch.set_goal(["at(wp_end)", "phase_at_depth()"])
136
+ orch.execute_plan()
137
+ ```
138
+
139
+ `dynos call plan` will show something like `takeover_control, setup_descent, descent_sequence(target=wp_end)`.
140
+
141
+ ## Public API
142
+
143
+ | Symbol | Purpose |
144
+ |--------------------------|-----------------------------------------------------------------------------------|
145
+ | `Zone` | The polygonal survey region (object type with `ValueField` descriptors). |
146
+ | `Coordinate` | A named waypoint (object type). |
147
+ | `survey` | Transition for surveying a zone (used as a building block of `full_coverage_of`). |
148
+ | `goto` | Transition for moving between coordinates. |
149
+ | `full_coverage_of(zone)` | Goal-side fluent: "this zone has been fully surveyed." Use this in `set_goal`. |
150
+ | `SurveyParams` | Parameter dataclass for `survey`. |
151
+ | `CoordinateGotoParams` | Parameter dataclass for `goto`. |
152
+
153
+ Lifecycle phase predicates (`phase_at_depth`, `phase_ascending`,
154
+ `phase_surface`) are reachable via goal strings; the backend resolves them.
155
+
156
+ ## What is intentionally not exposed
157
+
158
+ Hardware fluents (`Thruster`, `Servo`, `controller_survey`,
159
+ `bottom_follow_configured`, ...) and internal transitions (`takeover_control`,
160
+ `descent_sequence`, ...) live in the backend extension layer, not here. They
161
+ are stripped from the public release; user code must not depend on them. If you
162
+ find yourself wanting one, the right move is usually to phrase it as a goal
163
+ that the planner can satisfy, or to file an issue describing the use case.
164
+
165
+ ## Next
166
+
167
+ For a complete worked example with a custom action and an end-to-end mission,
168
+ see `dynos-adaptive-resampling`. For the cross-package install / login /
169
+ first-survey walkthrough, see `user_guide.md`.
@@ -0,0 +1,11 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/dynos_sentry/__init__.py
4
+ src/dynos_sentry/_survey.py
5
+ src/dynos_sentry/_vehicle.py
6
+ src/dynos_sentry/sentry.py
7
+ src/dynos_sentry_domain.egg-info/PKG-INFO
8
+ src/dynos_sentry_domain.egg-info/SOURCES.txt
9
+ src/dynos_sentry_domain.egg-info/dependency_links.txt
10
+ src/dynos_sentry_domain.egg-info/requires.txt
11
+ src/dynos_sentry_domain.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ dynos-client>=0.1.2