КОРЗИНА
магазина
8 (499) 500-14-56 | ПН. - ПТ. 12:00-18:00
ЛЕСНОРЯДСКИЙ ПЕРЕУЛОК, 18С2, БЦ "ДМ-ПРЕСС"

Дистанционное управление Дройдиком по ИК

Введение:

В этом уроке мы дополним робота «Дройдика» модулем ИК-приёмник и будем управлять направлением и скоростью движения робота с помощью ИК-пульта.

Скорость и направление движения робота будет зависеть от нажатой клавиши на пульте. Робот сможет выполнять такие команды как движение вперёд или назад, с заворотом или без, разворот на месте влево или вправо.

Видео:

Waiting...

Нам понадобится:

Робот "Дройдик":

Библиотеки:

  • Библиотека iarduino_IR_RX - для работы с ИК-приёмниками/передатчиками;
  • Библиотеки SoftwareSerial и Servo входят в базовый набор Arduino IDE и не требуют установки.

О том как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE.

Схема подключения ИК-приёмника:

Trema ИК-приёмникTrema Shield
вывод Gчёрная колодка "Земля"
вывод Vкрасная колодка "+5V"
вывод S10 цифровой вывод (D10)

Вы можете изменить вывод D10 для подключения ИК-приёмника на любой другой, указав его в скетче при определении константы IR.

Схема подключения робота «Дройдика»:

Соберите механику, подключите Trema Shield, сервоприводы и откалибруйте робота, как это описано в уроке 38 Сборка «Дройдика». Далее на боковую панель установите ИК-приёмник.

СервоприводыTrema Shield
Верхние суставыЛевая нога «Дройдика»вывод 4 на белой колодке
Правая нога «Дройдика»вывод 5 на белой колодке
Нижние суставыЛевая нога «Дройдика»вывод 6 на белой колодке
Правая нога «Дройдика»вывод 7 на белой колодке

Вы можете изменить выводы 4-7 для подключения сервоприводов на любые другие, указав их в скетче при определении констант PIN_LEFT_TOPPIN_RIGHT_TOPPIN_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_TOPCENTR_LEFT_TOPCENTR_LEFT_TOPCENTR_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 (максимальный поворот вправо).

Управление:

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

Ссылки:




Обсуждение

Гарантии и возврат Используя сайт Вы соглашаетесь с условями