Metadata-Version: 2.1
Name: dynos-sentry-domain
Version: 0.1.3
Summary: Public Sentry-vehicle survey domain for DYNOS
License: Apache-2.0
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: dynos-client>=0.1.3

# dynos-sentry-domain

The Sentry-AUV survey vocabulary for DYNOS. Mostly `Zone`, `Coordinate`, `survey`,
`goto`, `full_coverage_of`. Importing this package gives you the words to use
when constructing goals for a Sentry mission.

The package is backend-agnostic. It only declares the public domain. The
hardware extensions (thrusters, weights, descent sequencing, control modes)
live behind the backend boundary and are not shipped on PyPI; the planner knows
about them when it runs, but your code never references them.

Treat this repository like a static API for Sentry. `dynos-client` lets you
talk to a backend, `dynos-sentry-domain` gives you the words to use. You
usually install both together.

## Install

```bash
pip install dynos-sentry-domain
```

Pulls in `dynos-client` (and `dynos-core`) transitively.

## Concepts

A short refresher of `dynos-core`:

- Symbolic state is a set of named facts (fluents) about typed objects.
  `at(wp_end)` and `phase_at_depth()` are atoms; the current world is the set
  of atoms that are true now.
- Goals are states not commands. You tell the system *what should be true*; the
  planner derives the action sequence that makes it true.
- Transitions are action schemas. `survey(zone)` is the symbolic side; the
  executable side is on the backend.

### `Zone`

A polygonal survey region. The planner expands `full_coverage_of(zone)` into
per-trackline `fly_trackline(...)` actions using the zone's geometry — you do
not enumerate the tracklines yourself.

| Field              | Description                                | Example                                   |
|--------------------|--------------------------------------------|-------------------------------------------|
| `vertices`         | Polygon corners as `[lon, lat]`            | `[[-70.67, 41.52], [-70.66, 41.52], ...]` |
| `coordinate_frame` | Currently only `"geographic"` is supported | `"geographic"`                            |
| `altitude`         | Survey depth (m)                           | `65.0`                                    |
| `speed`            | Vehicle speed (m/s)                        | `1.0`                                     |
| `coverage_width`   | Sensor swath width (m)                     | `170.0` (multibeam), `5.0` (camera)       |
| `robot_width`      | Vehicle width (m)                          | `0.5`                                     |
| `envelope`         | Altitude tolerance (m)                     | `20.0`                                    |

### `Coordinate`

A named waypoint. The planner uses it as a goto target.

```python
Coordinate(name="wp_end", latitude=41.525, longitude=-70.66, coordinate_frame="geographic")
```

### Lifecycle phases

Sentry missions have lifecycle predicates that goals usually combine with the
survey or goto goal so the vehicle ends up in a known state when the plan
finishes:

- `phase_at_depth()`: vehicle is at operating depth.
- `phase_ascending()`: vehicle is ascending after the mission.
- `phase_surface()`: vehicle is at the surface.

These predicates are visible to the planner as goal terms. You typically
reference them as **strings** in `dynos call goal` or as bare term-builder
calls in Python (e.g. `phase_ascending()`); the backend resolves them
server-side.

## 60-second example: a single-zone survey

```python
from dynos_client import RemoteOrchestrator
from dynos_sentry.sentry import Zone, full_coverage_of

orch = RemoteOrchestrator.from_config(timeout_s=3600)

site_alpha = Zone("site_alpha",
    coordinate_frame="geographic",
    vertices=[[-70.67, 41.52], [-70.66, 41.52],
              [-70.66, 41.525], [-70.67, 41.525]],
    altitude=70.0,
    envelope=20.0,
    speed=0.8,
    coverage_width=170.0,
    robot_width=0.5,
)
orch.create_object(site_alpha)
orch.set_goal([full_coverage_of(site_alpha), "phase_ascending()"])
orch.execute_plan()
```

CLI equivalent (using a `zone.json` file):

```bash
dynos call create zone.json
dynos call goal "full_coverage_of(site_alpha)" "phase_ascending()"
dynos call plan        # optional: print the action sequence
dynos call execute     # synchronous; will time out the CLI for long surveys
```

After it finishes, pull a GeoJSON of the executed survey for inspection:

```bash
dynos call geojson -o survey.geojson
```

## Goto: a goal, not a primitive

"Go to a waypoint" in DYNOS is a goal, not a command. You declare the world
state you want (like `at(wp_end) & phase_at_depth()`) and the planner derives
the prerequisite sequence (takeover, descent setup, the descent itself). There
is deliberately no "just go" button: routing through the planner is what keeps
the symbolic world consistent and what makes replanning on failure work.

```python
from dynos_sentry.sentry import Coordinate

orch.create_object(Coordinate(name="wp_end", latitude=41.525, longitude=-70.66,
                              coordinate_frame="geographic"))
orch.set_goal(["at(wp_end)", "phase_at_depth()"])
orch.execute_plan()
```

`dynos call plan` will show something like `takeover_control, setup_descent, descent_sequence(target=wp_end)`.

## Public API

| Symbol                   | Purpose                                                                           |
|--------------------------|-----------------------------------------------------------------------------------|
| `Zone`                   | The polygonal survey region (object type with `ValueField` descriptors).          |
| `Coordinate`             | A named waypoint (object type).                                                   |
| `survey`                 | Transition for surveying a zone (used as a building block of `full_coverage_of`). |
| `goto`                   | Transition for moving between coordinates.                                        |
| `full_coverage_of(zone)` | Goal-side fluent: "this zone has been fully surveyed." Use this in `set_goal`.    |
| `SurveyParams`           | Parameter dataclass for `survey`.                                                 |
| `CoordinateGotoParams`   | Parameter dataclass for `goto`.                                                   |

Lifecycle phase predicates (`phase_at_depth`, `phase_ascending`,
`phase_surface`) are reachable via goal strings; the backend resolves them.

## What is intentionally not exposed

Hardware fluents (`Thruster`, `Servo`, `controller_survey`,
`bottom_follow_configured`, ...) and internal transitions (`takeover_control`,
`descent_sequence`, ...) live in the backend extension layer, not here. They
are stripped from the public release; user code must not depend on them. If you
find yourself wanting one, the right move is usually to phrase it as a goal
that the planner can satisfy, or to file an issue describing the use case.

## Next

For a complete worked example with a custom action and an end-to-end mission,
see `dynos-adaptive-resampling`. For the cross-package install / login /
first-survey walkthrough, see `user_guide.md`.
