Arduino тыква — готовимся в Хэллоуину
Arduino тыква — готовимся в Хэллоуину
Уроки и проекты /
Общие сведения:
В этом уроке мы создадим тематическое устройство, которое можно использовать как украшение стола, а именно 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-SR04DFRobotDFPlayerMini 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-SR04uint8_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
;
- Если препятствие находится вблизи, то запускается трек 4, ставится флаг наличия препятствия
- Проверяется, был ли установлен флаг наличия препятствия:
- Если препятствие было обнаружено вблизи (установлен флаг
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;
Станьте первым!