Spaces:
Running
Running
| Plan for SimpleDances reachy mini app (v1) | |
| ========================================= | |
| 0. Context & goals | |
| ------------------ | |
| - Reuse the structure of `reachy_mini_radio` to build a Reachy Mini app with a custom UI hosted from `SimpleDances/SimpleDances/static`. | |
| - Drive actual motions using `reachy_mini_dances_library`, exposing *all* available moves with tunable parameters. | |
| - Provide a clean web UI with dance selection, parameter sliders + numeric inputs, start/stop toggle, BPM + amplitude sliders, reset-to-default per dance, and a rhythmic visualization tied to all 8 DoF (6 head + 2 antenna) using live data from the control loop. | |
| - Persist parameter tweaks so each dance remembers its last settings between runs. | |
| 1. Backend design (SimpleDances/SimpleDances/main.py) | |
| ---------------------------------------------------- | |
| - Import `AVAILABLE_MOVES` + antenna metadata from the dance library, and pre-compute a catalog: name, friendly label (title case), description, default params, metadata (duration, etc.). | |
| - Build helpers to: | |
| * Load/save persisted parameters (JSON file adjacent to main.py). Structure: `{ "globals": {"bpm": float, "amplitude_scale": float}, "dances": {dance_name: {param: value}} }`. | |
| * Merge saved params with defaults per dance. | |
| * Derive UI specs for each param (type, slider min/max/step, unit, display multiplier) using heuristics based on the param name (e.g. `_rad` => degrees slider ±(default*3 capped), `_m` => centimeters range, `subcycles` => 0-4, `phase_offset` => 0-1, enumerations for waveform/antenna moves). | |
| * Convert between internal units and UI units when serving values + when updates arrive. | |
| - Shared runtime state guarded by a `threading.Lock`: selected dance name, per-dance params, BPM, amplitude scale, playing flag, timestamps, last computed offsets for visualization, file persistence timestamps, etc. | |
| - Settings API endpoints on `self.settings_app`: | |
| * `GET /api/dances` -> list of dances (name, label, description). | |
| * `GET /api/state` -> current selection, playing flag, bpm, amplitude scale, parameter specs for the selected dance (values already converted for UI), and last-saved timestamp. | |
| * `POST /api/select` -> pick a dance (payload: `{name}`), responds with updated param specs + selection. | |
| * `POST /api/params` -> update parameters for the (selected) dance; payload includes `name` + `params` dictionary in UI units; convert, persist, respond with new specs. | |
| * `POST /api/globals` -> update BPM and amplitude scale with validation + persistence. | |
| * `POST /api/toggle` -> set playing flag (payload `{"playing": bool}`) and resets timing when toggling on. | |
| * `POST /api/reset` -> reset a dance back to defaults (payload `{"name": ...}`) with save + updated specs. | |
| * `GET /api/visualization` -> return most recent normalized offsets (position/orientation/antennas arrays) for front-end animation plus playing + bpm (read-only, polled at ~10–15 Hz by UI). | |
| - Control loop logic: | |
| * On `run`, load ReachyMini, ensure motors enabled as needed (maybe only when playing), instantiate start time. | |
| * Inside loop (50–100 Hz), read `state` snapshot; if playing and a dance is selected, compute beat time using global BPM, call the corresponding move function with stored params, scale offsets by amplitude scale, convert to head pose with `create_head_pose`, and send `reachy_mini.set_target(head=head_pose, antennas=...)`. If stopped, gradually go to neutral pose (or hold last command) to avoid abrupt freeze. | |
| * Update shared `latest_offsets` for visualization each cycle, store for `/api/visualization`. | |
| * Sleep for ~0.02s. | |
| - Persist JSON whenever params/globals change (debounce by writing immediately under lock). | |
| - Handle graceful shutdown (stop flag already provided); ensure motors disabled on exit. | |
| 2. Front-end (SimpleDances/SimpleDances/static/{index.html,style.css,main.js}) | |
| ----------------------------------------------------------------------------- | |
| - Layout: split page with header, global controls, dance selector, parameter panel, start/stop button, and visualization canvas/bars. | |
| - Use CSS with pastel gradient, glassmorphism cards, responsive grid for parameter controls. | |
| - JS boot flow: | |
| * Fetch `/api/dances` once for the list (populate `<select>` or tiles). | |
| * Fetch `/api/state` and render: selection (pre-select from list), global slider values, playing state, params grid. | |
| * On selection change -> POST `/api/select` then update UI. | |
| * Parameter controls: for each spec (value + slider + numeric). Both inputs stay in sync and `debounce` POST `/api/params` updates; show “saved” indicator and disable controls while saving to avoid jitter. | |
| * Reset button -> POST `/api/reset`. | |
| * Start/stop toggle button -> POST `/api/toggle`. | |
| * Global BPM + amplitude sliders with numeric inputs -> POST `/api/globals` when changed (debounced) with validation (BPM 40–180, amplitude 0–2.0 as slider requirements hint). | |
| - Visualization: create `<canvas>` or `<svg>` area that animates arcs/waves based on telemetry from `/api/visualization`. Poll every ~150 ms and animate smoothly using requestAnimationFrame. Map the 8 DoF to color-coded bars/rings (e.g., 3 orientation lines, 3 translation pulses, 2 antenna bars); amplitude drives height/opacity to satisfy “each DoF has an impact”. Provide fallback animation even when not playing (dim, idle oscillation) to keep it “beautiful and simple”. | |
| 3. Persistence + utilities | |
| -------------------------- | |
| - JSON file path: `SimpleDances/SimpleDances/dance_params.json` (auto-created). On failure to load parseable JSON, fall back to defaults but keep file for next writes. | |
| - Provide helper to sanitize payloads and ensure only known params are stored. | |
| - On each save, update `state["last_saved"]` so UI can display “Saved at …”. | |
| 4. Testing / validation | |
| ----------------------- | |
| - Manual: lint via running `python -m compileall` or `uv run`? (Not necessary yet but consider). Without hardware, run `python SimpleDances/SimpleDances/main.py` in dry-run to ensure no import errors and that endpoints accept sample requests. | |
| - UI: open `index.html` via app host after hooking to CLI environment (can't do now, but ensure markup includes helpful fallback text + `aria` labels). | |
| Open questions / assumptions | |
| ---------------------------- | |
| - Slider heuristics rely on parameter names; confirm tomorrow whether ranges feel right. Might need fine-tuning later. | |
| - Visualization currently planned as polling endpoint; if future requirement wants streaming/websocket, architecture allows swap. | |