Web Server Robotic

Mr. Seng Theara

Learning Objective

By the end of the lesson, student will be able to:

  • Understand how a joystick works electrically

  • Explain pull-up button logic

  • Read analog and digital signals

  • Map controller inputs to robot movements

  • Design basic control logic for robots

Learning Objective

By the end of the lesson, student will be able to:

  • Explain what a web server is

  • Understand how ESP32 acts as a web server

  • Create a simple web page hosted by ESP32

  • Control robot movement from a browser

  • Understand HTTP request flow

  • Debug basic network problems

4 Buttons

Joystick

Big Picture

Joystick

Big Picture

Joystick

Big Picture

Example:

Web Browser

Browser sends HTTP request.

ESP32 receives it

ESP32 executes function

Robot

Motor move

You click button

Client

Server

4 Buttons

Joystick

What is a Web Server?

4 Buttons

Joystick

What is a Web Server?

A web server is a system that:

  • Listens for requests from clients

  • Processes those requests

  • Sends back responses (usually HTML)

A web server is simply a device that waits for someone to ask for something.

4 Buttons

What is a Web Server?

 A web server has 3 responsibilities:

1. Listen:

2. Understand Request

3.  Send Response

It waits for incoming connections.

WiFiServer server(80);

  • Port 80 is opened

  • Server waits

When client sends: GET /forward HTTP/1.1

  • Read this text

  • Interpret it

  • Decide what to do

Server

Server replies: HTTP/1.1 200 OK

                           Content-Type: text/html

Then sends HTML page.

4 Buttons

Joystick

What is HTTP?

4 Buttons

Joystick

What is HTTP?

HTTP(HyperText Transfer Protocol) is a protocol that defines: 

  • How a client sends a request

  • How a server sends a response

Client → HTTP Request

Server → HTTP Response

GET /forward HTTP/1.1
Host: 192.168.1.105

HTTP/1.1 200 OK
Content-Type: text/html

ESP32 Connect WIFI

WiFi Connection Process:

1. ESP32 starts WiFi
2. It tries to connect to your router

3. Router checks password
4. Router assigns IP address                    automatically (DHCP)
5. ESP32 prints its IP

#include <WiFi.h>

const char* ssid = "YOUR_WIFI_NAME";
const char* password = "YOUR_WIFI_PASSWORD";

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

  Serial.println("Connecting to WiFi...");

  // Start WiFi connection
  WiFi.begin(ssid, password);

  // Wait until connected
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nConnected to WiFi!");

  // Print assigned IP address (DHCP)
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());
}

void loop() {

}

4 Buttons

Joystick

Creating a Web Page

4 Buttons

Joystick

Creating a Web Page

A web page is not magic. It is just text written in HTML.

Basic HTML Structure

<!DOCTYPE html>
<html>
  <head>
    <title>My Page</title>
  </head>
  <body>
    <h1>Hello</h1>
  </body>
</html>

Creating a Button in HTML

<button>Turn ON</button>

This only creates a visual button.It does NOT control LED yet.

ESP32 Sends a Web Page

server.send(200, "text/html", html);

Joystick

Creating HTML Inside Arduino Code

HTML in arduino Code

String html = "<html>";
html += "<body>";
html += "<h1>ESP32 LED</h1>";
html += "</body>";
html += "</html>";

Adding Style (CSS)

<style>
button {
  padding: 15px;
  font-size: 20px;
}
</style>

CSS controls appearance.

We build HTML like building a long text message.

+= means: Add more text to existing string.

Joystick

Creating HTML Inside Arduino Code

Create a simple Button

#include <WiFi.h>
#include <WebServer.h>


const char* ssid = "project";
const char* password = "1234567890";

WebServer server(80);


void handleRoot() {
  String html = "<!DOCTYPE html><html><body>";
  html += "<h1>ESP32 Web Page</h1>";
  html += "<button>Turn ON</button>";
  html += "<button>Turn OFF</button>";
  html += "</body></html>";

  server.send(200, "text/html", html);
}
void setup() {
  Serial.begin(115200);

  // Connect to WiFi
  WiFi.begin(ssid, password);
  Serial.print("Connecting");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nConnected!");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // Define route
  server.on("/", handleRoot);

  server.begin();
  Serial.println("Web server started");
}

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

Joystick

Creating HTML+CSS Inside Arduino Code

Create a simple Button

#include <WiFi.h>
#include <WebServer.h>

// Replace with your WiFi credentials
const char* ssid = "project";
const char* password = "1234567890";

WebServer server(80);


void handleRoot() {

  String html = "<!DOCTYPE html><html>";
  html += "<head>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";
  html += "<title>ESP32 Button Page</title>";
  html += "<style>";
  html += "body { font-family: Arial; text-align: center; margin-top: 50px; }";
  html += "button { padding:15px 30px; font-size:20px; margin:10px; border:none; color:white; cursor:pointer; }";
  html += ".blueButton { background-color: blue; }";
  html += ".redButton { background-color: red; }";
  html += "</style>";
  html += "</head>";
  html += "<body>";
  html += "<h1>ESP32 Web Page</h1>";
  html += "<button class='blueButton'>Turn ON</button>";
  html += "<button class='redButton'>Turn OFF</button>";
  html += "</body>";
  html += "</html>";

  server.send(200, "text/html", html);
}

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

  // Connect to WiFi
  WiFi.begin(ssid, password);
  Serial.print("Connecting");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nConnected!");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // Define route
  server.on("/", handleRoot);

  server.begin();
  Serial.println("Web server started");
}

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

Joystick

Creating Web Page to control LED on ESP32

#include <WiFi.h>
#include <WebServer.h>

const char* ssid = "project";
const char* password = "1234567890";

WebServer server(80);


const int ledPin = 12; // LED pin


void handleRoot() {
  String html = "<!DOCTYPE html><html><head>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";
  html += "<style>";
  html += "body { font-family: Arial; text-align: center; margin-top: 50px; }";
  html += "button { padding:15px 30px; font-size:20px; margin:10px; border:none; color:white; cursor:pointer; }";
  html += ".blueButton { background-color: blue; }";
  html += ".redButton { background-color: red; }";
  html += "</style>";
  html += "</head><body>";

  html += "<h1>ESP32 LED Control</h1>";
  html += "<a href='/on'><button class='blueButton'>Turn ON</button></a>";
  html += "<a href='/off'><button class='redButton'>Turn OFF</button></a>";

  html += "</body></html>";

  server.send(200, "text/html", html);
}

// -------- LED ON --------
void handleOn() {
  digitalWrite(ledPin, HIGH);
  handleRoot();   // Refresh page
}

// -------- LED OFF --------
void handleOff() {
  digitalWrite(ledPin, LOW);
  handleRoot();   // Refresh page
}

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

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  // Connect to WiFi
  WiFi.begin(ssid, password);
  Serial.print("Connecting");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nConnected!");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // Routes
  server.on("/", handleRoot);
  server.on("/on", handleOn);
  server.on("/off", handleOff);

  server.begin();
  Serial.println("Web server started");
}

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

Practice

Design a web page hosted by the ESP32 that contains five control buttons to operate the robot. Create a web interface with the following five buttons: Forward, Backward, Left, Right, and Stop

4 Buttons

Joystick

 From Control to Feedback

4 Buttons

Joystick

 From Control to Feedback

Right now, our webpage can control the LED. But it does not know whether the LED is ON or OFF. So in order to that, we can:

1. Add a State Variable

String ledState = "OFF";

2. Update State Inside Handlers

void handleOn() {
  digitalWrite(ledPin, HIGH);
  ledState = "ON";
  handleRoot();
}

void handleOff() {
  digitalWrite(ledPin, LOW);
  ledState = "OFF";
  handleRoot();
}

3. Modify the webpage

html += "<h2>LED State: " + ledState + "</h2>";

MIT App Inventor Web Server

MIT App Inventor Web Server

MIT App Inventor is a block-based programming platform to create apps.

Features:

  • Drag and drop UI

  • Block programming (no complex syntax)

  • Works with Bluetooth / WiFi / IoT devices

MIT App Inventor Interface

There are 3 mains part in the MIT App inventor

Designer

Used to build the app interface

Examples:

  • Buttons

  • Labels

  • Images

Blocks

Used to create the logic

Components

Devices used by the app

Examples:

  • Bluetooth

  • WiFi

  • Sensors

MIT App Inventor Interface

There are 3 mains part in the MIT App inventor

Designer

Used to build the app interface

Examples:

  • Buttons

  • Labels

  • Images

Blocks

Used to create the logic

Components

Devices used by the app

Examples:

  • Bluetooth

  • WiFi

  • Sensors

Designer Interface

We create 3 button in here to move backward, stop, and Forward

A slider here is used to adjust the speed

This horizontal Arrangement is just for spacing

Backward Appearance

Designer Interface

We create 3 button in here to move backward, stop, and Forward

A slider here is used to adjust the speed

This horizontal Arrangement is just for spacing

Stop Appearance

Designer Interface

We create 3 button in here to move backward, stop, and Forward

A slider here is used to adjust the speed

This horizontal Arrangement is just for spacing

Forward Appearance

Designer Interface

We create 3 button in here to move backward, stop, and Forward

A slider here is used to adjust the speed

This horizontal Arrangement is just for spacing

Slider Appearance

Component

In here, we use the wifi component. You can actually use the bluetooth, but it supports only the android 

Block

You need to adjust this with your own IP from the esp32 

ESP32 Code 

#include <WiFi.h>
#include <WebServer.h>

const char* ssid = "WIFI";
const char* password = "Password";

WebServer server(80);

void forward() {
  Serial.println("Command: FORWARD");
  server.send(200, "text/plain", "Forward received");
}

void backward() {
  Serial.println("Command: BACKWARD");
  server.send(200, "text/plain", "Backward received");
}


void stopMotor() {
  Serial.println("Command: STOP");
  server.send(200, "text/plain", "Stop received");
}

void setSpeed() {

  if (server.hasArg("value")) {
    String speedValue = server.arg("value");

    Serial.print("Speed value received: ");
    Serial.println(speedValue);
  }

  server.send(200, "text/plain", "Speed received");
}

void setup() {

  Serial.begin(115200);

  WiFi.begin(ssid, password);

  Serial.print("Connecting");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("Connected!");
  Serial.print("ESP32 IP: ");
  Serial.println(WiFi.localIP());

 
  server.on("/forward", forward);
  server.on("/backward", backward);
  server.on("/stop", stopMotor);
  server.on("/speed", setSpeed);

  server.begin();
}

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

Mobile Phone

Download the MIT App Inventor from your mobile phone and scan QR using MIT App Inventor AI Companion as shown below

Radar Code for web interface

#include <WiFi.h>
#include <WebServer.h>

const char* ssid = "project";
const char* password = "1234567890";

WebServer server(80);


float getFakeDistance() {
  return random(1, 100); 
}


String htmlPage() {
  return R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Front Radar</title>
<style>
body {
  margin: 0;
  background: black;
  overflow: hidden;
}
canvas {
  display: block;
}
</style>
</head>
<body>

<canvas id="radar"></canvas>

<script>
const canvas = document.getElementById("radar");
const ctx = canvas.getContext("2d");

function resizeCanvas() {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener("resize", resizeCanvas);

let distance = 100;

function drawRadar() {

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  const centerX = canvas.width / 2;
  const centerY = canvas.height * 0.95;
  const maxRadius = canvas.height * 0.9;

  ctx.strokeStyle = "lime";
  ctx.lineWidth = 0.8;

  let arcCount = 15;
  for (let i = 1; i <= arcCount; i++) {
    let r = (maxRadius / arcCount) * i;
    ctx.beginPath();
    ctx.arc(centerX, centerY, r, Math.PI, 2*Math.PI);
    ctx.stroke();
  }

  let lineCount = 30;
  for (let i = 0; i <= lineCount; i++) {
    let angle = Math.PI + (i / lineCount) * Math.PI;
    let x = centerX + maxRadius * Math.cos(angle);
    let y = centerY + maxRadius * Math.sin(angle);

    ctx.beginPath();
    ctx.moveTo(centerX, centerY);
    ctx.lineTo(x, y);
    ctx.stroke();
  }


  let scaled = (distance / 100) * maxRadius;
  let objectY = centerY - scaled;


  ctx.fillStyle = "red";
  ctx.beginPath();
  ctx.arc(centerX, objectY, 16, 0, 2*Math.PI);
  ctx.fill();


  ctx.fillStyle = "white";
  ctx.font = "32px Arial";
  ctx.fillText("Distance: " + distance.toFixed(1) + " cm", 30, 60);
}

function updateDistance() {
  fetch("/distance")
    .then(res => res.text())
    .then(data => {
      distance = parseFloat(data);
    });
}

setInterval(drawRadar, 30);
setInterval(updateDistance, 300);

</script>
</body>
</html>
)rawliteral";
}

void handleRoot() {
  server.send(200, "text/html", htmlPage());
}

void handleDistance() {
  float d = getFakeDistance();
  server.send(200, "text/plain", String(d));
}

void setup() {
  Serial.begin(115200);
  randomSeed(analogRead(34));

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nConnected!");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.on("/distance", handleDistance);
  server.begin();
}

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

In here I just create a fake distance, you have to use the ultrasonic in here by changing the function getFakeDistance()