Skip to content

FicTrac closed-loop for the v3 designer + web runner - #131

Merged
mbreiser merged 4 commits into
mainfrom
feat/fictrac-closed-loop-v3-runner
Jul 1, 2026
Merged

FicTrac closed-loop for the v3 designer + web runner#131
mbreiser merged 4 commits into
mainfrom
feat/fictrac-closed-loop-v3-runner

Conversation

@mbreiser

@mbreiser mbreiser commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

What

Adds FicTrac fly-on-ball closed-loop to the v3 Experiment Designer and the web runner. FicTrac is modeled as a plugin the web runner executes — its first runner-run plugin (the built-in log plugin is the 2nd; all other plugins still skip). It drives the arena via the local Python bridge (fictrac-bridge/bridge.py) + Mode-3 host-stepping, reusing the proven console machinery extracted into a shared client.

  • Closed-loop: the arena is driven by FicTrac heading (Mode 3, startClosedLoop/stopClosedLoop).
  • Open-loop: FicTrac is only logged while the arena runs its own Mode-2 stim (startRecording/stopRecording) — apply and logging are independent.
  • Logging: the bridge is the single default-on logger — one JSONL, one clock (bridge rx_ms), FicTrac frames + arena commands + runner semantic events interleaved. The console's per-page send-logging wrapper moved into ArenaSession (no more double-logging).

Design decisions (context)

  • Web-first: MATLAB (maDisplayTools) has no FicTracPlugin and no Mode-3 closed-loop — its only closed-loop is analog Mode 4. So this YAML runs on the web runner only for now; matlab: {class: FicTracPlugin} is forward-looking.
  • Rig = physical capability: fictrac is now a recognized rig plugin, declared only where a ball tracker physically exists. New fly-on-ball rig configs/rigs/cshl_g6_2x10_ball.yaml; the flight-arena cshl_g6_2x10.yaml is untouched (so you can't author a closed-loop run you can't do there). The logging bridge is infrastructure, distinct from the FicTrac capability.

Files

  • new js/fictrac-bridge-client.js — shared WS client (coalesced single-flight apply loop), dual-export classic <script>.
  • js/arena-runner-g6.js, js/arena-session.js — runner ops (fictracConnect/Apply/Mark, logMessage) + bridge ownership + logging routing.
  • js/plugin-registry.jsfictrac plugin, Mode 3 added to trialParams, fictrac rig-mapping.
  • arena_console.html — refactored onto the shared client (behavior-preserving).
  • experiment_designer_v3.html — Run-zone FicTrac panel + auto-connect + runSequence wiring.
  • configs/rigs/cshl_g6_2x10_ball.yaml + index.json, demo tests/fixtures/v3_fictrac_closed_loop.yaml, tests.

Verified

  • ✅ Full JS suite green (pixi run test), Prettier clean.
  • ✅ Emulator WS + unified-log path — console and designer connect to the bridge, frames flow (~50 Hz), one arena-log-*.jsonl with fictrac_frame + arena_command + runner events.
  • g6_2x10 smoke test on real hardware (confirms the console/session refactor didn't regress the normal run path).

⚠️ More FicTrac testing needed (not yet done)

  • On-arena FicTrac closed-loop is NOT yet verified — i.e. the arena actually rotating with (simulated/real) FicTrac heading via the designer full-sequence runner and via the console. Needs bench time. Run the bridge with --frames 200 (or load the g6_2x10 active set) so the modulus matches the demo's frame2_h_ccw_200f rotation pattern.
  • Real-FicTrac (not emulator) end-to-end.
  • Latency/jitter feel of the host-streamed Mode-3 loop on hardware.

Follow-ups

  • LAB-144 — full default-on logging redesign (all sessions, retire the console download log, disk auto-naming, page-wide "NOT LOGGING" banners).
  • Docs (CLAUDE.md / ROADMAP) entry for the FicTrac plugin-runner pattern.

🤖 Generated with Claude Code

mbreiser and others added 4 commits July 1, 2026 12:56
…st trialParams)

The inspector's per-condition arena button was a trialParams-only "dry-run"
(LAB-94) — it skipped waits, plugins, and the new setAnalogOut/setDigitalOut,
which was misleading now that the full-sequence runner (LAB-97) exists. Repurpose
it to run the WHOLE selected condition end-to-end.

- onRunConditionDryRun builds a one-step sequence for the selected condition and
  runs it through the same runSequence path as "Run on arena" (waits, allOn/allOff,
  setPositionX, setAnalogOut/setDigitalOut all replay; plugins skipped-with-warning).
  Button relabeled "Run this condition".
- Extract runStepsOnArena() shared by onRunSequence + the per-condition run
  (connect-on-demand + run + button re-sync in one place); drop the now-duplicate
  connect block from onRunSequence.
- preRunCheck(opts) parameterized: { steps, hasRandom, title, body, confirmLabel }
  scopes the confirm to one condition; no-arg = whole sequence.
- renderArenaTestControl shows the button for ANY condition with commands (dropped
  the trialParams-only gate); updated notes/tooltips/comments.
- Footer v0.37 -> v0.38.

Reuses the hardware-verified runSequence path. Browser-verified: the button now
renders for a non-trialParams condition (arena_check), module loads clean, pixi
run test green. The whole-condition run is NOT yet exercised on hardware.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… SD)

One-click AO/DO bench test in the "Load demo" dropdown: a pure-I/O condition
(setDigitalOut + setAnalogOut + waits, NO trialParams) so it runs with no
pattern/SD-card dependency — pairs with the new "Run this condition" button.

- tests/fixtures/v3_g6_io_bench.yaml (new)
- experiment_designer_v3.html: demo dropdown option; footer v0.38 -> v0.39

Browser-verified: demo loads (io_test + 6 commands), no console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Model FicTrac as a plugin the web runner EXECUTES (its first runner-run
plugin; the built-in `log` plugin is the 2nd) via a shared bridge client +
Mode-3 host-stepping. Closed-loop drives the arena from FicTrac heading;
open-loop logs FicTrac while the arena runs its own commands. The Python
bridge is the single default-on logger (one JSONL, one clock).

- js/fictrac-bridge-client.js (new): shared WS client extracted from the
  console's clBridge — coalesced single-flight apply loop; apply/logging are
  independent flags. Console refactored onto it (drops its own send-logging
  wrapper, so no double-logging).
- js/arena-runner-g6.js: translateCommand maps fictrac.* -> fictracConnect/
  Apply/Mark and the built-in log -> logMessage (all other plugins still
  skip); _runIR drives the injected bridge client.
- js/arena-session.js: owns the bridge client (applyFrame routes through
  session.send); per-command + runner-status logging routed to the bridge.
- js/plugin-registry.js: `fictrac` plugin (matlab FicTracPlugin,
  forward-looking); Mode 3 added to trialParams; fictrac recognized as a rig
  plugin (physical fly-on-ball capability).
- experiment_designer_v3.html: Run-zone FicTrac bridge panel + auto-connect
  at run start (gated on a declared fictrac plugin) + runSequence wiring.
- configs/rigs/cshl_g6_2x10_ball.yaml (new) + index.json: fly-on-ball rig
  declaring fictrac; the flight rig cshl_g6_2x10.yaml is left untouched.
- tests: bridge-client suite + runner fictrac/log suite + N12 rig-map
  assertions. Demo fixture: tests/fixtures/v3_fictrac_closed_loop.yaml.

Verified: full JS suite green; emulator WS + unified-log path (console and
designer); g6_2x10 smoke on real hardware. NOT yet verified: on-arena
FicTrac closed-loop (needs bench time). Full default-on logging redesign is
tracked in LAB-144.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…oop-v3-runner

# Conflicts:
#	arena_console.html
#	experiment_designer_v3.html
@mbreiser
mbreiser merged commit 35e1c90 into main Jul 1, 2026
3 checks passed
@mbreiser
mbreiser deleted the feat/fictrac-closed-loop-v3-runner branch July 1, 2026 20:15
mbreiser added a commit that referenced this pull request Jul 2, 2026
* docs(arena-studio): unification design + wireframes v1–v5 + handover

Consolidated onto current main. v5 is the approved density/ergonomics
pass over v4 (one 44px bar; Console essentials + collapsible foot-gun
groups; 150px collapsible run-log) with content re-synced to shipped
main: ArenaSession broker shipped, run-log module built-but-unwired,
plus #126 analog/digital-out, #129 run-whole-condition, #130 0x88 +
panel-display-mode, #131 FicTrac. Handover refreshed to the verified
2026-07-01 shipped-vs-pending table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* arena-studio: ISP firmware-push handoff + same-origin dev artifacts

Groundwork for Arena Studio's "push official builds to panels" flow:

- docs/development/arena-studio-isp-firmware-push-handoff.md — catalog
  schema (isp_file/isp_sha256, firmware repo PR #17), the 0xE0/0xE3/0xC8/
  0xC9 wire flow (encoders already in js/arena-wire-g6.js), UX notes from
  the real fleet reflash, gotchas (CORS: Pages yes / Release assets no).
- flasher/firmware/manifest-dev.json — schema-identical dev catalog to
  develop against until PR #17 + a release tag publish the real one.
- Dev builds (same-origin): isp-progress-display 23d66af (progress bar
  while ISP-flashing + first-boot smiley), both revs, .bin + .uf2; plus
  the current fleet build (dd7d3f9) ISP bins.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
mbreiser added a commit that referenced this pull request Jul 2, 2026
)

Follow-up to #131. Removes the fictrac plugin's cosmetic start/stopRecording (they only logged a marker; the bridge records continuously). Leaves connect/disconnect + startClosedLoop/stopClosedLoop. Camera's recording untouched. Open-loop trials run the arena's own commands with no fictrac call. Windowed recording, if ever wanted, is deferred to LAB-144.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant