Джойстик Ардуино – подключение и скетч. Делаем еще один джойстик (геймпад) на Arduino Joystick shield v1 a подключение

Шла обычная пятница, ничто не предвещало беды…

Но червь «нужно что-то сделать» уже начал свою работу. После прочтения статьи я вспомнил, что у меня в барахле лет 15, если не больше, валяется сеговский геймпад. Забрал я его с твердым намерением сделать геймпад на процессоре AVR (про ардуино я тогда и не слышал, но пару небольших проектов на AVR сделал).

Еще больше утвердила мое намерение статья про MSX , и в пятницу я решил - делаю!


Из закромов был вытащен на белый свет сеговский геймпад в разобранном состоянии. К моему изумлению он был в полном комплекте (ну, если не считать порезанные дорожки и отсутствующий оригинальный контроллер), не хватало только 2-х болтиков.

В качестве контроллера я решил использовать Beetle , так как он был заказан мной когда-то, но пока не испробован, да и не очень понравился «малым количеством портов».

И тут меня ждало разочарование - портов 6, кнопок 10. Горю моему не было предела, но мозг таки нашел решение, для начала я решил попробовать собрать прототип из 2-х кнопок, так как я решил использовать фокус с диодом, чтобы опрашивать 10 кнопок с помощью 6 выводов. Практически окрыленный, я засел за проверку… И тут случилась следующая неприятность - кнопок на джойстике больше, чем 10! В общем это был тот момент, когда нужно было смотреть в документацию, хотя идей было много - например припаять (ага, моим паяльником, который накрывает почти все ножки с одной стороны микросхемы), или поискать просветления в интернете.
Документация же четко сказала, что портов у Beetle на самом деле не 6, а 10, что сделало дальнейший процесс скучным (так я думал). (Использование 8 выводов дает возможность опрашивать 2 * 6 = 12 кнопок, что мне и было нужно)

Схема подключения - матрица 6 х 2, потому как оригинальная плата была разведена удобным мне образом. (Кстати в процессе предыдущей переделки дорожки были порезаны, чтобы подключить клавиатурный контроллер, пришлось восстанавливать, вышло страшненько)

Схема получившегося геймпада:

Быстро накидав пример я убедился что он не работает… Не понял?! Пример то простейший. Подумав, сообразил, что цифровому пину не хватает того сопротивления, что дают резиновые токопроводящие кнопки, немного изменил схему, теперь читается аналоговый сигнал и сравнивается с половиной максимума. Перепаиваю контакты, переписываю программу и… ничего не работает, совсем. Контроллер не определяется, все пропало. Код проверен, и перепроверен, все должно работать! А контроллер не видится ни в какую. Мотивация падает, делаем перерыв.

Через некоторое время безуспешно поигравшись с Beetle, ну все, убил контроллер своим паяльником, с сожалением достаю из закромов Arduino Micro, прошиваю прошивку и снова тишина! Становится понятно, что-то не так с кодом, в конце концов нахожу банальную причину - бесконечный цикл в loop(), исправляю, но зашить то не могу! Оказывается проблема, когда контроллер не видится решается нажатием на резет во время прошивания (или замыканием пинов в моем случае)

В итоге получился сеговский геймпад, проверен, работает, я счастлив: поиграл в Metal Gear, Felix The Cat, Super Mario.





P. S. «Трюк со светодиодом». Конечно не обязательно использовать светодиод, обычный диод лучше подходит, суть простая, вместо двух выводов использовать один, соединенный с разными кнопками через 2 диода:


Процесс сборки самоделки:

Шаг первый. Подключаем серводвигатели
Процесс сборки самоделки начинается с подключения серводвигателей. Для того чтобы собрать предварительный макет, применяется монтажная плата. Потом можно будет сделать отдельный шилд. На рисунке можно увидеть, как именно все подключается.


Красный кабель - это питание, он подключается к пину 5V на контроллере Arduino.
Черный провод - это минус (земля), он подключается к выходу на Arduino под названием GND.
Желтый кабель от серводвигателя Right & Left нужно подключить к пину 11. На некоторых моделях он может быть и белого цвета.
Аналогичный желтый кабель Up & Down нужно подключить к пину 4. Он также на некоторых моделях двигателей может быть белого цвета.
Важно помнить, что коннекторы сигнала, которыми происходит управление двигателем, исходят из ШИМ выходов.

Шаг второй. Подключаем джойстик

Как подключается джойстик, можно увидеть на картинке. Поначалу схема может показаться довольно сложной, но на самом деле ничего сложного здесь нет. Как и в случае с двигателями для подключения здесь используется монтажная плата.


1. На модуле джойстика можно найти выходы U/R+ и L/R+. Через эти выходы происходит подключение питания. Соответственно сюда нужно подать напряжение +5V от соответствующего пина на Arduino.

2. Еще на джойстике присутствует два разъема под названием L/R и два разъема U/D. Их нужно подключить к аналоговым выходам А3 и А4.

3. Ну и в заключении землю на джойстике нужно соединить с землей на Arduino.

После сборки подключение нужно перепроверить. Именно из-за ошибок подключения в большинстве случаев возникают проблемы. Особенно это касается случаев, когда используется монтажная плата и на ней находится много подключений.

Шаг третий. Скетч для Arduino
Код очень простой и в нем присутствуют подробные комментарии. Приведенный код нужно просто скопировать в Arduino IDE. После того как код будет загружен, двигатели не должны двигаться. Они должны начинать двигаться только при нажатии кнопки на джойстике.


Проблемы, которые могут возникнуть и способы их решения
1. Если двигатели не включаются, нужно перепроверить подключение. Для подключения двигателей используются выходы типа ШИМ, а для подключения джойстиков применяются аналоговые выходы.

2. Бывает такое, что сразу после загрузки кода двигатели начинают вибрировать. Такое бывает если неправильно подключить пины U/D+ L/R+. Подключение нужно тщательно проверить. Чтобы не сжечь плату во время проверки, ее нужно обязательно отключить от компьютера.

3. Если все перепроверено, но двигатели все равно не хотят работать, можно попробовать переподключить джойстик. Его нужно снять с монтажной платы, а затем установить назад с некоторым усилием. Коннекторы джойстика должны хорошо войти в макетку.

Если все вышло, теперь можно приступать к созданию каких-либо самоделок с управлением через джойстик. К примеру, можно сделать робота, которым можно будет управлять с помощью джойстика, и многое другое.

Сегодня я решил попробовать управлять сервоприводом при помощи джойстика, собрав простую схемку на базе Arduino Uno.

Что нам потребуется

  1. Соединительные провода;

Исходный код

#include
int joyX=0;
int angl=0;
Servo myservo;
void setup()
{
myservo.attach(9);
pinMode(joyX,INPUT);
Serial.begin(9600);
}
void loop()
{
int val = (analogRead(joyX)/64)-8;
if (val > 0) {
angl=angl+abs(val);
}
else {
if (val < 0) {
angl=angl-abs(val);}
}
if (angl < 0) angl = 0;
if (angl > 180) angl = 180;
Serial.print("Power: ");
Serial.println(val);
Serial.print("Angle: ");
Serial.println(angl);
myservo.write(angl);
int spd = 500;
if (val != 0) {
spd = 600/abs(val);
}
Serial.print("Speed: ");
Serial.println(spd);
Serial.println("-----------");
delay(spd);
}

Как это работает

Управлять сервоприводом оказалось просто (с использованием библиотеки). Мы просто вызываем функцию write и значение угла поворота в градусах. А вот само значение угла мы будем изменять динамически с помощью джойстика.

В цикле считывается значение с аналогового входа (изменяется от 0 до 1023 в зависимости от положения джойстика), я делю это значение, чтобы уменьшить шаг на 64 и вычитаю 8, чтобы усреднить. Теперь мы будем иметь значение от 7 до -8. Затем на это значение я изменяю переменную, хранящую угол поворота. Также изменяю задержку в зависимости от этого значения. Чем больше отклонение, тем меньше задержка (быстрее происходит вращение).

  1. С Arduino берём +5 В на одну сторону бредборда (красный првоод);
  2. Чёрный провод идёт с GND на другую сторону бредборда;
  3. Сигнальный пин – девятый, зелёный провод, идёт на сервомотор (жёлтый шлейф);
  4. Так же на аналоговый вход a0 подаётся синий провод от джойстика (пин S-X);
  5. С джойстика VCC стороны X идёт красным проводом на +5 В бредборда;
  6. С джойстика GND стороны X идёт белым проводом на GND общее бредборда;
  7. Ну и соответственно белый провод GND бредборда в чёрный шлейф сервомотора;
  8. Оранжевый провод +5 В бредборда в красный шлейф сервомотора;

Что получилось

Использование джойстика – это один из способов обмена информацией между человеком и устройством (компьютер, микроконтроллер) на основе Arduino. Чаще всего их используют для управления механизмами или роботами. По аналогии с привычным игровым миром джойстики также часто называют геймпадами. Геймпад прост и удобен в использовании. Сегодня существует большое количество видов джойстиков по количеству степеней свободы, частоте считывания информации и используемой технологии. В данной статье мы рассмотрим наиболее популярный вариант, научимся управлению джойстиком и узнаем, как его подключать.

Аналоговый джойстик выглядит как ручка, которая закрепляется на шарнире с двумя потенциометрами, определяющими оси X и Y, и кнопкой Z. Наклон или поворот ручки вращает специальный подвижный контакт, из-за чего изменяется выходное напряжение. Сам геймпад оснащен пружиной, благодаря которой плавно возвращается в первоначальное центральное состояние после отпускания его с какой-либо позиции. Устройство позволяет более плавно отследить степень отклонения от центральной (нулевой) точки.

Подключение джойстика к ардуино

Подключение джойстика к Arduino Uno выполняется по схеме, приведенной ниже.

На модуле имеется 5 выходов – Vcc, Gnd, X, Y и Key (обозначения могут различаться в зависимости от устройства).

Данные по оси X выводятся на вход А0, по оси Y – на А1. Для визуального контроля нажатия кнопки также можно подключить светодиод D11. Питание осуществляется напряжением 5 Вольт. Пин GND присоединяется к такому же пину на плате Ардуино. Контакт SW можно подсоединить к любому цифровому пину.

Как видим, подключение модуля джойстика не сложно. Если устройство не работает после подключения, проверьте, правильно ли вы подсоединили все пины.

Как отслеживать текущее положение или направление джойстика

Для использования джойстка в реальном проекте нам понадобится написать скетч, чтобы обрабатывать данные, которые отправляет джойстик во время своей работы.

Узнать, в каком положении в текущий момент находится устройство, можно в зависимости от значений потенциометров. Перемещение происходит по направлению находящихся перпендикулярно осей X и Y. Считывание информации с геймпада происходит с помощью – она показывает значения в диапазоне от 0 до 1023. В качестве аргументов ей поступают номера пинов, к которым произведено подключение джойстика:

Serial.println(analogRead(A0)); // показывает положение X координаты

Serial.println(analogRead(A1)); // показывает положение Y координаты

Для удобства советуется использовать константы, чтобы уменьшить и упростить итоговый код. Аналоговые пины как раз можно объявить постоянными:

const byte PIN_ANALOG_X = A0; // постоянная для координаты Х

const byte PIN_ANALOG_Y = A1; // постоянная для координаты Y

Определение направления движения джойстиком

Управление с помощью джойстика подразумевает собой то, что мы должны узнать направление движения ручки джойстика. Для этого нам придется получить и интерпретировать данные по всем осям.

По значению положений осей X и Y можно узнать, находится ли джойстик в центре или произошло смещение. Значения во всех направлениях находятся в диапазоне от 0 до 1023, как говорилось ранее. В первую очередь приходит мысль, что центральная точка будет находиться примерно в значении 511-512. Это заключение не совсем правильно, так как абсолютно точное положение определить нельзя.

Неверное определение центрального значения может привести к тому, что будет получена ошибочная информация о движении джойстика, если он будет находиться в неподвижном состоянии. Для этого следует выбрать числовой диапазон и условно считать, что любое значение в нем будет центральной точкой. Значения нужно подстраивать под каждый вид джойстика, но примерно оно будет в диапазоне 505-518. Полученные значения записываются в код в виде постоянных:

const int X_THRESHOLD_LOW = 505;

const int X_THRESHOLD_HIGH = 518;

const int Y_THRESHOLD_LOW = 500;

const int Y_THRESHOLD_HIGH = 510;

Следующим шагом будет преобразование координат в диапазон от -1 до 1. Для X -1 – это перемещение влево, 0 – нет движения, 1 – вправо. По Y -1 – движение вниз, 0 – центральное значение, 1 – вверх. Изначально устанавливаем все значения в центр 0. Для проверки, происходит ли перемещение, используем выражения if/else.

Подводные камни в работе геймпада

Как и с любое устройство, джойстики не лишены недостатков. В первую очередь, наличие пружины не позволяет ручке точно вернуться в центральное положение из-за трения в механических деталях. Это приводит к тому, что приходится программно определять центральное положение, вернее диапазон значений, в которых любая точка будет условно считаться серединой.

Второй проблемой можно назвать наличие так называемых мертвых зон. Два крайних значения при наибольших отклонениях должно быть равным 0 В и напряжению питания. В действительности эти значения могут различаться, так как не используется весь электрический диапазон изменения сопротивления. Для решения этой проблемы крайние точки могут соответствовать значениям 1 кОм и 9 кОм.

Плата расширения JoyStick shield

Для управления роботами или другими механизмами иногда требуется использовать джойстик к кнопками и средствами коммуникаций. Для того, чтобы не придумывать каждый раз новые конструкции, рекомендуется купить готовую плату расширения ардуино для джойстика, в которой все необходимые элементы будут спаяны.

Рассмотрим, что представляет собой этот шилд от известного в мире ардуино производителя Sparkfun. Данный геймпад работает исправно и стоит относительно недорого. Устройство может поставляться в немного разобранном виде, так что сначала его нужно собрать.


Шилд содержит несколько стандартных кнопок (4 обычных сбоку и кнопка выбора). В зависимости от модели, на плате могут быть добавлены разъемы для подключения модулей bluetooth или wifi. Традиционно, с помощью выходов пинов и гребенки можно подключать внешние устройства.

Заключение

Джойстик ардуино – незаменимая вещь во моих проектах. Благодаря этому виду датчиков вы можете добавить в свое устройство удобные и современные средства управления. В некоторых ситуациях без джойстика вообще обойтись практически невозможно: джойстик ардуино используется для управления роботами, умными машинами, сервоприводами, громкостью музыкой и яркостью подсветки на мониторе, как навигация в различных играх и во многих других проектах.

Подключение готового модуля не сложно, так же весьма доступным является и сам управляющий скетч. Чаще всего, джойстик используется в месте с кнопками и в паре с беспроводными интерфейсами, потому то управлять джойстиком на проводе быстро перемещающимися устройствами практически невозможно. Поэтому рекомендуется для работы использовать готовые шилды, в которых есть все необходимое.

Является модулем ввода данных. С его помощью можно управлять роботами, манипуляторами, станками, различными моделями (машинки, танки, самолёты, вертолёты, квадрокоптеры, лодки и т.д.), а также использовать для создания игровых приставок, выбора пунктов меню на дисплеях и индикаторах, ввода значений, и т.д. Джойстик можно не только перемещать по осям X и Y, но и нажимать на него.

Видео:

Спецификация:

  • Напряжение питания: 5 В / 3,3 В (оба напряжения входят в диапазон допустимых значений).
  • Потребляемый ток: < 10 мА
  • Габариты: 30x30 мм

Все модули линейки "Trema" выполнены в одном формате

Подключение:

  • Выводы «X» и «Y» модуля подключается к любым аналоговым входам Arduino . Значения, считываемые с этих выводов, растут при перемещении джойстика слева на право и снизу вверх.
  • Вывод «K» является цифровым и подключается к любому выводу Arduino . В обычном состоянии на нём уровень логического «0», а при нажатии на джойстик, он меняется на логическую «1».
  • Выводы «V» и «G» являются выводами питания.

Модуль удобно подключать 3 способами, в зависимости от ситуации:

Способ - 1: Используя проводной шлейф и Piranha UNO

Используя провода «Папа - Мама », подключаем напрямую к контроллеру Piranha UNO


Способ - 2: Используя Trema Set Shield

Модуль можно подключить к любому из аналоговых входов Trema Set Shield.


Способ - 3: Используя проводной шлейф и Shield

Используя 5-и проводной шлейф, к Trema Shield, Trema-Power Shield, Motor Shield, Trema Shield NANO и тд.


Питание:

Входное напряжение 5 В или 3,3 В постоянного тока, подаётся на выводы Vcc (V) и GND (G).

Подробнее о модуле:

Данные модуля считываются с двух потенциометров и тактовой кнопки, механически связанных с рычагом джойстика. Кнопка подключена в разрыв питания Vcc и выхода «K», который прижат к GND через резистор. Следовательно, на выходе «K» может устанавливаться только два состояния: логический «0» (кнопка отпущена) или «1» (кнопка нажата). Выводы координат «X» и «Y» являются аналоговыми выходами модуля, они подключены к потенциометрам так, что напряжение снимаемое между этими выводами и GND растет при перемещении джойстика слева на право и снизу вверх.

Примеры:

Определение положения джойстика и включение светодиода по нажатию кнопки

const int8_t Xaxis = A0; // Определяем номер вывода, к которому подключен контакт оси Х джойстика const int8_t Yaxis = A1; // Определяем номер вывода, к которому подключен контакт оси У джойстика const int8_t Button = 2; // Определяем номер вывода, к которому подключен контакт кнопки джойстика const int8_t LED = 7; // Определяем номер вывода, к которому подключен светодиод uint16_t XborderMIN = 505; // Задаём границу значений, НИЖЕ которой будет считаться, что джойстик отклонён по оси Х влево uint16_t XborderMAX = 515; // Задаём границу значений, ВЫШЕ которой будет считаться, что джойстик отклонён по оси Х вправо uint16_t YborderMIN = 505; // Задаём границу значений, НИЖЕ которой будет считаться, что джойстик отклонён по оси У вниз uint16_t YborderMAX = 515; // Задаём границу значений, ВЫШЕ которой будет считаться, что джойстик отклонён по оси У вверх uint16_t Xvol = 0, Yvol = 0; // Задаём переменные, которые будут принимать значения, считанные с осей джойстика void setup() { Serial.begin(9600); // Инициируем передачу данных в монитор последовательного порта pinMode(LED, OUTPUT); // Настраиваем вывод LED на работу в режиме выхода pinMode(Button, INPUT); // Настраиваем вывод Button на работу в режиме входа } void loop() { Xvol = analogRead(Xaxis); // Считываем значения оси Х Yvol = analogRead(Yaxis); // Считываем значения оси У if (Xvol < XborderMIN) { // Проверяем, полученное значение Х меньше нижней границы центрального положения или нет. Если да, то if (Yvol < YborderMIN) { // проверяем, полученное значение У меньше нижней границы центрального положения или нет. Если да, то Serial.println("Left-Down"); // значит джойстик находится в положении ВЛЕВО-ВНИЗ } else if (Yvol > YborderMAX) { // Если же полученное значение У больше верхней границы центрального положения, то Serial.println("Left-Up"); // значит джойстик находится в положении ВЛЕВО-ВВЕРХ } else { Serial.println("Left"); // Если же полученное значение У входит в границы центрального положения по оси У, значит джойстик отклонён ВЛЕВО } } else if (Xvol > XborderMAX) { // Проверяем, полученное значение Х больше верхней границы центрального положения или нет. Если да, то if (Yvol < YborderMIN) { // проверяем, полученное значение У меньше нижней границы центрального положения или нет. Если да, то Serial.println("Right-Down"); // значит джойстик находится в положении ВПРАВО-ВНИЗ } else if (Yvol > YborderMAX) { // Если же полученное значение У больше верхней границы центрального положения, то Serial.println("Right-Up"); // значит джойстик находится в положении ВПРАВО-ВВЕРХ } else { Serial.println("Right"); // Если же полученное значение У входит в границы центрального положения по оси У, значит джойстик отклонён ВПРАВО } } else { // Если полученное значение Х входит в границы центрального положения по оси Х, значит if (Yvol < YborderMIN) { // проверяем, полученное значение У меньше нижней границы центрального положения или нет. Если да, то Serial.println("Down"); // значит джойстик находится в положении ВНИЗ } else if (Yvol > YborderMAX) { // Если же полученное значение У больше верхней границы центрального положения, то Serial.println("Up"); // значит джойстик находится в положении ВВЕРХ } else { Serial.println("Center"); // Если же полученное значение У входит в границы центрального положения по оси У, значит джойстик находится в центре. } } if (digitalRead(Button)) { // Проверяем, нажата ли кнопка delay(1); // Если кнопка была нажата, то подавляем дребезг digitalWrite(LED, !digitalRead(LED)); // и меняем состояние на выходе светодиода Serial.println("Button click!"); // Выводим текст о том, что кнопка была нажата while (digitalRead(Button)) {} // Если кнопка удерживается, то ничего не делаем delay(10); // Если кнопка отпускается, то подавляем дребезг } }

В мониторе последовательного порта вы увидите.