Журнал LinuxFormat - перейти на главную

LXF106:Arduino

Материал из Linuxformat
Версия от 11:58, 5 мая 2009; Crazy Rebel (обсуждение | вклад)

(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск
Arduino Аппаратный хакинг для любителей гаражной электроники

Содержание

Arduino: Набор барабанщика

Подобно Лео Фендеру, Роберту Мугу и Леону Термену, Грэм Моррисон взялся за сложную вещь и показал, что все на самом деле просто – на примере драм-машины и Arduino.

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


Вы скажете, что мы могли бы использовать для этого и обычные кнопки, однако у пьезоэлементов есть несколько важных преимуществ. Они могут быть прикреплены к любой поверхности, от оборотной стороны коврика мыши и крышки стола до кожи реального барабана. До тех пор, пока к элементу передается достаточное количество вибраций, он будет генерировать ток. Кроме того, в отличие от кнопочного подхода в стиле «вкл/выкл», пьезоэлементы являются аналоговыми устройствами и генерируют поток энергии, который соответствует контуру удара. Это важное качество, потому что при использовании пьезоэлементов в качестве барабанных триггеров мы можем принять во внимание скорость и продолжительность удара по инструменту.

Подключение

Подключение пьезоэлемента выполняется просто, но очень важно не перепутать полярность. Большинство деталей поставляется с уже прикрепленными проводами – черный для «минуса» и красный для «плюса». Если же проводов нет, то минусовой провод подключается к центральной части пьезоэлемента, а плюсовой – к краю. Красный провод на каждом пьезоэлементе должен быть подключен к отдельной клеммной колодке на макетной плате, и от каждой колодки необходимо провести провод до аналогового входа Arduino. Мы использовали позиции 0–3.

Тот же контакт нужно подключить через резистор на 1 МОм к «земле». Так как мы используем несколько пьезоэлементов, то рекомендуем взять GND от Arduino и подключить его к одной из шин на макетной плате. Другой провод (черный) должен быть напрямую подключен к GND. Мы нашли, что легче всего прикрепить пьезоэлементы на поверхность стола или что-то такое же твердое. Наконец, для генерации звука подключим динамик на то же место, что и в игре «Саймон сказал», с минусовым проводом на 9-м цифровом контакте Arduino и положительным – на контакте 9 В.

Решение проблем

Существуют два основных вопроса, которые мы должны решить в данном проекте. Первый связан с характером пьезоэлементов и профилями, генерируемыми при ударе. Второй – обработка двух и более одновременных ударов. Вы, наверное, думаете, что обнаружение удара по пьезоэлементу заключается просто в ожидании появления напряжения определенного уровня. Это действительно так, но здесь возникают проблемы – в один и тот же момент времени могут быть зарегистрированы несколько фальшивых ударов. Так происходит потому, что однократный удар будет резонировать, создавая несколько пиков после первоначального воздействия. Чтобы найти решение этой проблемы, мы сняли сигнал с одного из аналоговых входов Arduino и послали его через последовательный порт назад на наш компьютер с Linux. Монитор в Arduino IDE выдал результаты, а мы скопировали и вставили их в OpenOffice.org Calc, а затем построили диаграмму, чтобы увидеть характер огибающей удара. Вы можете посмотреть на сгенерированные нами графики во врезке.


Они ясно показывают, что поиск общего элемента, точно отражающего одиночный удар, затруднен. Мы пытались решить этот вопрос с огибающей последовательностью, чтобы понять, какая часть цикла вывода с пьезоэлемента читается в настоящее время, и игнорировать ложные пики. Это работало не очень хорошо, и мы пришли к лучшей идее. Существует один аспект каждого удара, который является общим для всех: быстрый рост напряжения происходит только на первом ударе, в то время как кривизна кривых вторичных и третичных пиков менее резкая. Чтобы запрограммировать это, нам достаточно обнаруживать темпы изменения сигнала до определенного порога для выявления реальных срабатываний пьезоэлемента. Это подводит нас ко второй проблеме – обработке более чем одного удара одновременно. Если наша программа будет сидеть и ждать, действительно ли было срабатывание пьезоэлемента 1 или нет, мы не сможем зафиксировать сигналы с пьезоэлементов 2, 3 или 4. Это плохо.

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

А теперь – закодируем это!

Перво-наперво, давайте введем понятные имена для различных констант и переменных. STAGE0 содержит значение порога срабатывания, а STAGE1 – значение, которого должно достичь напряжение, чтобы считается ударом. MAXPADS – это число пьезоэлементов, подключенных к Arduino, а speakerOut характеризует цифровой разъем для динамика. val будет целым числом, которое мы используем для чтения аналоговых входов.

#define STAGE0 100
#define STAGE1 400
#define MAXPADS 4
int speakerOut = 12;
int val = 0 ;

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

int piezoStart[] = {0,0,0,0};
int piezoIn[] = {0,1,2,3};
int piezoState[] = {0,0,0,0};

Процедура начальной установки тоже несложная. Мы инициализируем вывод динамика и используем цикл for для установки аналоговых входов для пьезоэлментов:

void setup() {
  pinMode(speakerOut, OUTPUT);
  for (int i=0; i<MAXPADS; i++) {
      pinMode(piezoIn[i], INPUT);
  }
}

Теперь давайте пошалим – то есть пошумим. Есть много разных способов, позволяющих сделать это, но мы выбрали простой вариант, модифицировав тот генератор, что использовался для игры «Саймон...». Единственное отличие этой функции заключается в том, что мы добавили выражение note = note + 10, сбрасывая тон в каждом цикле и делая звук более похожим на «бум», а также сократили его продолжительность.


void playTom(int note) {
  int duration = 50000;
  long elapsed_time = 0;
  while (elapsed_time < duration) {
       digitalWrite(speakerOut, HIGH);
       delayMicroseconds(note / 2);
       digitalWrite(speakerOut, LOW);
       delayMicroseconds(note / 2);
       elapsed_time += (note);
       note += 10;
    }
}

Нам нужна только одна дополнительная функции для выбора, какой барабан используется. В основном цикле, мы генерируем различные звуки барабана в зависимости от того, какой пьезоэлемент был ударен, вызывая описанную выше функцию playTom с различной тональностью:

void playDrum(int drum) {
   switch (drum) {
     case 0:
       playTom(3500); break;
     case 1:
       playTom(3000); break;
     case 2:
       playTom(2500); break;
     case 3:
       playTom(2000); break;
   }
}

Теперь – основной управляющий цикл. Все, что мы сделаем – это претворим в жизнь оба решения, которые мы описали выше. Первый цикл for опрашивает каждый из входов пьезоэлементов по очереди и считывает текущее входное значение в val. Если эта величина выше, чем пороговая STAGE0, мы отмечаем, что состояние входа – true, потому что он может быть потенциальным ударом по пьезоэлементу. Затем мы продолжаем проверку других входов.

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

void loop(){
  for (int i=0; i<MAXPADS; i++) {
     val = analogRead(piezoIn[i]);
     if(( val >= STAGE0) && (piezoState[i] == false)) {
       piezoState[i] = true;
       piezoStart[i] = val;
     } else if ( ((val - piezoStart[i]) > STAGE1) && (piezoState[i] == true)) {
       piezoState[i] = false;
       playDrum(i);
     } else if ((piezoState[i] == true) && ( val < STAGE0)) {
       piezoState[i] = false;
     }
   }
   delay(1);
}

На этом все. Скомпилировав и послав эту программу на вашу Arduino, вы должны обнаружить, что когда вы один раз ударяете по пьезоковрику, динамик генерирует звук. Как видно, этого достаточ- но, чтобы создать ритм, поэтому, пока остывает паяльник, вы можете открыть в себе Джона Бонэма. Удачи! LXF

Персональные инструменты
купить
подписаться
Яндекс.Метрика