Files
radar_system/README.md
T
Ayzen 515049d2ed deploy: USB update kit for the Pi and Jetson
pack-usb.sh writes the host part of the last commit and update.sh to a flash drive.
update.sh installs it over ~/Documents/radar_system, keeps configs, calibrations and
data, and leaves the previous version next to it as radar_system<N>.
2026-10-02 16:21:16 +03:00

230 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Radar System
A real-time radar acquisition and imaging system for vector-network-analyzer (VNA)
and ADC front-ends. It drives the radar through a frequency sweep, calibrates and
preprocesses the measured S-parameters, runs a selectable imaging/detection
processor, and presents the live result in a desktop GUI and an in-process web
interface. The same application runs interactively on a workstation or unattended
as a headless Raspberry Pi appliance.
## Overview
The system is split into a **C++ real-time pipeline** and a **Python application**
that supervises it and handles visualization and control.
The pipeline runs as three independent processes connected by lock-free POSIX
shared-memory ring buffers. Each stage advances on its own, and a slow consumer
never blocks a producer — the rings are latest-wins, so a reader that falls behind
simply skips to the freshest frame:
1. **Acquisition** — `sweep_orchestrator` (or a hardware-specific producer)
configures the radar, performs the frequency sweep, and publishes raw S11/S21
traces.
2. **Preprocessing** — `data_preprocessor` applies through/OSL calibration,
reference subtraction, and optional frequency-domain notch filtering.
3. **Processing** — `data_processor` runs the selected processing mode and emits
results (pass-through traces, B-scan images, GPR images with detected objects,
or 3D SAR views). Detected objects are additionally broadcast to subscribers
over a TCP locator server.
The **Python application** (`python_app`) starts and monitors the C++ binaries,
reads the result rings, renders the live view with pyqtgraph, and exposes the same
controls plus a pixel-identical live plot through an embedded web UI.
```
radar hardware
│
▼
Acquisition ──[raw ring]──▶ Preprocessing ──[preprocessed ring]──▶ Processing ──[result ring]──▶ GUI / Web
│
└──▶ TCP locator (detected objects)
```
## Supported hardware
- **librevna** — single LibreVNA.
- **librevna_multi** — synchronized multi-device LibreVNA.
- **compact_m_k209** — Compact-M K209 / S2VNA (including Raspberry Pi remote mode).
- **sn9000** — SNVNA SN9000 over VISA (pure-Python `@py` backend).
- **kamil_adc** — external Kamil ADC acquisition process, with optional laser control.
- **mock / simulator** — driver-less mode for development without hardware.
## Processing modes
- **pass_through** — magnitude and phase of the selected channel for each combo.
- **bscan** — depth-versus-sweep B-scan heatmap.
- **gpr** — coherent back-projection GPR imaging with object detection.
- **legacy_gpr** — ellipse-intersection MIMO localization (point and extended/region modes).
- **sar3d** — 3D SAR of the reference notebook `Multi_antenna_3D_clean_v1.ipynb`
on an NVIDIA GPU: front (X-Y), side (Z-Y), top (X-Z) and 3D views of the imaged
volume. Its settings carry the notebook's parameter names; the scene window is
fixed (X −2…2 m, height −0.5…2 m above the ground), its range extent follows
`MIN_DEPTH`/`MAX_DEPTH`, and the voxels are cubes with edge `SAR_VOXEL_M`
(default 2 cm). The radar motion is corrected from each trace's capture
timestamps, so the sweep timing needs no parameters.
## Repository layout
| Path | Contents |
| --- | --- |
| `data_acq_and_processing/` | C++ pipeline: `sweep_orchestrator/`, `preprocessing/`, `processing/` (including `locator/`), shared `common_cpp/` (config, IPC rings), and vendored `third_party/` (Eigen, nlohmann/json). |
| `python_app/` | Python application: `gui/`, `orchestration/` (process supervisor, shared-memory readers, config), `hardware_full/` (device drivers and services), `webui/`, `storage/`, `models/`, `workflows/`, `scripts/` (producers and tools), and `tests/`. |
| `run_config_examples/` | Ready-made configuration profiles, one per hardware setup. |
| `deploy/` | systemd daemon installer, and the USB update kit for the Pi and Jetson (`pack-usb.sh`, `update.sh`). |
| `build/bin/` | Compiled C++ binaries. |
| `device_firmware/`, `docs/` | Device firmware and vendor manuals. |
## Requirements
- Linux (POSIX shared memory; GPIO on Raspberry Pi). The deployment target is a
**Raspberry Pi 5**; hardware PWM gating for the generator sweep is Pi 5
specific (GPIO12/13/18/19, `dtoverlay=pwm-2chan`).
- A C++20 compiler and `make` — Eigen and nlohmann/json are vendored, so no extra C++ dependencies are needed.
- **Python 3.10 or newer**, in a virtual environment.
- For the `sar3d` processor: an NVIDIA GPU with its driver (`libcuda`). The
kernels are compiled at run time by NVRTC, so there is no nvcc step; `make`
needs only `nvrtc.h`, `cuda.h` and `libnvrtc`, taken from the pip
`nvidia-cuda-*` packages in `.venv` (`requirements.txt`, x86_64; CUDA 13 covers
Turing and newer GPUs) or from a system toolkit in `/usr/local/cuda` (Jetson).
Without them everything else still builds, and sar3d reports that CUDA is
missing — a Raspberry Pi needs none of it.
## Build and run
From the repository root:
```bash
python3 -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install -r requirements.txt
make # build the C++ binaries into build/bin/
```
`make` builds the sar3d GPU code when it finds CUDA (see Requirements) and
prints a note when it does not. After installing the CUDA requirements into an
existing venv, run `make` again: it notices the change and rebuilds that part.
Run the desktop GUI:
```bash
.venv/bin/python -m python_app.gui.main
# or, with the build step and single-instance handling:
./start.sh
```
`start.sh` supports `--headless` (offscreen, auto-start — for unattended Pi use),
`--profile PATH`, `--producer-only`, `--skip-build`, and `--clean-shm`; see
`./start.sh --help`. The acquisition device (LibreVNA, Kamil ADC, …) is detected
automatically from the active config's `radar.model` — there is no per-device flag.
## Jetson (aarch64) bring-up
Ubuntu 22.04 on Jetson has glibc 2.35, and PyQt6 6.8+ ships only
`manylinux_2_39` aarch64 wheels — `requirements.txt` therefore pins PyQt6 to
`<6.8` on aarch64 (6.7.1 is the last release with a compatible wheel). With
that pin the stock `./start.sh` provisioning works; the extra steps are only
for the CUDA-backed `sar3d` processor:
```bash
# 1. copy the replay dataset (for dataset-replay profiles) and point
# radar.replay.dataset_dir in the profile at the local copy — the path in
# run_config_examples/*.json is machine-specific.
# 2. normal launch; make takes the JetPack CUDA from /usr/local/cuda
# (requirements.txt installs no pip nvidia-* packages on aarch64) and the
# driver's /usr/lib/aarch64-linux-gnu/nvidia/libcuda.so.1:
./start.sh --profile run_config_examples/run_config_replay_vna.example.json
```
Ubuntu 22.04 ships Python 3.10, and the host parses the radar stream in Python:
the same parsing code ran 1.6 times slower on 3.10 than on 3.13 (the Pi's version)
in a benchmark. Use Python 3.13 for the venv, installed with uv so the system
`python3` stays untouched (apt depends on it):
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh # then open a new terminal
uv python install 3.13
bash radar_update/update.sh --python 3.13 # see Deployment
```
## Running without hardware (emulation)
Two ways to run the full pipeline with no radar attached:
**Mock producer (synthetic data).** The default `run_config.json` already sets
`radar.driver_mode: "mock"`, so the producer generates synthetic S-parameters.
The preprocessor still requires S21 calibration/reference sets; create them once:
```bash
.venv/bin/python -m python_app.scripts.manual_smoke_run --duration 1.0 # creates smoke_cal/smoke_ref
./start.sh # then in the GUI: Preprocessing Panel -> pick the sets -> Start
```
(Alternatively use the GUI's "Create neutral sets" button, which makes
identity calibration + zero reference so preprocessing is a pass-through.)
**Dataset replay (recorded scene, meaningful sar3d picture).** When
`radar.replay.dataset_dir` is set in the profile, the supervisor launches
`python_app.scripts.replay_raw_producer` instead of the normal producer: it
replays recorded snapshots into the raw ring at the recorded cadence, looping
forever with a monotonic timeline. Pair it with NEUTRAL preprocess sets so the
already-preprocessed recording passes through the preprocessor bit-exactly.
A ready profile for the VNA_AlGo tank005 dataset is provided:
```bash
# one-time: neutral sets for this profile (or use the GUI button)
.venv/bin/python -m python_app.scripts.create_neutral_preprocess_sets \
--config run_config_examples/run_config_replay_vna.example.json
# interactive GUI (mode sar3d is pre-selected by the profile's gui section):
./start.sh --profile run_config_examples/run_config_replay_vna.example.json
```
The sar3d processor keeps about 75 MB of buffers on the GPU at the default
2 cm voxel and depth 2…8 m (plus the CUDA context). The volume grows as
1/`SAR_VOXEL_M`³: 1 cm takes about 600 MB and ran about 6 times slower in
testing. If the GPU has no room, it logs the CUDA error once and publishes empty
results until memory frees.
The web interface is served in-process at `http://<host>:8080`. It mirrors the live
plot and offers Start / Stop / Capture controls and the active processor settings.
## Configuration
The active profile is `run_config.json`. It selects the radar model and sweep, the
switch matrix and acquisition combos, the preprocessing calibration/reference
assets, the GPR geometry, and the shared-memory ring sizes. Profiles for each
hardware setup are provided in `run_config_examples/` — copy one to
`run_config.json`, or pass it with `--profile`, to use it.
## Deployment
On a Raspberry Pi, `deploy/install-daemon.sh` installs a systemd service that runs
the application headless and restarts it on failure. A single-instance lock ensures
the interactive GUI and the daemon never run at the same time, since they share the
radar, the shared-memory rings, and the locator port.
**Updating a device from a USB flash drive.** On the development machine
`deploy/pack-usb.sh` writes the host part of the last commit (no venv, build, data
or local configs) and the update script into `radar_update/` on the flash drive.
On the Pi or Jetson, close the program and run, from the drive's folder:
```bash
bash radar_update/update.sh # or: --python 3.13 for a fresh venv
```
It installs the newest archive into `~/Documents/radar_system` (or `RADAR_DIR`);
the current version is renamed to `radar_system<N>`, the next free number. Kept from
it: `run_config.json`, profiles in `run_config_examples/` changed or added on the
device (the release version of a changed one lands next to it as `.new`),
`python_app/runtime/` without logs, `python_app/data*` and any other top-level
folder that is not part of the release, as hard links. Then it carries the venv over
(or builds a new one with `--python`), builds the C++ part and restarts
`radar.service` if it was running. To go back:
`rm -rf radar_system && mv radar_system<N> radar_system`.
## Tests
```bash
.venv/bin/python -m unittest discover -s python_app/tests
```