Radar Deteksi Objek Menggunakan Sensor Ultrasonic HC-SR04 dan ESP32 sebagai Server (Web Radar PHP)

1. Judul Praktikum

Radar Deteksi Objek Menggunakan Sensor Ultrasonic HC-SR04 dengan ESP32 sebagai Server dan PHP sebagai Dashboard Visual Radar

2. Tujuan Praktikum

Setelah praktikum ini mahasiswa mampu:

    1. Menghubungkan sensor Ultrasonic HC-SR04 ke ESP32.
    2. Mengirim data jarak secara real-time melalui WebServer ESP32.
    3. Membuat dashboard radar sederhana menggunakan PHP + AJAX.
    4. Menampilkan visual radar bergerak (sweep 0–180°) berbasis web.
    5. Mempraktikkan konsep REST API, JSON, dan komunikasi HTTP.

3. Alat & Bahan

No Nama Peralatan Jumlah
1 ESP32 Devkit 1
2 Sensor Ultrasonic HC-SR04 1
3 Servo Motor SG90/MG90S 1
4 Kabel jumper secukupnya
5 Breadboard 1
6 Laptop + Arduino IDE 1
7 Web Server lokal (XAMPP/Laragon) 1

4. Dasar Teori

4.1 Sensor Ultrasonic HC-SR04

Sensor bekerja dengan memancarkan gelombang ultrasonik 40KHz dan menghitung waktu pantul (echo).
Rumus jarak:

Jarak = Waktu X 0.0343 /2

4.2 ESP32 Web Server

ESP32 dapat membuat REST API berbasis HTTP sehingga data sensor bisa diakses melalui URL, contoh:

http://192.168.1.50/data

Output JSON:

{"sudut":45,"jarak":120}

4.3 PHP Web Dashboard

PHP membaca data dari API ESP32 menggunakan AJAX untuk menampilkan radar bergerak.

5. Rangkaian

radar esp32

🟦 ESP32 ke HC-SR04

HC-SR04 ESP32
VCC 5V
GND GND
Trig GPIO 5
Echo GPIO 18

🟩 ESP32 ke Servo

Servo ESP32
VCC 5V
GND GND
Signal GPIO 13

6. Program ESP32 (Web API Radar)

Upload menggunakan Arduino IDE.

#include <WiFi.h>

#include <WebServer.h>

const char* ssid = "bisaioti_1";

const char* password = "bisaioti123";

#define trigPin 5

#define echoPin 18

WebServer server(80);

// =======================================================

// Fungsi baca jarak ultrasonik

// =======================================================

int getDistance() {

  digitalWrite(trigPin, LOW);

  delayMicroseconds(2);

  digitalWrite(trigPin, HIGH);

  delayMicroseconds(10);

  digitalWrite(trigPin, LOW);

  long duration = pulseIn(echoPin, HIGH, 30000); // timeout 30ms

  int distance = duration * 0.034 / 2;

  if (distance <= 0 || distance > 400) distance = 0;

  return distance;

}

// =======================================================

// Handler data untuk radar

// =======================================================

void handleData() {

  int angle = random(0, 181);       // Sudut 0–180

  int dist  = getDistance();        // Baca jarak

  // Serial Monitor

  Serial.printf("Sudut: %d°, Jarak: %d cm\n", angle, dist);

  // JSON

  String json = "{\"sudut\":" + String(angle) +

                ",\"jarak\":" + String(dist) + "}";

  // Header WAJIB DULUAN

  server.sendHeader("Access-Control-Allow-Origin", "*");

  server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");

  server.sendHeader("Pragma", "no-cache");

  server.sendHeader("Expires", "-1");

  // Baru kirim JSON

  server.send(200, "application/json", json);

}

// =======================================================

void setup() {

  pinMode(trigPin, OUTPUT);

  pinMode(echoPin, INPUT);

  Serial.begin(115200);

  delay(1000);

  Serial.println("\nStarting AP...");

  WiFi.softAP(ssid, password);

  delay(500); // penting agar AP stabil

  Serial.print("AP IP: ");

  Serial.println(WiFi.softAPIP());

  server.on("/data", handleData);

  server.begin();

  Serial.println("Server Ready!");

}

// =======================================================

void loop() {

  server.handleClient();

}

✅ ESP32 akan membuat WiFi sendiri:

SSID: bisaioti_1 
Password: bisaioti123

URL API data real-time:

http://192.168.4.1/data

PENJELASAN PROGRAM

1. Library yang Dipakai

#include <WiFi.h>

#include <WebServer.h>
  • WiFi.h → mengaktifkan fitur WiFi pada ESP32.
  • WebServer.h → membuat web server (HTTP server) di port 80.

2. Konfigurasi Access Point

const char* ssid = "bisaioti_1";

const char* password = "bisaioti123";

ESP32 akan membuat WiFi Hotspot sendiri dengan nama:

  • SSID : bisaioti_1
  • Password : wasiswa123

Client (HP/Laptop) harus terhubung ke AP ini untuk membaca data sensor.

3. Pin Ultrasonik HC-SR04

#define trigPin 5
#define echoPin 18
  • Pin 5 → TRIG
  • Pin 18 → ECHO

4. Objek Web Server

WebServer server(80);

ESP32 akan membuat server di:

  • Port 80
  • Endpoint utama: /data

5. Fungsi Baca Jarak Ultrasonik

int getDistance() {

  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH, 30000); // timeout 30ms
  int distance = duration * 0.034 / 2;
  if (distance <= 0 || distance > 400) distance = 0;
  return distance;
}

Cara kerja:

  1. TRIG diberi pulsa 10 mikrodetik → sensor mulai “menembak” ultrasonik.
  2. ECHO membaca waktu pantulan (dalam mikrodetik).
  3. Rumus:
  1. jarak = durasi * kecepatan suara (0.034 cm/µs) / 2
  1. Jarak dibatasi 0–400 cm (range aman HC-SR04).
  2. Jika tidak valid, jarak di-set 0.

6. Handler /data – untuk JSON RADAR

void handleData() {
  int angle = random(0, 181);   // Sudut radar 0-180 derajat
  int dist  = getDistance();    // Baca jarak sensor
  • Sudut dibuat random → nanti digunakan untuk animasi radar web.
  • Jarak diambil dari ultrasonik.

Debug Print:

Serial.printf("Sudut: %d°, Jarak: %d cm\n", angle, dist);

Format JSON yang dikirim ke browser:

{"sudut": 90, "jarak": 35}

 

7. Header Anti-Cache (Wajib untuk grafis real-time)

server.sendHeader("Access-Control-Allow-Origin", "*");
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server.sendHeader("Pragma", "no-cache");
server.sendHeader("Expires", "-1");

Ini memastikan:
✅ Browser tidak menyimpan data
✅ Data selalu real-time

8. Kirim Data ke Client

server.send(200, "application/json", json);

 

9. Setup()

WiFi.softAP(ssid, password);
Serial.println(WiFi.softAPIP());
  • ESP32 membuat Access Point (AP Mode)
  • Mencetak IP default AP biasanya: 192.168.4.1

Register endpoint:

server.on("/data", handleData);
server.begin();

Artinya:

  • Jika user mengakses http://192.168.4.1/data → ESP32 kirim data JSON radar

 

10. Loop()

server.handleClient();

Dipanggil terus untuk melayani request HTTP.

 

RANGKUMAN CARA KERJA PROGRAM

  1. ESP32 membuat WiFi hotspot bernama bisaioti_1.
  2. Browser tersambung ke AP tersebut.
  3. Browser/web app melakukan fetch ke:
  1. http://192.168.4.1/data
  1. ESP32 membaca jarak ultrasonik.
  2. ESP32 membuat sudut random 0–180°.
  3. Data dikirim dalam bentuk JSON:
  1. {“sudut”:90,”jarak”:25}
  1. Browser menampilkan animasi radar bergerak (canvas atau chart).

 

7. Program PHP (Dashboard Radar)

Buat folder di htdocs/ bernama radar/
Buat file index.php berikut:

<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="utf-8" />
<title>Radar Ultrasonic ESP32 — Pro</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
:root {
--bg: #000;
--grid: rgba(0,255,0,.20);
--grid-soft: rgba(0,255,0,.10);
--glow: #31ff5f;
--sweep: #00ff6a;
--dot: #ff4040;
--text: #e8fff0;
}
html,body{height:100%}
body{
margin:0;background:var(--bg);color:var(--text);
font-family:Segoe UI,Roboto,Arial,Helvetica,sans-serif; display:flex; flex-direction:column; align-items:center;
}
h1{font-size:clamp(18px,2.6vw,32px); margin:16px 0 6px}
.wrap{width:min(96vw,1100px); display:grid; gap:14px}
.panel{background:#040804; border:1px solid #0e3016; border-radius:14px; padding:10px 12px}
.grid2{display:grid; grid-template-columns:1fr; gap:14px}
@media (min-width:980px){ .grid2{grid-template-columns: 2fr 1fr} }
canvas{display:block; width:100%; height:auto; aspect-ratio:1/1; border-radius:12px}
.row{display:flex; gap:8px; align-items:center; flex-wrap:wrap}
.pill{background:#0d2b17; border:1px solid #154d2a; color:#baffcf; padding:6px 10px; border-radius:999px; font-size:12px}
.muted{opacity:.75}
.chart{aspect-ratio: 5/2}
.legend{display:flex; gap:10px; font-size:12px; opacity:.85}
.legend span::before{content:""; display:inline-block; width:10px; height:10px; margin-right:6px; border-radius:2px; vertical-align:baseline}
.legend .dist::before{background:var(--sweep)}
.legend .near::before{background:var(--dot)}
</style>
</head>
<body>

<h1>Radar Ultrasonic ESP32</h1>

<div class="wrap">
<div class="row">
<span class="pill">Mode: <b id="mode">LIVE</b></span>
<span class="pill">ESP32: <b id="status">menunggu...</b></span>
<span class="pill muted">IP: <span id="ip">http://192.168.4.1/data</span></span>
<span class="pill muted">Refresh: 100 ms</span>
</div>

<div class="grid2">
<div class="panel">
<canvas id="radar"></canvas>
</div>
<div class="panel">
<canvas id="chart" class="chart"></canvas>
<div class="legend" style="margin-top:6px">
<span class="dist">Jarak (cm)</span>
<span class="near">Objek dekat (&lt;= 40 cm)</span>
</div>
<div class="row" style="margin-top:10px">
<span class="pill">Sudut: <b id="angleLabel">0°</b></span>
<span class="pill">Jarak: <b id="distLabel">0 cm</b></span>
<span class="pill">Objek: <b id="objLabel">0</b></span>
</div>
</div>
</div>
</div>

<script>
/* ================== Konfigurasi ================== */
const ESP32_URL = "http://192.168.4.1/data"; // ganti bila perlu
const FETCH_INTERVAL = 100; // ms
const MAX_RANGE_CM = 300; // jangkauan visual radar
const NEAR_THRESHOLD = 40; // penanda objek dekat
/* ================================================= */

const radar = document.getElementById('radar');
const rctx = radar.getContext('2d');
const chart = document.getElementById('chart');
const cctx = chart.getContext('2d');

const statusEl = document.getElementById('status');
const modeEl = document.getElementById('mode');
document.getElementById('ip').textContent = ESP32_URL;

let W, H, CX, CY, R;
let sweep = 0; // sudut sweep animasi (0..360)
let dotHistory = []; // riwayat titik (fade-out)
let distSeries = []; // seri jarak untuk grafik
let lastFetchOK = false;
let lastTargets = []; // target terakhir dari ESP32

// Helper: resize sesuai pixel ratio
function fitCanvas(can, ctx, w, h){
const dpr = Math.max(1, window.devicePixelRatio || 1);
can.width = Math.floor(w*dpr);
can.height = Math.floor(h*dpr);
can.style.width = w + "px";
can.style.height = h + "px";
ctx.setTransform(dpr,0,0,dpr,0,0);
}

// Inisialisasi ukuran canvas responsif
function layout(){
// radar selalu persegi, ambil lebar panel
const box = radar.parentElement.getBoundingClientRect();
const size = Math.min(box.width-24, 700);
fitCanvas(radar, rctx, size, size);
W = radar.width / (window.devicePixelRatio||1);
H = radar.height / (window.devicePixelRatio||1);
CX = W/2; CY = H/2; R = Math.min(W,H)*0.46;

// chart ratio 5:2
const cbox = chart.parentElement.getBoundingClientRect();
const ch = Math.max(180, Math.round(cbox.width*0.4));
fitCanvas(chart, cctx, cbox.width-24, ch);
}
layout();
window.addEventListener('resize', layout);

// ================== Radar Drawing ==================
function drawRadarBase(){
// fade-out: layer hitam transparan agar jejak memudar
rctx.fillStyle = "rgba(0,0,0,0.20)";
rctx.fillRect(0,0,W,H);

// grid 3D/holo: radial gradient
const g = rctx.createRadialGradient(CX, CY, 0, CX, CY, R);
g.addColorStop(0, "rgba(0,255,120,0.08)");
g.addColorStop(1, "rgba(0,255,80,0.02)");
rctx.beginPath();
rctx.fillStyle = g;
rctx.arc(CX, CY, R, 0, Math.PI*2);
rctx.fill();

// rings
rctx.strokeStyle = "rgba(0,255,0,.20)";
rctx.lineWidth = 2;
[R, R*0.66, R*0.33].forEach(r=>{
rctx.beginPath(); rctx.arc(CX,CY,r,0,Math.PI*2); rctx.stroke();
});
}

function drawSweep(){
const a = sweep * Math.PI/180;
const x = CX + R*Math.cos(a);
const y = CY + R*Math.sin(a);

// sweep glow
rctx.save();
rctx.lineWidth = 2;
rctx.strokeStyle = getGlow(0.95);
rctx.shadowBlur = 18;
rctx.shadowColor = "#30ff7a";
rctx.beginPath();
rctx.moveTo(CX, CY);
rctx.lineTo(x, y);
rctx.stroke();
rctx.restore();
}

function getGlow(alpha=1){
const grad = rctx.createLinearGradient(0,0,W,0);
grad.addColorStop(0, `rgba(0,255,120,${0.00*alpha})`);
grad.addColorStop(0.2,`rgba(0,255,120,${0.35*alpha})`);
grad.addColorStop(0.6,`rgba(0,255,120,${0.95*alpha})`);
grad.addColorStop(1, `rgba(0,255,120,${0.65*alpha})`);
return grad;
}

// titik + fade-out
function drawDots(){
// kurangi alpha tiap frame (fade)
dotHistory.forEach(p=> p.a *= 0.93);
dotHistory = dotHistory.filter(p=> p.a > 0.05);

dotHistory.forEach(p=>{
const d = Math.min(Math.max(p.dist,5), MAX_RANGE_CM);
const scale = d * (R / MAX_RANGE_CM);
const rad = p.angle * Math.PI/180;
const x = CX + scale*Math.cos(rad);
const y = CY + scale*Math.sin(rad);

rctx.beginPath();
rctx.fillStyle = `rgba(255,64,64,${p.a})`;
rctx.shadowBlur = 12*p.a;
rctx.shadowColor = "rgba(255,64,64,.7)";
rctx.arc(x,y, 6, 0, Math.PI*2);
rctx.fill();
rctx.shadowBlur = 0;
});
}

// ================== Chart Drawing ==================
function drawChart(){
cctx.clearRect(0,0,chart.width/(window.devicePixelRatio||1), chart.height/(window.devicePixelRatio||1));

const w = chart.width/(window.devicePixelRatio||1);
const h = chart.height/(window.devicePixelRatio||1);
// grid
cctx.strokeStyle = "rgba(0,255,0,.1)";
cctx.lineWidth = 1;
for(let i=0;i<4;i++){
const y = h*(i+1)/4;
cctx.beginPath(); cctx.moveTo(0,y); cctx.lineTo(w,y); cctx.stroke();
}

if(distSeries.length<2) return;

// scale
const N = distSeries.length;
const maxV = MAX_RANGE_CM;
const stepX = w/(N-1);

// line jarak
cctx.beginPath();
cctx.lineWidth = 2;
cctx.strokeStyle = "#00ff6a";
cctx.shadowBlur = 8;
cctx.shadowColor = "#00ff6a";
for(let i=0;i<N;i++){
const x = i*stepX;
const y = h - (distSeries[i]/maxV)*h;
if(i===0) cctx.moveTo(x,y); else cctx.lineTo(x,y);
}
cctx.stroke();
cctx.shadowBlur = 0;

// area danger (<= NEAR_THRESHOLD)
const yDanger = h - (NEAR_THRESHOLD/maxV)*h;
cctx.fillStyle = "rgba(255,64,64,.10)";
cctx.fillRect(0,yDanger,w,h-yDanger);
}

// ================== Data Fetch ==================
async function pollData(){
try{
const res = await fetch(ESP32_URL + "?t=" + Math.random(), {cache:'no-store'});
const js = await res.json();
lastFetchOK = true;
statusEl.textContent = "ONLINE";
statusEl.style.color = "#4dff9c";

let targets = [];
if(js.targets && Array.isArray(js.targets)){ // multi target
targets = js.targets.map(t => ({
angle: Number(t.sudut||t.angle||0),
dist: Number(t.jarak||t.distance||0)
}));
}else{ // single target
targets = [{ angle:Number(js.sudut||0), dist:Number(js.jarak||0) }];
}
lastTargets = targets;

// update UI ringkas (pakai target terdekat)
const nearest = targets
.filter(t=>t.dist>0)
.sort((a,b)=>a.dist-b.dist)[0] || {angle:0,dist:0};

document.getElementById('angleLabel').textContent = Math.round(nearest.angle) + "°";
document.getElementById('distLabel').textContent = Math.round(nearest.dist) + " cm";
document.getElementById('objLabel').textContent = targets.length;

// simpan ke grafik
distSeries.push(Math.min(nearest.dist || 0, MAX_RANGE_CM));
if(distSeries.length>150) distSeries.shift();

// tambahkan ke jejak titik (fade-out)
targets.forEach(t=>{
dotHistory.push({ angle: t.angle, dist: t.dist, a: 1.0 });
});

}catch(err){
// fallback DEMO MODE
lastFetchOK = false;
statusEl.textContent = "OFFLINE (DEMO)";
statusEl.style.color = "#ffaa4d";
modeEl.textContent = "DEMO";
demoInject();
}
}

function demoInject(){
// jika offline, generate data demo agar UI tetap hidup
const demoAngle = (sweep + Math.random()*6-3 + 360)%360;
const demoDist = 30 + Math.abs(Math.sin(sweep*Math.PI/180))*220 + Math.random()*15;
lastTargets = [{ angle: demoAngle, dist: demoDist }];
dotHistory.push({ angle: demoAngle, dist: demoDist, a:1.0 });

distSeries.push(Math.min(demoDist, MAX_RANGE_CM));
if(distSeries.length>150) distSeries.shift();
}

// ================== Main Loop ==================
function frame(){
drawRadarBase();
drawDots();

sweep = (sweep + 2) % 360; // sweep halus
drawSweep();

drawChart();

requestAnimationFrame(frame);
}

// Start
setInterval(pollData, FETCH_INTERVAL);
frame();
</script>

</body>
</html>

✅ Dashboard menampilkan radar bergerak 0–180°
✅ Titik merah muncul saat objek terdeteksi
✅ Komunikasi memakai AJAX fetch JSON

8. Langkah Kerja Praktikum

    1. Rangkai ESP32, HC-SR04, dan servo seperti diagram.
    2. Upload program ESP32 melalui Arduino IDE.
    3. ESP32 akan membuat WiFi hotspot → koneksi laptop ke SSID tersebut.
    4. Jalankan XAMPP / Laragon → aktifkan Apache.
    5. Masukkan file PHP ke folder htdocs/radar/.
    6. Buka browser → akses:
  1. http://localhost/radar/

Amati radar bergerak mengikuti sweep servo (jika menggunakankan servo).

Uji objek di depan sensor → radar menampilkan titik deteksi.

9. Hasil & Analisis

Mahasiswa harus mampu:

✅ Menghasilkan visual radar bergerak
✅ Menjelaskan hubungan ESP32 WebServer & PHP
✅ Menganalisis akurasi sensor HC-SR04
✅ Mengukur kestabilan pengiriman data real-time

10. Pertanyaan Evaluasi

    1. Apa fungsi Trig dan Echo pada HC-SR04?
    2. Mengapa servo harus melakukan sweep 0–180°?
    3. Apa kelebihan menggunakan JSON untuk pertukaran data?
    4. Bagaimana cara menangani noise jarak sensor?
    5. Apa yang akan terjadi jika WiFi ESP32 overload?

 

 

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *