From 79e0be007e21af82bcb15c08e57862207beec0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?PROFERIS=20-=20Mi=C2=B3osz=20Stocki?= Date: Thu, 9 Jul 2026 13:39:40 +0200 Subject: [PATCH] Implement motion timeout. #21 --- web/js/motion.js | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/web/js/motion.js b/web/js/motion.js index 68994d9..1c9dbe8 100644 --- a/web/js/motion.js +++ b/web/js/motion.js @@ -6,13 +6,22 @@ import { MotionEffects } from './motion-effects.js'; const CONFIG = { SEGMENT_SIZE_MM: 25, // Maximum distance between waypoints to prevent out-of-bounds joint-space arcs - BLEND_THRESHOLD_STEPS: 300 // Send next waypoint when within this many steps (prevents deceleration) + BLEND_THRESHOLD_STEPS: 300, // Send next waypoint when within this many steps (prevents deceleration) + WAYPOINT_TIMEOUT_MS: 8000 // Max time to wait for a single waypoint to complete before declaring a stall }; // Global state tracking let steps1 = 0; let steps2 = 0; +function forceUnhome(reason) { + localStorage.setItem('wiji_homed', 'false'); + UI.log(reason, 'warn'); + document.dispatchEvent(new CustomEvent('wiji:unhomed')); + const warningEl = document.getElementById('home-warning'); + if (warningEl) warningEl.style.display = 'block'; +} + // Listen to BLE position updates document.addEventListener('ble:status', (e) => { const msg = e.detail; @@ -25,11 +34,7 @@ document.addEventListener('ble:status', (e) => { if (parts.length > 2) { const isHolding = parts[2] === '1'; if (!isHolding && localStorage.getItem('wiji_homed') === 'true') { - localStorage.setItem('wiji_homed', 'false'); - UI.log('Steppers are not holding. Rehoming required.', 'warn'); - document.dispatchEvent(new CustomEvent('wiji:unhomed')); - const warningEl = document.getElementById('home-warning'); - if (warningEl) warningEl.style.display = 'block'; + forceUnhome('Steppers are not holding. Rehoming required.'); } } } @@ -88,12 +93,24 @@ async function executeQueue() { // Setup interval to monitor progress if (queueCheckInterval) clearInterval(queueCheckInterval); + const waypointStartTime = Date.now(); queueCheckInterval = setInterval(async () => { // Calculate distance to target in steps const dist1 = Math.abs(target.s1 - steps1); const dist2 = Math.abs(target.s2 - steps2); const maxDist = Math.max(dist1, dist2); + // Check for timeout stall + if (Date.now() - waypointStartTime > CONFIG.WAYPOINT_TIMEOUT_MS) { + clearInterval(queueCheckInterval); + motionQueue = []; + isMoving = false; + forceUnhome('Motion timeout! Arms may be stuck. Rehoming required.'); + if (currentResolve) currentResolve(false); + currentResolve = null; + return; + } + if (motionQueue.length > 0) { const nextTarget = motionQueue[0]; const queueAction = MotionEffects.getQueueAction(target.mode, nextTarget.mode, maxDist, CONFIG.BLEND_THRESHOLD_STEPS);