Initial commit: project docs and wiring diagram

Smart bench press trainer with electric motor (M365 Pro).
CAN Bus architecture: ESP32-S3 (master) + Flipsky 75100 (VESC) + STM32 Blue Pill (carriage).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
sm
2026-02-25 19:03:55 +03:00
commit c76ca89cc9
5 changed files with 812 additions and 0 deletions

24
.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Build artifacts
build/
*.o
*.elf
*.bin
*.hex
*.map
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# PlatformIO
.pio/
# Archives
*.zip

55
CHANGELOG.md Normal file
View File

@@ -0,0 +1,55 @@
# CHANGELOG — История проектных решений
## v1 → v2: Расчёт мотора и барабана
- Выбран барабан D30мм (оптимум по расчёту: 100кг при 30А рабочих)
- Рассчитаны константы мотора M365 Pro (Kt, Ke, R, KV)
- Кабестан 3 витка, μ=0.25 — коэффициент удержания 14.1
- Контроллер: MKS VESC Mini 6.7 Pro (первоначальный выбор)
- Батарея 48В 500Вт·ч (автономная работа)
## v2 → v3: Waveshare ESP32-S3 Touch LCD 3.5"
- **Замена:** ESP32 + OLED + RTC + TF → Waveshare ESP32-S3 Touch LCD 3.5" (~$20)
- Плата включает: 3.5" IPS тачскрин, QMI8658 IMU, PCF85063 RTC, AXP2101 PMU, TF слот
- ESP32-S3 имеет TWAI (аппаратный CAN) — нужен только трансивер SN65HVD230
- Бортовой IMU (QMI8658) для диагностики; внешний MPU6050 на каретке для ускорения штанги
- BOM электроники снизился с ~$350 до ~$270
## v3 → v4: CAN Bus архитектура
- **Проблема I2C:** шлейф ~1м к каретке рядом с фазными проводами — ненадёжно для I2C
- **Решение:** CAN шина, 3 узла, все датчики читаются локально
- **CAN узел #3 (каретка):** STM32F103C8T6 Blue Pill (~$2)
- Выбран вместо ESP32-C3 (overkill) и ATtiny (нет встроенного CAN)
- STM32F103 — самый распространённый STM32, CAN 2.0B встроен, $1.5-2, тонна примеров
- Читает MPU6050 (I2C) + HX711+тензодатчик (GPIO) локально
- **Тензодатчик перемещён на каретку** (inline: каретка ↔ трос)
- Раньше был внизу у ролика — длинный провод HX711 к ESP32
- Теперь рядом с Blue Pill — провод 3 см, никаких проблем
- Бонус: мерим силу прямо в точке приложения к штанге
- **Контроллер:** Flipsky 75100 Pro V2 вместо MKS VESC Mini 6.7
- 100А длительно (запас ×2 при пиках 40-50А)
- 84В макс (48В батарея — в зоне комфорта)
- BT встроен (VESC Tool без провода)
- Фазный EMI фильтр на плате
- Стоимость: ~$90 (vs ~$35 MKS)
## v4 дополнения: Питание и безопасность
- **Питание от сети 220В** — вводной щит (автомат + УЗО + БП 48В)
- **Батарея уменьшена:** 500Вт·ч → 100-250Вт·ч (только буфер рекуперации + UPS)
- Заряд до 90% — оставляем буфер для приёма энергии рекуперации
- **Тормозной резистор:** 100-200Вт, 1-5Ом — сброс излишков при полной батарее
- Flipsky 75100 поддерживает brake resistor нативно
- Без резистора: батарея 100% → рекуперация → overvoltage → VESC fault → штанга падает
- **Реле:** 3× НЗ 40А (не 80А — реально через обмотки 20-30А при торможении)
- Или трёхфазный контактор НЗ на DIN-рейку в щите
- **Концевики:** остаются на GPIO ESP32 с RC-фильтром (1К+100нФ)
- Бинарный сигнал, помехозащита RC-фильтром достаточна, CAN overkill
## Открытые вопросы / TODO
- [ ] Софт ESP32: CAN-драйвер, управляющие алгоритмы, UI на тачскрине
- [ ] Софт STM32: чтение IMU+HX711, упаковка в CAN фрейм
- [ ] Настройка VESC: FOC, лимиты тока/температуры, brake resistor
- [ ] Чертежи: барабан, каретка, кронштейны, щит
- [ ] Приложение смартфон (BLE): профили, статистика
- [ ] Тестирование безопасности: watchdog, реле, концевики
- [ ] Выбор конкретного контактора НЗ / реле для щита
- [ ] Подбор БП 48В от сети (мощность, форм-фактор)

66
README.md Normal file
View File

@@ -0,0 +1,66 @@
# Bench Press Trainer — умный тренажёр жима лёжа
Уличный тренажёр с электронным управлением нагрузкой. Мотор-колесо Xiaomi M365 Pro работает как управляемый тормоз/генератор через барабан кабестана. Нагрузка регулируется током VESC-контроллера (FOC).
## Архитектура
3 узла на CAN Bus (250 Кбит/с):
| Узел | Компонент | Роль |
|------|-----------|------|
| ID:20 | Waveshare ESP32-S3 LCD 3.5" | Мастер, UI, управление |
| ID:10 | Flipsky 75100 Pro V2 | VESC, FOC current control |
| ID:30 | STM32F103 Blue Pill | Каретка: IMU + тензодатчик |
## Структура проекта
```
smart-trainer/
├── README.md # Этот файл
├── SPEC.md # Полная инженерная спецификация
├── CHANGELOG.md # История проектных решений v1→v4
├── docs/
│ └── wiring.html # Схема подключения (интерактивная)
├── firmware/ # (будущее) прошивки ESP32, STM32
└── cad/ # (будущее) чертежи барабана, каретки, рамы
```
## Схема подключения
Интерактивная схема: [`docs/wiring.html`](docs/wiring.html)
## Как работать со схемой (wiring.html)
Схема построена на CSS grid с карточками модулей. Каждый модуль — `<div class="mod" id="mod-xxx">`.
### Секции (сверху вниз):
1. **Силовая часть** — питание, VESC, реле, мотор, тормозной резистор, watchdog
2. **CAN Bus bar** — визуализация шины с узлами
3. **Управление** — ESP32 Waveshare, STM32 Blue Pill
4. **Периферия** — концевики, NFC, смартфон, TF карта, Flipsky BT
5. **Data Flow** — таблица CAN трафика + описание безопасности
6. **BOM** — две таблицы (электроника + силовая/механика)
### ID модулей для поиска:
- `mod-power` — питание 220В + батарея
- `mod-vesc` — Flipsky 75100
- `mod-relay` — реле НЗ
- `mod-motor` — мотор M365 Pro
- `mod-brake-resistor` — тормозной резистор
- `mod-watchdog` — watchdog 555
- `mod-esp32` — Waveshare ESP32-S3
- `mod-stm32` — Blue Pill STM32 каретка
- `mod-endstops` — концевики
- `mod-nfc` — RC522 NFC
- `mod-phone` — смартфон BLE
- `mod-tf` — TF карта
- `mod-flipsky-bt` — Flipsky Bluetooth
- `mod-dataflow` — таблица CAN трафика
- `mod-safety-summary` — сводка безопасности
- `mod-bom-electronics` — BOM электроника
- `mod-bom-power-mech` — BOM силовая + механика
## Документация
- [Спецификация](SPEC.md) — все инженерные решения и расчёты
- [История изменений](CHANGELOG.md) — эволюция проекта v1→v4

159
SPEC.md Normal file
View File

@@ -0,0 +1,159 @@
# Умный тренажёр для жима лёжа — Спецификация проекта
## Концепция
Уличный тренажёр с электронным управлением нагрузкой. Мотор-колесо Xiaomi M365 Pro работает как управляемый тормоз/генератор через барабан кабестана. Нагрузка регулируется током VESC-контроллера (FOC). Питание от сети 220В + батарея-буфер для рекуперации и UPS.
## Мотор M365 Pro — паспортные данные
- Kt = 0.511 Н·м/А (моментная постоянная)
- Ke = 0.511 В/(рад/с) (противо-ЭДС)
- R = 0.392 Ом (сопротивление обмоток)
- KV = 16.67 об/(мин·В)
- 15 пар полюсов, Hall-сенсоры встроены (U/V/W + 5V + GND)
- NTC 10K термистор встроен
- Outrunner — ротор снаружи
## Барабан кабестана
- Диаметр: D = 30мм (оптимальный выбор по расчёту)
- Материал: нержавеющая сталь 12Х18Н10Т
- 3 канавки под трос D4мм, шаг 6мм, глубина 2мм (полукруглый профиль R2)
- Крепление: фланец к ободу ротора (outrunner)
- Кабестан: 3 витка, μ=0.25 (сталь-полимер), коэффициент удержания e^(0.25×6π) = 14.1
- Свободный конец троса → пружина-натяжитель 1-2 кг
## Нагрузки на барабане D30мм
| Ток (А) | Сила (кг) | Режим |
|---------|-----------|-------|
| 20 | 65 | лёгкий |
| 30 | 100 | рабочий (подход 30с) |
| 40 | 135 | пик (3-5с) |
| 50 | 170 | абсолютный максимум |
## Электроника — CAN Bus архитектура (3 узла)
### CAN узел #1: Flipsky 75100 Pro V2 (ID: 10)
- VESC 6.0, 100А длительно, 84В макс
- FOC current control
- BT встроен (VESC Tool настройка по Bluetooth)
- Фазный EMI фильтр на плате
- CAN 2.0B встроен
- Стоимость: ~$90
- Расположение: низ рамы, в электрощите
- Отдаёт: ERPM, I_mot, T_mot, V_bat (100 Гц)
- Принимает: set_current(I_ref) от ESP32
### CAN узел #2: Waveshare ESP32-S3 Touch LCD 3.5" (ID: 20) — МАСТЕР
- ESP32-S3R8, двухъядерный LX7 240МГц
- 3.5" IPS тачскрин 320×480, ёмкостный (ST7796 + FT6336)
- QMI8658 6-осевой IMU на плате (бортовой, для диагностики вибраций)
- PCF85063 RTC часы реального времени
- AXP2101 управление питанием + зарядка Li-ion
- TF-карта слот (логирование тренировок)
- WiFi 802.11 b/g/n + BLE 5
- TWAI (CAN) контроллер встроен в ESP32-S3
- Стоимость: ~$20
- Расположение: верхняя перекладина рамы, тачскрин к спортсмену
- Подключение к CAN через внешний трансивер SN65HVD230 ($1)
- Дополнительная периферия (локально на ESP32):
- Концевики ×2 (GPIO, НЗ, pull-up 10K, RC-фильтр 1К+100нФ)
- RC522 NFC (SPI, идентификация пользователей)
- BLE → смартфон (настройки, статистика)
### CAN узел #3: STM32F103C8T6 Blue Pill (ID: 30) — КАРЕТКА
- Cortex-M3, 72МГц, CAN 2.0B встроен
- Стоимость: ~$2
- Расположение: на каретке штанги (движется)
- Подключение к CAN через SN65HVD230 ($1)
- Локальные датчики:
- MPU6050 (I2C): 6-осевой IMU, 200 Гц, ускорение + гироскоп
- HX711 + тензодатчик S-тип 200кг (GPIO): реальная сила на тросе, 80 Гц
- Тензодатчик inline: между кареткой и точкой крепления троса
- Кабель к основной шине: 4 провода (CAN_H, CAN_L, 5V, GND), гибкий шлейф вдоль направляющей
- Отдаёт: accel[3], gyro[3], force_N (200 Гц)
### CAN шина
- Стандарт: CAN 2.0B, 250 Кбит/с
- Топология: линейная, витая пара
- Терминаторы: 120Ω на обоих концах (ESP32 сверху, VESC снизу)
- Blue Pill — отвод к каретке (без терминатора, посередине шины)
- Загрузка шины: ~30%, запас для расширения
- Протокол: VESC CAN (стандартные команды set_current, get_values, status msgs)
## Питание
- Сеть 220В → вводной щит (автомат + УЗО) → БП 48В
- Батарея 48В 100-250Вт·ч (буфер рекуперации + UPS)
- Заряд до 90% (50.4В на 13S), оставляя буфер для рекуперации
- DC-DC 48В → 5В для логики, LDO 3.3В на каждом узле
- Тормозной резистор: 100-200Вт, 1-5Ом, через MOSFET
- Сброс излишков рекуперации при полной батарее
- Flipsky 75100 поддерживает brake resistor нативно (настройка порога в VESC Tool)
- Расположение: в щите или на раме (нужна вентиляция)
## Безопасность — аппаратная цепь
- ESP32 GPIO → Watchdog (555/TPL5010, 50мс) → реле НЗ → замыкание обмоток мотора
- Реле: 3× автомобильных НЗ 40А, катушки параллельно ИЛИ трёхфазный контактор НЗ на DIN-рейку в щите
- Логика: ESP32 генерирует импульсы ~100Гц → watchdog сбрасывается. Сбой/зависание → watchdog timeout 50мс → реле отпускает → НЗ контакты замыкают три фазы → электромагнитное торможение
- Тормозная сила при замкнутых обмотках: F = Kt² × v / (R × r²). При 0.5 м/с → ~150 кг
- Опционально: резистор 0.1-0.3Ω / 100Вт в цепи замыкания для смягчения торможения
- Софтовый лимит позиции по ERPM (дополнительно к аппаратному)
- VESC: max input voltage лимит (ослабление рекуперации при высоком напряжении)
## Концевики
- Нижний: homing (нулевая точка отсчёта позиции)
- Верхний: аварийный стоп
- НЗ контакты, pull-up 10K к 3.3В
- RC-фильтр: 1К + 100нФ на входе GPIO ESP32 (τ = 0.1мс, подавление наводок)
- Debounce программный: 10-20мс
- Подключены напрямую к GPIO ESP32 (бинарный сигнал, помехозащита RC-фильтром достаточна)
## Механика
- Рама: профиль 80×80×4мм, сталь 09Г2С, сварная
- Высота стоек ~1200мм, ширина между стойками ~340мм, глубина ~700мм
- Анкеры 4×M12 в бетон
- Направляющие: 2 вала D25мм, сталь 40Х хромированная, длина 900мм
- Линейные подшипники LM25UU ×4 на каретке
- Ход каретки: 650мм
- Каретка: масса 8кг (с грифом), крепление троса снизу через тензодатчик
- Компенсация веса каретки: противовес 8кг на тросе через ролик наверху (груз в стойке: стальной цилиндр D60×300мм)
- Трос: D4мм, сталь в полимерной оболочке, разрывная нагрузка 8000Н
- Путь троса: каретка → тензодатчик (inline) → вниз → ролик D60мм (подшипник 6201-2RS, поворот 90°) → горизонтально к барабану мотора → 3 витка → пружина-натяжитель
- Мотор: закреплён за ось внизу рамы, антивандальный кожух сталь 2мм
- Вводной щит 220В: на раме или рядом (DIN-рейка: автомат, УЗО, БП 48В, контактор НЗ, тормозной резистор)
- Электроника: IP54 бокс (VESC, DC-DC, Watchdog) внизу рамы / в щите
- Батарея: IP67 бокс
- Габариты: Ш×Г×В ≈ 800×700×1250мм
## Режимы нагрузки
1. **Постоянная**: фиксированный ток, опц. виртуальная инерция (F = m_virtual × a)
2. **Эксцентрический**: разная нагрузка вверх/вниз (направление по ERPM)
3. **Аккомодационное**: F(x) = F_min + (F_max - F_min) × x / L
4. **Интервальный**: чередование нагрузок по повторениям
5. **Изокинетический**: постоянная скорость, VESC speed control
6. **Страховщик**: v_up < 0.05 м/с > 0.5с → снизить 30%; v_down > 0.7 м/с > 0.3с → аварийное торможение
## BOM (оценка)
| Компонент | Стоимость |
|-----------|-----------|
| Waveshare ESP32-S3 LCD 3.5" | ~$20 |
| Flipsky 75100 Pro V2 | ~$90 |
| Blue Pill STM32F103 | ~$2 |
| SN65HVD230 ×2 | ~$2 |
| MPU6050 + HX711 + тензодатчик S-тип 200кг | ~$10 |
| 3× реле НЗ 40А / контактор НЗ | ~$15 |
| Watchdog 555 + обвязка | ~$2 |
| RC522 NFC | ~$3 |
| Концевики ×2 | ~$2 |
| DC-DC 48→5V | ~$5 |
| Тормозной резистор 100Вт + MOSFET | ~$5 |
| Батарея 48V 100-250Вт·ч | ~$100-150 |
| БП 48В от сети | ~$25 |
| Мотор M365 Pro (б/у) | ~$60 |
| Рама + направляющие + механика | ~$120 |
| Щит 220В (автомат + УЗО) | ~$20 |
| **ИТОГО** | **~$480-530** |
## Файлы проекта
- `SPEC.md` — этот файл
- `CHANGELOG.md` — история решений
- `wiring.html` — схема подключения (модульная, CSS grid)
- (будущее) `firmware/` — прошивки ESP32, STM32
- (будущее) `cad/` — чертежи барабана, каретки, рамы

508
docs/wiring.html Normal file
View File

@@ -0,0 +1,508 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Схема подключения v4 — CAN Bus</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600;700&family=Outfit:wght@300;400;600;700&display=swap');
:root {
--bg: #08090e; --card-bg: #111620; --border: #1a2030;
--text: #c8d6e5; --dim: #4e5e74; --label: #e2e8f0;
--red: #ef4444; --green: #22c55e; --cyan: #22d3ee;
--amber: #f59e0b; --purple: #8b5cf6; --pink: #f43f5e;
--teal: #2dd4bf; --orange: #fb923c; --blue: #3b82f6;
--indigo: #818cf8;
}
* { margin:0; padding:0; box-sizing:border-box; }
body { background:var(--bg); color:var(--text); font-family:'Outfit',sans-serif; }
code, .mono { font-family:'JetBrains Mono',monospace; }
/* ── Header ── */
.header { text-align:center; padding:20px 16px 12px; border-bottom:1px solid var(--border); }
.header h1 { font-size:18px; font-weight:700; color:var(--label); }
.header p { font-size:11px; color:var(--dim); margin-top:3px; font-family:'JetBrains Mono',monospace; }
/* ── Section ── */
.section { max-width:1100px; margin:0 auto; padding:14px 12px 4px; }
.section-title {
font-size:10px; font-weight:600; color:var(--dim);
text-transform:uppercase; letter-spacing:1.5px; margin-bottom:8px;
padding-left:4px; border-left:3px solid var(--border);
}
/* ── Grid layouts ── */
.grid-2 { display:grid; grid-template-columns:1fr 1fr; gap:8px; }
.grid-3 { display:grid; grid-template-columns:1fr 1fr 1fr; gap:8px; }
.grid-4 { display:grid; grid-template-columns:repeat(auto-fit, minmax(200px, 1fr)); gap:8px; }
/* ── Module card ── */
.mod {
background:var(--card-bg); border:1px solid var(--border);
border-radius:8px; padding:12px 14px; position:relative;
}
.mod:hover { border-color:#2a3a50; }
.mod-head { display:flex; align-items:center; gap:6px; margin-bottom:6px; }
.mod-dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
.mod-name { font-size:12px; font-weight:700; color:var(--label); }
.mod-tag {
font-size:8px; font-family:'JetBrains Mono',monospace;
padding:1px 5px; border-radius:3px; margin-left:auto;
}
.mod-desc { font-size:10px; color:#5a6a80; line-height:1.6; font-family:'JetBrains Mono',monospace; }
.mod-pins { margin-top:6px; font-size:9px; color:#7a8a9e; font-family:'JetBrains Mono',monospace; line-height:1.7; }
.mod-pins .pin { display:flex; gap:6px; }
.mod-pins .pin-dir { color:var(--dim); width:16px; text-align:center; }
.mod-pins .pin-name { color:#9aa8ba; }
.mod-pins .pin-dest { color:var(--dim); margin-left:auto; }
/* ── CAN bus bar ── */
.can-bus {
max-width:1100px; margin:0 auto; padding:0 12px;
}
.can-bar {
background:linear-gradient(90deg, #082828, #0a3535, #082828);
border:1.5px solid var(--cyan); border-radius:8px;
padding:12px 20px; display:flex; align-items:center;
justify-content:space-between; position:relative;
}
.can-bar::before {
content:''; position:absolute; top:50%; left:20px; right:20px;
height:3px; background:var(--cyan); opacity:.2; border-radius:2px;
}
.can-node {
position:relative; z-index:1; text-align:center;
background:#0b1520; border:1px solid var(--cyan);
border-radius:6px; padding:6px 14px;
}
.can-node-id { font-size:10px; font-weight:700; color:var(--cyan); font-family:'JetBrains Mono',monospace; }
.can-node-name { font-size:8px; color:#5a8a8a; font-family:'JetBrains Mono',monospace; }
.can-term {
font-size:8px; color:var(--cyan); font-family:'JetBrains Mono',monospace;
background:#061518; border:1px solid #1a4a4a; border-radius:4px;
padding:2px 8px; position:relative; z-index:1;
}
.can-info {
text-align:center; margin-top:6px; font-size:9px;
color:#155e75; font-family:'JetBrains Mono',monospace;
}
/* ── Wire description ── */
.wire {
font-size:9px; font-family:'JetBrains Mono',monospace;
padding:3px 8px; border-radius:4px; display:inline-flex;
align-items:center; gap:5px; margin:2px 0;
}
.wire::before { content:''; width:14px; height:2px; border-radius:1px; }
.wire-red::before { background:var(--red); } .wire-red { color:#fca5a5; }
.wire-cyan::before { background:var(--cyan); } .wire-cyan { color:#67e8f9; }
.wire-amber::before { background:var(--amber); } .wire-amber { color:#fcd34d; }
.wire-green::before { background:var(--green); } .wire-green { color:#86efac; }
.wire-pink::before { background:var(--pink); } .wire-pink { color:#fda4af; }
.wire-purple::before { background:var(--indigo); } .wire-purple { color:#c4b5fd; }
.wire-orange::before { background:var(--orange); } .wire-orange { color:#fdba74; }
.wire-teal::before { background:var(--teal); } .wire-teal { color:#99f6e4; }
/* ── Data flow table ── */
.flow-table { width:100%; font-size:10px; font-family:'JetBrains Mono',monospace; border-collapse:collapse; }
.flow-table th { color:var(--dim); text-align:left; padding:4px 8px; border-bottom:1px solid #1a2a3a; font-weight:400; }
.flow-table td { padding:4px 8px; color:#7a9aba; }
.flow-table tr:hover td { color:var(--label); }
/* ── BOM table ── */
.bom-table { width:100%; font-size:10px; font-family:'JetBrains Mono',monospace; border-collapse:collapse; }
.bom-table td { padding:3px 8px; color:#64748b; }
.bom-table td:last-child { text-align:right; }
.bom-table tr.total td { color:var(--label); font-weight:700; border-top:1px solid var(--border); padding-top:6px; }
/* ── Legend ── */
.legend { max-width:1100px; margin:8px auto; padding:0 12px; display:flex; flex-wrap:wrap; gap:10px; justify-content:center; }
.legend-i { display:flex; align-items:center; gap:4px; font-size:9px; font-family:'JetBrains Mono',monospace; color:#5a6a80; }
.legend-l { width:18px; height:3px; border-radius:2px; }
</style>
</head>
<body>
<!-- ════════════════════════════════════════════════════════════════ -->
<!-- HEADER -->
<!-- ════════════════════════════════════════════════════════════════ -->
<div class="header">
<h1>Схема подключения v4 — CAN Bus архитектура</h1>
<p>3 узла CAN · Waveshare ESP32-S3 · STM32F103 Blue Pill · Flipsky 75100 Pro V2 · 250 Кбит/с</p>
</div>
<!-- ════════════════════════════════════════════════════════════════ -->
<!-- SECTION: СИЛОВАЯ ЧАСТЬ -->
<!-- ════════════════════════════════════════════════════════════════ -->
<div class="section">
<div class="section-title">Силовая часть</div>
<div class="grid-4">
<!-- MODULE: Питание 220В + Батарея -->
<div class="mod" id="mod-power">
<div class="mod-head">
<div class="mod-dot" style="background:var(--blue)"></div>
<span class="mod-name">Питание</span>
</div>
<div class="mod-desc">
Сеть 220В → щит (автомат + УЗО)<br>
→ БП 48В → батарея 48В 100-250Вт·ч<br>
Батарея = буфер рекуперации + UPS<br>
Заряд до 90% (буфер для рекуп.)<br>
DC-DC 48→5V · LDO 3.3V на узлах
</div>
<div class="mod-pins">
<div class="pin"><span class="pin-dir"></span><span class="pin-name">+48V</span><span class="pin-dest">→ VESC BAT+</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">GND</span><span class="pin-dest">→ общая шина</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">5V</span><span class="pin-dest">→ ESP32, STM32</span></div>
</div>
</div>
<!-- MODULE: Flipsky VESC -->
<div class="mod" id="mod-vesc">
<div class="mod-head">
<div class="mod-dot" style="background:var(--green)"></div>
<span class="mod-name">Flipsky 75100 Pro V2</span>
<span class="mod-tag" style="background:#0f2518;color:#86efac;">CAN ID:10</span>
</div>
<div class="mod-desc">
VESC 6.0 · 100А · 84В макс · ~$90<br>
FOC current control · BT встроен<br>
Фазный EMI фильтр на плате
</div>
<div class="mod-pins">
<div class="pin"><span class="pin-dir"></span><span class="pin-name">BAT+/GND</span><span class="pin-dest">← батарея 48В</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">CAN_H/L</span><span class="pin-dest">↔ CAN шина</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">Ph A/B/C</span><span class="pin-dest">→ реле НЗ → мотор</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">HALL 5p</span><span class="pin-dest">← мотор Hall U/V/W</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">MOT TEMP</span><span class="pin-dest">← мотор NTC 10K</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">BRAKE RES</span><span class="pin-dest">→ тормозной резистор</span></div>
</div>
</div>
<!-- MODULE: Реле НЗ -->
<div class="mod" id="mod-relay">
<div class="mod-head">
<div class="mod-dot" style="background:var(--pink)"></div>
<span class="mod-name">Реле НЗ ×3 (40А)</span>
</div>
<div class="mod-desc">
3× авто-реле НЗ, катушки параллельно<br>
или 3-фазный контактор НЗ на DIN-рейку<br>
Опц. резистор 0.1-0.3Ω в цепи КЗ
</div>
<div class="mod-pins">
<div class="pin"><span class="pin-dir"></span><span class="pin-name">Ph A/B/C вход</span><span class="pin-dest">← VESC фазы</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">Ph A/B/C выход</span><span class="pin-dest">→ мотор</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">Катушка</span><span class="pin-dest">← Watchdog OUT</span></div>
</div>
</div>
<!-- MODULE: Мотор -->
<div class="mod" id="mod-motor">
<div class="mod-head">
<div class="mod-dot" style="background:var(--amber)"></div>
<span class="mod-name">Мотор M365 Pro</span>
</div>
<div class="mod-desc">
BLDC 350W · 15pp · Outrunner<br>
Барабан D30мм · Кабестан 3 витка<br>
90 имп/об → ~1мм разрешение хода
</div>
<div class="mod-pins">
<div class="pin"><span class="pin-dir"></span><span class="pin-name">Ph A/B/C</span><span class="pin-dest">← реле НЗ</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">Hall U/V/W</span><span class="pin-dest">→ VESC HALL</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">NTC 10K</span><span class="pin-dest">→ VESC MOT TEMP</span></div>
</div>
</div>
<!-- MODULE: Тормозной резистор -->
<div class="mod" id="mod-brake-resistor">
<div class="mod-head">
<div class="mod-dot" style="background:var(--orange)"></div>
<span class="mod-name">Тормозной резистор</span>
</div>
<div class="mod-desc">
100-200Вт · 1-5Ом · через MOSFET<br>
Сброс рекуперации при полной батарее<br>
Flipsky поддерживает нативно<br>
Расположение: щит (вентиляция!)
</div>
<div class="mod-pins">
<div class="pin"><span class="pin-dir"></span><span class="pin-name">BRAKE RES</span><span class="pin-dest">← VESC разъём</span></div>
</div>
</div>
<!-- MODULE: Watchdog -->
<div class="mod" id="mod-watchdog">
<div class="mod-head">
<div class="mod-dot" style="background:var(--pink)"></div>
<span class="mod-name">Watchdog 50мс</span>
</div>
<div class="mod-desc">
555 / TPL5010 · таймаут 50мс<br>
ESP32 шлёт импульсы ~100Гц<br>
Сбой → реле отпускает → КЗ фаз<br>
Торможение ~150кг при 0.5 м/с
</div>
<div class="mod-pins">
<div class="pin"><span class="pin-dir"></span><span class="pin-name">WDI</span><span class="pin-dest">← ESP32 GPIO</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">OUT</span><span class="pin-dest">→ катушка реле НЗ</span></div>
</div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════ -->
<!-- CAN BUS BAR -->
<!-- ════════════════════════════════════════════════════════════════ -->
<div class="can-bus" style="padding-top:12px;">
<div class="section-title" style="max-width:1100px;margin:0 auto 8px;padding-left:16px;">CAN Bus · 250 Кбит/с · витая пара</div>
<div class="can-bar">
<div class="can-term">120Ω</div>
<div class="can-node">
<div class="can-node-id">ID:20 МАСТЕР</div>
<div class="can-node-name">ESP32 Waveshare</div>
</div>
<div class="can-node">
<div class="can-node-id">ID:10</div>
<div class="can-node-name">VESC Flipsky</div>
</div>
<div class="can-node">
<div class="can-node-id">ID:30 КАРЕТКА</div>
<div class="can-node-name">STM32 Blue Pill</div>
</div>
<div class="can-term">120Ω</div>
</div>
<div class="can-info">4 провода к каретке: CAN_H · CAN_L · 5V · GND (гибкий шлейф вдоль направляющей)</div>
</div>
<!-- ════════════════════════════════════════════════════════════════ -->
<!-- SECTION: УПРАВЛЕНИЕ -->
<!-- ════════════════════════════════════════════════════════════════ -->
<div class="section">
<div class="section-title">Управление (CAN узлы #2 и #3)</div>
<div class="grid-2">
<!-- MODULE: Waveshare ESP32-S3 -->
<div class="mod" id="mod-esp32">
<div class="mod-head">
<div class="mod-dot" style="background:var(--purple)"></div>
<span class="mod-name">Waveshare ESP32-S3 LCD 3.5"</span>
<span class="mod-tag" style="background:#1a1040;color:#c4b5fd;">CAN ID:20 · МАСТЕР</span>
</div>
<div class="mod-desc">
ESP32-S3R8 · 240МГц · WiFi/BLE5 · ~$20<br>
3.5" IPS тачскрин 320×480 (ST7796 + FT6336)<br>
QMI8658 IMU (борт) · PCF85063 RTC · AXP2101 PMU<br>
TF-карта (лог тренировок) · TWAI (CAN) встроен<br>
Расположение: верхняя перекладина, тачскрин к спортсмену
</div>
<div class="mod-pins">
<div class="pin"><span class="pin-dir"></span><span class="pin-name">TWAI TX/RX</span><span class="pin-dest">→ SN65HVD230 ($1) → CAN шина</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">GPIO WDG_OUT</span><span class="pin-dest">→ Watchdog WDI (~100Гц)</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">GPIO END_LO</span><span class="pin-dest">← концевик НИЗ (НЗ, RC 1К+100нФ)</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">GPIO END_HI</span><span class="pin-dest">← концевик ВЕРХ (НЗ, RC 1К+100нФ)</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">SPI</span><span class="pin-dest">↔ RC522 NFC (идентификация)</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">BLE 5</span><span class="pin-dest">↔ смартфон (беспроводное)</span></div>
</div>
</div>
<!-- MODULE: Blue Pill STM32 — Carriage -->
<div class="mod" id="mod-stm32">
<div class="mod-head">
<div class="mod-dot" style="background:var(--teal)"></div>
<span class="mod-name">STM32F103C8T6 Blue Pill</span>
<span class="mod-tag" style="background:#0a2020;color:#5eead4;">CAN ID:30 · КАРЕТКА</span>
</div>
<div class="mod-desc">
Cortex-M3 72МГц · CAN 2.0B встроен · ~$2<br>
Расположение: на каретке штанги (движется)<br>
Кабель: 4 пров. гибкий шлейф к CAN шине
</div>
<div class="mod-pins">
<div class="pin"><span class="pin-dir"></span><span class="pin-name">CAN TX/RX</span><span class="pin-dest">→ SN65HVD230 ($1) → CAN шина</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">I2C SDA/SCL</span><span class="pin-dest">← MPU6050 (провод 3 см)</span></div>
<div class="pin"><span class="pin-dir"></span><span class="pin-name">GPIO SCK/DT</span><span class="pin-dest">← HX711 (провод 3 см)</span></div>
</div>
<div style="margin-top:8px;padding:6px 8px;background:#0d2828;border-radius:5px;">
<div class="mod-desc" style="color:#2dd4bf;">
<strong>Локальные датчики (на каретке):</strong><br>
• MPU6050 — 6-осевой IMU · I2C · 200 Гц · ~$2<br>
• HX711 + тензодатчик S-тип 200кг · GPIO · 80 Гц · ~$8<br>
• Тензодатчик inline: каретка ↔ трос<br>
→ CAN фрейм: accel[3] + gyro[3] + force(Н)
</div>
</div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════ -->
<!-- SECTION: ПЕРИФЕРИЯ -->
<!-- ════════════════════════════════════════════════════════════════ -->
<div class="section">
<div class="section-title">Периферия (локально на ESP32)</div>
<div class="grid-4">
<div class="mod" id="mod-endstops">
<div class="mod-head">
<div class="mod-dot" style="background:var(--orange)"></div>
<span class="mod-name">Концевики ×2</span>
</div>
<div class="mod-desc">
Нижний (homing) + Верхний (аварийный)<br>
НЗ · pull-up 10K · RC-фильтр 1К+100нФ<br>
Debounce 10-20мс программный<br>
GPIO ESP32 напрямую · ~$2
</div>
</div>
<div class="mod" id="mod-nfc">
<div class="mod-head">
<div class="mod-dot" style="background:var(--indigo)"></div>
<span class="mod-name">RC522 NFC</span>
</div>
<div class="mod-desc">
SPI · идентификация пользователей<br>
Профили нагрузок по карте<br>
~$3
</div>
</div>
<div class="mod" id="mod-phone">
<div class="mod-head">
<div class="mod-dot" style="background:var(--indigo)"></div>
<span class="mod-name">Смартфон</span>
</div>
<div class="mod-desc">
BLE 5 (встроен ESP32-S3)<br>
Настройки · статистика · профили<br>
Беспроводное подключение
</div>
</div>
<div class="mod" id="mod-tf">
<div class="mod-head">
<div class="mod-dot" style="background:#64748b"></div>
<span class="mod-name">TF карта</span>
</div>
<div class="mod-desc">
Встроена в Waveshare<br>
Логирование тренировок<br>
SDIO интерфейс
</div>
</div>
<div class="mod" id="mod-flipsky-bt">
<div class="mod-head">
<div class="mod-dot" style="background:var(--green)"></div>
<span class="mod-name">Flipsky BT</span>
</div>
<div class="mod-desc">
Встроен в 75100 Pro V2<br>
VESC Tool · калибровка FOC<br>
Настройка лимитов тока/температуры
</div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════ -->
<!-- SECTION: DATA FLOW -->
<!-- ════════════════════════════════════════════════════════════════ -->
<div class="section">
<div class="section-title">CAN Data Flow</div>
<div class="grid-2">
<div class="mod" id="mod-dataflow">
<table class="flow-table">
<tr><th>ID</th><th>Узел</th><th></th><th>Данные</th><th>Частота</th></tr>
<tr style="color:#86efac"><td>10</td><td>Flipsky 75100</td><td>→ шина</td><td>ERPM, I_mot, T_mot, V_bat</td><td>100 Гц</td></tr>
<tr style="color:#c4b5fd"><td>20</td><td>ESP32 Waveshare</td><td>→ VESC</td><td>set_current(I_ref)</td><td>100 Гц</td></tr>
<tr style="color:#5eead4"><td>30</td><td>STM32 Blue Pill</td><td>→ шина</td><td>accel[3], gyro[3], F(Н)</td><td>200 Гц</td></tr>
</table>
<div class="mod-desc" style="margin-top:8px;color:var(--dim);">
Загрузка шины: ~30% при 250 Кбит/с · запас для расширения
</div>
</div>
<div class="mod" id="mod-safety-summary">
<div class="mod-head">
<div class="mod-dot" style="background:var(--pink)"></div>
<span class="mod-name">Цепь безопасности (аппаратная)</span>
</div>
<div class="mod-desc" style="color:#fca5a5;">
ESP32 GPIO ~100Гц → Watchdog 555 (50мс)<br>
→ катушка 3× реле НЗ 40А<br>
→ при сбое: фазы КЗ → электромагнитное торможение<br>
→ F = Kt²·v / (R·r²) ≈ 150 кг при 0.5 м/с<br><br>
Дополнительно:<br>
• Тормозной резистор (overvoltage protection)<br>
• VESC max input voltage лимит<br>
• Софтовый лимит позиции по ERPM<br>
• Концевики (homing + аварийный стоп)
</div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════ -->
<!-- SECTION: BOM -->
<!-- ════════════════════════════════════════════════════════════════ -->
<div class="section">
<div class="section-title">BOM — Оценка стоимости</div>
<div class="grid-2">
<div class="mod" id="mod-bom-electronics">
<div class="mod-head">
<span class="mod-name">Электроника</span>
</div>
<table class="bom-table">
<tr><td>Waveshare ESP32-S3 LCD 3.5"</td><td>~$20</td></tr>
<tr><td>Flipsky 75100 Pro V2</td><td>~$90</td></tr>
<tr><td>Blue Pill STM32F103</td><td>~$2</td></tr>
<tr><td>SN65HVD230 ×2</td><td>~$2</td></tr>
<tr><td>MPU6050 + HX711 + тензодат. S-тип</td><td>~$10</td></tr>
<tr><td>3× реле НЗ 40А / контактор</td><td>~$15</td></tr>
<tr><td>Watchdog 555 + обвязка</td><td>~$2</td></tr>
<tr><td>RC522 NFC + концевики ×2</td><td>~$5</td></tr>
<tr><td>DC-DC 48→5V</td><td>~$5</td></tr>
<tr><td>Тормозной резистор 100Вт</td><td>~$5</td></tr>
<tr class="total"><td>Итого электроника</td><td>~$156</td></tr>
</table>
</div>
<div class="mod" id="mod-bom-power-mech">
<div class="mod-head">
<span class="mod-name">Силовая + механика</span>
</div>
<table class="bom-table">
<tr><td>Батарея 48V 100-250Вт·ч (буфер)</td><td>~$100</td></tr>
<tr><td>БП 48В от сети 220В</td><td>~$25</td></tr>
<tr><td>Щит 220В (автомат + УЗО)</td><td>~$20</td></tr>
<tr><td>Мотор M365 Pro (б/у)</td><td>~$60</td></tr>
<tr><td>Рама + направляющие + механика</td><td>~$120</td></tr>
<tr class="total"><td>Итого сил. + мех.</td><td>~$325</td></tr>
<tr class="total" style="font-size:12px"><td>ОБЩИЙ ИТОГ</td><td>≈ $480</td></tr>
</table>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════ -->
<!-- LEGEND -->
<!-- ════════════════════════════════════════════════════════════════ -->
<div class="legend" style="padding-bottom:20px;">
<div class="legend-i"><div class="legend-l" style="background:var(--red)"></div>Питание</div>
<div class="legend-i"><div class="legend-l" style="background:var(--amber)"></div>Фазы A/B/C</div>
<div class="legend-i"><div class="legend-l" style="background:var(--cyan)"></div>CAN Bus</div>
<div class="legend-i"><div class="legend-l" style="background:var(--green)"></div>Hall</div>
<div class="legend-i"><div class="legend-l" style="background:var(--pink)"></div>Безопасность</div>
<div class="legend-i"><div class="legend-l" style="background:var(--indigo)"></div>SPI/данные</div>
<div class="legend-i"><div class="legend-l" style="background:var(--orange)"></div>GPIO</div>
<div class="legend-i"><div class="legend-l" style="background:var(--teal)"></div>Каретка</div>
</div>
</body>
</html>