Ардуино: инфракрасный пульт и приемник

Инфракрасный пульт дистанционного управления — один из самых простых способов взаимодействия с электронными приборами. Так, практически в каждом доме есть несколько таких устройств: телевизор, музыкальный центр, видеоплеер, кондиционер. Но самое интересное применение инфракрасного пульта — дистанционное правление роботом. Собственно, на этом уроке мы попытаемся реализовать такой способ управления с помощью популярного контроллера Ардуино Уно.

ИК-пульт

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

Инфракрасный пульт

На таком пульте есть 10 цифровых кнопок и 11 кнопок для манипуляции с музыкой: громкость, перемотка, play, stop, и т.д. Для наших целей более чем достаточно.

ИК-датчик

Во-вторых, для приема сигнала с пульта нам потребуется специальный ИК-датчик. Вообще, мы можем детектировать инфракрасное излучение обычным фотодиодом/фототранзистором, но в отличие от него, наш ИК-датчик воспринимает инфракрасный сигнал только на частоте 38 кГц (иногда 40кГц). Именно такое свойство позволяет датчику игнорировать много посторонних световых шумов от ламп освещения и солнца.

Для этого урока воспользуемся популярным ИК-датчиком VS1838B, который обладает следующими характеристиками:

  • несущая частота: 38 кГц;
  • напряжение питания: 2,7 — 5,5 В;
  • потребляемый ток: 50 мкА.

Можно использовать и другие датчики, например: TSOP4838, TSOP1736, SFH506.

Список необходимых компонентов

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

В корзину
В корзину
В корзину
В корзину

Подключение

Датчик имеет три вывода (три ноги). Если посмотреть на датчик со стороны приёмника ИК сигнала, как показано на рисунке,

  • то слева будет — выход на контроллер,
  • по центру — отрицательный контакт питания (земля),
  • и справа — положительный контакт питания (2.7 — 5.5В).

Принципиальная схема подключения

ardu-ir_схема

Внешний вид макета

ardu-ir_bb

Программа

Подключив ИК-датчик будем писать программу для Ардуино Уно. Для этого воспользуемся стандартной библиотекой IRremote, которая предназначена как раз для упрощения работы с приёмом и передачей ИК сигналов. С помощью этой библиотеки будем принимать команды с пульта, и для начала, просто выводить их в окно монитора последовательного порта. Эта программа нам пригодится для того, чтобы понять какой код дает каждая кнопка.

#include "IRremote.h"

IRrecv irrecv(2); // указываем вывод, к которому подключен приемник

decode_results results;

void setup() {
  Serial.begin(9600); // выставляем скорость COM порта
  irrecv.enableIRIn(); // запускаем прием
}

void loop() {
  if ( irrecv.decode( &results )) { // если данные пришли
    Serial.println( results.value, HEX ); // печатаем данные
    irrecv.resume(); // принимаем следующую команду
  }
}

Загружаем программу на Ардуино. После этого, пробуем получать команды с пульта. Открываем монитор последовательного порта (Ctrl+Shift+M), берём в руки пульт, и направляем его на датчик. Нажимая разные кнопочки, наблюдаем в окне монитора соответствующие этим кнопкам коды.

ir-sensor

Проблема с загрузкой программы

В некоторых случаях, при попытке загрузить программу в контроллер, может появиться ошибка:

TDK2 was not declared In his scope

Чтобы ее исправить, достаточно удалить два файла из папки библиотеки. Заходим в проводник. Переходим в папку, где установлено приложение Arduino IDE (скорее всего это «C:\Program Files (x86)\Arduino»). Затем в папку с библиотекой:

…\Arduino\libraries\RobotIRremote

, и удаляем файлы: IRremoteTools.cpp и IRremoteTools.h. Затем, перезапускаем Arduino IDE, и снова пробуем загрузить программу на контроллер.

Управляем светодиодом с помощью ИК-пульта

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

  • FFA857 — увеличение громкости;
  • FFE01F — уменьшение громкости.

В качестве светодиода, используем встроенный светодиод на выводе №13, так что схема подключения останется прежней. Итак, программа:

#include "IRremote.h"

IRrecv irrecv(2); // указываем вывод, к которому подключен приемник

decode_results results;

void setup() {
  irrecv.enableIRIn(); // запускаем прием
}

void loop() {
  if ( irrecv.decode( &results )) { // если данные пришли
    switch ( results.value ) {
    case 0xFFA857:
        digitalWrite( 13, HIGH );
        break;
    case 0xFFE01F:
        digitalWrite( 13, LOW );
        break;
    }    
    irrecv.resume(); // принимаем следующую команду
  }
}

Загружаем на Ардуино и тестируем. Жмем vol+ — светодиод зажигается. Жмем vol- — гаснет. Теперь, зная как это все работает, можно вместо светодиода управлять двигателями робота, или другими самодельными микроэлектронными устройствами!

К размышлению

Несмотря на то, что инфракрасные пульты всё еще сильно распространены, этот способ передачи данных сильно проигрывается более современным подходам. Для управления устройствами удобнее использовать bluetooth, wi-fi или zigbee. Также для создания самодельных устройств с дистанционным управлением подойдут низкоуровневые передатчики: самый простой RF433 или RF315, а также более серъёзный NRF24L01.


Изменено:

Ардуино: инфракрасный пульт и приемник: 79 комментариев

  1. Во-первых спасибо за пример!
    но он не работал у меня(

    пришлось его доделать=)

    #include «IRremote.h»

    IRrecv irrecv(2); // указываем вывод, к которому подключен приемник

    decode_results results;
    int Relay = 4;

    void setup()
    {
    pinMode(Relay, OUTPUT);
    irrecv.enableIRIn(); // запускаем прием
    }
    void loop() {
    if ( irrecv.decode( &results )) { // если данные пришли
    switch ( results.value ) {
    case 0x40BF807F:
    digitalWrite( Relay, HIGH );
    break;
    case 0x40BF40BF:
    digitalWrite( Relay, LOW );
    break;
    }
    irrecv.resume(); // принимаем следующую команду
    }
    }

      • у меня тоже не заработал скетч . вот скетч который у меня
        заработал.

        #include // подключаем библиотеку для IR приемника

        IRrecv irrecv(6); // указываем пин, к которому подключен IR приемник
        decode_results results;

        void setup() // процедура setup
        {
        irrecv.enableIRIn(); // запускаем прием инфракрасного сигнала

        pinMode(11, OUTPUT); // пин 13 будет выходом (англ. «output»)
        pinMode(12, OUTPUT); // пин 12 будет выходом (англ. «output»)
        pinMode(A0, INPUT); // пин A0 будет входом (англ. «intput»)

        Serial.begin(9600); // подключаем монитор порта
        }

        void loop() // процедура loop
        {
        if (irrecv.decode(&results)) // если данные пришли выполняем команды
        {
        Serial.println(results.value); // отправляем полученные данные на порт

        // включаем и выключаем светодиоды, в зависимости от полученного сигнала

        if (results.value == 12535991) {
        digitalWrite(11, HIGH);
        }
        if (results.value == 12574751 ) {
        digitalWrite(11, LOW);
        }
        if (results.value == 16718055) {
        digitalWrite(12, HIGH);
        }
        if (results.value == 16724175) {
        digitalWrite(12, LOW);
        }
        irrecv.resume(); // принимаем следующий сигнал на ИК приемнике
        }
        }

  2. Большое спасибо за познавательный урок, я бы хотел попросить вас усложнить задачку и сделать при помощи ШИМ плавное вкл/откл светодиода. Спасибо!

    • Дополнить программу кодом в данном месте (для увеличения яркости)
      case 0xFFA857:
      // например
      int val = 0;
      val += 50; // значение может быть любым
      // или val++; для более плавного перехода
      if (val > 255) val = 255
      analogWrite( 13, val );
      break;

          • Нужно подключать к выходам с ШИМ (PWM)

      • У вас ошибка в коде. При таком алгоритме значение val всегда будет 50, так как постоянно при нажатии на кнопку пульта у вас будет переопределяться переменная val. Во избежание этого следует добавить слово «static» к типу данных val.

  3. Подключил как в гайде, но все равно не работает( Имею в виду что монитор не показывает что я нажал пультом) но это не такой пульт как в этом гайде. В чем может быть проблема?

    • Скетч залился успешно, без ошибок? Причины могут быть разные. Например, пульт дает сигнал на частоте 40КГц, а приемник скорее всего 38КГц.

      • Я пробовал и таким же пультом и пультом от телевизора все работает. Посмотри все ли у тебя подключено правильно.

    • Как сделать так что бы ик приемник получал один и тот же сигнал, у меня он принимает с одной кнопки разные коды

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

  4. А почему на схеме и на внешнем виде макета отличается подключение выводов? На схеме у вас (слева направо) идёт земля выход вход, а на макете земля вход выход.

    Я просмотрел уже несколько сайтов по подключению этого приёмника — везде подключают по разному, у одних левый вывод это выход, у других земля. Чепуха какая-то.

    • Спасибо за замечание! Оказалось, что в редакторе схем fritzing ИК-датчик отображается неверно. Заменили на правильный вариант. Теперь всё как надо. Если не заработает, ищите проблему в другом.

  5. Я пишу скетч на управление сервой с помощью ик приёмника и вылетает ошибка:
    ‘results’ was not declared in this scope

    Скетч:
    #include
    #include
    #include

    Servo MyServo;

    IRrecv irrecv(2);

    void setup() {
    Serial.begin(9600);
    irrecv.enableIRIn(); // запускаем прием
    MyServo.attach(4);

    }

    void loop() {
    if ( irrecv.decode( &results )) {
    switch ( results.value ) {
    case 0xFFA25D:
    MyServo.write(0);
    break;
    case 0xFF629D:
    MyServo.write(90); //поворот на 90 градусов
    break;
    }
    irrecv.resume(); // принимаем следующую команду
    }

  6. Спасибо за пример! Заработал с первого раза. Очень доходчиво и просто. Спасибо.

  7. Добрый день!

    Использовал скетчи из этой темы для того, что бы сделать лазертаг мишень: принимает ИК сигнал выстрела, загорается и гаснет, но вот какие вопросы:
    1. Как только программа загружается в Ардуино — диод горит сразу.
    2. Что надо сделать, что бы принял сигнал — моргнул 500 мсек — погас?

    #include «IRremote.h»

    IRrecv irrecv(2); // указываем вывод, к которому подключен приемник

    decode_results results;

    void setup() {
    Serial.begin(9600); // выставляем скорость COM порта
    irrecv.enableIRIn(); // запускаем прием
    pinMode(3, OUTPUT);
    }

    void loop() {
    if ( irrecv.decode( &results )) { // если данные пришли
    switch ( results.value ) {
    case 0x2FD58A7:
    digitalWrite ( 3, HIGH );
    delay (10);
    case 0x2FDD827:
    digitalWrite ( 3, LOW);
    delay (100);
    }
    Serial.println( results.value, HEX ); // печатаем данные
    irrecv.resume(); // принимаем следующую команду
    }

    }

  8. Автору респект.
    Alexandr, отдельная благодарность.
    Светодиод горел на авторском скетче вполнакала,
    с Вашей поправкой все заработало отлично.

  9. Добрый день.
    Не подскажете, в чем может быть проблема?
    #include «IRremote.h»
    void setup() {}
    void loop(){}
    Не компилируется:
    IRremote.h: No such file or directory

    Спасибо.

  10. Использую код из ваших примеров, но среда упорно пишет «Ошибка компиляции для платы Arduino/Genuino Uno». Никаких подробностей не указано больше. В чем проблема может быть?

    • Бывает такое при подключении платы с уже запущенным приложением Arduino IDE. Закрой ИДЕшку, извлеки провод, с помощью которого прошиваешь плату, запусти ИДЕ, подключи плату(ардуинку). PROFIT

      • Можно сделать проще: зайти в программу, Инструменты, Порт и выбираем

  11. Добрый день? возможно ли подключить к uno серво шилд и wi-fi шилд? если нет, то какой вариант возможен?

  12. извините,но в вашем коде какая то фигня… Вставте ваш код в word и вы поймёте.

  13. собрал все по схеме светодиодом моргать получается а когда вместо светодиода цепляю реле неработает

    • Скорее всего тока не хватает для управления реле.
      Какое реле подключаете?

  14. Доброго времени суток!
    Господа, я новичок в освоении Ардуино, Но!
    Получаю команды с пульта всегда в двух числах, исходя из этого
    хотел бы спросить профессионалов — Почему 2 цифры?
    Как я понял одна из них и есть код сигнала, а вторая преселектор (т.е доп сигнал, для считывания нажатия комбинации кнопок в момент времени),.
    Так, как в моем случае, мне нужна быстрая реакция на нажатие, я включил их в обработку
    Пример ниже…

    Текст Кода

    #include «IRremote.h»

    IRrecv irrecv(2); // указываем вывод, к которому подключен приемник

    decode_results results;

    void setup() {
    pinMode(13,OUTPUT);
    pinMode(12,OUTPUT);
    Serial.begin(9600); // выставляем скорость COM порта
    irrecv.enableIRIn(); // запускаем прием
    }

    void loop() {
    if ( irrecv.decode( &results )) { // если данные пришли
    Serial.println( results.value ); // печатаем данные

    if (results.value ==32||results.value==2080)
    {
    digitalWrite( 13, HIGH );
    }
    if (results.value ==33||results.value==2081)
    {
    digitalWrite( 13, LOW );
    }
    if (results.value ==17||results.value==2065)
    {
    digitalWrite( 12, HIGH );
    }
    if (results.value ==16||results.value==2064)
    {
    digitalWrite( 12, LOW );
    }
    irrecv.resume(); // принимаем следующую команду
    }
    }

    • Какая ошибка? case неверный? Допишите перед вашим значением кода 0x Например case 0xCE1972FD

  15. Почему приёмник иногда пишет в консоль разные коды на одну и ту же кнопку? Как эти коды можно контролировать в понятный для Android вид чтобы создать программный пульт?

    • ТЫ НА ПУЛЬТЕ НАЖИМАЕШЬ РАЗНЫЕ КНОПКИ ПРОСТО СМОТРИ НА ПУЛЬТ И НАЖИМАЙ НОГТЕМ НА ОДНУ КНОПКУ НЕ УДЕРЖИВАЯ ПРИМЕРНО МЕНЬШЕ СЕКУНДЫ!

  16. ГДЕ ВЫ ПОКАЗАЛИ КАК ПОДКЛЮЧАТЬ ИК ДАТЧИК ТАМ НЕ ПРАВИЛЬНО МОЖНО БЫЛО ПОДКЛЮЧИТЬ НА 3 ВОЛЬТА А МОТОР НА 5 ИЛИ НА СЕМЬ ВОЛЬТ МЕНЬШЕ ПЯТИ ВОЛЬТ МОТОРУ НЕ ХВАТАЕТ МОЩНОСТИ!

  17. Если использовать в одном скрипте + tone для пищалки, то вылетает ошибка
    >>
    Arduino: 1.8.8 (Windows XP), Плата:»Arduino/Genuino Uno»
    Tone.cpp.o (symbol from plugin): In function `timer0_pin_port’:
    (.text+0x0): multiple definition of `__vector_7′
    libraries\IRremote\IRremote.cpp.o (symbol from plugin):(.text+0x0): first defined here
    collect2.exe: error: ld returned 1 exit status
    exit status 1
    Ошибка компиляции для платы Arduino/Genuino Uno.
    <<
    Куда копать?

    • Функция tone () использует таймер 2, который по умолчанию IRremote также использует при использовании чипа ATmega2560.
      В файле IRremoteInt.h вы можете определить, какой таймер использовать. Или скачайте библиотеку TonePlayer

  18. копировал, поменял на сигнал для своего пульта, закинул, выдает
    Arduino: 1.8.9 Hourly Build 2019/03/18 11:33 (Windows 10), Плата: «Arduino BT, ATmega328P»

    Скетч використовує 6502 байтів (22%) місця зберігання для програм. Межа 28672 байтів.
    Глобальні змінні використовують 236 байтів (11%) динамічної пам’яті, залишаючи 1812 байтів для локальних змінних. Межа 2048 байтів.
    avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x78
    avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x86
    avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x60
    avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x66
    avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0x86
    avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0x78
    avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0x06
    avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0x18
    avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0x60
    avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0xe6
    Сталася помилка при вивантаженні скетча

    Цей звіт міститиме більше інформації, якщо
    в меню Файл -> Налаштування увімкнути опцію
    «Показати докладний звіт при компіляції».

    • Судя по ошибке, Arduino IDE не может залить скетч на плату по каким-то причинам. При этом скетч скомпилирован, к программе уже претензий нет. Проверьте кабель, подключение. Может загрузчик слетел с ардуины, такое тоже бывает.

  19. Добрый день! Кто знает: как сделать так, чтобы светодиод горел столько, сколько жмешь кнопку на пульте? Зараннее спасибо!

  20. Ошибка компиляции — нет предустановленной библиотеки IRremote.h
    А жаль…

    • Так просто вместо светодиода подключить зуммер, никакой разницы.

  21. Здравствуйте.Возможно ли подключить к ДУ на 1506 ХЛ2?Для управления УМЗЧ

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

    • так это светодиод для индикации питания, вот он и горит всегда когда модуль запитан

  23. ( irrecv.decode( &results )) , монитор порта пишет что это устарело и работает не правильно

    • #include «IRremote.h»

      void setup() {
      Serial.begin(115200); // выставляем скорость COM порта

      IrReceiver.begin(A5);
      }

      void loop() {

      if (IrReceiver.decode()) { // если данные пришли

      IrReceiver.printIRResultAsCVariables(&Serial); // Output address and data as source code variables

      IrReceiver.resume();
      }
      }

      • Это простой вывод того что пришлос пульта. Обновляйте программу ардуино и библиотеку и читайте на гитхабе об изменениях. Теперь всё по другому

  24. Хочу получать код при нажатии и удержании кнопки. При отпускании не получать. Подскажите как сделать.

  25. Первый код идет согласно техданных, а при длительном нажатии пульт для Ардуино выдает FFFFFFFF. Большинство китайских пультов работают по пртоколу NEC, поэкспериментируйте с библиотеками . У меня идет IRremote 2.0.1

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.