From 9651e8bc6a9ababcef5def014c04970b573e28fb Mon Sep 17 00:00:00 2001 From: Me Here Date: Fri, 5 Jun 2026 22:13:07 -0500 Subject: [PATCH] pm-kit: fix jumpy jog (stop drawing mid-spin) - smooth steady spin The ~1s hitch was the once-per-second readout: show_stats() allocates text bitmaps (GC pause) and display.refresh() blocks the SPI blit, both stalling the step loop exactly every second. Now the rate is measured silently while spinning and the readout (steps + peak) is redrawn only when you release; a gc.collect() on release + before spinning keeps the heap clean. Steady spin does zero display work -> smooth. Co-Authored-By: Claude Opus 4.8 (1M context) --- pico-cp/README.md | 7 ++++--- pico-cp/app.py | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/pico-cp/README.md b/pico-cp/README.md index 67098eb..36dd9d0 100644 --- a/pico-cp/README.md +++ b/pico-cp/README.md @@ -122,9 +122,10 @@ The Kit can drive a **physical metronome pendulum**: a 4-input unipolar stepper power‑cycle. - **Jog / test mode** (hold **A + B** at boot): the joystick sets **direction only** — **L = CCW, R = CW** — and the motor **accelerates to `STEPPER_MAX_RATE`** (reversing decelerates through zero first), with an on‑screen - needle + RGB LED and a **live step counter + rate readout**. *Tuning:* raise `STEPPER_MAX_RATE` until the - motor starts skipping, then back off; if it stalls *starting*, lower `STEPPER_ACCEL` / `STEPPER_JOG_START`. - Power‑cycle (no buttons) to exit. + needle + RGB LED. The **step count + peak‑rate readout updates when you release** (drawing mid‑spin would + stall the step loop and make it jumpy, so the spin itself stays glitch‑free). *Tuning:* hold to spin, release + to read the peak; raise `STEPPER_MAX_RATE` until the motor skips, then back off; if it stalls *starting*, + lower `STEPPER_ACCEL` / `STEPPER_JOG_START`. Power‑cycle (no buttons) to exit. ## programs.json diff --git a/pico-cp/app.py b/pico-cp/app.py index 66a72ee..f6df469 100644 --- a/pico-cp/app.py +++ b/pico-cp/app.py @@ -1179,8 +1179,9 @@ class App: # Joystick = DIRECTION only (no fine speed). Spin at STEPPER_MAX_RATE, reached via an # acceleration ramp (STEPPER_ACCEL) so the motor doesn't stall trying to start at top speed; # reversing decelerates through zero, then accelerates the other way. - spin = 0; cur = 0.0; total = 0; win = 0; peak = 0 + spin = 0; cur = 0.0; total = 0; win = 0; peak = 0; lastrate = 0 now = time.monotonic(); last = now; tsample = now; tjoy = now + gc.collect() # clean heap before spinning (avoid a GC pause mid-spin) while True: # no per-iteration sleep: tight step timing in this mode now = time.monotonic() if now - tjoy >= 0.004: # control update (joystick + accel), off the step hot-path @@ -1194,15 +1195,16 @@ class App: elif cur > target: cur = max(0.0, cur - STEPPER_ACCEL * cdt) # decelerate if cur <= 0.0 and spin != 0 and want != spin: # finished slowing -> stop, or flip direction if self.pend is not None and self.pend.ok: self.pend.release() - if want == 0: spin = 0; set_needle(0) - else: spin = want; cur = float(STEPPER_JOG_START); set_needle(spin) + if want == 0: # stopped -> now safe to draw the readout + tidy the heap + spin = 0; show_stats(total, lastrate, peak); set_needle(0); gc.collect() + else: + spin = want; cur = float(STEPPER_JOG_START); set_needle(spin) if spin != 0 and cur > 0.0 and self.pend is not None and self.pend.ok and now - last >= 1.0 / cur: self.pend.spin(spin > 0); last = now; total += 1; win += 1 - if now - tsample >= 1.0: # step-rate readout, once/s (one tiny refresh) - rate = int(win / (now - tsample)) - if rate > peak: peak = rate - show_stats(total, rate, peak); win = 0; tsample = now - self.display.refresh() + if now - tsample >= 1.0: # measure rate SILENTLY (drawing here is what hitched it) + lastrate = int(win / (now - tsample)) + if lastrate > peak: peak = lastrate + win = 0; tsample = now # ---------- audio + light ---------- def click(self, level):