Operator speed control + max-rate (50 Hz) relay sampling#3
Merged
Conversation
…pling - Add a Speed slider to the demo page (drag right = faster). It maps inversely to the relay's video_duration_s over [6 s fastest .. 45 s slowest] and shows the resulting "~N s per loop". Syncs back from config and is blocked during sync to avoid feedback loops. - Raise the dense sample + bus-write rate to 50 Hz everywhere (preset, yaml, config + from_dict defaults). 50 Hz is the realistic 8-servo sync-write ceiling = the highest rate that reads as smooth without making the demo run in slow motion (the absolute-paced loop would otherwise fall behind a schedule the bus can't meet). - Fix the now-stale speed advisory: the relay streams one dense write per sample (not waypoint_count), so warn only above ~55 Hz and explain the slow-motion failure mode. Update the matching test to 80 Hz. 149 demo/relay/pattern tests pass. Speed mapping verified (100->6 s, 1->45 s, roundtrips through sync) and preview shows ~1000 writes @ 50 Hz for a 20 s loop. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
jacklange22
added a commit
that referenced
this pull request
May 29, 2026
…ore close-out main carries the slow-motion demo work as the squash-merged 356e4fe (#3), while this branch still had the original unsquashed d74752b of the same work, so GitHub could not auto-merge PR #6. This commit aligns the five overlapping slow-motion files byte-for-byte with origin/main (verified: the four pure slow-motion files are identical to origin/main; experiment_pages.py keeps the new full_factorial_grid work on top), resolving the divergence so the squash merge applies cleanly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jacklange22
added a commit
that referenced
this pull request
May 29, 2026
…ial workspace grid (#6) * feat(slow-motion-demo): operator speed control + max-rate (50 Hz) sampling - Add a Speed slider to the demo page (drag right = faster). It maps inversely to the relay's video_duration_s over [6 s fastest .. 45 s slowest] and shows the resulting "~N s per loop". Syncs back from config and is blocked during sync to avoid feedback loops. - Raise the dense sample + bus-write rate to 50 Hz everywhere (preset, yaml, config + from_dict defaults). 50 Hz is the realistic 8-servo sync-write ceiling = the highest rate that reads as smooth without making the demo run in slow motion (the absolute-paced loop would otherwise fall behind a schedule the bus can't meet). - Fix the now-stale speed advisory: the relay streams one dense write per sample (not waypoint_count), so warn only above ~55 Hz and explain the slow-motion failure mode. Update the matching test to 80 Hz. 149 demo/relay/pattern tests pass. Speed mapping verified (100->6 s, 1->45 s, roundtrips through sync) and preview shows ~1000 writes @ 50 Hz for a 20 s loop. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(two-seg demo): make penprobe lookup demo run on servo_only-derived maps The two-segment penprobe chasing demo could not run on a map built from the big collected dataset: that dataset is servo_only and never recorded a physical_assembly, so the built map carries empty bottom/top segment keys. The controller's check_compatibility() treated empty keys as a *mismatch* against the live bench (segment_b/segment_a), blocking the demo in precheck. Distinguish an UNKNOWN (empty) map assembly from a genuine CONFLICT: - Controller (two_segment_lookup_controller.py): add LookupControllerConfig.allow_unknown_map_assembly (default False = strict). check_compatibility() now reports bottom/top_segment_key_unknown_in_map for an empty map assignment (relaxable via the flag) while a present-but-different assignment still hard-blocks as ..._mismatch. Add map_assembly_is_unknown. - Demo experiment (two_segment_penprobe_lookup_demo.py): add allow_unknown_map_assembly (default True, mirrors allow_unknown_map_tip_tool), thread it into the controller, and record a loud map_assembly_unknown warning + flags into the run metrics. A genuine conflict is still blocked; servo IDs, per-servo tick envelope, nearest-distance hard stop and current limits are unchanged. GUI (TwoSegmentPenprobeLookupDemoPage): add "Use Latest Built Map" + "Browse…" buttons (scan data/experiments/two_segment_workspace_lookup_maps/), a CLI build hint, and an "Allow unknown bottom/top assignment" checkbox so the demo is operable without hand-editing the map path. Verified end-to-end against a real map built from 20260526_235950_two_segment_collect_pose_command_dataset (2493 points): the demo runs, issues commands for on-manifold targets, and records the warning. Tests: controller unknown-vs-conflict matrix, demo runs on an unknown-assembly map (and blocks when opted out), and a GUI page-construction test. Also add the lookup + penprobe-demo test files to scripts/run_tests.sh two-segment so they run in the bench-day net (267 pass). quick (126) and hardware-safe green. Note: pre-existing unrelated failure test_shipped_system_yaml_carries_slowdown_profile expects default_profile_velocity>=5 but the operator set it to 3; untouched here. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(two-segment-workspace): full_factorial_grid target mode — equally-spaced N-per-axis lattice Adds a fourth target-generator mode to the two-segment workspace repeatability experiment alongside workspace_latin_hypercube (default), rings_and_axes, and grid_subsample. full_factorial_grid lays out N equally-spaced levels on every one of the 4 command axes (bottom_x, bottom_y, top_x, top_y) and takes the full Cartesian product — a regular 4D lattice that covers the entire [-amp, +amp]^4 box with the corners included (np.linspace endpoints, not LHS midpoints). With N=3 the per-axis levels are exactly [-amp, 0, +amp], the minimal grid that hits the centre, every face, edge, and corner. Because N-per-axis in 4D is N^4 targets, the per-axis resolution is an explicit knob (grid_points_per_axis, default 3 -> 81 targets) rather than silently disagreeing with target_count: - from_dict derives target_count = grid_points_per_axis ** 4 when grid mode is active, keeping the round-robin visit plan, planned-visits math, and the thesis-validity check (planned_target_count >= target_count) all consistent. - grid_points_per_axis is clamped to [2, 10]; 10 -> 10,000 targets is the practical ceiling (the value the operator floated). - the lattice is deterministic (no RNG) — fully specified by N + amplitude. GUI (TwoSegmentWorkspaceRepeatabilityPage): - "Full Factorial Grid (N per axis, equally spaced)" added to the Target Generator dropdown with an explanatory tooltip. - New "Grid Points / Axis (grid mode)" spinbox (range 2-10) with a tooltip spelling out N^4 (3->81, 4->256, 5->625, 10->10,000). - In grid mode the grid spin is the live control and Target Count is read-only (it shows the derived N^4); other modes do the reverse. - _on_target_generator_changed / _on_grid_points_per_axis_changed publish the derived target_count immediately and re-sync the page. The summary text writer now reports grid_points_per_axis (annotated with "targets = N^4" in grid mode). The run metric grid_points_per_axis is recorded for every run regardless of mode. Tests (6 new): - target_count derived from N^4, manual target_count ignored in grid mode - equally-spaced levels [-amp, 0, +amp] per axis; corners + centre present - deterministic regardless of seed; 4^4 = 256 targets - grid_points_per_axis clamped to [2, 10] - full_factorial_grid present in SUPPORTED_TARGET_GENERATOR_MODES - grid_points_per_axis is inert (doesn't touch target_count) in LHS mode scripts/run_tests.sh quick: 126 passed. scripts/run_tests.sh two-segment: 273 passed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * merge: reconcile branch slow-motion files with squashed main (#3) before close-out main carries the slow-motion demo work as the squash-merged 356e4fe (#3), while this branch still had the original unsquashed d74752b of the same work, so GitHub could not auto-merge PR #6. This commit aligns the five overlapping slow-motion files byte-for-byte with origin/main (verified: the four pure slow-motion files are identical to origin/main; experiment_pages.py keeps the new full_factorial_grid work on top), resolving the divergence so the squash merge applies cleanly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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
Follow-up to #1/#2. Adds the two things requested:
video_duration_sover [6 s fastest .. 45 s slowest] and shows the resulting "~N s per loop". (For this demo, speed = how fast the spine traverses the whole path = the motion duration; the servo profile stays un-throttled so it tracks the path at whatever speed you set.)Also fixes the now-stale speed advisory: the relay streams one dense write per sample (not
waypoint_count), so it now warns only above ~55 Hz and explains the slow-motion failure mode.Test plan
tests/test_two_segment_slow_motion_demo.py,tests/test_sci_fi_waypoint_relay.py,tests/test_two_segment_motion_patterns.py— 149 passed~1000 bus writes @ 50 Hzcommand_rate_hzReviewer notes
command_rate_hzin the YAML.two_segment_workspace_repeatability_outputs.pychange is left out.🤖 Generated with Claude Code