pm-kit: fix jog-mode step-rate cap (loop overhead, not the motor)

The ~330 steps/s ceiling was the CircuitPython loop, not the stepper: an analog
read + time.sleep(0.0005) every iteration made each pass ~3ms (1/0.003 ~ 330).
Tighten the jog loop - poll the joystick at ~250Hz off the step hot-path, drop
the per-iteration sleep, refresh the readout ~1/s instead of 3+/s, and raise the
commanded ceiling to ~1600 steps/s - so the peak reflects the motor's real limit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Me Here 2026-06-05 21:51:34 -05:00
parent 36c7406d71
commit 5f9e9dfad7

View file

@ -1157,19 +1157,19 @@ class App:
show_stats(0, 0, 0) show_stats(0, 0, 0)
self.display.refresh() self.display.refresh()
time.sleep(0.1); center = self.jx.value time.sleep(0.1); center = self.jx.value
last = time.monotonic(); lastdir = None total = 0; win = 0; peak = 0; cw = True; dt = 1.0; lastdir = None
total = 0; win = 0; peak = 0; tsample = time.monotonic() now = time.monotonic(); last = now; tsample = now; tjoy = now
while True: while True: # no per-iteration sleep: tight step timing in this mode
now = time.monotonic() now = time.monotonic()
if now - tjoy >= 0.004: # poll the joystick ~250x/s, OFF the step hot-path
tjoy = now
dx = self.jx.value - center; mag = abs(dx) dx = self.jx.value - center; mag = abs(dx)
if mag > JOY_DEADZONE: if mag > JOY_DEADZONE:
cw = dx > 0 cw = dx > 0
frac = (mag - JOY_DEADZONE) / (32768 - JOY_DEADZONE) frac = (mag - JOY_DEADZONE) / (32768 - JOY_DEADZONE)
if frac > 1.0: frac = 1.0 if frac > 1.0: frac = 1.0
dt = 0.02 + (0.001 - 0.02) * frac # full push ~1000 steps/s; just past deadzone = slow dt = 0.02 + (0.0006 - 0.02) * frac # commanded up to ~1600 steps/s (find the motor's real wall)
if self.pend is not None and self.pend.ok and now - last >= dt: if cw != lastdir: # direction changed -> LED + needle (rare, so refresh here)
self.pend.spin(cw); last = now; total += 1; win += 1
if cw != lastdir: # direction changed -> update LED + needle
lastdir = cw lastdir = cw
if cw: self.led.set(0, 150, 0) if cw: self.led.set(0, 150, 0)
else: self.led.set(0, 0, 255) else: self.led.set(0, 0, 255)
@ -1179,18 +1179,19 @@ class App:
arm.points = [(PEND_PX - 4, PEND_PY), (PEND_PX + 4, PEND_PY), (bx, by)] arm.points = [(PEND_PX - 4, PEND_PY), (PEND_PX + 4, PEND_PY), (bx, by)]
self.display.refresh() self.display.refresh()
elif lastdir is not None: # back to center -> stop, release, recentre needle elif lastdir is not None: # back to center -> stop, release, recentre needle
lastdir = None lastdir = None; dt = 1.0
if self.pend is not None and self.pend.ok: self.pend.release() if self.pend is not None and self.pend.ok: self.pend.release()
self.led.set(0, 0, 0) self.led.set(0, 0, 0)
bob.x = PEND_PX; bob.y = PEND_PY - PEND_LEN bob.x = PEND_PX; bob.y = PEND_PY - PEND_LEN
arm.points = [(PEND_PX - 4, PEND_PY), (PEND_PX + 4, PEND_PY), (PEND_PX, PEND_PY - PEND_LEN)] arm.points = [(PEND_PX - 4, PEND_PY), (PEND_PX + 4, PEND_PY), (PEND_PX, PEND_PY - PEND_LEN)]
self.display.refresh() self.display.refresh()
if now - tsample >= 0.3: # ~3x/s: commanded-rate window -> readout (peak = motor ceiling) if lastdir is not None and self.pend is not None and self.pend.ok and now - last >= dt:
self.pend.spin(lastdir); last = now; total += 1; win += 1
if now - tsample >= 1.0: # readout once/s (one tiny refresh, not 3+ hitches/s)
rate = int(win / (now - tsample)) rate = int(win / (now - tsample))
if rate > peak: peak = rate if rate > peak: peak = rate
show_stats(total, rate, peak); win = 0; tsample = now show_stats(total, rate, peak); win = 0; tsample = now
self.display.refresh() self.display.refresh()
time.sleep(0.0005)
# ---------- audio + light ---------- # ---------- audio + light ----------
def click(self, level): def click(self, level):