To control bipolar stepper motors with CircuitPython, you need a dual H-bridge driver (like the TB6612FNG or two DRV8871 breakout boards), a microcontroller running CircuitPython 8.x or 9.x, and the adafruit_motor library. Unlike unipolar steppers that only require simple transistor switches, bipolar steppers require current reversal through their two internal coils to sequence the magnetic poles. This means you must use an H-bridge configuration to drive them effectively.
Sizing and Selecting the Right Stepper for Your Load
Before writing a single line of code, you must match the motor physics to your mechanical load. Steppers and servos are not interchangeable; steppers provide maximum torque at zero RPM (holding torque) and excel at open-loop position control, while servos rely on closed-loop feedback and excel at high-speed dynamic movements.
| Motor Type | Torque Curve | Control Needs | Typical Cost (2026) |
|---|---|---|---|
| Bipolar Stepper (NEMA 17) | High holding torque at 0 RPM, drops sharply past 800-1000 RPM | Dual H-bridge or chopper driver, PWM or step/dir | $12 - $18 |
| Unipolar Stepper | ~30% lower torque than bipolar (only half the coil is energized at a time) | Simple MOSFET array (e.g., ULN2003), center-tapped wiring | $8 - $12 |
| RC Servo | High torque at specific angles, zero holding torque without continuous feedback | 50Hz PWM signal, internal potentiometer for closed-loop | $5 - $25 |
| BLDC (Outrunner) | Smooth, high RPM torque, requires active commutation | 3-phase ESC, FOC controller, Hall sensors or encoders | $25 - $60+ |
Sizing Rule of Thumb and Worked Example
The industry standard for DIY CNCs, 3D printers, and linear actuators is the NEMA 17 (42mm x 42mm faceplate) bipolar stepper. A common model like the 17HS4401 provides roughly 40 Ncm (Newton-centimeters) of holding torque at 1.5A RMS.
Rule of Thumb: Calculate your required operational torque, then apply a 2.0x safety factor to account for friction, acceleration inertia, and the stepper's torque drop-off at speed.
Worked Load Example: You are lifting a 2kg Z-axis carriage using an 8mm pitch lead screw (0.8cm lead) with an assumed 90% mechanical efficiency (0.9).
- Force: 2kg × 9.81 m/s² = 19.62 N
- Torque Formula: (Force × Pitch) / (2 × π × Efficiency)
- Calculation: (19.62 N × 0.008 m) / (2 × 3.14159 × 0.9) = 0.0277 Nm (or 2.77 Ncm)
- Safety Factor: 2.77 Ncm × 2.0 = 5.54 Ncm required
A standard 40 Ncm NEMA 17 is more than sufficient for this load profile, leaving ample headroom for acceleration.
Wiring and Terminal Identification for Bipolar Steppers
A bipolar stepper has exactly four wires and no center taps. Inside the motor, there are two distinct coils: Coil A and Coil B. To identify them, you need a basic digital multimeter set to the resistance (Ω) range.
Driver Demands
Because you must reverse current flow, you need a dual H-bridge. Do not use a simple ULN2003 Darlington array; it is for unipolar motors only.
- TB6612FNG: Excellent for low-current NEMA 17s (up to 1.2A continuous per channel). It operates efficiently on logic-level voltages and is available on convenient Adafruit/SparkFun breakouts.
- DRV8871: If your motor pulls 1.5A or more, use two DRV8871 breakout boards (one for Coil A, one for Coil B). The DRV8871 handles up to 3.6A continuous and supports up to 45V, making it ideal for higher-torque 24V systems.
CircuitPython Implementation and Failure Signatures
To drive the motor, we use the CircuitPython Motor Library. This library abstracts the complex PWM timing required to sequence the coils. Ensure you have the adafruit_motor library installed in your lib folder.
import board
import pwmio
from adafruit_motor import stepper
import time
# Define PWM pins for Coil A (Dual H-Bridge Channel 1)
coila1 = pwmio.PWMOut(board.D5, frequency=1000)
coila2 = pwmio.PWMOut(board.D6, frequency=1000)
# Define PWM pins for Coil B (Dual H-Bridge Channel 2)
coilb1 = pwmio.PWMOut(board.D9, frequency=1000)
coilb2 = pwmio.PWMOut(board.D10, frequency=1000)
# Initialize the stepper motor object (microsteps=8 for smoother operation)
motor = stepper.StepperMotor(coila1, coila2, coilb1, coilb2, microsteps=8)
print('Rotating 1 full revolution (200 steps) forward...')
for i in range(200):
motor.onestep(direction=stepper.FORWARD, style=stepper.SINGLE)
time.sleep(0.01) # 10ms delay = 100 steps/sec
print('Releasing coils to save power and reduce heat.')
motor.release()
Diagnosing Failure Signatures
Steppers fail in very specific, diagnosable ways. If your motor isn't behaving, check these signatures:
- Hum/Vibrate but no movement: Your step rate (the
time.sleep()delay) is too fast for the rotor's inertia to catch up. This is known as exceeding the 'pull-in' rate. Increase the delay, or implement an acceleration ramp. Alternatively, your coils might be wired out of phase (e.g., A-B-A-B instead of A-A-B-B). - Overheat (too hot to touch): Steppers are designed to run hot, but if it exceeds 60°C, your driver's current limit (Vref) is set higher than the motor's RMS rating. Furthermore, failing to call
motor.release()when idle keeps full holding current applied, generating unnecessary heat. - Stall/Skip at specific speeds: Steppers suffer from mid-range resonance, typically between 150 and 250 RPM. The rotor overshoots the magnetic detent and stalls. Fix this by adding mechanical damping (a friction pad), using half-stepping/microstepping, or simply accelerating quickly through the resonant RPM band.
Frequently Asked Questions
Can I control a unipolar stepper motor as a bipolar stepper in CircuitPython?
Yes. Many 6-wire or 8-wire unipolar steppers can be driven as bipolar steppers. Simply leave the center tap wires (usually white and yellow) unconnected and isolated. Wire the remaining four outer coil wires to your dual H-bridge driver. This actually increases your available torque by roughly 40% because the entire length of the coil winding is energized, rather than just half of it. You will need to ensure your H-bridge can handle the slightly higher current draw.
Why does my bipolar stepper motor lose torque at high RPMs?
This is a fundamental limitation of stepper physics, governed by the coil's inductance and the driver's supply voltage. As the step rate increases, the time available for current to ramp up in the highly inductive coils decreases. The current never reaches its peak rated value before the next step occurs, resulting in a sharp drop in torque. To push the torque curve higher into the RPM range, you must increase the supply voltage to the driver (e.g., moving from 12V to 24V) while using a chopper driver to limit the current to the motor's rated RMS value.
Do I need a dedicated chopper driver like a TMC2209 instead of an H-bridge for CircuitPython?
For basic positioning and low-speed actuators, the H-bridge method shown above is perfectly adequate. However, if you are building a 3D printer or a silent CNC router, you should upgrade to a dedicated chopper driver like the Trinamic TMC2209 or TI DRV8825. These drivers handle the complex microstepping and current decay modes internally. In CircuitPython, you would control them using simple digital step and direction pins rather than the adafruit_motor PWM H-bridge library, resulting in much quieter operation and higher speed capability.






