Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ target/
run*.csv
*.tflite.tmp
/backlog
windows.csv
64 changes: 62 additions & 2 deletions docs/eng/bench-assembly.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,45 @@ Why exactly this: the top leg's drop at zero current is 2.5 V → GPIO4 sees
headroom on both sides. Rows 20–22 keep the divider as a self-contained
block — easier to probe with a multimeter.

A multimeter check before the USB power-up: between the GPIO4 jumper and
(−) — about 1.2–1.3 V with the machine off (that is the ACS712's "zero").
A multimeter check (USB plugged in — the board powers the module, the
machine off): between the GPIO4 jumper and (−) — about 1.2–1.3 V when the
module runs on 5 V (that is the ACS712's "zero"; on 3V3 it is roughly half
as much — the `zero` norms are in 4b).

Continuity check (power off): mid↔top ≈ 10 kΩ and mid↔bottom ≈ 10 kΩ
(0 Ω — a resistor is shorted: both legs landed in the same row);
bottom↔the board's GND ≈ 0 Ω.

Rows 20–22 are not a dogma: any three neighboring rows work, but on one
side of the center groove (the groove splits a row in half — a chain
crossing it is not connected).

A note from the bring-up bench (2026-09-16): the DevKitC-1 clone's 5V pin
is dead (0.14 V) — the ACS712 module is temporarily powered from 3V3;
the `zero` norms for that case are in 4b.

### 4b. Diagnosing by `zero=` (one line per boot)

`a: zero=NNN` is printed at firmware startup — the average of 800 ADC
reads over 0.5 s of rest (`firmware/a/src/main.rs`); the scale: 4095
counts = 3.1 V (`features-cli/src/calibration.rs`). Bench-refined
guidelines:

| `zero` | What GPIO4 sees |
| ------------------ | ------------------------------------------------------------------------------------------------------------ |
| 750–850 | the divider midpoint, the module on 3V3 — the norm (the bring-up bench) |
| ~1300–1650 | the divider midpoint, the module on 5 V — the norm |
| 1900–2200, stable | OUT past the divider: the tap is not in the middle row, a resistor is shorted, or the bottom is not grounded |
| ~0 | the divider top does not arrive: no OUT or no module power |
| 4095 | the input is pinned to a supply rail or the pin floats |
| jumps boot to boot | a floating contact |

The bench case (2026-09-16): `zero=1966` — 1.49 V, exactly the top of the
ladder (OUT). While the pin sees OUT past the divider, the firmware
doubles the amplitudes (`divider = 2.0` in the calibration): a 2 A run
looks like ~4 A, the model confuses run/overload; idle stays honest —
the zero is subtracted at startup. The fix is the 4a continuity check
and the diagnosis table above.

## 5. Node Q — sound and the tapper (DevKitC-1 #2)

Expand Down Expand Up @@ -360,6 +397,29 @@ Per the shakedown decomposition sessions
5. **S6**: node P — a run of N parts, the count = N, bouncing gives no
repeats.

## 9a. The "it does not work — why" cheat sheet

| Symptom | Cause | Fix |
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| garbage in UART | wrong baud / the wrong port | 115200, the bridge's port (not OTG) |
| the board won't flash | not in boot mode | hold BOOT while plugging in |
| the servo twitches, the board reboots | no common GND / no capacitor | tie the grounds, add the 470 µF |
| node A's readings drift | ACS712 zero drift | start the firmware with the machine off |
| GPIO4 voltage ≈ OUT, not the midpoint | a resistor shorted (both legs in one row), the tap not in the middle row, or the bottom not grounded | the 4a continuity check; the `zero` diagnosis — 4b |
| node A's readings are garbage | no wire (-) rail → the board's GND | check the ground net (section 3) |
| the machine's motor does not spin | the loop is open: only one wire got into the clamp | check IP+ and IP− — both in the cut |
| the boot log is visible, but no `a: boot` | the cable is in the native "USB" port (by-id `usb-Espressif`) | replug into "COM"; the bridge is by-id `usb-1a86*` |
| `cat` on the port is silent after a replug | the replug reset the baud to the default (9600) | `stty ... && cat` as one line, no pause |
| the gauges are empty with node A alive | the aggregator on the default `--expect a,p,q` | restart with `--expect a` (the watermark at zero) |
| the aggregator died at ~31 s of silence | a pre-2026-09-15-fix binary | rebuild (`PING_AFTER=15 s`); the card in backlog/done |
| P overcounts | bouncing | the 50 ms debounce is in the firmware already; check the pot |

The step-by-step shakedown order (S0–S7) —
[`HARDWARE-assembly-guide.md`](./HARDWARE-assembly-guide.md) and
[`decompose/firmware-shakedown-runbook.md`](./decompose/firmware-shakedown-runbook.md);
the first bring-up facts (2026-09-14, all three boards alive) —
`firmware/NOTES.md`.

## 10. Safety

- The sensors and the INA226 — only into circuits ≤36 V (the machine/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Агрегатор умирает на 30-секундной тишине живого стенда (ping = idle-cut брокера)

- **Серьёзность**: важно
- **Компонент**: oee-aggregator (+ mqtt-min — контрагент)
- **Источник**: живой стенд, S1 узла A → фаза 2, 2026-09-15
- **Локация**: `oee-aggregator/src/aggregator.rs` (`PING_AFTER`), контрагент — `mqtt-min/src/testing.rs` (`serve_connection`, read timeout 30 с)

## Сценарий

Живой стенд (не реплей): узел A — событийный, строки `a,bench-a,<t>,<state>` уходят только при подтверждённой смене состояния. Мотор работает ровно → поток молчит дольше 30 секунд → ожидающий сообщений агрегатор не отправляет брокеру ни байта.

## Поведение

Ровно на 31-й секунде простоя агрегатор падал: `Error: aggregating from 127.0.0.1:1883: mqtt protocol violation: peer closed the connection`. Воспроизведено изолированно (свежий брокер + агрегатор, `--expect a --minute-ms 10000`, таймаут 60 с): EXIT=1 AFTER 31s — с тем же текстом.

## Последствие

Переподключения у агрегатора нет («mid-run disconnects abort the run», так задокументировано в `bin/aggregator.rs`) — конвейер недели 5 против физического стенда рвался при любой паузе длиннее 30 с. В реплей-бенче не всплывало: плотный поток → после каждого сообщения агрегатор сам публикует snapshot → вход брокера никогда не молчит 30 с.

## Корень

`PING_AFTER = 30 с` («половина negotiated keepalive 60 с») против фиксированного read timeout 30 с внутри брокера (брокер keepalive из CONNECT не читает). Равные таймеры: чтобы отправить пинг, агрегатор должен сначала проснуться от своего 5-секундного read-таймаута — брокерский cut всегда наступает на микросекунды раньше. Фотофиниш проигран конструктивно.

Сюда же: дашборд (`oee-dashboard/src/mqtt.rs`) не пингует вовсе — брокер режет его каждые 30 с даже при трафике (важны пакеты от клиента), но reconnect-цикл (1 с) + snapshot-дизайн делают churn незаметным.

## Как исправлено (2026-09-15)

`PING_AFTER: 30 с → 15 с` + комментарий у константы с привязкой к 30-с idle-cut брокера. Проверка: 60-секундный idle-тест — EXIT=124 (внешний timeout, ошибок нет, до фикса — Error на 31 с); `cargo test -p oee-aggregator` — 5 passed.

Отложено: инвариант-тест `PING_AFTER < IDLE_READ_TIMEOUT` (требует выноса литерала таймаута из `serve_connection` в публичную константу mqtt-min); `send_ping` в idle-ветке дашборда.
61 changes: 59 additions & 2 deletions docs/rus/bench-assembly.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,43 @@ GPIO4 приходит 1.25 В (ADC 11 дБ, диапазон до ~3.1 В); п
будет 2.25 В — запас с обеих сторон. Ряды 20–22 держат делитель отдельным
блоком — проще найти мультиметром.

Контроль мультиметром до включения USB: между GPIO4-джампером и (−) —
около 1.2–1.3 В при выключенном станке (это и есть «ноль» ACS712).
Контроль мультиметром (USB воткнут — плата питает модуль, станок выключен):
между GPIO4-джампером и (−) — около 1.2–1.3 В при питании модуля от 5 В
(это и есть «ноль» ACS712; при питании от 3V3 — примерно вдвое меньше,
нормы `zero` — в 4б).

Прозвонка (питание отключено): середина↔верх ≈ 10 кОм и середина↔низ ≈
10 кОм (0 Ом — резистор закорочен: обе ножки угодили в один ряд);
низ↔GND платы ≈ 0 Ом.

Ряды 20–22 — не догма: годятся любые три соседних ряда, но на одной
стороне центральной канавки (канавка разрывает ряд пополам — цепочка,
пересекающая её, не соединена).

Примечание обкаточного стенда (2026-09-16): у клона DevKitC-1 пин 5V
мёртв (0.14 В) — модуль ACS712 временно питается от 3V3; нормы `zero`
для этого случая — в 4б.

### 4б. Диагностика по `zero=` (одна строка на boot'е)

`a: zero=NNN` печатается на старте прошивки — среднее 800 замеров АЦП
за 0.5 с покоя (`firmware/a/src/main.rs`); шкала: 4095 counts = 3.1 В
(`features-cli/src/calibration.rs`). Ориентиры, уточнённые на стенде:

| `zero` | Что видит GPIO4 |
| ------------------------- | ---------------------------------------------------------------------------------------------- |
| 750–850 | середина делителя, модуль на 3V3 — норма (обкаточный стенд) |
| ~1300–1650 | середина делителя, модуль на 5 В — норма |
| 1900–2200, стаб | OUT напрямую, мимо делителя: отвод не из среднего ряда, резистор закорочен или низ не на земле |
| ~0 | верх делителя не доходит: нет OUT или питания модуля |
| 4095 | вход прижат к шине питания или пин висит |
| скачет от boot'а к boot'у | плавающий контакт |

Кейс стенда (2026-09-16): `zero=1966` — 1.49 В, ровно верх лестницы
(OUT). Пока пин видит OUT мимо делителя, прошивка удваивает амплитуды
(`divider = 2.0` в калибровке): run 2 А выглядит как ~4 А, модель путает
run/overload; idle остаётся честным — нуль вычитается при старте.
Лечение — прозвонка по 4а и диагнозы таблицы выше.

## 5. Узел Q — звук и таппер (DevKitC-1 №2)

Expand Down Expand Up @@ -337,6 +372,28 @@ TCRT5000 ×2 (в модуле уже компаратор, резисторы н
отдельный); вердикт по звуку на эталонных деталях.
5. **Э6**: узел P — прогон N деталей, счёт = N, дребезг не даёт повторов.

## 9а. Шпаргалка «не работает — почему»

| Симптом | Причина | Лечение |
| -------------------------------------- | ------------------------------------------------------------------------------------------ | -------------------------------------------------------- |
| мусор в UART | неверный baud / не тот порт | 115200, порт моста (не OTG) |
| плата не шьётся | не в boot-режиме | зажать BOOT при подключении |
| серво дёргается, плата ребутится | нет общего GND / конденсатора | соединить минусы, поставить 470 мкФ |
| показания A плывут | дрейф нуля ACS712 | стартовать прошивку при выключенном станке |
| на GPIO4 напряжение ≈ OUT, не середина | резистор закорочен (обе ножки в одном ряду), отвод не из среднего ряда или низ не на земле | прозвонка по 4а, диагноз по `zero` — 4б |
| показания A — мусор | нет провода шина (−) → GND платы | проверить земляную сеть (разд. 3) |
| мотор станка не крутится | петля разомкнута: в зажим попал только один провод | проверить IP+ и IP− — оба в разрезе цепи |
| boot-лог виден, а `a: boot` нет | кабель в нативном «USB»-порту (by-id `usb-Espressif`) | перетыкнуть в «COM»; мост — by-id `usb-1a86*` |
| `cat` порта молчит после перетыка | перетык сбросил baud в дефолт (9600) | `stty ... && cat` одной строкой, без паузы |
| гейджи пустые при живом узле A | агрегатор с дефолтным `--expect a,p,q` | перезапустить с `--expect a` (водяной знак на нуле) |
| агрегатор упал на ~31-й секунде тишины | старый бинарчик до фикса 2026-09-15 | пересобрать (`PING_AFTER=15 с`); карточка в backlog/done |
| P считает лишнее | дребезг | антидребезг 50 мс уже в прошивке; проверить потенциометр |

Порядок обкатки по шагам S0–S7 —
[`HARDWARE-assembly-guide.md`](./HARDWARE-assembly-guide.md) и
[`decompose/firmware-shakedown-runbook.md`](./decompose/firmware-shakedown-runbook.md);
факты первой обкатки (2026-09-14, все три платы живы) — `firmware/NOTES.md`.

## 10. Безопасность

- Датчики и INA226 — только в цепи ≤36 В (БП станка/конвейера). Сеть 220 В —
Expand Down
Loading