Files
esp32s3-ld2453/orangepi-server
2026-09-11 22:09:39 +07:00
..
2026-09-11 22:09:39 +07:00
2026-09-11 20:14:37 +07:00
2026-09-11 22:09:39 +07:00
2026-09-11 20:14:37 +07:00
2026-09-11 22:09:39 +07:00

ESP32-S3 LD2453 Radar — Web Visualizer cho Orange Pi

English version below / Xem bản tiếng Anh ở cuối file.

Hướng dẫn cài đặt và sử dụng Web Visualizer trên Orange Pi (hoặc máy tính bất kỳ có Python 3.8+) để hiển thị dữ liệu radar realtime dưới dạng giao diện web đẹp trên trình duyệt.

✅ Không cần giao diện desktop (Tkinter/Pygame) nữa. Visualizer chạy nền dạng Web Server (FastAPI), bạn chỉ cần mở trình duyệt (trên điện thoại, laptop, PC…) là xem được đồ họa.


1. Chuẩn bị

1.1 Yêu cầu hệ thống

  • Orange Pi / Raspberry Pi / PC bất kỳ có Python 3.8+
  • Cùng mạng LAN với ESP32 (WiFi hoặc cổng LAN)
  • Biết IP của ESP32 (xem Serial Monitor khi boot, hoặc vào router xem)

1.2 Cấu trúc thư mục

orangepi-server/
├── visualizer.py          # Web Server (FastAPI): kết nối ESP32 + broadcast tới trình duyệt
├── requirements.txt       # Python dependencies
├── templates/
│   └── index.html         # Giao diện Web (HTML)
└── static/
    ├── style.css          # Giao diện (CSS): sáng/tối, responsive, song ngữ
    └── app.js             # Canvas render + WebSocket client trong trình duyệt

1.3 Copy file lên Orange Pi

Copy cả thư mục orangepi-server/ lên Orange Pi (clone repo, SCP, USB…).

Ví dụ SCP (chạy từ máy bạn):

scp -r orangepi-server/ orangepi@<ORANGE_PI_IP>:/home/orangepi/

2. Cài đặt Python dependencies

cd ~/orangepi-server

# (Tùy chọn nhưng khuyến nghị) Dùng virtual env
python3 -m venv venv
source venv/bin/activate

# Cài dependencies
pip install -r requirements.txt

Cài global (nhanh hơn, không khuyến nghị):

pip3 install -r requirements.txt

Không cần python3-tk nữa — toàn bộ chạy trên web.


3. Sử dụng

3.1 Bật ESP32 ở chế độ Full Stage

Trong config.h trên Arduino IDE:

#define DIAGNOSTIC_MODE 0   // Full mode: WiFi + WebSocket + REST API

Nạp code, mở Serial Monitor lấy IP ESP32. Ví dụ: 192.168.1.100

3.2 Khởi động Web Visualizer trên Orange Pi

# Nếu dùng venv:
source venv/bin/activate

# Chạy (thay bằng IP ESP32 của bạn):
python3 visualizer.py 192.168.1.100

Các tùy chọn lệnh:

# Tùy chỉnh port (mặc định 8000):
python3 visualizer.py 192.168.1.100 --port 8080

# Giới hạn truy cập chỉ local (không cho từ ngoài):
python3 visualizer.py 192.168.1.100 --host 127.0.0.1

# Log chi tiết:
python3 visualizer.py 192.168.1.100 --verbose

Màn hình console sẽ hiển thị:

==============================================================
  ESP32-S3 LD2453 Radar — Web Visualizer
==============================================================
  ESP32   : ws://192.168.1.100/ws
  Web UI  : http://0.0.0.0:8000/
  WS UI   : ws://<OrangePi_IP>:8000/ws
==============================================================

3.3 Mở trình duyệt xem kết quả

Trên bất kỳ thiết bị nào cùng LAN (điện thoại, laptop, PC…):

http://<IP_OrangePi>:8000/

Ví dụ: Orange Pi có IP 192.168.1.50 → mở http://192.168.1.50:8000/


4. Tính năng giao diện Web

4.1 Tổng quan

Tính năng Mô tả
🎨 Giao diện đẹp Chủ đề sáng/tối (Light/Dark), màu sắc theo chuẩn Catppuccin
🌐 Song ngữ Bật/tắt Tiếng Việt / English ngay trên header
📱 Responsive Xem tốt trên cả mobile, tablet, desktop
🧭 Radar Canvas Hiển thị radar, grid 1m, vòng tròn khoảng cách, hiệu ứng quét (sweep)
🎯 Targets Lên đến 3 target với màu khác nhau, đường dẫn (trail), mũi tên tốc độ, nhãn tọa độ
🟩 Zones 3 vùng hình chữ nhật với màu & trạng thái (Có người / Trống)
📊 Thống kê Frames nhận, target hợp lệ, vùng có người, cập nhật lần cuối
📝 Chi tiết Thông tin chi tiết từng target & zone ở panel bên phải
✏️ Sửa zones Chỉnh tọa độ zones ngay trên web, tự động gửi cập nhật tới ESP32
🔗 Multi client Nhiều trình duyệt xem cùng lúc, dữ liệu đồng bộ realtime

4.2 Header

  • 🟢 / 🟡 / 🔴 Trạng thái kết nối ESP32 và WebSocket
  • ☀️ / 🌙 Nút chuyển Sáng / Tối
  • VI / EN Nút chuyển ngôn ngữ

4.3 Radar View (Canvas)

  • Grid: Mỗi ô = 1 mét, có đánh số (−5m ← 0 → +5m ngang, 0 → 7m thẳng)
  • Vòng tròn khoảng cách: Các vòng tròn nét đứt cách nhau 1m tính từ radar
  • Trục Y chính: Nét đứt màu xanh, chỉ hướng thẳng từ radar
  • Radar: Vị trí radar ở giữa cạnh dưới (điểm đỏ, ghi chữ RADAR)
  • Hiệu ứng quét: Cảm giác radar thực tế, có thể tắt trong công cụ
  • Zones (3 hình chữ nhật):
    • Zone 1 (Xanh lá), Zone 2 (Cam), Zone 3 (Đỏ)
    • Có người → Màu đậm, nét liền, badge CÓ NGƯỜI
    • Trống → Màu nhạt, nét đứt, badge TRỐNG
  • Targets (3 điểm):
    • Màu: Vàng (Slot 1), Tím (Slot 2), Xanh (Slot 3)
    • Điểm sáng có viền trắng, bao quanh là hiệu ứng glow
    • Mũi tên: Tốc độ (độ dài tỉ lệ với cm/s, hướng theo chuyển động)
    • Nhãn: T# | X,Y mm | tốc độ cm/s
    • Đường dẫn (trail): Mờ dần theo thời gian (tối đa 3.5s)
    • Target vừa mất dấu: Hiển thị viền đứt mờ trong 3.5s nữa

4.4 Công cụ trên Canvas (bên phải tiêu đề)

  • ✅ Hiệu ứng quét — Bật/tắt hiệu ứng quét radar
  • ✅ Đường dẫn target — Bật/tắt trail fade
  • ✅ Hiển thị label — Bật/tắt nhãn trên zones & targets

4.5 Panel bên phải

Thống kê:

  • Frames nhận (tổng cộng)
  • Cập nhật cách đây bao nhiêu giây
  • Target hợp lệ / 3
  • Vùng có người / 3

Chi tiết Target:

  • Mỗi target có một thẻ màu, hiển thị:
    • Trạng thái: Đã phát hiện / Vừa mất dấu / Trống
    • X, Y (mm)
    • Tốc độ (cm/s)
    • Khoảng cách (m)
    • Góc (°) — 0° = thẳng, âm = trái, dương = phải

Zones:

  • Danh sách 3 zones với tọa độ
  • Nút Sửa zones mở form chỉnh sửa từng toạ độ X1/Y1/X2/Y2 (mm)
    • Mặc định: Khôi phục layout gốc
    • Hủy: Bỏ sửa
    • Lưu & Áp dụng: Gửi cập nhật POST /api/zones → forward tới ESP32 /updateZones, hiển thị toast thành công

5. Kiến trúc & luồng dữ liệu

 ┌───────────┐     WebSocket /ws     ┌──────────────────┐    WebSocket /ws     ┌──────────────┐
 │  ESP32-S3 │ ◄──────────────────► │  Orange Pi (WS   │ ◄──────────────────► │  Trình duyệt │
 │  LD2453   │  JSON frame radar     │  Server FastAPI) │  JSON state đồng bộ  │  (Canvas 2D) │
 └───────────┘                       └──────────────────┘                      └──────────────┘
        ▲                                   ▲                                          ▲
        │ REST GET /zones                   │ GET / → trả về index.html               │
        │ REST POST /updateZones            │ GET /static/* → CSS, JS                  │
        └───────────────────────────────────┘ REST API /api/*                          │
                              Visualizer tự động gọi ESP32 khi bạn chỉnh zones trên web │

Các endpoint chính:

Method Endpoint Mục đích
GET / Trả về trang web chính
GET /api/state Lấy trạng thái radar hiện tại (JSON)
GET /api/zones Lấy danh sách zones
POST /api/zones Cập nhật zones (forward tới ESP32 /updateZones)
WS /ws Endpoint WebSocket cho trình duyệt (broadcast realtime)

6. Tùy chỉnh & chạy nền

6.1 Chạy nền bằng tmux

tmux new -s radar
cd ~/orangepi-server && source venv/bin/activate
python3 visualizer.py 192.168.1.100
# Ctrl+B D → detach (thoát ra mà vẫn chạy)
# tmux attach -t radar → quay lại session

6.2 systemd service (tự chạy khi boot Orange Pi)

Tạo file /etc/systemd/system/radar-web.service:

[Unit]
Description=LD2453 Radar Web Visualizer
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=orangepi
WorkingDirectory=/home/orangepi/orangepi-server
ExecStart=/home/orangepi/orangepi-server/venv/bin/python3 /home/orangepi/orangepi-server/visualizer.py 192.168.1.100 --port 8000
Restart=always
RestartSec=5
Environment=PYTHONUNBUFFERED=1

[Install]
WantedBy=multi-user.target

Sau đó:

sudo systemctl daemon-reload
sudo systemctl enable radar-web
sudo systemctl start radar-web
journalctl -u radar-web -f   # Xem log realtime

6.3 Tùy chỉnh giao diện

  • Màu sắc & chủ đề: chỉnh các biến CSS ở đầu file static/style.css (định nghĩa --z1, --t1, --bg…)
  • Range hiển thị: chỉnh hằng MAP.X_MIN/X_MAX/Y_MIN/Y_MAX trong static/app.js
  • Mặc định zones: sửa DEFAULT_ZONES trong static/app.js và STATE.zones[0..2] trong visualizer.py

7. Troubleshooting — Kiểm tra lỗi nhanh

7.1 Quick check trong 60 giây

Nếu backend log "Đã kết nối WebSocket tới ESP32" nhưng web không thấy dữ liệu, làm theo thứ tự:

  1. Mở DevTools (F12) → tab Console:

    • Gõ: await fetch('/api/state').then(r=>r.json()).then(d=>console.log(d))
    • Kết quả đúng phải là object có zones và targets (3 phần tử mỗi mảng)
    • Nếu nhận được object: WebSocket frontend đang có vấn đề (hãy xem log có chữ [Radar] WebSocket closed?)
    • Nếu không nhận được: backend có vấn đề (xem log terminal backend)
  2. Xem 2 chip trạng thái trên header (góc trên phải):

    • ESP32: Đã kết nối (xanh) — backend ↔ ESP32 OK
    • WS: Đã kết nối (xanh) — trình duyệt ↔ backend OK
    • Nếu WS màu đỏ: mở DevTools → Network → WS → chọn /ws → xem "Messages" có dòng nào không.
  3. Hiển thị gì phải có ngay cả khi parser ESP32 là stub?

    • Grid, vòng tròn khoảng cách, radar (điểm đỏ dưới cùng), 3 zones theo mặc định phải hiện rõ ràng
    • Chip ESP32 phải xanh, Frames trong Thống kê = 0 là bình thường (parser stub)
    • Target không thấy là Bình thường nếu parser chưa implement — nhưng zones & grid PHẢI hiện.

7.2 Không mở được trang web

  1. Ping Orange Pi: ping <OrangePi_IP>
  2. Kiểm tra port đang mở: ss -tulpn | grep 9000 (thay 9000 bằng port bạn dùng)
  3. Tường lửa? sudo ufw allow 9000/tcp hoặc tạm thời sudo ufw disable
  4. Visualizer đang chạy? ps aux | grep visualizer

7.3 Không thấy dữ liệu radar / không có target

  1. Kiểm tra 2 chip trạng thái (section 7.1)
  2. Ping ESP32: ping 192.168.88.32 (thay IP của bạn)
  3. Test REST ESP32: curl http://192.168.88.32/status → phải trả JSON {"status":"ok",...}
  4. Test state từ backend (ngoài trình duyệt): curl http://<OrangePi_IP>:9000/api/state → object JSON 2 mảng zones + targets
  5. ESP32 đang DIAGNOSTIC_MODE 1? → phải là 0 mới có WiFi/WebSocket
  6. Parser ESP32 vẫn là stub? → Target luôn = 0 / INVALID là BÌNH THƯỜNG cho đến khi bạn implement tryParseFrame() thật trong LD2453Parser.cpp. Grid + zones vẫn phải hiện.

7.4 Tốc độ cập nhật chậm

  • Mặc định radar LD2453 gửi ~2 frame/giây. Đó là giới hạn phần cứng.
  • Bảo đảm Orange Pi gửi state liên tục: heartbeat 1 giây luôn gửi ngay cả khi ESP32 không gửi frame mới.
  • Đảm bảo Orange Pi và ESP32 có tín hiệu WiFi tốt.

7.5 WebSocket không kết nối (trình duyệt báo lỗi)

  • Mở DevTools (F12) → Console sẽ log rõ ràng: [Radar] WebSocket closed (code=...)
    • code=1006: mạng bị ngắt giữa chừng → tự động reconnect 2s sau
    • code=403/404: mở sai port hoặc sai path
  • Kiểm tra trình duyệt truy cập đúng http://<IP>:9000 (KHÔNG https://)
  • Nếu mở trên mobile cùng WiFi mà không được: tắt "VPN / Private DNS / Use random MAC" trên điện thoại thử lại
  • Nếu dùng reverse proxy (Caddy/Nginx): cấu hình WebSocket upgrade (header Upgrade: websocket)

8. So sánh với bản cũ (Tkinter/Pygame)

Đặc điểm Tkinter cũ Web Visualizer mới
Cần màn hình gắn Orange Pi? ✅ Có ❌ Không (xem trên trình duyệt bất kỳ đâu)
Xem trên điện thoại? ❌ Không ✅ Có
Nhiều người xem cùng lúc? ❌ 1 người ✅ Không giới hạn (multi-client)
Đồ họa đẹp? ⭐⭐ cơ bản ⭐⭐⭐⭐⭐ Canvas2D + hiệu ứng + sáng/tối
Chỉnh sửa zones? Edit code Python ✅ Form trên web
Song ngữ VI/EN? ❌ Không ✅ Có
Responsive mobile? ❌ Không ✅ Có


🇬🇧 English Version

ESP32-S3 LD2453 Radar — Orange Pi Web Visualizer

Installation and usage guide for the Web Visualizer on Orange Pi (or any machine with Python 3.8+) to display realtime radar data via a beautiful web interface — no Tkinter/Pygame desktop required anymore.


1. Requirements

  • Orange Pi / Raspberry Pi / Any PC with Python 3.8+
  • Same LAN as the ESP32 (Wi-Fi or Ethernet)
  • ESP32 IP address known (check Serial Monitor at boot, or router admin)

1.1 Folder structure

orangepi-server/
├── visualizer.py          # FastAPI server: connects to ESP32 + broadcasts to browsers
├── requirements.txt       # Python dependencies
├── templates/
│   └── index.html         # Web UI HTML
└── static/
    ├── style.css          # Styling: light/dark, responsive, bilingual
    └── app.js             # Canvas renderer + browser WebSocket client

1.2 Copy files to Orange Pi

Copy the whole orangepi-server/ folder to the Orange Pi. SCP example:

scp -r orangepi-server/ orangepi@<ORANGE_PI_IP>:/home/orangepi/

2. Install Python dependencies

cd ~/orangepi-server

# (Recommended) Use a virtual env
python3 -m venv venv
source venv/bin/activate

# Install dependencies
pip install -r requirements.txt

Global install (faster, not recommended):

pip3 install -r requirements.txt

No python3-tk needed — everything runs in the browser.


3. Usage

3.1 Flash ESP32 in Full Stage mode

In config.h (Arduino IDE):

#define DIAGNOSTIC_MODE 0   // Full mode: WiFi + WebSocket + REST API

Flash the code, grab the ESP32 IP from Serial Monitor. Example: 192.168.1.100.

3.2 Start the Web Visualizer on Orange Pi

source venv/bin/activate   # if using venv
python3 visualizer.py 192.168.1.100

CLI options:

# Custom port (default 8000):
python3 visualizer.py 192.168.1.100 --port 8080

# Restrict to localhost only:
python3 visualizer.py 192.168.1.100 --host 127.0.0.1

# Verbose logging:
python3 visualizer.py 192.168.1.100 --verbose

The console will print:

==============================================================
  ESP32-S3 LD2453 Radar — Web Visualizer
==============================================================
  ESP32   : ws://192.168.1.100/ws
  Web UI  : http://0.0.0.0:8000/
  WS UI   : ws://<OrangePi_IP>:8000/ws
==============================================================

3.3 Open the web UI on any device

On any device on the same LAN (phone, laptop, desktop…) open:

http://<OrangePi_IP>:8000/

Example: if Orange Pi IP is 192.168.1.50 → http://192.168.1.50:8000/


4. Web UI features

4.1 Highlights

Feature Description
🎨 Beautiful UI Light/Dark themes with Catppuccin color palette
🌐 Bilingual Vietnamese / English toggle in header
📱 Responsive Looks great on mobile, tablet, desktop
🧭 Radar Canvas Grid, concentric range rings, sweep animation
🎯 Targets Up to 3 colored targets, trails, velocity arrows, labels
🟩 Zones 3 rectangular zones with occupancy state badges
📊 Stats Frames received, valid targets, occupied zones, latency
📝 Details Per-target and per-zone info in the right panel
✏️ Zone editor Edit zone coordinates directly in the UI → pushes to ESP32
🔗 Multi-client Any number of browser tabs/screens stay in sync

4.2 Header

  • 🟢/🟡/🔴 ESP32 + WebSocket connection status chips
  • ☀️/🌙 Theme toggle (Light/Dark)
  • VI / EN Language toggle

4.3 Radar View (Canvas)

  • Grid: 1m cells with labels (−5m ← 0 → +5m horizontal, 0 → 7m forward)
  • Range rings: Dashed concentric arcs every 1m from the radar
  • Radar dot: Red circle at bottom-center with "RADAR" label
  • Sweep effect: Rotating semi-transparent cone (toggleable)
  • Zones (3 rectangles):
    • Z1 (Green), Z2 (Orange), Z3 (Red)
    • Occupied → solid fill, bold border, OCCUPIED badge
    • Empty → faint fill, dashed border, EMPTY badge
  • Targets (3 slots):
    • Colors: Yellow (S1), Purple (S2), Cyan (S3)
    • Glowing dots with white outline
    • Velocity arrow (length ∝ cm/s, points along direction)
    • Label: T# | X,Y mm | speed cm/s
    • Fading trail for each target, persists ~3.5s
    • Recently-lost targets show as dashed ghost circles

4.4 Tool toggles (top-right of canvas)

  • Sweep effect on/off
  • Target trails on/off
  • Zone/target labels on/off

4.5 Side panels (right column)

Statistics:

  • Total frames received
  • Seconds since last frame
  • Valid targets / 3
  • Occupied zones / 3

Target details:

  • Colored cards per target with status badge (Detected/Recently seen/Free)
  • X/Y (mm), Speed (cm/s), Distance (m), Angle (°)

Zones:

  • Per-zone list with coordinates and status
  • Edit zones button opens a form (X1/Y1/X2/Y2 in mm):
    • Reset defaults → reload original layout
    • Cancel → close without saving
    • Save & Apply → POST to /api/zones → forwarded to ESP32 /updateZones with success toast

5. Architecture & data flow

 ┌───────────┐     WebSocket /ws     ┌──────────────────┐    WebSocket /ws     ┌──────────────┐
 │  ESP32-S3 │ ◄──────────────────► │  Orange Pi (WS   │ ◄──────────────────► │   Browser    │
 │  LD2453   │  JSON radar frames    │  FastAPI Server) │  synced state JSON    │  (Canvas 2D) │
 └───────────┘                       └──────────────────┘                      └──────────────┘
        ▲                                   ▲                                          ▲
        │ REST /zones /updateZones          │ GET / → index.html                      │
        └───────────────────────────────────┘ GET /static/* → CSS, JS                │
                              Zone edits in the UI are forwarded to the ESP32          │

Endpoints:

Method Endpoint Purpose
GET / Main web page
GET /api/state Current radar state (fallback poll)
GET /api/zones Zones list
POST /api/zones Update zones (forwarded to ESP32 /updateZones)
WS /ws Realtime broadcast for browser clients

6. Background running & customization

6.1 Run with tmux

tmux new -s radar
cd ~/orangepi-server && source venv/bin/activate
python3 visualizer.py 192.168.1.100
# Ctrl+B D → detach; tmux attach -t radar to return

6.2 systemd service (auto-start at boot)

Create /etc/systemd/system/radar-web.service:

[Unit]
Description=LD2453 Radar Web Visualizer
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=orangepi
WorkingDirectory=/home/orangepi/orangepi-server
ExecStart=/home/orangepi/orangepi-server/venv/bin/python3 /home/orangepi/orangepi-server/visualizer.py 192.168.1.100 --port 8000
Restart=always
RestartSec=5
Environment=PYTHONUNBUFFERED=1

[Install]
WantedBy=multi-user.target

Then:

sudo systemctl daemon-reload
sudo systemctl enable radar-web
sudo systemctl start radar-web
journalctl -u radar-web -f   # Live logs

6.3 Customization tips

  • Colors/themes: edit CSS variables at top of static/style.css (--z1, --t1, --bg…)
  • Display range: tweak MAP.X_MIN/X_MAX/Y_MIN/Y_MAX constants in static/app.js
  • Default zones: modify DEFAULT_ZONES in static/app.js and STATE.zones[0..2] in visualizer.py

7. Troubleshooting

Can't open the web page

  1. Ping Orange Pi: ping <OrangePi_IP>
  2. Check open port: ss -tulpn | grep 8000
  3. Firewall? sudo ufw allow 8000/tcp
  4. Is visualizer running? ps aux | grep visualizer

No radar targets visible

  1. Check ESP32 connection status chip (top-right corner of UI)
  2. Ping ESP32: ping 192.168.1.100
  3. Test ESP32 REST: curl http://192.168.1.100/status → JSON expected
  4. ESP32 still in DIAGNOSTIC_MODE 1? → set to 0 for WiFi/WebSocket
  5. ESP32 parser is still stubbed? → Targets always INVALID until real byte parser is implemented (see main repo README)

Slow UI updates

  • LD2453 radar sends ~2 frames/second by design (hardware limit)
  • Ensure good Wi-Fi signal on both ESP32 and Orange Pi

Browser WebSocket fails to connect

  • Open DevTools → Console for the exact error
  • Make sure you visit http://<IP>:8000 (not https://)
  • If behind Caddy/Nginx: enable WebSocket upgrade headers (Upgrade: websocket)

8. Comparison with old Tkinter/Pygame version

Aspect Old Tkinter New Web Visualizer
Requires a monitor on Orange Pi? Yes ❌ No — view anywhere
View on phone? No ✅ Yes
Multiple viewers? No ✅ Unlimited clients
Graphics quality Basic ⭐⭐ Canvas + effects + themes ⭐⭐⭐⭐⭐
Zone editor Edit Python ✅ In-UI form
i18n (VI/EN) No ✅ Built-in
Mobile responsive No ✅ Yes