# GY-271 — цифровой компас (магнитометр)

Компонент опрашивает 3-осевой магнитометр на плате "GY-271" по I2C и
вычисляет азимут (курс относительно магнитного севера). Под одним и тем же
названием платы на рынке продаются два несовместимых чипа — оригинальный
Honeywell HMC5883L и более новый QST QMC5883L. Драйвер сам определяет, какой
из них на шине, и настраивает именно его — подробнее в [THEORY.md](THEORY.md).

## Файлы

- [include/Gy271Compass.h](include/Gy271Compass.h) / [src/Gy271Compass.cpp](src/Gy271Compass.cpp) — драйвер.
- [src/main.cpp](src/main.cpp) — тестовый стенд: калибровка, расчёт азимута,
  Serial-команды.
- [tools/compass_view.py](tools/compass_view.py) — живая стрелка компаса на
  компьютере (см. раздел "Визуализация" ниже).
- [THEORY.md](THEORY.md) — физика магнитометра, регистры обоих чипов, зачем нужна калибровка.
- [WIRING.md](WIRING.md) — схема подключения.
- [Lesson.md](Lesson.md) — методический план урока для учителя.

## Подключение (кратко)

| GY-271 | ESP32 (по умолчанию в `main.cpp`) |
|--------|-------------------------------------|
| VCC    | 3.3V                                 |
| GND    | GND                                   |
| SDA    | GPIO21                                |
| SCL    | GPIO22                                |

Полная схема — в [WIRING.md](WIRING.md).

## Быстрый старт

1. Собрать схему по [WIRING.md](WIRING.md).
2. Прошить: `pio run -e esp32dev -t upload`.
3. Открыть Serial Monitor на 115200 бод.
4. При старте компонент сообщает, какой чип найден на плате
   ([main.cpp:121-127](src/main.cpp#L121-L127)) — QMC5883L или HMC5883L. Оба варианта
   поддерживаются одинаково, дальше работа не отличается.
5. Ввести команду `c` и вращать плату во всех плоскостях 30 секунд —
   это калибровка, без неё азимут считаться не будет (подробнее —
   [THEORY.md, раздел «Калибровка»](THEORY.md#4-калибровка-hard-iron-без-неё-никак)).
6. Команда `r` — разовое чтение X/Y/Z и азимута, `h` — только направление.

## Визуализация

`tools/compass_view.py` рисует живую стрелку компаса на экране вместо чисел
в Serial Monitor — так эффект калибровки виден сразу:

```bash
cd tools
pip install -r requirements.txt
python3 compass_view.py /dev/ttyUSB0
```

Serial Monitor прошивки на момент запуска скрипта должен быть закрыт.
Подробнее — [Lesson.md, блок практики](Lesson.md#блок-iv-калибровка-и-практика).

## Калибровка

Магнитометр искажается металлом рядом с платой (Hard-Iron/Soft-Iron эффекты) —
эти искажения индивидуальны для каждой платы, монтажа и помещения. Поэтому
драйвер **не хранит** калибровочные коэффициенты — только сырые X/Y/Z.
Калибровка (поиск границ min/max по осям) реализована в тестовом стенде:
[main.cpp:66-100](src/main.cpp#L66-L100). Результат нужно вручную перенести
в `calibration` в начале `main.cpp` ([main.cpp:17-21](src/main.cpp#L17-L21)) —
как и пороги в компоненте APDS-9960, это подстраивается под конкретный
экземпляр, а не берётся из библиотеки.

Магнитное склонение (`MAGNETIC_DECLINATION_DEG`, [main.cpp:10](src/main.cpp#L10))
нужно подставить под свой регион — по умолчанию 0° (курс "магнитный").

## API драйвера

| Метод | Назначение |
|-------|------------|
| `begin(sda, scl)` | Определяет чип на шине (QMC5883L на `0x0D`, иначе HMC5883L на `0x1E`) и настраивает его. |
| `getChipType()` | Какой чип реально найден. |
| `readRaw(MagSample &out)` | Сырые X/Y/Z, порядок осей уже приведён к единому виду независимо от чипа. |
| `isAlive(timeoutMs)` | Была ли недавняя успешная транзакция с чипом. |

## Используемые регистры

Полный разбор — в [THEORY.md](THEORY.md#3-регистры-которые-мы-используем).
Константы — [Gy271Compass.h:53-77](include/Gy271Compass.h#L53-L77).

## Известные ограничения

- Без калибровки (команда `c`) азимут не считается — драйвер честно
  сообщает об этом (`computeHeadingDeg()` возвращает `-1`).
- Точность падает рядом с металлическими предметами и электромоторами.
- Если датчик не отвечает ни на `0x0D`, ни на `0x1E` — проверьте проводку,
  см. [WIRING.md](WIRING.md).


## Связанные материалы

- [Пространство и положение](/docs/robotics/concepts/geometry/) — системы координат,
  курс и точка отсчёта; компас даёт угол $\theta$ для одометрии.
- [Сигналы и данные](/docs/robotics/concepts/signals/) — почему показания рядом с
  моторами искажаются и как с этим работать.
- [MPU6050](/docs/sensors/navigation/mpu6050/) — гироскоп быстрый, но уплывает;
  компас медленный, но абсолютный. Вместе они дают устойчивый курс.
