When tackling autonomous raspberry pi robot projects, the gap between a bench prototype and a rover that actually navigates a room usually comes down to three things: power delivery, logic-level matching, and sensor polling rates. The Raspberry Pi 5 (8GB) is the current baseline for edge-compute robotics in 2026, offering enough PCIe and USB 3.0 bandwidth to handle simultaneous LIDAR sweeps and motor control without dropping packets.
This guide walks through building a 2-wheel drive (2WD) autonomous rover using a Pi 5, a Slamtec RPLiDAR A1M8, and a high-efficiency TB6612FNG motor driver. We will cover the exact bill of materials, hardware pin mapping, and provide a complete, copy-pasteable Python script using gpiozero and the rplidar library.
Hardware Spec Sheet & Bill of Materials
Before cutting wires, verify your components. The most common failure in Pi-based robots is browning out the compute module when motors draw stall current. The BOM below assumes a 3S LiPo power architecture with isolated 5V regulation for the Pi.
| Component | Exact Model / Variant | Key Specification | Est. Cost (2026) |
|---|---|---|---|
| Compute | Raspberry Pi 5 (8GB) | Quad-core Cortex-A76, 2.4GHz, 3.3V logic | $80.00 |
| Motor Driver | Pololu TB6612FNG Dual | 1.2A continuous per channel, 3.3V VCC compatible | $12.50 |
| LIDAR Sensor | Slamtec RPLiDAR A1M8 | 360° sweep, 8000 samples/sec, 115200 baud UART | $99.00 |
| Drive Motors | JGB37-520 12V 30RPM | 150mA no-load, 1.2A stall, metal gear | $24.00 (pair) |
| Main Battery | Zeee 3S 11.1V 2200mAh LiPo | 50C discharge, XT60 connector | $28.00 |
| Step-Down Regulator | Pololu D24V50F5 | 5V 5A output, 7-38V input (Powers Pi 5 & LIDAR) | $16.00 |
Pin Mapping & Power Distribution
The TB6612FNG is a MOSFET-based driver, vastly superior to the ancient L298N bipolar junction transistor drivers that waste 2V-3V as heat. Because the Pi 5 operates at 3.3V logic, the TB6612FNG is ideal: its VCC pin accepts 2.7V to 5.5V for logic thresholds. Wire VCC to the Pi's 3.3V pin (Pin 1).
Note: The Raspberry Pi 5 routes hardware PWM to specific GPIO pins. We use GPIO 12 and 13 for motor speed control to avoid the latency of software PWM. (Reference: Raspberry Pi Hardware Documentation).
| TB6612FNG Pin | Wired To (Pi 5 GPIO / Power) | Function |
|---|---|---|
| VCC | Pi Pin 1 (3.3V) | Logic level reference |
| GND | Pi Pin 6 (GND) | Common ground |
| PWMA | Pi GPIO 12 (Pin 32) | Left Motor Speed (Hardware PWM0) |
| AIN1 / AIN2 | Pi GPIO 23 / GPIO 24 | Left Motor Direction |
| PWMB | Pi GPIO 13 (Pin 33) | Right Motor Speed (Hardware PWM1) |
| BIN1 / BIN2 | Pi GPIO 25 / GPIO 8 | Right Motor Direction |
| STBY | Pi 3.3V (Tied High) | Keeps driver active permanently |
| VMOT | 3S LiPo Positive (via XT60) | Motor power (11.1V - 12.6V) |
Python Motor Control & LIDAR Sweep Code
This script targets the Raspberry Pi 5 (8GB) running Raspberry Pi OS (64-bit, Bookworm or newer). It uses the gpiozero library for motor abstraction and the rplidar package for sensor polling. The logic implements a basic "bang-bang" obstacle avoidance: if a mass of points is detected within 400mm in the forward 90-degree arc, the rover halts and pivots.
Prerequisites: Run sudo apt install python3-gpiozero python3-rplidar and ensure your user is in the dialout group for serial access.
import time
import signal
import sys
from gpiozero import Motor
from rplidar import RPLidar
# --- Hardware Pin Definitions (Raspberry Pi 5 40-pin header) ---
# Left Motor (Channel A)
LEFT_FWD = 23
LEFT_BWD = 24
LEFT_EN = 12 # Hardware PWM0
# Right Motor (Channel B)
RIGHT_FWD = 25
RIGHT_BWD = 8
RIGHT_EN = 13 # Hardware PWM1
# Initialize Motors
left_motor = Motor(forward=LEFT_FWD, backward=LEFT_BWD, enable=LEFT_EN)
right_motor = Motor(forward=RIGHT_FWD, backward=RIGHT_BWD, enable=RIGHT_EN)
# Initialize LIDAR (Assuming USB adapter maps to /dev/ttyUSB0)
LIDAR_PORT = '/dev/ttyUSB0'
lidar = RPLidar(LIDAR_PORT)
def clean_shutdown(signum, frame):
"""Safely stop motors and LIDAR on Ctrl+C or system kill."""
print("\n[!] Shutdown signal received. Stopping rover...")
left_motor.stop()
right_motor.stop()
lidar.stop_motor()
lidar.disconnect()
sys.exit(0)
signal.signal(signal.SIGINT, clean_shutdown)
signal.signal(signal.SIGTERM, clean_shutdown)
def navigate():
"""Main control loop: process LIDAR scans and adjust motor vectors."""
print("[*] Starting LIDAR sweep and motor control...")
# Base speed (0.0 to 1.0)
base_speed = 0.45
try:
for scan in lidar.iter_scans():
obstacle_detected = False
# scan returns list of tuples: (quality, angle, distance)
for _, angle, distance in scan:
# Check forward arc (315° to 360° and 0° to 45°)
if (angle >= 315 or angle <= 45) and distance < 400:
obstacle_detected = True
break
if obstacle_detected:
# Halt and pivot right to avoid
left_motor.forward(base_speed * 0.8)
right_motor.backward(base_speed * 0.5)
else:
# Drive forward
left_motor.forward(base_speed)
right_motor.forward(base_speed)
except Exception as e:
print(f"[X] Runtime Error: {e}")
clean_shutdown(None, None)
if __name__ == '__main__':
navigate()
Debugging: First Three Things to Check When It Fails
Robotics code rarely fails on the first compile; it fails in the physical layer. If your rover is dead on arrival, run through these three checks before rewriting your Python logic.
1. The Serial Permission Denial
Exact Error String: serial.serialutil.SerialException: [Errno 13] Permission denied: '/dev/ttyUSB0'
Ranked Causes:
- User not in dialout group: The Pi defaults to restricting serial ports. Fix:
sudo usermod -a -G dialout $USER, then reboot. - USB Cable is charge-only: The RPLiDAR USB pigtail lacks data lines. Swap to a verified data-sync micro-USB cable.
- Port mapped to ttyUSB1: Unplug and replug the LIDAR, then run
dmesg | grep ttyto verify the exact node.
2. The PWM Pin Mismatch
Exact Error String: gpiozero.exc.PinPWMUnsupported: Pin 18 does not support PWM
Ranked Causes:
- Using non-hardware PWM pins without pigpiod: If you changed GPIO 12/13 to GPIO 18,
gpiozerotries to use software PWM. You must start the daemon:sudo systemctl enable pigpiod && sudo systemctl start pigpiod. - Pin physically shorted: A stray strand of copper from the motor direction wires is bridging the PWM pin to 5V, triggering the Pi's internal protection and disabling the pin block.
3. The LIDAR Body Size Exception
Exact Error String: rplidar.rplidar.RPLidarException: Wrong body size
Ranked Causes:
- Baud rate mismatch: The A1M8 defaults to 115200. If your USB-to-Serial adapter is hardcoded to 9600, the Python library reads garbage bytes and throws a size error. Verify adapter specs.
- Insufficient 5V current to LIDAR motor: The A1M8 internal motor draws ~150mA on spin-up. If powered from a Pi USB port that is current-limited (due to non-PD power supply), the motor stutters, corrupting the UART data stream mid-packet.
Extending vs. Simplifying the Build
Not every project needs a $250 BOM, and some need significantly more compute. Here is how to scale this architecture based on your actual goals.
Drop the RPLiDAR and swap the Pi 5 for a Raspberry Pi Zero 2 W. Replace the LIDAR with an HC-SR04 ultrasonic sensor mounted on an SG90 micro servo. You will need a logic level converter (like a BSS138 MOSFET bi-directional board) to step the Pi Zero's 3.3V GPIO up to the HC-SR04's 5V trigger requirement, and step the 5V echo down to 3.3V for the Pi. This setup is perfect for basic line-following or maze-solving where mapping isn't required.
Extend the Build (Target: Advanced SLAM & Vision)
If you want to move from simple obstacle avoidance to true Simultaneous Localization and Mapping (SLAM), integrate ROS 2 Jazzy running on Ubuntu 24.04 Server. Add an OAK-D Lite spatial camera connected via USB 3.0 for depth perception and object classification. You will need to upgrade the motor driver to a RoboClaw 2x15A to handle the heavier chassis and implement quadrature encoder feedback from the JGB37-520 motors for precise odometry. (Reference: Pololu TB6612FNG Datasheet & Alternatives).






