Танцевальная битва

  • Платформы: Iskra JS
  • Языки программирования: JavaScript
  • Тэги: танцы, дуэль, прыжки, спорт, спор, Troyka модуль, кто не скачет…

Что это?

Кто быстрее? Кто сильнее? Кто круче?

Мы поможем поставить точку в подобных спорах раз и навсегда.

Вставайте на игровые площадки, жмите старт и прыгайте что есть сил. Светодиоды будут загораться от каждого прыжка, а общий уровень очков покажет количество жидкости в пивной башне. Опередивший соперника на 20 прыжков — победитель.

Покажи всем друзьям и коллегам, что ты — король вечеринки.

Что нам понадобится?

Как собрать?

  1. Закрепите платформу Iskra JS на панели #структора «крепление Arduino 7×8 шипов» с помощью акриловых стоек. Стойки закрепите на панели винтами, сверху установите платформу и зафиксируйте гайками.
  2. Установите Motor Shield на плату Iskra JS.
  3. Установите «лицевую панель Arduino c microUSB-интерфейсом 4×6 шипов» и через неё подключите входящие в комплектацию помп «разъёмы-переходники на 2 провода» к Motor Shield. Красный провод к плюсу, чёрный — к минусу.
  4. Установите Troyka Shield на бутерброд из плат Iskra JS и Motor Shield.
  5. Закрепите два модуля сенсора вибрации с помощью саморезов и гаек на боковых панелях #структора «7×7 шипа».
  6. Подключите модули сенсора вибрации к аналоговым пинам A0 и A5 Troyka Shield и через клеммник выведите провода «папа-папа» для дальнейшего подключения пьезо-дисков.
  7. Закрепите силовой ключ с помощью нейлоновых винтов к детали #структора (крепление Troyka 4×7 шипа), откусите бокорезами неиспользуемую часть и подключите к 6 пину Troyka Shield.
  8. Подготовьте провода для подключения колонки к Iskra JS через силовой ключ:
    1. «Плюс» колонки подключите к пину 5V
    2. «Минус» колонки — к «плюсу» силового ключа.
    3. Пин GND — к «минусу» силового ключа.
  9. Прикрепите обновлённые боковые панели («пластины 7×6 шипов») и заднюю панель («пластина 6×6 шипов») к основанию корпуса устройства («крепление Arduino 7×8 шипов»).
  10. Закрепите клеммник с помощью двухстороннего скотча к задней панели корпуса и подключите к нему выведенные ранее провода от модулей сенсоров вибрации и силового ключа.
  11. Возьмите кнопку (Troyka-модуль), прикрутите её к панели для крепления Troyka-модулей. из четырёх панелей конструктора (3x2 шипов) соорудите «башенку» и закрепите на будущей верхней панели корпуса («пластина 7×8 шипов»).
  12. Закрепите два светодиода «Пиранья» на панелях крепления Troyka-модулей, затем закрепите их по бокам верхней панели устройства.
  13. Подключите два светодиода «Пиранья» к 8 и 9 пину Troyka Shield, а кнопку (Troyka-модуль) — к 3 пину Troyka Shield.
  14. Закончите сборку лицевой части корпуса с помощью реек #структора и пластины (2×6 шипов). Прикрепите верхнюю панель («пластина 7×8 шипов») к передней, задней и боковым стенкам корпуса.
  15. Отпаяйте от пьезо-диска короткие провода и замените их на провод длинной около 1–2 метров. Повторите это для второго датчика.
  16. Подключите пьезо-диски к модулям сенсора вибрации через установленный ранее клеммник.
  17. Припаяйте многожильный монтажный провод к выводам динамика.
  18. Соберите корпус для динамика из четырёх «мега пластин» #Структора и подключите его к клеммнику на задней части корпуса.
  19. Возьмите две «пивные башни», опустите в них погружные помпы, концы выходящих трубок проведите в противоположную «башню». Помпы будут откачивать жидкость из башен соперника.В итоге должна получите схема.
  20. Подключите помпы к Motor Shield через «разъём-переходник на 2 провода»
  21. Выпилите из листа фанеры два модуля «Troyka XXL» и покрасьте их белой краской.
  22. На задней части модуля «Troyka XXL» закрепите несколько кусков поролона и приклейте пьезо-диск. Повторите действие со вторым «Troyka XXL» и сенсором вибрации.
  23. Расположите все модули на расстоянии в 15–20 см друг от друга и подключите источник питания к устройству.

Теперь осталось залить любимый «лимонад» в пивные башни и можно играть.

Алгоритм

  • После подключения питания ничего не делаем пока не нажата кнопка «старт/сброс»;
  • Проверяем текущее количество очков. Если значение очков дошло до левой или правой границы интервала:
    • заканчиваем игру;
    • показываем светодиодом победителя;
    • переходим в режим ожидания нажатия кнопки «старт/сброс»;
  • Считываем данные с сенсоров;
  • Если значение сенсора первого игрока превысило порог:
    • отнимаем от общего числа очков единицу;
    • мигаем светодиодом об удачном прыжке;
    • если количество очков кратно 3, включаем «помпу 1» на 3 секунды. Если помпа в данный момент работает, добавляем к времени её работы ещё 3 секунды.
  • Если значение сенсора второго игрока превысило порог:
    • прибавляем к общему числу очков единицу;
    • мигаем светодиодом об удачном прыжке;
    • если количество очков кратно 3, включаем «помпу 2» на 3 секунды. Если помпа в данный момент работает, добавляем к её времени работы ещё 3 секунды.

Исходный код

duel.js
// подключаем библиотеку для проигрывание мелодий
// в формате Nokia RTTTL
var player = require('@amperka/ringtone').create(P11);
// мелодия старта
var melodyStart = 'smb:d=4,o=5,b=100:16e6,16e6,32p,8e6,16c6,8e6,8g6,8p,8g,8p';
// мелодия окончания
var melodyEnd = 'smbdeath:d=4,o=5,b=90:32c6,32c6,32c6,8p,16b,16f6,16p,'+
'16f6,16f.6,16e.6,16d6,16c6,16p,16e,16p,16c';
// подключаем библиотеку для управления кнопкой
// подключенной к пину 3
var button = require('@amperka/button')
  .connect(P3);
// подключаем библиотеку для управления моторами
var Motor = require('@amperka/motor');
// присваиваем первому игроку мотор канала M2 на Motor Shield
var motorPlayer1 = Motor.connect(Motor.MotorShield.M2);
// присваиваем второму игроку мотор канала M1 на Motor Shield
var motorPlayer2 = Motor.connect(Motor.MotorShield.M1);
// подключаем библиотеку для управления светодиодами
// подключенные к пинам 8 и 9
var ledPlayer1 = require('@amperka/led').connect(P8);
var ledPlayer2 = require('@amperka/led').connect(P9);
 
// время работы помп
var timeWorkPump1 = 3000;
var timeWorkPump2 = 3000;
// новое время работы помп
var newTimeWorkPump1 = 0;
var newTimeWorkPump2 = 0;
// текущее время начало работы помп
var startTimeWorkPump1 = 0;
var startTimeWorkPump2 = 0;
// текущее количество очков
var score = 0;
// количество очков для победы
var maxScore = 20;
// состояние работы помп
var idPumpPlayer1 = 0;
var idPumpPlayer2 = 0;
// состояние готовности устройства принять прыжок игрока
var statePlayer1 = 0;
var statePlayer2 = 0;
// состояние игры
var idPlayGame = 0;
// состояние конца игры
var idEndGame = 0;
 
// прерывание по нажатию кнопки
button.on('press', function() {
  ledPlayer1.turnOn();
  ledPlayer2.turnOn();
  // проигрываем мелодию о начале игры
  player.play(melodyStart).then(function() {
    print('Melody completed');
    // сбрасываем игру
    resetGame();
    // начинаем игру
    playGame();
  });
});
 
// функция начало игры
function playGame() {
  print('Start Game');
  idPlayGame = setInterval(function() {
 
    // Не закончилась ли игра?
    if (score >= maxScore || score <= -maxScore) {
      clearInterval(idPlayGame);
      print('Stop Game');
      // заканчиваем игру
      endGame();
      // проигрываем мелодию об окончании игры
      player.play(melodyEnd).then(function() {
        print('End Game');
      });
    }
 
    // считывание значений с датчиков вибрации
    var sensorVal1 = analogRead(A5);
    var sensorVal2 = analogRead(A0);
    // если значение сенсора первого игрока превысило порог
    if (sensorVal1 > 0.03 && statePlayer1 === 0) {
      ledPlayer1.turnOn();
      statePlayer1 = 1;
      // отнимаем от общего числа очков единицу
      score--;
      print(score);
      if (score % 3 === 0) {
        try {
          clearTimeout(idPumpPlayer1);
          // интервал времени, который прошёл
          // на данный момент работы помпы 1
          var intervalTimeWorkedPump1 = (getTime()*1000-startTimeWorkPump1);
          // оставшиеся время работы помпы 1
          var lastTimeWorkPump1 = timeWorkPump1 - intervalTimeWorkedPump1;
          // новое время работы помпы 1
          newTimeWorkPump1 = newTimeWorkPump1 + lastTimeWorkPump1;
          print('Yes Timer for player 1');
          print('Timer1 = ', newTimeWorkPump1);
          pump1Off(newTimeWorkPump1);
        } catch (e) {
          newTimeWorkPump1 = timeWorkPump1;
          print('No Timer for player 1');
          print('Timer1 = ', newTimeWorkPump1);
          pump1CycleOnOff();
        }
      }
      // следующий засчитанный прыжок будет доступен через 100 мс
      setTimeout(function() {
        statePlayer1 = 0;
        ledPlayer1.turnOff();
        print('Continue read player 1');
      }, 100);
    }
 
    // если значение сенсора второго игрока превысило порог
    if (sensorVal2 > 0.03 && statePlayer2 === 0) {
      ledPlayer2.turnOn();
      statePlayer2 = 1;
      // прибавляем к общему числу очков единицу
      score++;
      print(score);
      if (score % 3 === 0) {
        try {
          clearTimeout(idPumpPlayer2);
          // интервал времени, который прошёл
          // на данный момент работы помпы 2
          var intervalTimeWorkedPump2 = (getTime()*1000-startTimeWorkPump2);
          // оставшиеся время работы помпы 2
          var lastTimeWorkPump2 = timeWorkPump2 - intervalTimeWorkedPump2;
          // новое время работы помпы 2
          newTimeWorkPump2 = newTimeWorkPump2 + lastTimeWorkPump2;
          print('Yes Timer for player 2');
          print('Timer2 = ', newTimeWorkPump2);
          pump2Off(newTimeWorkPump2);
        } catch (e) {
          newTimeWorkPump2 = timeWorkPump2;
          print('No Timer for player 2');
          print('Timer2 = ', newTimeWorkPump2);
          pump2CycleOnOff();
        }
      }
      // следующий засчитанный прыжок будет доступен через 100 мс
      setTimeout(function() {
        statePlayer2 = 0;
        ledPlayer2.turnOff();
        print('Continue read player 2');
      }, 100);
    }
  }, 10);
}
 
 
// функция включения помпы первого игрока с последующим отключением
function pump1CycleOnOff() {
  print('Pump Player 1 On');
  startTimeWorkPump1 = getTime()*1000;
  motorPlayer1.write(1.0);
  ledPlayer1.turnOn();
  pump1Off(timeWorkPump1);
}
 
// функция выключения помпы первого игрока
function pump1Off(time) {
  startTimeWorkPump1 = getTime()*1000;
  idPumpPlayer1 = setTimeout(function() {
    print('Pump Player 1 Off');
    motorPlayer1.write(0);
    ledPlayer1.turnOff();
    idPumpPlayer1 = 0;
  }, time);
}
 
// функция включения помпы второго игрока с последующим отключением
function pump2CycleOnOff() {
  print('Pump Player 2 On');
  startTimeWorkPump2 = getTime()*1000;
  motorPlayer2.write(1.0);
  ledPlayer2.turnOn();
  pump2Off(timeWorkPump2);
}
 
// функция выключения помпы второго игрока
function pump2Off(time) {
  startTimeWorkPump2 = getTime()*1000;
  idPumpPlayer2 = setTimeout(function() {
    print('Pump Player 2 Off');
    motorPlayer2.write(0);
    ledPlayer2.turnOff();
    idPumpPlayer2 = 0;
  }, time);
}
 
// выключить помпы и светодиоды
function allOff() {
  motorPlayer1.write(0);
  motorPlayer2.write(0);
  ledPlayer1.turnOff();
  ledPlayer2.turnOff();
}
 
// сброс игры
function resetGame() {
  score = 0;
  try {
    clearInterval();
    print('Yes Interval');
  } catch (e) {
    print('No Interval');
  }
  try {
    clearTimeout();
    print('Yes Timeout');
  } catch (e) {
    print('No Timeout');
  }
  allOff();
}
 
// конец игры
function endGame() {
  try {
    clearInterval();
    print('Yes Interval');
  } catch (e) {
    print('No Interval');
  }
  try {
    clearTimeout();
    print('Yes Timeout');
  } catch (e) {
    print('No Timeout');
  }
  if (score === -maxScore) {
    // если выиграл первый игрок
    motorPlayer1.write(1.0);
    motorPlayer2.write(0);
    ledPlayer1.turnOn();
    ledPlayer2.turnOff();
    print('Player 1 Win');
  } else if (score === maxScore) {
    // если выиграл второй игрок
    motorPlayer1.write(0);
    motorPlayer2.write(1.0);
    ledPlayer1.turnOff();
    ledPlayer2.turnOn();
    print('Player 2 Win');
  } else {
    allOff();
    print('No Win');
  }
  // после победы одного из игроков
  // через 10 секунд выключаем помпы и светодиоды
  idEndGame = setTimeout(function() {
    allOff();
  }, 10000);
}

Демонстрация работы устройства

Что дальше?

Добавьте в проект дисплей чтобы показывать точное количество очков.

Не оказалось платы Iskra JS, не беда. Любой обладатель платы Arduino может собрать подобный проект — в его основе лежит скетч из 20 эксперимента Матрёшки Z.

Используй больше датчиков вибрации и собери свой ответ Dance Dance Revolution.