The Raspberry Pi GPIO pins output 3.3V logic and can safely source only about 16mA per pin (with a 50mA total limit across all pins). A standard DC gearmotor draws 150mA to 2A under load. Connecting a motor directly to the Pi will instantly fry the GPIO header or trigger the Pi's polyfuse. To successfully integrate raspberry pi and motors, you must use a motor driver IC (like the L298N for DC motors or DRV8825 for steppers) to isolate the low-voltage logic from the high-current motor power, while sharing a common ground.

Spec Sheet & Parts List

This build targets the Raspberry Pi 4 Model B (4GB) running Raspberry Pi OS (Bookworm, 64-bit). While the Pi 5 is excellent, its transition to the RP1 chip requires different GPIO libraries (lgpio), making the Pi 4 the most stable baseline for standard gpiozero tutorials in 2026.

Component Exact Variant / Model Role in Circuit Est. Price
Microcontroller Raspberry Pi 4 Model B (4GB) Logic and PWM generation $55.00
Motor Driver (DC) L298N Dual H-Bridge Module High-current switching for DC motors $6.50
Motor Driver (Stepper) DRV8825 Carrier (Pololu 2133) Microstepping controller for NEMA 17 $8.00
DC Motor TT Gearmotor (3V-6V, 1:48 ratio) Actuator / drive wheel $3.00
Power Supply 12V 5A Switching PSU (or 3S 18650 pack) Isolated high-current motor power $14.00

Pin Mapping & Wiring the L298N

The L298N uses bipolar Darlington transistor pairs, which introduce a voltage drop of roughly 1.5V to 2V. If you supply 12V to the motor power terminals, your motor will only see about 10V. Keep this in mind when calculating RPM and torque.

GPIO to L298N Pinout

Raspberry Pi 4 GPIO Physical Pin # L298N Terminal Function
GPIO 17 11 IN1 Motor A Direction 1
GPIO 27 13 IN2 Motor A Direction 2
GPIO 22 15 ENA (PWM) Motor A Speed Control
GND 9 GND Common Logic Ground
⚠️ Critical Wiring Step: You MUST connect the Raspberry Pi GND to the L298N GND. Without a common ground reference, the 3.3V logic signals from the Pi will float, causing erratic motor behavior or failing to trigger the optocouplers/H-bridge entirely.

Numbered Wiring Steps

  1. Motor Power: Connect your 12V power supply positive to the L298N 12V terminal, and negative to the GND terminal.
  2. Logic Power Jumper: If using a 12V supply, remove the 5V enable jumper cap on the L298N. The board will use its internal 7805 regulator to power its logic side. If using a 7V supply, leave the jumper on.
  3. Common Ground: Run a jumper wire from the Raspberry Pi physical Pin 9 (GND) to the L298N GND terminal.
  4. Logic Signals: Connect Pi GPIO 17 to IN1, GPIO 27 to IN2, and GPIO 22 to ENA. Ensure the ENA jumper cap on the L298N is removed so the Pi can control PWM speed.
  5. Motor Terminals: Connect the two TT gearmotor wires to OUT1 and OUT2. Polarity does not matter; swapping them simply reverses the forward/backward logic.

Complete Python Control Code

This script uses gpiozero, the modern standard for Raspberry Pi GPIO control, replacing the deprecated RPi.GPIO library. It targets the Pi 4 and includes hardware cleanup and exception handling.

from gpiozero import Motor, PWMOutputDevice
from time import sleep
import sys

# Pin definitions for Raspberry Pi 4 Model B
FORWARD_PIN = 17
BACKWARD_PIN = 27
ENABLE_PIN = 22  # PWM pin for speed control

def main():
    try:
        # Initialize motor with explicit PWM enable pin
        # gpiozero handles hardware PWM fallback to software PWM automatically
        enable = PWMOutputDevice(ENABLE_PIN, frequency=1000)
        motor = Motor(forward=FORWARD_PIN, backward=BACKWARD_PIN, enable=enable)
        
        print('Motor initialized. Starting test sequence...')
        
        # Ramp up speed forward
        for speed in range(0, 11):
            current_speed = speed / 10.0
            enable.value = current_speed
            motor.forward()
            print(f'Forward at {current_speed * 100}% speed')
            sleep(0.5)
            
        sleep(1)
        
        # Reverse at half speed
        enable.value = 0.5
        motor.backward()
        print('Reversing at 50% speed')
        sleep(2)
        
        # Stop
        motor.stop()
        print('Motor stopped.')
        
    except KeyboardInterrupt:
        print('\nSequence interrupted by user.')
    except Exception as e:
        print(f'Hardware or Pin Factory Error: {e}')
        sys.exit(1)
    finally:
        # gpiozero handles cleanup on exit, but explicit stop is good practice
        if 'motor' in locals():
            motor.stop()
            print('GPIO resources released.')

if __name__ == '__main__':
    main()

Debugging: When the Motor Won't Spin

If your code runs but the motor remains dead, do not immediately blame the Pi. Follow these diagnostic steps.

The First Three Things to Check

  1. Common Ground Integrity: Use a multimeter in continuity mode. Probe the Raspberry Pi GND pin and the L298N GND terminal. It must read < 1 ohm. If it reads OL (open loop), your logic signals have no return path.
  2. Voltage Under Load: Measure the 12V power supply terminals on the L298N while the motor is trying to spin. A weak wall-wart supply will sag from 12V down to 4V under a 1A motor stall current, causing the L298N logic to brownout and shut off.
  3. The ENA Jumper Cap: If you left the metal jumper cap on the ENA pins on the L298N board, the board ties ENA directly to 5V. Your Pi PWM signal on GPIO 22 will be completely ignored. Remove the cap.

Exact Error Strings & Ranked Causes

When the Python script fails to launch, the terminal will throw specific exceptions. Here is how to fix them.

Error 1: gpiozero.exc.BadPinFactory: Unable to load any default pin factory!

  • Cause: You are running a headless, minimal install of Raspberry Pi OS Bookworm that lacks the underlying GPIO C-libraries.
  • Fix: Install the native pin factory backend by running sudo apt update && sudo apt install python3-rpi.gpio. (Note: If you are on a Pi 5, you must install python3-lgpio instead).

Error 2: RuntimeWarning: This channel is already in use, continuing anyway.

  • Cause: You are mixing legacy RPi.GPIO code with gpiozero, or a previous script crashed before calling GPIO.cleanup().
  • Fix: Stick strictly to gpiozero as shown in the code block above. It automatically registers exit handlers to release pins when the script terminates or crashes.

Extending and Simplifying the Build

Depending on your project scope, breadboarding raw L298N modules can become a wiring nightmare. Here is how to scale your build.

How to Simplify: Use an I2C Motor HAT

If you are building a robotics chassis with 4 DC motors, abandon the L298N. Use an I2C-based driver like the Adafruit DC and Stepper Motor HAT. It uses a dedicated PWM chip (PCA9685) communicating over just two I2C pins (SDA/SCL). This frees up your Pi's hardware PWM pins, eliminates messy jumper wires, and provides hardware-level flyback diode protection.

How to Extend: Closed-Loop Encoder Control

The L298N is open-loop; the Pi commands 50% PWM, but has no idea if the motor is actually spinning at 50% speed or stalling against a wall. To extend this, mount a quadrature optical encoder to the TT motor shaft. Wire the encoder A/B channels to Pi GPIO pins configured as gpiozero.RotaryEncoder. You can then implement a PID control loop in Python to adjust the PWM duty cycle dynamically, maintaining exact RPM regardless of battery voltage sag or terrain friction.

Frequently Asked Questions

Can I power a motor directly from the Raspberry Pi 5V pin?

No. The Raspberry Pi's 5V rail is fed either by the USB-C power supply or the internal polyfuse, which is typically rated for 1.5A to 2A total. The Pi's own CPU and RAM draw up to 1.2A under heavy load. If you connect a motor that draws 500mA directly to the 5V pin, the sudden inrush current will cause the 5V rail to sag below 4.6V, triggering an immediate brownout reboot. Always use an external power supply for the motors.

Why does my Raspberry Pi reboot when the motor starts?

This is caused by two phenomena: voltage sag and back-EMF. When a DC motor starts, it acts briefly as a dead short (stall current), pulling massive current and dropping the shared voltage rail. Furthermore, when the motor stops, its spinning mass generates a reverse voltage spike (back-EMF). If you lack flyback diodes (which the L298N includes internally, but raw MOSFET circuits do not), this spike feeds back into the Pi's ground plane, corrupting the CPU's power management IC and forcing a reset.

How do I control Raspberry Pi and motors using PWM for speed?

The gpiozero library handles PWM automatically when you use the Motor class. Under the hood, it attempts to use the Pi's hardware PWM channels for smooth, jitter-free signals. If you assign a pin that does not support hardware PWM (like GPIO 17), gpiozero seamlessly falls back to software PWM. For audio-sensitive projects where software PWM causes DAC noise, ensure your enable pins are mapped to hardware PWM-capable GPIOs (e.g., GPIO 12, 13, 18, or 19).

Is the L298N better than a MOSFET for Raspberry Pi motor control?

For basic bidirectional control, the L298N is easier to wire because it includes the H-bridge logic, flyback diodes, and optoisolation on one cheap board. However, the L298N is highly inefficient; its Darlington pairs waste 2V to 3V as heat. If you are building a battery-powered robot where efficiency matters, use a modern MOSFET-based driver like the TB6612FNG or DRV8871. They operate at near 100% efficiency with almost zero voltage drop, though they require slightly more careful wiring.