.
This commit is contained in:
parent
954fa3ceac
commit
aee55b8d5d
59
app/page.tsx
59
app/page.tsx
@ -1,14 +1,19 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
export default function RobotDashboard() {
|
export default function RobotDashboard() {
|
||||||
const streamUrl = 'http://172.17.19.107:8080/stream';
|
// Ganti dengan IP Tailscale Pi atau IP lokal
|
||||||
|
const PI_IP = '172.17.19.107';
|
||||||
|
const streamUrl = `http://${PI_IP}:8080/stream`;
|
||||||
|
|
||||||
const [gamepadStatus, setGamepadStatus] = useState("Menunggu pemindaian...");
|
const [gamepadStatus, setGamepadStatus] = useState("Menunggu...");
|
||||||
const [steering, setSteering] = useState({ x: 0, y: 0 });
|
const [steering, setSteering] = useState({ x: 0, y: 0 });
|
||||||
|
|
||||||
// Fungsi untuk memaksa baca secara manual saat tombol diklik
|
// Referensi untuk WebSocket dengan penambahan tipe TypeScript
|
||||||
|
const wsRef = useRef<WebSocket | null>(null);
|
||||||
|
|
||||||
|
// FUNGSI INI KEMBALI DITAMBAHKAN AGAR TOMBOL BISA BEKERJA
|
||||||
const forceScanGamepad = () => {
|
const forceScanGamepad = () => {
|
||||||
if (typeof navigator !== "undefined" && navigator.getGamepads) {
|
if (typeof navigator !== "undefined" && navigator.getGamepads) {
|
||||||
const gamepads = navigator.getGamepads();
|
const gamepads = navigator.getGamepads();
|
||||||
@ -22,15 +27,40 @@ export default function RobotDashboard() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (activeGp) {
|
if (activeGp) {
|
||||||
setGamepadStatus(`🟢 SUKSES DITEMUKAN: ${activeGp.id.substring(0, 20)}`);
|
setGamepadStatus(`🟢 TERHUBUNG: ${activeGp.id.substring(0, 15)}...`);
|
||||||
} else {
|
|
||||||
setGamepadStatus("🔴 TETAP KOSONG. Pastikan URL adalah localhost:3000!");
|
// Joystick Kiri (hanya sumbu X untuk belok)
|
||||||
alert("Gamepad tidak terdeteksi oleh kode. Pastikan kamu membuka web via http://localhost:3000");
|
const rawX = activeGp.axes[0];
|
||||||
|
|
||||||
|
// Membaca Trigger LT dan RT (nilainya 0.0 hingga 1.0)
|
||||||
|
const lt = activeGp.buttons[6].value;
|
||||||
|
const rt = activeGp.buttons[7].value;
|
||||||
|
|
||||||
|
// Logika Gas: RT positif (Maju), LT negatif (Mundur)
|
||||||
|
const throttle = rt - lt;
|
||||||
|
|
||||||
|
const x = Math.abs(rawX) > 0.15 ? Number(rawX.toFixed(2)) : 0;
|
||||||
|
const y = Number(throttle.toFixed(2)); // Kita tetap namakan 'y' agar backend mudah membacanya
|
||||||
|
|
||||||
|
setSteering({ x, y });
|
||||||
|
|
||||||
|
// 3. KIRIM DATA KE RASPBERRY PI
|
||||||
|
if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
|
||||||
|
wsRef.current.send(JSON.stringify({ x, y }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// 1. Buka Koneksi WebSocket ke Pi
|
||||||
|
const ws = new WebSocket(`ws://${PI_IP}:8765`);
|
||||||
|
|
||||||
|
ws.onopen = () => console.log("WebSocket Terhubung ke Pi!");
|
||||||
|
ws.onclose = () => console.log("WebSocket Terputus.");
|
||||||
|
wsRef.current = ws;
|
||||||
|
|
||||||
|
// 2. Loop Joystick
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
if (typeof navigator !== "undefined" && navigator.getGamepads) {
|
if (typeof navigator !== "undefined" && navigator.getGamepads) {
|
||||||
const gamepads = navigator.getGamepads();
|
const gamepads = navigator.getGamepads();
|
||||||
@ -43,8 +73,7 @@ export default function RobotDashboard() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (activeGp) {
|
if (activeGp) {
|
||||||
setGamepadStatus(`🟢 TERHUBUNG: ${activeGp.id.substring(0, 20)}...`);
|
setGamepadStatus(`🟢 TERHUBUNG: ${activeGp.id.substring(0, 15)}...`);
|
||||||
|
|
||||||
const rawX = activeGp.axes[0];
|
const rawX = activeGp.axes[0];
|
||||||
const rawY = activeGp.axes[1];
|
const rawY = activeGp.axes[1];
|
||||||
|
|
||||||
@ -52,11 +81,19 @@ export default function RobotDashboard() {
|
|||||||
const y = Math.abs(rawY) > 0.15 ? Number(rawY.toFixed(2)) : 0;
|
const y = Math.abs(rawY) > 0.15 ? Number(rawY.toFixed(2)) : 0;
|
||||||
|
|
||||||
setSteering({ x, y });
|
setSteering({ x, y });
|
||||||
|
|
||||||
|
// 3. KIRIM DATA KE RASPBERRY PI
|
||||||
|
if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
|
||||||
|
wsRef.current.send(JSON.stringify({ x, y }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
return () => {
|
||||||
|
clearInterval(interval);
|
||||||
|
if (wsRef.current) wsRef.current.close();
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user