Введение:
В этом уроке мы дополним робота «Дройдика» модулем ИК-приёмник и будем управлять направлением и скоростью движения робота с помощью ИК-пульта.
Скорость и направление движения робота будет зависеть от нажатой клавиши на пульте. Робот сможет выполнять такие команды как движение вперёд или назад, с заворотом или без, разворот на месте влево или вправо.
Видео:
Waiting...
Нам понадобится:
Робот "Дройдик":
- Образовательный набор «Дройдик» x1 шт.
- Trema ИК-приёмник х1шт;
- ИК-пульт х1шт;
Библиотеки:
- Библиотека iarduino_IR_RX - для работы с ИК-приёмниками/передатчиками;
- Библиотеки SoftwareSerial и Servo входят в базовый набор Arduino IDE и не требуют установки.
О том как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE.
Схема подключения ИК-приёмника:

| Trema ИК-приёмник | Trema Shield |
|---|---|
| вывод G | чёрная колодка "Земля" |
| вывод V | красная колодка "+5V" |
| вывод S | 10 цифровой вывод (D10) |
Вы можете изменить вывод D10 для подключения ИК-приёмника на любой другой, указав его в скетче при определении константы IR.
Схема подключения робота «Дройдика»:
Соберите механику, подключите Trema Shield, сервоприводы и откалибруйте робота, как это описано в уроке 38 Сборка «Дройдика». Далее на боковую панель установите ИК-приёмник.
| Сервоприводы | Trema Shield | |
|---|---|---|
| Верхние суставы | Левая нога «Дройдика» | вывод 4 на белой колодке |
| Правая нога «Дройдика» | вывод 5 на белой колодке | |
| Нижние суставы | Левая нога «Дройдика» | вывод 6 на белой колодке |
| Правая нога «Дройдика» | вывод 7 на белой колодке | |
Вы можете изменить выводы 4-7 для подключения сервоприводов на любые другие, указав их в скетче при определении констант PIN_LEFT_TOP, PIN_RIGHT_TOP, PIN_LEFT_BOT, PIN_RIGHT_BOT.
Трехпроводные шлейфы сервоприводов устанавливаются следующим образом:
- Оранжевый провод подключается к выводу на белой колодке.
- Красный провод подключается к выводу на красной колодке.
- Коричневый провод подключается к выводу на чёрной колодке.
Код программы для чтения сигналов с пульта:
#include "iarduino_IR_RX.h" // Подключаем библиотеку для работы с ИК-приёмником
iarduino_IR_RX IR(10); // Объявляем объект IR и указываем вывод, к которому подключён ИК-приёмник
void setup() {
Serial.begin(9600); // Инициируем передачу данных в монитор порта на скорости 9600 бит/сек
IR.begin(); // Инициируем работу с ИК-приёмником
}
void loop() {
// Если в буфере имеются данные, принятые с пульта (удерживается кнопка), то выводим код нажатой кнопки
if (IR.check(true)) Serial.println(IR.data, HEX);
}
Данный скетч пригодится вам в том случае, если вы решите взять любой другой ИК-пульт вместо нашего. В этом случае вам надо будет определить коды кнопок, используя данный скетч, а затем указать их уже в основном коде "Дройдика", там где указана функцияIR.data.
Код программы для «Дройдика»:
#define GO_LEFT_UP 1 // Определяем константу для движения влево-вверх
#define GO_UP 2 // Определяем константу для движения вверх
#define GO_RIGHT_UP 3 // Определяем константу для движения вправо-вверх
#define GO_LEFT 4 // Определяем константу для движения влево
#define STOP 5 // Определяем константу для движения стоп
#define GO_RIGHT 6 // Определяем константу для движения вправо
#define GO_LEFT_DOWN 7 // Определяем константу для движения влево-вниз
#define GO_DOWN 8 // Определяем константу для движения вниз
#define GO_RIGHT_DOWN 9 // Определяем константу для движения вправо-вниз
#define PIN_ECHO 2 // Определяем константу с номером вывода подключённым к выводу ECHO датчика расстояний (можно указывать только те выводы Arduino, которые могут работать с внешними прерываниями)
#define PIN_TRIG 3 // Определяем константу с номером вывода подключённым к выводу TRIG датчика расстояний (может быть любым)
#define PIN_LEFT_TOP 4 // Определяем константу с номером вывода подключённым к верхнему сервоприводу левой ноги (может быть любым)
#define PIN_RIGHT_TOP 5 // Определяем константу с номером вывода подключённым к верхнему сервоприводу правой ноги (может быть любым)
#define PIN_LEFT_BOT 6 // Определяем константу с номером вывода подключённым к нижнему сервоприводу левой ноги (может быть любым)
#define PIN_RIGHT_BOT 7 // Определяем константу с номером вывода подключённым к нижнему сервоприводу правой ноги (может быть любым)
#define CENTR_LEFT_TOP 119 // Определяем константу центрального угла в градусах для верхнего сервопривода левой ноги (по умолчанию = 100)
#define CENTR_RIGHT_TOP 65 // Определяем константу центрального угла в градусах для верхнего сервопривода правой ноги (по умолчанию = 80 )
#define CENTR_LEFT_BOT 79 // Определяем константу центрального угла в градусах для нижнего сервопривода левой ноги (по умолчанию = 60 )
#define CENTR_RIGHT_BOT 76 // Определяем константу центрального угла в градусах для нижнего сервопривода правой ноги (по умолчанию = 120)
#define MAX_STEP_SIZE 25 // Определяем константу размера шага в градусах поворота верхних сервоприводов (чем больше угол, тем шире шаг)
#define MAX_STEP_HEIGHT 20 // Определяем константу высоты шага в градусах наклона в стороны при ходьбе (чем больше угол, тем выше шаг)
#define SPEED_DELAY 13 // Определяем константу обратно пропорциональную скорости движения (чем больше значение, тем медленнее скорость)
#define IR_SIGNAL_WAITING_TIME 100 // Определяем константу времени ожидания прихода пакета от ИК-пульта
// Подключаем библиотеки:
#include "Servo.h" // Подключаем библиотеку для работы с сервоприводами
#include "iarduino_IR_RX.h" // Подключаем библиотеку для работы с ИК-приёмником
// Создаём объекты:
Servo OBJ_SERVO_LEFT_TOP; // Создаём объект servoLEFT_TOP для работы с верхним левым сервоприводом
Servo OBJ_SERVO_RIGHT_TOP; // Создаём объект OBJ_SERVO_RIGHT_TOP для работы с верхним правым сервоприводом
Servo OBJ_SERVO_LEFT_BOT; // Создаём объект OBJ_SERVO_LEFT_BOT для работы с нижним левым сервоприводом
Servo OBJ_SERVO_RIGHT_BOT; // Создаём объект OBJ_SERVO_RIGHT_BOT для работы с нижним правым сервоприводом
iarduino_IR_RX IR(10); // Объявляем объект IR, с указанием вывода к которому подключён ИК-приёмник
// Создаём переменные:
uint8_t ValPosition = 224; // Определяем переменную (движение) для хранения текущей позиции шага (счёт от 0 до 255 или обратно), начальная позиция 224
int8_t ValTurning = 0; // Определяем переменную (поворот ) для пересчета размера шага в градусах поворота верхних сервоприводов (-10 - влево ... 0 - прямо ... +10 вправо)
uint8_t MaxLeftSize = MAX_STEP_SIZE; // Определяем переменную максимального размера шага в градусах поворота верхнего левого сервопривода (чем меньше угол, тем сильнее робот будет уходить вправо)
uint8_t MaxRightSize = MAX_STEP_SIZE; // Определяем переменную максимального размера шага в градусах поворота верхнего правого сервопривода (чем меньше угол, тем сильнее робот будет уходить влево )
uint8_t Flg = 0; // Флаг кнопок
uint32_t FlgTime; // Флаг начала отправки пакетов
void setup(){
IR.begin(); // Инициируем работу с ИК-приёмником
// Указываем объектам сервоприводов их выводы:
OBJ_SERVO_LEFT_TOP. attach(PIN_LEFT_TOP ); // Указываем объекту OBJ_SERVO_LEFT_TOP работать с выводом PIN_LEFT_TOP
OBJ_SERVO_RIGHT_TOP.attach(PIN_RIGHT_TOP); // Указываем объекту OBJ_SERVO_RIGHT_TOP работать с выводом PIN_RIGHT_TOP
OBJ_SERVO_LEFT_BOT. attach(PIN_LEFT_BOT ); // Указываем объекту OBJ_SERVO_LEFT_BOT работать с выводом PIN_LEFT_BOT
OBJ_SERVO_RIGHT_BOT.attach(PIN_RIGHT_BOT); // Указываем объекту OBJ_SERVO_RIGHT_BOT работать с выводом PIN_RIGHT_BOT
// Устанавливаем центральные углы сервоприводов:
OBJ_SERVO_LEFT_TOP. write (CENTR_LEFT_TOP ); // Устанавливаем центральную позицию (угол CENTR_LEFT_TOP ) для сервопривода подключённого к выводу PIN_LEFT_TOP
OBJ_SERVO_RIGHT_TOP.write (CENTR_RIGHT_TOP); // Устанавливаем центральную позицию (угол CENTR_RIGHT_TOP) для сервопривода подключённого к выводу PIN_RIGHT_TOP
OBJ_SERVO_LEFT_BOT. write (CENTR_LEFT_BOT ); // Устанавливаем центральную позицию (угол CENTR_LEFT_BOT ) для сервопривода подключённого к выводу PIN_LEFT_BOT
OBJ_SERVO_RIGHT_BOT.write (CENTR_RIGHT_BOT); // Устанавливаем центральную позицию (угол CENTR_RIGHT_BOT) для сервопривода подключённого к выводу PIN_RIGHT_BOT
}
void loop(){
if (IR.check(true)) { // Настраиваем считывание данных при нажатой и зажатой кнопках
// Флаг времени кнопки
if (IR.data == 0xFFA25D) { FlgTime = millis(); Flg = GO_LEFT_UP; } else
if (IR.data == 0xFF629D) { FlgTime = millis(); Flg = GO_UP; } else
if (IR.data == 0xFFE21D) { FlgTime = millis(); Flg = GO_RIGHT_UP; } else
if (IR.data == 0xFF22DD) { FlgTime = millis(); Flg = GO_LEFT; } else
if (IR.data == 0xFFC23D) { FlgTime = millis(); Flg = GO_RIGHT; } else
if (IR.data == 0xFFE01F) { FlgTime = millis(); Flg = GO_LEFT_DOWN; } else
if (IR.data == 0xFFA857) { FlgTime = millis(); Flg = GO_DOWN; } else
if (IR.data == 0xFF906F) { FlgTime = millis(); Flg = GO_RIGHT_DOWN;}
}
if (FlgTime > millis()) FlgTime = 0; // Если millis() переполнен, то сбрасываем флаг в ноль
if ((FlgTime + IR_SIGNAL_WAITING_TIME) > millis()) { // Если пакеты с пульта приходят в течении 100 мс
if(millis() % SPEED_DELAY == 0){
switch (Flg) { //Направ. движения Направ. вращения
case GO_LEFT_UP: ValPosition += 2; ValTurning = -5; break;
case GO_UP: ValPosition += 2; ValTurning = 0; break;
case GO_RIGHT_UP: ValPosition += 2; ValTurning = 5; break;
case GO_LEFT: ValPosition += 2; ValTurning = -10; break;
case GO_RIGHT: ValPosition += 2; ValTurning = 10; break;
case GO_LEFT_DOWN: ValPosition -= 2; ValTurning = -5; break;
case GO_DOWN: ValPosition -= 2; ValTurning = 0; break;
case GO_RIGHT_DOWN: ValPosition -= 2; ValTurning = 5; break;
}
}
MaxRightSize = MAX_STEP_SIZE; if(ValTurning<0){ MaxRightSize = map(ValTurning, 0,-10, MAX_STEP_SIZE, 0);} /* Прямо или влево */ // Корректируем значение MaxRightSize (размера шага правой ноги) в соответствии со значением ValTurning.
MaxLeftSize = MAX_STEP_SIZE; if(ValTurning>0){ MaxLeftSize = map(ValTurning, 0, 10, MAX_STEP_SIZE, 0);} /* Прямо или вправо */ // Корректируем значение MaxLeftSize (размера шага левой ноги) в соответствии со значением ValTurning.
if(ValPosition<64 ){OBJ_SERVO_LEFT_TOP. write(map(ValPosition, 0, 63, CENTR_LEFT_TOP - MaxLeftSize , CENTR_LEFT_TOP + MaxLeftSize )); // Левая нога поворачивается вправо => отходит назад.
OBJ_SERVO_RIGHT_TOP.write(map(ValPosition, 0, 63, CENTR_RIGHT_TOP - MaxRightSize , CENTR_RIGHT_TOP + MaxRightSize ));}else // Правая нога поворачивается вправо => выходит вперёд.
if(ValPosition<128){OBJ_SERVO_LEFT_BOT. write(map(ValPosition, 64, 127, CENTR_LEFT_BOT - MAX_STEP_HEIGHT , CENTR_LEFT_BOT +(MAX_STEP_HEIGHT/2))); // Левая нога наклоняется вправо => переносит центр тяжести с себя на правую ногу, которая станет опорной.
OBJ_SERVO_RIGHT_BOT.write(map(ValPosition, 64, 127, CENTR_RIGHT_BOT -(MAX_STEP_HEIGHT/2) , CENTR_RIGHT_BOT + MAX_STEP_HEIGHT ));}else // Правая нога наклоняется вправо => опускается вниз (становится опорной) и поднимает левую ногу.
if(ValPosition<192){OBJ_SERVO_LEFT_TOP. write(map(ValPosition, 128, 191, CENTR_LEFT_TOP + MaxLeftSize , CENTR_LEFT_TOP - MaxLeftSize )); // Левая нога поворачивается влево => выходит вперёд.
OBJ_SERVO_RIGHT_TOP.write(map(ValPosition, 128, 191, CENTR_RIGHT_TOP + MaxRightSize , CENTR_RIGHT_TOP - MaxRightSize ));}else // Правая нога поворачивается влево => отходит назад.
/*ValPosition<255*/{OBJ_SERVO_LEFT_BOT. write(map(ValPosition, 192, 255, CENTR_LEFT_BOT +(MAX_STEP_HEIGHT/2) , CENTR_LEFT_BOT - MAX_STEP_HEIGHT )); // Левая нога наклоняется влево => опускается вниз (становится опорной) и поднимает правую ногу.
OBJ_SERVO_RIGHT_BOT.write(map(ValPosition, 192, 255, CENTR_RIGHT_BOT + MAX_STEP_HEIGHT , CENTR_RIGHT_BOT -(MAX_STEP_HEIGHT/2)));} // Правая нога наклоняется влево => переносит центр тяжести с себя на левую ногу, которая станет опорной.
}
}
Константы CENTR_LEFT_TOP, CENTR_LEFT_TOP, CENTR_LEFT_TOP, CENTR_LEFT_TOP должны быть изменены (откалиброваны) на действительные углы сервоприводов в градусах, при которых все суставы робота находятся в центральном положении. Это выполняется с использованием калибровочного скетча, как описано в уроке 38 Сборка «Дройдика».
В данном коде управление роботом осуществляется в три основных этапа: получение данных с пульта; изменение значений переменных ValPosition и ValTurning; установка сервоприводов в требуемые позиции.
- Получение данных с пульта
- Данный блок начинается с оператора
ifв условии которого написаноIR.check(true). Это условие верно, если с ИК-пульта приходят пакеты на ИК-приёмник. - Далее следует оператор
ifусловием которого являетсяIR.data ==. Далее указан код кнопки ИК-пульта. Если код совпадает, то выполняется код в теле оператора, код которого совпал с принятым от ИК-пульта. - При выполнении кода в теле оператора
ifтак же обновляется значение счётчика времениFlgTime, который в последствии будет использоваться для ограничения времени на получение пакета (в скетче выше время получения указано ниже в виде(FlgTime + IR_SIGNAL_WAITING_TIME) > millis()).
- Данный блок начинается с оператора
- Изменение значений переменных valPosition, valTurning
- Данный блок начинается с оператора
ifв условии которого написано(FlgTime + IR_SIGNAL_WAITING_TIME) > millis()),что ограничивает время принятия пакета на времяIR_SIGNAL_WAITING_TIME, а затем стоит операторifс условиемmillis() % SPEED_DELAY == 0. Это условие будет верно каждыеSPEED_DELAYсекунд, потому что символ%в условии это операция "остаток от деления". В данном случае остаток от деленияmillis()наSPEED_DELAYдолжен быть равен 0, то естьmillis()должна делиться нацело (без остатка). - Далее следует оператор
Switch (условие) { case (условие): код }, который отвечает за выполнение кода вcaseпри совпадении с ним условия изSwitch. В данном блоке определены все движения Дройдика. - Переменная
ValPositionиспользуется в следующем блоке и определяет изменение позиции шага от 0 до 255. Чем выше значение, тем на больший угол поворачиваются сервоприводы; - Переменная
ValTurningиспользуется в следующем блоке и определяет степень отклонения от центра (для совершения движения в сторону или разворота) от -10 до +10; - Значения переменным
valPositionиvalTurningприсваиваются в соответствии с принятыми данными о нажатой кнопке на ИК-пульте
- Данный блок начинается с оператора
- Установка сервоприводов в требуемые позиции - выполняется при наличии связи с пультом или в течении
IR_SIGNAL_WAITING_TIMEпосле получения последнего пакета.- Движение осуществляется в соответствии со значениями переменных
ValPositionиvalTurning. - Полный шаг робота разбит на 256 частей (от 0 до 255) на которые и указывает значение переменной
valPosition. - Если значение переменной
ValPositionне меняется, то робот стоит на месте. - Если значение переменной
ValPositionувеличивается, то робот будет идти вперёд (переход от 255 к 0 считается увеличением). - Если значение переменной
ValPositionубывает, то робот будет идти назад (переход от 0 к 255 считается уменьшением). - Чем быстрее выполняется увеличение/уменьшение переменной
ValPosition, тем быстрее шагает робот. - Так как в предыдущем блоке переменная
ValPositionлибо уменьшается, либо увеличивается, значит скорость её уменьшения или увеличения зависит от условияmillis() % SPEED_DELAY == 0, которое определяет промежутки времени между изменением переменнойValPosition. - Значение переменной
ValTurningограничивает движение левой или правой ноги, что приводит к повороту робота влево или вправо. Переменная может содержать значения от -10 (максимальный поворот влево), 0 (без поворота), до +10 (максимальный поворот вправо).
- Движение осуществляется в соответствии со значениями переменных
Управление:
Управление Дройдиком начинается после того, как на него будет подано питание и все сервоприводы будут выставлены в центральные положения (требуется предварительная калибровка). После этого кнопками пульта со стрелками можно управлять направлением движения робота.

Обсуждение