Электронное приложение к набору «IO.KIT Робот Ампи: Голова»
На этой странице ты найдёшь все нужные материалы для проектов набора Робот Ампи: Голова из серии IO.KIT:
- Схему подключения модулей.
- Исходный код программ (копируй его в редактор Arduino IDE).
- Дополнительные материалы: программные библиотеки, даташиты и т. п.
Обрати внимание
Для сборки и функционирования головы робота Ампи тебе понадобится IO.KIT Базовый!
Схема
Проекты
Прежде чем приступать к экспериментам, нужно подготовить свой компьютер:
- Установи среду программирования Arduino IDE и копируй туда готовый код проектов.
- Установи дополнительные библиотеки для Arduino IDE, пользуясь нашим руководством.
Драйвер чипа CH340
Установи драйвер CH340 для Windows или Linux, чтобы твой компьютер мог корректно распознать и прошить плату Iskra Nano.
№1. Электронные глаза
Активируй светодиодные глаза робота Ампи.
- SampleEyes.ino
- // Подключаем библиотеку для работы со светодиодными матрицами
- #include <TroykaLedMatrix.h>
- // Создаём объект матрицы левого глаза
- // на шине I²C с адресом 0x60 (указан по умолчанию)
- TroykaLedMatrix matrixL;
- // Создаём объект матрицы правого глаза
- // на шине I²C с адресом 0x63
- TroykaLedMatrix matrixR(0x63);
- // Создаём иконку «Взгляд прямо» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- // Эмоции рисуем в редакторе изображений для LED-матрицы
- // https://amperka.github.io/led-matrix-editor/
- constexpr uint8_t ICON_EYE_STRAIGHT[] {
- 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e
- };
- void setup() {
- // Инициализируем матрицы
- matrixL.begin();
- matrixR.begin();
- // Очищаем матрицы
- matrixL.clear();
- matrixR.clear();
- // Устанавливаем яркость матриц
- matrixL.setCurrentLimit(ROW_CURRENT_05MA);
- matrixR.setCurrentLimit(ROW_CURRENT_05MA);
- // Отображаем на матрицах иконку «Взгляд прямо»
- matrixL.drawBitmap(ICON_EYE_STRAIGHT);
- matrixR.drawBitmap(ICON_EYE_STRAIGHT);
- }
- void loop() {
- }
№2. Осмотр местности
- LookAround.ino
- // Подключаем библиотеку для работы со светодиодными матрицами
- #include <TroykaLedMatrix.h>
- // Создаём объект матрицы левого глаза
- // на шине I²C с адресом 0x60 (указан по умолчанию)
- TroykaLedMatrix matrixL;
- // Создаём объект матрицы правого глаза
- // на шине I²C с адресом 0x63
- TroykaLedMatrix matrixR(0x63);
- // Создаём массив иконок анимации «Осмотр местности по сторонам» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- // Эмоции рисуем в редакторе изображений для LED-матрицы
- // https://amperka.github.io/led-matrix-editor/
- constexpr uint8_t ICON_EYE_LOOK_AROUND[][8] {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x87, 0x87, 0x81, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0xe1, 0xe1, 0x81, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7e, 0x99, 0x99, 0x81, 0x81, 0x81, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x81, 0x81, 0x99, 0x99, 0x7e }
- };
- // Создаём массив иконок анимации «Осмотр местности по углам» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_LOOK_CORNER[][8] {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7e, 0x87, 0x87, 0x81, 0x81, 0x81, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x81, 0x81, 0x87, 0x87, 0x7e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x81, 0x81, 0xe1, 0xe1, 0x7e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7e, 0xe1, 0xe1, 0x81, 0x81, 0x81, 0x81, 0x7e }
- };
- // Вычисляем количество кадров в массиве «Осмотр местности»
- constexpr uint8_t COUNT_FRAMES_LOOK_AROUND = sizeof(ICON_EYE_LOOK_AROUND)
- / sizeof(ICON_EYE_LOOK_AROUND[0]);
- // Вычисляем количество кадров в массиве «Осмотр местности по диагонали»
- constexpr uint8_t COUNT_FRAMES_LOOK_CORNER = sizeof(ICON_EYE_LOOK_CORNER)
- / sizeof(ICON_EYE_LOOK_CORNER[0]);
- void setup() {
- // Инициализируем матрицы
- matrixL.begin();
- matrixR.begin();
- // Очищаем матрицы
- matrixL.clear();
- matrixR.clear();
- }
- void loop() {
- // Перебираем массив «Осмотр местности» по кадрам
- for (int i = 0; i < COUNT_FRAMES_LOOK_AROUND; i++) {
- // Отображаем на матрицах текущий кадр
- matrixL.drawBitmap(ICON_EYE_LOOK_AROUND[i]);
- matrixR.drawBitmap(ICON_EYE_LOOK_AROUND[i]);
- // Ждём 500 мс
- delay(500);
- }
- }
№3. Отображение эмоций
- Emotions.ino
- // Подключаем библиотеку для работы со светодиодными матрицами
- #include <TroykaLedMatrix.h>
- // Создаём объект матрицы левого глаза
- // на шине I²C с адресом 0x60 (указан по умолчанию)
- TroykaLedMatrix matrixL;
- // Создаём объект матрицы правого глаза
- // на шине I²C с адресом 0x63
- TroykaLedMatrix matrixR(0x63);
- // Создаём структуру анимации
- struct AnimationFrame {
- uint8_t* iconEyeL;
- uint8_t* iconEyeR;
- int timeFrame;
- };
- // Создаём массив иконок анимации «Моргание» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- // Эмоции рисуем в редакторе изображений для LED-матрицы
- // https://amperka.github.io/led-matrix-editor/
- constexpr uint8_t ICON_EYE_BLINK[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x00, 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x7e },
- { 0x00, 0x00, 0x7e, 0x81, 0x99, 0x99, 0x81, 0x7e },
- { 0x00, 0x00, 0x00, 0x7e, 0x99, 0x99, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x7e, 0x99, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x7e, 0x99, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x7e, 0x99, 0x99, 0x7e, 0x00 },
- { 0x00, 0x00, 0x7e, 0x81, 0x99, 0x99, 0x81, 0x7e },
- { 0x00, 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Злость»
- // в шестнадцатеричной системе HEX для левого глаза
- constexpr uint8_t ICON_EYE_ANGRY_L[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x78, 0x84, 0x82, 0x9a, 0x9a, 0x82, 0x82, 0x7c },
- { 0x70, 0x88, 0x84, 0x9a, 0x9a, 0x82, 0x82, 0x7c },
- { 0x60, 0x90, 0x88, 0x9c, 0x9a, 0x82, 0x82, 0x7c },
- { 0x40, 0xa0, 0x90, 0x88, 0xb4, 0xb2, 0x82, 0x7c },
- { 0x80, 0xc0, 0xa0, 0x90, 0xa8, 0xb4, 0x82, 0x7c },
- { 0x40, 0xa0, 0x90, 0x88, 0xb4, 0xb2, 0x82, 0x7c },
- { 0x60, 0x90, 0x88, 0x9c, 0x9a, 0x82, 0x82, 0x7c },
- { 0x70, 0x88, 0x84, 0x9a, 0x9a, 0x82, 0x82, 0x7c },
- { 0x78, 0x84, 0x82, 0x9a, 0x9a, 0x82, 0x82, 0x7c },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Злость»
- // в шестнадцатеричной системе HEX для правого глаза
- constexpr uint8_t ICON_EYE_ANGRY_R[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x1e, 0x21, 0x41, 0x59, 0x59, 0x41, 0x41, 0x3e },
- { 0x0e, 0x11, 0x21, 0x59, 0x59, 0x41, 0x41, 0x3e },
- { 0x06, 0x09, 0x11, 0x39, 0x59, 0x41, 0x41, 0x3e },
- { 0x02, 0x05, 0x09, 0x11, 0x2d, 0x4d, 0x41, 0x3e },
- { 0x01, 0x03, 0x05, 0x09, 0x15, 0x2d, 0x41, 0x3e },
- { 0x02, 0x05, 0x09, 0x11, 0x2d, 0x4d, 0x41, 0x3e },
- { 0x06, 0x09, 0x11, 0x39, 0x59, 0x41, 0x41, 0x3e },
- { 0x0e, 0x11, 0x21, 0x59, 0x59, 0x41, 0x41, 0x3e },
- { 0x1e, 0x21, 0x41, 0x59, 0x59, 0x41, 0x41, 0x3e }
- };
- // Создаём массив иконок анимации «Грусть»
- // в шестнадцатеричной системе HEX для левого глаза
- constexpr uint8_t ICON_EYE_SAD_L[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x3e, 0x41, 0x81, 0x99, 0x99, 0x81, 0x82, 0x7c },
- { 0x1e, 0x21, 0x41, 0x99, 0x99, 0x81, 0x82, 0x7c },
- { 0x0e, 0x11, 0x21, 0x41, 0x8d, 0x8d, 0x82, 0x7c },
- { 0x0e, 0x11, 0x21, 0x41, 0x4d, 0x4d, 0x42, 0x3c },
- { 0x06, 0x09, 0x11, 0x21, 0x4d, 0x4d, 0x42, 0x3c },
- { 0x0e, 0x11, 0x21, 0x41, 0x4d, 0x4d, 0x42, 0x3c },
- { 0x0e, 0x11, 0x21, 0x41, 0x8d, 0x8d, 0x82, 0x7c },
- { 0x1e, 0x21, 0x41, 0x99, 0x99, 0x81, 0x82, 0x7c },
- { 0x3e, 0x41, 0x81, 0x99, 0x99, 0x81, 0x82, 0x7c },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Грусть»
- // в шестнадцатеричной системе HEX для правого глаза
- constexpr uint8_t ICON_EYE_SAD_R[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7c, 0x82, 0x81, 0x99, 0x99, 0x81, 0x41, 0x3e },
- { 0x78, 0x84, 0x82, 0x99, 0x99, 0x81, 0x41, 0x3e },
- { 0x70, 0x88, 0x84, 0x82, 0xb1, 0xb1, 0x41, 0x3e },
- { 0x70, 0x88, 0x84, 0x82, 0xb2, 0xb2, 0x42, 0x3c },
- { 0x60, 0x90, 0x88, 0x84, 0xb2, 0xb2, 0x42, 0x3c },
- { 0x70, 0x88, 0x84, 0x82, 0xb2, 0xb2, 0x42, 0x3c },
- { 0x70, 0x88, 0x84, 0x82, 0xb1, 0xb1, 0x41, 0x3e },
- { 0x78, 0x84, 0x82, 0x99, 0x99, 0x81, 0x41, 0x3e },
- { 0x7c, 0x82, 0x81, 0x99, 0x99, 0x81, 0x41, 0x3e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Радость» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_HAPPY[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x00, 0x7e, 0x81, 0x99, 0x99, 0x81, 0x7e, 0x00 },
- { 0x00, 0x7e, 0x81, 0x99, 0x99, 0xff, 0x00, 0x00 },
- { 0x00, 0x7e, 0xdb, 0x99, 0xff, 0x81, 0x00, 0x00 },
- { 0x00, 0x3c, 0x5a, 0xff, 0xc3, 0x81, 0x00, 0x00 },
- { 0x00, 0x3c, 0x7e, 0xc3, 0xc3, 0x81, 0x00, 0x00 },
- { 0x00, 0x3c, 0x5a, 0xff, 0xc3, 0x81, 0x00, 0x00 },
- { 0x00, 0x7e, 0xdb, 0x99, 0xff, 0x81, 0x00, 0x00 },
- { 0x00, 0x7e, 0x81, 0x99, 0x99, 0xff, 0x00, 0x00 },
- { 0x00, 0x7e, 0x81, 0x99, 0x99, 0x81, 0x7e, 0x00 },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Удивление» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_AMAZED[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7e, 0x81, 0x99, 0xbd, 0xbd, 0x99, 0x81, 0x7e },
- { 0x7e, 0x81, 0xbd, 0xbd, 0xbd, 0xbd, 0x81, 0x7e },
- { 0x7e, 0x81, 0x99, 0xbd, 0xbd, 0x99, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Любовь» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_LOVE[][8] PROGMEM {
- { 0x66, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x18 },
- { 0x00, 0x00, 0x24, 0x7e, 0x7e, 0x3c, 0x18, 0x00 }
- };
- // Создаём массив иконок анимации Сон» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_SLEEP[][8] PROGMEM {
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 0x7e, 0x00 }
- };
- // Создаём анимацию «Моргание»
- AnimationFrame animationBlink[] = {
- { ICON_EYE_BLINK[0], ICON_EYE_BLINK[0], 500 },
- { ICON_EYE_BLINK[1], ICON_EYE_BLINK[1], 25 },
- { ICON_EYE_BLINK[2], ICON_EYE_BLINK[2], 25 },
- { ICON_EYE_BLINK[3], ICON_EYE_BLINK[3], 25 },
- { ICON_EYE_BLINK[4], ICON_EYE_BLINK[4], 25 },
- { ICON_EYE_BLINK[5], ICON_EYE_BLINK[5], 25 },
- { ICON_EYE_BLINK[6], ICON_EYE_BLINK[6], 25 },
- { ICON_EYE_BLINK[7], ICON_EYE_BLINK[7], 25 },
- { ICON_EYE_BLINK[8], ICON_EYE_BLINK[8], 25 },
- { ICON_EYE_BLINK[9], ICON_EYE_BLINK[9], 25 },
- { ICON_EYE_BLINK[10], ICON_EYE_BLINK[10], 500 }
- };
- // Создаём анимацию «Злость»
- AnimationFrame animationAngry[] = {
- { ICON_EYE_ANGRY_L[0], ICON_EYE_ANGRY_R[0], 500 },
- { ICON_EYE_ANGRY_L[1], ICON_EYE_ANGRY_R[1], 50 },
- { ICON_EYE_ANGRY_L[2], ICON_EYE_ANGRY_R[2], 50 },
- { ICON_EYE_ANGRY_L[3], ICON_EYE_ANGRY_R[3], 50 },
- { ICON_EYE_ANGRY_L[4], ICON_EYE_ANGRY_R[4], 50 },
- { ICON_EYE_ANGRY_L[5], ICON_EYE_ANGRY_R[5], 2000 },
- { ICON_EYE_ANGRY_L[6], ICON_EYE_ANGRY_R[6], 50 },
- { ICON_EYE_ANGRY_L[7], ICON_EYE_ANGRY_R[7], 50 },
- { ICON_EYE_ANGRY_L[8], ICON_EYE_ANGRY_R[8], 50 },
- { ICON_EYE_ANGRY_L[9], ICON_EYE_ANGRY_R[9], 50 },
- { ICON_EYE_ANGRY_L[10], ICON_EYE_ANGRY_R[10], 500 }
- };
- // Создаём анимацию «Грусть»
- AnimationFrame animationSad[] = {
- { ICON_EYE_SAD_L[0], ICON_EYE_SAD_R[0], 500 },
- { ICON_EYE_SAD_L[1], ICON_EYE_SAD_R[1], 50 },
- { ICON_EYE_SAD_L[2], ICON_EYE_SAD_R[2], 50 },
- { ICON_EYE_SAD_L[3], ICON_EYE_SAD_R[3], 50 },
- { ICON_EYE_SAD_L[4], ICON_EYE_SAD_R[4], 50 },
- { ICON_EYE_SAD_L[5], ICON_EYE_SAD_R[5], 3000 },
- { ICON_EYE_SAD_L[6], ICON_EYE_SAD_R[6], 50 },
- { ICON_EYE_SAD_L[7], ICON_EYE_SAD_R[7], 50 },
- { ICON_EYE_SAD_L[8], ICON_EYE_SAD_R[8], 50 },
- { ICON_EYE_SAD_L[9], ICON_EYE_SAD_R[9], 50 },
- { ICON_EYE_SAD_L[10], ICON_EYE_SAD_R[10], 500 }
- };
- // Создаём анимацию «Радость»
- AnimationFrame animationHappy[] = {
- { ICON_EYE_HAPPY[0], ICON_EYE_HAPPY[0], 500 },
- { ICON_EYE_HAPPY[1], ICON_EYE_HAPPY[1], 40 },
- { ICON_EYE_HAPPY[2], ICON_EYE_HAPPY[2], 40 },
- { ICON_EYE_HAPPY[3], ICON_EYE_HAPPY[3], 40 },
- { ICON_EYE_HAPPY[4], ICON_EYE_HAPPY[4], 40 },
- { ICON_EYE_HAPPY[5], ICON_EYE_HAPPY[5], 2000 },
- { ICON_EYE_HAPPY[6], ICON_EYE_HAPPY[6], 40 },
- { ICON_EYE_HAPPY[7], ICON_EYE_HAPPY[7], 40 },
- { ICON_EYE_HAPPY[8], ICON_EYE_HAPPY[8], 40 },
- { ICON_EYE_HAPPY[9], ICON_EYE_HAPPY[9], 40 },
- { ICON_EYE_HAPPY[10], ICON_EYE_HAPPY[10], 500 }
- };
- // Создаём анимацию «Удивление»
- AnimationFrame animationAmazed[] = {
- { ICON_EYE_AMAZED[0], ICON_EYE_AMAZED[0], 500 },
- { ICON_EYE_AMAZED[1], ICON_EYE_AMAZED[1], 100 },
- { ICON_EYE_AMAZED[2], ICON_EYE_AMAZED[2], 2000 },
- { ICON_EYE_AMAZED[3], ICON_EYE_AMAZED[3], 100 },
- { ICON_EYE_AMAZED[4], ICON_EYE_AMAZED[4], 500 }
- };
- // Создаём анимацию «Любовь»
- AnimationFrame animationLove[] = {
- { ICON_EYE_LOVE[0], ICON_EYE_LOVE[0], 1000 },
- { ICON_EYE_LOVE[1], ICON_EYE_LOVE[1], 300 }
- };
- // Создаём анимацию «Сон»
- AnimationFrame animationSleep[] = {
- { ICON_EYE_SLEEP[0], ICON_EYE_SLEEP[0], 750 },
- { ICON_EYE_SLEEP[1], ICON_EYE_SLEEP[1], 750 }
- };
- // Вычисляем количество кадров в анимации «Моргание»
- constexpr uint8_t COUNT_FRAMES_BLINK = sizeof(animationBlink) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Злость»
- constexpr uint8_t COUNT_FRAMES_ANGRY = sizeof(animationAngry) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Грусть»
- constexpr uint8_t COUNT_FRAMES_SAD = sizeof(animationSad) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Радость»
- constexpr uint8_t COUNT_FRAMES_HAPPY = sizeof(animationHappy) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Удивление»
- constexpr uint8_t COUNT_FRAMES_AMAZED = sizeof(animationAmazed) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Бьющее серде»
- constexpr uint8_t COUNT_FRAMES_LOVE = sizeof(animationLove) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Сон»
- constexpr uint8_t COUNT_FRAMES_SLEEP = sizeof(animationSleep) / sizeof(AnimationFrame);
- // Создаём константу для хранения повторений эмоции
- constexpr uint8_t COUNT_REPEAT_EMOTION = 3;
- void setup() {
- // Инициализируем матрицы
- matrixL.begin();
- matrixR.begin();
- // Очищаем матрицы
- matrixL.clear();
- matrixR.clear();
- }
- void loop() {
- // Перебираем количество повторений анимации «Моргание»
- for (int i = 0; i < COUNT_REPEAT_EMOTION; i++) {
- // Отображаем анимацию «Моргание»
- drawAnimation(animationBlink, COUNT_FRAMES_BLINK);
- }
- // Перебираем количество повторений анимации «Злость»
- for (int i = 0; i < COUNT_REPEAT_EMOTION; i++) {
- // Отображаем анимацию «Злость»
- drawAnimation(animationAngry, COUNT_FRAMES_ANGRY);
- }
- // Перебираем количество повторений анимации «Грусть»
- for (int i = 0; i < COUNT_REPEAT_EMOTION; i++) {
- // Отображаем анимацию «Грусть»
- drawAnimation(animationSad, COUNT_FRAMES_SAD);
- }
- // Перебираем количество повторений анимации «Радость»
- for (int i = 0; i < COUNT_REPEAT_EMOTION; i++) {
- // Отображаем анимацию «Радость»
- drawAnimation(animationHappy, COUNT_FRAMES_HAPPY);
- }
- // Перебираем количество повторений анимации «Удивление»
- for (int i = 0; i < COUNT_REPEAT_EMOTION; i++) {
- // Отображаем анимацию «Удивление»
- drawAnimation(animationAmazed, COUNT_FRAMES_AMAZED);
- }
- // Перебираем количество повторений анимации «Любовь»
- for (int i = 0; i < COUNT_REPEAT_EMOTION; i++) {
- // Отображаем анимацию «Любовь»
- drawAnimation(animationLove, COUNT_FRAMES_LOVE);
- }
- }
- // Функция отображения анимации на матрицах
- void drawAnimation(AnimationFrame* animationFrame, int countFrames) {
- // Перебираем анимацию по кадрам
- for (int indexFrame = 0; indexFrame < countFrames; indexFrame++) {
- // Отображаем на матрицах текущий кадр
- matrixL.drawBitmapF(animationFrame[indexFrame].iconEyeL);
- matrixR.drawBitmapF(animationFrame[indexFrame].iconEyeR);
- // Ждём время задержки текущего кадра
- delay(animationFrame[indexFrame].timeFrame);
- }
- }
№4. Эмоции со звуком
- EmotionSound.ino
- // Подключаем библиотеку для работы с мелодиями в формате RTTTL
- #include <anyrtttl.h>
- // Подключаем библиотеку для работы с таймером millis
- #include <TimerMs.h>
- // Подключаем библиотеку для работы со светодиодными матрицами
- #include <TroykaLedMatrix.h>
- // Даём понятное имя пину 3 с пищалкой
- constexpr uint8_t BUZZER_PIN = 3;
- // Создаём объект для работы с таймером
- TimerMs timer;
- // Создаём объект матрицы левого глаза
- // на шине I²C с адресом 0x60 (указан по умолчанию)
- TroykaLedMatrix matrixL;
- // Создаём объект матрицы правого глаза
- // на шине I²C с адресом 0x63
- TroykaLedMatrix matrixR(0x63);
- // Создаём массив данных мелодии «Моргание» в формате RTTTL
- constexpr uint8_t melodyBlink[] PROGMEM = "Blink:d=4,o=4,b=120:"
- "16e,16p,16g,16p,16e,16p,16g,16p,";
- // Создаём массив данных мелодии «Злость» в формате RTTTL
- constexpr uint8_t melodyAngry[] PROGMEM = "Angry:d=4,o=4,b=200:"
- "16g,16g,16f#,16f#,16e,16e,16d#,16d#,"
- "16c,16c,16b4,16b4,16a4,16a4,16g4,16g4";
- // Создаём массив данных мелодии «Грусть» в формате RTTTL
- constexpr uint8_t melodySad[] PROGMEM = "Sad:d=4,o=4,b=25:"
- "16g,16a#,16d,16f,"
- "16d,16c,16a#";
- constexpr uint8_t melodyHappy[] PROGMEM = "Happy:d=4,o=4,b=140:"
- "8c4,8e4,8g4,8c4,8e4,8g4,8c4,8e4"
- "8g4,8c4,8e4,8g4";
- // Создаём массив данных мелодии «Удивление» в формате RTTTL
- constexpr uint8_t melodyAmazed[] PROGMEM = "Amazed:d=4,o=4,b=180:"
- "16c,16d,16e,16f,16g,16a,16b,16c,"
- "16b,16a,16g,16f,16e,16d,16c,16d";
- // Создаём массив данных мелодии «Любовь» в формате RTTTL
- constexpr uint8_t melodyLove[] PROGMEM = "Love:d=4,o=4,b=100:"
- "8g,8p,8g,8p,8a,8p,8g,8p,"
- "8g,8p,8g,8p,8f,8e,8d";
- // Создаём массив данных мелодии «Сонливость» в формате RTTTL
- constexpr uint8_t melodySleep[] PROGMEM = "Sleep:d=4,o=4,b=45:"
- "8c,8c,8d,8e,8d,8c,8d,8e";
- // Создаём перечисление эмоций с соответствующей переменной
- enum Emotion {
- EMOTION_BLINK,
- EMOTION_ANGRY,
- EMOTION_SAD,
- EMOTION_HAPPY,
- EMOTION_AMAZED,
- EMOTION_LOVE,
- EMOTION_SLEEP,
- } emotion;
- // Создаём структуру анимации
- struct AnimationFrame {
- uint8_t* iconEyeL;
- uint8_t* iconEyeR;
- int timeFrame;
- };
- // Создаём объект структуры анимации
- AnimationFrame* animationFrame;
- // Создаём массив иконок анимации «Моргание» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- // Эмоции рисуем в редакторе изображений для LED-матрицы
- // https://amperka.github.io/led-matrix-editor/
- constexpr uint8_t ICON_EYE_BLINK[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x00, 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x7e },
- { 0x00, 0x00, 0x7e, 0x81, 0x99, 0x99, 0x81, 0x7e },
- { 0x00, 0x00, 0x00, 0x7e, 0x99, 0x99, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x7e, 0x99, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x7e, 0x99, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x7e, 0x99, 0x99, 0x7e, 0x00 },
- { 0x00, 0x00, 0x7e, 0x81, 0x99, 0x99, 0x81, 0x7e },
- { 0x00, 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Злость»
- // в шестнадцатеричной системе HEX для левого глаза
- constexpr uint8_t ICON_EYE_ANGRY_L[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x78, 0x84, 0x82, 0x9a, 0x9a, 0x82, 0x82, 0x7c },
- { 0x70, 0x88, 0x84, 0x9a, 0x9a, 0x82, 0x82, 0x7c },
- { 0x60, 0x90, 0x88, 0x9c, 0x9a, 0x82, 0x82, 0x7c },
- { 0x40, 0xa0, 0x90, 0x88, 0xb4, 0xb2, 0x82, 0x7c },
- { 0x80, 0xc0, 0xa0, 0x90, 0xa8, 0xb4, 0x82, 0x7c },
- { 0x40, 0xa0, 0x90, 0x88, 0xb4, 0xb2, 0x82, 0x7c },
- { 0x60, 0x90, 0x88, 0x9c, 0x9a, 0x82, 0x82, 0x7c },
- { 0x70, 0x88, 0x84, 0x9a, 0x9a, 0x82, 0x82, 0x7c },
- { 0x78, 0x84, 0x82, 0x9a, 0x9a, 0x82, 0x82, 0x7c },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Злость»
- // в шестнадцатеричной системе HEX для правого глаза
- constexpr uint8_t ICON_EYE_ANGRY_R[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x1e, 0x21, 0x41, 0x59, 0x59, 0x41, 0x41, 0x3e },
- { 0x0e, 0x11, 0x21, 0x59, 0x59, 0x41, 0x41, 0x3e },
- { 0x06, 0x09, 0x11, 0x39, 0x59, 0x41, 0x41, 0x3e },
- { 0x02, 0x05, 0x09, 0x11, 0x2d, 0x4d, 0x41, 0x3e },
- { 0x01, 0x03, 0x05, 0x09, 0x15, 0x2d, 0x41, 0x3e },
- { 0x02, 0x05, 0x09, 0x11, 0x2d, 0x4d, 0x41, 0x3e },
- { 0x06, 0x09, 0x11, 0x39, 0x59, 0x41, 0x41, 0x3e },
- { 0x0e, 0x11, 0x21, 0x59, 0x59, 0x41, 0x41, 0x3e },
- { 0x1e, 0x21, 0x41, 0x59, 0x59, 0x41, 0x41, 0x3e }
- };
- // Создаём массив иконок анимации «Грусть»
- // в шестнадцатеричной системе HEX для левого глаза
- constexpr uint8_t ICON_EYE_SAD_L[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x3e, 0x41, 0x81, 0x99, 0x99, 0x81, 0x82, 0x7c },
- { 0x1e, 0x21, 0x41, 0x99, 0x99, 0x81, 0x82, 0x7c },
- { 0x0e, 0x11, 0x21, 0x41, 0x8d, 0x8d, 0x82, 0x7c },
- { 0x0e, 0x11, 0x21, 0x41, 0x4d, 0x4d, 0x42, 0x3c },
- { 0x06, 0x09, 0x11, 0x21, 0x4d, 0x4d, 0x42, 0x3c },
- { 0x0e, 0x11, 0x21, 0x41, 0x4d, 0x4d, 0x42, 0x3c },
- { 0x0e, 0x11, 0x21, 0x41, 0x8d, 0x8d, 0x82, 0x7c },
- { 0x1e, 0x21, 0x41, 0x99, 0x99, 0x81, 0x82, 0x7c },
- { 0x3e, 0x41, 0x81, 0x99, 0x99, 0x81, 0x82, 0x7c },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Грусть»
- // в шестнадцатеричной системе HEX для правого глаза
- constexpr uint8_t ICON_EYE_SAD_R[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7c, 0x82, 0x81, 0x99, 0x99, 0x81, 0x41, 0x3e },
- { 0x78, 0x84, 0x82, 0x99, 0x99, 0x81, 0x41, 0x3e },
- { 0x70, 0x88, 0x84, 0x82, 0xb1, 0xb1, 0x41, 0x3e },
- { 0x70, 0x88, 0x84, 0x82, 0xb2, 0xb2, 0x42, 0x3c },
- { 0x60, 0x90, 0x88, 0x84, 0xb2, 0xb2, 0x42, 0x3c },
- { 0x70, 0x88, 0x84, 0x82, 0xb2, 0xb2, 0x42, 0x3c },
- { 0x70, 0x88, 0x84, 0x82, 0xb1, 0xb1, 0x41, 0x3e },
- { 0x78, 0x84, 0x82, 0x99, 0x99, 0x81, 0x41, 0x3e },
- { 0x7c, 0x82, 0x81, 0x99, 0x99, 0x81, 0x41, 0x3e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Радость» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_HAPPY[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x00, 0x7e, 0x81, 0x99, 0x99, 0x81, 0x7e, 0x00 },
- { 0x00, 0x7e, 0x81, 0x99, 0x99, 0xff, 0x00, 0x00 },
- { 0x00, 0x7e, 0xdb, 0x99, 0xff, 0x81, 0x00, 0x00 },
- { 0x00, 0x3c, 0x5a, 0xff, 0xc3, 0x81, 0x00, 0x00 },
- { 0x00, 0x3c, 0x7e, 0xc3, 0xc3, 0x81, 0x00, 0x00 },
- { 0x00, 0x3c, 0x5a, 0xff, 0xc3, 0x81, 0x00, 0x00 },
- { 0x00, 0x7e, 0xdb, 0x99, 0xff, 0x81, 0x00, 0x00 },
- { 0x00, 0x7e, 0x81, 0x99, 0x99, 0xff, 0x00, 0x00 },
- { 0x00, 0x7e, 0x81, 0x99, 0x99, 0x81, 0x7e, 0x00 },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Удивление» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_AMAZED[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7e, 0x81, 0x99, 0xbd, 0xbd, 0x99, 0x81, 0x7e },
- { 0x7e, 0x81, 0xbd, 0xbd, 0xbd, 0xbd, 0x81, 0x7e },
- { 0x7e, 0x81, 0x99, 0xbd, 0xbd, 0x99, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Любовь» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_LOVE[][8] PROGMEM {
- { 0x66, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x18 },
- { 0x00, 0x00, 0x24, 0x7e, 0x7e, 0x3c, 0x18, 0x00 }
- };
- // Создаём массив иконок анимации Сон» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_SLEEP[][8] PROGMEM {
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 0x7e, 0x00 }
- };
- // Создаём анимацию «Моргание»
- AnimationFrame animationBlink[] = {
- { ICON_EYE_BLINK[0], ICON_EYE_BLINK[0], 500 },
- { ICON_EYE_BLINK[1], ICON_EYE_BLINK[1], 25 },
- { ICON_EYE_BLINK[2], ICON_EYE_BLINK[2], 25 },
- { ICON_EYE_BLINK[3], ICON_EYE_BLINK[3], 25 },
- { ICON_EYE_BLINK[4], ICON_EYE_BLINK[4], 25 },
- { ICON_EYE_BLINK[5], ICON_EYE_BLINK[5], 25 },
- { ICON_EYE_BLINK[6], ICON_EYE_BLINK[6], 25 },
- { ICON_EYE_BLINK[7], ICON_EYE_BLINK[7], 25 },
- { ICON_EYE_BLINK[8], ICON_EYE_BLINK[8], 25 },
- { ICON_EYE_BLINK[9], ICON_EYE_BLINK[9], 25 },
- { ICON_EYE_BLINK[10], ICON_EYE_BLINK[10], 500 }
- };
- // Создаём анимацию «Злость»
- AnimationFrame animationAngry[] = {
- { ICON_EYE_ANGRY_L[0], ICON_EYE_ANGRY_R[0], 500 },
- { ICON_EYE_ANGRY_L[1], ICON_EYE_ANGRY_R[1], 50 },
- { ICON_EYE_ANGRY_L[2], ICON_EYE_ANGRY_R[2], 50 },
- { ICON_EYE_ANGRY_L[3], ICON_EYE_ANGRY_R[3], 50 },
- { ICON_EYE_ANGRY_L[4], ICON_EYE_ANGRY_R[4], 50 },
- { ICON_EYE_ANGRY_L[5], ICON_EYE_ANGRY_R[5], 2000 },
- { ICON_EYE_ANGRY_L[6], ICON_EYE_ANGRY_R[6], 50 },
- { ICON_EYE_ANGRY_L[7], ICON_EYE_ANGRY_R[7], 50 },
- { ICON_EYE_ANGRY_L[8], ICON_EYE_ANGRY_R[8], 50 },
- { ICON_EYE_ANGRY_L[9], ICON_EYE_ANGRY_R[9], 50 },
- { ICON_EYE_ANGRY_L[10], ICON_EYE_ANGRY_R[10], 500 }
- };
- // Создаём анимацию «Грусть»
- AnimationFrame animationSad[] = {
- { ICON_EYE_SAD_L[0], ICON_EYE_SAD_R[0], 500 },
- { ICON_EYE_SAD_L[1], ICON_EYE_SAD_R[1], 50 },
- { ICON_EYE_SAD_L[2], ICON_EYE_SAD_R[2], 50 },
- { ICON_EYE_SAD_L[3], ICON_EYE_SAD_R[3], 50 },
- { ICON_EYE_SAD_L[4], ICON_EYE_SAD_R[4], 50 },
- { ICON_EYE_SAD_L[5], ICON_EYE_SAD_R[5], 3000 },
- { ICON_EYE_SAD_L[6], ICON_EYE_SAD_R[6], 50 },
- { ICON_EYE_SAD_L[7], ICON_EYE_SAD_R[7], 50 },
- { ICON_EYE_SAD_L[8], ICON_EYE_SAD_R[8], 50 },
- { ICON_EYE_SAD_L[9], ICON_EYE_SAD_R[9], 50 },
- { ICON_EYE_SAD_L[10], ICON_EYE_SAD_R[10], 500 }
- };
- // Создаём анимацию «Радость»
- AnimationFrame animationHappy[] = {
- { ICON_EYE_HAPPY[0], ICON_EYE_HAPPY[0], 500 },
- { ICON_EYE_HAPPY[1], ICON_EYE_HAPPY[1], 40 },
- { ICON_EYE_HAPPY[2], ICON_EYE_HAPPY[2], 40 },
- { ICON_EYE_HAPPY[3], ICON_EYE_HAPPY[3], 40 },
- { ICON_EYE_HAPPY[4], ICON_EYE_HAPPY[4], 40 },
- { ICON_EYE_HAPPY[5], ICON_EYE_HAPPY[5], 2000 },
- { ICON_EYE_HAPPY[6], ICON_EYE_HAPPY[6], 40 },
- { ICON_EYE_HAPPY[7], ICON_EYE_HAPPY[7], 40 },
- { ICON_EYE_HAPPY[8], ICON_EYE_HAPPY[8], 40 },
- { ICON_EYE_HAPPY[9], ICON_EYE_HAPPY[9], 40 },
- { ICON_EYE_HAPPY[10], ICON_EYE_HAPPY[10], 500 }
- };
- // Создаём анимацию «Удивление»
- AnimationFrame animationAmazed[] = {
- { ICON_EYE_AMAZED[0], ICON_EYE_AMAZED[0], 500 },
- { ICON_EYE_AMAZED[1], ICON_EYE_AMAZED[1], 100 },
- { ICON_EYE_AMAZED[2], ICON_EYE_AMAZED[2], 2000 },
- { ICON_EYE_AMAZED[3], ICON_EYE_AMAZED[3], 100 },
- { ICON_EYE_AMAZED[4], ICON_EYE_AMAZED[4], 500 }
- };
- // Создаём анимацию «Любовь»
- AnimationFrame animationLove[] = {
- { ICON_EYE_LOVE[0], ICON_EYE_LOVE[0], 1000 },
- { ICON_EYE_LOVE[1], ICON_EYE_LOVE[1], 300 },
- { ICON_EYE_LOVE[0], ICON_EYE_LOVE[0], 1000 },
- { ICON_EYE_LOVE[1], ICON_EYE_LOVE[1], 300 },
- { ICON_EYE_LOVE[0], ICON_EYE_LOVE[0], 1000 },
- { ICON_EYE_LOVE[1], ICON_EYE_LOVE[1], 300 },
- { ICON_EYE_LOVE[0], ICON_EYE_LOVE[0], 1000 },
- { ICON_EYE_LOVE[1], ICON_EYE_LOVE[1], 300 },
- };
- // Создаём анимацию «Сон»
- AnimationFrame animationSleep[] = {
- { ICON_EYE_SLEEP[0], ICON_EYE_SLEEP[0], 750 },
- { ICON_EYE_SLEEP[1], ICON_EYE_SLEEP[1], 750 },
- { ICON_EYE_SLEEP[0], ICON_EYE_SLEEP[0], 750 },
- { ICON_EYE_SLEEP[1], ICON_EYE_SLEEP[1], 750 },
- { ICON_EYE_SLEEP[0], ICON_EYE_SLEEP[0], 750 },
- { ICON_EYE_SLEEP[1], ICON_EYE_SLEEP[1], 750 },
- { ICON_EYE_SLEEP[0], ICON_EYE_SLEEP[0], 750 },
- { ICON_EYE_SLEEP[1], ICON_EYE_SLEEP[1], 750 }
- };
- // Вычисляем количество кадров в анимации «Моргание»
- constexpr uint8_t COUNT_FRAMES_BLINK = sizeof(animationBlink) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Злость»
- constexpr uint8_t COUNT_FRAMES_ANGRY = sizeof(animationAngry) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Грусть»
- constexpr uint8_t COUNT_FRAMES_SAD = sizeof(animationSad) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Радость»
- constexpr uint8_t COUNT_FRAMES_HAPPY = sizeof(animationHappy) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Удивление»
- constexpr uint8_t COUNT_FRAMES_AMAZED = sizeof(animationAmazed) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Любовь»
- constexpr uint8_t COUNT_FRAMES_LOVE = sizeof(animationLove) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Сон»
- constexpr uint8_t COUNT_FRAMES_SLEEP = sizeof(animationSleep) / sizeof(AnimationFrame);
- // Создаём константу для хранения общего количества повторений эмоции
- constexpr int COUNT_REPEAT_EMOTION = 3;
- // Создаём переменную для хранения текущего счётчика количества повторений эмоции
- int countRepeatEmotion;
- // Создаём переменную для хранения счётчика текущего кадра
- int indexFrame;
- // Создаём переменную для хранения количества кадров
- int countFrames;
- // Создаём переменную для хранения флага последнего кадра
- bool lastFrame;
- void setup() {
- // Инициализируем матрицы
- matrixL.begin();
- matrixR.begin();
- // Очищаем матрицы
- matrixL.clear();
- matrixR.clear();
- // Настраиваем пин с пищалкой в режим выхода
- pinMode(BUZZER_PIN, OUTPUT);
- // Сбрасываем все настройки переменных по умолчанию
- resetState();
- // Устанавливаем таймер в режим остановки после срабатывания
- timer.setTimerMode();
- // Передаём случайное число с пина A1
- // для последующей генерации случайных чисел
- randomSeed(analogRead(A1));
- // Устанавливаем анимацию «Моргание»
- setEmotion(EMOTION_BLINK);
- }
- void loop() {
- // Переходим в функцию обработки эмоций
- emotionHandler();
- }
- // Функция обработки эмоций
- void emotionHandler() {
- // Вызываем функцию обновление анимации
- updateEmotion();
- // Разрешаем играть выбранный трек
- anyrtttl::nonblocking::play();
- }
- // Функция установки текущей эмоции
- void setEmotion(Emotion emotionNow) {
- // Обновляем полученную эмоцию
- emotion = emotionNow;
- // Проверяем состояние текущей эмоции
- switch (emotion) {
- // Эмоция «Моргание»
- case EMOTION_BLINK:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Моргание»
- animationFrame = animationBlink;
- countFrames = COUNT_FRAMES_BLINK;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodyBlink);
- break;
- // Эмоция «Злость»
- case EMOTION_ANGRY:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Злость»
- animationFrame = animationAngry;
- countFrames = COUNT_FRAMES_ANGRY;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodyAngry);
- break;
- // Эмоция «Грусть»
- case EMOTION_SAD:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Грусть»
- animationFrame = animationSad;
- countFrames = COUNT_FRAMES_SAD;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodySad);
- break;
- // Эмоция «Радость»
- case EMOTION_HAPPY:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Радость»
- animationFrame = animationHappy;
- countFrames = COUNT_FRAMES_HAPPY;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodyHappy);
- break;
- // Эмоция «Удивление»
- case EMOTION_AMAZED:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Удивление»
- animationFrame = animationAmazed;
- countFrames = COUNT_FRAMES_AMAZED;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodyAmazed);
- break;
- // Эмоция «Любовь»
- case EMOTION_LOVE:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Любовь»
- animationFrame = animationLove;
- countFrames = COUNT_FRAMES_LOVE;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodyLove);
- break;
- // Эмоция «Сон»
- case EMOTION_SLEEP:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Сон»
- animationFrame = animationSleep;
- countFrames = COUNT_FRAMES_SLEEP;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodySleep);
- break;
- }
- // Устанавливаем в таймер значение счетчика 0
- timer.setTime(0);
- // Запускаем таймер
- timer.start();
- }
- // Функция переключения на следующую эмоцию
- // Для активации смены эмоции, необходимо вызвать функцию установки эмоции setEmotion()
- void nextEmotion() {
- if (emotion == EMOTION_BLINK) {
- emotion = EMOTION_ANGRY;
- } else if (emotion == EMOTION_ANGRY) {
- emotion = EMOTION_SAD;
- } else if (emotion == EMOTION_SAD) {
- emotion = EMOTION_HAPPY;
- } else if (emotion == EMOTION_HAPPY) {
- emotion = EMOTION_AMAZED;
- } else if (emotion == EMOTION_AMAZED) {
- emotion = EMOTION_LOVE;
- } else if (emotion == EMOTION_LOVE) {
- emotion = EMOTION_SLEEP;
- } else if (emotion == EMOTION_SLEEP) {
- emotion = EMOTION_BLINK;
- }
- }
- // Функция выбора случайной эмоции
- // Для активации смены эмоции, необходимо вызвать функцию установки эмоции setEmotion()
- void randomEmotion() {
- emotion = random(0, 8);
- if (emotion == 0) {
- emotion = EMOTION_BLINK;
- } else if (emotion == 1) {
- emotion = EMOTION_ANGRY;
- } else if (emotion == 2) {
- emotion = EMOTION_SAD;
- } else if (emotion == 3) {
- emotion = EMOTION_HAPPY;
- } else if (emotion == 4) {
- emotion = EMOTION_AMAZED;
- } else if (emotion == 5) {
- emotion = EMOTION_LOVE;
- } else if (emotion == 6) {
- emotion = EMOTION_SLEEP;
- } else if (emotion == 7) {
- emotion = EMOTION_BLINK;
- }
- }
- // Функция обновления эмоции
- void updateEmotion() {
- // Если таймер досчитал до конца
- if (timer.tick()) {
- // Если флаг последнего кадра в состоянии «не активен»
- if (lastFrame == false) {
- // Отображаем текущий кадр анимации
- matrixL.drawBitmapF(animationFrame[indexFrame].iconEyeL);
- matrixR.drawBitmapF(animationFrame[indexFrame].iconEyeR);
- // Устанавливаем в таймер значение счетчика задержки текущего кадра анимации
- timer.setTime(animationFrame[indexFrame].timeFrame);
- // Запускаем таймер
- timer.start();
- // Если текущий кадр не последний в анимации
- if (indexFrame < countFrames - 1) {
- // Переходим на следующий кадр
- indexFrame++;
- } else {
- // Устанавливаем флаг последнего кадра в состояние «активен»
- lastFrame = true;
- }
- } else {
- // Останавливаем таймер
- timer.stop();
- // Проверяем сколько раз повторялась текущая анимация
- if (countRepeatEmotion < COUNT_REPEAT_EMOTION - 1) {
- // Увеличиваем счётчик повторения текущей анимации
- countRepeatEmotion++;
- } else {
- // Вызываем функцию переключение на следующую эмоцию
- nextEmotion();
- // Обнуляем счётчик повторения текущей анимации
- countRepeatEmotion = 0;
- }
- // Устанавливаем текущую анимацию
- setEmotion(emotion);
- // Устанавливаем флаг последнего кадра в состояние «не активен»
- lastFrame = false;
- // Обнуляем счётчик кадров
- indexFrame = 0;
- }
- }
- }
- // Функция сброса всех настроек переменных по умолчанию
- void resetState() {
- // Обнуляем переменную для хранения количества повторений эмоции
- countRepeatEmotion = 0;
- // Обнуляем счётчик кадра
- indexFrame = 0;
- // Устанавливаем флаг последнего кадра в состояние «не активен»
- lastFrame = false;
- }
№5. Обзор влево-вправо
- HeadLeftRight.ino
- // Подключаем библиотеку для работы с сервоприводом
- #include <Servo.h>
- // Создаём объект сервопривода
- Servo servoYaw;
- // Даём понятное имя пину A3 с сервоприводом
- constexpr uint8_t SERVO_YAW_PIN = A3;
- // Задаём максимально доступные углы поворота сервопривода головы влево-вправо
- constexpr uint8_t MAX_ANGLE_YAW_R = 0;
- constexpr uint8_t MAX_ANGLE_YAW_L = 180;
- // Вычисляем средний угол поворота сервопривода головы влево-вправо
- constexpr uint8_t MID_ANGLE_YAW = (MAX_ANGLE_YAW_R + MAX_ANGLE_YAW_L) / 2;
- // Создаём константу для хранения паузы между поворотом вала сервопривода
- constexpr uint8_t DELAY_SWEEP_SERVO_YAW = 20;
- void setup() {
- // Подключаем сервомотор
- servoYaw.attach(SERVO_YAW_PIN);
- }
- void loop() {
- // Перебираем значения угла сервы от max слева до max справа
- for (int pos = MAX_ANGLE_YAW_R; pos <= MAX_ANGLE_YAW_L; pos++) {
- // Отправляем текущий угол на сервопривод
- servoYaw.write(pos);
- // Выжидаем паузу
- delay(DELAY_SWEEP_SERVO_YAW);
- }
- // Перебираем значения угла сервы от max справа до max слева
- for (int pos = MAX_ANGLE_YAW_L; pos >= MAX_ANGLE_YAW_R; pos--) {
- // Отправляем текущий угол на сервопривод
- servoYaw.write(pos);
- // Выжидаем паузу
- delay(DELAY_SWEEP_SERVO_YAW);
- }
- }
№6. Обзор вверх-вниз
- HeadUpDown.ino
- // Подключаем библиотеку для работы с сервоприводом
- #include <Servo.h>
- // Создаём объект сервопривода
- Servo servoPitch;
- // Даём понятное имя пину A0 с сервоприводом
- constexpr uint8_t SERVO_PITCH_PIN = A0;
- // Задаём максимально доступные углы поворота сервопривода головы вверх-вниз
- constexpr uint8_t MAX_ANGLE_PITCH_DOWN = 60;
- constexpr uint8_t MAX_ANGLE_PITCH_UP = 120;
- // Вычисляем средний угол поворота сервопривода головы вверх-вниз
- constexpr uint8_t MID_ANGLE_PITCH = (MAX_ANGLE_PITCH_DOWN + MAX_ANGLE_PITCH_UP) / 2;
- // Создаём константу для хранения паузы между поворотом вала сервопривода
- constexpr uint8_t DELAY_SWEEP_SERVO_PITCH = 20;
- void setup() {
- // Подключаем сервомотор
- servoPitch.attach(SERVO_PITCH_PIN);
- }
- void loop() {
- // Перебираем значения угла сервы от max вниз до max вверх
- for (int pos = MAX_ANGLE_PITCH_DOWN; pos <= MAX_ANGLE_PITCH_UP; pos++) {
- // Отправляем текущий угол на сервопривод
- servoPitch.write(pos);
- // Выжидаем паузу
- delay(DELAY_SWEEP_SERVO_PITCH);
- }
- // Перебираем значения угла сервы от max вверх до max вниз
- for (int pos = MAX_ANGLE_PITCH_UP; pos >= MAX_ANGLE_PITCH_DOWN; pos--) {
- // Отправляем текущий угол на сервопривод
- servoPitch.write(pos);
- // Выжидаем паузу
- delay(DELAY_SWEEP_SERVO_PITCH);
- }
- }
№7. Консольный ИК-приёмник
Проверка пульта
Протестируй свой пульт и сравни коды кнопок в консоли с целевыми кодами из таблицы ниже.
- Если полученные коды совпадают, можно смело пользоваться нашими скетчами
.ino
без изменений. - Если коды не совпали, значит тебе попался пульт другой модификации. Ничего страшного!
Запиши фактические коды кнопок в таблицу. Они пригодятся тебе для подстановки в последующие проекты с ИК-пультом и приёмником.
Имя кнопки | Код кнопки | |
---|---|---|
Целевой | По факту | |
Power | 0x0B | |
⊖ | 0x07 | |
⊕ | 0x1B | |
🔴 | 0x00 | |
🟢 | 0x03 | |
🔵 | 0x01 | |
x | 0x09 | |
▢ | 0x05 | |
△ | 0x02 | |
↖ | 0x0A | |
↑ | 0x06 | |
↗ | 0x1A | |
← | 0x08 | |
▶ | 0x1C | |
→ | 0x19 | |
↙ | 0x18 | |
↓ | 0x1D | |
↘ | 0x04 | |
X | 0x0C | |
Y | 0x0D | |
Z | 0x0E |
- IrConsole.ino
- // Подключаем библиотеку для работы с ИК-приёмником
- #include <IRremote.hpp>
- // Даём понятное имя пину 2 с ИК-приёмником
- constexpr uint8_t IR_RECEIVE_PIN = 2;
- void setup() {
- // Открываем монитор Serial-порта
- Serial.begin(9600);
- // Инициализируем ИК-приёмник
- IrReceiver.begin(IR_RECEIVE_PIN);
- }
- void loop() {
- // Если пришёл новый сигнал на ИК-приёмник, декодируем его
- if (IrReceiver.decode()) {
- // Игнорируем повторное нажатие кнопки
- if ((IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT)) {
- // Разрешаем обрабатывать следующий сигнал
- IrReceiver.resume();
- // Выходим из всего цикла
- return;
- }
- // Создаём переменную и присваиваем ей декодируемый код кнопки
- uint32_t code = IrReceiver.decodedIRData.command;
- // Печатем код кнопки в консоль с форматированием
- printCode(code);
- // Разрешаем обрабатывать следующий сигнал
- IrReceiver.resume();
- }
- }
- // Функция печати кода кнопки в консоль с форматированием
- void printCode(uint32_t code) {
- Serial.print("0x");
- if (code < 15) {
- Serial.print("0");
- }
- Serial.println(code, HEX);
- }
№8. Звёздный бот
- StarBot.ino
- // Подключаем библиотеку для работы с мелодиями в формате RTTTL
- #include <anyrtttl.h>
- // Подключаем библиотеку для работы с ИК-приёмником
- #include <IRremote.hpp>
- // Подключаем библиотеку для работы со светодиодными матрицами
- #include <TroykaLedMatrix.h>
- // Даём понятное имя пину 3 с пищалкой
- constexpr uint8_t BUZZER_PIN = 3;
- // Даём понятное имя пину 2 с ИК-приёмником
- constexpr uint8_t IR_RECEIVE_PIN = 2;
- // Создаём объект матрицы левого глаза
- // на шине I²C с адресом 0x60 (указан по умолчанию)
- TroykaLedMatrix matrixL;
- // Создаём объект матрицы правого глаза
- // на шине I²C с адресом 0x63
- TroykaLedMatrix matrixR(0x63);
- // Создаём константу для хранения базовой частоты
- constexpr int FREQUENCY = 2000;
- // Создаём константы для хранения минимальной и максимальной частоты
- constexpr int MIN_FREQUENCY = FREQUENCY - (0.25 * FREQUENCY);
- constexpr int MAX_FREQUENCY = FREQUENCY + (0.25 * FREQUENCY);
- // Создаём иконку «Взгляд прямо» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- // Эмоции рисуем в редакторе изображений для LED-матрицы
- // https://amperka.github.io/led-matrix-editor/
- constexpr uint8_t ICON_EYE_STRAIGHT[] PROGMEM {
- 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e
- };
- // Создаём иконку «Глаза выключены» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- constexpr uint8_t ICON_EYE_OFF[] PROGMEM {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- void setup() {
- // Инициализируем матрицы
- matrixL.begin();
- matrixR.begin();
- // Очищаем матрицы
- matrixL.clear();
- matrixR.clear();
- // Настраиваем пин с пищалкой в режим выхода
- pinMode(BUZZER_PIN, OUTPUT);
- // Инициализируем ИК-приёмник
- IrReceiver.begin(IR_RECEIVE_PIN);
- // Передаём случайное число с пина A1
- // для последующей генерации случайных чисел
- randomSeed(analogRead(A1));
- }
- void loop() {
- // Переходим в функцию обработки ИК-приёмника
- remoteHandler();
- }
- // Функция отображения иконки на матрицах
- void drawIcon(uint8_t* iconEyeL, uint8_t* iconEyeR) {
- matrixL.drawBitmapF(iconEyeL);
- matrixR.drawBitmapF(iconEyeR);
- }
- // Функция обработки ИК-приёмника
- void remoteHandler() {
- // Если пришёл новый сигнал на ИК-приёмник, декодируем его
- if (IrReceiver.decode()) {
- // Создаём переменную и присваиваем ей декодируемый код кнопки
- uint32_t code = IrReceiver.decodedIRData.command;
- // Если код кнопки равен 0, пришёл шум и игнорируем его
- if (code == 0x00) {
- // Разрешаем обрабатывать следующий сигнал
- IrReceiver.resume();
- // Выходим из функции
- return;
- }
- // Отключаем ИК-приёмник
- IrReceiver.stop();
- // Вызываем функцию генератора последовательных длинных семплов
- toneLongSamples();
- // Вызываем функцию генератора непоследовательных коротких семплов
- toneShortSamples();
- // Запускаем ИК-приёмник
- IrReceiver.start();
- // Разрешаем обрабатывать команды с ИК-приёмника
- IrReceiver.resume();
- }
- }
- // Функция генерации последовательных длинных семплов
- void toneLongSamples() {
- // Генерируем случайное количество семплов от 1 до 6
- int countSamples = random(1, 7);
- // Перебираем нумерацию семплов в цикле
- for (int i = 0; i < countSamples; i++) {
- // Генерируем случайное число: true или false
- bool typeSamples = random(0, 2);
- // Если тип семпла true
- if (typeSamples) {
- // Вызываем функцию генерации тона toneSlowDownFastUp:
- // Сначала медленный убывающий тон со случайными задержками
- // Затем быстрый возрастающий тон со случайными задержками
- toneSlowDownFastUp();
- } else {
- // Если тип семпла false
- // Вызываем функцию генерации тона toneSlowUpFastDown:
- // Сначала медленный возрастающий тон со случайными задержками
- // Затем быстрый убывающий тон со случайными задержками
- toneSlowUpFastDown();
- }
- }
- }
- // Функция генерации непоследовательных коротких семплов
- void toneShortSamples() {
- // Генерируем случайное количество семплов от 3 до 9
- int countSamples = random(3, 10);
- // Генерируем случайную частоту на базе FREQUENCY
- int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
- for (int i = 0; i <= countSamples; i++) {
- // Активируем глаза
- drawIcon(ICON_EYE_STRAIGHT, ICON_EYE_STRAIGHT);
- // Генерируем случайный интервал на базе FREQUENCY
- int range = random(-FREQUENCY, FREQUENCY);
- tone(BUZZER_PIN, frequency + range);
- // Выполняем случайную задержку от 70 до 170 мс
- delay(random(70, 170));
- // Деактивируем глаза
- drawIcon(ICON_EYE_OFF, ICON_EYE_OFF);
- // Выключаем звук
- noTone(BUZZER_PIN);
- // Выполняем случайную задержку от 0 до 30 мс
- delay(random(0, 30));
- }
- }
- // Функция генерации звуковой последовательности
- // Сначала медленный убывающий тон со случайными задержками
- // Затем быстрый возрастающий тон со случайными задержками
- void toneSlowDownFastUp() {
- // Генерируем случайную частоту на базе FREQUENCY
- int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
- // Активируем глаза
- drawIcon(ICON_EYE_STRAIGHT, ICON_EYE_STRAIGHT);
- // Генерируем медленный понижающий тон со случайными задержками
- for (int range = 0; range <= random(100, 1000); range++) {
- tone(BUZZER_PIN, (range * 2));
- delayMicroseconds(random(0, 1000));
- }
- // Деактивируем глаза
- drawIcon(ICON_EYE_OFF, ICON_EYE_OFF);
- // Генерируем быстрый повышающий тон со случайными задержками
- for (int range = 0; range <= random(100, 1000); range++) {
- tone(BUZZER_PIN, frequency + (range * 10));
- delayMicroseconds(random(0, 1000));
- }
- }
- // Функция генерации звуковой последовательности
- // Сначала медленный возрастающий тон со случайными задержками
- // Затем быстрый убывающий тон со случайными задержками
- void toneSlowUpFastDown() {
- // Генерируем случайную частоту на базе FREQUENCY
- int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
- // Активируем глаза
- drawIcon(ICON_EYE_STRAIGHT, ICON_EYE_STRAIGHT);
- // Генерируем медленный возрастающий тон со случайными задержками
- for (int range = 0; range <= random(100, 1000); range++) {
- tone(BUZZER_PIN, (range * 2));
- delayMicroseconds(random(0, 1000));
- }
- // Деактивируем глаза
- drawIcon(ICON_EYE_OFF, ICON_EYE_OFF);
- // Генерируем быстрый понижающий тон со случайными задержками
- for (int range = 0; range <= random(100, 1000); range++) {
- tone(BUZZER_PIN, (range * 10));
- delayMicroseconds(random(0, 1000));
- }
- }
№9. Эмо-бот
Изменение кода кнопок пульта
Вернись к шпаргалке с таблицей из эксперимента №7 «Консольный ИК-приёмник» и подставь фактические коды кнопок твоего пульта в строках 62
–70
, когда откроешь скетч IrEmotions.ino
в Arduino IDE.
enum Emotion { EMOTION_BLINK = 0x1C, EMOTION_ANGRY = 0x02, EMOTION_SAD = 0xC, EMOTION_HAPPY = 0x0D, EMOTION_AMAZED = 0x05, EMOTION_LOVE = 0x09, EMOTION_SLEEP = 0x0E, } emotion;
- IrEmotions.ino
- // Подключаем библиотеку для работы с мелодиями в формате RTTTL
- #include <anyrtttl.h>
- // Подключаем библиотеку для работы с ИК-приёмником
- #include <IRremote.hpp>
- // Подключаем библиотеку для работы с таймером millis
- #include <TimerMs.h>
- // Подключаем библиотеку для работы со светодиодными матрицами
- #include <TroykaLedMatrix.h>
- // Даём понятное имя пину 3 с пищалкой
- constexpr uint8_t BUZZER_PIN = 3;
- // Даём понятное имя пину 2 с ИК-приёмником
- constexpr uint8_t IR_RECEIVE_PIN = 2;
- // Создаём объект для работы с таймером
- TimerMs timer;
- // Создаём объект матрицы левого глаза
- // на шине I²C с адресом 0x60 (указан по умолчанию)
- TroykaLedMatrix matrixL;
- // Создаём объект матрицы правого глаза
- // на шине I²C с адресом 0x63
- TroykaLedMatrix matrixR(0x63);
- // Создаём массив данных мелодии «Моргание» в формате RTTTL
- constexpr uint8_t melodyBlink[] PROGMEM = "Blink:d=4,o=4,b=120:"
- "16e,16p,16g,16p,16e,16p,16g,16p,";
- // Создаём массив данных мелодии «Злость» в формате RTTTL
- constexpr uint8_t melodyAngry[] PROGMEM = "Angry:d=4,o=4,b=200:"
- "16g,16g,16f#,16f#,16e,16e,16d#,16d#,"
- "16c,16c,16b4,16b4,16a4,16a4,16g4,16g4";
- // Создаём массив данных мелодии «Грусть» в формате RTTTL
- constexpr uint8_t melodySad[] PROGMEM = "Sad:d=4,o=4,b=25:"
- "16g,16a#,16d,16f,"
- "16d,16c,16a#";
- constexpr uint8_t melodyHappy[] PROGMEM = "Happy:d=4,o=4,b=140:"
- "8c4,8e4,8g4,8c4,8e4,8g4,8c4,8e4"
- "8g4,8c4,8e4,8g4";
- // Создаём массив данных мелодии «Удивление» в формате RTTTL
- constexpr uint8_t melodyAmazed[] PROGMEM = "Amazed:d=4,o=4,b=180:"
- "16c,16d,16e,16f,16g,16a,16b,16c,"
- "16b,16a,16g,16f,16e,16d,16c,16d";
- // Создаём массив данных мелодии «Любовь» в формате RTTTL
- constexpr uint8_t melodyLove[] PROGMEM = "Love:d=4,o=4,b=100:"
- "8g,8p,8g,8p,8a,8p,8g,8p,"
- "8g,8p,8g,8p,8f,8e,8d";
- // Создаём массив данных мелодии «Сонливость» в формате RTTTL
- constexpr uint8_t melodySleep[] PROGMEM = "Sleep:d=4,o=4,b=45:"
- "8c,8c,8d,8e,8d,8c,8d,8e";
- // Создаём перечисление эмоций с соответствующей переменной
- enum Emotion {
- EMOTION_BLINK = 0x1C,
- EMOTION_ANGRY = 0x02,
- EMOTION_SAD = 0xC,
- EMOTION_HAPPY = 0x0D,
- EMOTION_AMAZED = 0x05,
- EMOTION_LOVE = 0x09,
- EMOTION_SLEEP = 0x0E,
- } emotion;
- // Создаём структуру анимации
- struct AnimationFrame {
- uint8_t* iconEyeL;
- uint8_t* iconEyeR;
- int timeFrame;
- };
- // Создаём объект структуры анимации
- AnimationFrame* animationFrame;
- // Создаём иконку «Взгляд прямо» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- // Эмоции рисуем в редакторе изображений для LED-матрицы
- // https://amperka.github.io/led-matrix-editor/
- constexpr uint8_t ICON_EYE_STRAIGHT[] PROGMEM {
- 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e
- };
- // Создаём иконку «Глаза выключены» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- constexpr uint8_t ICON_EYE_OFF[] PROGMEM {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- // Создаём массив иконок анимации «Моргание» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_BLINK[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x00, 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x7e },
- { 0x00, 0x00, 0x7e, 0x81, 0x99, 0x99, 0x81, 0x7e },
- { 0x00, 0x00, 0x00, 0x7e, 0x99, 0x99, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x7e, 0x99, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x7e, 0x99, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x7e, 0x99, 0x99, 0x7e, 0x00 },
- { 0x00, 0x00, 0x7e, 0x81, 0x99, 0x99, 0x81, 0x7e },
- { 0x00, 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Злость»
- // в шестнадцатеричной системе HEX для левого глаза
- constexpr uint8_t ICON_EYE_ANGRY_L[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x78, 0x84, 0x82, 0x9a, 0x9a, 0x82, 0x82, 0x7c },
- { 0x70, 0x88, 0x84, 0x9a, 0x9a, 0x82, 0x82, 0x7c },
- { 0x60, 0x90, 0x88, 0x9c, 0x9a, 0x82, 0x82, 0x7c },
- { 0x40, 0xa0, 0x90, 0x88, 0xb4, 0xb2, 0x82, 0x7c },
- { 0x80, 0xc0, 0xa0, 0x90, 0xa8, 0xb4, 0x82, 0x7c },
- { 0x40, 0xa0, 0x90, 0x88, 0xb4, 0xb2, 0x82, 0x7c },
- { 0x60, 0x90, 0x88, 0x9c, 0x9a, 0x82, 0x82, 0x7c },
- { 0x70, 0x88, 0x84, 0x9a, 0x9a, 0x82, 0x82, 0x7c },
- { 0x78, 0x84, 0x82, 0x9a, 0x9a, 0x82, 0x82, 0x7c },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Злость»
- // в шестнадцатеричной системе HEX для правого глаза
- constexpr uint8_t ICON_EYE_ANGRY_R[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x1e, 0x21, 0x41, 0x59, 0x59, 0x41, 0x41, 0x3e },
- { 0x0e, 0x11, 0x21, 0x59, 0x59, 0x41, 0x41, 0x3e },
- { 0x06, 0x09, 0x11, 0x39, 0x59, 0x41, 0x41, 0x3e },
- { 0x02, 0x05, 0x09, 0x11, 0x2d, 0x4d, 0x41, 0x3e },
- { 0x01, 0x03, 0x05, 0x09, 0x15, 0x2d, 0x41, 0x3e },
- { 0x02, 0x05, 0x09, 0x11, 0x2d, 0x4d, 0x41, 0x3e },
- { 0x06, 0x09, 0x11, 0x39, 0x59, 0x41, 0x41, 0x3e },
- { 0x0e, 0x11, 0x21, 0x59, 0x59, 0x41, 0x41, 0x3e },
- { 0x1e, 0x21, 0x41, 0x59, 0x59, 0x41, 0x41, 0x3e }
- };
- // Создаём массив иконок анимации «Грусть»
- // в шестнадцатеричной системе HEX для левого глаза
- constexpr uint8_t ICON_EYE_SAD_L[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x3e, 0x41, 0x81, 0x99, 0x99, 0x81, 0x82, 0x7c },
- { 0x1e, 0x21, 0x41, 0x99, 0x99, 0x81, 0x82, 0x7c },
- { 0x0e, 0x11, 0x21, 0x41, 0x8d, 0x8d, 0x82, 0x7c },
- { 0x0e, 0x11, 0x21, 0x41, 0x4d, 0x4d, 0x42, 0x3c },
- { 0x06, 0x09, 0x11, 0x21, 0x4d, 0x4d, 0x42, 0x3c },
- { 0x0e, 0x11, 0x21, 0x41, 0x4d, 0x4d, 0x42, 0x3c },
- { 0x0e, 0x11, 0x21, 0x41, 0x8d, 0x8d, 0x82, 0x7c },
- { 0x1e, 0x21, 0x41, 0x99, 0x99, 0x81, 0x82, 0x7c },
- { 0x3e, 0x41, 0x81, 0x99, 0x99, 0x81, 0x82, 0x7c },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Грусть»
- // в шестнадцатеричной системе HEX для правого глаза
- constexpr uint8_t ICON_EYE_SAD_R[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7c, 0x82, 0x81, 0x99, 0x99, 0x81, 0x41, 0x3e },
- { 0x78, 0x84, 0x82, 0x99, 0x99, 0x81, 0x41, 0x3e },
- { 0x70, 0x88, 0x84, 0x82, 0xb1, 0xb1, 0x41, 0x3e },
- { 0x70, 0x88, 0x84, 0x82, 0xb2, 0xb2, 0x42, 0x3c },
- { 0x60, 0x90, 0x88, 0x84, 0xb2, 0xb2, 0x42, 0x3c },
- { 0x70, 0x88, 0x84, 0x82, 0xb2, 0xb2, 0x42, 0x3c },
- { 0x70, 0x88, 0x84, 0x82, 0xb1, 0xb1, 0x41, 0x3e },
- { 0x78, 0x84, 0x82, 0x99, 0x99, 0x81, 0x41, 0x3e },
- { 0x7c, 0x82, 0x81, 0x99, 0x99, 0x81, 0x41, 0x3e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Радость» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_HAPPY[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x00, 0x7e, 0x81, 0x99, 0x99, 0x81, 0x7e, 0x00 },
- { 0x00, 0x7e, 0x81, 0x99, 0x99, 0xff, 0x00, 0x00 },
- { 0x00, 0x7e, 0xdb, 0x99, 0xff, 0x81, 0x00, 0x00 },
- { 0x00, 0x3c, 0x5a, 0xff, 0xc3, 0x81, 0x00, 0x00 },
- { 0x00, 0x3c, 0x7e, 0xc3, 0xc3, 0x81, 0x00, 0x00 },
- { 0x00, 0x3c, 0x5a, 0xff, 0xc3, 0x81, 0x00, 0x00 },
- { 0x00, 0x7e, 0xdb, 0x99, 0xff, 0x81, 0x00, 0x00 },
- { 0x00, 0x7e, 0x81, 0x99, 0x99, 0xff, 0x00, 0x00 },
- { 0x00, 0x7e, 0x81, 0x99, 0x99, 0x81, 0x7e, 0x00 },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Удивление» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_AMAZED[][8] PROGMEM {
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e },
- { 0x7e, 0x81, 0x99, 0xbd, 0xbd, 0x99, 0x81, 0x7e },
- { 0x7e, 0x81, 0xbd, 0xbd, 0xbd, 0xbd, 0x81, 0x7e },
- { 0x7e, 0x81, 0x99, 0xbd, 0xbd, 0x99, 0x81, 0x7e },
- { 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e }
- };
- // Создаём массив иконок анимации «Любовь» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_LOVE[][8] PROGMEM {
- { 0x66, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x18 },
- { 0x00, 0x00, 0x24, 0x7e, 0x7e, 0x3c, 0x18, 0x00 }
- };
- // Создаём массив иконок анимации Сон» в шестнадцатеричной системе HEX
- // Массив иконок для левого и правого глаза одинаковый
- constexpr uint8_t ICON_EYE_SLEEP[][8] PROGMEM {
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7e, 0x00 },
- { 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 0x7e, 0x00 }
- };
- // Создаём анимацию «Моргание»
- AnimationFrame animationBlink[] = {
- { ICON_EYE_BLINK[0], ICON_EYE_BLINK[0], 500 },
- { ICON_EYE_BLINK[1], ICON_EYE_BLINK[1], 25 },
- { ICON_EYE_BLINK[2], ICON_EYE_BLINK[2], 25 },
- { ICON_EYE_BLINK[3], ICON_EYE_BLINK[3], 25 },
- { ICON_EYE_BLINK[4], ICON_EYE_BLINK[4], 25 },
- { ICON_EYE_BLINK[5], ICON_EYE_BLINK[5], 25 },
- { ICON_EYE_BLINK[6], ICON_EYE_BLINK[6], 25 },
- { ICON_EYE_BLINK[7], ICON_EYE_BLINK[7], 25 },
- { ICON_EYE_BLINK[8], ICON_EYE_BLINK[8], 25 },
- { ICON_EYE_BLINK[9], ICON_EYE_BLINK[9], 25 },
- { ICON_EYE_BLINK[10], ICON_EYE_BLINK[10], 500 }
- };
- // Создаём анимацию «Злость»
- AnimationFrame animationAngry[] = {
- { ICON_EYE_ANGRY_L[0], ICON_EYE_ANGRY_R[0], 500 },
- { ICON_EYE_ANGRY_L[1], ICON_EYE_ANGRY_R[1], 50 },
- { ICON_EYE_ANGRY_L[2], ICON_EYE_ANGRY_R[2], 50 },
- { ICON_EYE_ANGRY_L[3], ICON_EYE_ANGRY_R[3], 50 },
- { ICON_EYE_ANGRY_L[4], ICON_EYE_ANGRY_R[4], 50 },
- { ICON_EYE_ANGRY_L[5], ICON_EYE_ANGRY_R[5], 2000 },
- { ICON_EYE_ANGRY_L[6], ICON_EYE_ANGRY_R[6], 50 },
- { ICON_EYE_ANGRY_L[7], ICON_EYE_ANGRY_R[7], 50 },
- { ICON_EYE_ANGRY_L[8], ICON_EYE_ANGRY_R[8], 50 },
- { ICON_EYE_ANGRY_L[9], ICON_EYE_ANGRY_R[9], 50 },
- { ICON_EYE_ANGRY_L[10], ICON_EYE_ANGRY_R[10], 500 }
- };
- // Создаём анимацию «Грусть»
- AnimationFrame animationSad[] = {
- { ICON_EYE_SAD_L[0], ICON_EYE_SAD_R[0], 500 },
- { ICON_EYE_SAD_L[1], ICON_EYE_SAD_R[1], 50 },
- { ICON_EYE_SAD_L[2], ICON_EYE_SAD_R[2], 50 },
- { ICON_EYE_SAD_L[3], ICON_EYE_SAD_R[3], 50 },
- { ICON_EYE_SAD_L[4], ICON_EYE_SAD_R[4], 50 },
- { ICON_EYE_SAD_L[5], ICON_EYE_SAD_R[5], 3000 },
- { ICON_EYE_SAD_L[6], ICON_EYE_SAD_R[6], 50 },
- { ICON_EYE_SAD_L[7], ICON_EYE_SAD_R[7], 50 },
- { ICON_EYE_SAD_L[8], ICON_EYE_SAD_R[8], 50 },
- { ICON_EYE_SAD_L[9], ICON_EYE_SAD_R[9], 50 },
- { ICON_EYE_SAD_L[10], ICON_EYE_SAD_R[10], 500 }
- };
- // Создаём анимацию «Радость»
- AnimationFrame animationHappy[] = {
- { ICON_EYE_HAPPY[0], ICON_EYE_HAPPY[0], 500 },
- { ICON_EYE_HAPPY[1], ICON_EYE_HAPPY[1], 40 },
- { ICON_EYE_HAPPY[2], ICON_EYE_HAPPY[2], 40 },
- { ICON_EYE_HAPPY[3], ICON_EYE_HAPPY[3], 40 },
- { ICON_EYE_HAPPY[4], ICON_EYE_HAPPY[4], 40 },
- { ICON_EYE_HAPPY[5], ICON_EYE_HAPPY[5], 2000 },
- { ICON_EYE_HAPPY[6], ICON_EYE_HAPPY[6], 40 },
- { ICON_EYE_HAPPY[7], ICON_EYE_HAPPY[7], 40 },
- { ICON_EYE_HAPPY[8], ICON_EYE_HAPPY[8], 40 },
- { ICON_EYE_HAPPY[9], ICON_EYE_HAPPY[9], 40 },
- { ICON_EYE_HAPPY[10], ICON_EYE_HAPPY[10], 500 }
- };
- // Создаём анимацию «Удивление»
- AnimationFrame animationAmazed[] = {
- { ICON_EYE_AMAZED[0], ICON_EYE_AMAZED[0], 500 },
- { ICON_EYE_AMAZED[1], ICON_EYE_AMAZED[1], 100 },
- { ICON_EYE_AMAZED[2], ICON_EYE_AMAZED[2], 2000 },
- { ICON_EYE_AMAZED[3], ICON_EYE_AMAZED[3], 100 },
- { ICON_EYE_AMAZED[4], ICON_EYE_AMAZED[4], 500 }
- };
- // Создаём анимацию «Любовь»
- AnimationFrame animationLove[] = {
- { ICON_EYE_LOVE[0], ICON_EYE_LOVE[0], 1000 },
- { ICON_EYE_LOVE[1], ICON_EYE_LOVE[1], 300 },
- { ICON_EYE_LOVE[0], ICON_EYE_LOVE[0], 1000 },
- { ICON_EYE_LOVE[1], ICON_EYE_LOVE[1], 300 },
- { ICON_EYE_LOVE[0], ICON_EYE_LOVE[0], 1000 },
- { ICON_EYE_LOVE[1], ICON_EYE_LOVE[1], 300 },
- { ICON_EYE_LOVE[0], ICON_EYE_LOVE[0], 1000 },
- { ICON_EYE_LOVE[1], ICON_EYE_LOVE[1], 300 },
- };
- // Создаём анимацию «Сон»
- AnimationFrame animationSleep[] = {
- { ICON_EYE_SLEEP[0], ICON_EYE_SLEEP[0], 750 },
- { ICON_EYE_SLEEP[1], ICON_EYE_SLEEP[1], 750 },
- { ICON_EYE_SLEEP[0], ICON_EYE_SLEEP[0], 750 },
- { ICON_EYE_SLEEP[1], ICON_EYE_SLEEP[1], 750 },
- { ICON_EYE_SLEEP[0], ICON_EYE_SLEEP[0], 750 },
- { ICON_EYE_SLEEP[1], ICON_EYE_SLEEP[1], 750 },
- { ICON_EYE_SLEEP[0], ICON_EYE_SLEEP[0], 750 },
- { ICON_EYE_SLEEP[1], ICON_EYE_SLEEP[1], 750 },
- };
- // Вычисляем количество кадров в анимации «Моргание»
- constexpr uint8_t COUNT_FRAMES_BLINK = sizeof(animationBlink) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Злость»
- constexpr uint8_t COUNT_FRAMES_ANGRY = sizeof(animationAngry) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Грусть»
- constexpr uint8_t COUNT_FRAMES_SAD = sizeof(animationSad) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Радость»
- constexpr uint8_t COUNT_FRAMES_HAPPY = sizeof(animationHappy) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Удивление»
- constexpr uint8_t COUNT_FRAMES_AMAZED = sizeof(animationAmazed) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Любовь»
- constexpr uint8_t COUNT_FRAMES_LOVE = sizeof(animationLove) / sizeof(AnimationFrame);
- // Вычисляем количество кадров в анимации «Сон»
- constexpr uint8_t COUNT_FRAMES_SLEEP = sizeof(animationSleep) / sizeof(AnimationFrame);
- // Создаём переменную для хранения счётчика текущего кадра
- int indexFrame;
- // Создаём переменную для хранения количества кадров
- int countFrames;
- // Создаём переменную для хранения флага последнего кадра
- bool lastFrame;
- void setup() {
- // Инициализируем матрицы
- matrixL.begin();
- matrixR.begin();
- // Очищаем матрицы
- matrixL.clear();
- matrixR.clear();
- // Инициализируем ИК-приёмник
- IrReceiver.begin(IR_RECEIVE_PIN);
- // Сбрасываем все настройки переменных по умолчанию
- resetState();
- // Устанавливаем таймер в режим остановки после срабатывания
- timer.setTimerMode();
- }
- void loop() {
- // Переходим в функцию обработки эмоций
- emotionHandler();
- // Переходим в функцию обработки ИК-приёмника
- remoteHandler();
- }
- // Функция отображения иконки на матрицах
- void drawIcon(uint8_t* iconEyeL, uint8_t* iconEyeR) {
- matrixL.drawBitmapF(iconEyeL);
- matrixR.drawBitmapF(iconEyeR);
- }
- // Функция обработки эмоций
- void emotionHandler() {
- // Вызываем функцию обновление анимации
- updateEmotion();
- // Разрешаем играть выбранный трек
- anyrtttl::nonblocking::play();
- }
- // Функция обработки ИК-приёмника
- void remoteHandler() {
- // Если пришёл новый сигнал на ИК-приёмник, декодируем его
- if (IrReceiver.decode()) {
- // Создаём переменную и присваиваем ей декодируемый код кнопки
- uint32_t code = IrReceiver.decodedIRData.command;
- // Проверяем код кнопки
- switch (code) {
- // Если нажата кнопка с кодом эмоции «Моргание»
- case EMOTION_BLINK:
- setEmotion(EMOTION_BLINK);
- break;
- // Если нажата кнопка с кодом эмоции «Злость»
- case EMOTION_ANGRY:
- // Отображаем анимацию «Злость»
- setEmotion(EMOTION_ANGRY);
- break;
- // Если нажата кнопка с кодом эмоции «Грусть»
- case EMOTION_SAD:
- // Отображаем анимацию «Грусть»
- setEmotion(EMOTION_SAD);
- break;
- // Если нажата кнопка с кодом эмоции «Радость»
- case EMOTION_HAPPY:
- // Отображаем анимацию «Радость»
- setEmotion(EMOTION_HAPPY);
- break;
- // Если нажата кнопка с кодом эмоции «Удивление
- case EMOTION_AMAZED:
- // Отображаем анимацию «Удивление»
- setEmotion(EMOTION_AMAZED);
- break;
- // Если нажата кнопка с кодом эмоции «Любовь»
- case EMOTION_LOVE:
- // Отображаем анимацию «Любовь»
- setEmotion(EMOTION_LOVE);
- break;
- // Если нажата кнопка с кодом эмоции «Сон»
- case EMOTION_SLEEP:
- // Отображаем анимацию «Сон»
- setEmotion(EMOTION_SLEEP);
- break;
- }
- // Разрешаем обрабатывать следующий сигнал
- IrReceiver.resume();
- }
- }
- // Функция установки текущей эмоции
- void setEmotion(Emotion emotionNow) {
- // Обновляем полученную эмоцию
- emotion = emotionNow;
- // Проверяем состояние текущей эмоции
- switch (emotion) {
- // Эмоция «Моргание»
- case EMOTION_BLINK:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Моргание»
- animationFrame = animationBlink;
- countFrames = COUNT_FRAMES_BLINK;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodyBlink);
- break;
- // Эмоция «Злость»
- case EMOTION_ANGRY:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Злость»
- animationFrame = animationAngry;
- countFrames = COUNT_FRAMES_ANGRY;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodyAngry);
- break;
- // Эмоция «Грусть»
- case EMOTION_SAD:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Грусть»
- animationFrame = animationSad;
- countFrames = COUNT_FRAMES_SAD;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodySad);
- break;
- // Эмоция «Радость»
- case EMOTION_HAPPY:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Радость»
- animationFrame = animationHappy;
- countFrames = COUNT_FRAMES_HAPPY;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodyHappy);
- break;
- // Эмоция «Удивление»
- case EMOTION_AMAZED:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Удивление»
- animationFrame = animationAmazed;
- countFrames = COUNT_FRAMES_AMAZED;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodyAmazed);
- break;
- // Эмоция «Любовь»
- case EMOTION_LOVE:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Любовь»
- animationFrame = animationLove;
- countFrames = COUNT_FRAMES_LOVE;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodyLove);
- break;
- // Эмоция «Сон»
- case EMOTION_SLEEP:
- // Устанавливаем анимацию, кол-во кадров и мелодию для эмоции «Сон»
- animationFrame = animationSleep;
- countFrames = COUNT_FRAMES_SLEEP;
- anyrtttl::nonblocking::begin_P(BUZZER_PIN, melodySleep);
- break;
- }
- // Отключаем ИК-приёмник
- IrReceiver.stop();
- // Устанавливаем в таймер значение счетчика 0
- timer.setTime(0);
- // Запускаем таймер
- timer.start();
- }
- // Функция обновления эмоции
- void updateEmotion() {
- // Если таймер досчитал до конца
- if (timer.tick()) {
- // Если флаг последнего кадра в состоянии «не активен»
- if (lastFrame == false) {
- // Отображаем текущий кадр анимации
- matrixL.drawBitmapF(animationFrame[indexFrame].iconEyeL);
- matrixR.drawBitmapF(animationFrame[indexFrame].iconEyeR);
- // Устанавливаем в таймер значение счетчика задержки текущего кадра анимации
- timer.setTime(animationFrame[indexFrame].timeFrame);
- // Запускаем таймер
- timer.start();
- // Если текущий кадр не последний в анимации
- if (indexFrame < countFrames - 1) {
- // Переходим на следующий кадр
- indexFrame++;
- } else {
- // Устанавливаем флаг последнего кадра в состояние «активен»
- lastFrame = true;
- }
- } else {
- // Останавливаем таймер
- timer.stop();
- // Запускаем ИК-приёмник
- IrReceiver.start();
- // Сбрасываем все настройки по умолчанию
- resetState();
- }
- }
- }
- // Функция сброса всех настроек по умолчанию
- void resetState() {
- // Обнуляем счётчик кадра
- indexFrame = 0;
- // Устанавливаем флаг последнего кадра в состояние «не активен»
- lastFrame = false;
- // Отображаем на матрицах иконку «Взгляд прямо»
- drawIcon(ICON_EYE_STRAIGHT, ICON_EYE_STRAIGHT);
- }
№10. Робоголова
Изменение кода кнопок пульта
Вернись к шпаргалке с таблицей из эксперимента №7 «Консольный ИК-приёмник» и подставь фактические коды кнопок твоего пульта в строках 144
–157
, когда откроешь скетч RobotHead.ino
в Arduino IDE.
enum CODE { POWER = 0x0B, LEFT = 0x08, RIGHT = 0x19, UP = 0x06, DOWN = 0x1D, UP_LEFT = 0x0A, UP_RIGHT = 0x1A, DOWN_LEFT = 0x18, DOWN_RIGHT = 0x04, RED = 0x00, GREEN = 0x03, BLUE = 0x01 } code;
- RobotHead.ino
- // Подключаем библиотеку для работы с мелодиями в формате RTTTL
- #include <anyrtttl.h>
- // Подключаем библиотеку для работы с ИК-приёмником
- #include <IRremote.hpp>
- // Подключаем библиотеку для работы с сервоприводом
- #include <Servo.h>
- // Подключаем библиотеку для работы с таймером millis
- #include <TimerMs.h>
- // Подключаем библиотеку для работы со светодиодными матрицами
- #include <TroykaLedMatrix.h>
- // Даём понятное имя пину 3 с пищалкой
- constexpr uint8_t BUZZER_PIN = 3;
- // Даём понятное имя пину 2 с ИК-приёмником
- constexpr uint8_t IR_RECEIVE_PIN = 2;
- // Даём понятное имя пину A3 с сервоприводом
- constexpr uint8_t SERVO_YAW_PIN = A3;
- // Даём понятное имя пину A0 с сервоприводом
- constexpr uint8_t SERVO_PITCH_PIN = A0;
- // Создаём объект сервопривода влево-вправо
- Servo servoYaw;
- // Создаём объект сервопривода вверх-вниз
- Servo servoPitch;
- // Создаём объект для работы с таймером
- TimerMs timer;
- // Создаём объект матрицы левого глаза
- // на шине I²C с адресом 0x60 (указан по умолчанию)
- TroykaLedMatrix matrixL;
- // Создаём объект матрицы правого глаза
- // на шине I²C с адресом 0x63
- TroykaLedMatrix matrixR(0x63);
- // Создаём константу для хранения базовой частоты
- constexpr int FREQUENCY = 2000;
- // Создаём константы для хранения минимальной и максимальной частоты
- constexpr int MIN_FREQUENCY = FREQUENCY - (0.25 * FREQUENCY);
- constexpr int MAX_FREQUENCY = FREQUENCY + (0.25 * FREQUENCY);
- // Задаём максимально доступные углы поворота сервопривода головы влево-вправо
- constexpr uint8_t MAX_ANGLE_YAW_R = 0;
- constexpr uint8_t MAX_ANGLE_YAW_L = 180;
- // Задаём максимально доступные углы поворота сервопривода головы вверх-вниз
- constexpr uint8_t MAX_ANGLE_PITCH_DOWN = 60;
- constexpr uint8_t MAX_ANGLE_PITCH_UP = 120;
- // Вычисляем средний угол поворота сервопривода головы влево-вправо
- constexpr uint8_t MID_ANGLE_YAW = (MAX_ANGLE_YAW_R + MAX_ANGLE_YAW_L) / 2;
- // Вычисляем средний угол поворота сервопривода головы вверх-вниз
- constexpr uint8_t MID_ANGLE_PITCH = (MAX_ANGLE_PITCH_DOWN + MAX_ANGLE_PITCH_UP) / 2;
- // Создаём переменную для хранения текущего положения сервопривода головы влево-вправо
- uint8_t angleYaw = MID_ANGLE_YAW;
- // Создаём переменную для хранения текущего положения сервопривода головы вверх-вниз
- uint8_t anglePitch = MID_ANGLE_PITCH;
- // Создаём константу для хранения паузы между поворотом вала сервопривода
- constexpr uint8_t ANGLE_RANGE = 2;
- // Создаём иконку «Взгляд прямо» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- // Эмоции рисуем в редакторе изображений для LED-матрицы
- // https://amperka.github.io/led-matrix-editor/
- constexpr uint8_t ICON_EYE_STRAIGHT[] PROGMEM {
- 0x7e, 0x81, 0x81, 0x99, 0x99, 0x81, 0x81, 0x7e
- };
- // Создаём иконку «Взгляд влево» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- constexpr uint8_t ICON_EYE_LEFT[] PROGMEM {
- 0x7e, 0x81, 0x81, 0xe1, 0xe1, 0x81, 0x81, 0x7e
- };
- // Создаём иконку «Взгляд вправо» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- constexpr uint8_t ICON_EYE_RIGHT[] PROGMEM {
- 0x7e, 0x81, 0x81, 0x87, 0x87, 0x81, 0x81, 0x7e
- };
- // Создаём иконку «Взгляд вверх» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- constexpr uint8_t ICON_EYE_UP[] PROGMEM {
- 0x7e, 0x99, 0x99, 0x81, 0x81, 0x81, 0x81, 0x7e
- };
- // Создаём иконку «Взгляд вниз» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- constexpr uint8_t ICON_EYE_DOWN[] PROGMEM {
- 0x7e, 0x81, 0x81, 0x81, 0x81, 0x99, 0x99, 0x7e
- };
- // Создаём иконку «Взгляд вверх-влево» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- constexpr uint8_t ICON_EYE_UP_LEFT[] PROGMEM {
- 0x7e, 0xe1, 0xe1, 0x81, 0x81, 0x81, 0x81, 0x7e
- };
- // Создаём иконку «Взгляд вверх-вправо» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- constexpr uint8_t ICON_EYE_UP_RIGHT[] PROGMEM {
- 0x7e, 0x87, 0x87, 0x81, 0x81, 0x81, 0x81, 0x7e
- };
- // Создаём иконку «Взгляд вниз-влево» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- constexpr uint8_t ICON_EYE_DOWN_LEFT[] PROGMEM {
- 0x7e, 0x81, 0x81, 0x81, 0x81, 0xe1, 0xe1, 0x7e
- };
- // Создаём иконку «Взгляд вниз-вправо» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- constexpr uint8_t ICON_EYE_DOWN_RIGHT[] PROGMEM {
- 0x7e, 0x81, 0x81, 0x81, 0x81, 0x87, 0x87, 0x7e
- };
- // Создаём иконку «Глаза выключены» в шестнадцатеричной системе HEX
- // Иконка для левого и правого глаза одинаковая
- constexpr uint8_t ICON_EYE_OFF[] PROGMEM {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- // Создаём константу для хранения статуса слежения глазами за поворотом робоголовы
- constexpr bool STATE_LOOK_TURN = false;
- // Создаём перечисление состояний робота с соответствующей переменной
- enum {
- ROBOT_ON, // Робот включен
- ROBOT_OFF, // Робот выключен
- } robotState;
- // Создаём перечисление кодов и ИК-пульта с соответствующей переменной
- enum CODE {
- POWER = 0x0B,
- LEFT = 0x08,
- RIGHT = 0x19,
- UP = 0x06,
- DOWN = 0x1D,
- UP_LEFT = 0x0A,
- UP_RIGHT = 0x1A,
- DOWN_LEFT = 0x18,
- DOWN_RIGHT = 0x04,
- RED = 0x00,
- GREEN = 0x03,
- BLUE = 0x01
- } code;
- void setup() {
- // Подключаем сервомоторы головы влево-вправо и вниз-вверх
- servoYaw.attach(SERVO_YAW_PIN);
- servoPitch.attach(SERVO_PITCH_PIN);
- // Приравниваем текущим положениям вала сервоприводов
- // влево-вправо и вверх-вниз среднее значение
- angleYaw = MID_ANGLE_YAW;
- anglePitch = MID_ANGLE_PITCH;
- // Устанавливаем углы сервоприводов по умолчанию
- servoYaw.write(angleYaw);
- servoPitch.write(anglePitch);
- // Инициализируем ИК-приёмник
- IrReceiver.begin(IR_RECEIVE_PIN);
- // Инициализируем матрицы
- matrixL.begin();
- matrixR.begin();
- // Очищаем матрицы
- matrixL.clear();
- matrixR.clear();
- // Отображаем на матрицах иконку «Взгляд прямо»
- drawIcon(ICON_EYE_STRAIGHT, ICON_EYE_STRAIGHT);
- // Устанавливаем таймер в режим остановки после срабатывания
- timer.setTimerMode();
- // Передаём случайное число с пина A1
- // для последующей генерации случайных чисел
- randomSeed(analogRead(A1));
- // Устанавливаем режим «Робот включен»
- robotState = ROBOT_ON;
- }
- void loop() {
- // Если робот включен
- if (robotState == ROBOT_ON) {
- // Переходим в функцию обработки режима «Робот включен»
- handleRobotOn();
- }
- // Если робот выключен
- if (robotState == ROBOT_OFF) {
- // Переходим в функцию обработки режима «Робот выключен»
- handleRobotOff();
- }
- }
- // Функция отображения иконки поворотов на матрицах
- void drawIconTurn(uint8_t* iconEyeL, uint8_t* iconEyeR) {
- // Если статус активности слежение глаз за поворотом включен
- if (STATE_LOOK_TURN) {
- // Отображаем на матрицах полученные иконки
- matrixL.drawBitmapF(iconEyeL);
- matrixR.drawBitmapF(iconEyeR);
- }
- }
- // Функция отображения иконки на матрицах
- void drawIcon(uint8_t* iconEyeL, uint8_t* iconEyeR) {
- // Отображаем на матрицах полученные иконки
- matrixL.drawBitmapF(iconEyeL);
- matrixR.drawBitmapF(iconEyeR);
- }
- // Функция обработки режима «Робот выключен»
- void handleRobotOff() {
- // Выключаем глаза
- drawIcon(ICON_EYE_OFF, ICON_EYE_OFF);
- // Если робот выключен
- while (robotState == ROBOT_OFF) {
- // Переходим в функцию обработки ИК-приёмника в режиме «Робот выключен»
- remoteHandlerRobotOff();
- }
- }
- // Функция обработки режима «Робот включен»
- void handleRobotOn() {
- // Включаем глаза
- drawIcon(ICON_EYE_STRAIGHT, ICON_EYE_STRAIGHT);
- // Если робот включен
- while (robotState == ROBOT_ON) {
- // Переходим в функцию обработки ИК-приёмника в режиме «Робот включен»
- remoteHandlerRobotOn();
- }
- }
- // Функция обработки ИК-приёмника в режиме «Робот выключен»
- void remoteHandlerRobotOff() {
- // Если пришёл новый сигнал на ИК-приёмник, декодируем его
- if (IrReceiver.decode()) {
- // Создаём переменную и присваиваем ей декодируемый код кнопки
- uint32_t code = IrReceiver.decodedIRData.command;
- // Если нажата кнопка «Включение/выключение»
- if (code == POWER) {
- // Даём роботу 500 мс на включение
- delay(500);
- // Включаем робота
- robotState = ROBOT_ON;
- }
- // Разрешаем обрабатывать следующий сигнал
- IrReceiver.resume();
- }
- }
- // Функция обработки ИК-приёмника в режиме «Робот включен»
- void remoteHandlerRobotOn() {
- // Если пришёл новый сигнал на ИК-приёмник, декодируем его
- if (IrReceiver.decode()) {
- // Создаём переменную и присваиваем ей декодируемый код кнопки
- uint32_t code = IrReceiver.decodedIRData.command;
- // Устанавливаем в таймер значение счетчика 500
- timer.setTime(500);
- // Запускаем таймер
- timer.start();
- // Выбираем действие в зависимости от текущего режима игры
- switch (code) {
- // Если нажата кнопка «Включение/выключение»
- case POWER:
- // Даём роботу 500 мс на выключение
- delay(500);
- // Выключаем робота
- robotState = ROBOT_OFF;
- break;
- // Если нажата кнопка «Влево»
- case LEFT:
- // Обновляем переменную положение головы влево-вправо
- angleYaw = angleYaw + ANGLE_RANGE;
- // Обновляем положения вала влево-вправо
- servoYaw.write(angleYaw);
- // Отображаем на матрицах иконку «Взгляд влево»
- drawIconTurn(ICON_EYE_LEFT, ICON_EYE_LEFT);
- break;
- // Если нажата кнопка «Вправо»
- case RIGHT:
- // Обновляем переменную положение головы влево-вправо
- angleYaw = angleYaw - ANGLE_RANGE;
- // Обновляем положения вала влево-вправо
- servoYaw.write(angleYaw);
- // Отображаем на матрицах иконку «Взгляд вправо»
- drawIconTurn(ICON_EYE_RIGHT, ICON_EYE_RIGHT);
- break;
- // Если нажата кнопка «Вверх»
- case UP:
- // Обновляем переменную положение головы вверх-вниз
- anglePitch = anglePitch + ANGLE_RANGE;
- // Обновляем положения вала вверх-вниз
- servoPitch.write(anglePitch);
- // Отображаем на матрицах иконку «Взгляд вверх»
- drawIconTurn(ICON_EYE_UP, ICON_EYE_UP);
- break;
- // Если нажата кнопка «Вниз»
- case DOWN:
- // Обновляем переменную положение головы вверх-вниз
- anglePitch = anglePitch - ANGLE_RANGE;
- // Обновляем положения вала вверх-вниз
- servoPitch.write(anglePitch);
- // Отображаем на матрицах иконку «Взгляд вниз»
- drawIconTurn(ICON_EYE_DOWN, ICON_EYE_DOWN);
- break;
- // Если нажата кнопка «Вверх-влево»
- case UP_LEFT:
- // Обновляем переменную положение головы влево-вправо
- angleYaw = angleYaw + ANGLE_RANGE;
- // Обновляем переменную положение головы вверх-вниз
- anglePitch = anglePitch + ANGLE_RANGE;
- // Обновляем положения вала влево-вправо
- servoYaw.write(angleYaw);
- // Обновляем положения вала вверх-вниз
- servoPitch.write(anglePitch);
- // Отображаем на матрицах иконку «Взгляд вверх-влево»
- drawIconTurn(ICON_EYE_UP_LEFT, ICON_EYE_UP_LEFT);
- break;
- // Если нажата кнопка «Вверх-вправо»
- case UP_RIGHT:
- // Обновляем переменную положение головы влево-вправо
- angleYaw = angleYaw - ANGLE_RANGE;
- // Обновляем переменную положение головы вверх-вниз
- anglePitch = anglePitch + ANGLE_RANGE;
- // Обновляем положения вала влево-вправо
- servoYaw.write(angleYaw);
- // Обновляем положения вала вверх-вниз
- servoPitch.write(anglePitch);
- // Отображаем на матрицах иконку «Взгляд вверх-влево»
- drawIconTurn(ICON_EYE_UP_RIGHT, ICON_EYE_UP_RIGHT);
- break;
- // Если нажата кнопка «Вниз-влево»
- case DOWN_LEFT:
- // Обновляем переменную положение головы влево-вправо
- angleYaw = angleYaw + ANGLE_RANGE;
- // Обновляем переменную положение головы вверх-вниз
- anglePitch = anglePitch - ANGLE_RANGE;
- // Обновляем положения вала влево-вправо
- servoYaw.write(angleYaw);
- // Обновляем положения вала вверх-вниз
- servoPitch.write(anglePitch);
- // Отображаем на матрицах иконку «Взгляд вниз-влево»
- drawIconTurn(ICON_EYE_DOWN_LEFT, ICON_EYE_DOWN_LEFT);
- break;
- // Если нажата кнопка «Вниз-вправо»
- case DOWN_RIGHT:
- // Обновляем переменную положение головы влево-вправо
- angleYaw = angleYaw - ANGLE_RANGE;
- // Обновляем переменную положение головы вверх-вниз
- anglePitch = anglePitch - ANGLE_RANGE;
- // Обновляем положения вала влево-вправо
- servoYaw.write(angleYaw);
- // Обновляем положения вала вверх-вниз
- servoPitch.write(anglePitch);
- // Отображаем на матрицах иконку «Взгляд вниз-влево»
- drawIconTurn(ICON_EYE_DOWN_RIGHT, ICON_EYE_DOWN_RIGHT);
- break;
- case RED:
- // Отключаем ИК-приёмник
- IrReceiver.stop();
- // Вызываем функцию генератора последовательных длинных семплов
- toneLongSamples();
- // Вызываем функцию генератора непоследовательных коротких семплов
- toneShortSamples();
- // Запускаем ИК-приёмник
- IrReceiver.start();
- break;
- case GREEN:
- // Отключаем ИК-приёмник
- IrReceiver.stop();
- // Вызываем функцию генератора последовательных длинных семплов
- toneLongSamples();
- // Вызываем функцию генератора непоследовательных коротких семплов
- toneShortSamples();
- // Запускаем ИК-приёмник
- IrReceiver.start();
- break;
- case BLUE:
- // Отключаем ИК-приёмник
- IrReceiver.stop();
- // Вызываем функцию генератора последовательных длинных семплов
- toneLongSamples();
- // Вызываем функцию генератора непоследовательных коротких семплов
- toneShortSamples();
- // Запускаем ИК-приёмник
- IrReceiver.start();
- break;
- }
- // Разрешаем обрабатывать следующий сигнал
- IrReceiver.resume();
- }
- // Если таймер досчитал до конца
- if (timer.tick()) {
- // Отображаем на матрицах иконку «Взгляд прямо»
- drawIcon(ICON_EYE_STRAIGHT, ICON_EYE_STRAIGHT);
- }
- }
- // Функция генерации последовательных длинных семплов
- void toneLongSamples() {
- // Генерируем случайное количество семплов от 1 до 6
- int countSamples = random(1, 7);
- // Перебираем нумерацию семплов в цикле
- for (int i = 0; i < countSamples; i++) {
- // Генерируем случайное число: true или false
- bool typeSamples = random(0, 2);
- // Если тип семпла true
- if (typeSamples) {
- // Вызываем функцию генерации тона toneSlowDownFastUp:
- // Сначала медленный убывающий тон со случайными задержками
- // Затем быстрый возрастающий тон со случайными задержками
- toneSlowDownFastUp();
- } else {
- // Если тип семпла false
- // Вызываем функцию генерации тона toneSlowUpFastDown:
- // Сначала медленный возрастающий тон со случайными задержками
- // Затем быстрый убывающий тон со случайными задержками
- toneSlowUpFastDown();
- }
- }
- }
- // Функция генерации непоследовательных коротких семплов
- void toneShortSamples() {
- // Генерируем случайное количество семплов от 3 до 9
- int countSamples = random(3, 10);
- // Генерируем случайную частоту на базе FREQUENCY
- int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
- for (int i = 0; i <= countSamples; i++) {
- // Активируем глаза
- drawIcon(ICON_EYE_STRAIGHT, ICON_EYE_STRAIGHT);
- // Генерируем случайный интервал на базе FREQUENCY
- int range = random(-FREQUENCY, FREQUENCY);
- tone(BUZZER_PIN, frequency + range);
- // Выполняем случайную задержку от 70 до 170 мс
- delay(random(70, 170));
- // Деактивируем глаза
- drawIcon(ICON_EYE_OFF, ICON_EYE_OFF);
- // Выключаем звук
- noTone(BUZZER_PIN);
- // Выполняем случайную задержку от 0 до 30 мс
- delay(random(0, 30));
- }
- }
- // Функция генерации звуковой последовательности
- // Сначала медленный убывающий тон со случайными задержками
- // Затем быстрый возрастающий тон со случайными задержками
- void toneSlowDownFastUp() {
- // Генерируем случайную частоту на базе FREQUENCY
- int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
- // Активируем глаза
- drawIcon(ICON_EYE_STRAIGHT, ICON_EYE_STRAIGHT);
- // Генерируем медленный понижающий тон со случайными задержками
- for (int range = 0; range <= random(100, 1000); range++) {
- tone(BUZZER_PIN, frequency - (range * 2));
- delayMicroseconds(random(0, 1000));
- }
- // Деактивируем глаза
- drawIcon(ICON_EYE_OFF, ICON_EYE_OFF);
- // Генерируем быстрый повышающий тон со случайными задержками
- for (int range = 0; range <= random(100, 1000); range++) {
- tone(BUZZER_PIN, frequency + (range * 10));
- delayMicroseconds(random(0, 1000));
- }
- }
- // Функция генерации звуковой последовательности
- // Сначала медленный возрастающий тон со случайными задержками
- // Затем быстрый убывающий тон со случайными задержками
- void toneSlowUpFastDown() {
- // Генерируем случайную частоту на базе FREQUENCY
- int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
- // Активируем глаза
- drawIcon(ICON_EYE_STRAIGHT, ICON_EYE_STRAIGHT);
- // Генерируем медленный возрастающий тон со случайными задержками
- for (int range = 0; range <= random(100, 1000); range++) {
- tone(BUZZER_PIN, frequency + (range * 2));
- delayMicroseconds(random(0, 1000));
- }
- // Деактивируем глаза
- drawIcon(ICON_EYE_OFF, ICON_EYE_OFF);
- // Генерируем быстрый понижающий тон со случайными задержками
- for (int range = 0; range <= random(100, 1000); range++) {
- tone(BUZZER_PIN, frequency - (range * 10));
- delayMicroseconds(random(0, 1000));
- }
- }
Ресурсы
- Наборы IO.KIT в магазине