Общие сведения:
В этом уроке мы создадим тематическое устройство, которое можно использовать как украшение стола, а именно Arduino-тыкву, реагирующую на движение в зоне видимости датчика расстояния.
У датчика существует 2 зоны чувствительности (в зависимости от расстояния от датчика), попав в каждую из которых будет выполняться светозвуковая анимация.
Видео:
Нам понадобится:
- 1х Arduino / Piranha UNO;
- 1х Battery Shield;
- 1х Trema Shield;
- 4х Trema-модуль Адресный светодиод NeoPixel;
- 1х датчика расстояния HC-SR04;
- 1х MP3-плеер;
- 1х Карта памяти MicroSD;
- 1х Динамик;
- 1х ПВХ-конструктор;
- 1х Тыква;
Для реализации проекта нам необходимо установить библиотеки:
- DFPlayer Mini mp3 Arduino Library V1.3 — для работы с плеером;
- iarduino_HC_SR04_int — для работы с ультразвуковыми датчиками расстояния;
- iarduino_NeoPixel — для работы с адресными светодиодами NeoPixel;
О том, как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE.
Описание работы устройства:
После подачи питания Arduino-тыква готова к работе.
Для того, чтобы включить анимацию, достаточно поднести руку к датчику на одно из двух указанных расстояний.
Схема сборки:
Arduino / Piranha UNO:
Batery Shield:
Установите Battery Shield на Arduino / Piranha UNO:
Во время установки Battery Shield должен быть в выключенном состоянии.
Trema Shield:
На Battery Shield установите Trema Shield:
MP3-плеер:
Подключите MP3-плеер к Trema Shield и динамик к MP3-плееру:
Так как выводы 0 и 1 зарезервированы под RX и TX, перед загрузкой скетча необходимо отключить плеер от платы, а после загрузки и перед использованием подключить обратно.
Датчик расстояния
Подключите датчик расстояния HC-SR04 к Trema Shield:
Адресные светодиоды:
Подключите адресные светодиоды NeoPixel к Trema Shield:
Все используемые в уроке Trema-модули NeoPixel соединены друг c другом, а первый модуль можно подключить к любому выводу Arduino. Номер вывода указывается в скетче (в примере используется вывод D5
). Чем больше модулей в цепи, тем больше тока она потребляет, поэтому в схеме используется стабилизированный источник питания Battery Shield на 5В постоянного тока.
Код программы (скетч):
#include <DFRobotDFPlayerMini.h> // подключаем библиотеку для работы с MP3-плеером #include <iarduino_NeoPixel.h> // подключаем библиотеку для работы со светодиодами NEoPixel #include <iarduino_HC_SR04_int.h> // подключаем библиотеку для работы с датчиком расстояния HC-SR04 DFRobotDFPlayerMini myDFPlayer; // объявляем объект myDFPlayer для работы с плеером uint8_t neo_pin = 5; // указываем вывод, к которому подключены светодиоды NeoPixel uint16_t modul_number = 4; // указываем количество модулей в цепи iarduino_NeoPixel led(neo_pin, modul_number * 4 ); // объявляем объект led для работы со светодиодами NeoPixel iarduino_HC_SR04_int sensor(3, 2); // объявляем объект sensor для работы с датчиком расстояния HC-SR04 uint8_t j; // Объявляем переменную для хранения значения сдвига спектра цветов для всех светодиодов (от 0 до 255) uint8_t r, g, b; // Объявляем переменную для хранения цветов RGB для каждого светодиода uint32_t timer1, timer2; // счётчики времени при срабатывании анимации uint32_t timer3; // счётчик времени при включении светодиодной подсветки тыквы uint32_t hcsr_waiting_time_far = 600000; // время ожидания повтора анимации ДВИЖЕНИЕ ВДАЛЕКЕ uint32_t hcsr_waiting_time_near = 60000; // время ожидания повтора анимации ДВИЖЕНИЕ ВБЛИЗИ uint32_t action_time = 10000; // время работы анимации uint8_t flg_near, flg_far; // флаги для включения анимации uint8_t rev_flg; // флаг включения реверса при счёте uint8_t p; // переменная для хранения номера светодиода при сдвиге uint8_t l; // переменная для хранения значения яркости светодиодов void setup() { Serial.begin(9600); // инициируем работу Монитора последовательного порта на скорости 9600бод myDFPlayer.begin(Serial); // указываем последовательный порт для общения с MP3-плеером led.begin(); // инициализируем адресные светодиоды led.setColor(NeoPixelAll, 0, 0, 0); // указываем всем светодиодам погаснуть led.write(); // выключаем светодиоды randomSeed(analogRead(0)); // инициируем генератор псевдослучайных чисел sensor.distance(); // запрашиваем значение расстояния delay(500); // задержка 0.5сек } void loop() { //====================================================================// //====================================================================// if (sensor.distance() >= 1 && sensor.distance() <= 15) { // Проверяем, если расстояние до препятствия от 1 до 15см, то if(millis() > timer1 + hcsr_waiting_time_near || flg_near ==0){ // проверяем, прошло ли заданное время после последней сработки, или сброшен ли флаг при первом запуске, и если да, то flg_near = true; // ставим флаг, timer1 = millis(); // обновляем значение таймера, myDFPlayer.volume(20); // выставляем уровень громкости плеера myDFPlayer.play(4); // указываем плееру включить 4 трек } } if (sensor.distance() >= 30 && sensor.distance() <= 70) { // Проверяем, если расстояние до препятствия от 30 до 70 см, то if(millis() > timer2 + hcsr_waiting_time_far || flg_far ==0){ // проверяем, прошло ли заданное время после последней сработки, или сброшен ли флаг при первом запуске, и если да, то flg_far = true; // ставим флаг, timer2 = millis(); // обновляем значение таймера, myDFPlayer.volume(15); // выставляем уровень громкости плеера myDFPlayer.play(5); // указываем плееру включить 5 трек l = 0; // обнуляем переменную для изменения значения яркости светодиодов } } //====================================================================// //====================================================================// if (flg_near) { // Если был установлен флаг ПРЕПЯТСТВИЕ БЛИЗКО, то if(millis() < timer1 + action_time){ // проверяем, прошло ли заданное время на выполнение анимации, и если нет, то //============================================================// // БЛОК РАБОТЫ ВНУТРЕННЕЙ ПОДСВЕТКИ if (millis() > timer3 + 500) { // Проверяем, прошло ли время с момента последнего выполнения блока, и если нет, то timer3 = millis(); // обновляем значение таймера, uint16_t f; // определяем переменную как коэффициент яркости if (f == 0 ) {f = 42; } else // f=60° (0 ... 42 ... 255 = 0° ... 60° ... 360°) if (f == 42 ) {f = 85; } else // f=120° (0 ... 85 ... 255 = 0° ... 120° ... 360°) if (f == 85 ) {f = 127;} else // f=180° (0 ... 127 ... 255 = 0° ... 180° ... 360°) if (f == 127) {f = 170;} else // f=240° (0 ... 170 ... 255 = 0° ... 240° ... 360°) if (f == 170) {f = 212;} else // f=300° (0 ... 212 ... 255 = 0° ... 300° ... 360°) if (f == 212) {f = 0; } // f=360° (0 ... 255 ... 255 = 0° ... 360° ... 360°) if (f < 85) { b = 0; r = f * 3; g = 255 - r;} else // перелив от зелёного к красному, через жёлтый if (f < 170) {f -= 85; g = 0; b = f * 3; r = 255 - b;} else // перелив от красного к синему , через фиолетовый {f -= 170; r = 0; g = f * 3; b = 255 - g;} // перелив от синего к зелёному, через голубой for (uint8_t t = 0; t < 8; t++) {led.setColor(t, r, g, b);} // устанавливаем выбранный цвет для очередного светодиода } //============================================================// // БЛОК РАБОТЫ "ГЛАЗ" - эффект "бегающих" по кругу глаз p++; // увеличиваем значение переменной на 1 при каждом выполнении цикла if (p == 4) p = 0; // при превышении значения сбрасываем его led.setColor(8 + p, 255, 0, 0); // указываем указанному светодиоду на левом модуле гореть красным led.setColor(12 + p, 255, 0, 0); // указываем указанному светодиоду на правом модуле гореть красным led.setColor(7 + (p ? p : 4), 127, 127, 127); // указываем всем остальным светодиодам на левом модуле гореть белым led.setColor(11 + (p ? p : 4), 127, 127, 127); // указываем всем остальным светодиодам на правом модуле гореть белым //============================================================// led.write(); // записываем указанные цвета в модули delay(100); // задержка 100мс } else { // Если время выполнения анимации закончилось, то flg_near = false; // Сбрасываем флаг led.setColor(NeoPixelAll, 0, 0, 0); // устанавливаем цвет всех светодиодов в чёрный(гасим) led.write(); // записываем указанный цвет в модули } } //====================================================================// //====================================================================// else if (flg_far) { // Если был установлен флаг ПРЕПЯТСТВИЕ ДАЛЕКО, то if(millis() < timer2 + action_time){ // проверяем, прошло ли заданное время на выполнение анимации, и если нет, то if (!rev_flg) { // проверяем, установлен флаг реверса, и если нет, то l++; // увеличиваем значение яркости на 1 при кажом выполнении цикла r = l; g = 0; b = 0; // устанавливаем светодиодам внутри красный цвет, и задаём яркость for (uint8_t e = 0; e < 8; e++) { // проходим по указанным светодиодам (установленным внутри) led.setColor(e, r, g, b); // задаём указанным светодиодам яркость и цвет } led.write(); // записываем указанный цвет и яркость в модули delay(19); // задержка 19мс if (l == 255) rev_flg = 1; // при достижении максимального значения яркости устанавливаем флаг реверса } else { // Если установлен флаг реверса, то l--; // уменьшаем значение яркости на 1 при каждом выполнении цикла r = l; g = 0; b = 0; // устанавливаем светодиодам внутри красный цвет, и задаём яркость for (uint8_t e = 0; e < 8; e++) { // проходим по указанным светодиодам (установленным внутри) led.setColor(e, r, g, b); // задаём указанным светодиодам яркость и цвет } led.write(); // записываем указанный цвет и яркость в модули delay(19); // задержка 19мс if (l == 0) rev_flg = 0; // при достижении минимального значения яркости сбрасываем флаг реверса } } else { // Если время выполнения анимации закончилось, то flg_far = false; // Сбрасываем флаг led.setColor(NeoPixelAll, 0, 0, 0); // устанавливаем цвет всех светодиодов в чёрный(гасим) led.write(); // записываем указанный цвет в модули } } }
Алгоритм работы скетча:
До кода void setup()
определяются переменные, подключаются необходимые библиотеки.
В коде void setup()
инициализируется MP3-плеер, адресные светодиоды NeoPixel, датчик расстояния, выключаются светодиоды, если до этого они горели.
Код void loop()
делится 2 части:
- Проверяется, обнаружил ли датчик расстояния препятствие в одной из 2 указанных зон:
- Если препятствие находится вблизи, то запускается трек 4, ставится флаг наличия препятствия
flg_near
в данной зоне, обнуляется счётчик времениtimer1
, фиксирующий наступление события, чтобы в следующий раз оно сработало через времяhcsr_waiting_time_near
; - Если препятствие находится вдалеке, то запускается трек 5, ставится флаг наличия препятствия
flg_far
в данной зоне, обнуляется счётчик времениtimer2
, фиксирующий наступление события, чтобы в следующий раз оно сработало через времяhcsr_waiting_time_far
;
- Проверяется, был ли установлен флаг наличия препятствия:
- Если препятствие было обнаружено вблизи (установлен флаг
flg_near
):- Проверяем, истекло время выполнения анимации
timer1 + action_time
или нет;- Если не истекло, то задаём режим работы светодиодных модулей;
- Если истекло, то гасим все светодиоды и сбрасываем флаг;
- Проверяем, истекло время выполнения анимации
- Если препятствие было обнаружено вдалеке (установлен флаг
flg_far
):- Проверяем, истекло время выполнения анимации
timer2 + action_time
или нет;- Если не истекло, то задаём режим работы светодиодных модулей;
- Если истекло, то гасим все светодиоды и сбрасываем флаг;
- Проверяем, истекло время выполнения анимации
- Если препятствие было обнаружено вблизи (установлен флаг
Ссылки:
- Библиотека iarduino_NeoPixel;
- Библиотека DFPlayer Mini mp3 Arduino Library V1.3;
- Библиотека iarduino_HC_SR04_int;
- Wiki - Установка библиотек в Arduino IDE;
- Wiki - Piranha UNO;
- Wiki - Battery Shield;
- Wiki - Trema Shield;
- Wiki - Trema-модуль Адресные светодиоды NeoPixel;
- Wiki - Ультразвуковой датчик измерения расстояния HC-SR04;
Обсуждение