pm-kit: stepper/pendulum tuning via settings.json (no recompile)

_load_settings now also reads stepper_max_rate / stepper_accel / stepper_jog_start
/ pend_swing_deg / stepper_steps_per_rev and recomputes the derived PEND_THETA +
STEPPER_ARC, so the motor speed/accel/swing can be dialed in by editing the file
on the drive instead of rebuilding the firmware. README documents the keys.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Me Here 2026-06-05 21:59:35 -05:00
parent 19d646a873
commit a7e8061a9b
2 changed files with 12 additions and 0 deletions

View file

@ -117,6 +117,9 @@ The Kit can drive a **physical metronome pendulum**: a 4-input unipolar stepper
- `STEPPER_ACCEL` — ramp (halfsteps/sec²) used to reach top speed without stalling; lower it if the motor - `STEPPER_ACCEL` — ramp (halfsteps/sec²) used to reach top speed without stalling; lower it if the motor
stalls/buzzes when starting. stalls/buzzes when starting.
- `STEPPER_JOG_START` — jog kickoff rate from rest (keep at or below the motor's pullin rate). - `STEPPER_JOG_START` — jog kickoff rate from rest (keep at or below the motor's pullin rate).
- *Tune without recompiling:* these five are also read from **`/settings.json`** (keys `stepper_max_rate`,
`stepper_accel`, `stepper_jog_start`, `pend_swing_deg`, `stepper_steps_per_rev`) — edit in editor mode,
powercycle.
- **Jog / test mode** (hold **A + B** at boot): the joystick sets **direction only****L = CCW, R = CW** — and - **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 onscreen the motor **accelerates to `STEPPER_MAX_RATE`** (reversing decelerates through zero first), with an onscreen
needle + RGB LED and a **live step counter + rate readout**. *Tuning:* raise `STEPPER_MAX_RATE` until the needle + RGB LED and a **live step counter + rate readout**. *Tuning:* raise `STEPPER_MAX_RATE` until the

View file

@ -1054,6 +1054,7 @@ class App:
# ---------- Settings persistence (/settings.json) ---------- # ---------- Settings persistence (/settings.json) ----------
def _load_settings(self): def _load_settings(self):
global LED_BRIGHTNESS, MUTE_SPEAKER, SPEAKER_AUTO_MUTE, MIDI_ENABLED, MIDI_CHANNEL, MIDI_CLOCK_OUT, MIDI_CLOCK_IN global LED_BRIGHTNESS, MUTE_SPEAKER, SPEAKER_AUTO_MUTE, MIDI_ENABLED, MIDI_CHANNEL, MIDI_CLOCK_OUT, MIDI_CLOCK_IN
global STEPPER_MAX_RATE, STEPPER_ACCEL, STEPPER_JOG_START, PEND_SWING_DEG, STEPPER_STEPS_PER_REV, STEPPER_ARC, PEND_THETA
try: try:
with open("/settings.json") as f: d = json.load(f) with open("/settings.json") as f: d = json.load(f)
except Exception: return except Exception: return
@ -1065,6 +1066,14 @@ class App:
MIDI_CHANNEL = max(1, min(16, int(d.get("midi_channel", MIDI_CHANNEL)))) MIDI_CHANNEL = max(1, min(16, int(d.get("midi_channel", MIDI_CHANNEL))))
MIDI_CLOCK_OUT = bool(d.get("clock_out", MIDI_CLOCK_OUT)) MIDI_CLOCK_OUT = bool(d.get("clock_out", MIDI_CLOCK_OUT))
MIDI_CLOCK_IN = bool(d.get("clock_in", MIDI_CLOCK_IN)) MIDI_CLOCK_IN = bool(d.get("clock_in", MIDI_CLOCK_IN))
# Stepper/pendulum tuning (so you can dial it in by editing the file, no recompile):
STEPPER_MAX_RATE = max(50, min(4000, int(d.get("stepper_max_rate", STEPPER_MAX_RATE))))
STEPPER_ACCEL = max(50, int(d.get("stepper_accel", STEPPER_ACCEL)))
STEPPER_JOG_START = max(1, int(d.get("stepper_jog_start", STEPPER_JOG_START)))
PEND_SWING_DEG = max(1, min(180, int(d.get("pend_swing_deg", PEND_SWING_DEG))))
STEPPER_STEPS_PER_REV = max(1, int(d.get("stepper_steps_per_rev", STEPPER_STEPS_PER_REV)))
PEND_THETA = math.radians(PEND_SWING_DEG) / 2.0 # keep derived values in sync
STEPPER_ARC = round(STEPPER_STEPS_PER_REV * PEND_SWING_DEG / 360.0)
except Exception as e: print("settings:", e) except Exception as e: print("settings:", e)
def _save_settings(self): def _save_settings(self):
if not self.can_write: return if not self.can_write: return