Electronics > Beginners
Advises on programming/tuning a PID for Peltier element
(1/4) > >>
arronar:
Hi again.

In another thread I described that I'm driving a Peltier element using the Syren 10A driver with a raspberry pi zero. According to driver's manual, I'm using it with the R/C mode where on page 11 says the following:


--- Quote ---A 1500us pulse is zero speed,
a 1000 us pulse is full reverse and
a 2000 us pulse is full forward
--- End quote ---

So now I'm trying to program a PID controller to make Peltier element keep a stable temperature. I'm writing it in python language and here is the code so far:


--- Code: ---from time import sleep
from w1thermsensor import W1ThermSensor
import pigpio

pi = pigpio.pi()


def GET_TEMP():
    sensor = W1ThermSensor()
    temp   = sensor.get_temperature()
    return temp

def PLTR_CTRL( PWM_VALUE ):
    pi.set_servo_pulsewidth( PLTR_PIN, PWM_VALUE )

def FAN_CTRL( FAN_VALUE ):
    pi.write( FAN_PIN, FAN_VALUE )

# PIN CONFIGURATION
PLTR_PIN    = 18
FAN_PIN     = 5

# PARAMETERS CONFIGURATION
SAMPLE_TIME = 1
PWM_ON      = 2000
PWM_OFF     = 1500
PWM_REVERSE = 1000
TARGET_TEMP = 40

KP          = 0.55
KD          = 0.72

output      = 1
OldMin      = 0
OldMax      = 1
NewMax      = 2000
NewMin      = 1500
prevError  = 0         # Previous error

# MAIN PROGRAM STARTS HERE

# INITIALLY OPEN THE FAN
FAN_CTRL(1)
# AND THE PELTIER
PLTR_CTRL( PWM_ON )

# OPEN FILE
f = open("temp_data.txt", "w+")

try:

    while True:
       
        error = TARGET_TEMP - GET_TEMP()
        output += (error * KP) + (prevError * KD)
        # Turn it in a value between 0 an 1
        output = max(min(1, output),0)
        # Rescale the output into 1500  - 2000 range
        newPulse = ((( output - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
       
        # Apply the new pulse
        PLTR_CTRL( int(newPulse) )

        print("Temperature: ", GET_TEMP(), "\tError: ", error, "\t\tOutput: ", int(newPulse) )
        f.write( "%f\n" % GET_TEMP() )
        sleep(SAMPLE_TIME)
        prevError = error


except KeyboardInterrupt:
    PLTR_CTRL( PWM_OFF )
    FAN_CTRL(0)
    f.close()
    pi.stop()
--- End code ---

So far I have implemented only the proportional and the derivative parts. As you can see I'm calculating the output variable based on the KP, KD and the error. Then I transform this output variable into a meaningful for the driver range of values by scaling it up between 1500 and 2000 usec pulses. I didn't include pulses smaller than 1000 usec because then the polarity get inverted and the Peltier element cools instead of heat.

So now I'm actually trying to tune the whole idea and because its the first time that I'm doing something like that I would be interested to read your opinions and advises on the way that I'm approaching it and of course if you have any hint or pipeline that will help me achieve a good enough tuning.
rstofer:
Derivative is usually omitted and integral is usually included.  However, 'wind-up' of integral error needs to be handled otherwise it can become the dominant term.

First things first, get proportional working.  Get the timing and factor squared away for proportional before even considering integral or derivative.

When you have the gain right for proportional, there will probably be some overshoot and settling within a very few oscillations.  But the actual output will have some steady state error and that is removed by integrating the error until it becomes large enough to be a factor.

Here is a pretty good article about PID but Google is FULL of similar documents.  I like this one because I have Matlab and as soon as I get it printed, I'm going to play with it.
langwadt:

--- Quote from: arronar on November 19, 2018, 10:41:01 pm ---Hi again.

In another thread I described that I'm driving a Peltier element using the Syren 10A driver with a raspberry pi zero. According to driver's manual, I'm using it with the R/C mode where on page 11 says the following:


--- Quote ---A 1500us pulse is zero speed,
a 1000 us pulse is full reverse and
a 2000 us pulse is full forward
--- End quote ---

So now I'm trying to program a PID controller to make Peltier element keep a stable temperature. I'm writing it in python language and here is the code so far:


--- Code: ---from time import sleep
from w1thermsensor import W1ThermSensor
import pigpio

pi = pigpio.pi()


def GET_TEMP():
    sensor = W1ThermSensor()
    temp   = sensor.get_temperature()
    return temp

def PLTR_CTRL( PWM_VALUE ):
    pi.set_servo_pulsewidth( PLTR_PIN, PWM_VALUE )

def FAN_CTRL( FAN_VALUE ):
    pi.write( FAN_PIN, FAN_VALUE )

# PIN CONFIGURATION
PLTR_PIN    = 18
FAN_PIN     = 5

# PARAMETERS CONFIGURATION
SAMPLE_TIME = 1
PWM_ON      = 2000
PWM_OFF     = 1500
PWM_REVERSE = 1000
TARGET_TEMP = 40

KP          = 0.55
KD          = 0.72

output      = 1
OldMin      = 0
OldMax      = 1
NewMax      = 2000
NewMin      = 1500
prevError  = 0         # Previous error

# MAIN PROGRAM STARTS HERE

# INITIALLY OPEN THE FAN
FAN_CTRL(1)
# AND THE PELTIER
PLTR_CTRL( PWM_ON )

# OPEN FILE
f = open("temp_data.txt", "w+")

try:

    while True:
       
        error = TARGET_TEMP - GET_TEMP()
        output += (error * KP) + (prevError * KD)
        # Turn it in a value between 0 an 1
        output = max(min(1, output),0)
        # Rescale the output into 1500  - 2000 range
        newPulse = ((( output - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
       
        # Apply the new pulse
        PLTR_CTRL( int(newPulse) )

        print("Temperature: ", GET_TEMP(), "\tError: ", error, "\t\tOutput: ", int(newPulse) )
        f.write( "%f\n" % GET_TEMP() )
        sleep(SAMPLE_TIME)
        prevError = error


except KeyboardInterrupt:
    PLTR_CTRL( PWM_OFF )
    FAN_CTRL(0)
    f.close()
    pi.stop()
--- End code ---

So far I have implemented only the proportional and the derivative parts. As you can see I'm calculating the output variable based on the KP, KD and the error. Then I transform this output variable into a meaningful for the driver range of values by scaling it up between 1500 and 2000 usec pulses. I didn't include pulses smaller than 1000 usec because then the polarity get inverted and the Peltier element cools instead of heat.

So now I'm actually trying to tune the whole idea and because its the first time that I'm doing something like that I would be interested to read your opinions and advises on the way that I'm approaching it and of course if you have any hint or pipeline that will help me achieve a good enough tuning.

--- End quote ---

it'd think it should be, output += (error * KP) + ((prevError-error) * KD)

rstofer:
EEVacademy video:

arronar:

--- Quote --- Get the timing and factor squared away for proportional before even considering integral or derivative.
--- End quote ---
Excuse me but I don't understand what you are saying here. What's the timing? You mean to change the sampling period?


--- Quote ---Here is a pretty good article about PID but Google is FULL of similar documents.  I like this one because I have Matlab and as soon as I get it printed, I'm going to play with it.

--- End quote ---

you probably forgot the link.


--- Quote ---it'd think it should be, output += (error * KP) + ((prevError-error) * KD)

--- End quote ---

You probably are right. I'll double check it.
Navigation
Message Index
Next page
There was an error while thanking
Thanking...

Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod