servo per-layer calibration gating + chute aiming geometry model & calibration UI #155
Merged
Merged
Conversation
When a Pico is already in bootloader mode, the block device appears (/dev/sda1, label RPI-RP2) but may not be auto-mounted. The previous code only checked mounted paths, so it fell through to serial scanning and bailed with "No Pico boards found over USB". Now checks the block device before scanning serial ports. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Telemetry DB (stepper_telemetry.py): runs + samples tables in local_state.sqlite, self-creating, with downsampling-on-read and a retention prune. - StallGuard sweep endpoint now records each run + full per-sample context and returns run_id; added loaded/label params (loaded -> stall_test). - Query router (server/routers/telemetry.py): list/summary/run/samples/delete. - Frontend page (settings/stepper-stallguard) + StallGuardChart.svelte: per-motor summary, run list, canvas SG load-curve chart, sweep controls, save-SGTHRS-to-TOML. - Firmware (sorter_interface_firmware.cpp): leave stepper nEN HIGH at boot, enable per-channel on first move / explicit enable so motors don't hold at boot. NOTE: this file also carries pre-existing GET_VERSION work, entangled in the same working-tree edit; included here since it can't be split non-interactively. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Prevents machine-specific config from being swept into commits. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
TMC_UART_BUS_COUNT was a `const uint8_t`, but it gates `#if TMC_UART_BUS_COUNT > 1` blocks that construct and route the second TMC UART bus. The preprocessor cannot see a C++ const (it evaluates as 0), so `#if 0 > 1` was false and the entire second bus was compiled out on v1-2 — every channel silently fell back to bus 0. Make it a #define so the conditional sees the real count. v1-1 and skr stay at 1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bake git describe, short commit, UTC build time, and the hw/role variant into the firmware at configure time and expose them through the already-present GET_VERSION command handler. Add the matching host-side MCUDevice.get_version() so the backend can read what is actually flashed on each board. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…fix DRV_STATUS CPU spike TMC2209 chips can reset (motor power rail cycling after Pico boot) and return to hardware defaults: I_SCALE_ANALOG=1 (current from VREF, not IRUN) and MSTEP_REG_SELECT=0 (microsteps from MS pins, not CHOPCONF). Backend now writes GCONF=0x1C0 (PD_DISABLE | MSTEP_REG_SELECT | MULTISTEP_FILT) at the top of each stepper's init sequence, before applying microsteps/current from machine.toml. Also remove continuous DRV_STATUS refresh from the 500ms StepperSidebar poll — it was reading all 15 TMC registers over USB serial every 500ms whenever the driver panel was open, causing ~500% CPU on the Pi. The panel still refreshes on open and after saving settings. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
UART bus1 (uart1, ch4) is not currently working, so the chute stepper was unreachable over UART. Move it to bus0 where UART is confirmed functional. c_channel_2_rotor takes the lone bus1 slot (ch4) since it is less dependent on UART control right now. New channel order on bus0: chute(ch0), c1_rotor(ch1), c3_rotor(ch2), carousel(ch3). c2_rotor on bus1 ch4. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PCA9685 servos require explicit per-layer calibration before moving. Servos stay uncalibrated (angles=None) and no-op until both open/closed angles are locked in via the UI; uncalibrated layers are skipped during sorting and never moved on boot. Adds the shared ServoLayerCalibrator component used by the storage-layers settings page and setup wizard. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ly tested) What this is for ---------------- The chute rotates to point a falling piece at the correct bin in the bin tower. Previously the aiming math used ad-hoc constants (first_bin_center + pillar_width_deg, with section count hardcoded at 60deg) that predate the current hardware (moved home switch, all-bins-reachable geometry) and did NOT generalize across layouts with different bin counts. This replaces that with a clean, bin-count-independent geometry: bin_center = theta0 + section*(360/N) + (i + 0.5)*(W / K) calibrated from three invariants: num_sections (N), section_width_deg (W), first_section_offset_deg (theta0). Bins are equal slots aimed at their midpoints, so 1/2/3/5-bin layers all center correctly from one calibration. - chute.py: rewritten to the theta0/W/N midpoint model; angleForVirtualBin() is the single source of truth. Legacy first_bin_center/pillar_width_deg kept as derived props so chute_stress + the old /settings/chute page still work. - parse_user_toml.py: ChuteCalibrationConfig gains the canonical keys; loader prefers them and derives from legacy keys when absent (migration). - hardware.py: endpoints to save geometry, derive theta0/W from a measured first->last bin span, jog to an absolute angle, and test-aim at a virtual bin; plus a reachability check across the installed layout. - local_state.py: new chute_calibrations table + CRUD. Each calibration/manual save is stored as an instance; the active instance's geometry is what gets written to the TOML. Supports a history list + "lock in" to re-activate. - frontend /settings/chute-aiming: parameters shown read-only (edit hidden behind hover), a vertical gated calibration wizard (home -> jog to first bin -> jog to last bin + bin count -> derive & lock in), a drawn arrow-key jog pad (up/down fine 0.25deg, left/right coarse 2deg, real arrow keys bound), a calibration history list, and a verify-aim circle. Status: WIP, only lightly tested. Backend unit tests pass and endpoints/route were smoke-checked on dark-brown-axle, but the calibration has NOT been run on real hardware (no motor verification, no real first->last measurement yet). Open question still being chased: whether the jog + test-aim moves use normal default acceleration. Also folds in a few unrelated working-tree default flips that were outstanding on this shared branch (classification channel + feeder mode defaults, machine_setup default) per request to commit everything. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve api.py conflict by keeping both telemetry and tailscale routers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Stacked on the now-merged StallGuard branch (#150); the diff against
mainis just the servo/chute calibration work below.Servo per-layer calibration gating
PCA9685 servos now require explicit per-layer calibration before they can move. Layers stay uncalibrated (
angles=None) and no-op until both open/closed angles are locked in via the UI. Uncalibrated layers are skipped during sorting and never moved on boot. Adds the sharedServoLayerCalibratorcomponent used by both the storage-layers settings page and the setup onboarding wizard.Chute aiming calibration: geometry model + calibration UI (WIP)
The chute rotates to point a falling piece at the correct bin in the tower. The old aiming math used ad-hoc constants (
first_bin_center + pillar_width_deg, section count hardcoded at 60°) that predate the current hardware (moved home switch, all-bins-reachable geometry) and did not generalize across layouts with different bin counts.Replaced with a clean, bin-count-independent geometry:
calibrated from three invariants:
num_sections(N),section_width_deg(W),first_section_offset_deg(theta0). Bins are equal slots aimed at their midpoints, so 1/2/3/5-bin layers all center correctly from one calibration.Key changes
chute.py— rewritten to the theta0/W/N midpoint model;angleForVirtualBin()is the single source of truth. Legacyfirst_bin_center/pillar_width_degkept as derived props so chute_stress + the old/settings/chutepage still work.parse_user_toml.py—ChuteCalibrationConfiggains the canonical keys; loader prefers them and derives from legacy keys when absent (migration).hardware.py— endpoints to save geometry, derive theta0/W from a measured first→last bin span, jog to an absolute angle, test-aim at a virtual bin, and a reachability check across the installed layout.local_state.py— newchute_calibrationstable + CRUD. Each calibration/manual save is stored as an instance; the active instance's geometry is what gets written to the TOML. Supports a history list + "lock in" to re-activate./settings/chute-aiming— read-only parameters (edit behind hover), a gated calibration wizard (home → jog to first bin → jog to last bin + bin count → derive & lock in), an arrow-key jog pad (up/down fine 0.25°, left/right coarse 2°), a calibration history list, and a verify-aim circle.Status
WIP, lightly tested. Backend unit tests pass (
test_chute_aiming.py) and endpoints/routes were smoke-checked on dark-brown-axle, but chute calibration has not been run on real hardware (no motor verification, no real first→last measurement yet). Open question: whether the jog + test-aim moves use normal default acceleration.Also folds in a few unrelated working-tree default flips outstanding on this shared branch (classification channel + feeder mode defaults, machine_setup default).
🤖 Generated with Claude Code