Raspberry Pi y el Motor de Pasos 28BYJ-48

El 28BYJ-48 es el motor de pasos más barato que hay y viene con su driver, el ULN2003. Esta página usaba la biblioteca RPi.GPIO, que no funciona en la Raspberry Pi 5. La versión de ahora usa gpiozero, la que recomienda la documentación oficial y que sirve en todos los modelos.

Cómo se ha comprobado esta página. No tenemos el montaje físico en el banco de pruebas, así que el programa se ejecutó con los pines simulados que trae la propia gpiozero, que permiten comprobar qué valor tendría cada pin en cada paso. Las salidas que aparecen son de esas ejecuciones.

Conexión

Diagrama de conexión entre la Raspberry Pi, el driver ULN2003 y el motor de pasos 28BYJ-48
Las cuatro entradas del driver van a los GPIO 17, 18, 27 y 22.
No alimentes el motor desde la Raspberry si puedes evitarlo. El 28BYJ-48 consume bastante para lo que puede dar el pin de 5 V, y los picos de corriente pueden reiniciar la placa. Lo seguro es una fuente de 5 V aparte para el driver, con las tierras de las dos unidas.

Por qué ya no RPi.GPIO

RPi.GPIO escribe directamente en los registros del procesador. En la Raspberry Pi 5 los pines los controla otro chip, el RP1, y esos registros ya no están donde la biblioteca los busca, así que falla. gpiozero funciona del 1 al 5 y viene instalada en Raspberry Pi OS. Si tienes mucho código antiguo, existe rpi-lgpio, que imita la interfaz de RPi.GPIO sobre la nueva.

El código

from gpiozero import OutputDevice
import time

PINES = (17, 18, 27, 22)
SECUENCIA = [                     # medio paso: 8 fases por ciclo
    (1, 0, 0, 1), (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),
]
PASOS_POR_VUELTA = 4096

bobinas = [OutputDevice(p) for p in PINES]

def girar(pasos, sentido=1, espera=0.002):
    for i in range(pasos):
        fase = SECUENCIA[(i * sentido) % len(SECUENCIA)]
        for bobina, valor in zip(bobinas, fase):
            bobina.value = valor
        time.sleep(espera)

def soltar():
    for b in bobinas:
        b.off()

try:
    girar(PASOS_POR_VUELTA)              # una vuelta
    girar(PASOS_POR_VUELTA // 4, -1)     # un cuarto hacia atrás
finally:
    soltar()

Con los pines simulados, estas son las primeras nueve fases que recibe el driver y lo que tarda un octavo de vuelta:

salidalas primeras nueve fases: 1001 1000 1100 0100 0110 0010 0011 0001 1001
un octavo de vuelta (512 pasos): 1.20 s

Cada paso enciende una o dos bobinas, y la novena fase vuelve a ser la primera: es un ciclo. sentido=-1 recorre la secuencia al revés y el motor gira hacia el otro lado. Fíjate en el tiempo: 512 pasos con una espera de 2 ms deberían ser 1,02 segundos, y son 1,20. time.sleep siempre tarda algo más de lo que pides, y en un sistema operativo normal no hay forma de evitarlo; para un motor de pasos no importa.

El finally con soltar() es importante. Si el programa termina con alguna bobina encendida, el motor y el driver se quedan calentándose aunque no se mueva nada. Así se apagan pase lo que pase, también si cortas el programa con Ctrl+C.

Revisada en octubre de 2026 para Raspberry Pi OS actual. Las salidas están copiadas de ejecuciones reales; lo que no se pudo ejecutar sin el hardware se indica en el propio texto.