The 28BYJ-48 is the ₹150 geared stepper in most starter kits, sold with a ULN2003 driver board. The Pico W drives the board’s four inputs from GP10–GP13 and the motor runs from VBUS (5 V).
No library is needed: the script steps through the eight-entry half-step table, turns a full revolution, then a quarter-turn back, and switches the coils off between moves.
Wiring
| Raspberry Pi Pico W | 28BYJ-48 stepper motor + ULN2003 driver | Wire | Notes |
|---|---|---|---|
| GP10 | IN1 | blue | GP10 is physical pin 14. |
| GP11 | IN2 | purple | GP11 is physical pin 15. |
| GP12 | IN3 | yellow | GP12 is physical pin 16. |
| GP13 | IN4 | orange | GP13 is physical pin 17. |
| VBUS | + | red | VBUS (pin 40) is USB 5 V for the 5 V motor (about 200–250 mA while stepping). Never 3V3. |
| GND | - | black |
5 V for the 5 V version of the motor (about 200–250 mA while stepping) part, 3.3 V board. The ULN2003 inputs accept 3.3 V or 5 V logic, so ESP32 and Pico drive IN1–IN4 directly. Power the motor from 5 V — not from a 3.3 V pin — and share GND with the board.
Board quirks
- The ULN2003 accepts 3.3 V inputs, so GP10–GP13 drive it directly — four neighbouring pins on the left header.
- 4096 half-steps is one turn of the output shaft (the real gear ratio makes it about 4076, so expect a small drift over many turns).
- Below about 1 ms per half-step the motor stalls and just buzzes. It is a slow motor: roughly 15 s per turn here.
release()switches all coils off after each move so the motor and the driver don’t heat up. Leave them on only if something must be held in place.
Code
# 28BYJ-48 stepper + ULN2003 driver board on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: IN1 -> GP10 (pin 14), IN2 -> GP11 (pin 15), IN3 -> GP12 (pin 16), IN4 -> GP13 (pin 17),
# + -> VBUS (pin 40, USB 5 V), - -> GND. The motor plugs into the white 5-pin socket.
from machine import Pin
import time
STEPS_PER_REV = 4096 # half-steps per output-shaft turn (64 x 64:1 gearbox, about 4076 really)
STEP_MS = 1 # 1 ms per half-step = about 15 s per turn; go lower and it stalls
coils = [Pin(n, Pin.OUT, value=0) for n in (10, 11, 12, 13)]
HALF_STEP = (
(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),
)
pos = 0
def step(n):
"""Move n half-steps; negative = the other way."""
global pos
d = 1 if n > 0 else -1
for _ in range(abs(n)):
pos += d
for pin, v in zip(coils, HALF_STEP[pos % 8]):
pin.value(v)
time.sleep_ms(STEP_MS)
def release():
for pin in coils:
pin.value(0) # coils off: no holding torque, but no heat or wasted current either
def turn_degrees(deg):
step(int(deg * STEPS_PER_REV / 360))
print("28BYJ-48 on GP10-GP13")
while True:
print("One turn clockwise")
turn_degrees(360)
release()
time.sleep(1)
print("Quarter turn back")
turn_degrees(-90)
release()
time.sleep(1)# 28BYJ-48 stepper + ULN2003 driver board on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: IN1 -> GP10 (pin 14), IN2 -> GP11 (pin 15), IN3 -> GP12 (pin 16), IN4 -> GP13 (pin 17),
# + -> VBUS (pin 40, USB 5 V), - -> GND. The motor plugs into the white 5-pin socket.
from machine import Pin
import time
STEPS_PER_REV = 4096 # half-steps per output-shaft turn (64 x 64:1 gearbox, about 4076 really)
STEP_MS = 1 # 1 ms per half-step = about 15 s per turn; go lower and it stalls
coils = [Pin(n, Pin.OUT, value=0) for n in (10, 11, 12, 13)]
HALF_STEP = (
(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),
)
pos = 0
def step(n):
"""Move n half-steps; negative = the other way."""
global pos
d = 1 if n > 0 else -1
for _ in range(abs(n)):
pos += d
for pin, v in zip(coils, HALF_STEP[pos % 8]):
pin.value(v)
time.sleep_ms(STEP_MS)
def release():
for pin in coils:
pin.value(0) # coils off: no holding torque, but no heat or wasted current either
def turn_degrees(deg):
step(int(deg * STEPS_PER_REV / 360))
print("28BYJ-48 on GP10-GP13")
while True:
print("One turn clockwise")
turn_degrees(360)
release()
time.sleep(1)
print("Quarter turn back")
turn_degrees(-90)
release()
time.sleep(1)Expected serial output
28BYJ-48 on GP10-GP13
One turn clockwise
Quarter turn back28BYJ-48 on GP10-GP13 One turn clockwise Quarter turn back
Common errors
Motor vibrates but doesn’t turn
IN wires out of order or the step delay is too short. Check IN1–IN4 go to GP10–GP13 in order, and keep STEP_MS at 1 or more.
Pico resets when the motor starts
The motor is pulling too much from USB. Power the ULN2003 + pin from a separate 5 V supply and join the grounds.