A continuación se muestra la implementación y teoría de un sencillo control de giro y velocidad de un motor de DC utilizando un solo potenciómetro a través de la UNIT Pulsar ESP32-C6 y un programa en MicroPython
Introducción
En esta entrada te mostraremos a controlar un motor de DC utilizando dos señales complementarias moduladas por ancho de pulso por medio de un sencillo programa en MicroPython.
Materiales
- UNIT Pulsar ESP32-C6 x1
- Protoboard x1
- Potenciómetro 3 pines lineal 1k Ω x1
- Alambre para protoboard 1m
- Driver L298N x1
- Motor con Hélice de 72mm
- Fuente de alimentación (7v a 9v)
Desarrollo
Conocimientos previos
Voltaje promedio (V average)
El voltaje promedio es el valor medio de una señal de voltaje durante un período de tiempo dado. Matemáticamente se define como:

donde:

Lo que a grandes rasgos se puede describir como la sumatoria de areas (V * t) dividido por el periodo de la señal en cuestión y para ilustrarlo, muestro un par de ejemplos numéricos con un par de señales cuadradas 1.

En este primer ejemplo observamos que el valor promedio de esta onda alterna (aunque sea cuadrada, es alterna debido a que maneja partes negativas y positivas) es igual a cero debido a que las áreas se anulan en la sumatoria algebraica

Por otra parte, en este segundo ejemplo el valor promedio es diferente de cero debido a que las aportaciones de área no son iguales y, por lo tanto, no se anulan. Tras esta información llegamos a la razón de ser de la modulación del ancho de pulso 🤓
Modulación por Ancho de Pulso (PWM)
Es una técnica de modulación en la que se varía el ancho (duración) de los pulsos de una señal periódica para controlar el voltaje promedio entregado a una carga o sistema, mientras que la frecuencia y la amplitud de la señal portadora permanecen constantes.
En otras palabras, el voltaje promedio depende directamente del tiempo en alto de la señal (Duty cycle). Si aumentas el duty, aumentas el voltaje promedio y viceversa. Matemáticamente queda como:

donde:
Lo podemos visualizar mejor con la siguiente animación:

Para el caso de esta señal el voltaje promedio siempre tiene valores iguales o mayores a cero debido a que no se tienen componentes negativas, es decir, se trata de una señal de corriente directa, por lo que el voltaje promedio depende solo del Duty cycle 😀
De esta manera, mediante una señal PWM podemos controlar una tensión promedio que será aprovechada como intensidad luminosa para el caso de los LEDs o de velocidad en un motor de DC
Configuración del driver L298N
¿Ahora si podemos iniciar con la práctica?… ¡No tan rápido Timmy! Aún faltan unos cuantos aspectos a considerar para lograr el control de giro y velocidad de un motor de DC 😵💫
Las señales PWM pueden ser fácilmente generadas por circuitos con OPAMPs, multivibradores NE555, y cualquier microcontrolador, pero como quizá ya sabes, no podemos conectar directamente las señales a un motor cuyo consumo de corriente podría dañar al MCU o dispositivo que estemos utilizando. Debido a esto necesitamos un driver que será algo así como un hermano mayor o guardaespaldas situado entre el microcontrolador y el motor, así las señales que entrega el microcontrolador controlan indirectamente al motor.
Para esta entrada usaremos el L298n un popular módulo puente H que, para efectos prácticos, nos limitaremos a decir que, si todos sus jumpers se encuentran conectados en sus sitios, al aplicar un 1 en IN1 y un 0 en IN2 el motor A gira en un sentido y si se invierte la lógica (0 → IN1 y 1 → IN2) gira en sentido opuesto, lo mismo para el motor B y sus pines IN3 e IN4
Señales PWM complementarias
Con lo anterior en mente realizaremos el control de velocidad y giro usando un solo potenciómetro, un microcontrolador ESP32-C6 de la tarjeta UNIT Pulsar conectados a los pines IN1 e IN2 utilizando un par de señales PWM complementarias, pero antes de continuar
Pero…¿A qué se refieren las señales PWM complementarias? 🤔
Se trata de un par de señales donde una está invertida o desplazada 180 grados respecto de la otra, o en otras palabras, cuando una sube la otra baja, tal como se observa en el siguiente video
Estas señales complementarias aplicadas a driver y este al motor provocan que este último “vea” un voltaje promedio en sus bornes, de manera que si el duty de una de las señales es mayor que el otro provoca un voltaje promedio de una polaridad ocasionando que el motor gire en un sentido y viceversa.
Tomemos de ejemplo este oscilograma

En él se puede observar un par de señales PWM complementarias, ambas con un Duty del 50% por lo que el motor se mantendrá estático debido a que genera una tensión promedio = 0v
Pero si el Duty de la traza amarilla es de 80% y por consecuencia el de la traza azul es del 20% el motor gira en un sentido al ser alimentado por una tensión promedio positiva
Por último, si el Duty de la traza amarilla es de 20% y por consecuencia el de la traza azul es del 80% el motor gira en sentido contrario al ser alimentado por una tensión promedio negativa

Diagramas de conexiones
! Atención¡Para el control del giro y velocidad de un motor de DC el motor exige una cantidad considerable de corriente, por lo que el siguiente circuito es alimentado por una fuente externa de 7 V a 9 VCD, ya que de lo contrario, se podría quemar el puerto USB de tu computadora o tu tarjeta UNIT Pulsar. Dicha fuente de alimentación, energiza al Driver L298 y este mediante su regulador de 5 V alimenta a la tarjeta.
Código
El siguiente programa escrito en MicroPython utiliza tres pines, donde uno es la entrada analógica para leer la tensión del Potenciómetro y en función de esta lectura modificar las señales PWM complementarias que salen por los 2 pines restantes
from machine import Pin, PWM, ADC import time # --- Configuración --- PIN_PWM_A = 14 # GPIO para PWM normal PIN_PWM_B = 0 # GPIO para PWM inverso PIN_POT = 1 # GPIO ADC para potenciómetro FREQ_PWM = 1000 # Frecuencia en Hz DEAD_TIME_US = 5 # Tiempo muerto en microsegundos # --- Inicializar PWM --- pwm_a = PWM(Pin(PIN_PWM_A)) pwm_b = PWM(Pin(PIN_PWM_B)) pwm_a.freq(FREQ_PWM) pwm_b.freq(FREQ_PWM) # --- Inicializar ADC --- pot = ADC(Pin(PIN_POT)) pot.atten(ADC.ATTN_11DB) # Rango 0-3.3V pot.width(ADC.WIDTH_12BIT) # Resolución 12 bits (0-4095) # --- Calcular dead-time en duty --- # Periodo total en microsegundos period_us = 1_000_000 / FREQ_PWM # Dead time como fracción del ciclo dead_fraction = DEAD_TIME_US / period_us def update_pwm(duty_percent): # Convertir duty a fracción [0.0 - 1.0] duty_frac = max(0.0, min(1.0, duty_percent / 100)) # Aplicar reducción para crear tiempo muerto duty_a_frac = max(0.0, min(1.0, duty_frac - dead_fraction)) duty_b_frac = max(0.0, min(1.0, (1.0 - duty_frac) - dead_fraction)) pwm_a.duty_u16(int(duty_a_frac * 65535)) pwm_b.duty_u16(int(duty_b_frac * 65535)) # --- Bucle principal --- try: while True: val = pot.read() + 370 # Valor 0-4095 duty = (val / 4095) * 100 update_pwm(duty) print(f"Pot: {val} | Duty A: {round(duty, 1)}% | Duty B: {round(100-duty, 1)}% | Dead: {DEAD_TIME_US} us") time.sleep(0.05) except KeyboardInterrupt: pwm_a.deinit() pwm_b.deinit() print("PWM detenido.")
Conclusiones
El PWM es una técnica para controlar la tensión promedio entregada por una señal pulsante a través del tiempo en alto de la misma y dicho valor promedio se traduce en velocidad de giro en un motor de corriente continua
El uso de un driver es indispensable para implementar un sistema de control, ya que, la carga (un motor) supone una corriente excesiva para dispositivos como microcontroladores
Es posible controlar la velocidad y el sentido de giro de un motor de corriente continua mediante un par de señales PWM complementarias debido a que los ciclos de trabajo de las mismas varían el voltaje promedio que alimenta al motor, el cual sabemos que dado un cambio de polaridad en sus bornes gira en uno u otro sentido.