En esta entrada veremos cómo usar salidas PWM en Raspberry Pi para controlar dispositivos como LEDs, motores y servos.
Las salidas PWM (Pulse Width Modulation) son una técnica en electrónica que nos permite controlar la señales eléctricas generando una señal “pseudo-analógica”.
Si quieres aprender más sobre salidas PWM consulta,
Conceptos clave de PWM
Una salida PWM es una forma sencilla (y barata) de conseguir una señal “más o menos analógica”.
En lugar de variar el voltaje directamente, PWM modifica el tiempo que una señal está en estado alto (ON) frente al tiempo que está en estado bajo (OFF) dentro de un ciclo.
Ciclo de trabajo (Duty Cycle): Es el porcentaje de tiempo que la señal está en estado alto (ON) durante un ciclo completo. Por ejemplo, un ciclo de trabajo del 50% significa que la señal está en estado alto la mitad del tiempo y en estado bajo la otra mitad.
Frecuencia: Es el número de ciclos completos por segundo. Se mide en Hertz (Hz). Una frecuencia alta significa que los ciclos se repiten rápidamente, mientras que una frecuencia baja significa que los ciclos se repiten más lentamente.
Para algunas máquinas, una señal PWM funciona “más o menos igual” que una señal analógica real. Por ejemplo, un LED nos va a dar prácticamente el mismo funcionamiento.
Sin embargo, una señal PWM no es una señal analógica. Realmente aplicáis pulsos de 3V3. Si lo a un dispositivo que no soporta esa tensión, podéis dañarlo.
Salidas PWM por hardware
La Raspberry Pi tiene dos pines que soportan PWM por hardware: GPIO18 y GPIO19. Estos pines son adecuados para aplicaciones que requieren una precisión y estabilidad alta (como el control de servos o motores).
Vamos a ver un ejemplo, en el que utilizaremos el pin GPIO18 para controlar el brillo de un LED mediante PWM.
import RPi.GPIO as GPIO
import time
# Configuración del pin
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
# Crear una instancia de PWM con una frecuencia de 100 Hz
pwm = GPIO.PWM(18, 100)
# Iniciar PWM con un ciclo de trabajo del 0% (LED apagado)
pwm.start(0)
try:
while True:
# Aumentar el brillo del LED gradualmente
for duty_cycle in range(0, 101, 5):
pwm.ChangeDutyCycle(duty_cycle)
time.sleep(0.1)
# Disminuir el brillo del LED gradualmente
for duty_cycle in range(100, -1, -5):
pwm.ChangeDutyCycle(duty_cycle)
time.sleep(0.1)
except KeyboardInterrupt:
# Detener PWM y limpiar los pines GPIO
pwm.stop()
GPIO.cleanup()
En este código:
- Configuramos el pin GPIO18 como salida.
- Creamos una instancia de PWM con una frecuencia de 100 Hz.
- Iniciamos PWM con un ciclo de trabajo del 0% (LED apagado).
- Utilizamos un bucle para aumentar y disminuir el brillo del LED gradualmente.
Software PWM
Si necesitamos más pines PWM o no tenemos acceso a los pines de hardware, podemos utilizar PWM por software.
El PWM por software es menos preciso y puede consumir más recursos de la CPU.
En este ejemplo, utilizaremos el pin GPIO17.
import RPi.GPIO as GPIO
import time
# Configuración del pin
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)
# Frecuencia de PWM (en Hz)
frequency = 100
# Ciclo de trabajo inicial (0%)
duty_cycle = 0
# Tiempo de ciclo (1 / frecuencia)
cycle_time = 1.0 / frequency
try:
while True:
# Calcular el tiempo en estado alto y bajo
on_time = cycle_time * (duty_cycle / 100.0)
off_time = cycle_time - on_time
# Encender el LED
GPIO.output(17, GPIO.HIGH)
time.sleep(on_time)
# Apagar el LED
GPIO.output(17, GPIO.LOW)
time.sleep(off_time)
# Aumentar el ciclo de trabajo
duty_cycle += 5
if duty_cycle > 100:
duty_cycle = 0
except KeyboardInterrupt:
# Limpiar los pines GPIO
GPIO.cleanup()
En este código:
- Configuramos el pin GPIO17 como salida.
- Implementamos PWM por software utilizando un bucle que alterna entre encender y apagar el LED.
- Aumentamos el ciclo de trabajo gradualmente para simular un aumento en el brillo del LED.
Ejemplos prácticos
Control de un motor DC
PWM también se utiliza para controlar la velocidad de un motor DC. Al variar el ciclo de trabajo, podemos controlar la cantidad de energía que se entrega al motor, lo que a su vez controla su velocidad.
import RPi.GPIO as GPIO
import time
# Configuración de los pines
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
# Crear una instancia de PWM con una frecuencia de 100 Hz
pwm = GPIO.PWM(18, 100)
# Iniciar PWM con un ciclo de trabajo del 0% (motor detenido)
pwm.start(0)
try:
while True:
# Aumentar la velocidad del motor gradualmente
for duty_cycle in range(0, 101, 5):
pwm.ChangeDutyCycle(duty_cycle)
time.sleep(0.5)
# Disminuir la velocidad del motor gradualmente
for duty_cycle in range(100, -1, -5):
pwm.ChangeDutyCycle(duty_cycle)
time.sleep(0.5)
except KeyboardInterrupt:
# Detener PWM y limpiar los pines GPIO
pwm.stop()
GPIO.cleanup()
Control de un servo
Los servos son dispositivos que se utilizan para controlar la posición de un eje. PWM es esencial para controlar servos, ya que la posición del servo depende del ciclo de trabajo de la señal PWM.
import RPi.GPIO as GPIO
import time
# Configuración del pin
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
# Crear una instancia de PWM con una frecuencia de 50 Hz (típica para servos)
pwm = GPIO.PWM(18, 50)
# Iniciar PWM con un ciclo de trabajo del 7.5% (posición central)
pwm.start(7.5)
try:
while True:
# Mover el servo a la posición 0 grados
pwm.ChangeDutyCycle(2.5)
time.sleep(1)
# Mover el servo a la posición 90 grados
pwm.ChangeDutyCycle(7.5)
time.sleep(1)
# Mover el servo a la posición 180 grados
pwm.ChangeDutyCycle(12.5)
time.sleep(1)
except KeyboardInterrupt:
# Detener PWM y limpiar los pines GPIO
pwm.stop()
GPIO.cleanup()
En este código:
- Configuramos el pin GPIO18 como salida.
- Creamos una instancia de PWM con una frecuencia de 50 Hz, que es típica para servos.
- Utilizamos diferentes ciclos de trabajo para mover el servo a diferentes posiciones (0°, 90°, 180°).