# Установка и запуск Программа работает в Linux: на рабочей станции с экраном и на Raspberry Pi 5 без оператора. Python-часть ставится в виртуальное окружение `.venv` внутри каталога проекта, C++-часть собирается командой `make` в `build/bin/`. ## Что нужно | Что | Зачем | | --- | --- | | Linux, bash, coreutils, `flock` | запуск через `start.sh` | | Python 3.10 или новее с модулем `venv` | программа и окружение | | компилятор C++20 (g++), `make` | процессы конвейера | | библиотеки `libusb-1.0` и `libatomic.so.1` | USB-доступ к LibreVNA и кольца разделяемой памяти | | `libxcb-cursor0`, `libxkbcommon-x11-0` (Debian/Ubuntu) | окно Qt на рабочем столе | | видеокарта NVIDIA с драйвером, NVRTC и заголовки CUDA | только для режима 3D SAR | | библиотеки L-Card `libx502api.so`, `libe502api.so` | только для радиофотонного радара с АЦП E-502 | Python-пакеты перечислены в `requirements.txt`: | Пакет | Для чего | | --- | --- | | `numpy` | массивы данных | | `scipy` | оптимизация в калибровке по объекту | | `libusb1` | USB-драйвер LibreVNA | | `pyserial` | последовательный порт платы лазеров | | `PyQt6` | окно программы (без экрана — тоже, в режиме `offscreen`) | | `pyqtgraph` | графики | | `fastapi`, `uvicorn[standard]` | веб-интерфейс | | `nvidia-cuda-nvrtc`, `nvidia-cuda-runtime` | NVRTC и заголовки CUDA для 3D SAR; ставятся только на x86_64 | PyQt6 ставится только из готовых сборок (wheel), поэтому pip выбирает самую новую версию, которая работает с системной glibc. ## Установка Из каталога проекта: ```sh python3 -m venv .venv .venv/bin/python -m pip install --upgrade pip .venv/bin/python -m pip install -r requirements.txt make # build/bin/data_preprocessor и build/bin/data_processor make rph_radar_collector # только для радиофотонного радара с АЦП E-502 ``` `./start.sh` при обычном запуске делает это сам: создаёт `.venv`, если его нет, ставит недостающие пакеты, ставит системные библиотеки через менеджер пакетов (apt, dnf, yum, pacman, zypper или brew, через `sudo`), правило udev для LibreVNA и собирает C++. Без экрана (`--headless`) он ничего не ставит: всё должно быть установлено заранее. ## Запуск ```sh ./start.sh --profile run_config_examples/run_config_librevna_multi_per_point.example.json ``` Без `--profile` программа берёт последний использованный профиль, а если его нет — корневой `run_config.json` (симулятор). Порядок выбора профиля — в главе [Файл конфигурации](configuration.md). Но сам `start.sh` без `--profile` определяет модель радара, решает, собирать ли коллектор E-502, и проверяет программы по корневому `run_config.json`, а `--producer-only` берёт именно его. Поэтому с профилем радиофотонного радара и для `--producer-only` всегда указывайте `--profile`. | Ключ `start.sh` | Что делает | | --- | --- | | `--profile ПУТЬ` | профиль для запуска; файл должен существовать. Относительный путь — от каталога проекта | | `--headless` | без окна: окно не показывается, через 0,5 с выполняется **Apply Radar**, ещё через 1 с — **Start**; если **Start** не удался, программа завершается с кодом 1 (`Headless auto-start did not bring the pipeline up`). Ничего не устанавливает | | `--auto-start` | с окном, но **Start** выполняется сам через 0,5 с после запуска | | `--producer-only` | запустить только процесс сбора для профиля, без окна; вывод — в терминал | | `--skip-build` | не собирать C++ (наличие программ всё равно проверяется) | | `--build-only` | подготовить окружение, собрать и выйти | | `--clean-shm` | удалить известные кольца в `/dev/shm` перед запуском (глава [Данные на диске](data.md)) | | `-h`, `--help` | справка | Порядок работы `start.sh`: проверка окружения → определение модели радара по профилю → системные библиотеки и правило udev (не для `--headless`) → Python-пакеты → сборка C++ (для радиофотонного радара — и коллектора) → проверка программ в `build/bin/` → остановка службы `radar.service`, если она работает → блокировка `/tmp/radar_system.lock` → запуск программы. Если блокировку держит другой экземпляр, `start.sh` завершается с `Another radar instance already holds /tmp/radar_system.lock; aborting.` Для разработки окно можно запустить и напрямую: `.venv/bin/python -m python_app.gui.main`. Тогда нет ни сборки, ни блокировки. ### Первый запуск без железа 1. Запустите `./start.sh` (корневой профиль — симулятор). 2. Нажмите **Preprocessing…**, затем **Create Neutral S21 Sets**: предобработке нужны наборы калибровки и референса, нейтральные данные не меняют. 3. Нажмите **Start**. Симулятор показывает точечный отражатель, который движется по сцене; режим обработки меняется списком **Mode**. Режим 3D SAR без видеокарты NVIDIA показывает только предупреждение. ### Первый запуск с железом 1. Скопируйте нужный профиль из `run_config_examples/` и проверьте в нём серийные номера, порты, линии GPIO и геометрию антенн (глава [Файл конфигурации](configuration.md)). 2. Запустите `./start.sh --profile <профиль>`. При первом запуске он может спросить пароль `sudo`, чтобы поставить системные библиотеки и правило udev для LibreVNA. 3. Нажмите **Apply Radar**, снимите калибровку и референс (глава [Калибровка и предобработка](preprocessing.md)) и нажмите **Start**. 4. Нажмите **Save Config…**: выбор наборов и правки в окне сохраняются только так. Порядок работы по шагам — в главе [Типовые сценарии](workflow.md). ## Видеокарта для 3D SAR Ядра 3D SAR компилируются при запуске библиотекой NVRTC под установленную карту. `make` ищет `nvrtc.h`, `cuda.h` и `libnvrtc` в пакетах `nvidia-cuda-*` из `.venv` и в `/usr/local/cuda`, а `libcuda.so.1` (драйвер) — в системных каталогах. Если чего-то нет, `make` пишет `note: CUDA not found, selecting sar3d will show a warning` и собирает процессор без 3D SAR. После установки CUDA снова запустите `make`: он заметит изменение и пересоберёт нужную часть. - На x86_64 CUDA 13 ставится из `requirements.txt`. Целевая карта — RTX 5070. - NVRTC 13 не компилирует под карты старее поколения sm_75 (например, GTX 1060, sm_61). Для них поставьте NVRTC 12 отдельно от `.venv` и соберите в отдельный каталог: ```sh pip install --target ~/.cache/radar_nvrtc12 nvidia-cuda-nvrtc-cu12 nvidia-cuda-runtime-cu12 make BUILD_DIR=/tmp/build-nvrtc12 CUDA_ROOTS="$HOME/.cache/radar_nvrtc12/nvidia/cuda_nvrtc $HOME/.cache/radar_nvrtc12/nvidia/cuda_runtime" ``` Программа запускает процессор только из `build/bin/`, поэтому такая сборка нужна для проверки на старой карте (глава [Разработка](development.md)). - На Jetson CUDA берётся из JetPack (`/usr/local/cuda`); pip-пакеты CUDA там не ставятся. PyQt6 на Jetson с glibc 2.35 — версии 6.7. ## Служба без экрана На машине без оператора программу запускает служба systemd. Установка — один раз, от обычного пользователя через `sudo`: ```sh sudo bash deploy/install-daemon.sh ``` Скрипт создаёт `/etc/systemd/system/radar.service`, разрешает пользователю без пароля `sudo systemctl stop|start|restart radar.service` (`/etc/sudoers.d/radar`) и включает службу при загрузке, но не запускает её. Служба работает от имени этого пользователя в каталоге проекта, запускает `start.sh --headless --skip-build`, перезапускается через 3 с после сбоя, а при остановке ждёт программу до 25 с. ```sh sudo systemctl start radar.service # запустить systemctl status radar.service # состояние journalctl -u radar.service -f # журнал sudo systemctl disable --now radar.service && sudo rm /etc/systemd/system/radar.service /etc/sudoers.d/radar && sudo systemctl daemon-reload # удалить ``` Служба берёт последний использованный профиль. Перед её запуском откройте окно программы на этой машине, загрузите профиль с железом, выберите наборы и нажмите **Save Config…**. Работа со службой — в разделе «Работа без экрана» главы [Веб-интерфейс, кнопка и локатор](web.md). ## Машина развёртывания Raspberry Pi 5 Model B (Cortex-A76 ×4, 4 ГиБ), Debian 13, Python 3.13. Проект лежит в `~/Documents/radar_system`. На машине собираются `.venv` и C++; копировать их с рабочей станции нельзя: там другая архитектура (x86_64). ```sh python3 -m venv .venv && .venv/bin/python -m pip install -r requirements.txt make -j4 QT_QPA_PLATFORM=offscreen .venv/bin/python -m unittest discover -s python_app/tests ``` На Pi нужна только часть проекта: `data_acq_and_processing`, `deploy`, `python_app`, `run_config_examples`, `Makefile`, `requirements.txt`, `run_config.json`, `start.sh`. Каталог `device_firmware/` и документация не нужны. > **Внимание.** Номер GPIO-чипа 40-контактного разъёма на Pi 5 зависит от версии > ядра. После установки и обновления ядра проверьте его: `gpiodetect` и > `gpioinfo -c gpiochip0`. Неверный чип в профиле — ключи, которые молча не > переключаются. ## Обновление с флешки На рабочей станции: ```sh deploy/pack-usb.sh /media/<пользователь>/<флешка> ``` Без аргумента скрипт берёт единственную подключённую съёмную флешку. В каталог `radar_update/` на ней он кладёт архив `radar_system-<дата коммита>-<хеш>.tar.gz` с частью проекта для Pi из **последнего коммита** (незакоммиченные изменения в него не попадают) и скрипт `update.sh`. На машине, от обычного пользователя (не через `sudo`), из каталога, где лежит `radar_update`: ```sh bash radar_update/update.sh # перенести текущий .venv bash radar_update/update.sh --python 3.13 # собрать .venv заново этим Python ``` Скрипту можно передать путь к архиву: `bash radar_update/update.sh <архив>`; без него берётся последний по имени `radar_system-*.tar.gz` рядом со скриптом. Перед обновлением закройте окно программы, иначе скрипт откажется и покажет, какие процессы работают в каталоге. Службу он остановит сам и запустит снова, если она работала. Что делает `update.sh`: 1. проверяет архив и переименовывает текущую версию в `radar_system` — следующий свободный номер; это копия для отката; 2. разворачивает новую версию в `~/Documents/radar_system` (другой каталог задаёт переменная `RADAR_DIR`); 3. переносит из прежней версии: `run_config.json`; профили из `run_config_examples/`, изменённые на машине (версия из архива ложится рядом с окончанием `.new`); `python_app/runtime/` без журналов; данные `python_app/data*` и чужие каталоги верхнего уровня — жёсткими ссылками, без копирования и места на диске; `.venv` — копией; 4. ставит пакеты из `requirements.txt` и собирает C++ (`make all rph_radar_collector`); 5. записывает имя архива в файл `RELEASE` и запускает службу, если она работала. Если что-то пошло не так, скрипт печатает команду отката. Вручную: ```sh sudo systemctl stop radar.service mv ~/Documents/radar_system ~/Documents/radar_system_failed mv ~/Documents/radar_system ~/Documents/radar_system sudo systemctl start radar.service ``` Новую версию при откате лучше переименовать, а не удалять: в ней могут быть измерения, снятые после обновления. На свежую машину (без прежней версии) `update.sh` спрашивает `Install a fresh one there? [y/N]` и ставит корневой `run_config.json` из архива, то есть симулятор: профиль с железом нужно выбрать после установки.