Car Project 1 : ESP32 Wi-Fi Controlled RC Car

Overview

In this tutorial, we will build an RC car that can be controlled via a Wi-Fi-based web interface using an ESP32. The car will have forward, backward, left, and right movement controls, along with a speed control slider.

Required Components

  • ESP32 Development Board
  • L298N Motor Driver
  • 2 DC Motors
  • Battery Pack
  • Jumper Wires
  • Chassis with Wheels

Circuit Diagram

Diagram Representation:

  • Connect IN1 (L298N) to GPIO 19
  • Connect IN2 (L298N) to GPIO 32
  • Connect ENA (L298N) to GPIO 33
  • Connect IN3 (L298N) to GPIO 23
  • Connect IN4 (L298N) to GPIO 18
  • Connect ENB (L298N) to GPIO 5
  • Connect VCC (L298N) to 5V (ESP32 or External Power)
  • Connect GND (L298N) to GND (ESP32)

This setup allows the ESP32 to control the motors’ movement and speed via PWM signals.

Step 2: Upload the Code

Code Breakdown

  • Wi-Fi Setup: Connects to the given Wi-Fi network.
  • Web Server: Hosts a webpage for control buttons and a speed slider.
  • Motor Control: Controls the direction and speed of the motors.

Upload Code

  1. Connect your ESP32 to the PC.
  2. Select the correct COM Port in Tools → Port.
  3. Upload the provided code.
#include <WiFi.h>
#include <WebServer.h>

// Replace with your network credentials
const char* ssid = "Tesla";
const char* password = "elonDaddy";

// Create an instance of the WebServer on port 80
WebServer server(80);

// Motor 1
int motor1Pin1 = 19;
int motor1Pin2 = 32;
int enable1Pin = 33;

// Motor 2
int motor2Pin1 = 23;
int motor2Pin2 = 18;
int enable2Pin = 5;

// Setting PWM properties
const int freq = 30000;
const int resolution = 8;
int dutyCycle = 0;

String valueString = String(0);

void handleRoot() {
const char html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
<style>
body {
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #1e3c72, #2a5298);
color: white;
text-align: center;
margin: 0;
padding: 0;
}
h1 {
margin-top: 20px;
font-size: 28px;
text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
}
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 80vh;
}
.button {
background-color: #4CAF50;
border: none;
color: white;
padding: 14px 32px;
font-size: 24px;
margin: 10px;
border-radius: 10px;
cursor: pointer;
transition: 0.3s;
box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);
}
.button:hover { background-color: #45a049; }
.button2 { background-color: #d9534f; }
.button2:hover { background-color: #c9302c; }
.direction-buttons {
display: flex;
justify-content: center;
gap: 15px;
margin-top: 10px;
}
.slider-container {
margin-top: 20px;
}
input[type="range"] {
width: 80%;
height: 10px;
background: #ddd;
border-radius: 5px;
outline: none;
-webkit-appearance: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 25px;
height: 25px;
background: #4CAF50;
border-radius: 50%;
cursor: pointer;
}
</style>
<script>
function moveForward() { fetch('/forward'); }
function moveLeft() { fetch('/left'); }
function stopRobot() { fetch('/stop'); }
function moveRight() { fetch('/right'); }
function moveReverse() { fetch('/reverse'); }

function updateMotorSpeed(pos) {
document.getElementById('motorSpeed').innerText = pos;
fetch(`/speed?value=${pos}`);
}
</script>
</head>
<body>
<div class="container">
<h1>ESP32 Motor Control</h1>
<button class="button" onclick="moveForward()">FORWARD</button>
<div class="direction-buttons">
<button class="button" onclick="moveLeft()">LEFT</button>
<button class="button button2" onclick="stopRobot()">STOP</button>
<button class="button" onclick="moveRight()">RIGHT</button>
</div>
<button class="button" onclick="moveReverse()">REVERSE</button>

<div class="slider-container">
<p>Motor Speed: <span id="motorSpeed">0</span></p>
<input type="range" min="0" max="100" step="25" id="motorSlider" oninput="updateMotorSpeed(this.value)" value="0"/>
</div>
</div>
</body>
</html>)rawliteral"
;
server.send(200, "text/html", html);
}

void handleForward() {
Serial.println("Forward");
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, HIGH);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, HIGH);
server.send(200);
}

void handleLeft() {
Serial.println("Left");
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, HIGH);
server.send(200);
}

void handleStop() {
Serial.println("Stop");
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, LOW);
server.send(200);
}

void handleRight() {
Serial.println("Right");
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, HIGH);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, LOW);
server.send(200);
}

void handleReverse() {
Serial.println("Reverse");
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, HIGH);
digitalWrite(motor2Pin2, LOW);
server.send(200);
}

void handleSpeed() {
if (server.hasArg("value")) {
valueString = server.arg("value");
int value = valueString.toInt();
if (value == 0) {
ledcWrite(enable1Pin, 0);
ledcWrite(enable2Pin, 0);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, LOW);
} else {
dutyCycle = map(value, 25, 100, 200, 255);
ledcWrite(enable1Pin, dutyCycle);
ledcWrite(enable2Pin, dutyCycle);
Serial.println("Motor speed set to " + String(value));
}
}
server.send(200);
}

void setup() {
Serial.begin(115200);

// Set the Motor pins as outputs
pinMode(motor1Pin1, OUTPUT);
pinMode(motor1Pin2, OUTPUT);
pinMode(motor2Pin1, OUTPUT);
pinMode(motor2Pin2, OUTPUT);

// Configure PWM Pins
ledcAttach(enable1Pin, freq, resolution);
ledcAttach(enable2Pin, freq, resolution);

// Initialize PWM with 0 duty cycle
ledcWrite(enable1Pin, 0);
ledcWrite(enable2Pin, 0);

// Connect to Wi-Fi
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());

// Define routes
server.on("/", handleRoot);
server.on("/forward", handleForward);
server.on("/left", handleLeft);
server.on("/stop", handleStop);
server.on("/right", handleRight);
server.on("/reverse", handleReverse);
server.on("/speed", handleSpeed);

// Start the server
server.begin();
}

void loop() {
server.handleClient();
}

Step 3: Access the Web Interface

  1. Open Serial Monitor (Baud rate: 115200).
  2. Look for the ESP32’s IP Address (e.g., 192.168.1.100).
  3. Open a web browser and enter ESP32’s IP Address.
  4. You should see a webpage with control buttons.

Step 4: Control the Car

Buttons

  • FORWARD: Moves the car forward.
  • LEFT: Turns the car left.
  • STOP: Stops the motors.
  • RIGHT: Turns the car right.
  • REVERSE: Moves the car backward.

Speed Control

  • Use the slider to adjust motor speed (0% to 100%).

Troubleshooting

  • Not Connecting to Wi-Fi?
  • Check SSID and Password.
  • Ensure your router is in range.

Motors Not Moving?

  • Check motor driver connections.
  • Ensure your power supply is sufficient.

ESP32 Not Responding?

  • Press the BOOT button while uploading code.

Conclusion

You have successfully built a Wi-Fi-controlled RC car using ESP32! 🚗💨

Back to blog

Leave a comment