ARM PID Controller Help - Page 1
Forum section: electronics / general

author: rheb1026
author_rank: Regular Contributor
timestamp: December 30, 2016, 01:44:26 am
content: I've been attempting to use the ARM CMSIS PID Controller function in a project to control the temperature of a peltier. A little bit about the specs: I have three temperature values that need to be achieved, one about 15C, another about 5C, and a third at -10C. I'm actively controlling the cooling only and letting it heat on it's own. I have a temperature sensor attached to a small aluminum block which sits on the cold side of the peltier. I'm using PWM to control the power to the peltier through a MOSFET. If it makes any difference, the microcontroller is an STM32 Cortex M4F.I would like to be able to control the temperature to within 0.1C of the set temperature (my testing so far has achieved this). The temperature sensor is good enough to resolve 0.01C, and the PWM values are between 0 and 3199 (due to the clock prescaling to get the frequency I want)Everything works great except that the PID controller never quite reaches the set temperature. At the high temperature the error is not important, but is close to 0.2C too warm. At the middle temperature the temperature is also not terribly important, but the error is closer to 0.6C too warm. The coldest temperature is the most critical, and this is where the error offset is the greatest, around 1C too warm. By offset I mean that my set temperature is -10C and the PID function will stabilize at -9C, even though the error input into the PID function is 1C. I've gotten around this by subtracting an 'offset' value before passing the set temperature to the PID function, but I'm concerned that this may cause issues in the future as the peltier and the insulation around the cooler age.Part of my confusion stems from the fact that I don't understand what kind of values the PID function should return and how to get them to map to my PWM values. What I've done is to scale the PID gain values until the numbers being output from the function are within reason and then limit them. Is there a better way to go about doing this? Is this part of my issue with the offsets?Here's my cooler control functionCode:void Cooler_Control(sensorStruct *cooler, arm_pid_instance_f32 *pid){cooler->pid_error = cooler->temperature - (cooler->set_temperature - cooler->offset);//Gain Scheduling: Change PID gains based on error difference// Power should be 100% on or 100% off when temperature is// outside 2C of set pointif (cooler->pid_error < 2.0 && cooler->pid_error > -2.0){pid->Kp = 320; //25 | 10pid->Ki = 0.32; //70 | .1pid->Kd = 1600; //5 | 50// Re-Initialize PID valuesarm_pid_init_f32(pid, 1);}else{pid->Kp = 2500;pid->Ki = 0;pid->Kd = 0;// Initialize PID valuesarm_pid_init_f32(pid, 1);}cooler->pid_output = arm_pid_f32(pid, cooler->pid_error);if (cooler->pid_output > 3199){cooler->pwm_duty = 3199;}else if (cooler->pid_output < 0){cooler->pwm_duty = 0;}else cooler->pwm_duty = (uint16_t)cooler->pid_output;// Update Cooler PWMset_cooler_pwm(cooler->pwm_duty);}

author: ajb
author_rank: Super Contributor
timestamp: December 30, 2016, 04:11:28 pm
content: Your I and D terms seem way out of whack. The fact that you have a very small KI and a very large KD suggests to me that your timescale is too short and you were having problems with the integral winding up and causing oscillation. How frequently are you calling the cooler update function? A TEC stuck between two lumps of metal tends to have a fairly long time constant in MCU terms, so there's no point in banging away at the control loop as fast as possible.I'd suggest you try running the loop at something like 5Hz, in proportional only. Once you have an idea of how that performs, start increasing KI until the steady-state error gets to within tolerable levels. I would be surprised if you need any KD at all if you have a reasonable thermomechanical design (which mainly means a low thermal time constant between the TEC cold side and your temperature sensor/load, which in turn mainly means a low thermal resistance between the TEC cold side and the sensor/load). If you need faster response and your TEC is capable of higher slew rates, you can start driving up KP and increasing the update frequency until you get to where you need to be.One other thing to watch out for with the integral term is that small error levels can get rounded down to zero, which means they integrate to...zero. It looks like your PID uses floats, so probably not an issue here, but can be a trap for int or fixed point implementations.As far as TECs and PWM: generally not the most efficient way to go, and can limit your systems performance. A linear or class D driver that gives a constant current is generally better for a system that must perform well over a wide range of conditions

author: snarkysparky
author_rank: Frequent Contributor
timestamp: December 30, 2016, 05:29:30 pm
content: The PID controller should zero out the error. Are you by any chance checking the temperatures with a different sensor than is the input to the PID.The output of the PID is the drive signal to the controller. It has no dimension nor any expected value as due to feedback it will ( should ) come to a point that makes the feedback balance the setpoint.When the temps stabilize is (cooler->pid_error == 0) , if so there is a measurement issue

author: rheb1026
author_rank: Regular Contributor
timestamp: December 30, 2016, 08:14:02 pm
content: I guess a little more info is needed on my part: The temperature sensor updates around 6 Hz and is the only one driving the computed error to pass to the PID function. The PID function updates at a much quicker rate than the sensor. When I initially tested it I found that updating the PID function at the same rate as the temperature sensor caused it to never really stabilize like I wanted (maybe this was due to incorrect gain values). Just for kicks I tried updating the PID function more often than the sensor (using the most recent sensor reading) and this caused the temperature to stabilize much better. The most important spec is that the cool down time from 5C to -10C is stabilized within one minute and that the temperature is within 0.1C of the set point.I read everything I could find online about tuning PIDs when I first started this and tried numerous gain values and combinations/ratios based on what I read. This is what seemed to come out the best after much trial and error. I will go back and try running proportional control only and then adding in the integral.I'm kind of stuck with using PWM at this point as I'm modifying a system that's already in use. Is there a better way to map the PID output to a PWM signal than trying to scale the gains like I'm doing?I can't recall whether or not the error value is zero once it's stabilized, but I will check and report back

author: rstofer
author_rank: Super Contributor
timestamp: December 31, 2016, 05:38:17 pm
content: ajb's answer is correct. Get rid of the derivative term and zero out the integral term and get your loop operating as good as it can using only the proportional term. The integral term is added back, a little bit at a time, until the error cancels out. You don't want the integral term to have much authority because it is integrating (and increasing output) all during the proportional time span.There are MANY 'tuning pid loop' tutorials on Google. They will all agree with ajb's answer.Matlab also has a package for tuning loops:https://www.mathworks.com/campaigns/products/ppc/google/pid-tuning-b.htmlThe derivative term is used to slow down the approach to set point. It looks at the rate of change of error and tries to slow it down. It is seldom necessary but it can be useful when large step changes cause the proportional gain to pour on the coal with the possibility of overshoot.

author: IanB
author_rank: Super Contributor
timestamp: December 31, 2016, 06:35:30 pm
content: Just to add on at the end, tuning constants like Kp, Ki and Kd have units of measure. Unless you state those units of measure alongside the value, judgments of whether the values are large or small for any given tuning constant are almost meaningless.

author: Kleinstein
author_rank: Super Contributor
timestamp: December 31, 2016, 08:17:25 pm
content: Using just PWM to control the cooling is reasonable linear. So just linear scaling the PID output to PWM values is OK.However using direct PWM to the Peltier element is not very efficient. Even linear operation can be more efficient: waste heat is generated at the linear operating transistor instead of in the TEC. However with linear control of the TEC, the relationship of current (or voltage) to cooling power will no longer be that linear. It is more like a parabola with maximum cooling power at an optimum current that is usually slightly lower than the maximum rated current. So in this case a different translation from PID output to current should be used.The 6 Hz cycle of the temperature sensor is quite slow. But might be just good enough. It does not make much sense to call the PID routine faster than the sensor updates. So a slightly fast sensor reading might be a good idea, even if this means more noise.To get a very fast response it can be a good idea to have a second temperature sensor at the ho side of the TEC too. The temperature of the hot side also as big influence on the heat flow and could be treated by a kind of feed forward or by including it when calculating PWM/current values from PID output.PID tuning needs some care, especially with a relatively slow system. A usual way for such slow systems is to measure the pulse of step response for the system and than determine suitable parameters from that curve. One could try is without the D term first - it might be fast enough this way. Including the D term allows for more gain and thus usually an overall faster response, even if the D term by it's own makes the approach more gradual. .

author: Jeroen3
author_rank: Super Contributor
timestamp: January 02, 2017, 03:31:08 pm
content: You are now mapping the output of the pid to an on/off threshold. This makes it hard to get a stable system.The PID in f32 probably uses the full range of the variables, or -1 to +1.You should normalize the output to fit your 10 bit timer so that it actually does PWM instead of feeding an ON/OFF controller.As it is now you won't see the effects ofIvery well because it has to integrate for a long time before it reaches your threshold.Oh and, please please please usesaturating arithmetic.

author: tatus1969
author_rank: Super Contributor
timestamp: January 02, 2017, 06:09:41 pm
content: my guess would be: you are repeatedly calling the pid init function. that will probably reset the integrator accumulator, making the i part unusable. plus: why do you switch bewteen two control sets?

author: diyaudio
author_rank: Frequent Contributor
timestamp: January 02, 2017, 08:14:27 pm
content: QuoteYou might want to have a look at how a Quadcopter flight computer (ArduPilot) does it, have a look at the PID tests and the code that controls the signal PWM to the ESC (Electronic Speed Control).https://github.com/ArduPilot/ardupilot/tree/master/librariesAlso, have you tried to actually simulate your system in Matlab ? Simulink PID app is very useful.

author: tatus1969
author_rank: Super Contributor
timestamp: January 03, 2017, 12:09:07 am
content: checked that arm_pid_init_f32() function. it clears the integrator state as I assumed. You are supposed to do that only once during initialization. And there is no need for this code "pid->Kp = 2500;pid->Ki = 0;pid->Kd = 0;", just let the PID do its job. And there is no need to execute it more often than once every second or so. Make sure to calculate the right integral term, the update rate is an input value of the formula. For a temperature controller, you do not need a D term.This is a good starting point, you need to know the step response of your controlled system first. Just set the PWM to a small fixed value and record how the temperature develops, plot a graph -->https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_methodEDIT: the english wiki is a bit abbreviated and only describes the oscillation method. That is not what I am referring to. The german page describes the other method (stationary tangent), and here is the most important picture:https://de.wikipedia.org/wiki/Faustformelverfahren_(Automatisierungstechnik)#/media/File:Tutg.svg

author: retrolefty
author_rank: Super Contributor
timestamp: January 03, 2017, 12:13:40 am
content: QuoteThat is not my experience at all. Preventing overshoot for a process with larger thermal mass is what the D term is best at.

author: tatus1969
author_rank: Super Contributor
timestamp: January 03, 2017, 12:29:15 am
content: Quote from: retrolefty on January 03, 2017, 12:13:40 amA PID will give you better dynamic response than a PI, but both can be adjusted to control a PT1_Tt system without any overshoot. PID becomes a must for higher order systems with more than one dominant time constant.

author: rheb1026
author_rank: Regular Contributor
timestamp: January 03, 2017, 03:14:12 pm
content: Thank you all for the recommendations and my apologies for the slow response - I was in the process of moving and didn't have regular access to internet.I'll try to respond to most of the questions and sorry if I miss any. The reason for me choosing to use PID vs just 'bang bang' doing it myself was because I thought it would be easier this way! I have not tried simulating or tried the step response method, which I obviously should have done first thing. It'll be what I do next.The reason for calling the pid_init function is to have two separate control schedules. When the temperature is outside +/- 2C I want the cooler to be either on full power or completely off. I will take a look into the reinitializing and see if it's causing the issues. It is easy enough anyway to just do the full on/off manually. I figured it would be easier to tune if I only had to worry about a 4 degree window instead of a 40 degree window.Thanks for the suggestion to normalize the output. This was one of the ideas that I was thinking about over the weekend

author: Kleinstein
author_rank: Super Contributor
timestamp: January 03, 2017, 04:10:52 pm
content: With PWM to control the TEC, the system is quite good linear. So the best PID control parameters will be the same over the whole temperature range. If it works for the small range near the set point, it will work for the whole range too. Adding gain scheduling only makes things complicated, and you don't need it here. Especially if you reinitialize the regulator there will be an upset, and thus likely likely an extra delay and possible extra trouble (like oscillation around the step in gain scheduling).It is extremely hard to find a heuristic control that is better than a well tuned PID - so usually it is better to spend a little more time in doing proper tuning instead of programming a second control.Gain scheduling something for truly nonlinear systems (e.g. if the time constants change with temperature). If nonlinearity is just from the control element (e.g. TEC controlled by current) it is easier and often better to use a nonlinear function to map PID output to control values.If you want to ge beyond the simple PID, the most effective part would be likely measuring the hot side temperature as well. You may want that for protection against overheating (e.g. fan failure) anyway.

author: obrien
author_rank: Contributor
timestamp: January 04, 2017, 09:50:30 pm
content: It has been a while since I designed the PIDs, but I remember few notes that helps to get it done. it is very "high level notes" but I hope it will help:Start with P only -> P controls the speed of regulation, if high you will have a overshoot. For temperature you will have probably always constant error, if only P is used. But start with P only to get the basic speed you need.Then PI -> I eliminates the constant error - it makes the system reach the reference. But it can destabilize the system, starts with lover values and see the response.Lastly D -> D is used to stabilize the system which cannot be stabilize by PI, it can also eliminates the overshoot if used properly. BUT it is super sensitive to sampling errors, noise, wrong reading etc.------------------------------------------------------------To understand what each represent:P evaluates the current value/error right now. It is simple - how much I am from the target !now!I evaluates the past (integrates) - it remembers the past, so if you have persistent (even small error) it will adds up (integrates) over time and eventually it will make your controller react. But if you have oscillation (+- same value), the errors will cancel each other out and you can have non-stable system.D evaluates the future (linear interpolation) - it tries to guess where the system will be next time. Or better, it evaluates the direction of the error. You do not need it all the time, but it can stabilize your system (if used properly).