jueves, 13 de abril de 2017

Controlar un timbre, zumbador o buzzer pasivo con Python

En este post os voy a mostrar como usar los puertos GPIO y un pequeño programa en Python para controlar un timbre piezoeléctrico pasivo(también llamado zumbador o buzzer). aquí os dejo una imagen del que he usado yo.



Como podéis ver se parece mucho, pero mucho a un buzzer activo, luego os explico la diferencia.
Para ello voy a usar una placa protoboard, cables de conexión, 1 timbre activo, 1 resistencia (opcional, según el modelo de timbre que tengáis) y mi RaspberryPi. Si sois nuevos en esto os aconsejo leer los anteriores posts (del uso de los GPIO en el apartado Programación/GPIO).


1. Que es un buzzer pasivo


No soy ni mucho menos un experto pero voy a intentar explicarlo de forma fácil (si alguien sabe dar una mejor explicación por favor que haga un comentario en el blog).
Al igual que un buzzer activo se trata de un altavoz, pero nos permite generar tonos ya que debemos enviarle una señal ampliada o modificada para que emita un sonido. A efectos prácticos, el buzzer activo emite sonido solamente conectando el polo positivo y negativo, mientras que el buzzer pasivo emitirá un sonido al enviarle una señal modificada (amplificada). Si conectamos el buzzer pasivo como en el ejemplo del buzzer activo este no emite sonido. Tendremos que modificar la señal de salida para obtener un tono. Lo veremos con un ejemplo muy muy fácil.

2. Organización del circuito

En primer lugar vamos a ver como nos debe quedar nuestro circuito para poder controlar un timbre. Aquí os dejo una imagen para que veáis la distribución que he usado, tened cuidado y respetad la posición de los polos positivo y negativo del timbre (generalmente está indicado, en caso contrario la conexión más larga indica el polo positivo)



si no habéis leído los anteriores post sobre leds os recomiendo hacerlo (sobretodo el primero, en el que detallo el uso de las conexiones y hay un apartado al final sobre el uso de las resistencias, aquí está el link). 
Bien, como podéis ver uso el pin número 6 (cable azul para tierra, etiquetado como GROUND) y el pin número 12 (cable rojo para el positivo, etiquetado como GPIO18). En mi caso conecto el timbre directamente si ninguna resistencia. Si vuestro timbre requiere resistencia o no estáis seguros os recomiendo  usar una resistencia de 470 omnios (colocadla en el cable positivo antes del timbre). Si habéis puesto una resistencia y el timbre no suena o suena muy bajo, sustituid la resistencia por una menor. 


3. Código Python

Ahora vamos a crear un pequeño programa en python que al ejecutarlo nos permita modificar la señal de salida del puerto GPIO18 y provoque que el timbre emita un sonido. Si no sabéis como crear un archivo con un programa en python os recomiendo leer los post sobre programación python del apartado Programación/GPIO del blog.

En primer lugar abrimos el IDLE de Python en nuestra RaspberryPi (yo uso Python3), una vez abierto creamos un nuevo fichero (en el menú File-New File) y introducimos el siguiente código

# importamos libreria GPIO
import RPi.GPIO as GPIO
# desactivamos mensajes de error
GPIO.setwarnings(False)
# guardamos en una variable el pin de salida
pin=18
# indicamos el uso de  la identificacion BCM para los GPIO
GPIO.setmode(GPIO.BCM)
# indicamos que el GPIO18 es de salida de corriente
GPIO.setup(pin,GPIO.OUT)
# bucle que se repite de forma indefinida
while (True):
    # input para introducir el PWM
    PWM=input("Enter PWM (1 to 99):")
    # input para introducir los Herzios
    HZ=input("Enter Hz (0 to 2000);")
    # pasamos los valores a integer
    pwm=int(PWM)
    hz=int(HZ)
    # enviamos el sonido
    pwm_led=GPIO.PWM(pin,hz)

    pwm_led.start(pwm)

guardamos el archivo en una ubicación conocida (en el menú File-Save As), si es necesario apuntad la ruta por si la necesitáis usar más tarde. 

Podemos ejecutar directamente este pequeño programa presionando la tecla F5 (también se puede ejecutar des de el menú Run-Run Module)

Si todo es correcto se abre una nueva ventana de IDLE de python y empieza la ejecución, tenemos que introducir el valor de PWM, por ejemplo 70, y seguidamente el valor de Hz, por ejemplo 400, el timbre debería empezar a sonar de forma continuada (si no suena revisad el circuito, si es correcto y usáis una resistencia, poned una menor). Cambiad los valores y veréis como se modifica el tono.
Si habéis practicado mucho con los tonos, ya se que molesta bastante el ruido, para parar el timbre en la nueva pantalla del IDLE presionad CTRL+C para finalizar el programa y ejecutáis la línea de código siguiente

exit()

presionad Intro en el teclado (os preguntará si queréis finalizar la ejecución del porgrama, haced click en OK, el sonido debería parar y la pantalla se cerrará).

4. Canciones en Python

He encontrado por la web unas melodías, aunque la calidad del sonido no es muy buena con este tipo de altavoz, vale la pena ver el código en el que se definen las notas, las melodias y las duración de cada una de las notas.

# importamos librerias necesarias
import RPi.GPIO as GPIO
import time
# definimos variable con el identificador del pin GPIO
Buzzer = 18
# Creamos listas para guardar las notas
# Lista con frecuencia en Hz de las notas bajas 
CL = [0, 131, 147, 165, 175, 196, 211, 248]
# Lista con frecuencia en Hz de las notas medias
CM = [0, 262, 294, 330, 350, 393, 441, 495]
# Lista con frecuencia en Hz de las notas altas
CH = [0, 525, 589, 661, 700, 786, 882, 990]
# Notas cancion 1
song_1 = [CM[3], CM[5], CM[6], CM[3], CM[2], CM[3], CM[5], CM[6],
          CH[1], CM[6], CM[5], CM[1], CM[3], CM[2], CM[2], CM[3],
          CM[5], CM[2], CM[3], CM[3], CL[6], CL[6], CL[6], CM[1],
          CM[2], CM[3], CM[2], CL[7], CL[6], CM[1], CL[5]]
# duracion de las notas cancion 1
beat_1 = [1, 1, 3, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 1,
          1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3]
# Notas cancion 2
song_2 = [CM[1], CM[1], CM[1], CL[5], CM[3], CM[3], CM[3], CM[1],
          CM[1], CM[3], CM[5], CM[5], CM[4], CM[3], CM[2], CM[2],
          CM[3], CM[4], CM[4], CM[3], CM[2], CM[3], CM[1], CM[1],
          CM[3], CM[2], CL[5], CL[7], CM[2], CM[1]]
# Duracion de las notas cancion 2
beat_2 = [1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 3, 1, 1, 2,
          2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 3]
#
# definimos funcion que inicializa el puerto GPIO18
def setup():
    # desactivamos mensajes de error
    GPIO.setwarnings(False)
    # indicamos el uso de  la identificacion BCM para los GPIO
    GPIO.setmode(GPIO.BCM)
    # indicamos que el GPIO18 es de salida de corriente
    GPIO.setup(Buzzer, GPIO.OUT)
    # definimos variable global para guardar el PWM del GPIO
    global Buzz # Assign a global variable to replace GPIO.PWM
    # asignamos a la variable la frecuencia inicial de salida (440)
    Buzz = GPIO.PWM(Buzzer, 440)
    # iniciamos la salida al 50%
    Buzz.start(50)
#
# definimos bucle que hace sonar las canciones
def loop():
    while True:
        print ('\n    Cancion 1...')
        # for que recorre las notas de la cancion 1
        for i in range(1, len(song_1)):
            # cambiamos la frecuencia con las notas de la cancion
            Buzz.ChangeFrequency(song_1[i])
            # tiempo de espera para la siguiente nota
            time.sleep(beat_1[i] * 0.5)
            #
            time.sleep(5) # esperamos 5 segundos para la cancion 2
        print ('\n\n    Cancion 2...')
        # for que recorre las notas de la cancion 2
        for i in range(1, len(song_2)):
            # cambiamos la frecuencia con las notas de la cancion
            Buzz.ChangeFrequency(song_2[i])
            # tiempo de espera para la siguiente nota
            time.sleep(beat_2[i] * 0.5)
#
# funcion que para la ejecucion del programa
def destory():
    # paramos el buzzer
    Buzz.stop()
    GPIO.output(Buzzer, 1)
    GPIO.cleanup()
# inicio del programa
if __name__ == '__main__':
    setup()
    try:
        loop()
    except KeyboardInterrupt: # Presionar CTRL+C para finalizar programa.

        destory()

si queréis ver la url original dónde he encontrado el código haced click aquí.

Espero que os haya gustado (acepto críticas), hasta pronto!