Мне недавно попался на глаза датчик SW-520D, он определяет вибрацию, а также может определить положение – только очень грубо: вертикально или горизонтально. Повертев датчик в руках, ни чего лучше, как сделать шар с предсказаниями в голову не пришло. Работа шара очень простая, если он находится в состоянии покоя, то ни чего не происходит, но стоит потрусить шар, тогда должно появиться сообщение, подсказка к действию. В идеале нужно сделать дисплей и на нем отображать разные текстовые сообщения, но тратить на такую игрушку дисплей – это большое расточительство. Поэтому было решено урезать ответы шара до двух – «Да» и «Нет».
Как работает датчик вибрации SW-520D
Прежде чем, начать работу над проектом нужно понять, как работает датчик вибрации, ведь на него будет завязана вся логика. Как оказалось, датчик имеет очень простую реализацию, на столько, что при желании его можно сделать и самому: внутри цилиндра находится два электрода и металлический шарик. При встряске или при перевороте, шарик скатывается к электродам и замыкает цепь. Все очень просто и в то же время безотказно работает.
Как выглядит датчик можно посмотреть на фотке ниже.
Визуализация ответа магического шара
Я уже написал, что для вывода ответа шара не хочу использовать дисплей, но все же ответы нужно как-то выводить, поэтому тут пришлось немного извратиться и сделать отображение ответа «Да» и «Нет» с помощью светодиодов. Из красных получилось собрать крестик, а из зеленых галочку. Что получилось можно посмотреть на картинке ниже.
Логика работы магического шара
В двух словах опишу логику работы устройства. В состоянии покоя ни чего не происходит, только мониторим порт, к которому подключен датчик SW-520D. Как только на нем появляется сигнал, начинаем анимацию – поочередно моргаем красными и зелеными светодиодами, сопровождая переключения писком зуммера. Генерируем случайное число — 0 или 1, что и будет нашим ответом. По завершению анимации, необходимо включить соответствующие светодиоды ответа – да или нет. Когда загорелся ответ, сделаем задержку на несколько секунд, во время которой не будем обращать внимание на встряску. Так же можно гасить светодиоды ответа после 10-15 секунд, чтобы экономить питание.
Ни чего сложного в логике нет, хочу только обратить внимание на генерацию случайного числа. Сначала у меня с этим были проблемы, после включения arduino всегда получались одни и те же последовательности ответов. Микроконтроллер arduino не умеет генерировать случайные числа, они все псевдослучайные, поэтому повторяются. Чтобы решить эту проблему, можно внутри setup указать, чтобы микроконтроллер брал случайные числа опираясь на шумы с одного из аналоговых пинов, которые не задействованы в устройстве. Сделать это можно вот такой функцией: randomSeed(analogRead(0));
Что использовалось в проекте:
- Atmega8A. Покупал тут: Atmega8A 5 шт
- Зуммер. Покупал тут: Зуммер 10 шт
- Датчик вибрации SW-520D. Покупал тут: Датчик вибрации SW-520D 10 шт
- 2 резисторов сопротивлением 300 Ом. Покупал тут:набор резисторов 700 шт. От 10 Ом до 1 МОм
- 16 светодиодов. Покупал тут: 100 светодиодов, 10 разных цветов
- Кварцевый резонатор 16MHz. Покупал тут: Кварцевый резонатор 16MHz, 10шт
Скетч магического шара на arduino
Все что можно было тут рассказать, я описал, остается только привести код скетча, он будет ниже, а также доступен для скачивания тут: скачать.
int pinGreen = 10; // пин для зеленой галочки int pinRed = 11; // пин для красного крестика int pinShock = 12; // пин, который определяет встряска int pinBeep = 9; // пищалка bool startAnimate = false; // флаг работы анимации int timer_sec = 0; // таймеранимации int timer_sleep = 0; // таймер простоя int oldRnd = 2; // значение активного пина, нужно для сравнения void beep(unsigned char delayms){ analogWrite(pinBeep, 10); delay(delayms); analogWrite(pinBeep, 0); delay(delayms); } void setup() { pinMode(pinGreen, OUTPUT); pinMode(pinRed, OUTPUT); pinMode(pinShock, INPUT); pinMode(pinBeep, OUTPUT); digitalWrite(pinGreen, LOW); digitalWrite(pinRed, LOW); // пусть рандомное число генерится на основе шумов на аналоговом пине A0 randomSeed(analogRead(0)); } void loop() { // если была встряска, то начинаем моргать, пищать и через 3 сек выведем результат if(digitalRead(pinShock) == HIGH) startAnimate = true; if(startAnimate){ int pinRnd = random(0, 2); // рандомное число int arrayPins[2] = {pinGreen, pinRed}; // тушим два ответа digitalWrite(pinGreen, LOW); digitalWrite(pinRed, LOW); // зажигаем случайный ответ digitalWrite(arrayPins[pinRnd], HIGH); timer_sec = timer_sec + 50; // считаем время анимации // пищим если сменился вариант if(oldRnd != pinRnd){ beep(50); oldRnd = pinRnd; timer_sec = timer_sec + 50; // добавляем еще чуток } // время вышло, выводим результат if(timer_sec > 3000){ // выключаем анимацию и обнуляем переменные startAnimate = false; timer_sec = 0; oldRnd = 2; timer_sleep = 0; delay(3000); // останавливаем все на 3 секунды } delay(40); }else{ if(timer_sleep > 20000){ // если 20 сек шар не трусят, то выключаем результат digitalWrite(pinGreen, LOW); digitalWrite(pinRed, LOW); }else{ timer_sleep = timer_sleep + 10; } } delay(10); }
Послесловие
В завершение статьи приведу видео работы устройства, электронику я собрал на небольшой плате, запитал от трех пальчиковых батареек, а корпус напечатал на 3D принтере.
P.S. после финальной сборки я обнаружил косяк — пара светодиодов сгорело или уже были плохие, но это подпортило внешний вид законченного устройства. Может быть когда-нибудь доберусь и впаяю новые, но пока желания нет :)
Эх, где Вы были 1,5 года назад.
Подобная работа была проделана мной для защиты дипломного проекта.
Только вместо датчика вибрации я использовал акселерометр стоимостью 3-4$ и дисплей для вывода ответов (около 18 ответов:»да, нет, возможно, скорее всего нет и др.»).
Отличная работа.
Ответ надо брать не из random, а из-за счётчика встряски. В такой реализации теряется магия!