diff --git a/src/components/panels/ArmControlPanel.tsx b/src/components/panels/ArmControlPanel.tsx index b6deba6..50e866d 100644 --- a/src/components/panels/ArmControlPanel.tsx +++ b/src/components/panels/ArmControlPanel.tsx @@ -373,7 +373,7 @@ const ArmControlPanel: React.FC = () => { /> - @@ -539,4 +539,4 @@ const ArmControlPanel: React.FC = () => { ); }; -export default ArmControlPanel; \ No newline at end of file +export default ArmControlPanel; diff --git a/src/components/panels/MotorStatusPanel.tsx b/src/components/panels/MotorStatusPanel.tsx index 1f4ef08..e45261a 100644 --- a/src/components/panels/MotorStatusPanel.tsx +++ b/src/components/panels/MotorStatusPanel.tsx @@ -8,6 +8,7 @@ type MotorStatus = { velocity: number; output_current: number; active_errors: number; + remaining: number; }; const MOTORS = { @@ -121,6 +122,12 @@ const MotorStatusPanel: React.FC = () => { ); }; + const handleResetAll = () => { + (Object.entries(MOTORS) as [MotorKey, typeof MOTORS[MotorKey]][]).forEach( + ([key, { topic }]) => handleResetErrors(key, topic), + ); + }; + useEffect(() => { if (!ros) return; @@ -140,7 +147,8 @@ const MotorStatusPanel: React.FC = () => { [key]: { velocity: msg.velocity, output_current: msg.output_current, - active_errors: msg.active_errors + active_errors: msg.active_errors, + remaining: 2 }, })); }; @@ -152,8 +160,30 @@ const MotorStatusPanel: React.FC = () => { return () => unsubscribers.forEach(unsub => unsub()); }, [ros]); + useEffect(() => { + const interval = window.setInterval(() => { + setMotorStats(prev => { + const next = { ...prev }; + (Object.keys(prev) as MotorKey[]).forEach(key => { + const stat = prev[key]; + if (!stat) return; + next[key] = { ...stat, remaining: stat.remaining - 0.1 }; + }); + return next; + }); + }, 100); + + return () => window.clearInterval(interval); + }, []); return (
+ @@ -169,10 +199,16 @@ const MotorStatusPanel: React.FC = () => { ([key, { label, topic }]) => { const stat = motorStats[key]; var errorStr = '-'; + var color = "#6c757d"; if (stat) { var errNames: string[] = []; Object.keys(MotorError).forEach((key: string) => { if (stat.active_errors & MotorError[key]) errNames.push(key) }) errorStr = errNames.length ? errNames.join(', ') : "NONE"; + color = errNames.length ? "#ef4444" : "#22c55e"; + if (stat.remaining < 0) { + errorStr = "STALE"; + color = "#ffc107"; + } } return ( @@ -180,7 +216,7 @@ const MotorStatusPanel: React.FC = () => { - +
{label} {stat && Number.isFinite(stat.velocity) ? stat.velocity.toFixed(2) : '-'} {stat && Number.isFinite(stat.output_current) ? `${stat.output_current.toFixed(2)}A` : '-'}{errorStr}{errorStr}