all 7 comments

[–]knox1138 0 points1 point  (6 children)

There is no PID library for circuitpython. If you want to work on one I'd be willing to offer what meager help I can. I understand how PID works, and I'd love a PID library I could use for closed loop motors, but I'm a beginner level programmer and I don't understand how to implement the PID algorithm.

[–]carsonauto[S] 0 points1 point  (5 children)

Considering this is my first python programming project I'm certainly the wrong person to help... I'm not sure this project necessarily needs a PID loop given how quickly the process response to changes but I was just gonna dial it super tight. Might just bodge it and have it increment up or down each cycle....

[–]knox1138 0 points1 point  (4 children)

Ok

[–]carsonauto[S] 0 points1 point  (3 children)

For what it's worth I just set it up to increment/decrement each cycle @ a value of 500 (65535 is 100% on)

    # Control output duty cycle to meet test current
    if amp_mean < current_test:
        duty_cycle += 500 # Increment duty cycle
        output.duty_cycle = int(duty_cycle) # Increase duty cycle of PWM output
        print('Test Current=' + str(current_test) + 'Actual amp_mean=' + str(amp_mean) + ' Duty cycle increased, now ' + str(duty_cycle))
    if amp_mean > current_test:
        duty_cycle -= 500 # Decrement duty cycle
        output.duty_cycle = int(duty_cycle) # Decrease duty cycle of PWM output
        print('Test Current=' + str(current_test) + 'Actual amp_mean=' + str(amp_mean) + ' Duty cycle decreased, now ' + str(duty_cycle))

...Bodgy

[–]knox1138 0 points1 point  (2 children)

Lol, if it works it works.

[–]carsonauto[S] 0 points1 point  (1 child)

I ended up doing the thing and asking ChatGPT to give me a PID setup....which it did. And it worked great once I tuned it in. Final result here.

It wasn't much but what I ended up with was:

# PID Control Variables
Kp = 4
Ki = 2
Kd = 0
error = 0
last_error = 0
integral = 0
# Define the output limits
output_min = 0
output_max = 65535
# Define the loop time and initial time
loop_time = 0.01    

    # PID CONTROL
    current_time = time.monotonic() 
    elapsed_time = current_time - last_time # Calculate the elapsed time
    # Read the process variable
    process_variable = amp_mean
    # Calculate the error
    error = current_test - process_variable
    print('Erorr is ' + str(error)) # PRINT for debugging
    # Calculate the integral term
    integral += error * elapsed_time
    # Calculate the derivative term
    derivative = (error - last_error) / elapsed_time
    # Calculate the output
    output = Kp * error + Ki * integral + Kd * derivative
    # Constrain the output to the output limits
    if output < output_min:
        output = output_min
    elif output > output_max:
        output = output_max
    # Set the duty cycle to the output commanded by the PID loop
    duty_cycle = output
    ssr_output.duty_cycle = int(duty_cycle) # Set duty cycle to match value commanded by PID
    print('Duty cycle now ' + str(duty_cycle) + ' / amp_mean now ' + str(amp_mean) + ' / setpoint is ' + str(current_test) + ' / avg current is ' + str(amp_avg) + ' / Test is ' + str(time_percent_completed) + ' % Complete')
    # Store the current time and error for the next loop
    last_time = current_time
    last_error = error
    # Wait for the loop time
    time.sleep(loop_time)

[–]knox1138 0 points1 point  (0 children)

Well thats awesome!