To build a responsive remote control car with Raspberry Pi, use the Raspberry Pi Zero 2 W paired with a TB6612FNG dual H-bridge motor driver and a 2S LiPo battery. This specific combination eliminates the massive 1.5V voltage drop inherent to older L298N drivers, keeps the chassis light enough for standard TT gear motors to actually move, and provides enough processing headroom for low-latency UDP control.
This guide provides the exact hardware spec sheet, pin mapping, and a complete, compilable Python UDP server script using the gpiozero library. We will also cover the power architecture required to prevent brownouts and debug the three most common failure modes you will encounter on the bench.
Decision Tree: Choosing Your Motor Driver
The biggest mistake in Pi-based RC builds is picking a motor driver based on price rather than voltage drop and switching frequency. Here is the decision matrix for standard 6V TT motors.
| Driver IC | Topology | Voltage Drop | Continuous Current | Verdict |
|---|---|---|---|---|
| L298N | Bipolar BJT | ~1.5V to 2.0V | 2.0A per channel | Reject. Wastes battery as heat; starves 6V motors. |
| DRV8833 | MOSFET | ~0.2V | 1.5A per channel | Acceptable, but max input voltage is 10.8V (risky for fully charged 2S LiPo at 8.4V + spikes). |
| TB6612FNG | MOSFET | ~0.5V | 1.2A (3.2A peak) | Default Pick. High efficiency, handles 15V max, perfect match for TT motor stall currents. |
Hardware Spec Sheet & Pin Mapping
This build targets the Raspberry Pi Zero 2 W running Raspberry Pi OS Bookworm Lite (64-bit). The Zero 2 W is chosen over the Pi 4 because its lower idle current (~120mA vs ~600mA) drastically extends runtime on a small LiPo pack, and its physical footprint fits standard 2WD acrylic chassis kits without overhanging.
Parts List (2026 Pricing)
- Compute: Raspberry Pi Zero 2 W (~$15) with soldered 2x20 male header.
- Motor Driver: TB6612FNG Dual Motor Driver Breakout (Pololu or SparkFun variant, ~$8).
- Chassis & Motors: Generic 2WD Acrylic Kit with 130-size TT motors and 65mm wheels (~$15).
- Power: Zeee 2S 7.4V 1300mAh LiPo with XT60 connector (~$18).
- Regulation: LM2596 Step-Down Buck Converter module (~$3).
- Wiring: 18 AWG silicone wire for power, 24 AWG stranded for logic.
GPIO Pin Mapping (BCM Numbering)
The TB6612FNG requires a standby (STBY) pin to be pulled HIGH to enable the H-bridges. We handle this via a dedicated GPIO pin rather than tying it to VCC, allowing the Pi to hard-disable the motors during software crashes.
| TB6612FNG Pin | Pi Zero 2 W GPIO (BCM) | Function |
|---|---|---|
| VCC | 3.3V (Pin 1) | Logic level reference |
| GND | GND (Pin 6) | Common ground |
| STBY | GPIO 24 | Enable/Disable driver |
| PWMA | GPIO 12 | Left motor PWM speed |
| AIN1 | GPIO 17 | Left motor direction 1 |
| AIN2 | GPIO 27 | Left motor direction 2 |
| PWMB | GPIO 13 | Right motor PWM speed |
| BIN1 | GPIO 22 | Right motor direction 1 |
| BIN2 | GPIO 23 | Right motor direction 2 |
Power Architecture: Preventing Pi Brownouts
Never power the Pi Zero 2 W directly from the motor driver's 5V output, and never share a raw LiPo feed without regulation. TT motors generate massive inductive voltage spikes when reversing direction, which will corrupt the Pi's SD card or trigger the onboard brownout detector (lightning bolt icon).
- Primary Source: Connect the 2S LiPo (8.4V full, 6.0V empty) to the TB6612FNG VMOT pin and the LM2596 buck converter input.
- Regulation: Use a multimeter to adjust the LM2596 potentiometer until the output reads exactly 5.1V. Do this before connecting the Pi.
- Decoupling: Solder a 470µF electrolytic capacitor across the buck converter's output terminals. This acts as a local energy reservoir to absorb motor-induced voltage sags.
- Connection: Feed the 5.1V output directly to the Pi's 5V and GND GPIO pins (bypassing the USB micro port's polyfuse to eliminate an unnecessary voltage drop point).
The Control Code: UDP Server with gpiozero
We use raw UDP sockets instead of TCP or HTTP/WebSockets for the control link. UDP eliminates the handshake overhead and TCP retransmission delays that cause 'laggy' steering. The Pi listens for JSON payloads containing left and right motor speeds (-1.0 to 1.0).
Target Board: Raspberry Pi Zero 2 W | OS: Bookworm Lite | Library: gpiozero (pre-installed)
import socket
import json
from gpiozero import Motor, PWMOutputDevice
from signal import pause
# --- PIN DEFINITIONS (BCM) ---
# Left Motor (A)
LEFT_FWD = 17
LEFT_BWD = 27
LEFT_PWM = 12
# Right Motor (B)
RIGHT_FWD = 22
RIGHT_BWD = 23
RIGHT_PWM = 13
# Driver Enable
STBY_PIN = 24
# Initialize Motors (gpiozero handles PWM on the enable pins)
left_motor = Motor(forward=LEFT_FWD, backward=LEFT_BWD, pwm=True)
right_motor = Motor(forward=RIGHT_FWD, backward=RIGHT_BWD, pwm=True)
# TB6612FNG requires STBY HIGH to operate
stby = PWMOutputDevice(STBY_PIN)
stby.on()
UDP_IP = '0.0.0.0'
UDP_PORT = 5005
def setup_socket():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# SO_REUSEADDR prevents Errno 98 on quick script restarts
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((UDP_IP, UDP_PORT))
return sock
def drive(left_speed, right_speed):
# Clamp values to valid gpiozero range
left_speed = max(-1.0, min(1.0, left_speed))
right_speed = max(-1.0, min(1.0, right_speed))
if left_speed >= 0:
left_motor.forward(left_speed)
else:
left_motor.backward(abs(left_speed))
if right_speed >= 0:
right_motor.forward(right_speed)
else:
right_motor.backward(abs(right_speed))
if __name__ == '__main__':
try:
sock = setup_socket()
print(f'Listening on UDP {UDP_IP}:{UDP_PORT}')
while True:
data, addr = sock.recvfrom(1024)
try:
cmd = json.loads(data.decode('utf-8'))
drive(cmd.get('L', 0), cmd.get('R', 0))
except json.JSONDecodeError:
print('Invalid JSON payload received')
except OSError as e:
print(f'Socket Error: {e}')
except KeyboardInterrupt:
print('\nStopping motors and exiting.')
finally:
# Safe shutdown sequence
left_motor.stop()
right_motor.stop()
stby.off() # Hard disable the H-bridges
print('Motors disabled. STBY pulled LOW.')
Debugging: When the Motors Don't Spin
If you send UDP packets but the chassis sits dead, do not start rewriting code. Hardware and permission faults account for 95% of Pi RC failures.
The First Three Things to Check
- STBY Pin State: Measure the voltage on the TB6612FNG STBY pin with a multimeter. It must read ~3.3V. If it reads 0V, your H-bridges are internally disabled. Check your GPIO 24 wiring.
- VMOT vs VCC: Ensure the LiPo power is connected to VMOT (motor power), not VCC (logic power). VCC must connect to the Pi's 3.3V pin. Swapping these will instantly fry the Pi's 3.3V regulator.
- UFW Firewall: If the Python script runs but the Pi ignores your PC's UDP packets, the Pi's firewall is blocking port 5005. Run
sudo ufw allow 5005/udp.
Exact Error Strings & Ranked Causes
Error 1: OSError: [Errno 98] Address already in use
- Cause A (Most Likely): A ghost instance of your Python script is still running in the background from a previous SSH session, holding port 5005. Fix: Run
sudo lsof -i :5005and kill the PID. - Cause B: Missing
SO_REUSEADDRsocket option (already included in the provided code to prevent this).
Error 2: gpiozero.exc.GPIOPinInUse: pin 17 is already in use
- Cause A: Another library (like
RPi.GPIO) or a background service (likepigpiod) has claimed the pin. Fix: Stop conflicting services viasudo systemctl stop pigpiod. - Cause B: You wired a peripheral to the physical pin but mapped the wrong BCM number in the code. Verify BCM vs Physical pinout.
Extending or Simplifying the Build
Depending on your end goal, you can strip this build down to its bare essentials or scale it up into an FPV rover.
How to Simplify (The 'Weekend Cruiser' Route)
If you want to eliminate the buck converter and LiPo safety overhead, swap the 2S LiPo and LM2596 for a standard 5V 2A USB power bank. Feed the power bank's USB cable directly into the Pi Zero 2 W's micro-USB port. Trade-off: You must wire the TB6612FNG VMOT to a separate 4x AA battery pack (6V). You cannot run the motors and the Pi from the same 5V USB power bank; the motor spikes will reboot the Pi instantly.
How to Extend (The 'FPV Rover' Route)
To add camera-based First Person View (FPV) steering:
- Upgrade to a Raspberry Pi 4 (2GB) to handle H.264 video encoding without dropping UDP control packets.
- Add a Pi Camera Module V2 and use the
libcamera-vidpipeline to stream video over TCP port 8554. - Swap the fixed TT motors for continuous-rotation servos controlled via a PCA9685 I2C PWM board. This frees up the Pi's hardware PWM pins and provides much finer low-speed control than DC gear motors.
For authoritative reference on motor class implementations, consult the gpiozero Motor documentation. For detailed electrical characteristics and truth tables for the driver IC, review the Pololu TB6612FNG breakout datasheet. Always verify your power supply tolerances against the official Raspberry Pi power supply guidelines before applying voltage to the GPIO header.






