Как стать автором
Обновить

Оптический терменвокс на Arduino


Когда я впервые столкнулся с Arduino, терменвокс казался мне сложным устройством, состоящим из сенсора и исполнительного устройства. Но он оказался весьма доступным и интересным в создании. У него простое строение: лишь один фотодатчик и переделанные наушники. После нескольких экспериментов я понял, что необходима функция самокалибровки, если я хочу неизменные характеристики на различных уровнях освещённости. Также, я решил сделать автонастройку с помощью математики, а не таблицы поиска. Для меня, пентатонная настройка оказалась самой подходящей, хотя её можно легко заменить на хроматическую или другую настройку по желанию.

Вот список того, что я использовал:

*Arduino Uno (запущено на Mac OS X 10.7.4 Intel)
*Кабель USB
*Макетная плата
*Копеечные наушники-вкладыши
*Стандартный фотодатчик
*Резистор на 10 кОм
*Немного проволоки
*Паяльник и припой

Шаг первый. Переделываем наушники.



Для того, чтобы посылать сигналы в наушники, я обрезал провода и припаял их к паре проволочных перемычек. Но здесь есть несколько нюансов.
Для начала, когда вы перережете провода и снимете часть изоляции, вы увидите четыре провода, по два с каждой стороны. Каждая пара образует цепь с одним наушником, поэтому мы можем считать, что каждая пара состоит из плюсового провода (обычно окрашены в красный или голубой цвет) и заземляющего провода (обычно меднокрасный). Мы можем использовать или только один наушник (следовательно, только одну пару проводов), или объединить провода для использования обоих наушников, тем самым обеспечивая в два раза больше веселья. Для этого мы припаяем плюсовые провода из каждой пары к одной проволочной перемычке, а заземляющие провода – к другой. При необходимости смотрите фото выше.
Во-вторых, под заметной резиновой изоляцией часто можно встретить слой прозрачной резины, обволакивающий четыре провода по отдельности. Простейший способ избавиться от него – нагревать провод зажигалкой до тех пор, пока резина не сгорит. Обратите внимание: после того, как это будет сделано, будет очень трудно различить цвета. Поэтому рекомендую оставить небольшой кусок провода необожжённым для того, чтобы можно было определить тип провода. Также, я использовал мокрую ткань для того, чтобы стереть остатки сожжённой смолы для улучшения проводимости.
У меня было очень простое оборудование для пайки, поэтому я просто скрутил провода наушников вместе и вокруг проволочной перемычки, а затем капнул чуть-чуть припоя.

Шаг второй. Собираем цепь.



Здесь у нас две простые цепи:
1. Цепь наушников: Используем любой цифровой выходной контакт Arduino и заземлитель для создания цепи с проволочными перемычками наушников.

2. Цепь датчика: Это стандартный делитель напряжения, который позволяет меняющемуся сопротивлению фотодатчика регулировать напряжение, считываемое аналоговым входным контактом Arduino. Для начала, я сделал последовательную цепь, которая идет по порядку: Arduino 5V контакт питания -> фотодатчик -> резистор на 10кОм ->заземление. Я опробовал напряжение в узле между резистором и фотодатчиком, используя аналоговый вход A0.

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

Шаг третий. Пишем код.


Код состоит в основном из двух команд:
* команда AnalogRead, которая получает значение напряжения из вывода A0. Это эффективно измеряет уровень освещенности на фотодатчике.
* Команда tone, которая посылает сигнал к выводу 9 и заставляет наушники выдавать тон определённой частоты.
Конечно, есть ещё много вещей, которые нужно сделать:
* Установить контакт 9 как вывод.
* Цикл калибровки: пользователь показывает фотодатчику диапазон уровней освещения, обучая программу градуировать частоты.
* Измерить градацию и параметр сдвига на основе данных, полученных при калибровке.
* Автонастройка: округление частоты до ближайшего нужного тона с помощью логарифмов.
Вот сам код:

// Optical Theramin

//pin definitions
#define PHONES 9   // headphones connected to digital pin 9
#define PHOTOCELL 0 //photocell analog in pin 0

//variable definitions
long val = 0;        //stores raw value from photocell
long maxread = 0;    //maximum value from calibration phase
long minread = 1000;  // minimum value from calibration phase
double f = 0;         // frequency of sound
double normf = 0;    // normalized frequency 
double logf = 0;      // logarithm of normalized frequency
int ilogf = 0;        // rounded logarithm
int i = 0;            // loop dummy variable
double factor = 0;    // scaling factor for calibration
double shift = 0;     // shift for calibration
long maxfreq = 1048;  // maximum desired frequency after calibration
long minfreq = 131;   // minimum desired frequency after calibration


//magic numbers that make the intervals sound pleasing
double gap = 1.148698355;  //ratio of consecutive notes (pentatonic)
                             // it's the 5th root of 2
//double gap = 1.059463094;  //ratio of consecutive notes (chromatic)
                              // its the 12th root of 2

                              
void setup()
{
  pinMode(PHONES, OUTPUT);    // sets the digital pin as output

// calibration loop to determine a rasonable range of light levels (minread to maxread)
// and map that to frequencies between minfreq and maxfreq
  for (i = 0; i< 500; i++) {  // calibration loop runs for 5 seconds
    val = analogRead(PHOTOCELL);   // read photocell 
    tone(PHONES, val);          // play raw tone to guide calibration
    if (val > maxread) {        // as the values climb, store the largest
      maxread = val;
    }
    if (val < minread) {        // as the values drop, store the smallest
      minread = val;
    }  
    delay(10);                  // reasonable delay
  } 
  
  //Now we use the calibration to calculate scale and shift parameters
  factor = (double)(maxfreq - minfreq) / (double)(maxread - minread); // scale parameter
  //it's like a slope
  
  shift = factor * minread - minfreq;  //shift parameter: it's like an offset
}

void loop()
{
  val = analogRead(PHOTOCELL);   // read photocell 
  f = factor * val - shift;     // this linearly maps the frequency to
                                // a value between minfreq and maxfreq
                                // according to the calibration result
  
  normf = f / (double) minfreq;  // Dividing an exponential function by the min value
  logf = log(normf) / log(gap); // allows us to take the log (base gap) and the result 
  ilogf = round(logf);           // is the number of notes above the lowest, once we round it.
  f = minfreq * pow(gap,ilogf);  // we better "unlog" it.
  
  
  tone(PHONES, f);              // this produces the tone signal
  
}

Шаг четвёртый. Запускаем.


Теперь просто открываете редактор Arduino, верифицируете код, подсоединяете USB и загружаете. Вот видеогайд:

Конечно, есть много возможностей для изменения и улучшения. Некоторые возможности включают в себя:
* Добавление регулятора громкости (реостат или другой фотодатчик)
* Использование лучшего динамика
* Сделать код более эффективным (меньше переменных типа double)
* Воспользовавшись функцией map вместо маппинга калибровки вручную
Не стесняйтесь предлагать свои идеи, и веселиться, раздражая людей своим терменвоксом :)

Это перевод статьи с сайта instructables.com.

P.S. Это мой первый перевод, поэтому прошу судить строго и сообщать об ошибках.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.