19 KiB
Веб-интерфейс, кнопка и локатор
Кроме окна, с программой работают из браузера, 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. Они делают то же, что одноимённые кнопки окна (глава Окно программы).
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
профиля (глава Файл конфигурации) и читается один раз при запуске
программы.
Схема по умолчанию: кнопка между линией 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.
Пакет от радара:
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: внутри окна видимости, после отбора по
числу и фильтра приближения. При пересчёте после смены настроек уходит пакет только
для новейшей коллекции. Новый клиент сразу получает последний отправленный пакет.
Пакет к радару — скорость в м/с:
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 (установка — в главе Установка и запуск). Она
запускает ./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 в браузере.