saltylab-firmware/ui/map_panel.html
sl-webui f71dad5344 feat(arch): migrate all STM32/Mamba/BlackPill refs to ESP32 BALANCE/IO + fix roslib@1.4.0
Architecture change (2026-04-03): Mamba F722S (STM32F722) and BlackPill
replaced by ESP32 BALANCE (PID loop) and ESP32 IO (motors/sensors/comms).

- Update CLAUDE.md, docs, chassis BOM/ASSEMBLY, pinout, power-budget,
  wiring-diagram, TEAM.md, AUTONOMOUS_ARMING.md, docker-compose
- Update all ROS2 package comments, config labels, launch args
  (stm32_port→esp32_port, /dev/stm32-bridge→/dev/esp32-bridge)
- Update WebUI: stm32Mode→esp32Mode, stm32Version→esp32Version,
  "STM32 State/Mode" labels → "ESP32 State/Mode" (ControlMode, SettingsPanel)
- Add TODO(esp32-migration) markers on stm32_protocol.py and mamba_protocol.py
  binary frame layouts — pending ESP32 protocol spec from max
- Fix roslib CDN 1.3.0→1.4.0 in all 11 HTML panels (fixes ROS2 Humble
  rosbridge "Received a message without an op" incompatibility)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 08:25:24 -04:00

177 lines
5.6 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<title>Saltybot — Map View</title>
<link rel="stylesheet" href="map_panel.css">
<script src="https://cdn.jsdelivr.net/npm/roslib@1.4.0/build/roslib.min.js"></script>
</head>
<body>
<!-- ── Header ── -->
<div id="header">
<div class="logo">⚡ SALTYBOT — MAP</div>
<div id="conn-dot"></div>
<input id="ws-input" type="text" value="ws://localhost:9090" placeholder="ws://robot-ip:9090" />
<button id="btn-connect" class="hbtn">CONNECT</button>
<span id="conn-label" style="color:#4b5563;font-size:10px">Not connected</span>
</div>
<!-- ── Toolbar ── -->
<div id="toolbar">
<button id="btn-zoom-in" class="hbtn"></button>
<button id="btn-zoom-out" class="hbtn"></button>
<span id="zoom-display">1.00x</span>
<div class="tsep"></div>
<button id="btn-center" class="hbtn on">⊙ AUTO-CENTER</button>
<button id="btn-reset" class="hbtn">RESET VIEW</button>
<div class="tsep"></div>
<button id="btn-clear-trail" class="hbtn">CLEAR TRAIL</button>
<div class="tsep"></div>
<!-- Legend -->
<div style="display:flex;flex-direction:column;gap:2px">
<div class="legend-row">
<div class="legend-swatch" style="background:#22c55e"></div>
<span>LIDAR scan</span>
</div>
<div class="legend-row">
<div class="legend-swatch" style="background:rgba(239,68,68,.6)"></div>
<span>Danger zone (0.30m)</span>
</div>
</div>
<div style="display:flex;flex-direction:column;gap:2px">
<div class="legend-row">
<div class="legend-swatch" style="background:rgba(245,158,11,.5)"></div>
<span>Warn zone (1.00m)</span>
</div>
<div class="legend-row">
<div class="legend-swatch" style="background:#06b6d4"></div>
<span>Trail (100 pts)</span>
</div>
</div>
<div class="legend-row">
<div class="legend-swatch" style="background:#f59e0b;height:8px;width:8px;border-radius:0;transform:rotate(45deg);flex-shrink:0"></div>
<span>UWB anchor</span>
</div>
</div>
<!-- ── Main ── -->
<div id="main">
<!-- Map canvas -->
<div id="map-wrap">
<canvas id="map-canvas"></canvas>
<!-- No signal -->
<div id="no-signal">
<div class="icon">🗺️</div>
<div>Connect to rosbridge to view map</div>
<div style="font-size:10px;color:#374151">
/saltybot/pose/fused · /scan · /saltybot/safety_zone/status
</div>
</div>
<!-- E-stop banner -->
<div id="estop-overlay">🛑 E-STOP ACTIVE</div>
<!-- Mouse coords -->
<div id="coords-hud">(0.00, 0.00) m</div>
</div>
<!-- Sidebar -->
<aside id="sidebar">
<!-- Robot status -->
<div class="sb-card">
<div class="sb-title">Robot Position</div>
<div class="sb-row">
<span class="sb-lbl">Position</span>
<span class="sb-val" id="sb-pos"></span>
</div>
<div class="sb-row">
<span class="sb-lbl">Heading</span>
<span class="sb-val" id="sb-hdg"></span>
</div>
<div class="sb-row">
<span class="sb-lbl">Trail</span>
<span class="sb-val" id="sb-trail">0 pts</span>
</div>
</div>
<!-- Safety status -->
<div class="sb-card">
<div class="sb-title">Safety Zone</div>
<div class="sb-row">
<span class="sb-lbl"><span class="sdot gray" id="sb-zone-dot"></span>Fwd zone</span>
<span class="sb-val" id="sb-fwd"></span>
</div>
<div class="sb-row">
<span class="sb-lbl">Closest</span>
<span class="sb-val" id="sb-closest"></span>
</div>
<div class="sb-row">
<span class="sb-lbl">E-stop</span>
<span class="sb-val" id="sb-estop" style="color:#6b7280"></span>
</div>
</div>
<!-- UWB anchors -->
<div class="sb-card">
<div class="sb-title">UWB Anchors</div>
<div id="anchor-list"></div>
<!-- Add anchor form -->
<div style="margin-top:8px;font-size:9px;color:#6b7280;margin-bottom:4px">
ADD ANCHOR
</div>
<div class="anchor-inputs">
<input id="anc-x" type="number" step="0.1" placeholder="X (m)" />
<input id="anc-y" type="number" step="0.1" placeholder="Y (m)" />
<input id="anc-lbl" type="text" placeholder="Label" />
</div>
<button id="btn-add-anchor" class="hbtn" id="anchor-add"
style="width:100%;margin-top:6px;text-align:center">
+ ADD ANCHOR
</button>
</div>
<!-- Legend / topics -->
<div class="sb-card">
<div class="sb-title">Topics</div>
<div style="font-size:9px;color:#374151;line-height:1.9">
<div>SUB <code style="color:#4b5563">/saltybot/pose/fused</code></div>
<div style="color:#1e3a5f;padding-left:8px">geometry_msgs/PoseStamped</div>
<div>SUB <code style="color:#4b5563">/scan</code></div>
<div style="color:#1e3a5f;padding-left:8px">sensor_msgs/LaserScan</div>
<div>SUB <code style="color:#4b5563">/saltybot/safety_zone/status</code></div>
<div style="color:#1e3a5f;padding-left:8px">std_msgs/String (JSON)</div>
</div>
</div>
</aside>
</div>
<!-- ── Footer ── -->
<div id="footer">
<span>wheel=zoom · drag=pan · pinch=zoom (touch)</span>
<span>rosbridge: <code id="footer-ws">ws://localhost:9090</code></span>
<span>map view — issue #587</span>
</div>
<script src="map_panel.js"></script>
<script>
document.getElementById('ws-input').addEventListener('input', (e) => {
document.getElementById('footer-ws').textContent = e.target.value;
});
</script>
</body>
</html>