m-lundberg / simple-pid

A simple and easy to use PID controller in Python
MIT License
767 stars 209 forks source link

Question: how to incorporate a slew rate? #45

Closed kratsg closed 2 years ago

kratsg commented 2 years ago

For reference - this package works pretty nicely as it stands. I'm wondering how one might add a slew rate, in order to set the maximum "acceleration" of the PID. Perhaps with error_map ? (Is this where the slew term goes in?)

kratsg commented 2 years ago

Playing around a bit more, this is what I ended up with

def slew_rate(actual, target, max_rate=15.0/60.0, dt=1.0):
    delta = target - actual
    if abs(delta) < max_rate * dt:
        return (target, False)

    if delta > max_rate * dt:
        delta = max_rate * dt
    elif delta < -max_rate * dt:
        delta = -max_rate * dt
    slew_target = actual + delta
    return (slew_target, True)

pid = PID(-0.5*0.080, -0.8*0.5/24, -0.066*0.5/24, setpoint=0)
pid.proportional_on_measurement = True
pid.sample_time = 1.0
pid.output_limits = (0, 15)

try:
    while True:
        v = ps_peltier.measureVoltage()
        t, is_slewed = slew_rate(get_temperature(), pid.setpoint)
        if is_slewed:
            pid._integral = 0.0
        control = pid(t)
        print(f"{t:0.4f} °C ({v:0.4f} V) -> {control:0.4f} V{' slewing' if is_slewed else ''}")
        ps_peltier.setVoltageLevel(control)
        time.sleep(pid.sample_time)
except KeyboardInterrupt:
    ps_peltier.setVoltageLevel(0.0)

if there's any other suggestions.

m-lundberg commented 2 years ago

Hi, I really can't offer any more insight than what you have already provided yourself. Thanks for sharing what you came up with, it could be really useful to someone else!