Raspberry Pi Motor Control
with L298N & Li-ion Battery
Control two DC motors using Raspberry Pi GPIO, an L298N dual H-bridge driver, and an 18650 Li-ion battery pack — ideal for robotics, autonomous vehicles, and STEM automation.
📋 Project Overview
The Raspberry Pi sends I2C commands to an Adafruit PCA9685 PWM breakout, which drives the L298N dual H-bridge. The 18650 battery pack powers the motors directly for portable, high-current operation.
Running full Linux alongside motor control means the Pi can handle camera feeds, network comms, and AI inference — all in one board.
🔩 Components Required
⚡ How It Works
The Pi runs Python → I2C to PCA9685 → PWM signals to L298N → motors spin. The 18650 pack powers only the motors; the Pi takes power separately via USB-C.
🔌 Circuit Diagram
🔗 Wiring Guide
| From | To | On | Purpose |
|---|---|---|---|
| GPIO 2 (SDA) | SDA | PCA9685 | I2C Data |
| GPIO 3 (SCL) | SCL | PCA9685 | I2C Clock |
| Pi 5V | VCC | PCA9685 | Logic power |
| Pi GND | GND | PCA9685 + L298N | Common ground |
| PCA CH0 | IN1 | L298N | Motor 1 dir A |
| PCA CH1 | IN2 | L298N | Motor 1 dir B |
| PCA CH2 | IN3 | L298N | Motor 2 dir A |
| PCA CH3 | IN4 | L298N | Motor 2 dir B |
| PCA CH4 | ENA | L298N | Motor 1 speed |
| PCA CH5 | ENB | L298N | Motor 2 speed |
| Battery + | 12V | L298N | Motor power |
| Battery − | GND | L298N | Common GND |
| OUT1 / OUT2 | Motor 1 terminals | DC Motor 1 | Drive |
| OUT3 / OUT4 | Motor 2 terminals | DC Motor 2 | Drive |
🪜 Step-by-Step Build
Collect your Raspberry Pi, L298N, PCA9685 breakout, two DC motors, 18650 battery pack (fully charged), breadboard, and jumper wires.
Run sudo raspi-config → Interface Options → I2C → Enable. Reboot, then verify with i2cdetect -y 1 — you should see address 0x40.
pip install adafruit-circuitpython-pca9685 RPi.GPIO
SDA → GPIO 2, SCL → GPIO 3, VCC → 5V, GND → GND. This offloads all PWM generation from the Pi's GPIO pins.
CH0→IN1, CH1→IN2, CH2→IN3, CH3→IN4, CH4→ENA, CH5→ENB. Double-check polarity before powering on.
Motor 1 → OUT1/OUT2. Motor 2 → OUT3/OUT4. Swapping wires on a motor reverses its spin direction.
Battery positive (+) → L298N 12V. Battery negative (−) → L298N GND. Connect L298N GND to Pi GND too.
Copy the Python script below to your Pi. Run python3 motor_control.py. Motor 1 forward, Motor 2 backward for 2 s, then stop.
Adjust the duty cycle value (0–65535 Python / 0–4095 C++). HALF ≈ 50% speed. Tweak for smooth, consistent motion.
💻 Code
Two versions provided. Both use PCA9685 over I2C to offload PWM from the Pi's GPIO pins for smoother control.
Python 3 (Raspberry Pi native)
#!/usr/bin/env python3 """ Raspberry Pi Motor Control — L298N via PCA9685 (I2C) MakeMindz.com """ import time import board import busio from adafruit_pca9685 import PCA9685 # ── I2C + PCA9685 setup ───────────────────────────────── i2c = busio.I2C(board.SCL, board.SDA) pca = PCA9685(i2c) pca.frequency = 1600 # 1.6 kHz PWM # Channel map (PCA9685 → L298N) MOTOR1_IN1 = pca.channels[0] MOTOR1_IN2 = pca.channels[1] MOTOR2_IN3 = pca.channels[2] MOTOR2_IN4 = pca.channels[3] MOTOR1_ENA = pca.channels[4] # Motor 1 speed MOTOR2_ENB = pca.channels[5] # Motor 2 speed # PWM duty cycles (16-bit: 0–65535) FULL = 0xFFFF HALF = 0x7FFF # 50% speed OFF = 0 def motor1_forward(speed=HALF): MOTOR1_ENA.duty_cycle = FULL MOTOR1_IN1.duty_cycle = speed MOTOR1_IN2.duty_cycle = OFF def motor2_backward(speed=HALF): MOTOR2_ENB.duty_cycle = FULL MOTOR2_IN3.duty_cycle = OFF MOTOR2_IN4.duty_cycle = speed def stop_all(): for ch in [MOTOR1_IN1, MOTOR1_IN2, MOTOR2_IN3, MOTOR2_IN4]: ch.duty_cycle = OFF try: while True: print("▶ Motor 1 Forward | Motor 2 Backward") motor1_forward() motor2_backward() time.sleep(2) print("■ Stop") stop_all() time.sleep(2) except KeyboardInterrupt: stop_all() pca.deinit() print("Stopped cleanly.")
Arduino / C++ version
/* * Raspberry Pi Motor Control — L298N via PCA9685 * MakeMindz.com */ #include <Wire.h> #include <Adafruit_PWMServoDriver.h> Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); // addr 0x40 #define MOTOR1_IN1 0 #define MOTOR1_IN2 1 #define MOTOR2_IN3 2 #define MOTOR2_IN4 3 #define MOTOR1_ENA 4 #define MOTOR2_ENB 5 #define PWM_FULL 4096 // 100% (always ON) #define PWM_HALF 2048 // 50% speed #define PWM_OFF 0 void setup() { Wire.begin(); pwm.begin(); pwm.setPWMFreq(1600); pwm.setPWM(MOTOR1_ENA, 0, PWM_FULL); pwm.setPWM(MOTOR2_ENB, 0, PWM_FULL); } void loop() { // Motor 1 Forward, Motor 2 Backward pwm.setPWM(MOTOR1_IN1, 0, PWM_HALF); pwm.setPWM(MOTOR1_IN2, 0, PWM_OFF); pwm.setPWM(MOTOR2_IN3, 0, PWM_OFF); pwm.setPWM(MOTOR2_IN4, 0, PWM_HALF); delay(2000); // Stop all pwm.setPWM(MOTOR1_IN1, 0, PWM_OFF); pwm.setPWM(MOTOR1_IN2, 0, PWM_OFF); pwm.setPWM(MOTOR2_IN3, 0, PWM_OFF); pwm.setPWM(MOTOR2_IN4, 0, PWM_OFF); delay(2000); }
🖥️ Simulate It
Test virtually before building. All three platforms support the L298N and motor control logic.
Comments
Post a Comment