diff --git a/motor_test.py b/motor_test.py index 0c43fcd..3a97700 100644 --- a/motor_test.py +++ b/motor_test.py @@ -4,6 +4,7 @@ motor_test.py - Yahboom 4-ch driver over UART, motors on M3 + M4. python3 motor_test.py hand # motors stay OFF. Turn wheels by hand, watch the counts. python3 motor_test.py spin # WHEELS OFF THE GROUND. Low PWM steps, one motor at a time. + python3 motor_test.py reverse # WHEELS OFF THE GROUND. Why does the board go silent on reversing? Ctrl-C always stops the motors. """ @@ -89,6 +90,77 @@ def hold(d, ch, value, seconds): time.sleep(0.1) +def measure(d, ch, p, seconds=1.0): + """Hold PWM p and return (counts/s, encoder messages received).""" + t0, n0, _ = d.get(); s0 = time.perf_counter() + hold(d, ch, p, seconds) + t1, n1, _ = d.get(); s1 = time.perf_counter() + return (t1[ch] - t0[ch]) / (s1 - s0), n1 - n0 + + +def ramp(d, ch, start, end, steps=10, dt=0.1): + for k in range(1, steps + 1): + hold(d, ch, start + (end - start) * k / steps, dt) + + +def report(label, cps, msgs): + print(f"{label:<36} {cps:+8.0f} counts/s {msgs:4d} msgs") + return msgs > 0 + + +def diagnose(d, gentle): + print("\nEncoder stream STOPPED. Re-sending motor type + upload command...") + d.send("$mtype:1#") + _, n0, _ = d.get() + d.send("$upload:1,0,0#") + time.sleep(0.5) + _, n1, other = d.get() + if n1 > n0: + print("-> Stream came back after re-sending the settings: the board rebooted and lost them.") + if gentle: + print(" It died even on a GENTLE reverse, so negative PWM itself is the trigger, not a current spike.") + else: + print(" Gentle reverse was fine, only the hard one killed it: power dip (brownout) on the board.") + else: + print("-> Still silent. The board is hung or stopped transmitting. Power-cycle it.") + print(" non-encoder lines from the board:", other if other else "none") + + +def reverse(d): + ch = CHANNELS["M3"] + input("Are the wheels OFF the ground? Press Enter to start, Ctrl-C to abort... ") + + print("\nTest A: gentle reverse on M3 (ramp up, ramp to 0, pause, ramp to -800)") + ramp(d, ch, 0, 800) + ok = report(" +800 (ramped up)", *measure(d, ch, 800)) + ramp(d, ch, 800, 0); d.stop(); time.sleep(1.0) + ramp(d, ch, 0, -800) + ok = report(" -800 (ramped, after a full stop)", *measure(d, ch, -800)) and ok + ramp(d, ch, -800, 0); d.stop(); time.sleep(1.0) + if not ok: + diagnose(d, gentle=True) + return + + print("\nTest B: hard reverse on M3 (+1200 -> -1200 instantly)") + hold(d, ch, 1200, 0.5) + report(" +1200", *measure(d, ch, 1200)) + ok = report(" -1200 (instant reverse)", *measure(d, ch, -1200)) + d.stop(); time.sleep(1.0) + if not ok: + diagnose(d, gentle=False) + return + + print("\nTest C: hard reverse on M3 (+2500 -> -1600 instantly, same as the spin test)") + hold(d, ch, 2500, 0.5) + report(" +2500", *measure(d, ch, 2500)) + ok = report(" -1600 (instant reverse)", *measure(d, ch, -1600)) + d.stop(); time.sleep(1.0) + if not ok: + diagnose(d, gentle=False) + return + print("\nAll three survived - the spin-test failure didn't reproduce.") + + def hand(d): base, _, _ = d.get() print("Motors are OFF.") @@ -125,7 +197,7 @@ def spin(d): def main(): - if len(sys.argv) != 2 or sys.argv[1] not in ("hand", "spin"): + if len(sys.argv) != 2 or sys.argv[1] not in ("hand", "spin", "reverse"): sys.exit(__doc__) d = Driver() try: @@ -139,8 +211,10 @@ def main(): print(f"Driver board is talking ({n} encoder messages so far).\n") if sys.argv[1] == "hand": hand(d) - else: + elif sys.argv[1] == "spin": spin(d) + else: + reverse(d) except KeyboardInterrupt: pass finally: