Un motor paso a paso es un motor que avanza en pequeños incrementos controlables llamados pasos.
Cuando necesitamos que un robot se mueva exactamente 10 milímetros, o que una impresora 3D deposite plástico en la coordenada exacta, los motores DC se quedan cortos (son imprecisos) y los servos a veces no tienen rango suficiente (solo giran 180°).
Aquí es donde brillan los Motores Paso a Paso (Stepper Motors).
A diferencia de un motor normal que gira continuamente al darle corriente, un stepper divide una rotación completa en un número de pasos discretos. Es como el segundero de un reloj analógico: avanza “tic-tac”, paso a paso.
Esto nos permite un control absoluto de la posición y la velocidad sin necesidad de sensores externos (encoders). Simplemente contamos los pasos que enviamos.
Tipos de motores: unipolares y bipolares
Antes de conectar nada, debemos identificar qué “animal” tenemos entre manos, porque se controlan de forma muy diferente.
- Unipolares (5 o 6 cables): El más famoso es el pequeño 28BYJ-48. Son baratos, tienen poca fuerza y son fáciles de controlar con un driver ULN2003.
- Bipolares (4 cables): El estándar industrial, como los NEMA 17 de las impresoras 3D. Tienen mucha fuerza (torque) pero requieren drivers más complejos como el A4988 o DRV8825.
Vamos a ver cómo manejar ambos en MicroPython.
Motor unipolar 28BYJ-48
Este motor es omnipresente en los kits de iniciación. Tiene una reductora interna y funciona excitando sus 4 bobinas internas en una secuencia específica.
Para moverlo, no basta con poner un pin en HIGH. Tenemos que hacer un “baile” de encendido y apagado en los 4 pines de control (IN1, IN2, IN3, IN4).
La secuencia de pasos
Existen varias formas de excitarlos, pero la más suave y precisa es la Half-Step (medio paso), que tiene una secuencia de 8 estados:
Clase StepperULN2003
Vamos a encapsular esta lógica en una clase. Conectaremos el driver ULN2003 a 4 pines GPIO cualquiera.
import time
from machine import Pin
class StepperULN2003:
def __init__(self, pins_list, delay=0.001):
"""
:param pins_list: Lista de 4 objetos Pin [IN1, IN2, IN3, IN4]
:param delay: Tiempo entre pasos (velocidad). Mínimo recomendado 0.001 (1ms)
"""
self.pins = pins_list
self.delay = delay
# Secuencia de medio paso (8 pasos) para mayor suavidad
# Representa el estado de [IN1, IN2, IN3, IN4]
self.sequence = [
[1, 0, 0, 0],
[1, 1, 0, 0],
[0, 1, 0, 0],
[0, 1, 1, 0],
[0, 0, 1, 0],
[0, 0, 1, 1],
[0, 0, 0, 1],
[1, 0, 0, 1]
]
def move(self, steps, direction=1):
"""
Mueve el motor n pasos.
:param steps: Número de pasos a mover
:param direction: 1 (horario) o -1 (antihorario)
"""
for _ in range(steps):
if direction > 0:
# Avanzamos en la lista de secuencias
step_pattern = self.sequence.pop(0)
self.sequence.append(step_pattern)
else:
# Retrocedemos en la lista
step_pattern = self.sequence.pop()
self.sequence.insert(0, step_pattern)
# Aplicamos el patrón a los pines
for i in range(4):
self.pins[i].value(step_pattern[i])
time.sleep(self.delay)
def stop(self):
"""Apaga todas las bobinas para no consumir energía y no calentar"""
for pin in self.pins:
pin.value(0)
Ejemplo de uso
El motor 28BYJ-48 tiene una relación de reducción de aproximadamente 64:1. En modo medio paso, necesita 4096 pasos para dar una vuelta completa (360°).
# Pines conectados a IN1, IN2, IN3, IN4 del driver ULN2003
pins = [Pin(19, Pin.OUT), Pin(18, Pin.OUT), Pin(5, Pin.OUT), Pin(17, Pin.OUT)]
motor = StepperULN2003(pins)
print("Dando una vuelta completa...")
motor.move(4096, direction=1) # Sentido horario
print("Volviendo media vuelta...")
motor.move(2048, direction=-1) # Sentido antihorario
motor.stop() # Importante apagar al terminar
Motor bipolar NEMA 17 con driver A4988
Si quieres construir una CNC o un robot serio, usarás motores bipolares. Aquí NO controlamos las bobinas directamente. De eso se encarga un driver especializado como el A4988.
Nuestra vida es más fácil, porque la interfaz con el driver se reduce a dos pines:
- STEP: Cada pulso que enviamos aquí, el motor avanza un paso.
- DIR: Si es
HIGHgira a un lado, si esLOWal otro.
¡Peligro de muerte (del driver)! Nunca, bajo ninguna circunstancia, desconectes los cables del motor mientras el driver está alimentado. La energía almacenada en las bobinas no tendrá a dónde ir y freirá el chip A4988 al instante.
Control mediante STEP/DIR
Controlar esto es tan sencillo como encender y apagar un LED (el pin STEP).
from machine import Pin
import time
class StepperDriver:
def __init__(self, step_pin, dir_pin):
self.step_pin = Pin(step_pin, Pin.OUT)
self.dir_pin = Pin(dir_pin, Pin.OUT)
self.step_pin.value(0)
def move(self, steps, direction, delay=0.001):
"""
:param steps: Pasos a avanzar (un NEMA 17 suele tener 200 pasos/vuelta)
:param direction: 1 o 0 para el sentido de giro
:param delay: Velocidad (tiempo entre pasos)
"""
# Configuramos la dirección
self.dir_pin.value(1 if direction > 0 else 0)
for _ in range(steps):
# Generamos un pulso en STEP
self.step_pin.value(1)
time.sleep_us(10) # Pulso muy breve
self.step_pin.value(0)
# Esperamos antes del siguiente paso (control de velocidad)
time.sleep(delay)
# Ejemplo de Uso
# STEP en GPIO 26, DIR en GPIO 27
nema = StepperDriver(26, 27)
# Los NEMA 17 suelen ser de 1.8 grados por paso (200 pasos = 1 vuelta)
print("Giro rápido...")
nema.move(200, 1, delay=0.002)
print("Giro lento sentido contrario...")
nema.move(200, 0, delay=0.01)
Microstepping para un movimiento más suave
Seguramente notes que el motor vibra o hace ruido. Los drivers modernos permiten una técnica llamada Microstepping.
Mediante unos jumpers en la placa del driver (pines MS1, MS2, MS3), podemos decirle al A4988 que divida cada paso físico en micropasos (1/2, 1/4, 1/8, 1/16).
- Ventaja: Movimiento ultra suave y silencioso. Mayor resolución.
- Desventaja: El motor pierde un poco de torque y tenemos que enviar pulsos mucho más rápido (frecuencia más alta).
Qué motor elegir
- Usa el 28BYJ-48 (Unipolar) para aprender, para mover cosas ligeras (como una cortina pequeña o un juguete) y porque es muy barato.
- Usa un NEMA 17 (Bipolar) si necesitas precisión, velocidad y fuerza real (robots, impresoras 3D).
Ahora que controlamos la posición exacta, en la próxima sección veremos cómo leer sensores para que nuestro sistema sepa lo que pasa a su alrededor.