MicroPython L293D motor on a Pico: a knob sets speed
MicroPython on a Raspberry Pi Pico: a knob on GP26 drives a DC motor both ways on an L293D, IN1 and IN2 on GP15 and GP16 and PWM enable on GP17. The whole build, a Raspberry Pi Pico and 3 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Intermediate About 25 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $7. On Mokxi they're free.
What you'll learn
- Reversing a DC motor with an H-bridge driver
- Direction from two pins, speed from PWM on enable
- Reading a knob with an ADC in MicroPython
- Printing only when something changes
- Difficulty: Intermediate
- Time: About 25 minutes
- Board: Raspberry Pi Pico
- Parts: 7
How it works
A knob on GP26 is read as a number, and the program subtracts 32768 so the middle of the knob is 0. In the middle the motor stops. Turn either way and it runs that way.
The sign sets the direction. GP15 goes high for forward and GP16 goes high for back, and they feed the L293D inputs. The distance from the middle is doubled and sent as PWM on GP17, the enable pin, at 1000 Hz. Farther means faster.
The program prints "forward", "back" or "stop" only when the state changes. A speed of 2 percent or less counts as stop.
Parts list
7 parts, plus the jumper wires. They retail for about $7; on Mokxi they're free.
- 1 × Raspberry Pi PicoIn Fight Stick Kit.
- 1 × PotentiometerIn Halloween Prop Kit, Starter Projects Kit.
- 1 × Motor driver, L293DIn Claw Machine Kit.
- 1 × DC motor
- 1 × Power, 3.3 V
- 2 × Power, 5 V
Kits that can build it
This starter kit has every part in the circuit. Each kit's page lists what else it can build.
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Motor driver, L293D pin IN1 | Raspberry Pi Pico pin GP15 |
| Potentiometer pin 2 | Raspberry Pi Pico pin GP26 |
| Motor driver, L293D pin EN12 | Raspberry Pi Pico pin GP17 |
| Motor driver, L293D pin IN2 | Raspberry Pi Pico pin GP16 |
| Potentiometer pin 1 | Ground |
| Potentiometer pin 3 | 3.3 V |
| DC motor pin 1 | Motor driver, L293D pin OUT1 |
| Motor driver, L293D pin GND1 | Ground |
| Motor driver, L293D pin GND2 | Ground |
| DC motor pin 2 | Motor driver, L293D pin OUT2 |
| Motor driver, L293D pin VS | 5 V |
| Motor driver, L293D pin EN34 | Ground |
| Motor driver, L293D pin IN4 | Motor driver, L293D pin IN3 |
| Motor driver, L293D pin OUT4 | Motor driver, L293D pin OUT3 |
| Motor driver, L293D pin GND3 | Ground |
| Motor driver, L293D pin GND4 | Ground |
| Motor driver, L293D pin VSS | 5 V |
The code
The MicroPython code exactly as the editor opens it. Change a line there and press Run: the board runs it on the official MicroPython firmware, with nothing to compile.
# A motor both ways on an L293D, from the knob on GP26. The middle of the
# knob is stop; turned either way, GP15 and GP16 set the direction and the
# PWM on GP17 (the chip's enable) sets how fast.
from machine import ADC, Pin, PWM
import time
knob = ADC(26)
in1 = Pin(15, Pin.OUT)
in2 = Pin(16, Pin.OUT)
enable = PWM(Pin(17))
enable.freq(1000)
last = None
while True:
offset = knob.read_u16() - 32768 # -32768 to 32767
in1.value(offset > 0)
in2.value(offset < 0)
enable.duty_u16(min(65535, abs(offset) * 2))
speed = abs(offset) * 100 // 32768
state = ("forward" if offset > 0 else "back") if speed > 2 else "stop"
if state != last:
print(state)
last = state
time.sleep_ms(50)
Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The motor does not run. This project
Check GP17 goes to EN12 and that the L293D has 5 V on both VS and VSS. - The motor only turns one way. This project
Check GP15 goes to IN1 and GP16 goes to IN2. Both are needed to reverse. - The reading jumps around or only covers part of the range. Potentiometer
Wire the two outer legs to 5 V and ground and the middle leg (the wiper) to an analog pin. Using the wrong two legs gives a dead or partial range. - Turning the knob does nothing, or the value is stuck at 0 or 1023. Potentiometer
Check that the wiper goes to an analog input (A0 to A5 on an Uno), not a digital pin. Make sure both ends are connected, since a floating end gives noise. - The motor is weak or does not turn, and the chip gets hot. Motor driver
The L293D gives about 600 mA per channel and drops about 1.4 V per side. Use a motor that fits, and for bigger motors pick another driver. - Nothing moves even though the inputs are right. Motor driver
Power both supply pins: VCC1 (pin 16) at 5 V for logic and VCC2 (pin 8) for the motor. Tie the enable pin high, and join all grounds. - The motor does not spin, or the pin gets hot or the board resets when it is wired straight to a GPIO pin. DC motor
A pin gives about 20 mA and a motor needs far more. Drive it through a transistor or motor driver, with its own supply and a shared ground. - The transistor or pin is damaged by spikes when the motor stops. DC motor
Put a flyback diode across the motor, cathode to the positive side. A motor is a coil and kicks back voltage when switched off. Add a 0.1 uF capacitor across the motor terminals to cut noise.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.