Hello community,
is there anywhere out there a example of how to implement / what library to use for PID controller applications in CircuitPython?
i want to try to create a reflow soldering hot-plate controller :-)
i did not find any PID example in the learn search..
my next try would be the simple-pid library - as it is written in pure python and has no external dependencies..
please let me know all ideas / tips you have :-)
sunny greetings
stefan
CP - PID controller for reflow hot-plate
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- mikeysklar
- Posts: 16572
- Joined: Mon Aug 01, 2016 8:10 pm
Re: CP - PID controller for reflow hot-plate
stefan,
Because CircuitPython / MicroPython and Python are all so close if you can find an example in one it probably can easily be moved to another. Take a look at this simple micropython PID library.
https://github.com/B3AU/micropython/blob/master/PID.py
Because CircuitPython / MicroPython and Python are all so close if you can find an example in one it probably can easily be moved to another. Take a look at this simple micropython PID library.
https://github.com/B3AU/micropython/blob/master/PID.py
Code: Select all
__author__ = 'beau'
import pyb
class PID:
"""
Discrete PID control
"""
def __init__(self,input_fun,output_fun, P=3., I=0.01, D=0.0):
self.Kp=P
self.Ki=I
self.Kd=D
self.I_value = 0
self.P_value = 0
self.D_value = 0
self.I_max=100.0
self.I_min=0
self.set_point=0.0
self.prev_value = 0
self.output = 0
self.output_fun = output_fun
self.input_fun = input_fun
self.last_update_time = pyb.millis()
def update(self):
if pyb.millis()-self.last_update_time > 500:
"""
Calculate PID output value for given reference input and feedback
"""
current_value = self.input_fun()
self.error = self.set_point - current_value
print ('temp '+str(current_value))
print ('SP'+str(self.set_point))
self.P_value = self.Kp * self.error
self.D_value = self.Kd * ( current_value-self.prev_value)
lapsed_time = pyb.millis()-self.last_update_time
lapsed_time/=1000. #convert to seconds
self.last_update_time = pyb.millis()
self.I_value += self.error * self.Ki
if self.I_value > self.I_max:
self.I_value = self.I_max
elif self.I_value < self.I_min:
self.I_value = self.I_min
self.output = self.P_value + self.I_value - self.D_value
if self.output<0:
self.output = 0.0
if self.output>100:
self.output = 100.0
print("Setpoint: "+str(self.set_point))
print("P: "+str(self.P_value))
print("I: "+str(self.I_value))
print("Output: "+str(self.output))
print ()
self.output_fun(self.output/100.0)
self.last_update_time=pyb.millis()
- adafruit2
- Posts: 22549
- Joined: Fri Mar 11, 2005 7:36 pm
Re: CP - PID controller for reflow hot-plate
tbh hot plates are so slow you dont need PID - just heat to 220-240 *C then turn off the heat. :)
https://learn.adafruit.com/ez-make-oven
https://learn.adafruit.com/ez-make-oven
- slight
- Posts: 129
- Joined: Wed Sep 12, 2012 2:23 am
Re: CP - PID controller for reflow hot-plate
thanks @adafruit2!
that is a very useful recourse... ;-)
seems i only have to port it to my PyBadge (my main controller)
and see what happens...
i have some ceramic heating elements - i think they could be way faster than normal hotplates...
i will let you know!
sunny greetings
stefan
that is a very useful recourse... ;-)
seems i only have to port it to my PyBadge (my main controller)
and see what happens...
i have some ceramic heating elements - i think they could be way faster than normal hotplates...
i will let you know!
sunny greetings
stefan
- slight
- Posts: 129
- Joined: Wed Sep 12, 2012 2:23 am
Re: CP - PID controller for reflow hot-plate
hello again :-)
i made some progress -
and basics are working now
my pid implementation is based on these sources:
https://github.com/s-light/cp_reflow_co ... ain/pid.py
my full CircuitPythone reflow controller can be found at
https://github.com/s-light/cp_reflow_controller
and all the documentation at these both places: sunny greetings
stefan
i made some progress -
and basics are working now
my pid implementation is based on these sources:
- https://github.com/B3AU/micropython/blob/master/PID.py
- https://www.embeddedrelated.com/showarticle/943.php
- http://brettbeauregard.com/blog/2011/04 ... direction/
https://github.com/s-light/cp_reflow_co ... ain/pid.py
Code: Select all
#!/usr/bin/env python3
# coding=utf-8
# SPDX-FileCopyrightText: Copyright (c) 2021 Stefan Krüger s-light.eu
#
# SPDX-License-Identifier: MIT
"""
simple pid control.
based on
https://github.com/B3AU/micropython/blob/master/PID.py
and
https://www.embeddedrelated.com/showarticle/943.php
and
http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-direction/
"""
import time
class PID:
"""
Simple PID control.
P: proportional
I: integral
D: derivative
"""
def __init__(
self,
input_fun,
output_fun,
*, # force keyword arguments
update_intervall=0.1,
P_gain=0.0,
I_gain=0.0,
D_gain=0.0,
output_min=0.0,
output_max=100.0,
debug_out_print=False,
debug_out_fun=None,
):
self.input_fun = input_fun
self.output_fun = output_fun
self.update_intervall = update_intervall
self.P_gain = P_gain
self.P_value = 0
self.I_gain = I_gain
self.I_value = 0
self.I_state = 0
self.I_max = 100.0
self.I_min = 0
self.D_gain = D_gain
self.D_value = 0
self.D_state = 0
self.output_min = output_min
self.output_max = output_max
self.debug_out_print = debug_out_print
self.debug_out_fun = debug_out_fun
self.set_point = 0.0
self.output = 0
self.last_update_time = time.monotonic()
def _update(self, current_value):
# calculate the proportional term
self.P_value = self.P_gain * self.error
# calculate the integral state with appropriate limiting
self.I_state += self.error
# Limit the integrator state if necessary
if self.I_state > self.I_max:
self.I_state = self.I_max
elif self.I_state < self.I_min:
self.I_state = self.I_min
# calculate the integral term
self.I_value = self.I_gain * self.I_state
# calculate the derivative term
self.D_value = self.D_gain * (current_value - self.D_state)
self.D_state = current_value
# calculate output
self.output = self.P_value + self.I_value - self.D_value
# limit output
if self.output < self.output_min:
self.output = self.output_min
if self.output > self.output_max:
self.output = self.output_max
if self.debug_out_fun or self.debug_out_print:
debug_out = (
# "set_point: {set_point}\n"
"P_value: {P_value: > 7.2f} "
"I_value: {I_value: > 7.2f} "
"D_value: {D_value: > 7.2f} "
"output: {output: > 7.2f} "
"".format(
# set_point=self.set_point,
P_value=self.P_value,
I_value=self.I_value,
D_value=self.D_value,
output=self.output,
)
)
if self.debug_out_fun:
self.debug_out_fun(debug_out)
if self.debug_out_print:
print(debug_out, end="")
return self.output / 100.0
def update(
self,
*, # force keyword arguments
current_value=None,
set_point=None,
error=None,
):
"""Calculate PID output value."""
output = None
elapsed_time = time.monotonic() - self.last_update_time
if elapsed_time > self.update_intervall:
if not current_value:
current_value = self.input_fun()
if set_point:
self.set_point = set_point
if not error:
self.error = self.set_point - current_value
if self.debug_out_fun or self.debug_out_print:
debug_out = (
"current_value: {current_value: > 7.2f} "
"set_point: {set_point: > 7.2f} "
"error: {error: > 7.2f} "
"".format(
current_value=current_value,
set_point=self.set_point,
error=self.error,
)
)
if self.debug_out_fun:
self.debug_out_fun(debug_out)
if self.debug_out_print:
print(debug_out, end="")
else:
self.error = error
output = self._update(current_value)
self.output_fun(output)
self.last_update_time = time.monotonic()
if self.debug_out_print:
print()
return output
my full CircuitPythone reflow controller can be found at
https://github.com/s-light/cp_reflow_controller
and all the documentation at these both places: sunny greetings
stefan
Please be positive and constructive with your questions and comments.