Hoy vamos a modificar nuestro anterior proyecto (medidor de distancias) para construir un theremín, o algo que se aproxima a su funcionamiento.
Como siempre, comenzamos con preguntas: ¿qué es un theremín?
Un theremín es un instrumento musical que se toca sin contacto físico, haciendo variar las notas aproximando y alejando las manos del instrumento. Como ya sabemos medir distancias, vamos a utilizar la distancia que estamos midiendo para generar un sonido.
¿Cómo generamos sonido?
Para ello utilizaremos un “buzzer”, que viene a ser un vibrador o zumbador.
El sonido no deja de ser aire vibrando que nuestros oídos captan. Dependiendo de a qué frecuencia vibre, oiremos un sonido u otro: cuanto menor sea la frecuencia más grave será el sonido y cuanto mayor sea la frecuencia más agudo. El oído humano es capaz de percibir frecuencias entre los 20 Hercios (Hz, número de ciclos por segundo) y los 20.000 Hz.
Para nuestro proyecto vamos a traducir la distancia medida a una frecuencia y vamos a hacer vibrar el “buzzer” a esa frecuencia. El “buzzer” es un cilindro negro con un símbolo “+” encima de una de sus patillas, indicando su polaridad.
Para hacer vibrar el “buzzer” y por tanto generar un sonido, tenemos que activarlo (poniendo el pin a valor HIGH, es decir, +5 voltios) y desactivarlo (poniendo el pin a valor LOW, es decir, 0 voltios) a la frecuencia deseada, pero tenemos una función que nos permite hacerlo de manera sencilla: tone(). He aquí un ejemplo de código:
int PIN_BUZZER=9; int FREQUENCY=440; // A (la) pitch int DURATION=1000; // in milliseconds tone(PIN_BUZZER,FREQUENCY,DURATION);
Este código genera una señal de 440 hercios, que equivale a la nota La, durante un segundo en el pin número 9.
Potenciómetros
Para que nuestra familia no quiera echarnos de casa, vamos a añadirle un control del volumen. ¿Cómo hacemos esto?. Controlando el voltaje del “buzzer”: a mayor voltaje, más sonará. Y, ¿cómo podemos controlar o modificar el voltaje de una parte del circuito? Utilizando un potenciómetro.
Un potenciómetro es una resistencia variable, normalmente mediante una ruedecilla:
Como veis, este componente tiene 3 patillas y la patilla central (patilla B en el gráfico) es la que nos proporciona una resistencia variable. En nuestro caso tenemos un potenciómetro de 10 KΩ, así que girando el potenciómetro tendremos una resistencia entre 0 Ω y 10 KΩ. De esta manera podemos controlar cuál es el voltaje del buzzer y por tanto su volumen con este circuito
Conexiones
Las conexiones que vamos a realizar son exactamente las mismas que en el proyecto anterior pero sustituyendo el LED por el “buzzer”. La conexión del “buzzer” se haría de la siguiente manera:
Y conectado quedaría:
Código
Aquí tenéis el código del programa.
// Constants const int PIN_TRIGGER=9; const int PIN_ECHO=10; const int PIN_BUZZER=12; const long MIN_DISTANCE=200; // Vars long distance; long echoDurationTime; String stringOutput; void setup(){ Serial.begin(9600); pinMode(PIN_TRIGGER, OUTPUT); pinMode(PIN_ECHO, INPUT); pinMode(PIN_BUZZER,OUTPUT); } void loop(){ Serial.println("---------------------------------"); digitalWrite(PIN_TRIGGER,LOW); // Assure that we are LOW before we activate the trigger delayMicroseconds(5); digitalWrite(PIN_TRIGGER, HIGH); // Activate the trigger delayMicroseconds(10); echoDurationTime=pulseIn(PIN_ECHO, HIGH); // Read the echo signal distance= 0.17*echoDurationTime; // Distance in milimeters int pitch=31+distance; tone(PIN_BUZZER,pitch); delay(10); Serial.print("Buzzing at "); Serial.print(pitch); Serial.println(" Hz."); }
La primera parte del código es exactamente igual que nuestro proyecto anterior de medir distancias, pero hemos sustituido el código que hacía encenderse el LED por el código que genera el sonido:
- El rango audible comienza en los 20 Hz, pero si miramos la referencia de la función tone() vemos que la frecuencia mínima es 31 Hz. Para comenzar en los 31 Hz le sumamos 31 a la distancia calculada.
- Después, utilizamos la función tone() para emitir un sonido del tono (pitch en inglés) deseado.
- Añadimos un pequeño retardo.
Cómo mejorar nuestro proyecto
El principal problema viene dado por la sensibilidad del sensor y cómo traducir la distancia en una nota:
- Hay tonos realmente desagradables, tanto muy bajos como muy altos. Una opción es descartar frecuencias muy altas y muy bajas. Se puede hacer con un simple if:
if (distance<=50) { distance=50; } else if (distance>=1000) { distance=1000; }
O bien con la función constrain(), que básicamente hace lo mismo:
distance=constrain(distance, 50, 1000)
- Probando el proyecto tal cual, puede resultar que a poco que nos movamos y que la distancia cambie, el tono cambia mucho. Con este código, cada milímetro de diferencia implica un hercio de cambio y puede ser excesivo. Una manera sería hacer menos sensible a la distancia, dividiendo la distancia por 2 o por 3:
int pitch=31+distance/2;
Una manera más “elegante” de manejar la sensibilidad es utilizar la función map(), que traslada un rango de valores a otro rango de valores:
pitch=map(distance, 50, 1000,440,880);
Con este código trasladaríamos los valores de distancia entre 50 y 1000 milímetros al rango entre 440 .Hercios (la) y 880 Hercios (la en una octava más alta), es decir, el rango que equivale a una octava (nota: frecuencias de afinación de un piano).
Con estos cambios, podemos cambiar la siguiente parte de código:
int pitch=31+distance;
Podemos cambiarlo de la siguiente manera:
distance=constrain(distance, 50, 1000) int pitch=map(distance,50,1000,440,880);
Y a partir de aquí, la imaginación es el límite. Probad a realizar este proyecto y espero vuestros comentarios.
Wooow, me encanta! Es el proyecto más original que he visto en mucho tiempo. Felicidades, y gracias por compartir