From 85e464e54b05c4d4e665cb849fa27c08fc9fa923 Mon Sep 17 00:00:00 2001 From: Jetson Nano1 Date: Wed, 20 May 2026 20:08:31 -0400 Subject: [PATCH 1/2] New servo message --- src/components/panels/ScienceControlPanel.tsx | 68 ++++--------------- 1 file changed, 12 insertions(+), 56 deletions(-) diff --git a/src/components/panels/ScienceControlPanel.tsx b/src/components/panels/ScienceControlPanel.tsx index a8b34ca..88416a9 100644 --- a/src/components/panels/ScienceControlPanel.tsx +++ b/src/components/panels/ScienceControlPanel.tsx @@ -22,7 +22,6 @@ type ServoConfig = { defaultPosition: number; minPulseUs: number; maxPulseUs: number; - periodUs: number; maxDegrees: number; frequency: number; type: 'servo'; @@ -32,6 +31,7 @@ type MotorConfig = DCMotorConfig | ServoConfig; type SendCommandFn = ( motorID: number, + type: number, value: number, duration?: number, frequency?: number, @@ -50,6 +50,9 @@ type ServoMotorProps = { disabled: boolean; }; +const TYPE_DC = 0; +const TYPE_SERVO = 1; + function isDCMotor(motor: MotorConfig): motor is DCMotorConfig { return motor.type === 'dc'; } @@ -72,7 +75,6 @@ const motors: MotorConfig[] = [ defaultPosition: 90, minPulseUs: 615, maxPulseUs: 2495, - periodUs: 20000, maxDegrees: 195, frequency: 50, type: 'servo', @@ -83,7 +85,6 @@ const motors: MotorConfig[] = [ defaultPosition: 45, minPulseUs: 615, maxPulseUs: 2495, - periodUs: 20000, maxDegrees: 195, frequency: 50, type: 'servo', @@ -94,7 +95,6 @@ const motors: MotorConfig[] = [ defaultPosition: 45, minPulseUs: 350, maxPulseUs: 2500, - periodUs: 20000, maxDegrees: 360, frequency: 50, type: 'servo', @@ -109,6 +109,7 @@ const ScienceControlPanel: React.FC = () => { const sendCommand: SendCommandFn = ( motorID, + type, value, duration, frequency, @@ -132,6 +133,7 @@ const ScienceControlPanel: React.FC = () => { topic.publish( new ROSLIB.Message({ pin: motorID, + type: type, duty_cycle: dutyCycle, duration: safeDurationMs, frequency, @@ -141,6 +143,7 @@ const ScienceControlPanel: React.FC = () => { console.log('[SCIENCE PWM CMD]', { pin: motorID, + type: type, duty_cycle: dutyCycle, duration: safeDurationMs, frequency, @@ -355,14 +358,14 @@ const DCMotor: React.FC = ({ const safeTime = clamp(time, 0, 65.535); const safeDuty = clamp(duty, 0, 100); - sendCommand(motor.id, safeDuty, safeTime, motor.frequency); + sendCommand(motor.id, TYPE_DC, safeDuty, safeTime, motor.frequency); setStartTime(safeTime); setRemaining(safeTime); }; const handleStop = () => { - sendCommand(motor.id, 0, 0, motor.frequency); + sendCommand(motor.id, TYPE_DC, 0, 0, motor.frequency); setRemaining(null); }; @@ -448,31 +451,10 @@ const ServoMotor: React.FC = ({ disabled, }) => { const [position, setPosition] = useState(motor.defaultPosition); - const [remaining, setRemaining] = useState(null); const clamp = (val: number, min: number, max: number) => Math.min(Math.max(val, min), max); - useEffect(() => { - if (remaining === null) return; - - if (remaining <= 0) { - setRemaining(null); - return; - } - - const interval = window.setInterval(() => { - setRemaining((prev) => { - if (prev === null) return null; - - const next = prev - 0.1; - return next <= 0 ? null : next; - }); - }, 100); - - return () => window.clearInterval(interval); - }, [remaining]); - const handleGo = () => { const safePos = clamp(position, 0, motor.maxDegrees); @@ -480,10 +462,8 @@ const ServoMotor: React.FC = ({ motor.minPulseUs + (safePos / motor.maxDegrees) * (motor.maxPulseUs - motor.minPulseUs); - const dutyPercent = (pulseUs / motor.periodUs) * 100; - - sendCommand(motor.id, dutyPercent, 0.5, motor.frequency, 0); - setRemaining(0.5); + const dutyPercent = (pulseUs * motor.frequency / 1000000) * 100; + sendCommand(motor.id, TYPE_SERVO, dutyPercent, 0, motor.frequency); }; return ( @@ -503,34 +483,10 @@ const ServoMotor: React.FC = ({ /> - {remaining !== null && ( - <> -
{remaining.toFixed(1)}s remaining
- -
-
-
- - )} -
- - -
); From 6bc9623966db2d43c2bd478d97ef878b58425b70 Mon Sep 17 00:00:00 2001 From: Nathaniel Hargrave Date: Tue, 26 May 2026 09:23:58 -0400 Subject: [PATCH 2/2] feat: polarimeter control --- src/components/panels/ScienceControlPanel.tsx | 63 +++++++++++++++---- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/src/components/panels/ScienceControlPanel.tsx b/src/components/panels/ScienceControlPanel.tsx index 88416a9..34de05c 100644 --- a/src/components/panels/ScienceControlPanel.tsx +++ b/src/components/panels/ScienceControlPanel.tsx @@ -7,6 +7,13 @@ import ROSLIB from 'roslib'; // -------------------- // Types + Config // -------------------- + +interface RunPolarimeterResponse { + success: boolean; + message: string; + file_path: string; +} + type DCMotorConfig = { id: number; name: string; @@ -79,16 +86,6 @@ const motors: MotorConfig[] = [ frequency: 50, type: 'servo', }, - { - id: 27, - name: 'Polar Servo', - defaultPosition: 45, - minPulseUs: 615, - maxPulseUs: 2495, - maxDegrees: 195, - frequency: 50, - type: 'servo', - }, { id: 32, name: 'Resin Servo', @@ -107,6 +104,9 @@ const motors: MotorConfig[] = [ const ScienceControlPanel: React.FC = () => { const { ros } = useROS(); + const [title, setTitle] = useState(""); + const [polarStatus, setPolarStatus] = useState(""); + const sendCommand: SendCommandFn = ( motorID, type, @@ -151,6 +151,25 @@ const ScienceControlPanel: React.FC = () => { }); }; + const handlePolar = () => { + if (!ros) return; + + setPolarStatus("Waiting..."); + + const polarSrv = new ROSLIB.Service({ + ros, + name: "/run_polarimeter", + serviceType: "interfaces/srv/RunPolarimeter", + }); + + polarSrv.callService( + new ROSLIB.ServiceRequest({title: title}), + (response: RunPolarimeterResponse) => { + setPolarStatus(response.success ? "Success: " + response.message : "Failed"); + }, + ); + }; + return (

Science Control

@@ -173,6 +192,26 @@ const ScienceControlPanel: React.FC = () => { /> ) )} +
+

Polarimeter

+ + + +
+ + {polarStatus} +
+