diff --git a/pico-cp/app.py b/pico-cp/app.py index 157b4f6..df1d58d 100644 --- a/pico-cp/app.py +++ b/pico-cp/app.py @@ -1157,40 +1157,41 @@ class App: show_stats(0, 0, 0) self.display.refresh() time.sleep(0.1); center = self.jx.value - last = time.monotonic(); lastdir = None - total = 0; win = 0; peak = 0; tsample = time.monotonic() - while True: + total = 0; win = 0; peak = 0; cw = True; dt = 1.0; lastdir = None + now = time.monotonic(); last = now; tsample = now; tjoy = now + while True: # no per-iteration sleep: tight step timing in this mode now = time.monotonic() - dx = self.jx.value - center; mag = abs(dx) - if mag > JOY_DEADZONE: - cw = dx > 0 - frac = (mag - JOY_DEADZONE) / (32768 - JOY_DEADZONE) - if frac > 1.0: frac = 1.0 - dt = 0.02 + (0.001 - 0.02) * frac # full push ~1000 steps/s; just past deadzone = slow - if self.pend is not None and self.pend.ok and now - last >= dt: - self.pend.spin(cw); last = now; total += 1; win += 1 - if cw != lastdir: # direction changed -> update LED + needle - lastdir = cw - if cw: self.led.set(0, 150, 0) - else: self.led.set(0, 0, 255) - ang = PEND_THETA if cw else -PEND_THETA - bx = PEND_PX + int(PEND_LEN * math.sin(ang)); by = PEND_PY - int(PEND_LEN * math.cos(ang)) - bob.x = bx; bob.y = by - arm.points = [(PEND_PX - 4, PEND_PY), (PEND_PX + 4, PEND_PY), (bx, by)] + 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) + if mag > JOY_DEADZONE: + cw = dx > 0 + frac = (mag - JOY_DEADZONE) / (32768 - JOY_DEADZONE) + if frac > 1.0: frac = 1.0 + dt = 0.02 + (0.0006 - 0.02) * frac # commanded up to ~1600 steps/s (find the motor's real wall) + if cw != lastdir: # direction changed -> LED + needle (rare, so refresh here) + lastdir = cw + if cw: self.led.set(0, 150, 0) + else: self.led.set(0, 0, 255) + ang = PEND_THETA if cw else -PEND_THETA + bx = PEND_PX + int(PEND_LEN * math.sin(ang)); by = PEND_PY - int(PEND_LEN * math.cos(ang)) + bob.x = bx; bob.y = by + arm.points = [(PEND_PX - 4, PEND_PY), (PEND_PX + 4, PEND_PY), (bx, by)] + self.display.refresh() + elif lastdir is not None: # back to center -> stop, release, recentre needle + lastdir = None; dt = 1.0 + if self.pend is not None and self.pend.ok: self.pend.release() + self.led.set(0, 0, 0) + 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)] self.display.refresh() - elif lastdir is not None: # back to center -> stop, release, recentre needle - lastdir = None - if self.pend is not None and self.pend.ok: self.pend.release() - self.led.set(0, 0, 0) - 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)] - 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)) if rate > peak: peak = rate show_stats(total, rate, peak); win = 0; tsample = now self.display.refresh() - time.sleep(0.0005) # ---------- audio + light ---------- def click(self, level):