Проект 10: ИК-пульт управления
Введение
В этом проекте мы научимся принимать команды с ИК-пульта для дистанционного управления роботом Фобо (дальность до 5-8 метров).
Теория: как работает ИК-пульт
Основной принцип
Инфракрасное (ИК) излучение — это невидимый для глаза свет с длиной волны 940 нм.
Как работает передача:
Пульт (передатчик):
Внутри есть ИК-светодиод (похож на обычный, но излучает инфракрасный свет)
При нажатии кнопки светодиод мигает с частотой 38 кГц (38 000 раз в секунду!)
Последовательность вспышек кодирует информацию (какая кнопка нажата)
Приёмник VS1838B:
Внутри есть фототранзистор, чувствительный к ИК-свету
Демодулятор на 38 кГц — фильтрует помехи (солнечный свет, лампы)
Преобразует последовательность вспышек в электрический сигнал
Выдаёт на выводе OUT цифровой сигнал (HIGH/LOW)
Протокол NEC
Наш пульт использует протокол NEC — один из самых популярных:
Стартовый импульс: 9 мс LOW + 4.5 мс HIGH (сигнал начала передачи)
32 бита данных:
8 бит — адрес устройства (например, 0x00 для нашего пульта)
8 бит — инверсия адреса (для проверки ошибок)
8 бит — команда (код кнопки)
8 бит — инверсия команды
Логический 0: 562 мкс LOW + 562 мкс HIGH (короткая пауза)
Логическая 1: 562 мкс LOW + 1687 мкс HIGH (длинная пауза)
Пример декодирования кнопки «1»
Давайте разберём, как из последовательности импульсов получается код 0xFFA25D.
Шаг 1: Приёмник получает 32 бита данных
При нажатии кнопки «1» пульт передаёт 32 бита (каждый бит = короткая или длинная пауза):
11111111 10100010 01011101 10100010
\_____/ \______/ \______/ \______/
Адрес ~Адрес Команда ~Команда
Расшифровка:
Байт 1 (адрес):
11111111= 0xFF (255 в десятичной) — адрес нашего пультаБайт 2 (инверсия адреса):
00000000= 0x00 — для проверки (должен быть инверсией байта 1)Байт 3 (команда):
10100010= 0xA2 (162 в десятичной) — код кнопки «1»Байт 4 (инверсия команды):
01011101= 0x5D — инверсия команды для проверки ошибок
Шаг 2: Собираем 32-битное число
Теперь эти 4 байта объединяются в одно 32-битное число:
0xFF 0xA2 0x5D (пропускаем байт 2, т.к. он инверсия)
Но! В протоколе NEC все 4 байта передаются:
Байт 1 Байт 2 Байт 3 Байт 4
0xFF 0x00 0xA2 0x5D
Объединяем (слева направо):
0xFF 00 A2 5D → но обычно записывают: 0xFFA25D (без лидирующих нулей инверсии)
Почему именно так?
В реальности библиотека получает все 32 бита, но часто код записывают без байта инверсии адреса, если адрес стандартный (0xFF → 0x00). Поэтому:
Полный код:
0xFF00A25D(32 бита)Сокращённый:
0xFFA25D(24 бита, без 0x00)
Наглядный пример:
Кнопка "1" на пульте
↓
ИК-светодиод мигает по схеме NEC
↓
VS1838B принимает импульсы
↓
Демодулятор преобразует в биты: 11111111 10100010 01011101 10100010
↓
Библиотека AlashIRControlRX декодирует
↓
Получаем код: 0xFFA25D
Важно
В шестнадцатеричной системе (HEX):
0xA2 = 10 × 16¹ + 2 × 16⁰ = 160 + 2 = 162 (в десятичной)
0x5D = 5 × 16¹ + 13 × 16⁰ = 80 + 13 = 93 (в десятичной)
0xFF = 15 × 16¹ + 15 × 16⁰ = 240 + 15 = 255 (в десятичной)
Полный код 0xFFA25D = 16 753 245 в десятичной системе!
Примечание
Библиотека AlashIRControlRX делает всю сложную работу за нас! Мы просто получаем готовый код кнопки.
VS1838B: конструкция приёмника
Внутри VS1838B:
Фототранзистор (чувствителен к 940 нм)
Усилитель сигнала
Полосовой фильтр на 38 кГц (отсекает помехи от ламп, солнца)
Демодулятор (преобразует 38 кГц в цифровой сигнал)
Библиотека AlashIRControlRX
Установка: см. подробную инструкцию в Уроке 1. Скачайте ZIP с GitHub: https://github.com/Alash-electronics/AlashIRControl
Основные возможности библиотеки:
AlashIRControlRX irReceiver(pin)— создаёт объект приёмника на указанном пинеirReceiver.begin()— инициализация приёмника (в setup)irReceiver.check()— проверка, пришёл ли новый сигнал (в loop)irReceiver.data— код нажатой кнопки (в формате HEX)
Пример использования:
#include <AlashIRControlRX.h>
AlashIRControlRX irReceiver(A3); // Приёмник на пине A3
void setup() {
Serial.begin(9600);
irReceiver.begin(); // Запускаем приёмник
}
void loop() {
if (irReceiver.check()) { // Если кнопка нажата
Serial.println(irReceiver.data, HEX); // Выводим код
}
}
Код программы
Эксперимент 1: Считывание кодов кнопок
Цель: Научиться принимать сигналы с пульта и узнать коды всех кнопок в разных форматах (HEX и десятичный).
Скопируйте этот код в Arduino IDE:
1/*
2 * Проект 10: ИК-пульт управления
3 * Эксперимент 1: Считывание кодов кнопок
4 *
5 * Что делает программа:
6 * - Принимает сигналы с ИК-пульта
7 * - Выводит код каждой нажатой кнопки в Serial Monitor
8 * - Показывает код в двух форматах: HEX и десятичный
9 *
10 * Подключение:
11 * Модуль IR → Sensor Shield линия A3 (- → G, + → V, S → S)
12 */
13
14#include <AlashIRControlRX.h> // Подключаем библиотеку для ИК-приёмника
15
16// НАСТРОЙКИ ПРИЁМНИКА
17const int IR_PIN = A3; // Пин ИК-приёмника (A3 на Sensor Shield)
18
19AlashIRControlRX irReceiver(IR_PIN); // Создаём объект приёмника
20
21void setup() {
22 Serial.begin(9600); // Запускаем Serial Monitor на скорости 9600
23 irReceiver.begin(); // Инициализируем ИК-приёмник
24
25 Serial.println("=============================================");
26 Serial.println(" Проект 10: ИК-пульт управления");
27 Serial.println(" Эксперимент 1: Считывание кодов кнопок");
28 Serial.println("=============================================");
29 Serial.println();
30 Serial.println("Направьте пульт на приёмник и нажмите любую кнопку.");
31 Serial.println("Расстояние: 5-50 см для надёжного приёма.");
32 Serial.println();
33 Serial.println("Формат вывода:");
34 Serial.println(" HEX-код - для использования в программе");
35 Serial.println(" Десятичный - для понимания числового значения");
36 Serial.println();
37}
38
39void loop() {
40 // Проверяем, пришёл ли сигнал с пульта
41 if (irReceiver.check()) {
42 unsigned long code = irReceiver.data; // Сохраняем код в переменную
43
44 // Игнорируем код повтора (когда кнопка удерживается)
45 if (code == 0xFFFFFFFF) {
46 Serial.println(" ↻ [удерживается кнопка]");
47 return;
48 }
49
50 // Выводим код в двух форматах
51 Serial.println("┌─────────────────────────────────┐");
52
53 // HEX-формат (для программы)
54 Serial.print("│ HEX-код: 0x");
55 if (code < 0x10000000) Serial.print("0"); // Добавляем ведущий 0 если нужно
56 Serial.print(code, HEX);
57 Serial.println(" │");
58
59 // Десятичный формат (для понимания)
60 Serial.print("│ Десятичный: ");
61 Serial.print(code);
62 // Выравнивание
63 if (code < 10000000) Serial.print(" ");
64 if (code < 1000000) Serial.print(" ");
65 Serial.println(" │");
66
67 Serial.println("└─────────────────────────────────┘");
68 Serial.println();
69 }
70}
Как работает код:
Строка 16: Подключаем библиотеку
AlashIRControlRX.hСтрока 19: Определяем пин приёмника (A3)
Строка 21: Создаём объект
irReceiverдля работы с приёмникомСтрока 25: Инициализируем Serial Monitor (9600 бод)
Строка 26: Запускаем приёмник функцией
begin()Строка 43: Функция
check()возвращаетtrue, если пришёл новый сигналСтрока 44: Сохраняем код кнопки в переменную
code(типunsigned long)Строки 47-50: Игнорируем код повтора
0xFFFFFFFF(когда кнопка удерживается)Строки 53-69: Выводим код в двух форматах с красивым оформлением
Почему два формата?
HEX (шестнадцатеричный): Традиционный формат для ИК-кодов, используется в программах. Компактный:
0xFFA25Dвместо16753245Десятичный: Обычное число, которое легче понять человеку. Показывает реальное числовое значение кода.
Совет
В коде программы всегда используйте HEX-формат — он короче и нагляднее. Десятичный формат нужен только для понимания.
Загрузка и тестирование
Примечание
Процесс загрузки кода: см. подробную инструкцию в Уроке 1. Откройте Serial Monitor (9600 baud) после загрузки.
Что вы увидите в Serial Monitor
После загрузки программы:
==================================
Проект 10: ИК-пульт управления
Эксперимент 1: Считывание кодов
=================================
Направьте пульт на приёмник и нажмите любую кнопку.
Расстояние: 5-50 см для надёжного приёма.
Теперь возьмите пульт, направьте на VS1838B (расстояние 10-30 см) и нажмите любую кнопку.
Пример вывода:
Код кнопки: 0xFFA25D ← Нажата кнопка "1"
Код кнопки: 0xFF629D ← Нажата кнопка "2"
Код кнопки: 0xFF18E7 ← Нажата кнопка "▲" (вверх)
Код кнопки: 0xFF38C7 ← Нажата кнопка "OK"
Совет
Запишите коды всех кнопок! Они понадобятся для следующих экспериментов. У разных производителей пультов коды могут отличаться.
Таблица кодов стандартного пульта
Вот коды для типового пульта из набора Alash:
Кнопка |
HEX-код |
Десятичный код |
|---|---|---|
0 |
0xFF9867 |
16753767 |
1 |
0xFFA25D |
16753245 |
2 |
0xFF629D |
16736925 |
3 |
0xFFE21D |
16761405 |
4 |
0xFF22DD |
16720605 |
5 |
0xFF02FD |
16712445 |
6 |
0xFFC23D |
16757565 |
7 |
0xFFE01F |
16761375 |
8 |
0xFFA857 |
16754775 |
9 |
0xFF906F |
16748655 |
* |
0xFF6897 |
16738455 |
# |
0xFFB04F |
16756815 |
▲ (UP) |
0xFF18E7 |
16718055 |
▼ (DOWN) |
0xFF4AB5 |
16730805 |
◄ (LEFT) |
0xFF10EF |
16716527 |
► (RIGHT) |
0xFF5AA5 |
16734885 |
OK |
0xFF38C7 |
16726215 |
Предупреждение
Ваш пульт может иметь другие коды! Всегда проверяйте коды с помощью Эксперимента 1 перед использованием.
Использование других пультов (TV, кондиционер, телефон)
Можно ли использовать пульт от телевизора или кондиционера?
Да! VS1838B работает с любым пультом, использующим протокол NEC (большинство бытовых пультов). Вы не ограничены только пультом из набора!
Варианты пультов для управления роботом:
📺 Пульт от телевизора
Большинство телевизоров (Samsung, LG, Sony) используют протокол NEC
У вас уже есть дома, не нужно покупать новый
Большие кнопки, удобно нажимать
Недостаток: много лишних кнопок (можно использовать только нужные)
❄️ Пульт от кондиционера
Обычно также работают по протоколу NEC
Крупные кнопки с чёткими символами
Недостаток: некоторые кондиционеры используют другие протоколы
📱 Телефон с ИК-передатчиком
Многие телефоны имеют встроенный ИК-передатчик (Xiaomi, Huawei, Samsung Galaxy S-серия)
Можно установить приложение-пульт (например, Mi Remote, AnyMote, SURE Universal Remote)
Можно создать свой интерфейс с нужными кнопками!
Преимущество: всегда при себе, не нужен отдельный пульт
Проверка: посмотрите спецификацию телефона или найдите «ИК-порт» (обычно сверху рядом с разъёмом для наушников)
🎮 Универсальный пульт
Можно купить в магазине электроники (~$3-5)
Программируется на разные устройства
Как использовать свой пульт:
Шаг 1: Запустите Эксперимент 1 (считывание кодов)
Шаг 2: Направьте свой пульт на VS1838B и нажмите нужные кнопки
Шаг 3: Запишите коды в таблицу:
Пример для пульта от телевизора Samsung:
┌─────────────────────────────────┐
│ HEX-код: 0xE0E0D02F │ ← Кнопка VOL+ (громкость +)
│ Десятичный: 3772793903 │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│ HEX-код: 0xE0E0E01F │ ← Кнопка VOL- (громкость -)
│ Десятичный: 3772789791 │
└─────────────────────────────────┘
Шаг 4: Замените коды в программе:
// Пример: использование кнопок телевизора Samsung
const unsigned long BTN_UP = 0xE0E006F9; // CH+ (канал вверх)
const unsigned long BTN_DOWN = 0xE0E08679; // CH- (канал вниз)
const unsigned long BTN_LEFT = 0xE0E0A659; // ◄ (влево)
const unsigned long BTN_RIGHT = 0xE0E046B9; // ► (вправо)
const unsigned long BTN_OK = 0xE0E016E9; // OK (центр)
const unsigned long BTN_1 = 0xE0E020DF; // Цифра 1
const unsigned long BTN_2 = 0xE0E0A05F; // Цифра 2
Важные замечания:
Примечание
Не все пульты используют NEC! Если пульт не работает, попробуйте другой.
Коды у разных производителей отличаются — даже для одной кнопки «VOL+».
Некоторые пульты передают длинные последовательности — они могут не работать корректно.
Совет
Для телефонов с IR: Приложения типа Mi Remote позволяют:
Создать кастомный пульт с только нужными кнопками
Назвать кнопки по-своему (FORWARD, LEFT, RIGHT, STOP)
Программировать макросы (одна кнопка = несколько команд)
Проверка совместимости:
Если пульт не работает (Serial Monitor показывает 0x00000000 или вообще ничего):
Попробуйте другие кнопки — некоторые могут использовать другой протокол
Проверьте батарейку в пульте (направьте на камеру телефона — должна видна вспышка)
Попробуйте другой пульт — ваш может использовать RC5, RC6 или Sony SIRC (несовместимы с NEC)
Эксперимент 2: Распознавание кнопок
Цель: Научиться определять, какая именно кнопка нажата, и выводить её название.
1/*
2 * Проект 10: ИК-пульт управления
3 * Эксперимент 2: Распознавание кнопок
4 *
5 * Что делает программа:
6 * - Принимает сигналы с ИК-пульта
7 * - Определяет, какая кнопка нажата
8 * - Выводит название кнопки в Serial Monitor
9 *
10 * ВАЖНО: Замените коды кнопок на свои (из Эксперимента 1)!
11 */
12
13#include <AlashIRControlRX.h>
14
15const int IR_PIN = A3;
16AlashIRControlRX irReceiver(IR_PIN);
17
18// КОДЫ КНОПОК (замените на свои!)
19const unsigned long BTN_1 = 0xFFA25D;
20const unsigned long BTN_2 = 0xFF629D;
21const unsigned long BTN_3 = 0xFFE21D;
22const unsigned long BTN_4 = 0xFF22DD;
23const unsigned long BTN_5 = 0xFF02FD;
24const unsigned long BTN_6 = 0xFFC23D;
25const unsigned long BTN_7 = 0xFFE01F;
26const unsigned long BTN_8 = 0xFFA857;
27const unsigned long BTN_9 = 0xFF906F;
28const unsigned long BTN_0 = 0xFF9867;
29const unsigned long BTN_STAR = 0xFF6897;
30const unsigned long BTN_HASH = 0xFFB04F;
31const unsigned long BTN_UP = 0xFF18E7;
32const unsigned long BTN_DOWN = 0xFF4AB5;
33const unsigned long BTN_LEFT = 0xFF10EF;
34const unsigned long BTN_RIGHT = 0xFF5AA5;
35const unsigned long BTN_OK = 0xFF38C7;
36
37void setup() {
38 Serial.begin(9600);
39 irReceiver.begin();
40
41 Serial.println("========================================");
42 Serial.println(" Проект 10: Эксперимент 2");
43 Serial.println(" Распознавание кнопок пульта");
44 Serial.println("========================================");
45 Serial.println();
46 Serial.println("Нажимайте кнопки — я скажу их названия!");
47 Serial.println();
48}
49
50void loop() {
51 if (irReceiver.check()) {
52 unsigned long code = irReceiver.data; // Сохраняем код для проверки
53
54 // Определяем, какая кнопка нажата
55 Serial.print("Нажата кнопка: ");
56
57 if (code == BTN_0) Serial.println("0");
58 else if (code == BTN_1) Serial.println("1");
59 else if (code == BTN_2) Serial.println("2");
60 else if (code == BTN_3) Serial.println("3");
61 else if (code == BTN_4) Serial.println("4");
62 else if (code == BTN_5) Serial.println("5");
63 else if (code == BTN_6) Serial.println("6");
64 else if (code == BTN_7) Serial.println("7");
65 else if (code == BTN_8) Serial.println("8");
66 else if (code == BTN_9) Serial.println("9");
67 else if (code == BTN_STAR) Serial.println("* (звёздочка)");
68 else if (code == BTN_HASH) Serial.println("# (решётка)");
69 else if (code == BTN_UP) Serial.println("▲ ВВЕРХ");
70 else if (code == BTN_DOWN) Serial.println("▼ ВНИЗ");
71 else if (code == BTN_LEFT) Serial.println("◄ ВЛЕВО");
72 else if (code == BTN_RIGHT) Serial.println("► ВПРАВО");
73 else if (code == BTN_OK) Serial.println("OK");
74 else {
75 Serial.print("НЕИЗВЕСТНАЯ (код: 0x");
76 Serial.print(code, HEX);
77 Serial.println(")");
78 }
79 }
80}
Что нового:
Строки 18-35: Определяем константы для кодов кнопок (удобнее, чем писать 0xFFA25D каждый раз)
Строка 52: Сохраняем код в переменную
code(типunsigned long— беззнаковое целое 32 бита)Строки 57-73: Цепочка
if-else ifпроверяет, какой кнопке соответствует кодСтроки 74-78: Если код не совпал ни с одной кнопкой → «НЕИЗВЕСТНАЯ»
Совет
Константы вместо «магических чисел»: Код if (code == BTN_UP) гораздо понятнее, чем if (code == 0xFF18E7).
Пример вывода:
Нажата кнопка: 1
Нажата кнопка: ▲ ВВЕРХ
Нажата кнопка: OK
Нажата кнопка: * (звёздочка)
Нажата кнопка: НЕИЗВЕСТНАЯ (код: 0xFFFFFFFF)
Эксперимент 3: Управление с пульта (светодиод + сервопривод)
Цель: Использовать кнопки пульта для одновременного управления встроенным светодиодом и сервоприводом.
Функционал:
Кнопка 1 → Включить светодиод
Кнопка 2 → Выключить светодиод
Кнопки ◄/► → Поворот сервопривода влево/вправо (шаг 15°)
Кнопка OK → Вернуть сервопривод в центр (90°)
1/*
2 * Проект 10: ИК-пульт управления
3 * Эксперимент 3: Управление светодиодом и сервоприводом
4 *
5 * Управление:
6 * 1 = включить светодиод
7 * 2 = выключить светодиод
8 * ◄ = сервопривод влево (шаг 15°)
9 * ► = сервопривод вправо (шаг 15°)
10 * OK = сервопривод в центр (90°)
11 *
12 * Подключение:
13 * Модуль IR → Sensor Shield линия A3 (- → G, + → V, S → S)
14 * Сервопривод → Sensor Shield линия D9 (см. Проект 4)
15 *
16 * ВАЖНО: Используем servo.detach() для устранения помех!
17 */
18
19#include <AlashIRControlRX.h>
20#include <Servo.h>
21
22const int IR_PIN = A3;
23const int LED_PIN = 13; // Встроенный светодиод Arduino
24const int SERVO_PIN = 9; // Сервопривод на D9
25const int SERVO_CENTER = 90; // Калибровка центра серво (90 = стандарт, настройте под ваш серво)
26
27AlashIRControlRX irReceiver(IR_PIN);
28Servo myServo;
29
30// Коды кнопок (замените на свои!)
31const unsigned long BTN_1 = 0xFFA25D;
32const unsigned long BTN_2 = 0xFF629D;
33const unsigned long BTN_LEFT = 0xFF10EF;
34const unsigned long BTN_RIGHT = 0xFF5AA5;
35const unsigned long BTN_OK = 0xFF38C7;
36
37int servoAngle = SERVO_CENTER; // Текущий угол сервопривода (0-180°)
38
39// Функция для безопасного управления сервоприводом
40void moveServo(int angle) {
41 myServo.attach(SERVO_PIN); // Подключаем только на время движения
42 delay(15); // Даём время на стабилизацию
43 myServo.write(angle); // Устанавливаем позицию
44 delay(300); // Ждём завершения движения
45 myServo.detach(); // ВАЖНО: Отключаем для устранения помех!
46}
47
48void setup() {
49 Serial.begin(9600);
50 irReceiver.begin();
51 pinMode(LED_PIN, OUTPUT);
52
53 Serial.println("========================================");
54 Serial.println(" Проект 10: Эксперимент 3");
55 Serial.println(" Управление с ИК-пульта");
56 Serial.println("========================================");
57 Serial.println();
58 Serial.println("Управление:");
59 Serial.println(" [1] = Светодиод ВКЛ");
60 Serial.println(" [2] = Светодиод ВЫКЛ");
61 Serial.println(" [◄] = Сервопривод влево");
62 Serial.println(" [►] = Сервопривод вправо");
63 Serial.println(" [OK] = Сервопривод в центр");
64 Serial.println();
65
66 // Устанавливаем начальную позицию сервопривода
67 moveServo(servoAngle);
68 Serial.print("Сервопривод в центре: ");
69 Serial.print(servoAngle);
70 Serial.println("°");
71}
72
73void loop() {
74 if (irReceiver.check()) {
75 unsigned long code = irReceiver.data;
76
77 // Игнорируем код повтора
78 if (code == 0xFFFFFFFF) return;
79
80 // Обрабатываем команды для светодиода
81 if (code == BTN_1) {
82 digitalWrite(LED_PIN, HIGH);
83 Serial.println("✓ Светодиод ВКЛЮЧЕН");
84
85 } else if (code == BTN_2) {
86 digitalWrite(LED_PIN, LOW);
87 Serial.println("✗ Светодиод ВЫКЛЮЧЕН");
88
89 // Обрабатываем команды для сервопривода
90 } else if (code == BTN_LEFT) {
91 // Поворот влево (увеличиваем угол)
92 servoAngle += 15; // Шаг 15°
93 if (servoAngle > 180) servoAngle = 180; // Ограничение: максимум 180°
94 moveServo(servoAngle); // Используем функцию с detach()
95 Serial.print("◄ Сервопривод: ");
96 Serial.print(servoAngle);
97 Serial.println("°");
98
99 } else if (code == BTN_RIGHT) {
100 // Поворот вправо (уменьшаем угол)
101 servoAngle -= 15;
102 if (servoAngle < 0) servoAngle = 0; // Ограничение: минимум 0°
103 moveServo(servoAngle); // Используем функцию с detach()
104 Serial.print("► Сервопривод: ");
105 Serial.print(servoAngle);
106 Serial.println("°");
107
108 } else if (code == BTN_OK) {
109 // Возврат в центр
110 servoAngle = SERVO_CENTER;
111 moveServo(servoAngle); // Используем функцию с detach()
112 Serial.print("⊙ Сервопривод в центре (");
113 Serial.print(SERVO_CENTER);
114 Serial.println("°)");
115 }
116 }
117}
Что нового:
Строка 19: Подключаем библиотеку
Servo.hдля управления сервоприводомСтроки 23-24: Определяем пины для светодиода (D13) и сервопривода (D11)
Строка 36: Переменная
servoAngleхранит текущий угол (0-180°)Строки 39-45: Функция
moveServo()— ключевое решение проблемы помех!attach()— подключаем сервопривод только на время движенияdelay(15)— даём время на стабилизациюwrite()— устанавливаем нужный уголdelay(300)— ждём завершения движенияdetach()— отключаем сервопривод для устранения помех!
Строка 59: В
setup()используемmoveServo()вместо прямогоattach()Строки 76-79: Кнопки 1/2 включают/выключают светодиод (простое ON/OFF)
Строки 84-104: Кнопки ◄/► изменяют угол сервопривода с шагом 15° через
moveServo()Строки 90, 99: Кнопка OK возвращает сервопривод в центр (90°) через
moveServo()Ограничения:
if (servoAngle < 0)иif (servoAngle > 180)предотвращают выход за пределы
Важно
Почему detach() критически важен:
Без detach() сервопривод постоянно получает ШИМ-сигналы (50 Гц), создавая электромагнитные помехи (EMI), которые улавливаются чувствительным IR-приёмником. Вы заметите:
Сервопривод жужжит, пытаясь удерживать позицию
Индикатор IR-модуля мигает в такт шуму сервопривода
IR-приёмник «зависает» и не реагирует на пульт
Функция moveServo() решает проблему: подключаем сервопривод только на 300 мс для движения, затем отключаем. Сервопривод держит позицию механически, а IR-приёмник работает без помех!
Предупреждение
Важно про пин 13: Встроенный светодиод Arduino на пине D13 НЕ поддерживает ШИМ (плавное изменение яркости). В этом эксперименте мы используем простое включение/выключение (digitalWrite).
Примечание
Пины с ШИМ на Arduino Uno: Если вы хотите управлять яркостью светодиода, подключите внешний светодиод к одному из ШИМ-пинов: D3, D5, D6, D9, D10, D11. Эти пины помечены символом ~ (тильда) на плате Arduino.
Пример вывода:
Сервопривод в центре: 90°
✓ Светодиод ВКЛЮЧЕН
► Сервопривод: 105°
► Сервопривод: 120°
◄ Сервопривод: 105°
⊙ Сервопривод в центре (90°)
✗ Светодиод ВЫКЛЮЧЕН
Эксперимент (для самостоятельной работы):
Если вы хотите управлять яркостью светодиода с помощью ШИМ:
Подключите внешний светодиод (с резистором 220 Ом) к ШИМ-пину, например D9:
Длинная ножка (анод) → резистор 220 Ом → D9
Короткая ножка (катод) → GND
Измените код:
const int LED_PIN = 9; // Внешний светодиод на D9 (ШИМ-пин)
int brightness = 0; // Текущая яркость (0-255)
// В setup():
pinMode(LED_PIN, OUTPUT);
// Добавьте новые кнопки для яркости:
const unsigned long BTN_UP = 0xFF18E7; // Кнопка ▲
const unsigned long BTN_DOWN = 0xFF4AB5; // Кнопка ▼
// В loop() добавьте обработку:
} else if (code == BTN_UP) {
brightness += 25;
if (brightness > 255) brightness = 255;
analogWrite(LED_PIN, brightness);
Serial.print("▲ Яркость: ");
Serial.println(brightness);
} else if (code == BTN_DOWN) {
brightness -= 25;
if (brightness < 0) brightness = 0;
analogWrite(LED_PIN, brightness);
Serial.print("▼ Яркость: ");
Serial.println(brightness);
}
Совет
Как определить ШИМ-пины? Посмотрите на плату Arduino — пины с поддержкой ШИМ помечены символом ~ (тильда) перед номером. Или проверьте распиновку вашей платы в документации.
Поиск неисправностей
Проблема: Serial Monitor не показывает коды при нажатии кнопок
Возможные причины:
Перепутана распиновка VS1838B
Проверьте порядок выводов OUT-GND-VCC
У разных производителей порядок может отличаться!
Попробуйте поменять местами провода VCC и GND (если приёмник не греется)
Неправильный пин в коде
Убедитесь:
const int IR_PIN = A3;Приёмник подключён к линии A3 на Sensor Shield
Батарейка в пульте разряжена
Проверьте: направьте пульт на камеру телефона и нажмите кнопку
Должна быть видна вспышка ИК-светодиода (на экране телефона)
Пульт слишком далеко или не направлен на приёмник
Попробуйте расстояние 10-20 см
Направляйте пульт точно на полусферу VS1838B
Библиотека установлена неправильно
Переустановите AlashIRControl (процесс см. Урок 1)
Проблема: Выводятся странные коды (например, 0xFFFFFFFF)
Причина: Это код повтора (repeat code) — пульт отправляет его, когда кнопка удерживается нажатой.
Решение:
Нажимайте кнопки коротко (не удерживайте)
Или игнорируйте код 0xFFFFFFFF в программе:
if (irReceiver.check()) {
unsigned long code = irReceiver.data;
if (code != 0xFFFFFFFF) { // Игнорируем код повтора
// Обрабатываем команду
}
}
Проблема: Коды кнопок не совпадают с таблицей
Причина: Разные производители пультов используют разные коды.
Решение:
Всегда запускайте Эксперимент 1 для определения кодов вашего пульта
Замените константы
BTN_1,BTN_2и т.д. на свои коды
Проблема: Приёмник работает только на близком расстоянии (<10 см)
Возможные причины:
Яркое освещение (солнце, лампы дневного света)
VS1838B фильтрует помехи, но очень яркий свет может мешать
Попробуйте работать в помещении с обычным освещением
Слабые контакты
Проверьте надёжность подключения проводов к VS1838B
Попробуйте другие провода Female-Female
Повреждён приёмник
Проверьте визуально: нет ли трещин на корпусе
Попробуйте другой VS1838B (если есть)
Проблема: При работе с сервоприводом IR-приёмник «зависает» или пропускает команды
Симптомы:
Сервопривод издаёт шум (тихое жужжание), пытаясь удерживать позицию
ИК-приёмник перестаёт реагировать на пульт или сильно задерживается
Программа «зависает» после команды сервоприводу
Причина: Электромагнитные помехи (EMI) от работающего сервопривода влияют на чувствительный IR-приёмник. Сервопривод постоянно корректирует позицию, создавая электрические импульсы, которые улавливаются IR-приёмником как ложные сигналы.
Решение 1: Отключение сервопривода после движения
Используйте servo.detach() после того, как сервопривод достиг нужной позиции:
void moveServo(int angle) {
myServo.attach(SERVO_PIN); // Подключаем только на время движения
delay(15); // Даём время на стабилизацию
myServo.write(angle); // Устанавливаем позицию
delay(300); // Ждём завершения движения
myServo.detach(); // ВАЖНО: Отключаем сервопривод!
}
void loop() {
if (irReceiver.check()) {
unsigned long code = irReceiver.data;
if (code == BTN_LEFT) {
servoAngle += 15;
servoAngle = constrain(servoAngle, 0, 180);
moveServo(servoAngle); // Используем функцию с detach()
}
}
}
Решение 2: Фильтрация помех в коде
Добавьте проверки длины сигнала и антидребезг:
unsigned long lastCode = 0;
unsigned long lastTime = 0;
void loop() {
if (irReceiver.check(true)) { // true = проверять длину сигнала
unsigned long code = irReceiver.data;
// Фильтр 1: Игнорируем слишком короткие/длинные сигналы (помехи)
if (irReceiver.length < 10 || irReceiver.length > 40) return;
// Фильтр 2: Антидребезг (игнорируем сигналы чаще 80 мс)
if (millis() - lastTime < 80) return;
// Фильтр 3: Обработка повторов
if (code == 0xFFFFFFFF) {
if (millis() - lastTime < 200) {
code = lastCode; // Используем предыдущий код для удержания
} else {
return;
}
}
lastCode = code;
lastTime = millis();
// Теперь обрабатываем команду
if (code == BTN_LEFT) {
servoAngle += 15;
servoAngle = constrain(servoAngle, 0, 180);
moveServo(servoAngle);
}
}
}
Решение 3: Разнесение компонентов
Расположите IR-приёмник как можно дальше от сервопривода (минимум 10 см)
Используйте более длинные провода Female-Female для IR-приёмника
На роботе Фобо: IR-приёмник на верхнем ярусе, сервопривод на переднем крае
Почему detach() помогает?
myServo.attach()— включает ШИМ-сигнал (50 Гц), сервопривод постоянно получает импульсыmyServo.detach()— отключает ШИМ, сервопривод перестаёт корректировать позицию и не создаёт помехСервопривод держит позицию механически (если нет большой нагрузки)
Совет
Для робота Фобо: Всегда используйте servo.detach() после сканирования ультразвуковым датчиком. Подключайте сервопривод только на время поворота головы робота!
Расширенная информация
Другие протоколы ИК-связи
Кроме NEC, существуют и другие популярные протоколы:
RC5 (Philips): 14 бит, манчестерское кодирование, используется в европейской технике
RC6 (Philips): 20+ бит, улучшенная версия RC5
Sony SIRC: 12/15/20 бит, используется в продукции Sony
Samsung: 32 бита, похож на NEC, но другая частота повтора
Библиотека AlashIRControlRX поддерживает только протокол NEC — самый распространённый.
Дальность передачи ИК-сигнала
Факторы, влияющие на дальность:
Мощность ИК-светодиода в пульте: обычно 20-100 мВт
Чувствительность приёмника: VS1838B рассчитан на 5-8 метров
Угол приёма: VS1838B имеет угол ±45° (всего 90° конус)
Преграды: ИК-свет не проходит через стены, мебель, руки
Освещение: прямой солнечный свет сильно снижает дальность
Для робота Фобо достаточно 2-3 метра — этого хватит для управления в классе.
Частота модуляции 38 кГц
Почему именно 38 кГц?
Это компромисс между энергопотреблением и помехоустойчивостью
Низкая частота (напр. 10 кГц): может совпадать с частотой ламп (50/60 Гц и их гармоники)
Высокая частота (напр. 100 кГц): требует более быстрой электроники в приёмнике
38 кГц: стандарт с 1980-х годов, поддерживается большинством приёмников
Существуют также приёмники на 36 кГц, 40 кГц, 56 кГц — они несовместимы между собой!
Энергопотребление VS1838B
Типовые параметры:
Напряжение питания: 2.7-5.5V (оптимально 5V)
Ток потребления: 0.4-1.5 мА (в зависимости от уровня сигнала)
Режим ожидания: ~0.4 мА
Для сравнения: Arduino Uno потребляет ~45 мА, светодиод ~20 мА. VS1838B очень экономичен!
Что дальше?
Поздравляем! Вы научились работать с ИК-пультом — важнейшим инструментом дистанционного управления роботом.
Что мы узнали:
✅ Как работает ИК-связь (передатчик, приёмник, протокол NEC)
✅ Как подключить VS1838B к Sensor Shield
✅ Как установить и использовать библиотеку AlashIRControlRX
✅ Как считывать коды кнопок пульта
✅ Как распознавать кнопки и управлять устройствами
В следующих проектах:
Проект 11: Управление роботом через ИК-пульт — переключаем автономные режимы кнопками пульта
Проект 12: Bluetooth-модуль HM-10 — учимся работать с Bluetooth (Android и iOS!)
Проект 13: Управление роботом через Bluetooth — ручное управление моторами с телефона
Проект 14: Мастер-режим — полная интеграция: все автономные режимы + Bluetooth-управление!
Как ИК-пульт будет использоваться в роботе:
Кнопки ▲▼◄► — ручное управление движением (Проект 11)
Кнопки 1, 2, 3 — переключение автономных режимов (Проект 11)
Кнопка OK — старт/стоп программы (Проект 11)
До встречи в Проекте 11 — управление роботом через ИК-пульт! 🚀