41 lines
1.4 KiB
React
41 lines
1.4 KiB
React
import { useState } from 'react'
|
|
import { CameraControls } from './components/CameraControls.jsx'
|
|
import { RobotControls } from './components/RobotControls.jsx'
|
|
import { VideoStream } from './components/VideoStream.jsx'
|
|
import { useWebSocket } from './hooks/useWebSocket.js'
|
|
|
|
export default function App() {
|
|
const [jointStates, setJointStates] = useState({})
|
|
const [range, setRange] = useState(null)
|
|
|
|
const send = useWebSocket((msg) => {
|
|
if (msg.type === 'joint_states') setJointStates(msg.positions)
|
|
if (msg.type === 'ultrasonic') setRange(msg.range)
|
|
})
|
|
|
|
return (
|
|
<div style={{ display: 'flex', flexDirection: 'column', height: '100vh', padding: 8, gap: 8 }}>
|
|
{/* Header */}
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexShrink: 0 }}>
|
|
<span style={{ fontSize: 13, color: '#4ade80', letterSpacing: 2 }}>RASPBOT</span>
|
|
{range !== null && (
|
|
<span style={{ fontSize: 12, color: range < 0.3 ? '#f87171' : '#facc15' }}>
|
|
▶ {range.toFixed(2)} m
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
{/* Video */}
|
|
<div style={{ flexShrink: 0 }}>
|
|
<VideoStream />
|
|
</div>
|
|
|
|
{/* Controls */}
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 16, flex: 1 }}>
|
|
<RobotControls send={send} />
|
|
<CameraControls send={send} jointStates={jointStates} />
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|