Introduction
In this project, we will build a WiFi-controlled robotic car using the ESP8266 NodeMCU.
The robot creates its own WiFi network, and you can control it using a mobile browser — no internet required.
This is a perfect beginner-to-intermediate IoT + robotics project.
Components Required
- ESP8266 NodeMCU
- L298N Motor Driver Module
- DC Motors (2 or 4)
- Robot chassis + wheels
- Battery (7.4V Li-ion or 2×18650)
- Jumper wires
- USB cable
Circuit Diagram (Connections Explained)
Motor Driver → Motors
- OUT1 → Left Motor
- OUT2 → Left Motor
- OUT3 → Right Motor
- OUT4 → Right Motor
Motor Driver → ESP8266
| L298N | ESP8266 |
|---|---|
| IN1 | D1 |
| IN2 | D2 |
| IN3 | D5 |
| IN4 | D6 |
| ENA | D7 |
| ENB | D8 |
Power Connections (VERY IMPORTANT)
Correct Way:
- Battery → L298N (12V input)
- ESP8266 → USB power (recommended)
- GND of ESP8266 ↔ GND of L298N
Wrong Way (Avoid this)
- DO NOT power ESP8266 from L298N 5V
–> Causes reset, WiFi issues, unstable behavior
Arduino IDE Setup
1. Install ESP8266 Board
Go to:
- File → Preferences
- Add this URL:
http://arduino.esp8266.com/stable/package_esp8266com_index.json
Then:
- Tools → Board Manager
- Install ESP8266 Boards by ESP8266 Community
2. Select Board
- Tools → Board → NodeMCU 1.0 (ESP-12E Module)
Working Principle
- ESP8266 creates a WiFi hotspot: RobotCar
- Phone connects to it
- A web page with buttons is served
- Buttons send commands using AJAX (no page reload)
- Motors move accordingly
Complete Code
#include <ESP8266WiFi.h>
// ===== MOTOR PINS =====
#define IN1 D1
#define IN2 D2
#define IN3 D5
#define IN4 D6
// ===== SPEED PINS (PWM) =====
#define ENA D7
#define ENB D8
int speedValue = 300; // 0 - 1023
// ===== WIFI =====
const char* ssid = "RobotCar";
const char* password = "12345678";
WiFiServer server(80);
// ===== MOTOR FUNCTIONS =====
void forward() {
analogWrite(ENA, speedValue);
analogWrite(ENB, speedValue);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
}
void backward() {
analogWrite(ENA, speedValue);
analogWrite(ENB, speedValue);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
}
void left() {
analogWrite(ENA, speedValue);
analogWrite(ENB, speedValue);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
}
void right() {
analogWrite(ENA, speedValue);
analogWrite(ENB, speedValue);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
}
void stopCar() {
analogWrite(ENA, 0);
analogWrite(ENB, 0);
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
}
// ===== SETUP =====
void setup() {
Serial.begin(115200);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
pinMode(ENA, OUTPUT);
pinMode(ENB, OUTPUT);
analogWriteRange(1023);
analogWriteFreq(1000);
stopCar();
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password);
Serial.println("WiFi Started");
Serial.println(WiFi.softAPIP());
server.begin();
}
// ===== LOOP =====
void loop() {
WiFiClient client = server.available();
if (!client) return;
String request = client.readStringUntil('\r');
client.flush();
// ===== MOVEMENT COMMANDS =====
if (request.indexOf("GET /forward") != -1) forward();
else if (request.indexOf("GET /backward") != -1) backward();
else if (request.indexOf("GET /left") != -1) left();
else if (request.indexOf("GET /right") != -1) right();
else if (request.indexOf("GET /stop") != -1) stopCar();
// ===== SPEED COMMANDS =====
else if (request.indexOf("GET /speedlow") != -1) speedValue = 400;
else if (request.indexOf("GET /speedmed") != -1) speedValue = 700;
else if (request.indexOf("GET /speedhigh") != -1) speedValue = 1023;
// ===== RESPONSE =====
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE html><html><head>");
client.println("<meta name='viewport' content='width=device-width, initial-scale=1'>");
// ===== STYLE =====
client.println("<style>");
client.println("body { text-align:center; font-family: Arial; background:#111; color:white; }");
client.println("button { width:100px; height:100px; font-size:18px; margin:10px; border-radius:50%; border:none; }");
client.println(".f { background:green; }");
client.println(".b { background:blue; }");
client.println(".l { background:orange; }");
client.println(".r { background:orange; }");
client.println(".s { background:red; }");
client.println(".sp { width:80px; height:50px; border-radius:10px; }");
client.println("</style>");
// ===== JAVASCRIPT =====
client.println("<script>");
client.println("function send(cmd){");
client.println("var x=new XMLHttpRequest();");
client.println("x.open('GET','/'+cmd,true);");
client.println("x.send();");
client.println("}");
client.println("</script>");
client.println("</head><body>");
client.println("<h2>Robot Control</h2>");
// ===== SPEED BUTTONS =====
client.println("<p>Speed Control</p>");
client.println("<button class='sp' onclick=\"send('speedlow')\">Slow</button>");
client.println("<button class='sp' onclick=\"send('speedmed')\">Medium</button>");
client.println("<button class='sp' onclick=\"send('speedhigh')\">Fast</button><br><br>");
// ===== MOVEMENT BUTTONS =====
client.println("<button class='f' onclick=\"send('forward')\">Forward</button><br>");
client.println("<button class='l' onclick=\"send('left')\">Left</button>");
client.println("<button class='s' onclick=\"send('stop')\">Stop</button>");
client.println("<button class='r' onclick=\"send('right')\">Right</button><br>");
client.println("<button class='b' onclick=\"send('backward')\">Backward</button>");
client.println("</body></html>");
client.stop();
}
How to Use
- Upload code
- Power ESP8266
- Open Settings in your mobile, then go to WiFi and select “RobotCar”. Then type password “12345678”:
RobotCar
4. Open browser and type:
192.168.4.1
5. Use buttons to control the robot
Important Tips
- Turn OFF mobile data
- Use Chrome browser
- Keep ESP powered properly
- Keep motors and ESP power separate
Troubleshooting Guide
1. WiFi not visible
Causes:
- Code not uploaded properly
- ESP not powered
Fix:
- Press RESET button
- Check Serial Monitor (115200 baud)
2. Connected but page not opening
Fix:
- Turn OFF mobile data
- Use:
192.168.4.1
(Do not put this in Google search)
3. Buttons work only once
Cause:
- Page reload issue
Fix:
- Already solved using AJAX in this code
4. Weird symbols on buttons
Cause:
- Unicode not supported
Fix:
- Use text (Forward, Left, etc.)
5. ESP8266 not detected
Causes:
- Power issue
- USB driver issue
Fix:
- Use USB cable
- Check drivers:
- CP2102 USB to UART Bridge
- CH340 USB to Serial
6. Robot not moving correctly
Fix:
- Swap motor wires
- Adjust logic in code
7. ESP resets when motor runs
Cause:
- Voltage drop
Fix:
- Use separate power supply
- Use buck converter (LM2596 recommended)
Improvements You Can Add
- Voice control
- Obstacle avoidance
- Camera streaming using ESP32-CAM
Conclusion
This project demonstrates how to build a simple yet powerful IoT robot using ESP8266.
With proper power management and AJAX-based control, you get a smooth and responsive robotic car.