Джойстик из стартового набора я первые полчаса подозревал в браке: ручка стояла в покое, а монитор печатал x=503 и y=521 вместо учебных 512. Я пересаживал провода, менял аналоговые входы, перечитывал распиновку — числа держались. Разрешение пришло скучное: у каждого реального модуля центр свой, и полоса 500-523 в покое — это норма, а не дефект. Полчаса на пересадку проводов я мог бы сэкономить, зная полосу допусков, — теперь она висит у меня на стене над столом. Симулятор с его идеальными 512 эту правду замаскировал бы, поэтому первый запуск я советую делать на живой плате и сразу с честными ожиданиями.
Сам модуль называется KY-023 и устроен прозрачнее, чем кажется: внутри два потенциометра по 5 кОм — по одному на ось — плюс тактовая кнопка под стержнем ручки. Концы каждого потенциометра сидят на питании и земле, а средний отвод выведен наружу на контакты VRx и VRy. Наклон стержня поворачивает пластиковый крест, движки съезжают, и напряжение на отводах ползёт от нуля вольт до питания: analogRead превращает его в число от 0 до 1023.
Кнопка SW живёт отдельно от осей: нажатие замыкает её контакт на землю, в покое линия подтянута к 5 В. В этом уроке подключим все пять контактов, научимся печатать кадры парами x= y= sw=, откалибруем центр под конкретный экземпляр и поставим мёртвую зону 480-540, чтобы покой не притворялся движением. Направления — лево, право, верх, низ — мы уже строили в уроке про две оси; здесь копаем глубже, в железо и допуски.
Пять контактов и два движка
Схема подключения занимает минуту. VCC идёт к 5 В, GND к земле, VRx к A0, VRy к A1 — и оси уже читаются. Это тот же делитель напряжения, что и у одиночного потенциометра из урока про analogRead, только движков два и командует ими один стержень. Номинал 5 кОм подобран удачно: ток через движок — доли миллиампера, вход АЦП нагрузку не чувствует, показания не плывут. Встречаются партии и с 10-килоомными движками — на чтение это не влияет: АЦП видит одну и ту же пропорцию делителя.
Кнопка SW сядет на любой цифровой вход. В симуляторе автоподбор макетки отдаёт ей A2; на живой плате я сразу вешаю SW на D2 — там живут внешние прерывания, которые пригодятся в меню из третьего урока этого кластера. У типовых модулей резистор подтяжки к 5 В уже распаян на плате, поэтому в покое digitalRead видит HIGH, при нажатии — LOW. Клоны без резистора тоже встречаются, и для них спасает INPUT_PULLUP в скетче: полярность при этом не меняется, а вход перестаёт зависеть от щедрости производителя.
Механика — вторая половина правды о показаниях. Возвратная пружина возвращает стержень в центр, но не идеально: у изношенных модулей ручка не доходит до крайних положений, и вместо 0-1023 вы увидите, скажем, 8-1015. Поэтому первое, что я делаю с новым джойстиком, — гоняю ручку до упора в четыре стороны и записываю минимумы с максимумами. Эти четыре числа потом кормятся в map, и весь ход ручки распределяется по диапазону без мёртвых сантиметров на краях. Заодно проверьте дрожь на упорах: у живого модуля число на краю стоит как вкопанное, у разбитого — плавает на десяток единиц, и это второй аргумент за мёртвую зону.
| Контакт | Куда на плате | Что вы увидите |
|---|---|---|
| VCC | 5 В | питание двух потенциометров |
| GND | GND | общая земля с платой |
| VRx | A0 | ось X: 0-1023, в покое 500-523 |
| VRy | A1 | ось Y: тот же диапазон, своя полоса центра |
| SW | цифровой вход, в симе A2 | HIGH в покое, LOW при нажатии |
Центр, кадры и мёртвая зона
Читать оси удобно кадрами: пары x= и y= с шагом 250 миллисекунд дают читаемый лог и три именованных ряда на графике Serial Plotter. Кнопку печатаем в том же кадре числом sw=: единица в покое, ноль при нажатии. На живой плате кадры полезно снимать и рядом с вибрацией — моторы подмешивают шум, и полоса покоя расползается на глазах. Запустите скетч и не трогайте ручку — центр ляжет где-то в полосе 500-523: два резистора делителя имеют допуск, пружина возвращает стержень с небольшим недолётом, и у каждого экземпляра точка покоя своя. В симуляторе полоса сжата в одну точку 512 — макетка не знает допусков, и это удобно для отладки логики.
Мёртвая зона — коридор вокруг центра, внутри которого чтения считаются покоем. Полоса 480-540 покрывает и разброс центра, и шум в пару единиц; стоит отдать ось на серво — и без зоны каждое качание на 3-5 единиц превращается в микродёрганье рычага. Шире 100 единиц коридор не делайте: ручка перестанет отвечать вблизи центра, и управление станет ступенчатым. Если шум больше ожидаемого — сначала среднее нескольких чтений АЦП, потом расширение зоны: пять замеров гасят дрожь последних единиц почти бесплатно. Свою полосу покоя я смотрю по логу за минуту: если за шестьдесят секунд ни один кадр не вышел за 490-535, коридор 480-540 закроет всё с запасом.
// Джойстик: центр = среднее 10 чтений, дальше кадры в мониторе const int PIN_SW = A2; // в симуляторе SW садится на A2, на плате — любой цифровой int centerX = 512;int centerY = 512; void setup() { Serial.begin(9600); pinMode(PIN_SW, INPUT_PULLUP); // SW замыкает на GND: в покое HIGH long sumX = 0; long sumY = 0; for (int i = 0; i < 10; i++) { // центр = среднее 10 чтений, 100 мс sumX = sumX + analogRead(A0); sumY = sumY + analogRead(A1); delay(10); } centerX = sumX / 10; centerY = sumY / 10; Serial.print("centerX="); Serial.println(centerX); Serial.print("centerY="); Serial.println(centerY);} void loop() { int x = analogRead(A0); int y = analogRead(A1); int sw = digitalRead(PIN_SW); Serial.print("x="); Serial.print(x); Serial.print(" y="); Serial.print(y); Serial.print(" sw="); Serial.println(sw); delay(250);}Калибровка центра в setup — мой постоянный ритуал: десять чтений с паузой по 10 миллисекунд, среднее — и в переменную. Стоит это сто миллисекунд при старте, а взамен покой всегда даёт ноль отклонения: разность вычисляется от своего центра, а не от бумажных 512. На живой плате строка centerX=507 в начале лога честно говорит, где у вашего модуля середина хода, и все дальнейшие пороги откладываются от неё. В симуляторе centerX= выйдет ровно 512 — и это тоже тест: если строка печатает другое, скетч читает не тот пин.
С кнопкой работают те же мысли, что и с осью: печатайте сырой уровень и доверяйте фронтам. Для счёта нажатий этого мало — дребезг тактовой кнопки превращает один щелчок в три-пять событий, и лечится он дебаунсом, которому посвящён третий урок кластера. Куда отдать оси дальше — вопрос одного провода: сервопривод SG90 на D11 получает угол оси через map, а ручное управление углом мы уже делали с обычным потенциометром — джойстик отличается тем, что сам возвращается в центр.
История с «уехавшей» осью случилась у меня уже в готовой сборке: неделю кадры стояли по центру 511, потом x в покое намертво сел на 534. Я грешил на модуль, а виноват оказался удлинитель метр с лишним — передавленная жилка в линии VRx дала лишнее сопротивление, и ось уползла. С тех пор джойстик длиннее метра не тяну, а после любой пересборки макетки сначала смотрю кадр покоя и только потом калибрую центр заново.
На живой плате к арифметике добавляется макетка. Плохой контакт в проводе VRx даёт щелчки в логе: x прыгает на сотни единиц на мгновение и возвращается. Мой порядок диагностики простой: сначала пошевелите провода при работающем логе — прыжки в кадрах показывают виновника точнее любых догадок; потом пересадите VRx с A0 на A1 — если симптом переехал за проводом, дело в линии, если остался — в модуле. Десять чтений для калибровки — минимальная планка: при шумной макетке берите двадцать-тридцать, это всё ещё меньше трёхсот миллисекунд на старте. Симулятор этой комнаты с граблями лишён, зато логика зон на нём отрабатывается без помех.
- 1. Сколько потенциометров внутри KY-023 и какого номинала?
- 2. digitalRead на SW типового модуля вернул HIGH. Что это значит?
- 3. В покое ось показывает 523 вместо 512. Ваши действия?
- 4. Зачем оси мёртвая зона 480-540?
- 5. SW печатает мусор 0 и 1 в покое. Первая проверка?
- KY-023 — два потенциометра по 5 кОм с отводами VRx/VRy и кнопка SW, замыкающая на GND; пять проводов — вся схема.
- Центр в покое живёт в полосе 500-523, а не ровно на 512: допуски резисторов и механики; калибруйте средним из 10 чтений в setup.
- Полный диапазон оси — 0-1023; у изношенных модулей края не дотягивают: снимите минимум и максимум до упора в каждую сторону.
- Мёртвая зона 480-540 объявляет покоем всё внутри коридора: без неё серво отрабатывает шум оси дрожью рычага.
- SW с подтяжкой (своя на модуле или INPUT_PULLUP) даёт HIGH в покое и LOW при нажатии; без подтяжки вход читает мусор от руки.
Частые вопросы по теме урока
- Сколько потенциометров внутри KY-023 и какого номинала?
- Оси X и Y — это два потенциометра по 5 кОм (встречаются партии с 10-килоомными), средние отводы выведены на VRx и VRy. Кнопка — отдельный элемент. два по 5 кОм, по одному на ось
- digitalRead на SW типового модуля вернул HIGH. Что это значит?
- У типовых модулей SW через подтяжку к 5 В: покой — HIGH, нажатие — LOW. INPUT_PULLUP даёт ту же полярность на клонах без резистора. кнопка в покое — модуль тянет линию к 5 В через подтяжку
- В покое ось показывает 523 вместо 512. Ваши действия?
- Допуски резисторов и недолёт пружины дают каждому экземпляру свой центр в полосе 500-523. Среднее 10 чтений в setup фиксирует ваш центр. норма: центр гуляет в полосе 500-523 из-за допусков — калибруем
- Зачем оси мёртвая зона 480-540?
- Разброс центра плюс шум в пару единиц без зоны превращаются в дрожь рычага. Коридор 480-540 объявляет покоем всё, что внутри, и держит прежнее значение. чтобы покой в центре не двигал исполнитель — например, серво
- SW печатает мусор 0 и 1 в покое. Первая проверка?
- Плавающий вход ловит наводки от руки. Подтяжка к 5 В — на модуле или внутри контроллера через INPUT_PULLUP — возвращает полярность HIGH-покой, LOW-нажатие. подтяжка: INPUT_PULLUP в скетче или модуль с резистором на плате