Files
2026-10-16 18:35:02 +03:00

16 KiB
Raw Permalink Blame History

Установка и запуск

Программа работает в 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.

Установка

Из каталога проекта:

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) он ничего не ставит: всё должно быть установлено заранее.

Запуск

./start.sh --profile run_config_examples/run_config_librevna_multi_per_point.example.json

Без --profile программа берёт последний использованный профиль, а если его нет — корневой run_config.json (симулятор). Порядок выбора профиля — в главе Файл конфигурации. Но сам 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 перед запуском (глава Данные на диске)
-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 и геометрию антенн (глава Файл конфигурации).
  2. Запустите ./start.sh --profile <профиль>. При первом запуске он может спросить пароль sudo, чтобы поставить системные библиотеки и правило udev для LibreVNA.
  3. Нажмите Apply Radar, снимите калибровку и референс (глава Калибровка и предобработка) и нажмите Start.
  4. Нажмите Save Config…: выбор наборов и правки в окне сохраняются только так.

Порядок работы по шагам — в главе Типовые сценарии.

Видеокарта для 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 и соберите в отдельный каталог:

    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/, поэтому такая сборка нужна для проверки на старой карте (глава Разработка).

  • На Jetson CUDA берётся из JetPack (/usr/local/cuda); pip-пакеты CUDA там не ставятся. PyQt6 на Jetson с glibc 2.35 — версии 6.7.

Служба без экрана

На машине без оператора программу запускает служба systemd. Установка — один раз, от обычного пользователя через sudo:

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 с.

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…. Работа со службой — в разделе «Работа без экрана» главы Веб-интерфейс, кнопка и локатор.

Машина развёртывания

Raspberry Pi 5 Model B (Cortex-A76 ×4, 4 ГиБ), Debian 13, Python 3.13. Проект лежит в ~/Documents/radar_system. На машине собираются .venv и C++; копировать их с рабочей станции нельзя: там другая архитектура (x86_64).

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. Неверный чип в профиле — ключи, которые молча не переключаются.

Обновление с флешки

На рабочей станции:

deploy/pack-usb.sh /media/<пользователь>/<флешка>

Без аргумента скрипт берёт единственную подключённую съёмную флешку. В каталог radar_update/ на ней он кладёт архив radar_system-<дата коммита>-<хеш>.tar.gz с частью проекта для Pi из последнего коммита (незакоммиченные изменения в него не попадают) и скрипт update.sh.

На машине, от обычного пользователя (не через sudo), из каталога, где лежит radar_update:

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<N> — следующий свободный номер; это копия для отката;
  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 и запускает службу, если она работала.

Если что-то пошло не так, скрипт печатает команду отката. Вручную:

sudo systemctl stop radar.service
mv ~/Documents/radar_system ~/Documents/radar_system_failed
mv ~/Documents/radar_system<N> ~/Documents/radar_system
sudo systemctl start radar.service

Новую версию при откате лучше переименовать, а не удалять: в ней могут быть измерения, снятые после обновления.

На свежую машину (без прежней версии) update.sh спрашивает Install a fresh one there? [y/N] и ставит корневой run_config.json из архива, то есть симулятор: профиль с железом нужно выбрать после установки.