dlouapre HF Staff commited on
Commit
10e6ba6
·
1 Parent(s): 563f5e2

Implement client-side duration control for Spaces deployment

Browse files
Files changed (2) hide show
  1. README.md +3 -3
  2. frontend/app.js +17 -10
README.md CHANGED
@@ -67,9 +67,9 @@ uv run python app.py
67
  ## Current Limitations
68
 
69
  - Sound and picture actions are not yet implemented in execution
70
- - **On HuggingFace Spaces**: Due to browser security policies (HTTPS → HTTP localhost), movement durations may not be fully respected. For accurate timing, run the demo locally.
71
- - Spaces version uses WebSocket fallback which moves faster than specified durations
72
- - Local version uses REST API `/goto` endpoint with proper duration support
73
 
74
  ## Deployment to HuggingFace Spaces
75
 
 
67
  ## Current Limitations
68
 
69
  - Sound and picture actions are not yet implemented in execution
70
+ - **On HuggingFace Spaces**: Due to browser security policies (HTTPS → HTTP localhost), the demo uses a WebSocket fallback instead of the REST API `/goto` endpoint.
71
+ - Timing is approximated by repeatedly sending the target position over the specified duration
72
+ - For smoother interpolated movements with proper minimum-jerk trajectories, run the demo locally
73
 
74
  ## Deployment to HuggingFace Spaces
75
 
frontend/app.js CHANGED
@@ -405,23 +405,30 @@ async function executeIRAction(action) {
405
  await sleep(action.duration * 1000 + 100);
406
 
407
  } catch (fetchError) {
408
- // Fallback to WebSocket (for Spaces deployment)
409
- // Note: This won't respect duration perfectly - movements will be fast
410
- console.warn('Using WebSocket fallback (duration may not be accurate):', fetchError.message);
411
 
412
  if (!state.robotWs || state.robotWs.readyState !== WebSocket.OPEN) {
413
  throw new Error('Robot WebSocket not connected');
414
  }
415
 
416
- const wsMessage = {};
417
- if (head_pose) wsMessage.target_head_pose = head_pose;
418
- if (action.antennas) wsMessage.target_antennas = action.antennas;
419
- if (action.body_yaw !== null) wsMessage.target_body_yaw = action.body_yaw;
420
 
421
- state.robotWs.send(JSON.stringify(wsMessage));
 
 
 
 
422
 
423
- // Wait for duration even though robot may move faster
424
- await sleep(action.duration * 1000);
 
 
 
 
425
  }
426
  }
427
 
 
405
  await sleep(action.duration * 1000 + 100);
406
 
407
  } catch (fetchError) {
408
+ // Fallback to WebSocket with client-side interpolation (for Spaces deployment)
409
+ console.warn('Using WebSocket interpolation fallback for duration:', fetchError.message);
 
410
 
411
  if (!state.robotWs || state.robotWs.readyState !== WebSocket.OPEN) {
412
  throw new Error('Robot WebSocket not connected');
413
  }
414
 
415
+ // Simulate duration by sending intermediate targets
416
+ // Send updates at 10Hz (every 100ms) for smooth movement
417
+ const updateInterval = 100; // ms
418
+ const numSteps = Math.max(1, Math.floor((action.duration * 1000) / updateInterval));
419
 
420
+ for (let step = 0; step <= numSteps; step++) {
421
+ const wsMessage = {};
422
+ if (head_pose) wsMessage.target_head_pose = head_pose;
423
+ if (action.antennas) wsMessage.target_antennas = action.antennas;
424
+ if (action.body_yaw !== null) wsMessage.target_body_yaw = action.body_yaw;
425
 
426
+ state.robotWs.send(JSON.stringify(wsMessage));
427
+
428
+ if (step < numSteps) {
429
+ await sleep(updateInterval);
430
+ }
431
+ }
432
  }
433
  }
434