Repository navigation
Conversation
…ters, bridge node reusing bridge.py Separate pixi workspace (RoboStack Jazzy + conda-forge; osx-arm64/win-64/linux-64) under ros2-poc/; the root pixi.toml and fictrac-bridge/ are untouched so bridge 3.4 stays side by side. - Zenoh router + rmw_zenoh_cpp with loopback-only configs (stock files, endpoint lines only) - fictrac_udp_adapter: FicTrac UDP → /fictrac/raw (std_msgs/String JSON), FicTrac untouched - kinefly_udp_adapter + kinefly_sim: KF/1 (mbreiser/Kinefly-MacOS) → /kinefly/raw - bias_node + bias_sim + bias_cmd: BIAS HTTP command port ⇄ /bias/cmd,/bias/reply,/bias/status; timeout = unknown outcome + reconcile; video file reported as an artifact - bridge_node: bridge.py's Hub/LogWriter/Pipeline/make_dispatcher on ROS input, same WebSocket schema on ws://localhost:8765, same behavior_v2 log; adds connector_status latency lines, source_lost/resumed watchdog, ["kf",…] rows, BIAS connector events, /arena/frame mirror - rig.py: one `pixi run rig` command supervising router + nodes - tests: studio_emulator (the Studio runner's exact bridge conversation), check_runlog_readers (JS readers accept the log), test_ros2_poc (29 checks incl. adapter SIGKILL mid-run, closed-loop report rejection/idx checks, convert round trip): 29/29 on Linux Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KHyggowbCA5ucBg71bU26V
…outer restart, launcher pre-flight) - bridge_node: RosLogWriter hooks (on_open/on_close) replace the message re-parsing wrapper; source watchdog scoped per log file; ordered ROS shutdown (join the spin thread before destroy_node — removes "terminate called without an active exception" on SIGTERM) - bias_node: worker exception guard (a malformed BIAS body no longer kills the node), get-status polls coalesced to one pending - rig.py: port pre-flight with a one-line culprit per port (SO_REUSEADDR probe), router death stops the rig, Zenoh config paths set explicitly (Windows shells leave $PIXI_PROJECT_ROOT literal) - nodes/_common.py: shared envelope, QoS, spin/shutdown boilerplate, wait_port - test harness: adapter kill anchored on the runner's fictracApply line in the log; export guard - README: soak (12 runs, flat RSS, p99 ≈ 3.5 ms), zero loss at 200 Hz + 500 Hz, router kill/restart with no data gap, student-mistake messages Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KHyggowbCA5ucBg71bU26V
… TerminateProcess) Python cannot send SIGINT to another process on Windows (send_signal raises ValueError), so Ctrl-C on the rig PC would have looked like a launcher crash. popen_group/signal_group in nodes/_common.py give every child its own process group on both platforms and map SIGINT → CTRL_BREAK_EVENT, SIGTERM/SIGKILL → TerminateProcess on Windows; rig.py and the test harness use them (and catch ValueError). Linux path unchanged (setsid + killpg). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KHyggowbCA5ucBg71bU26V
…s a watch item) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KHyggowbCA5ucBg71bU26V
Mac run of the items the Linux container could not cover: pixi install 25 s fresh, talker/listener, 29/29 acceptance, the unmodified Pages Studio against `pixi run rig -- --sim` with a G6 controller (two Mode-3 constant-bias runs auto-committed to the course repo, byte-identical to the bridge node's file, idx mismatch 0.00 %, runlog-check OK), the real BIAS Mac port and the real Kinefly fork (9600/9600 datagrams, 0 rejected, kf rows in the committed log). bias_node: the real Mac port resolves a relative `filename` against its own cwd and start-capture then succeeds without capturing; the reply now carries a warning for relative names. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
WINDOWS-TEST.md scripts the one open acceptance item (install timing, the $PIXI_PROJECT_ROOT expansion check, talker/listener, the 29-check harness, rig + unmodified Studio + controller, real BIAS over HTTP with an absolute video path and the unknown-outcome path, Ctrl-C cleanup, student mistakes) and lists what to send back. Windows' signal module has no SIGKILL, so rig.py's stop escalation, the harness's mid-run adapter kill and _common.signal_group would have raised AttributeError there; they now share _common.SIGKILL (getattr fallback 9). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tudy + two-channel log plan - nodes/viz_node.py: typed republisher so Foxglove plots natively with NO custom message types — std_msgs/Float64 signals (/viz/fictrac|arena|kinefly|bias/*), Bool/String states, diagnostic_msgs/DiagnosticArray on /diagnostics (OK/STALE/WARN/ERROR per source with rate, seq, latency, last error + time), visualization_msgs/MarkerArray on /viz/markers (ball rotated by FicTrac lab-frame orientation with markings, fixed fly, arena cylinder, pattern feature at the mapped azimuth, readout) - foxglove/arena-fictrac.json, foxglove/arena-bias.json: layouts (3D, closed-loop plot, kinematics, index, health lights + gauges, BIAS state timeline, latest reply, last error, log) - pixi: ros-jazzy-foxglove-bridge (ws://127.0.0.1:8766; 8765 stays the Studio bridge), tasks viz / foxglove / size-study; rig.py --foxglove starts both (+ port pre-flight on 8766) - sizing/compare.py + sizing/frames300.py: NDJSON vs MCAP size study (per-message overhead, index, batching, zstd level; 300 Hz controller frame records every-frame vs changes-only) - README: Foxglove section; "Log format" section with the measured tables, per-hour numbers, the two-channel plan (frames batched 1 s + index changes per message) and 25 MiB file rolling - test harness: the no-custom-messages check now allows the ros-base interface packages Verified in the container: 22 typed channels advertised (CDR) on :8766, binary frames on subscription, 6 markers, diagnostics 50/100 Hz rows, BIAS state 1 Hz; acceptance 29/29. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KHyggowbCA5ucBg71bU26V
mbreiser
added a commit
that referenced
this pull request
Oct 16, 2026
…252's dashboards Opened runs 5.2 and the soak in Foxglove web 3.4 as local files: arena-fictrac, arena-bias and the PR #254 layout all draw; one benign profile-mismatch warning. Seven dashboard suggestions from the data (viz_node frame drops, unwrapped display angle, plot scaling, clipped indicators, /rosout not recorded, grating feature bar). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rer layouts From checking both dashboards in Foxglove (web 3.4) on ww18 hardware runs replayed at 1x through viz_node (data branch data/ros2-poc-ww18-2026-10-15): - /arena/frame subscription: RELIABLE_QOS (depth 200) like the other inputs. With depth 10 viz_node dropped 15 of 9,969 frames (step 5.2), 17 of 58,918 (soak), 8 of 12,226 (5c); now 9,969/9,969, 58,918/58,918 and 12,226/12,226. - /viz/arena/display_deg (DisplayAngle): the display's unwrapped rotation from the wrapped index (sum of index steps taken the short way round the modulus x frame_dir x deg_per_frame). The modulus is --frames N, else learned per epoch (largest index + 1). A 20-frame grating kept azimuth_deg inside one 36-degree period while the fly turned thousands of degrees; on the ww18 closed-loop runs display - turn - bias is now constant within +/-0.9 degrees (half a frame) in every epoch. The 3D feature bar sits at wrap180(display_deg): unchanged for a pattern spanning the arena, turning with a grating. - /viz/fictrac/fwd_dps, side_dps: rates of FicTrac's integrated cols 20/21 in deg/s (per frame-counter step, so a dropped frame does not double them), the units of speed_dps. - arena-fictrac: closed loop = fly turn vs display rotation; bias angle in its own plot; kinematics = speed / forward / side in deg/s; short indicator labels + panel titles. - arena-bias: camera frame count and displayed index on separate plots; BIAS / Camera / Video indicators with short labels; ROS log panels titled live-only (bags do not record /rosout). - tests/test_viz_node.py (pixi run test-viz): 11 checks of the math, no ROS graph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mbreiser
added a commit
that referenced
this pull request
Oct 16, 2026
Replayed all five bags at 1x through PR #258's viz_node: display_deg, fwd_dps and side_dps are new, and no frames are dropped (every frame's index + heading at its exact original time). Layouts are PR #258's fixed arena-fictrac + arena-bias; PR #252's first versions and their viz files stay in history at 659c234. README + tools updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ffline In Foxglove (1316 px window) the BIAS light still clipped "reachable" and the gauge title "Camera fps": the three lights now stack in a 60 % column beside the gauge, and the BIAS light reads online / offline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ros2-poc viz: display rotation, deg/s rates, no dropped frames + clearer layouts
mbreiser
added a commit
that referenced
this pull request
Oct 18, 2026
…viz port Studio / runner / client - connectorCommand waits timeout_s + CONNECTOR_TIMEOUT_MARGIN_MS (default 15 s): the browser outlasts the device node's own deadline, so a reply at the deadline is an outcome, not an 'unknown'. 2P protocol's waitIdle already declares timeout_s. - plugin-registry: ScanImagePlugin `set.value` is text (the allowlist holds numbers, booleans and paths); the node coerces "640" / "true" to the JSON scalar. - protocol-yaml-v3: `variables:` written as a list of anchored scalars (`- &name v`, the 2P protocols) kept their identity wrong — `.anchor` was read off a primitive (String.prototype.anchor), hence the 2026-10-16 "Variable "function anchor() …" is defined more than once" warning. extractVariables/_findVariablePair handle both shapes; v3 round-trip suite 39 (823/823). - runner test: connector plugin steps make a run bridge-dependent (loss in the ITI before a camera step → BRIDGE_LOST; without the map → continues). 547/547. - footer stamp; release notes v0.97 extended; CLAUDE.md: ROS-era rules. ros2-poc - mcap_index.reindex replaces the bag atomically (os.replace), never unlink-then-rename. - recorder: ONE constant storage sidecar per log dir (not one hidden file per run); optional max_bag_bytes → bridge_node --max-bag-mb (off by default: bags are archived on a share, not pushed to GitHub). - scanimage_node: coerce_scalar for `set` values. - kf_row lives once in nodes/_rows.py (no ROS imports), used by the node and the converter — `converted == live` depends on one encoder. - ported from #252: nodes/viz_node.py, foxglove/*.json, tests/test_viz_node.py, sizing/; rig.py --foxglove also starts viz_node (+ --viz-args); pixi tasks viz, test-viz, fox-json (nodes/foxglove_json.py salvaged from the data branch). - repo hygiene: colcon build logs (interfaces/log) and the one-off win-64 channel payload removed from the tree (+ .gitignore); the typed-prebuilt env still reads the pinned commit URL. - stamp.py: one stamping path again (stamp_tree takes a skip set); tiers 109/109. Harness: ros2-poc `pixi run test` all PASS (default env), test-viz PASS. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Contributor
Author
|
Closing as folded into #254 (LAB-303). Everything here that #254 lacked is now on that branch (commit f7ae2eb): |
5 of 6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The bounded ROS 2 spike from LAB-303 (decision in flight: ROS 2 graph vs. connector contract vs. Zenoh wire). Everything lives under
ros2-poc/as its own pixi workspace (RoboStack Jazzy + conda-forge,osx-arm64/win-64/linux-64); the rootpixi.tomlandfictrac-bridge/are untouched, so bridge 3.4 stays installed side by side.rmw_zenoh_cpp, loopback-only configs (stock rmw_zenoh files with only the endpoint lines changed — the stock router bindstcp/[::]:7447and fails on a host without IPv6).std_msgs/Stringcarrying JSON):fictrac_udp_adapter(FicTrac UDP →/fictrac/raw, FicTrac untouched),kinefly_udp_adapter(KF/1 frommbreiser/Kinefly-MacOS→/kinefly/raw, protocol discriminated before decoding),bias_node(BIAS HTTP command port ⇄/bias/cmd,/bias/reply,/bias/status; timeout = unknown outcome +get-statusreconcile; video file reported as anartifact).bridge_nodeimportsfictrac-bridge/bridge.pyby path and reusesHub,LogWriter,Pipeline,make_dispatcherunmodified. The unmodified Studio protocol onws://localhost:8765, the same behavior_v2 log. Additions are all visible in the log:connector_status(frames, adapter→bridge latency p50/p99),source_lost/source_resumedwatchdog,["kf",…]rows, BIAS connector events, plus an/arena/frameROS mirror for introspection.pixi run rigsupervises router + nodes (one command, port pre-flight with a one-line culprit per port);kinefly_sim.py,bias_sim.py,bias_cmd.pyfor hardware-free runs.--foxglove):nodes/viz_node.pyrepublishes the JSON streams as ros-base typed messages (std_msgs/Float64signals,diagnostic_msgs/DiagnosticArrayhealth rows,visualization_msgs/MarkerArrayball + fly + arena + pattern feature) and the stockfoxglove_bridgeserves them onws://localhost:8766; two layouts infoxglove/(Arena + FicTrac, Arena + BIAS).sizing/, README "Log format"): NDJSON vs MCAP measured on real logs — per-message overhead dominates; with the per-message index off, arena echoes batched 1 s and zstd-19, MCAP reaches parity with today's gzip NDJSON; 300 Hz controller frame records every-frame vs changes-only; the two-channel plan (frames batched + index changes per message) and 25 MiB file rolling.pixi run test(tests/test_ros2_poc.py): whole graph +fictrac_sim.py --model fly --kp 2+tests/studio_emulator.py(the Studio runner's exact bridge conversation, 3 constant-bias epochs), FicTrac adapter SIGKILLed mid-run and restarted, BIAS commands mid-run; thenscripts/closed-loop-report.py,bridge.py --convertround trip, and the JS readers (js/runlog-format.js,js/runlog-replay.js) over the exported log. 29 / 29 on Linux and on the Mac.Criterion-by-criterion evidence, the further automated checks (soak, zero loss under load, router kill/restart, student-mistake messages), the Mac results, the Foxglove and log-format sections, and the Windows plan (
WINDOWS-TEST.md) are inros2-poc/README.md.Tier
No web-tool code is touched (new
ros2-poc/directory only), so nothing here goes to Next or Production — treat like docs/skills-only. Confirm before merging.Release notes
none
Test plan
cd ros2-poc && pixi install(fresh, no manual steps; 3 platforms in the lock file)pixi run router,pixi run talker/listenerunderrmw_zenoh_cpppixi run fictrac-adapter+ rootfictrac_sim.py→ros2 topic hz /fictrac/raw= 50.0 Hzpixi run rig -- --sim --kinefly --bias --bias-sim, then SIGINT and SIGTERM: all children stop, no tracebacks, no abortpixi run test→ 29 / 29 (rerun after the review fixes and after the Foxglove additions)pixi run rig/ rig while bridge 3.4 holds :8765 → pre-flight names the ports, exit 2pixi run test(unchanged code) passes;pixi run format-checkwarnings are pre-existing files onmainpixi install25 s fresh (1.0 GB env, no manual step); talker/listener every message heard underrmw_zenoh_cpp;pixi run test29 / 29 in 27 s, latency p50 0.89 / p99 1.43 mspixi run rig -- --sim --sim-args "--model fly --kp 2 --seed 1"with a G6 2×10 controller over Web Serial; no Chrome local-network-access prompt; two Mode-3 constant-bias runs auto-committed the normal way toreiserlab/cshl-2026-courserunlogs/bench00/, each byte-identical to the bridge node's file;closed-loop-report.pyidx mismatch 0.00 % in all 6 epochs;runlog-check.pyOKbias-node+bias-cmd— all commands ok, reply shape identical tobias_sim.py; relativefilenameresolves against BIAS's cwd (node now warns); the Mac port writes<stem>_cam_0_…_v001/movie.mjpgrather than the<stem>.jpgit reports. Real Kinefly fork--udp 127.0.0.1:60001: 9600 / 9600 datagrams, 0 rejected, 9487["kf",…]rows in the committed logpixi run rig -- --sim --bias --bias-sim --foxglove→ 22 typed channels advertised on ws://127.0.0.1:8766 (CDR), binary frames on subscription,/diagnosticsrows at 50/100 Hz, 6 markers, BIAS state at 1 Hz; both layouts parsefoxglove/arena-fictrac.jsonandarena-bias.json, check the 3D scene, plots and health lights againstpixi run rig -- --sim --sim-args "--model fly --kp 2 --seed 1" --bias --bias-sim --foxglovewin-64resolves and locks only) — rig-PC session scripted inros2-poc/WINDOWS-TEST.md🤖 Generated with Claude Code
https://claude.ai/code/session_01KHyggowbCA5ucBg71bU26V