Skip to content

ros2-poc: okey-cokey rig — CW/CCW pair protocols, camera + G6 Foxglove dashboard, uFMF tools, ww14 run records (LAB-303) - #269

Merged
16 commits merged into
mainfrom
claude/okey-cokey-rig
Oct 29, 2026
Merged

16 commits merged into
mainfrom
claude/okey-cokey-rig

Conversation

@mbreiser

@mbreiser mbreiser commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

2026-10-28 — main (release 2026-10-27, #274 included) merged in; ready for the candidate with the rig-nodes 0.3.0 re-pin PR. rig_nodes.bias_health and the derive hook ship in rig-nodes 0.3.0 (rig-nodes#1 merged there), so the "needs the next package-set release" note below is satisfied by the re-pin PR in the same candidate. Dropped here: the [feature.dev.activation.env] Zenoh URIs for a sibling path checkout (the dev environment uses git source dependencies since 2026-10-27, so the installed package's configs apply). Kept: the protocols, the camera + G6 Foxglove dashboard (stimulus_node, stimulus_core, dashboard_replay, arena_display), the uFMF tools, rig/config/bias/okey-cokey-bfs-u3-51s5m.json, the ww14 run records, and [feature.viz.target.win-64.activation.env] PATH = '%CONDA_PREFIX%\Library\lib;%PATH%' (ww18 2026-10-28: --foxglove fails without it). Still local, for later: tools/ufmf.py → rig-nodes (numpy is now a rig_nodes run-dependency, so the blocker is gone), arena_display.py + tools/patfile.py → pyDisplayTools.

Summary

The okey-cokey rig work (LAB-303) that lived on two branches without a PR, claude/okey-cokey-pairs and claude/okey-cokey-dashboard (pairs is an ancestor of dashboard). Rebased as one branch onto released main, then merged over the extraction branch feat/rig-nodes-extraction (#274) on 2026-10-26 — this PR is stacked on #274 (base retargeted to that branch so the diff shows only the okey-cokey changes; GitHub retargets it to main when #274 lands). A candidate takes #274 and #269 together (order_prs wants the stack explicit).

  • Protocols (Grace's shape): protocols/g6_color_optomotor_test.yaml and _smoke.yaml run CW/CCW pairs (15 s each, no gap, 10 s dark between pairs); the smoke variant has the same shape.
  • rig/nodes/stimulus_node.py + stimulus_core.py: the expected-vs-observed display + arena-health node behind the camera + G6 Foxglove dashboard (foxglove/arena-okey-cokey.json; pixi run rig -- --stimulus); arena_display.py is a Python port of js/panel-color.js (the unit test runs the JS module under Node to pin the port).
  • dashboard_replay.py, tools/ufmf.py (BIAS uFMF reader), the BIAS camera config for the BFS-U3-51S5M, PowerShell launchers (okey-cokey-start.ps1 starts BIAS, the rig and the server through WMI so a restarting desktop app cannot take them down; bias-ufmf.ps1).
  • Records: bare-PC setup checklist, run sheet, ww14 setup + results (2026-10-22): the full g6_color_optomotor_test run with flies passed, arena 48/48 trials, BIAS 58/58 replies ok, 70 953 frames at 73.3 fps; open finding R4 (a panel-side glyph seen by eye in the second half; controller telemetry clean).
  • rig/pixi.toml: stimulus, test-stimulus, test-stimulus-live tasks; a win-64 viz activation fix (foxglove-bridge DLL path).

What moved with the extraction (2026-10-26)

The shared half of rig/ is now the installed rig_nodes package (reiserlab/rig-nodes, #274). This PR's additions are expressed through it:

Piece Before (on main) Now
rig/nodes/bias_health.py (CountRate + bias_drops) local module moved to rig-nodes — reiserlab/rig-nodes#1; viz_node.py, dashboard_replay.py import rig_nodes.bias_health; its unit checks moved to rig-nodes tests/test_pure.py
foxglove_json.py --stimulus the dashboard replay spliced into the local converter the arena wrapper keeps #274's enrich hook and adds the replay as the generic rewriter's new derive hook (whole record stream → new topics; images by the well-known foxglove.CompressedImage schema name) — the hook is the second half of rig-nodes#1; dashboard_replay.run_streams is unchanged
rig.py --no-fictrac / --stimulus / --stimulus-args edits to the local launcher the same options on the rig_nodes.supervise composition (stimulus_node.py is a Child like viz_node.py; the FicTrac adapter and its udp 60000 preflight are skipped together)
_common imports in stimulus_node.py, viz_node.py, test_stimulus_live.py from _common import … rig_nodes._common / rig_nodes.supervise

Needs rig-nodes ≥ the next package-set release (the one that ships rig-nodes#1): the pinned 0.2.1 has neither rig_nodes.bias_health nor the derive hook, so on the released channel viz_node.py, stimulus_node.py's replay and test-stimulus fail at import. Until then: cd rig && pixi install -e dev with a sibling ../../rig-nodes checkout on feat/bias-health (or main once merged), and run the tasks with -e dev. When rig-nodes releases, re-pin rig_nodes / rig_interfaces in rig/pixi.toml and re-lock (that is a one-line follow-up on this branch or the next candidate).

Still local, listed for rig-nodes in the record's §3.3: rig/tools/ufmf.py (a BIAS reader, device-generic). Not moved here — a follow-up, with patfile.py → pyDisplayTools.

Tier

next candidate (2026-10-28, with the rig-nodes 0.3.0 re-pin PR; the dashboard has been exercised on ww14 with flies, the protocols ran there). Based on main since 2026-10-28.

Release notes

Protocols

  • g6_color_optomotor_test / g6_color_optomotor_smoke now present each color as a CW/CCW pair (15 s each, no gap) with 10 s dark between pairs.

Test plan

  • Root pixi run test: 72/72 files (Mac, 2026-10-26, merged head)
  • cd rig && pixi run -e dev test-stimulus: 50 checks, 0 failures, 0 skips (incl. the --stimulus replay end to end through the derive hook)
  • cd rig && pixi run -e dev test-viz: PASS
  • cd rig && pixi run -e dev test (the ROS graph acceptance harness against the sibling rig-nodes build): 62/62 checks (after fixing the dev environment's Zenoh config URIs — editable install, see the second commit)
  • cd rig && pixi run -e dev test-stimulus-live: 10/10 (router → bridge → stimulus node on the fixture replay)
  • Full run with flies on REISERLAB-WW14, 2026-10-22 (results file in the PR; pre-extraction code)
  • Foxglove replay of the full run (not done yet per the results file)
  • On a rig PC: pixi install on the released channel once rig-nodes ships the next set, then pixi run rig -- --no-fictrac --bias --foxglove --viz-args "--sources bias" --stimulus-args "--panel-layout four-color"

Linear: LAB-303 (okey-cokey rig), LAB-338 (extraction)

🤖 Generated with Claude Code

mbreiser and others added 12 commits October 26, 2026 16:57
…rk between pairs) per Grace; smoke variant same shape

The full run is now 24 pairs (3 duties x 4 colors x 2 reps), ~16 min; the 10 s pause is
kept across block boundaries. The reversal is phase-continuous (15 s x 80 fps = 1200
frames, a multiple of the 20-frame period) and the camera timestamp moves to the start of
each pair so its round trip never stretches the CW half.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ove camera + G6 dashboard plan

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… dashboard phases 1/1b/2)

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

Live: bridge_node also publishes /arena/browser (the bag record is unchanged); the new
stimulus_node turns it into the EXPECTED display (the trial's .pat frame x duty in the
panels' LED colors, PNG) and the OBSERVED display (controller telemetry cf rows), plus the
arena's lag, display rate and health, all on the controller's own clock. viz_node gains BIAS
fps-from-count, drops, rtt and writer queue, and --sources. rig.py: --stimulus (included by
--foxglove) and --no-fictrac. Layout: foxglove/arena-okey-cokey.json.

Replay: foxglove_json.py --stimulus rebuilds the same topics from a finished bag
(nodes/dashboard_replay.py, the same pure code) and /camera/image from the run's uFMF
(tools/ufmf.py, BIAS's v4 layout), placed on the bridge clock by the getTimestamp replies.

Panel colors are a Python port of js/panel-color.js, pinned cell by cell under Node.
Tests: test-stimulus 54/54 (incl. a real 80 fps trial from the 2026-10-14 smoke run, every
lag 0), test-stimulus-live 10/10, harness 54/54, root suite 71/71. No live camera (BIAS
unchanged by decision).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e dashboard steps, handover for the lab-PC test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…art from it (no Python/git assumed)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- pixi.toml: viz env on win-64 prepends Library\lib to PATH; foxglove_bridge
  exited 0xC0000135 (foxglove.dll / foxglove_cpp_shared.dll not on the DLL path)
- tools/bias-ufmf.ps1 + config/bias/okey-cokey-bfs-u3-51s5m.json: BIAS v0.73.1
  restarts in jpg and rejects load-configuration until the camera has captured
  once; the script does connect -> 2 s capture -> load, run after every BIAS start
- setup checklist + run sheet: arena on this rig is mounted upside down
  (protocol CW turns CCW seen from above; protocols unchanged, no direction test
  needed), Foxglove install URL/silent flags, 8766 not 8765, path placeholders
  (no D: on ww14), runlog-check pre-run "unknown" trials, known issues
- .gitignore: stop ignoring tests/fixtures/*.jsonl.gz (the okey smoke fixture
  was never committed; still needs adding from ww18)
- okey-cokey-pc-ww14-setup-2026-10-22.md: PC facts, tool versions, BIAS/camera,
  two passing smoke runs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Run sheet step 5/6 on REISERLAB-WW14, 2026-10-22:
- Full g6_color_optomotor_test with flies: runlog-check 48/48 pass, BIAS
  58/58 ok, 70 953 frames at 73.3 fps. Results in
  okey-cokey-pc-results-2026-10-21.md.
- The first full attempt died at minute 9 when the Claude desktop app
  restarted and took BIAS, the rig and the Studio server with it. New
  tools/okey-cokey-start.ps1 starts all three through WMI so they outlive
  the launcher; the run sheet points real runs at it.
- The controller moved from COM3 to COM5 (a second Teensy is on COM3):
  setup notes and run sheet now say to pick it by the name G6_Arena.
- A deliberate occlusion made the ufmf 11.8 GB instead of ~0.5 GB; a
  by-eye panel glitch report is recorded as open (telemetry is clean).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ws Terminal tabs

Ran tools/okey-cokey-start.ps1 on ww14 with BIAS, the rig and the server
all stopped: exit 0, ports 5010/7447/8765/8766/8092 up, every listener's
parent chain runs through WmiPrvSE (none under the Claude app), BIAS on
ufmf. The rig and server consoles open as tabs of one Windows Terminal
window, which hid the rig tab from the operator at first; the script,
run sheet and results now say so and how to stop them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…or glyph on several panels

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nto claude/okey-cokey-rig

# Conflicts:
#	rig/.gitignore
#	rig/HANDOVER-okey-cokey-2026-10-21.md
#	rig/config/bias/okey-cokey-bfs-u3-51s5m.json
#	rig/docs/okey-cokey-foxglove-dashboard-plan.md
#	rig/foxglove/arena-okey-cokey.json
#	rig/nodes/arena_display.py
#	rig/nodes/bias_health.py
#	rig/nodes/dashboard_replay.py
#	rig/nodes/stimulus_core.py
#	rig/nodes/stimulus_node.py
#	rig/okey-cokey-pc-2026-10-21.md
#	rig/okey-cokey-pc-results-2026-10-21.md
#	rig/okey-cokey-pc-setup.md
#	rig/okey-cokey-pc-ww14-setup-2026-10-22.md
#	rig/tests/fixtures/protocols-2026-10-14/g6_color_optomotor_smoke.yaml
#	rig/tests/test_stimulus.py
#	rig/tests/test_stimulus_live.py
#	rig/tools/bias-ufmf.ps1
#	rig/tools/okey-cokey-start.ps1
#	rig/tools/ufmf.py
…y reads (it had only ever existed in one worktree; the .gitignore exception was added 2026-10-22 but the file never was)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mbreiser and others added 2 commits October 26, 2026 21:19
…d on the installed rig_nodes package (LAB-303, LAB-338)

The shared half of rig/ moved to reiserlab/rig-nodes (PR #274); this merge re-expresses the
okey-cokey additions through the installed package instead of the deleted local modules:

* rig.py — the --no-fictrac / --stimulus / --stimulus-args options and the stimulus Child on top of
  the rig_nodes.supervise composition (fictrac via `python -m rig_nodes.fictrac_udp_adapter` only
  when not --no-fictrac; the udp 60000 preflight skipped the same way).
* foxglove_json.py — the arena wrapper around rig_nodes.foxglove_json.convert keeps #274's
  `enrich` hook (frame derivations, FicTrac columns) and adds the --stimulus dashboard replay as the
  rewriter's `derive` hook (whole-stream → new topics, foxglove.CompressedImage by well-known
  schema name); dashboard_replay.run_streams is unchanged. Needs rig-nodes PR #1 (derive hook).
* bias_health.py — moved to rig-nodes (rig_nodes.bias_health, rig-nodes PR #1); viz_node.py,
  dashboard_replay.py and the tests import it from there, test_stimulus's bias_health section
  moved with it (tests/test_pure.py in rig-nodes).
* viz_node.py / stimulus_node.py / test_stimulus_live.py — `_common` → `rig_nodes._common`,
  the launcher primitives → `rig_nodes.supervise`.

Until the next rig-nodes package set ships, run with `cd rig && pixi install -e dev` (a sibling
../../rig-nodes checkout on feat/bias-health or later) — the released 0.2.1 has no bias_health /
derive. Tests (dev env): test-stimulus 50/50, test-viz, `pixi run test`; root `pixi run test` 72/72.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ut; test_stimulus_live reads them from rig_nodes.zenoh

`pixi install -e dev` installs rig_nodes EDITABLE (a .pth into ../../rig-nodes/src/rig_nodes), so the
workspace-level ZENOH_ROUTER/SESSION_CONFIG_URI (…/site-packages/rig_nodes/config/…) named files that
do not exist in that environment: the router and every rclpy process failed with "Error configuring
Zenoh session" and `pixi run -e dev test` lost every check. `[feature.dev.activation.env]` (+ the
win-64 target) now points both URIs into the checkout. (Pre-existing on feat/rig-nodes-extraction,
where the dev environment had not been run through the harness.)

test_stimulus_live.py read `rig/config/zenoh-*.json5`, deleted by the extraction; it takes the
installed package's paths (`rig_nodes.zenoh.ROUTER_CONFIG` / `SESSION_CONFIG`) instead.

Verified in the dev environment: `pixi run test` 62/62, `test-stimulus-live` 10/10.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@mbreiser
mbreiser changed the base branch from main to feat/rig-nodes-extraction October 27, 2026 01:27
Base automatically changed from feat/rig-nodes-extraction to main October 28, 2026 20:35
mbreiser and others added 2 commits October 28, 2026 17:16
…ency activation, bias_health from rig-nodes 0.3.0 (LAB-303)

The dev environment uses git source dependencies since 2026-10-27 (the package is installed, not
editable), so the sibling-checkout Zenoh URIs are gone. rig_nodes.bias_health and the derive hook
ship in rig-nodes 0.3.0 (rig-nodes#1), which the candidate's re-pin PR installs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mbreiser added a commit that referenced this pull request Oct 28, 2026
…after the BIAS node, docstring)

Coordinated with the session building the candidate with #269 (stimulus node): its hunks edit
the --sim argparse neighbourhood, the --foxglove docstring line and the lines after
nodes.append(bridge). Ours now sit after --sim-args, after the BIAS node append and after the
--sim docstring example, so the two PRs merge without conflict. No behaviour change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mbreiser added a commit that referenced this pull request Oct 28, 2026
…+ G6 Foxglove dashboard, uFMF tools, ww14 run records (LAB-303)
mbreiser added a commit that referenced this pull request Oct 28, 2026
Candidate for Production. PRs: #281, #269, #282, #284.

Release-Manifest: releases/2026-10-28.json
@mbreiser mbreiser closed this pull request by merging all changes into main in 59a377b Oct 29, 2026
@mbreiser
mbreiser deleted the claude/okey-cokey-rig branch October 29, 2026 00:43
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.

3 participants