From a8f52b6d1a5600c677c1635de2e45a69f2f886ac Mon Sep 17 00:00:00 2001 From: Nathaniel Hargrave Date: Mon, 13 Jul 2026 17:52:34 -0400 Subject: [PATCH 1/2] CIRC 0.5 updates: stale indicators, disable go, and reset all --- src/components/panels/ArmControlPanel.tsx | 4 +- src/components/panels/MotorStatusPanel.tsx | 44 ++++++++++++++++++++-- src/components/panels/NodeStatusPanel.tsx | 29 ++++++++++---- 3 files changed, 65 insertions(+), 12 deletions(-) diff --git a/src/components/panels/ArmControlPanel.tsx b/src/components/panels/ArmControlPanel.tsx index b6deba6..6deef4c 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..4012b92 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,11 @@ const MotorStatusPanel: React.FC = () => { ); }; + const handleResetAll = () => { + (Object.entries(MOTORS) as [MotorKey, typeof MOTORS[MotorKey]][]).map( + ([key, { label, topic }]) => handleResetErrors(key, topic)); + }; + useEffect(() => { if (!ros) return; @@ -140,7 +146,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 +159,33 @@ const MotorStatusPanel: React.FC = () => { return () => unsubscribers.forEach(unsub => unsub()); }, [ros]); + useEffect(() => { + const interval = window.setInterval(() => { + for (const key in motorStats) { + setMotorStats(prev => ({ + ...prev, + [key]: prev[key as MotorKey] + ? { + ...prev[key as MotorKey], + remaining: prev[key as MotorKey]!.remaining - 0.1, + } + : prev[key as MotorKey], + })); + } + }, 100); + + return () => window.clearInterval(interval); + }, [motorStats]); + return (
+ @@ -169,10 +201,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 +218,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}