added docs
This commit is contained in:
+226
@@ -0,0 +1,226 @@
|
||||
# Веб-интерфейс, кнопка и локатор
|
||||
|
||||
Кроме окна, с программой работают из браузера, GPIO-кнопкой и через TCP-локатор: он
|
||||
отдаёт внешним программам найденные объекты и принимает скорость радара. Без экрана
|
||||
(раздел «Работа без экрана») других способов нет.
|
||||
|
||||
## Веб-интерфейс
|
||||
|
||||
Веб-сервер работает внутри программы, и с окном, и без экрана. Откройте в браузере
|
||||
`http://<адрес машины>:8080/`. Порт меняется переменной окружения
|
||||
`RADAR_SYSTEM_WEBUI_PORT`; неверное значение заменяется на 8080. Если порт занят,
|
||||
программа работает без веб-интерфейса, а ошибка (`address already in use`) видна
|
||||
только в выводе процесса. Если сервер не смог запуститься по другой причине, в журнале
|
||||
появляется `Failed to start web UI`.
|
||||
|
||||
> **Внимание.** У веб-интерфейса нет пароля и шифрования: любой, кто достаёт до
|
||||
> порта по сети, управляет радаром. По адресам `/docs`, `/redoc` и `/openapi.json`
|
||||
> открыто описание API. Подключайте машину только к доверенной сети.
|
||||
|
||||
### Страница
|
||||
|
||||
Верхняя строка — кнопки управления: **Start**, **Single Capture**, **Stop**,
|
||||
**Capture Temporary Reference**, **Remove Last Measurement**. Они делают то же, что
|
||||
одноимённые кнопки окна (глава [Окно программы](desktop.md)).
|
||||
|
||||
**Processor Output** — картинка с графиков окна программы. Масштабировать её в
|
||||
браузере нельзя: она повторяет то, что показано в окне. В режиме B-scan над ней
|
||||
список пар (**Input i / Output o**) и кнопка **Next Combination**, в режиме 3D SAR —
|
||||
строка состояния 3D SAR.
|
||||
|
||||
Боковая панель:
|
||||
|
||||
| Блок | Элемент | Что делает |
|
||||
| --- | --- | --- |
|
||||
| **Config Profile** | список и **Load** | загружает профиль из каталога `run_configs/`, как **Load Config…**; доступна при остановленном сборе. Список читается при открытии страницы; новые файлы видны после её перезагрузки |
|
||||
| | `current: <файл>` | текущий профиль |
|
||||
| **Save / Record Dataset** | **Save path**, **Name (optional)** | каталог и имя набора данных; при открытии страницы берутся из окна, а сохранение и запись из браузера переписывают ими **Path** и **Name** окна (запись — и **Sweeps to record**) |
|
||||
| | **Save Last 1000** | сохраняет до 1000 последних коллекций каждой стадии, как одноимённая кнопка окна |
|
||||
| | **Sweeps to record** и **Start + Record to Disk** | запускает сбор и записывает на диск заданное число следующих коллекций; ниже — ход записи `recording N / M sweep(s)…` |
|
||||
| **Processor Settings** | форма | настройки текущего режима обработки (ниже); заголовок сворачивает форму |
|
||||
| | таблицы **Tx geometry**, **Rx geometry** | геометрия антенн в режимах GPR и 3D SAR: **−** удаляет антенну, **Add Antenna** добавляет следующую свободную |
|
||||
| | **Apply** | отправляет изменённые поля |
|
||||
| | **Clear Runtime History** | очищает историю, как одноимённая кнопка окна |
|
||||
|
||||
Нижняя строка: `running` — идёт ли сбор, `processor` — работает ли процессор,
|
||||
`ring` — имя кольца результатов, `scans` — сколько коллекций в истории каждой стадии,
|
||||
и признак картинки: `live` — кадры приходят, `stale` — новых кадров нет дольше 2 с
|
||||
(так бывает и тогда, когда картинка просто не меняется), `no data` — кадров ещё не
|
||||
было. Сообщения об успехе и ошибках всплывают на 2,6 с; ошибки — красным.
|
||||
|
||||
Если окно браузера уже 760 пикселей, панель уходит под картинку.
|
||||
|
||||
### Как выполняются действия
|
||||
|
||||
Каждая кнопка вызывает тот же код, что и кнопка окна, с теми же проверками. Действия
|
||||
из нескольких браузеров выполняются по очереди. Если окно программы не начало
|
||||
действие за 30 с, запрос отменяется
|
||||
(`The desktop did not start the action in time; the request was cancelled`). Если
|
||||
начало, но не закончило, браузер получает
|
||||
`The desktop action is still running; check its status before retrying`, а действие
|
||||
доводится до конца. Ошибки, которые возникают позже (например, на середине
|
||||
однократного съёма), видны только в журнале.
|
||||
|
||||
### Форма настроек
|
||||
|
||||
Форма строится из полей окна: те же подписи, пределы и группы. В ней поле **Mode** и
|
||||
поля текущего режима; смена режима сразу перестраивает форму. **Apply** отправляет
|
||||
только изменённые поля, поэтому два человека, правящие разные поля, не мешают друг
|
||||
другу. Порядок полей может отличаться от окна. Значения проверяются так же, как в
|
||||
окне: вне пределов — `Numeric setting is outside its allowed range`, неизвестный
|
||||
вариант — `Unknown setting option: …`; при ошибке не применяется ни одно поле из
|
||||
отправленных. Дробное число округляется до точности поля окна. Изменения из окна
|
||||
приходят в форму раз в секунду.
|
||||
|
||||
Только в окне программы:
|
||||
|
||||
- **Apply Radar**, **Load Config…** из произвольного места, **Save Config…**;
|
||||
- окно **Preprocessing…**: съём и выбор наборов, калибровка по объекту;
|
||||
- **Save S21 JSON**;
|
||||
- секции **Radar** и **Switches**: развёртка, лазер, ключи, пары сбора;
|
||||
- **Show magnitude**, **Show phase**, **Unwrap phase**, **Scans to show (stopped)**;
|
||||
- журнал и его уровень, строка состояния;
|
||||
- масштаб и сдвиг графиков мышью.
|
||||
|
||||
### Картинка и обновление
|
||||
|
||||
Программа снимает картинку графиков, только когда подключён хотя бы один браузер и
|
||||
изображение изменилось, и не чаще 5 раз в секунду. Каждый браузер получает самую
|
||||
свежую картинку, состояние и настройки; медленное соединение пропускает
|
||||
промежуточные кадры. Пока окно занято синхронным съёмом (калибровка, референс),
|
||||
картинка не обновляется. Браузер переподключается сам через 1,5 с после обрыва.
|
||||
|
||||
### API
|
||||
|
||||
Страница работает через HTTP API, которым можно пользоваться и из своих программ.
|
||||
Тело запросов и ответов — JSON; ошибка действия — код 400 и
|
||||
`{"detail": "<сообщение>"}`. Тело неверного вида (поле не того типа, нет обязательного
|
||||
поля) даёт код 422 со списком ошибок в `detail`.
|
||||
|
||||
| Запрос | Тело | Что делает |
|
||||
| --- | --- | --- |
|
||||
| `GET /api/status` | — | состояние (то же, что в нижней строке страницы) |
|
||||
| `POST /api/start` | — | **Start** |
|
||||
| `POST /api/single_capture` | — | **Single Capture** |
|
||||
| `POST /api/stop` | — | **Stop** |
|
||||
| `POST /api/tmp_reference` | — | **Capture Temporary Reference** |
|
||||
| `POST /api/remove_last` | — | **Remove Last Measurement** |
|
||||
| `POST /api/clear_history` | — | **Clear Runtime History** |
|
||||
| `GET /api/configs` | — | список профилей в `run_configs/` |
|
||||
| `POST /api/load_config` | `{"name": "<файл>.json"}` | загрузить профиль |
|
||||
| `POST /api/save_dataset` | `{"path": "…", "name": "…"}` | **Save Last 1000** |
|
||||
| `POST /api/start_recording` | `{"path": "…", "name": "…", "count": N}` | **Start + Record to Disk**, N от 1 до 1 000 000 |
|
||||
| `GET /api/live_settings` | — | описание полей формы |
|
||||
| `POST /api/live_settings` | `{"<поле>": значение, …}` | применить настройки. Имена полей — из описания формы; у настроек обработки они совпадают с ключами `processing_live.json` |
|
||||
| `POST /api/display_combo` | `{"input_pos": i, "output_pos": o}` | выбрать пару B-scan |
|
||||
| `POST /api/next_combo` | — | **Next Combination** |
|
||||
| `WS /ws` | — | поток сообщений `frame` (картинка PNG в base64), `status`, `settings` |
|
||||
|
||||
## GPIO-кнопка
|
||||
|
||||
Кнопка, подключённая к GPIO компьютера, снимает временный референс — то же, что
|
||||
**Capture Temporary Reference**. Она настраивается в разделе `control_button`
|
||||
профиля (глава [Файл конфигурации](configuration.md)) и читается один раз при запуске
|
||||
программы.
|
||||
|
||||
Схема по умолчанию: кнопка между линией GPIO и землёй, внутренняя подтяжка к питанию,
|
||||
нажатие — спад уровня, по одному действию на нажатие. Индикации на самой кнопке нет;
|
||||
результат виден в журнале (`GPIO control button pressed: capturing tmp reference`, затем
|
||||
`Tmp S21 Reference captured: …`) и на графике pass-through.
|
||||
|
||||
Нажатие, пришедшее, пока программа останавливает сбор перед съёмом, отбрасывается
|
||||
(`Tmp reference capture already in progress; ignoring duplicate request`). Нажатие во
|
||||
время самого съёма ждёт его конца и запускает ещё один съём. Ошибки съёма только
|
||||
записываются в журнал, окон с ошибкой кнопка не
|
||||
открывает. Если настройки неполные, кнопка не включается
|
||||
(`GPIO control button configuration is incomplete or unsupported; watcher not started`).
|
||||
Если линию не удалось открыть — `Failed to start GPIO control button watcher`; если
|
||||
наблюдение за линией прервалось — `GPIO control button watcher stopped: …`. В обоих
|
||||
случаях программа работает дальше без кнопки до перезапуска.
|
||||
|
||||
## TCP-локатор
|
||||
|
||||
Локатор — TCP-сервер внутри процессора. Он отдаёт подключившимся программам объекты,
|
||||
найденные режимом GPR, и принимает от них скорость радара для поправки на движение.
|
||||
Настройки — раздел `run.locator_server` профиля; по умолчанию порт 8888 на всех
|
||||
интерфейсах. Сервер работает, пока работает процессор: от первого **Start** до
|
||||
закрытия программы или перезапуска процессора. **Stop**, временный референс и
|
||||
пересчёт B-scan процессор и локатор не останавливают.
|
||||
|
||||
Обмен в обе стороны идёт пакетами: заголовок из 8 байт — номер устройства и длина
|
||||
данных (оба uint32, младший байт первым), затем текст JSON в UTF-8.
|
||||
|
||||
Пакет от радара:
|
||||
|
||||
```text
|
||||
03 00 00 00 71 00 00 00
|
||||
{"obs":[{"crs":0.3,"dst":4.3},{"crs":-1.0,"dst":6.0},{"crs":1.0,"dst":2.0}],"sts":1,"tim":"13:42:25.058","ver":1}
|
||||
```
|
||||
|
||||
| Поле | Что это |
|
||||
| --- | --- |
|
||||
| `obs` | объекты: `crs` — координата X (вдоль ряда антенн, поперёк направления обзора), `dst` — дальность (Z), метры, округлены до 0,1 м |
|
||||
| `sts` | всегда 1 |
|
||||
| `tim` | местное время сборки пакета `ЧЧ:ММ:СС.ммм` (не время съёма) |
|
||||
| `ver` | `run.locator_server.protocol_version` |
|
||||
|
||||
В заголовке — `run.locator_server.device_id`. Пакет уходит после обработки каждой
|
||||
новой коллекции в любом режиме; вне режима GPR и без объектов список `obs` пуст.
|
||||
Объекты — те же, что видны на графике GPR: внутри окна видимости, после отбора по
|
||||
числу и фильтра приближения. При пересчёте после смены настроек уходит пакет только
|
||||
для новейшей коллекции. Новый клиент сразу получает последний отправленный пакет.
|
||||
|
||||
Пакет к радару — скорость в м/с:
|
||||
|
||||
```text
|
||||
00 00 00 00 0c 00 00 00
|
||||
{"vlc":1.25}
|
||||
```
|
||||
|
||||
Остальные поля и номер устройства в заголовке не читаются. Скорость считается свежей
|
||||
5 с после прихода. Пока она свежая и на странице GPR или 3D SAR выключена
|
||||
**Ignore socket speed**, она заменяет скорость из поля, а её изменение пересчитывает
|
||||
новейшую коллекцию в GPR и 3D SAR. Использованная скорость сохраняется в каждом
|
||||
результате.
|
||||
|
||||
Клиентов может быть несколько; у каждого очередь на `client_queue_size` пакетов (по
|
||||
умолчанию 32), при переполнении выбрасываются старые. Клиент, который 5 с не принимает
|
||||
данные или прислал пакет больше `max_payload_bytes` (по умолчанию 65 536 байт),
|
||||
отключается. Сообщения локатора пишутся в
|
||||
`python_app/runtime/logs/data_processor.err.log`; если порт занят, процессор работает
|
||||
без локатора и пишет туда же `locator server disabled`.
|
||||
|
||||
## Работа без экрана
|
||||
|
||||
На машине без оператора (Raspberry Pi) программу запускает служба systemd
|
||||
`radar.service` (установка — в главе [Установка и запуск](installation.md)). Она
|
||||
запускает `./start.sh --headless --skip-build`: окно не показывается, через 0,5 с
|
||||
выполняется **Apply Radar**, ещё через 1 с — **Start**, даже если **Apply Radar** не
|
||||
удался. Если **Start** не удался, программа завершается, и systemd запускает её
|
||||
снова через 3 с.
|
||||
|
||||
Профиль служба берёт последний использованный (из
|
||||
`python_app/runtime/gui_session_state.json`), а если его нет — корневой
|
||||
`run_config.json`, то есть симулятор. Поэтому перед установкой службы загрузите или
|
||||
сохраните на машине нужный профиль. Если запомненный профиль не читается, программа
|
||||
пишет `Failed to load the last selected config profile; falling back to root run_config.json.`,
|
||||
берёт корневой профиль и запоминает уже его: исправленный профиль нужно загрузить снова.
|
||||
|
||||
| Канал | Для чего |
|
||||
| --- | --- |
|
||||
| браузер, `http://<машина>:8080/` | запуск и остановка, временный референс, сохранение данных, профили из `run_configs/`, настройки обработки |
|
||||
| GPIO-кнопка | временный референс |
|
||||
| TCP-локатор, порт 8888 | объекты и скорость |
|
||||
| `sudo systemctl start` / `stop` / `restart radar.service` | управление службой |
|
||||
| `journalctl -u radar.service -f` | журнал службы |
|
||||
|
||||
Без экрана нет окон с ошибками: всё пишется в журнал. Окно калибровки и
|
||||
**Save Config…** без экрана недоступны: калибровку снимайте, запустив окно программы
|
||||
на той же машине. При запуске окна `./start.sh` сначала останавливает службу; после
|
||||
закрытия окна она сама не запускается.
|
||||
|
||||
Если процесс конвейера упал, программа перезапускает конвейер: первый раз сразу,
|
||||
следующие подряд — не раньше чем через 6, 12, 24, 48, затем 60 с после предыдущей
|
||||
попытки; когда данные снова пошли, счёт начинается заново. После 400 подряд ошибок чтения
|
||||
колец конвейер останавливается и сам уже
|
||||
не запускается: нажмите **Start** в браузере.
|
||||
Reference in New Issue
Block a user