[Из песочницы] Брейн-система

В последнее время набирают популярность различные виды интеллектуальных игр: «Что? Где? Когда?», «Мелотрек», «Брейн-ринг». Но для некоторых видов игр не обойтись без специальной системы, которая будет управлять ходом игры. Вот в рамках курсового проекта решили попробовать сделать свою брейн-систему.
До этого мы никогда не сталкивались с Arduino или чем-то аппаратным, но глядя на то, как друзья и знакомые в университете с легкость собирают устройства, захотелось попробовать и нам сделать что-то свое. Поскольку мы были достаточно далеки от этой темы, то предложение собрать брейн-систему подкинул наш руководитель, сказав, что это будет хорошим стартом для нас. На удивление, так и произошло.

Для начала мы определили цель: брейн-система должна подавать звуковой сигнал, означающий начало времени вопросного раунда и сигнал, означающий окончание времени вопросного раунда, а также должна сигнализировать ведущему о готовности игрока дать ответ. Если один игрок нажал кнопку, то остальные кнопки блокируются. Также должна быть возможность выбора режима игры.

1f7cc4cc14a04c46989196e5f331b688.jpg

Необходимые компоненты


  • Arduino Nano
  • Динамик
  • Светодиоды 8 шт.
  • Кнопки 4 шт. для игроков и 2 для ведущего
  • Неработающий роутер
  • DIP-переключатель
  • Резисторы:
  • 8 шт. — 100 Ом (для диодов)
  • 6 шт. — 10 кОм (стягивающие резисторы)
  • 6 шт. — 1 кОм для дребезга
  • 4 шт. — 470 Ом для DIP (не обязательно)
  • 5 шт. — триггер Шмитта (но можно обойтись и одним)
  • Конденсаторы — 6 шт. 1 мкф
  • Ethernet-кабель 4 шт.
  • Разъемы RJ-45 — 4шт.
  • Корпус для кнопок


Структура системы


Стоит сказать, что систему можно разделить на 3 блока: главный модуль, кнопки игроков (4 штуки) и соединительные кабели. Система содержит 4 кнопки игрока. Если игрок успел нажать раньше остальных, то на его кнопке загорается светодиод.

Пульт ведущего. Если игрок нажал кнопку на своем пульте, то на главном блоке загорается диод, соответствующий кнопке игрока. Этот модуль осуществляет выбор режима игры. У ведущего есть две кнопки Старт и Сброс. В зависимости от игры с помощью этих кнопок включается и сбрасывается таймер.

На Ардуино приходят сигналы с кнопок. Если кнопка нажата, то загорается диод на кнопке и на пульте ведущего и включается звуковой сигнал. Это главная концепция.

Кнопки и пульт ведущего связаны Ethernet-кабелем. На кнопку идут земля, логическая единица и сигнал, который включает и выключает светодиод, а с кнопки в главный модуль приходит сигнал, нажатия кнопки.

Начало разработки


Мы начали с самого простого. На макетной плате собрали схему, которая включает диод. Всё заработало! Двигаемся дальше. Подключили Arduino и кнопки, при нажатии на которые загорались диоды. И тут мы столкнулись с проблемой дребезга кнопок.

d223481cb1be4a3285568df3cd652c7e.jpg

В кнопках нужно убрать дребезг сигнала, иначе система будет думать, что на кнопку нажимают много раз. Для кнопок игроков это не очень страшно, мы все равно ловим первое нажатие, а вот на кнопке ведущего старт от дребезга надо обязательно избавляться, так как в брейн-ринге нужно знать сколько раз нажат Старт. Для этого в схему кнопок включается триггер Шмитта, конденсатор и резистор. Про дребезг можно почитать здесь.

0615b49238a443c5ad80be5e2d2dce68.jpg

И в кнопках, и в главном модуле используются светодиоды. Но 5В это слишком большое напряжение для них. Поэтому чтобы предотвратить сгорание диодов к ним последовательно подключаются резисторы. Рассчитать сопротивление резисторов можно здесь. За счет того, что все светодиоды одинаковые, нам понадобилось 8 резисторов по 100 Ом.

c1be5dd0485a445db576115b7309adb4.jpg

Режим игры выбирается с помощью DIP-SWITCH:

  1. Брейн-ринг
  2. Что? Где? Когда?
  3. Эрудит-квартет, Тройка, Своя игра (работа системы в этих играх одинаковая)


Программная часть


Лень — залог успеха.

Параллельно с разработкой схемы писался код. Было очевидно, что нажатия кнопок стоит обрабатывать через прерывания. Вычитав про 2 внешних прерывания INT0 и INT1, мы расстроились, потому что для аж 6 кнопок двух прерываний маловато и придется повышать разрядность через регистр. Поскольку с аппаратными вещами вживую мы столкнулись в первый раз, то для нас было все сложно и непонятно. В общем, мы не очень обрадовались этому факту. Не поверив, что нашу проблему нельзя решить как-то по-другому, мы наткнулись на Pin Change Interrupt Requests, которые идеально подошли для нашего проекта. Никаких регистров!

Познакомиться с прерываниями можно здесь.

В нашей брейн-системе кнопки SET и RESET соответствуют пинам D8 и D9, а кнопки пользователей — A0-A3. Поэтому мы определили только два обработчика прерывания для каждой из используемых групп прерываний.

  • ISR (PCINT0_vect) — для кнопок ведущего.
  • ISR (PCINT1_vect) — для пользовательских кнопок.


Прерывания можно определить для каждой группы и каждого пина в отдельности. Этим занимаются регистры управления и масок, в которых необходимо установить соответствующие значения. Подробнее о настройке и разрешении прерываний смотрите здесь.

Обработчики прерываний поочередно опрашивают пины, чтобы определить, какая кнопка была нажата. Такая ситуация является одним из ограничений данных прерываний. Брейн-система должна реагировать на нажатие кнопок, поэтому значение пинов сравнивается с уровнем HIGH (то есть кнопка была нажата) в обработчике прерываний.

Настройка прерываний
ISR(PCINT0_vect) {
        noInterrupts();
        isPushed = false;
        if (digitalRead(ADMIN_BUTTON_SET) == HIGH ) {   
                gameMode->Set();
                Timer1.attachInterrupt(TimerInterrupt);
                gameMode->SetFalseStart(false);
        }
        if (digitalRead(ADMIN_BUTTON_RESET) == HIGH) {
                Timer1.stop();
                gameMode->Reset();
                gameMode->SetFalseStart(true);
        }
        interrupts();
}

ISR(PCINT1_vect){
        noInterrupts(); 
        if (isPushed == false){
                for (int i = 0; i < ARRAY_SIZE(ARRAY_USER_BUTTON); i++){
                        if (digitalRead(ARRAY_USER_BUTTON[i]) == HIGH){
                                isPushed = gameMode->UserButtonPushed(ARRAY_LED[i]);
                        }
                }               
        }       
        interrupts();
}



Весь код здесь.

Монтаж


Паяльник мы видели первый раз, поэтому начали с традиционного диода. Спаяли — диод загорелся! Затем спаяли кнопки. Проверить правильно ли все сделано было достаточно сложно, потому что главный модуль был все еще на макетной плате.

3c3c8ef3e79d4b72821a7f5e2f656a9f.jpg

Спаяли кнопки ведущего, диоды, переключатель режимов игры. В процессе мы поняли, что можно было обойтись и одним триггером Шмитта. Тогда его следует перенести в главный модуль, подвести к нему выходы кнопок через сетевой кабель, а сигналы с его выхода подавать на Arduino.

01c55f168f7f4458bc8016cd030a6e49.jpg

0ac0f3b3d57c4b459c23fa8639e19258.jpg

В целом главный блок был готов. Но по-прежнему он был не связан с кнопками игроков. За основу главного блока мы взяли нативную плату от роутера, в которой было выгодно использовать разъемы RJ-45. Хотя об этом мы слегка пожалели, ибо вырезать плату и напаивать контакты по второму кругу не самое приятное занятие. Но все прошло достаточно успешно.

Мы использовали для передачи логической 1 бело-оранжевый проводник, для логического 0 — оранжевый, сигнал на диод — бело-зеленый и сигнал с кнопки — зеленый. Хотя можно использовать любые, главное проверить какой кабель используется, потому что существуют различные варианты обжима.

Теперь главный модуль и кнопки соединялись и системы была практически готова, но появился один баг, которого не было на макетной плате. Если кнопка не была подключена к главному модулю, то система думала, что эта кнопка нажата. На просторах Интернета мы нашли решение — стягивающий резистор.

Чтобы на Ардуино не приходило «никаких» сигналов (когда кнопка вообще не подключена) в главном модуле нужно поставить стягивающие резистор (от 10 кОм) на каждый выход кнопки. При разомкнутой цепи нежелательный ток будет уходить через резистор в землю, а при замкнутой за счет большого сопротивления резистора сигнал пойдет к входному контакту.

После решения данной проблемы всё заработало.

f25c905ffcb242b69314d4ea50295fb0.jpg

Особенности режимов игр


Особенности брейн-ринга. Если старт не был нажат, то система определяет нажатие кнопок как фальстарт. Если старт нажат первый раз, то система будет ждать 20 секунд нажатия кнопок, по истечении времени система подаст звуковой сигнал. Если в течение этого времени команда все же знает правильный ответ и нажимает на кнопку, то звучит соответствующий сигнал, а таймер в свою очередь останавливается. В соответствии с правилами, в случае неправильного ответа, другие команды должны получить возможность на ответ. Для этого после второго нажатия на старт таймер запуститься на 10 секунд. Кнопка Reset сбрасывает систему, ее нажимают перед чтением следующего вопроса.

Особенности Что? Где? Когда?


После нажатия Старта подается звуковой сигнал. Звуковой сигнал подается после 50 и 60 секунд. В остальных играх отлавливается только нажатие кнопок игрока. Благодаря удобству работы с Arduino можно реализовывать и другие игры: менять таймер, разрешать фальстарт и т.д. это можно реализовать, добавив соответствующий код.

32e1e3b775e54fffbf496efe4871b8d8.jpg

8f15548d31f74f61b2cac5ff0e3ad3c2.jpg

Заключение


Оно работает и слава богу. Поскольку это был наш первый аппаратный опыт, мы довольны результатами. И не только тем, что все работало подключенное на макетной плате, но и как полноценное собранное устройство. Вышла полноценная брейн-система с режимами, игроками и ведущим. В качестве улучшения системы можно добавить выход для колонок, чтобы можно было играть на больших турнирах.
Что касается платы Arduino, то работать было легко и приятно. На просторах интернета достаточно информации и простых туториалов по сборке не самых простых для незнающего человека полезных и интересных штук. Это вполне может перерасти в хобби.

В проекте принимали участие Оксана Козлова и Марина Бардиян.

© Geektimes