# xSTEM Scope — осциллограф из школьного датчика НАУРА

«Датчик напряжения осциллографический» фирмы НАУРА (на этикетке логотип **НаР**)
поставлялся в школы с программой для Windows. На компьютерах под Linux он
лежит без дела: родная программа запускается только через Wine, а драйвер FTDI
под Wine не работает. На самом деле Linux видит датчик сразу, без драйверов,
как `/dev/ttyUSB0`.

xSTEM Scope — страница-осциллограф, которая работает с этим датчиком напрямую.

## Два способа запуска

| | С сайта | Программа на компьютере |
|---|---|---|
| Как открыть | [edu.xstem.ru/scope](https://edu.xstem.ru/scope/) | ярлык «xSTEM Scope» или `python3 xstem-scope.py` |
| Браузер | Chromium, Chrome, Edge, Firefox (проверен 158) | любой |
| Интернет | нужен, чтобы открыть страницу | не нужен |
| Установка | не нужна\* | не нужна\*, на весь класс — по SSH, [GUIDE.md](GUIDE.md) |
| Обновление | само, вместе с сайтом | `git pull` и повторная раздача |

\* Один раз нужен доступ к порту датчика для обычного пользователя — правило udev
из [`deploy/install.sh`](deploy/install.sh) или группа `dialout`
([WIRING.md](WIRING.md#если-не-работает)).

### С сайта

1. Подключите датчик к USB.
2. Откройте в Chromium **https://edu.xstem.ru/scope/**.
3. Нажмите «Подключить датчик» и выберите в окне браузера **FT232R USB UART**.
   В следующий раз страница подключится сама.

Браузер получает доступ только к тому устройству, которое выбрал человек, и
только для этого сайта. Отозвать доступ — значок слева от адреса → «Сбросить
разрешения».

### Программа на компьютере

Нужен только Python 3 — он есть на любом школьном Linux.

1. Скачайте в одну папку пять файлов:
   [`xstem-scope.py`](app/xstem-scope.py), [`index.html`](app/index.html),
   [`xstem-scope.js`](app/xstem-scope.js), [`b202.json`](app/b202.json),
   [`experiments.json`](app/experiments.json).
2. Подключите датчик к USB и выполните в этой папке:
   ```
   python3 xstem-scope.py
   ```
3. Браузер откроет `http://localhost:8765` сам. Остановить программу — `Ctrl+C`.

Если датчик не находится, программа скажет почему. Частые случаи разобраны в
[WIRING.md](WIRING.md#если-не-работает).

## Что умеет

| | |
|---|---|
| Каналы | 2, каждый со своим пределом: ±2 В, ±5 В, ±25 В, ±90 В |
| Оцифровка | от 200 Гц до 100 кГц (точка через 5 мс … 10 мкс) |
| Кадр | 3072 точки на канал: от 31 мс до 15 с записи |
| Самописец | лента 10, 30 или 60 с вживую, при точке через 0,5 мс и реже; разрывы 2–19 % времени |
| Синхронизация | по К1 или К2, по фронту или спаду, уровень в вольтах |
| Вход | постоянный (=) или переменный (~) ток |
| Замеры | максимум, минимум, размах, среднее, действующее, частота, период; если частота найдена, среднее и действующее — по целому числу периодов |
| Растяжка | ×1…×20; «Сдвиг окна» под графиком ведёт растянутое окно по всему кадру |
| Курсоры | два курсора: время, напряжения, Δt и 1/Δt; держатся за время сигнала, а не за место на экране |
| Экспорт | CSV для LibreOffice Calc / Excel |
| Опыты | готовые настройки для труда и физики, см. [Lesson.md](Lesson.md); новый опыт — строка в [`experiments.json`](app/experiments.json) |
| Датчик выдернули | измерение останавливается; вставьте датчик и нажмите «Пуск» — программу перезапускать не нужно |
| ESP32 | с прошивкой генератора из `src/` — синусоида, треугольник, пила, ШИМ со страницы; со скетчем урока 9 — поле «Слово по UART»: ученик вписывает слово и читает его с провода. Что прошито, страница узнаёт сама |

## Файлы

| Файл | Что это |
|---|---|
| [`app/index.html`](app/index.html) | экран осциллографа: он же страница на сайте |
| [`app/xstem-scope.js`](app/xstem-scope.js) | протокол датчика; связь через Web Serial или через программу |
| [`app/xstem-scope.py`](app/xstem-scope.py) | программа: открывает порт и отдаёт страницу, только стандартная библиотека Python |
| [`app/b202.json`](app/b202.json) | всё, что известно о датчике: скорости, периоды, пределы и калибровка каждого экземпляра по серийному номеру; читают и страница, и программа |
| [`app/experiments.json`](app/experiments.json) | опыты в списке «Опыт»: настройки и подсказка, по группам «Труд», «Физика», «Прибор» |
| [`tests/`](tests/test_protocol.py) | проверка протокола без железа: одни и те же примеры через JS и Python, запускается в CI |
| [`deploy/`](deploy/install.sh) | установка на один ПК и на весь класс по SSH, см. [GUIDE.md](GUIDE.md) |
| [`src/main.cpp`](src/main.cpp) | прошивка ESP32: генератор эталонных сигналов для проверки и калибровки |
| [`examples/lesson9/`](examples/lesson9/main.cpp) | скетч урока «UART и I2C»: UART и медленный I2C в одной программе; команды `char`, `text`, `baud`, `addr` — в мониторе порта или со страницы; `pio run -e lesson9 -t upload` |
| [THEORY.md](THEORY.md) | как устроен датчик и как мы разгадали его протокол |
| [WIRING.md](WIRING.md) | подключение, безопасность, калибровка |
| [Lesson.md](Lesson.md) | опыты для уроков труда и физики |
| [GUIDE.md](GUIDE.md) | развёртывание в классе и памятка группе |
| [ROADMAP.md](ROADMAP.md) | осциллограф в программе 5–9 классов и в проектах; датчик НАУРА и Rigol |

## Ограничения

- Датчик отдаёт кадр целиком, только когда запишет все 3072 точки. На медленной
  развёртке (кадр 3–15 с) график появляется с задержкой, пока идёт запись,
  внизу экрана бежит полоска. Чтобы видеть вживую — режим «Самописец»: датчику
  ставится короткий кадр (0,5 с), страница склеивает их в ленту. Пока датчик
  передаёт кусок, он не пишет: около 0,12 мс на каждую точку куска, то есть
  2 % времени при точке через 5 мс и 19 % при 0,5 мс. Эти места на графике —
  разрывы, в CSV — пустые ячейки.
- Общая калибровка снята с одного экземпляра датчика по питанию ESP32 3,3 В,
  точность около 3 %. Датчику можно записать свою калибровку по серийному
  номеру ([WIRING.md](WIRING.md#калибровка)); в заголовке страницы видно,
  какая сейчас действует.
- Проверено на модели B202 с прошивкой 3.02 (2011 год). Модель и прошивку
  страница пишет в заголовке.

### Что датчик успевает увидеть

Самая частая точка — через 10 мкс (100 кГц). Правило: на самую короткую
деталь сигнала нужно хотя бы 5 точек, иначе фронты превращаются в «пилу», а
частые импульсы — в сплошную стену со стробоскопическими узорами. Всё, что
быстрее, — для Rigol.

| Сигнал | Самая короткая деталь | Точек при 10 мкс | Видно? |
|---|---|---|---|
| UART 9600 | бит 104 мкс | 10 | да, байт читается (проверено) |
| UART 19200 | бит 52 мкс | 5 | на пределе: биты различимы, фронты грубые (расчёт) |
| UART 38400 | бит 26 мкс | 2–3 | соседние биты сливаются (расчёт) |
| UART 115200 | бит 8,7 мкс | меньше 1 | нет |
| I2C 100 кГц | такт 10 мкс | 1 | нет — поэтому в уроке шина замедлена до 1 кГц |
| ШИМ 1 кГц, 25 % | импульс 250 мкс | 25 (при 20 мкс — 12) | да (проверено); при точке 100 мкс — «стена» и 26,5 % вместо 25 % |
| WS2812, SPI, фронты логики | десятки–сотни нс | — | нет, только Rigol |

Ещё три особенности, найденные на железе:

- Кадр с синхронизацией начинается примерно через 15 мкс после фронта:
  первый импульс на экране короче настоящего. Длительность меряйте между
  фронтами внутри сигнала.
- В кадре 3072 точки: при 10 мкс это 30,7 мс — примерно 28 байт UART 9600
  подряд, если их слать без пауз.
- Первые 3–4 с после подключения к USB датчик мерит со своими настройками;
  программа эти секунды выжидает сама
  ([THEORY.md](THEORY.md#как-мы-разгадали-протокол)).
