added libraries

This commit is contained in:
2026-10-03 22:01:30 +00:00
parent 8620fde64b
commit 146887d01c
+30 -9
View File
@@ -2,6 +2,7 @@
"""
sudo python3 balance.py imu # find the balance point
sudo python3 balance.py balance --offset X # balance
sudo python3 balance.py balance --offset X --speed 200 # drive forward at 200 mm/s
"""
import argparse, math, os, sys, threading, time
import numpy as np
@@ -17,6 +18,7 @@ START_ANGLE = 5.0 # deg: arms when held this close to upright
PWM_MAX = 2000 # power-bank limit
PWM_SLEW = 300 # max PWM change per tick (no instant reversals)
ENC_TIMEOUT = 0.05 # s without encoder data -> motors off, re-init driver board
ACCEL_MAX = 150 # mm/s per second: how fast the speed setpoint ramps
LEFT, RIGHT = 2, 3 # M3 = left, M4 = right
MOTOR_SIGN = (-1, +1) # +PWM on M3 rolls the robot backward, so flip it
ENC_SIGN = (-1, +1) # M3 counts down when rolling forward, so flip it
@@ -167,7 +169,9 @@ def balance(imu, tilt, motors, args):
out = target = v = 0.0
prev = prev_t = None
last_reinit = time.perf_counter()
print(f"kp={args.kp} kd={args.kd} kv={args.kv} ki={args.ki} offset={args.offset}")
stats = [] # (wheel position mm, tilt, pwm) for the stillness readout
print(f"kp={args.kp} kd={args.kd} kv={args.kv} ki={args.ki} offset={args.offset} "
f"slew={args.slew} deadband={args.deadband} speed={args.speed}")
print("Hold it upright and still to arm. Ctrl-C to quit.", flush=True)
for tick, (dt, now) in enumerate(ticker(LOOP_HZ)):
@@ -193,6 +197,8 @@ def balance(imu, tilt, motors, args):
if tilt.ready() and abs(theta) < START_ANGLE and abs(rate) < 30:
armed, out, target, v = True, 0.0, 0.0, 0.0
speed_pid.reset()
speed_pid.setpoint = 0.0 # always start standing still, then ramp
stats.clear()
prev, prev_t = wheels, now
print("ARMED", flush=True)
elif tick % 20 == 0:
@@ -209,27 +215,42 @@ def balance(imu, tilt, motors, args):
if tick % 4 == 0:
v_now = (wheels[0] - prev[0] + wheels[1] - prev[1]) / 2 * MM_PER_TICK / (now - prev_t)
v = 0.7 * v + 0.3 * v_now # mm/s, smoothed
speed_pid.setpoint += clamp(args.speed - speed_pid.setpoint, ACCEL_MAX * (now - prev_t))
target = speed_pid(v, dt=now - prev_t)
prev, prev_t = wheels, now
# inner loop, 200 Hz: angle PD (D straight from the gyro, no differentiating)
u = clamp(args.kp * (theta - target) + args.kd * rate, PWM_MAX)
out += clamp(u - out, PWM_SLEW) # ramp, never jump
u = args.kp * (theta - target) + args.kd * rate
if u:
u += math.copysign(args.deadband, u) # help the wheels past static friction
u = clamp(u, PWM_MAX)
out += clamp(u - out, args.slew) # ramp, never jump
motors.pwm(out, out)
# stillness readout every 5 s: lower = stiller
stats.append(((wheels[0] + wheels[1]) / 2 * MM_PER_TICK, theta, out))
if len(stats) == 5 * LOOP_HZ:
pos, th, pw = (np.array(c) for c in zip(*stats))
print(f"STILLNESS 5s: wheels p-p {np.ptp(pos):5.1f} mm rms {pos.std():4.1f} mm "
f"tilt rms {th.std():5.2f} deg pwm rms {pw.std():4.0f}", flush=True)
stats.clear()
if tick % 20 == 0:
print(f"th {theta:+6.2f} tgt {target:+5.2f} rate {rate:+7.1f} v {v:+6.0f} mm/s pwm {out:+6.0f}",
flush=True)
print(f"th {theta:+6.2f} tgt {target:+5.2f} rate {rate:+7.1f} v {v:+6.0f} mm/s "
f"sp {speed_pid.setpoint:+4.0f} pwm {out:+6.0f}", flush=True)
def main():
p = argparse.ArgumentParser()
p.add_argument("mode", choices=["imu", "balance"])
p.add_argument("--offset", type=float, default=0.0, help="pitch at the balance point, deg")
p.add_argument("--kp", type=float, default=100.0, help="PWM per deg of lean")
p.add_argument("--kd", type=float, default=2.5, help="PWM per deg/s of tipping")
p.add_argument("--kv", type=float, default=0.0, help="deg of lean per mm/s of speed")
p.add_argument("--ki", type=float, default=0.0, help="deg of lean per mm of drift")
p.add_argument("--kp", type=float, default=120.0, help="PWM per deg of lean")
p.add_argument("--kd", type=float, default=3.0, help="PWM per deg/s of tipping")
p.add_argument("--kv", type=float, default=0.02, help="deg of lean per mm/s of speed")
p.add_argument("--ki", type=float, default=0.003, help="deg of lean per mm of drift")
p.add_argument("--speed", type=float, default=0.0, help="drive speed, mm/s, + = forward")
p.add_argument("--slew", type=float, default=PWM_SLEW, help="max PWM change per tick")
p.add_argument("--deadband", type=float, default=0.0, help="PWM added to beat static friction")
args = p.parse_args()
realtime()