Общие сведения:
В этом уроке мы создадим робота, который будем управлять с помощью удобного геймпада.
Изменяя положение левого стика (джойстика), робот будет менять направление движения, а нажатие на кнопки "КРУГ" или "КВАДРАТ" в правой части геймпада будет включать или выключать светодиодные модули.
Видео:
Нам понадобится:
- 1х Arduino / Piranha UNO;
- 1х Battery Shield;
- 1х Motor Shield;
- 2х Мотор-редуктора;
- 2х Крепеж для мотора;
- 2х Колесо;
- 1х Шаровая опора;
- 1х Светодиод красный;
- 1х Светодиод синий;
- 1х Геймпад DualShock 2;
- 1х ПВХ-пластина для крепления Piranha/Arduino UNO;
- 1х ПВХ-конструктор;
- 1х Комплект проводов;
Для реализации проекта нам необходимо установить библиотеки:
О том, как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE.
Описание работы робота:
После подачи питания робот готов к работе.
Нажимая на рукоятку джойстика вы выбираете направление движения робота.
Нажимая кнопки на правой части геймпада, вы включаете/выключаете светодиоды.
Схема сборки:
Arduino / Piranha UNO:
Batery Shield:
Установите Battery Shield на Arduino / Piranha UNO:
Во время установки Battery Shield должен быть в выключенном состоянии.
Motor Shield:
На Battery Shield установите Motor Shield
Светодиоды:
Подключите светодиоды к Motor Shield
Мотор-редукторы:
Подключите мотор-редукторы к Motor Shield
Крепёж 1:
Закрепите на ПВХ-пластине шаровую опору и мотор-редукторы
Крепёж 2:
Закрепите на ПВХ-конструкторе светодиоды и приёмник геймпада (с помощью стяжки)
Геймпад:
Подключите приёмник геймпада к Motor Shield
Вывод приёмника | Вывод Arduino |
GND | GND |
VCC | 5В |
DAT (MISO) | 12 |
CMD (MOSI) | 11 |
CLK (SCK) | 13 |
ATT (CS) | 10 |
Код программы (скетч):
#include <PsxControllerHwSpi.h> const uint8_t PS2_attention = 10; // Вывод Arduino, к которому подключен вывод приёмника геймпада ATT PsxControllerHwSpi<PS2_attention> psx; // Создаём объект "ps2x" uint8_t RAW_UP_OR_DOWN = 0; // переменная "сырых" значений с джойстика по оси Оу uint8_t RAW_LEFT_OR_RIGHT = 0; // переменная "сырых" значений с джойстика по оси Ох uint8_t GO_LEFT = 0; // переменная для хранения отсортированных значений по оси Ох для движения влево uint8_t GO_RIGHT = 0; // переменная для хранения отсортированных значений по оси Ох для движения вправо uint8_t GO_UP = 0; // переменная для хранения отсортированных значений по оси Оу для движения вверх uint8_t GO_DOWN = 0; // переменная для хранения отсортированных значений по оси Оу для движения вниз uint8_t pinShield_H2 = 4; // Вывод, подключенный к драйверу, для задания направления вращения левым мотором uint8_t pinShield_E2 = 5; // Вывод ШИМ, подключенный к драйверу, для задания скорости левого мотора uint8_t pinShield_E1 = 6; // Вывод ШИМ, подключенный к драйверу, для задания скорости правого мотора uint8_t pinShield_H1 = 7; // Вывод, подключенный к драйверу, для задания направления вращения правым мотором uint8_t valSpeed = 0; // Максимальная скорость ШИМ (число от 0 до 255) uint8_t led_right = 2; uint8_t led_left = 3; bool arrRoute[2] = {0, 0}; // Направление движения для каждого мотора ([0]- правый мотор, [1] - левый мотор) uint16_t arrSpeed[2]; // Скорость для каждого мотора ([0]- правый мотор, [1] - левый мотор) uint8_t flg; // Флаг направлений движения машинки bool flg_led_right = false; // Флаг работы светодиода красного цвета bool flg_led_left = false; // Флаг работы светодиода синего цвета // ГЕЙМПАД // Функция конфигурирования контроллера void configureGamepad(bool& configured) { if (psx.begin()) { // входим врежим конфигурирования if (!psx.enterConfigMode()) return; // если удалосль войти else { // включаем аналоговые джойстики psx.enableAnalogSticks(); // выходим из режима конфигурации psx.exitConfigMode(); // устанавливаем флаг конфигурации configured = true; } } } // Чтение контроллера void readGamepad(bool& configured) { // если не удалось прочитать - сбрасываем флаг конфигурации if (!psx.read()) configured = false; } // Обработка контроллера void handleGamepad() { static bool configured = false; // если не сконфигурирован - конфигурируем, передавая флаг if (!configured) { configureGamepad(configured); } // если сконфигурирован - читаем, передавая флаг else { readGamepad(configured); } } void setup() { // МОТОРЫ pinMode(pinShield_H2, OUTPUT); // Конфигурируем вывод pinShield_H2 как выход (направление вращения левого мотора) pinMode(pinShield_E2, OUTPUT); // Конфигурируем вывод pinShield_E2 как выход (скорость вращения левого мотора, ШИМ) pinMode(pinShield_E1, OUTPUT); // Конфигурируем вывод pinShield_E1 как выход (скорость вращения правого мотора, ШИМ) pinMode(pinShield_H1, OUTPUT); // Конфигурируем вывод pinShield_H1 как выход (направление вращения правого мотора) // СВЕТОДИОДЫ pinMode(led_right,OUTPUT); pinMode(led_left, OUTPUT); } void loop() { // обработка геймпада handleGamepad(); // Считываем "сырое" аналоговое значение с левого джойстика psx.getLeftAnalog(RAW_LEFT_OR_RIGHT, RAW_UP_OR_DOWN); // Если была нажата кнопка "КРУГ", то включаем красный светодоид if (psx.buttonPressed(PSB_CIRCLE)) { flg_led_right = !flg_led_right; digitalWrite(led_right, flg_led_right); } // Если была нажата кнопка "КВАДРАТ", то включаем синий светодоид if (psx.buttonPressed(PSB_SQUARE)) { flg_led_left = !flg_led_left; digitalWrite(led_left, flg_led_left ); } if (RAW_UP_OR_DOWN <=120) {GO_UP = map(RAW_UP_OR_DOWN, 0, 120, 255, 0); GO_DOWN = 0;} else // Если значение по оси Оу меньше 120, значит джойстик сдвинут вверх, переопределяем диапазон значений с джойстика (переворачиваем его) if(RAW_UP_OR_DOWN >=135) {GO_DOWN = map(RAW_UP_OR_DOWN, 135, 255, 0, 255); GO_UP = 0;} else // Если значение по оси Оу больше 135, значит джойстик сдвинут вниз, переопределяем диапазон значений с джойстика {GO_DOWN = 0; GO_UP = 0;} // Если значение находится в диапазоне от 120 до 135 - значит джойстик находится в центральном положении if (RAW_LEFT_OR_RIGHT <=120){GO_LEFT = map(RAW_LEFT_OR_RIGHT, 0, 120, 255, 0); GO_RIGHT = 0;} else // Если значение по оси Ох меньше 120, значит джойстик сдвинут влево, переопределяем диапазон значений с джойстика (переворачиваем его) if(RAW_LEFT_OR_RIGHT >=135){GO_RIGHT = map(RAW_LEFT_OR_RIGHT, 135, 255, 0, 255); GO_LEFT = 0;} else // Если значение по оси Оу больше 135, значит джойстик сдвинут вправо, переопределяем диапазон значений с джойстика {GO_LEFT = 0; GO_RIGHT = 0;} // Если значение находится в диапазоне от 120 до 135 - значит джойстик находится в центральном положении if (GO_UP){ // Если джойстик был сдвинут вверх, то if(!GO_LEFT || !GO_RIGHT) {flg = 2; valSpeed = GO_UP;} else // проверяем, сдвинут ли он вправо/влево, и если нет, то устанавливаем флаг движения на север if(GO_LEFT) {flg = 1; valSpeed = GO_UP;} else // если джойстик сдвинут влево, то устанавливаем флаг движения на северо-запад if(GO_RIGHT) {flg = 3; valSpeed = GO_UP;}} else // если джойстик сдвинут вправо, то устанавливаем флаг движения на северо-восток if(GO_DOWN){ // если джойстик сдвинут вниз, то if(!GO_LEFT || !GO_RIGHT) {flg = 8; valSpeed = GO_DOWN;} else // проверяем, сдвинут ли он вправо/влево, и если нет, то устанавливаем флаг движения на юг if(GO_LEFT) {flg = 7; valSpeed = GO_DOWN;} else // если джойстик сдвинут влево, то устанавливаем флаг движения на юго-запад if(GO_RIGHT) {flg = 9; valSpeed = GO_DOWN;}} else // если джойстик сдвинут вправо, то устанавливаем флаг движения на юго-восток if(GO_LEFT) {flg = 4; valSpeed = GO_LEFT;} else // Проверяем, сдвинут ли джойстик только влево, и если да, то устанавливаем флаг движения на запад if(GO_RIGHT) {flg = 6; valSpeed = GO_RIGHT;} else // Проверяем, сдвинут ли джойстик только вправо, и если да, то устанавливаем флаг движения на восток {flg = 5;} // Если джойстик не был сдвинут ни в одну из указанных выше сторон, то устанавливаем флаг остановки switch (flg) {// Направ. лев. м. Направ. прав. м. Скорость лев. м. Скорость прав. м. case 1: arrRoute[1] = 0; arrRoute[0] = 0; arrSpeed[1] = (valSpeed / 2); arrSpeed[0] = valSpeed; break; // С-З case 2: arrRoute[1] = 0; arrRoute[0] = 0; arrSpeed[1] = valSpeed; arrSpeed[0] = valSpeed; break; // С case 3: arrRoute[1] = 0; arrRoute[0] = 0; arrSpeed[1] = valSpeed; arrSpeed[0] = (valSpeed / 2); break; // С-В case 4: arrRoute[1] = 0; arrRoute[0] = 0; arrSpeed[1] = 0; arrSpeed[0] = valSpeed; break; // З case 5: arrRoute[1] = 0; arrRoute[0] = 0; arrSpeed[1] = 0; arrSpeed[0] = 0; break; // Стоп case 6: arrRoute[1] = 0; arrRoute[0] = 0; arrSpeed[1] = valSpeed; arrSpeed[0] = 0; break; // В case 7: arrRoute[1] = 1; arrRoute[0] = 1; arrSpeed[1] = (valSpeed / 2); arrSpeed[0] = valSpeed; break; // Ю-З case 8: arrRoute[1] = 1; arrRoute[0] = 1; arrSpeed[1] = valSpeed; arrSpeed[0] = valSpeed; break; // Ю case 9: arrRoute[1] = 1; arrRoute[0] = 1; arrSpeed[1] = valSpeed; arrSpeed[0] = (valSpeed / 2); break; // Ю-В } digitalWrite(pinShield_H2, arrRoute[1]); // тогда задаем направление вращения правого мотора digitalWrite(pinShield_H1, arrRoute[0]); // и левого мотора analogWrite(pinShield_E2, arrSpeed[1]); // Задаём скорость вращения для правого мотора analogWrite(pinShield_E1, arrSpeed[0]); // и для левого мотора delay(50); // Задержка 50мс }
Алгоритм работы скетча:
До кода void setup()
определяются переменные, подключаются необходимые библиотеки.
В коде void setup()
инициализируется геймпад, настраивается режим работы выводов для моторов и светодиодов.
Код void loop()
делится на несколько частей:
- Опрашивается геймпад
- Считывается аналоговое значение с джойстика по оси Оу
- Считывается аналоговое значение с джойстика по оси Ох
- Опрашиваются кнопки "Квадрат" и "Круг"
- Если они были нажаты, то состояние на выходах меняется на противоположное
- Если на джойстиках были изменения положения, то:
- Проверяем оси:
- Ось Y:
- Проверяем, было ли изменение в пределах от 0 до 120 - если да, то тогда робот движется вперёд;
- Проверяем, было ли изменение в пределах от 135 до 255 - если да, то тогда робот движется назад;
- Ось X:
- Проверяем, было ли изменение в пределах от 0 до 120 - если да, то тогда робот движется влево;
- Проверяем, было ли изменение в пределах от 135 до 255 - если да, то тогда робот движется вправо;
- Ось Y:
flg
;flg
устанавливаем направление вращения и скорость вращения колёс;
Обсуждение