Smart IoT Motor Control System Using ESP32 Dev Board and L298N Motor Driver Module

Smart IoT Motor Control System – ESP32 & L298N | MakeMindz
🚀 New projects weekly — Explore all tutorials at MakeMindz.com
🤖 Advanced Robotics Project

Smart IoT Motor Control with ESP32 & L298N

A wireless Bluetooth robot with PS3 controller input, dual DC motors, OLED score display, laser shooting system, and relay module — all in one project.

🧠 Advanced
⏱ ~3–4 Hours
📡 Bluetooth PS3
🖥 ESP32 Dev Board
⚡ L298N Driver
🎮 Shooting Game

Project Overview

This project is a feature-rich wireless motor automation system built around the ESP32. Using a PlayStation 3 controller over Bluetooth, you can drive dual DC motors, activate a laser shooter, monitor a live score on an OLED display, and switch external loads via a relay — all from a battery-powered portable robot chassis.

📡
Bluetooth Control
PS3 D-pad drives motors wirelessly via ESP32 Bluetooth stack.
Dual Motor PWM
L298N H-bridge controls speed and direction of both DC motors.
🖥
OLED Display
SSD1306 I²C OLED shows game title, live score, and game over.
🔴
Laser Shooter
Circle button fires laser for 2s; LM393 sensors detect hits and score.
🔌
Relay Output
Switch external loads — bulbs, pumps, or motors — from the controller.
🔋
Battery Powered
Fully portable with onboard voltage regulation for stable 5V.
💡 What you'll learn ESP32 Bluetooth classic with PS3 library, ESP32 LEDC PWM for motors, I²C OLED with Adafruit GFX, laser/photoresistor interfacing, and game state logic in embedded C++.

Components Required

ComponentFunctionQuantity
🧠ESP32 Dev BoardMain controller – Wi-Fi & Bluetooth1
L298N Motor DriverControls 2 DC motors1
⚙️Dual DC Geared MotorsRobot wheel drive2
🖥0.96" OLED SSD1306 (I²C)Score & status display1
🎮PS3 ControllerWireless Bluetooth control1
🔌Relay Module (1-CH)External appliance switching1
🔴Laser Module (5mW)Shooting mechanism1
💡LM393 Photosensor ×2Laser hit detection / scoring2
🔔Active BuzzerAudio alerts1
🔋Li-ion Battery Pack (7.4V)Portable power supply1
🔧Connecting WiresCircuit wiringSet
📦 Required Arduino Libraries Install via Arduino Library Manager: Ps3Controller by jvpernis · Adafruit SSD1306 · Adafruit GFX Library · Wire (built-in)

Circuit Diagram

The ESP32 connects to the L298N via digital + PWM pins, to the OLED over I²C, and reads the two LM393 sensors on digital inputs. The laser is driven by a PWM analog output. The relay is driven from a separate digital pin.

ESP32 Dev Board Xtensa LX6 3V3 GND GPIO21(SDA) GPIO22(SCL) GPIO14 GPIO16 GPIO18(Laser) GPIO23(PWMA) GPIO19(AIN2) GPIO5(AIN1) GPIO15(PWMB) GPIO2(BIN2) GPIO4(BIN1) GPIO→Relay SHOOTING GAME 05 OLED SSD1306 VCC→3V3 GND SDA→21 SCL→22 LM393 Sensor ×2 Laser Hit Detection OUT1→GPIO14 OUT2→GPIO16 Laser Module GPIO18 PWM L298N Motor Driver H-Bridge A H-Bridge B ENA←PWMA IN1←AIN1 IN2←AIN2 ENB←PWMB IN3←BIN1 IN4←BIN2 Motor A Left Wheel Motor B Right Wheel Relay Module IN←ESP32 GPIO PS3 Controller Bluetooth Classic MAC: 98:43:FA:59:56:AE Legend I²C (OLED) Motor Control Sensor Inputs Laser PWM Bluetooth

Pin Connection Table

ComponentComponent PinESP32 GPIOType
OLED SSD1306VCC3V3Power
OLED SSD1306GNDGNDGround
OLED SSD1306SDAGPIO 21I²C Data
OLED SSD1306SCLGPIO 22I²C Clock
LM393 Sensor 1DO (Digital Out)GPIO 14Digital Input
LM393 Sensor 2DO (Digital Out)GPIO 16Digital Input
Laser ModuleSignalGPIO 18PWM Output
L298N Motor DriverENA (Motor A speed)GPIO 23PWM (Ch 3)
L298N Motor DriverIN1 (Motor A dir)GPIO 5Digital Output
L298N Motor DriverIN2 (Motor A dir)GPIO 19Digital Output
L298N Motor DriverENB (Motor B speed)GPIO 15PWM (Ch 4)
L298N Motor DriverIN3 (Motor B dir)GPIO 4Digital Output
L298N Motor DriverIN4 (Motor B dir)GPIO 2Digital Output
Relay ModuleIN (Signal)GPIO (any free)Digital Output

PS3 Controller Input Map

The ESP32 connects to the PS3 DualShock controller over Bluetooth Classic using the Ps3Controller library. Use the D-pad for movement and special buttons for actions.

🔼
D-pad Up
Move Forward
🔽
D-pad Down
Move Backward
D-pad Left
Turn Left
D-pad Right
Turn Right
Circle (O)
Fire Laser (2s)
🛑
No button
Stop Motors
📡 Bluetooth Pairing Change the MAC address in Ps3.begin("98:43:FA:59:56:AE") to match your ESP32's actual Bluetooth address. Use SixaxisPairTool on PC to pair the PS3 controller to your ESP32's MAC.

Step-by-Step Instructions

1

Set Up Arduino IDE for ESP32

In Arduino IDE, go to File → Preferences and add the ESP32 board URL: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json. Then install the ESP32 board package via Board Manager. Select ESP32 Dev Module.

2

Install Required Libraries

Open Library Manager (Ctrl+Shift+I) and install:

  • Ps3Controller by jvpernis — Bluetooth PS3 input
  • Adafruit SSD1306 — OLED driver
  • Adafruit GFX Library — graphics primitives
3

Wire the OLED Display (I²C)

Connect the 0.96" SSD1306 OLED: VCC → 3V3, GND → GND, SDA → GPIO21, SCL → GPIO22. The default I²C address is 0x3C — if your OLED doesn't initialise, try 0x3D.

4

Connect the L298N Motor Driver

Wire the ESP32 PWM and direction pins to the L298N. Power the L298N from the 7.4V battery directly (the onboard 5V regulator on L298N can optionally power the ESP32 logic). Connect each motor to MOTOR A and MOTOR B terminals.

  • ENA ← GPIO23 (PWM channel 3)
  • IN1 ← GPIO5, IN2 ← GPIO19 (Motor A direction)
  • ENB ← GPIO15 (PWM channel 4)
  • IN3 ← GPIO4, IN4 ← GPIO2 (Motor B direction)
5

Set Up LM393 Photosensors (Laser Detection)

Mount two LM393 modules facing the laser module at your target positions. Connect DO pin of sensor 1 to GPIO14 and sensor 2 to GPIO16. VCC → 3V3, GND → GND. Adjust the potentiometer on each LM393 so the LED lights when laser hits it.

6

Wire the Laser Module

Connect the laser signal pin to GPIO18. The code uses analogWrite to control brightness: idle at PWM 30 (~2.3V) and full fire at PWM 230 (~3.2V). Never look directly into the laser.

⚠️ Laser Safety Use only Class 2 (≤1mW visible) laser modules. Never point at eyes. Mount on the robot chassis facing away from users.
7

Pair the PS3 Controller via Bluetooth

Download SixaxisPairTool on your PC. Connect the PS3 controller via USB and set the master Bluetooth address to your ESP32's MAC. Upload the code with your MAC in Ps3.begin("XX:XX:XX:XX:XX:XX"). Press PS button to connect.

8

Upload Code & Test

Upload the code at 115200 baud. Open Serial Monitor to see connection and movement logs. Test each D-pad direction, check motor rotation, and press ⭕ to test the laser. Adjust moveSpeed (default 200) and turnSpeed (default 180) for your motors.

9

Set Up the Shooting Game

Place the two LM393 sensors as targets. The OLED displays the score — each laser hit increments by 1 (with 2s cooldown). At score >50, "YOU LOSE" appears. Reset by power-cycling the ESP32. Adjust untouchableTime for difficulty.

Full Arduino Code (ESP32)

Complete production-ready sketch. Uses ESP32 LEDC PWM for motor speed, the Ps3Controller library for Bluetooth input, and Adafruit SSD1306 for OLED.

ESP32 Arduino (.ino)
/*
 * Smart IoT Motor Control System
 * ESP32 Dev Board + L298N Motor Driver
 *
 * Author : MakeMindz (makemindz.com)
 * Control: PS3 DualShock via Bluetooth Classic
 * Display: 0.96" OLED SSD1306 (I2C 0x3C)
 * Game   : Laser shooting with LM393 photosensors
 *
 * D-pad Up/Down/Left/Right → Motor direction
 * Circle (O)               → Fire laser (2 seconds)
 * Score > 50               → Game Over ("YOU LOSE")
 */

#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Ps3Controller.h>

// ── OLED Config ──────────────────────────────
#define OLED_WIDTH  128
#define OLED_HEIGHT 64
#define OLED_ADDR   0x3C
Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT, &Wire, -1);

// ── Pin Definitions ──────────────────────────
#define PHOTORESISTOR_1_PIN  14
#define PHOTORESISTOR_2_PIN  16
#define LASER_PIN            18
#define PWMA_PIN             23
#define AIN2_PIN             19
#define AIN1_PIN              5
#define PWMB_PIN             15
#define BIN2_PIN              2
#define BIN1_PIN              4

// ── PWM Parameters ───────────────────────────
const int motorFreq       = 1000;  // 1 kHz PWM frequency
const int motorResolution = 8;     // 8-bit (0–255)
const int motorAChannel   = 3;
const int motorBChannel   = 4;

// ── Speed Settings ───────────────────────────
const int moveSpeed = 200;  // 0–255, adjust for your motors
const int turnSpeed = 180;

// ── Game State ───────────────────────────────
int           val1, val2;
int           score          = 0;
unsigned long lastScoreTime  = 0;
const unsigned long untouchableTime = 2000;

// ── Laser State ──────────────────────────────
bool          laserOn         = false;
unsigned long laserOffTime    = 0;
const unsigned long laserFullPowerTime = 2000;

// ── Motor Movement ───────────────────────────
void moveMotors(int mtrAspeed, int mtrBspeed, bool forward) {
  if (!forward) {
    digitalWrite(AIN1_PIN, HIGH); digitalWrite(AIN2_PIN, LOW);
    digitalWrite(BIN1_PIN, HIGH); digitalWrite(BIN2_PIN, LOW);
  } else {
    digitalWrite(AIN1_PIN, LOW);  digitalWrite(AIN2_PIN, HIGH);
    digitalWrite(BIN1_PIN, LOW);  digitalWrite(BIN2_PIN, HIGH);
  }
  ledcWrite(motorAChannel, mtrAspeed);
  ledcWrite(motorBChannel, mtrBspeed);
}

// ── PS3 Controller Callback ──────────────────
void notify() {
  if      (Ps3.data.button.up)    moveMotors(moveSpeed, moveSpeed, true);
  else if (Ps3.data.button.down)  moveMotors(moveSpeed, moveSpeed, false);
  else if (Ps3.data.button.left)  moveMotors(0, moveSpeed, true);
  else if (Ps3.data.button.right) moveMotors(moveSpeed, 0, true);
  else                            moveMotors(0, 0, true);

  if (Ps3.data.button.circle && !laserOn) {
    laserOn = true;
    analogWrite(LASER_PIN, 230);  // Full power ~3.2V
    laserOffTime = millis() + laserFullPowerTime;
    Serial.println("Laser → FIRE");
  }
}

void onConnect() { Serial.println("PS3 Connected!"); }

// ── PS3 Setup ────────────────────────────────
void setupPS3Controller() {
  Ps3.attach(notify);
  Ps3.attachOnConnect(onConnect);
  Ps3.begin("98:43:FA:59:56:AE");  // ← Change to your ESP32 MAC

  pinMode(PWMA_PIN, OUTPUT); pinMode(PWMB_PIN, OUTPUT);
  pinMode(AIN1_PIN, OUTPUT); pinMode(AIN2_PIN, OUTPUT);
  pinMode(BIN1_PIN, OUTPUT); pinMode(BIN2_PIN, OUTPUT);

  ledcSetup(motorAChannel, motorFreq, motorResolution);
  ledcSetup(motorBChannel, motorFreq, motorResolution);
  ledcAttachPin(PWMA_PIN, motorAChannel);
  ledcAttachPin(PWMB_PIN, motorBChannel);
  Serial.println("PS3 Controller Ready.");
}

// ── OLED Init ────────────────────────────────
void initDisplay() {
  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
    Serial.println(F("SSD1306 failed!")); for (;;);
  }
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(15, 2);
  display.println("Shooting Game");
  display.display();
  delay(2000);
}

// ── Read Sensors ─────────────────────────────
void readPhotoresistors() {
  val1 = digitalRead(PHOTORESISTOR_1_PIN);
  val2 = digitalRead(PHOTORESISTOR_2_PIN);
}

// ── Update Game State ────────────────────────
void updateGameState() {
  unsigned long now = millis();
  if (now - lastScoreTime > untouchableTime) {
    if (val1 == 0 || val2 == 0) {
      score++;
      lastScoreTime = now;
      Serial.print("Score: "); Serial.println(score);
    }
  }
}

// ── Update OLED ──────────────────────────────
void updateDisplay() {
  display.clearDisplay();
  if (score > 50) {
    display.setTextSize(2);
    display.setCursor(0, 18);
    display.println("YOU LOSE");
  } else {
    display.setTextSize(6);
    display.setCursor(28, 13);
    display.println(score);
  }
  display.display();
}

// ── Laser Control ────────────────────────────
void controlLaser() {
  if (laserOn && millis() >= laserOffTime) {
    laserOn = false;
    analogWrite(LASER_PIN, 30);  // Idle ~2.3V
    Serial.println("Laser → IDLE");
  }
}

// ── Setup ────────────────────────────────────
void setup() {
  Serial.begin(115200);
  pinMode(PHOTORESISTOR_1_PIN, INPUT);
  pinMode(PHOTORESISTOR_2_PIN, INPUT);
  pinMode(LASER_PIN, OUTPUT);
  initDisplay();
  setupPS3Controller();
  analogWrite(LASER_PIN, 30);  // Start in idle mode
}

// ── Main Loop ────────────────────────────────
void loop() {
  if (!Ps3.isConnected()) return;
  readPhotoresistors();
  updateGameState();
  updateDisplay();
  controlLaser();
  delay(10);  // Reduce CPU load
}

Simulation Links

🖥 Simulate Before You Build

Use Wokwi or Cirkit Designer to test motor logic, OLED rendering, and sensor interactions before assembling hardware. Note that Bluetooth PS3 pairing requires physical hardware.

💡 Tip: In Wokwi, paste the diagram.json into the Diagram tab, then paste the .ino code. Use keyboard input to simulate D-pad when PS3 is not available.

Possible Upgrades

Wi-Fi web dashboard control
Firebase / MQTT cloud logging
ESP32-CAM FPV camera
GPS real-time tracking
Autonomous obstacle avoidance
AI object tracking (TensorFlow Lite)
HC-SR04 ultrasonic detection
Voice control (Google Assistant)
Custom Android / iOS app
Line follower mode

Key Features

📡
Fully Wireless
No USB tether — pure Bluetooth PS3 control at up to 10m range.
Precise PWM Speed
8-bit LEDC PWM at 1kHz for smooth, quiet motor speed control.
🎮
Built-in Game
Laser shooting game with live OLED score and game-over logic.
🔌
Expandable I/O
Relay output for external loads; ESP32 has plenty of free GPIOs.
🏆
Exhibition Ready
Impressive live demo for science fairs and robotics competitions.
🔋
Battery Portable
7.4V Li-ion pack with regulated 5V for stable operation anywhere.

Related Projects on MakeMindz

MakeMindz Electronics tutorials, IoT projects & maker guides — makemindz.com © 2026 MakeMindz · All rights reserved

Comments

try for free