Lidar_Muxa/README.md
Данил Омелечко b8e95eccbe ML-ядро детектора: конвейер на схемах мозга дрозофилы
Ретина, ламина, медулла, лобула, грибовидное тело, веерное тело,
центральный комплекс, нисходящие нейроны. Обучение памяти тоннеля и
считывания MBON, оценка leave-one-bag-out, полигон дальности, 24 теста.

Реальный объект на 55 м — 98.9 % кадров, ложных 7.5 трека на км,
кадр обрабатывается за 33 мс на CPU.
2026-09-21 17:24:25 +03:00

160 lines
8.9 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.

# FlyGuard · ML-ядро
Обнаружение посторонних объектов в тоннеле метро по данным 3D-лидара
Hesai Pandar128. Кейс 05, ЛЦТ-2026.
Это **ядро обработки**: облако точек на входе, решение о препятствии на выходе.
Узел ROS 2, транспорт, контейнер и визуализация живут отдельно и сюда не
входят — ядро от них не зависит и проверяется без ROS вообще.
---
## Чем это не является
Не нейросетевой детектор общего назначения. Конвейер собран по схемам
зрительной системы дрозофилы, и каждая стадия — это конкретный нейропиль с
конкретной функцией, а не слой, подобранный перебором:
```
облако точек 0.3–0.9 млн, 10 Гц
│
├─ RETINA омматидиальная решётка → дальностный образ 128 × N
├─ HALTERES плоскость рельсов: крен, тангаж, высота сенсора
├─ LAMINA диспаритет 1/R → ON/OFF, центр-окружение на 3 масштабах
├─ MEDULLA / LP T4/T5 → LPTC: скорость поезда без одометрии
├─ LOBULA LC11: кандидаты; разрез компоненты по контрасту
├─ MUSHROOM BODY KC → APL → MBON: новизна формы (без меток)
│ + обученное считывание MBON (с метками из физики)
├─ FAN-SHAPED BODY накопление лучей в координатах пути
├─ CENTRAL COMPLEX накопление улик в координатах пути, треки
└─ DESCENDING два порога с гистерезисом → решение
```
Ничего про геометрию сенсора не захардкожено: решётка лучей, высота установки,
крен и тангаж **калибруются по самим данным** на первых кадрах. В записях
встречаются две раскладки скана (3600 азимутов на 360° и 1200 на 120°) и две
высоты установки (1.31 и 1.70 м) — ядро работает с обеими без правок.
---
## Что нужно интеграции: один класс, один вызов
```python
from flyguard.pipeline import FlyGuard, Params
from flyguard.mushroom_body import MushroomBody
from flyguard.mbon_readout import MbonReadout
fg = FlyGuard(Params(),
memory=MushroomBody.load("artifacts/mushroom_body.npz"),
readout=MbonReadout.load("artifacts/mbon_readout.npz"))
res = fg.process(cloud) # cloud: flyguard.cdr.PointCloud2
if res is None:
... # первые 12 кадров уходят на калибровку решётки
else:
d = res.decision # detected, distance, confidence, emergency, objects
res.total_ms # время обработки кадра
```
Требования к входу: `flyguard.cdr.PointCloud2` — поля `x, y, z, intensity`,
порядок точек как в сыром CDR. Конвейер **хранит состояние между кадрами**
(решётка, плоскость пути, ось пути, треки, накопитель), поэтому один экземпляр
обслуживает один поток данных; для параллельных сценариев нужны разные
экземпляры.
Выход `Decision`: `detected`, `distance` (м), `confidence` (0…1),
`emergency` (флаг экстренного торможения), `objects` (список подтверждённых
треков с id, дистанцией и габаритами).
Всё считается на **CPU**, GPU не требуется. Медиана обработки кадра — 33 мс
при бюджете 100 мс.
---
## Структура
```
flyguard/ ядро: стадии обработки, память, считывание
bag.py cdr.py чтение rosbag2 и разбор CDR без ROS
retina.py geometry.py решётка лучей, плоскость рельсов, ось пути
lamina.py medulla.py контраст, движение
lobula.py кандидаты
mushroom_body.py память тоннеля (без меток)
mbon_readout.py обученное считывание (с метками)
fan_body.py накопление в координатах пути
central_complex.py треки и улики
descending.py решение
pipeline.py сборка
synth.py вставка предметов трассировкой лучей
tools/ обучение, оценка, разбор
tests/ 27 тестов, запускаются без данных и без ROS
docs/ методика и результаты
artifacts/ обученные модели
```
---
## Как запустить
```bash
pip install -r requirements.txt
pytest tests -q
```
Записи лидара в репозиторий не кладутся. Положите их рядом
(`../data/for_hackathon/...`) или укажите путь:
```bash
set FLYGUARD_DATA=D:\lidar\data
```
Обучение и оценка:
```bash
python tools/make_training_set.py # размеченная выборка
python tools/train_mbon.py --device cuda --baseline # считывание MBON
python tools/evaluate.py --mbon-dir artifacts/mbon_folds # ложные тревоги
python tools/make_benchmark.py --memory artifacts/mushroom_body.npz
python tools/plot_benchmark.py # дальность обнаружения
```
---
## Где мы сейчас
| Метрика | Значение | Чем измерено |
|---|---|---|
| Реальный объект 0.67 × 1.35 м на 55 м | **98.9 %** кадров | `tools/check_obstacle.py` |
| Ложные тревоги, leave-one-bag-out | **7.5 трека на км**, 16.7 % кадров | `tools/evaluate.py` |
| То же на новой линии, без обученной памяти | 21.8 на км | там же, холодный старт |
| Рабочая дальность (полигон, 14 004 наблюдения) | **100 м** человек стоя, P@50 = 0.70 | `tools/plot_benchmark.py` |
| Обработка кадра | медиана 33 мс из бюджета 100 мс | `tools/run_pipeline.py` |
| Разделение «знакомое / новое» | ROC AUC 0.905 | `tools/tune_memory.py` |
Проверка всегда **leave-one-bag-out**: память обучается на всех записях, кроме
проверяемой. Иначе цифры лгут — подавлять конструкции, которые сам же и
запомнил, умеет кто угодно, а на приватном тесте будет новый участок.
---
## Что честно не работает
Разобрано замерами, подробности — в `docs/EXPERIMENTS.md`:
* **За 200 м на этих участках не увидит никто**: прямая видимость в тоннелях
121–167 м, дальше линия взгляда упирается в стену кривой. На отдельных
перегонах и того меньше — 49–90 м.
* **Мелкие предметы на большой дальности невозможны с этим сенсором**: ведро
(0.1 м²) на 160–190 м даёт один луч, каска и бутылка — ноль.
* **За 80–90 м прирельсовая зона не наблюдается вовсе**: луч скользит по
полотну, и самая низкая видимая точка у оси пути оказывается выше головки
рельса на 0.1–0.6 м.
* Привыкание внутри проезда сделано и **отвергнуто замером** — п. 10.
---
## Документация
* `docs/ALGORITHM.md` — что делает каждая стадия и почему именно так.
* `docs/EXPERIMENTS.md` — все замеры, включая отрицательные результаты.
* `docs/CONNECTOME.md` — что взято из коннектома как число, а что как идея.