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) <noreply@anthropic.com>
This commit is contained in:
parent
a7e8061a9b
commit
9651e8bc6a
2 changed files with 14 additions and 11 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Reference in a new issue