-
Re: PID-filter routine (2nd try).
Hello,
Quote:
You have a desired value (setpoint), you take an incoming ADC reading & subtract it from your desired value....the PID sub routine then gets called & it returns a value of pid_out ?
Am I right so far?!!
Yes, or the other way around depening on the polarity of the feedback signal in relation to the polarity of the drive signal. So
pid_Error = Setpoint - ActualValue
or
pid_Error = ActualValue - SetPoint
Quote:
Ok, what to do with pid_out?
That is really up to you ;-)
Quote:
I'm wondering how I translate the "Direction = pid_Out.15" to be increment/decrementof thedigital pot ...or does it not matter - ie will the value of pid_out just be a value that I can write direct to the digital pot?
Yes, from my understanding of your application your input signal (setpoint) ranges from 0 to 255 and you want the output of the filter to range from 0 to 255 as well. The direction bit in this case is set when the filter wants negative output, not decreasing but negative, something you can't get with your setup.
So, what you need to do is to clamp the output to 0 with something like:
Code:
If pid_Out.15 THEN pid_Out = 0
Also, to clamp the output to a maximum of 255 you should set pid_Out_Clamp to 255. Or, which is actually better because it gives the filter more "resolution", set it to 1024 and then divide the final output by 4 before writing it to the pot.
Good luck!
/Henrik.
-
Re: PID-filter routine (2nd try).
I am doing a mini project for a PID control using PIC18F452 or PIC18F877 but I am not good in C code as I am electricial trained.
Below is my project requirement:
Hardware interfaces :
(1) 4 potentiometers as inputs to set the values of Kp, Ki , Kd and desired speed setting via analogue channels
(2) A dc permanent magnet motor to act as the targeted process to be controlled.
(3) A driver circuit to power the motor to its desired speed , using PWM output control from the PIC controller ( unidirectional control will be sufficient )
(4) A speed sensor to provide speed feed-back signal to the PIC controller ( a tacho-generator mechanically coupled to the motor shaft will be the easiest interface)
Software codes in C :
(1) Speed of the dc motor to be adjustable by the setting of the speed potentiometer.
(2) A simple PID algorithm to enable the motor speed response characteristics to be adjusted via the settings of Kp, Ki and Kd.
I had already done a simple driver circuit to control a motor and it coupled with another motor which provide the output voltage. Can you help me how to kick off to start my c code using pic19F452 for the PID requirement and also help to interface the circuit with my controller with the 4 potential meter intergated?
-
Re: PID-filter routine (2nd try).
Maybe the best suggestion is tolook for a C lanquage forum.
We do Basic here (Pic Basic by Melabs).
Ioannis
-
Re: Hi Henrik again after little time
Hello Henrik, All,
I have read through this thread regarding servo PID motor control that Henrik wrote. I need to modify the code for the direction part of the code. My h-bridge has 3 i/o. PWM drive, Portd.0 and Portd.1.
The allowable states are:
portd.0 = 1 and portd.1 = 0
portd.1 = 0 and portd.1 = 1
I see that Henrik uses 1 bit to control direction. can I simply replace his code
"Direction = pid_Out.15 'Set direction pin accordning to sign"
with.....
if pid_out.15 = 1 then
portd.0 = 1
portd.1 = 0
else
portd.0 = 0
portd.1 = 1
endif
I am concerned about messing up timing by introducing these lines of code. Will this affect the integrity of the original code?
Best Regards,
Nick
-
Re: PID-filter routine (2nd try).
Hi Nick,
Sure, you can do that - it won't have any effect on the PID code itself and it won't have any effect on the timing of the loop if you're not running the loop at extremely high frequencies.
However, your pins will be in an invalid state for a short period of time since you set each individual bit separately. Ie when going from 10 to 01 you first clear the high bit, now the output is 00, then you set the low bit to make the output 01. This is likely not a problem but depending on your particular hardware it's possible that 00 and/or 11 has some either undefined function or perhaps they brake the motor by shorting the two lower or two higher switches of the bridge.
If this prooves to be a concern then you can either fix it with hardware, a single inverter is all you need and you save a PIC pin. If adding hardware is not an option then look into writing all PortD-bits in one go, perhaps something like:
Code:
IF PID_Out.15 = 1 THEN
PortD = (PortD & %11111100) + 1
ELSE
PortD = (PortD & %11111100) + 2
ENDIF
I'm sure there are other ways of doing it too.
/Henrik.
EDIT: Aaarh, now the bloody editor keeps messing with my code again, removing the %-sign AND two digits in the binary value following it...
-
Re: PID-filter routine (2nd try).
Good point. I will make the suggested change. In your main code you have HPWM 1, pid_out, 10000 .... I know that pid_out is declared a word (2 bytes) and frequency is 10Khz? The HPWM in the manual says it works with 1 byte for duty cycle....can you explain this part of it? How does feeding a word work with HPWM?
Best Regards,
Nick
-
Re: PID-filter routine (2nd try).
Uhh, I guess it doesn't really...you're the first to notice!
That's an oversight on my behalf as far as the example goes. However, if you clamp the output to +/-255 using pid_Out_Clamp=255 I think it'll work as shown. I think PBP is smart enough to only get the low byte of the word in this case.
All internal calculations in the PID filter are based on word-sized variables so pid_Out should and must be a WORD.
/Henrik.
-
Re: PID-filter routine (2nd try).
Hello Henrik,
I just thought you should know that the code works perfectly in my servo application with the mods. I need to tweak constants / gains. Making small incremental changes in position is smooth. Making large changes causes some jerkiness and overshoot but no oscillations!
Best Regards,
Nick
-
Re: PID-filter routine (2nd try).
Hi Nick,
It's always nice to hear that things work out.
Large step inputs are always "hard" on the filter. It's definitely possible to tune the overshoot out, (lowering I and increasing D should help) but that has other drawbacks. In a servomotor application it's common to have a trajectory planner (think ramp up speed, run, ramp down) before the filter. Basically this "divides" a large step into several small ones making the overshoot you see with a large step input considerably smaller.
/Henrik.
-
Re: PID-filter routine (2nd try).
I see...basically no different than a CNC profile step shape going into the motor driver. I will work on the ramp up/down function and see if I can improve things a bit.
I need to control 2 servo motors each with feedback pot. Is it as simple (yet inefficient) as two separate routines one for each servo on the same MCU? or is there a more cleavor way of doing it? Maybe using Flags to switch between the two servo's running through 1 PID routine (not 2 routines)?
Nick
-
Re: PID-filter routine (2nd try).
Hi Nick,
Exactly, a trapetzoidal or triangular profile works nicely though an S-shaped profile is even better - but harder to compute.
Regarding multiple motor:
You need one regulator for each motor. The reason is that each regulator has memory of the past AND tries to predict the future. If you "switch" the filter between the two motors the filter will get confused and you're going to get very bad results. However, for obvious reasons it's not possible to include the file more than once but you could create a copy of it and append a _2 or whatever to each variable name thru out the code, that should do it.... Not ALL variables needs to be separate though but lets not get into those details now.
I DID make a special version some time back, for Malcolms terarium controller, it allows you to specify "any" number of regulators. It may lack some of the feature added to latest version of the filter but if you do a bit of searching on the forum you should be able to dig it up. If not let me know and I'll see if I can find it.
/Henrik.
-
Re: PID-filter routine (2nd try).
I have just read this whole thread and its very interesting. I plan to implement this on a buck converter. One question though is I'd like to be able to vary the output as required and providea ramp up time to the set output. To do this I would just have to change the setpoint on the fly, correct?
-
Re: PID-filter routine (2nd try).
That's correct, when tuned properly it will try it's best to follow the input. Just remember that the setpoint in itself is not the input of the filter, you feed the error (ie difference between setpoint and actual value) to the filter thru the PID_Error variable.
However, I'd imagine that regulating the output of switch mode converter requires quite a bit of bandwidth in the filter....
/Henrik.
-
Re: PID-filter routine (2nd try).
As short a cycle time as possible is desirable but as the load is the same number of LED's all the time, the current change over time is pretty slow, unless manually changed by the user, it really only changes with the temp rise of the LED's. Input voltage is regulated so that that is fairly stable.
-
Re: PID-filter routine (2nd try).
Getting back to trying this out finally.
So, I am converting a DC/DC converter that uses a very basic method of current control. I read the ADC value and compare it to the target ADC. If its below, I add +1 to the output HPWM, if its above the target ADC value I -1 to the HPWM value. This works ok if there are no upsets to input voltage or any rapid current changes on the output. It will oscillate quite badly on random occasions too. I think that is ripple on the ADC pin.
So I have just tried this for the first time and I'm getting some very unstable results. It is flickering quite badly. I'm sure this is a matter of tuning. Do you have any advice?
If I turn up the input voltage I also get to a point where it will no longer back off the output and try to maintain the correct current level, I assume this is a symptom of running into the lower level of the clamp?
-
Re: PID-filter routine (2nd try).
I set pid_Out_Clamp = 240 which is max duty cycle. At that max duty cycle current at the LED with an input voltage of 27.5V should never go above 2.5A, but it does. The set target is an ADC of 480. At those figures the following it the duty cycle:
Code:
0000- 240 000 000 000 255 240 240 240 0008- 240 240 240 240 240 240 240 240
0010- 240 240 240 240 240 240 240 240
0018- 240 240 240 240 240 177 240 240
0020- 240 240 240 240 240 240 240 240
0028- 240 240 240 240 240 240 240 240
0030- 240 240 240 240 240 240 240 240
0038- 240 240 030 240 240 240 240 049
0040- 240 240 240 240 240 240 240 240
0048- 203 240 240 240 240 116 110 240
0050- 007 240 240 240 240 081 240 240
0058- 240 240 240 240 240 240 240 240
0060- 158 240 021 129 240 240 240 240
0068- 240 240 240 075 240 240 240 240
0070- 240 240 240 240 149 240 240 240
0078- 240 190 240 240 041 240 240 240
0080- 240 112 240 240 240 240 240 240
0088- 240 147 240 240 203 240 240 240
0090- 240 240 096 240 240 240 240 240
0098- 240 240 240 240 141 240 240 240
00a0- 240 240 240 240 240 126 240 240
00a8- 240 240 240 240 240 240 240 240
00b0- 240 240 240 240 240 240 240 240
00b8- 240 240 240 240 240 240 240 102
00c0- 240 240 240 240 240 082 240 240
00c8- 240 188 240 240 240 240 129 240
00d0- 240 131 240 240 240 240 240 240
00d8- 240 192 240 240 240 240 240 240
00e0- 240 108 240 240 240 240 116 240
00e8- 240 224 240 240 240 013 240 079
00f0- 240 240 240 240 240 240 240 240
00f8- 240 240 240 240 240 240 042 240
And this is the ADC reading: (multiply these numbers by 4 to get the 10 bit actual value 166 = 664 etc etc.)
Code:
0000- 165 000 000 000 255 166 166 166 0008- 165 165 166 166 166 165 166 166
0010- 166 166 165 165 166 166 166 165
0018- 165 165 166 166 166 166 165 165
0020- 166 166 166 165 165 166 166 166
0028- 165 165 166 166 166 166 165 165
0030- 166 166 166 166 165 165 165 166
0038- 166 166 166 166 166 165 165 166
0040- 166 166 166 166 166 165 166 166
0048- 166 166 165 166 165 165 166 166
0050- 166 166 166 166 166 166 165 165
0058- 165 165 165 165 166 166 166 166
0060- 166 166 166 165 165 166 165 165
0068- 165 166 166 165 166 166 166 166
0070- 166 166 166 165 166 165 165 166
0078- 166 166 166 166 166 166 165 166
0080- 166 166 166 166 166 166 166 166
0088- 166 166 165 165 165 166 165 166
0090- 165 165 165 165 166 166 165 165
0098- 165 166 166 165 165 165 166 166
00a0- 166 166 165 166 166 166 166 165
00a8- 166 166 165 166 166 166 165 165
00b0- 166 165 166 166 165 165 165 165
00b8- 166 166 165 166 166 165 166 165
00c0- 165 166 165 165 166 166 165 166
00c8- 165 165 166 165 165 166 166 165
00d0- 166 166 165 166 166 165 166 166
00d8- 166 165 165 166 166 166 166 165
00e0- 165 166 166 166 166 166 166 166
00e8- 166 165 165 166 165 165 166 165
00f0- 165 165 166 166 166 165 166 166
00f8- 166 165 166 166 165 166 166 166
And finally, this is the result of pid_Error = Setpoint - CHANNEL1
[CODE0000- 077 000 000 000 255 076 077 076 0008- 077 077 076 076 077 077 076 075
0010- 075 077 076 076 076 077 077 076
0018- 076 077 077 076 076 077 077 077
0020- 077 076 076 077 077 076 076 077
0028- 077 076 076 075 077 076 077 077
0030- 077 076 077 077 077 076 076 077
0038- 076 077 077 076 075 077 076 076
0040- 077 077 076 076 077 077 076 077
0048- 077 076 077 077 076 077 077 076
0050- 075 075 076 076 077 077 076 077
0058- 076 076 077 076 075 077 077 076
0060- 075 076 076 075 077 076 076 077
0068- 076 077 077 076 077 076 076 077
0070- 076 076 075 076 075 076 076 075
0078- 075 076 076 077 076 076 077 076
0080- 076 077 076 076 077 076 075 077
0088- 076 076 075 076 076 077 076 075
0090- 076 076 077 077 076 077 077 076
0098- 076 077 075 077 076 075 077 076
00a0- 075 076 076 077 077 076 076 077
00a8- 076 077 076 076 077 077 076 077
00b0- 077 077 077 078 076 076 076 076
00b8- 077 076 076 076 076 077 077 077
00c0- 077 076 076 077 077 077 077 077
00c8- 076 076 076 077 077 077 076 076
00d0- 076 076 077 076 077 077 077 077
00d8- 077 077 076 076 076 076 077 077
00e0- 076 077 077 077 077 077 077 076
00e8- 076 076 076 076 077 076 077 077
00f0- 077 076 076 076 076 077 077 077
00f8- 077 077 077 077 077 077 076 076
[/CODE]
So, if the max ADC value is supposed to be 480, why is it clamping at a duty cycle of 240 giving a ADC value 664?
-
Re: PID-filter routine (2nd try).
Well I'm not sure if I'm making progress but here a few things I've noticed.
First, I cannot get this to maintain a stable output current at all. It will vary along with the input voltage.
Second, The flickering is, depending on input voltage, the pid_out going from the clamp limit (240) to what I assume to be a pid derived number. Depending on the input voltage, that number is anywhere from 0 - 240, however the range of input voltage is tiny and nowhere near the setpoint. See the code below:
Code:
0000- 240 000 240 035 240 036 240 035
0008- 240 036 240 036 240 037 240 035
0010- 240 038 240 036 240 037 240 036
0018- 240 037 240 038 240 036 240 038
0020- 240 036 240 036 240 037 240 036
0028- 240 035 240 037 240 037 240 036
0030- 240 036 240 035 240 037 240 036
0038- 240 036 240 036 240 037 240 035
0040- 240 037 240 035 240 036 240 035
0048- 240 037 240 036 240 037 240 035
0050- 240 037 240 036 240 037 240 036
0058- 240 037 240 035 240 036 240 035
0060- 240 038 240 035 240 038 240 035
0068- 240 036 240 037 240 038 240 039
0070- 240 037 240 037 240 035 240 037
0078- 240 036 240 037 240 036 240 036
0080- 240 035 240 036 240 036 240 036
0088- 240 038 240 038 240 035 240 036
0090- 240 038 240 035 240 036 240 036
0098- 240 037 240 037 240 037 240 035
00a0- 240 036 240 037 240 035 240 038
00a8- 240 036 240 036 240 036 240 036
00b0- 240 036 240 036 240 037 240 038
00b8- 240 036 240 037 240 036 240 037
00c0- 240 035 240 000 240 001 240 000
00c8- 240 001 240 004 240 007 240 009
00d0- 240 010 240 014 240 019 240 022
00d8- 240 025 240 027 240 029 240 034
00e0- 240 034 240 037 240 036 240 036
00e8- 240 036 240 036 240 036 240 037
00f0- 240 036 240 036 240 037 240 036
00f8- 240 037 240 035 240 036 240 036
Here is the code:
Code:
CLEAR
Define OSC 8
OSCCON=110000
DEFINE ADC_BITS 10
DEFINE ADC_CLOCK 3
DEFINE ADC_SAMPLEUS 50
DEFINE CCP1_REG PORTC 'Hpwm 1 pin port
DEFINE CCP1_BIT 2 'Hpwm 1 pin bit
CHANNEL1 var word
SETPOINT VAR WORD
SETPOINT = 480
INCLUDE "incPIDv1.5.pbp" 'Include the PID routine.
ADCON1 = 001011
ADCON2 = 001010
TRISA = 111111
TRISB = 000000
TRISC = 110001
CMCON = 7
UCON.3 = 0
UCFG.3 = 1
portc.1 = 0
alpha var word
CHANNEL14 var byte
PCBTEMP var word
CURRENT var word
LEDS var byte
POWER var byte
LEDS = 0
POWER = 0
pcbtemp = 0
CURRENT = 0
alpha = 0
channel1 = 0
channel14 = 0
'ADValue VAR WORD '<---This is your variable.
'Setpoint VAR WORD '<---This is your variable.
'Direction var PortB.7 '<---Direction bit to motor driver
'These variables are declared by the incPID routine but
'the user needs to assign values to them.
pid_Kp = $0100 'Set Kp to 7.0
pid_Ki = $0020 'Set Ki to 0.5
pid_Kd = $0010 'Set Kd to 2.14
pid_Ti = 8 'Update I-term every 8th call to PID
pid_I_Clamp = 25 'Clamp I-term to max ±100
pid_Out_Clamp = 240 'Clamp the final output to ±511
LOOP1:
portb.1 = 0
portb.2 = 0
portb.3 = 0
portb.4 = 0
portb.5 = 1
Gosub GetAD 'Get speed from tacho - NOT SHOWN HERE.
pid_Error = Setpoint - CHANNEL1 'Calculate the error
Gosub PID 'Result returned in pid_Drive
IF pid_Out.15 THEN pid_Out = 0 ' limit to positive values
pid_Out = ABS pid_Out 'Convert from two's comp. to absolute
HPWM 1, pid_Out, 30000 'Set PWM output
PORTB.0 = 1
PORTC.7 = 1
PORTC.6 = 1
PORTC.1 = 1
PORTA.6 = 1
PAUSE 10
GOTO LOOP1
GetAD:
ADCIN 0, CHANNEL1
alpha = alpha+1
'channel14 = channel1/4
WRITE alpha, pid_Out 'channel14
RETURN
-
Re: PID-filter routine (2nd try).
Couple more observations. It seems that there is a 50% duty cycle between a full on clamp and whatever the pid value should be. This is not a ripple issue as I can change the rate by changing the value of a pause statement at the end of the loop. With no pause, the flash rate is around 1mS. This on off at 50% duty cycle is shown in the above posts showing the memory dumps.
So the question now is, why is there an off period equal to the on period? If the output is higher than the setpoint, we get this 50% cycle, if its lower, we either get a 100% pid value for a very very small window or it clamps to zero and the pid value at a 50% duty cycle.
-
Re: PID-filter routine (2nd try).
Hi,
OK, lots of information here and I'm having a bit of a hard time following it all but here are a couple of thoughts.
Since you have the pid_OutClamp set to 240 and a proportional gain of 1 it means that the output will only "swing" when the CHANNEL1 variable is above 240 (because SetPoint is hardcoded to 480). If it's anything below 240 then the error * Kp is more than the clamp value so the output saturates. For example, if the CHANNEL1 value is 235 the error will be 480-235=245, the clamp is 240 so that's what you'll get.
If you do a step change of the PWM dutycycle, (ie. if you go from 20% to 80% dutycycle) how fast does the current in the system change?
I mean, you have a PAUSE 10 in there meaning you're only running the loop at 100Hz, it also looks like you're writing to EEPROM in the GetAD routine, which also takes around 10ms per byte so then we're down to around 50Hz. I'm not sure but 50Hz sounds awfully slow for a current control loop. You say that you've tried without any PAUSE at all but I still think you have around 10ms delay due to the WRITE instruction in the GetAD routine.
Not sure I understand what you mean with there is a 50% duty cycle between a full on clamp and whatever the pid value should be. Can you clarify?
May I suggest you try to implement this on something slower to begin with? Try a temp-sensor tightly coupled to lightbulb driven by the PWM signal for example - I think it'll make it a lot easier to begin with.
/Henrik.
-
Re: PID-filter routine (2nd try).
Hello Henrik,
Thank you for your reply. Sorry, last night was a brain dump and a "thinking out loud" of what was going on.
Your first point about proportional control, I was playing around with numbers to see what the effect was. So, for my case then, this number should be 0.5 or lower, correct? This would mean the output would swing when CHANNEL1 was above 480. (An ADC of 480 means 2.10A at the output.)
Ok, so lets recompile this with a 0.5 Kp and setpoint = 480.
I know that 27.5Vin with a duty cycle of 240 = 2.10A (ADCof 480) at the output. What I actually see if I WRITE the duty cycle values is exactly half the time (memory locations) at 240 and half the time at a duty cycle less than 240. Why is it clamping at 240 for half the time when it should be there all the time? If I raise the input voltage, there should be no clamping at 240 yet the higher the input voltage goes, there is still clamping at 240 for half the time but the other numbers will go down to 0. This means that eventually the output is flashing on and off at 50% duty cycle.
Current change response is quite fast. 20% - 80% change will be taken care of in ~1.2mS. However, the load change is very slow. These are 50W LED's and their current only changes due to self heating. They are on a huge big fan cooled heat sink. All this pid filter should have to maintain a very similar duty cycle, slowly dropping it over time. The lower the duty cycle, the cooler the LED, thus the less current, thus increased duty cycle etc etc. It takes about 1 minute for the LED to get to a temperature where the pid filter should start changing the duty cycle.
The ONLY thing I can think of here that is upsetting the system is ripple from the 30KHz switching circuits. I could add a lot of capacitance to the ADC pin to slow down the response and remove any ripples.
The control loop seems to be running a bit faster than what you have mentioned. I only have the WRITE in there for diagnostics, and run any changes twice, once with and once without the WRITE command. I was using the pause at the end of the loop to see what was happening with the 50% clamping at 240. If I make that pause 1S long, the duty cycle is 240 for 1 second and 0 for one second. If I take it out, the duty cycle is 240 for ~1mS and 0 for ~1mS. Thus the loop is running at ~1Khz. I cant see the on/off, I can only hear the inductors making noise.
I hope this clears up some things!
-
Re: PID-filter routine (2nd try).
Is there a way to have setpoint = 460 to 480 to create a "softer" current limit where some ripple at the output would be ok?
Also, what about having the clamp set at 960, then dividing that number by 4 and feeding it to the HPWM?
-
Re: PID-filter routine (2nd try).
Hi,
For simplicity, let's concentrate on the proportional gain alone (no Ki or Kd) to start with, OK?
Let's then assume the following:
* You have a proportional gain of 1, ie pid_Kp=$0100
* You're setpoint value is 480
* You have 2.1A flowing in your circuit resulting in an ADC value of 480
Now, when you calculate the error, pid_Error = SetPoint - ADC the error is 0 and therefor pid_Out will be 0. Since you're feeding pid_Out straight to the PWM module the dutycycle will be set to 0.
Now, because the dutycycle is 0 the current drops, rapidly. By the time you sample the current again it has dropped to 0 or close to it (I'm guessing a bit), so the ADC value is 0 and pid_Error will be 480. Because you have a proportional gain of 1 pid_Out would be 480 but it gets clamped to 240. That's where your bouncing output comes from.
If your 'idle' point requires a dutycycle of 240 then you need to set that up first. THEN you sample the current and run the error thru the PID-loop and ADD the pid_Out to the 'idle' dutycyle. For example, 240 is nominal dutycycle value, when the ADC returns 475 it means the current is on the low side, the error is 5 and pid_Out becomes 5 which you add to your 'idle' resulting in a dutycycle value of 245. If the ADC value is 490 (too much current) the error will be -10, the the pid_Out will be -10, which you add to your 'idle value' resulting in a dutycycle of 230, lowering the current.
Again, the above ilustrates what happens with a proportional gain of 1 only, when you add in the integral and derivative terms it'll act a little different.
There is no built in way to have it clamp in a soft way as you describe, you have to do that "manually" if you need.
/Henrik.
-
Re: PID-filter routine (2nd try).
How possible is it to make (and how, any ideas) the P-I-D parameters set automatically, like auto-tune?
I have seen some chinese temp. controllers that say they can do auto-tune according to the device they control.
Ioannis
-
Re: PID-filter routine (2nd try).
There are various ways for doing autotuning. Basicallly you step the setpoint and analyze the system response regarding risetime, overshoot, amplitude and frequency of any oscillation and so on.
I've got the question before and did some research into the matter but to be honest the math involved is beyond me. Right now I re-Googled PID Autotune and it came up with a link to a autotune library for Arduino - I may need to have a look at that!
If you're up for it, feel free to take a stab at it!
/Henrik.
-
Re: PID-filter routine (2nd try).
Thanks Henrik.
I will look at that link, although c and similar is not my strong.
What you proposed is I think the obvious way to approach the problem. I was thinking more or less the sam.
It seems that chinese are doing it much faster though. My REV200 Siemens temp controller is fast in evaluating the room too!
Ioannis
-
A couple of questions....
I am attempting to adapt Henrik's PID routine to my smoker temperature controller project. Basically, a fan provides air to the charcoal based on a temperature sensor in the chamber.
I set up a simulation using it, and it seems to work pretty cool, but I know I'm going to have to run on the real smoker to get it fully tuned up (I still have 3 feet of snow in my yard, so it may be a bit).
I have set it so that, if the output of the PID routine is negative, it sets the HPWM output to 0 (fan off) since I can't go negative.
Question 1: Why is the PID output clamp 511 in the original, when the PWM can only go to 255? Or am I missing something? When I set my simulation up so that it would drive to 100%, it was sending 511 - so I have set the PID output clamp to 255.
Question 2: Since I am dealing with charcoal here, its not a terribly fast heat source, I'm thinking that I should check the temperature every 5 seconds and only update the integral every minute or so (12 passes). Anyone have any thoughts on this?
Thanks Henrik for this WONDERFUL routine!
-
Re: PID-filter routine (2nd try).
Hi,
1) That is indeed an issue with the example code which went unobserved for a very long time, someone noticed it and mentioned it a couple of posts back in the thread. Unfortunately the forum doesn't allow me to fix it in the original post. Anyway, you are 100% right, if you're using the HPWM command then you should set the output clamp to 255. With that said the standard CCP module creating the PWM output can provide resolution of up to 10bits depending on frequency, you just can't "access" it using the HPWM command.
2) Sounds like a good start. Getting the tuning values right can be tricky, especially so on slow systems since it takes so damn long to see if you got it right or not. I expect this particular "plant" to be extra tricky due to the somewhat unrepeatable/unpredictable "performance" of a charcoal bed - I imagine.
One thing you might consider is to run the heater/fan/furnace whatever "open loop" until the temperature starts to approach the setpoint and only then switch on the PID. A more elegant but also a bit more complicated way is to create a ramping action in a way that the setpoint, instead of being bumped from ambient to "working temp" is ramped up at a rate that the "plant" can actually follow.
If you're concerned that a dutycycle of 0% won't provide enough oxygen to keep the fire alive then simply don't allow it to go below a certain value to keep the fan running at all times.
/Henrik.
-
Re: PID-filter routine (2nd try).
Quote:
Originally Posted by
HenrikOlsson
Hi,
One thing you might consider is to run the heater/fan/furnace whatever "open loop" until the temperature starts to approach the setpoint and only then switch on the PID. A more elegant but also a bit more complicated way is to create a ramping action in a way that the setpoint, instead of being bumped from ambient to "working temp" is ramped up at a rate that the "plant" can actually follow.
I had actually planned to run the fan in manual mode until I am near the setpoint, then allow the PID loop to take over in auto mode.
The other question I had is on the reset. In the example, it is set to .5. What causes the integral ramp to get steeper? Would that be an increase in the number? What kind of range of numbers are you expecting on the reset .1 to 1 or even higher than that?
BTW, while running it in simulation last night, I discovered that a derivative of 0 causes unpredictable results - to remove the derivative, you have to set it to 1.
In my reading and conversations with people who deal with PID (one of which was an instructor at a local community college) I am told that temperature control only requires process and integral, not derivative.
Thanks again,
Andy
-
Re: PID-filter routine (2nd try).
If anyone is interested, here is what I used to run the simulation (my controller has an LCD)
Code:
#CONFIG
__config _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_OFF & _LVP_OFF & _CP_OFF
#ENDCONFIG
DEFINE OSC 8 'LETS PBP KNOW THE OSCILLATOR IS RUNNING AT 8MHz
DEFINE NO_CLEARWDT 1 'NO WATCHDOG TIMER - FOR NOW - WILL DO OUR OWN CLRWDT
OSCCON = %01110001 '8 MHz INTERNAL OSCILLATOR, INTERNAL OSCILLATOR IS USED FOR SYSTEM CLOCK
DISABLE 'NO PBP INTERRUPTS NO PBP DEBUG
' Set LCD Data port
DEFINE LCD_DREG PORTB
' Set starting Data bit (0 or 4) if 4-bit bus
DEFINE LCD_DBIT 0
' Set LCD Register Select port
DEFINE LCD_RSREG PORTB
' Set LCD Register Select bit
DEFINE LCD_RSBIT 4
' Set LCD Enable port
DEFINE LCD_EREG PORTB
' Set LCD Enable bit
DEFINE LCD_EBIT 5
' Set LCD bus size (4 or 8 bits)
DEFINE LCD_BITS 4
' Set number of lines on LCD
DEFINE LCD_LINES 2
' Set command delay time in us
DEFINE LCD_COMMANDUS 1500
' Set data delay time in us
DEFINE LCD_DATAUS 44
'// Set up hardware registers, ADC etc here (not shown) //
ADValue VAR WORD '<---This is your variable.
SetPoint VAR WORD '<---This is your variable.
COUNTER VAR BYTE
RUN_IND VAR BYTE
INCLUDE "incPID.pbp" 'Include the PID routine.
'These variables are declared by the incPID routine but
'the user needs to assign values to them.
pid_Kp = $0700 'Set Kp to 7.0 GAIN
pid_Ki = $0080 'Set Ki to 0.5 RESET
pid_Kd = $0001 'Set Kd to 0 (Derivative not necessary)
pid_Ti = 8 'Update I-term every 8th call to PID
pid_I_Clamp = 100 'Clamp I-term to max ±100
pid_Out_Clamp = 255 'Clamp the final output to 0 to 255
Setpoint = 230 '<---Set desired position.
RUN_IND = 1
START:
FOR ADVALUE = 225 TO 235 'TEST A BUNCH OF VALUES
FOR COUNTER = 1 TO 10
pid_Error = Setpoint - ADValue 'Calculate the error
Gosub PID 'Result returned in pid_Drive
if pid_Out.15 then pid_out = 0 'IF NEGATIVE THEN SHUT OFF FAN
pid_Out = ABS pid_Out 'Convert from two's comp. to absolute
' HPWM 1, pid_Out, 10000 'Set PWM output
LCDOUT $FE, 1, "AD=", DEC ADVALUE, " PO=", SDEC PID_OUT
LCDOUT $FE, $C0, "RUN #", DEC COUNTER, " SETP ", DEC SETPOINT
Pause 1000 'Wait....
NEXT COUNTER
NEXT ADVALUE
IF RUN_IND = 1 THEN
RUN_IND = 0
GOTO START 'DO IT AGAIN SO THAT ITS AS IF THE TEMPERATURE DROPPED
ENDIF
LCDOUT $FE, 1, "DONE!"
DO
LOOP 'ENDLESS LOOP
END
-
Re: PID-filter routine (2nd try).
Hi,
I'm sure you're correct that you don't need derivative. I'm surprised though that you get unpredictable results when you set it to zero, I'll have to look into that. What exactly is it doing?
Anyway setting it to 1 is pretty close to 0 (1/256 to be precise.) So it shouldn't have any effect on the actual control loop in your case.
The PID_Ki isn't the "reset time" (at least I don't think it's comparable to that), it's the integral gain. To get more integral action (steeper ramp) you increase the gain.
Here's how it works, basically:
Each time you GOSUB PID the integral term takes the error and adds it to an accumulator. It then increments a counter and compares the counter value to PID_Ti, if the counter value is less than PID_Ti it's done. If the counter is equal to PID_Ti it takes the (value in the accumulator) * (integral gain/256) / PID_Ti, it then adds the result to the output and resets the accumulator as to not overflow it. I think you can compare the PID_Ti value to what's sometimes called "reset time". (It does a couple of other things as well but lets not go into that right now).
As to a range of values for the integral gain..... all I can say really is that it's usually a lot less than the proportional gain, which in turn is usually a lot less than the derivative gain (which you don't use here).
Hope it helps.
/Henrik.
-
Re: PID-filter routine (2nd try).
Quote:
Originally Posted by
HenrikOlsson
Hi,
I'm sure you're correct that you don't need derivative. I'm surprised though that you get unpredictable results when you set it to zero, I'll have to look into that. What exactly is it doing?
All this was observed using the code I posted above.
With the derivative set to one, and the loop at 216 (degrees) it usually starts with an output to the PWM of 150 or so. As the sample gets closer to the setpoint (230) it ramps down - as it should.
With derivative set to 0, the PWM starts at about 20, and goes down from there - I can't remember exactly where, but at some point (long before its at the setpoint) its at ZERO - with a charcoal fire, that means its never getting to the setpoint. Strangely enough, on the SECOND run through the numbers, it starts working properly - not sure why. Maybe its my fault.
It seems to work great with the derivative set to 1, though, acts exactly as it should.
Quote:
Originally Posted by
HenrikOlsson
Hope it helps.
Very much so. Now, if only this damn snow would go away........
Thanks again,
Andy
-
Re: PID-filter routine (2nd try).
Dear Mr. Henrik,
Would you please modify your PID routine for using on the other kinds of closed loop control, such as pressure control?
I want to implement a pressure transducer as feedback sensor and drive a water-pump by using of a frequency inverter to achieve a desired pressure in pipes. And of course, to make a stable level of pressure in pipes when people use water.
Deeply appreciating in advance.
Would you please help?
Regards,
P.S. I am beginner.
-
Re: PID-filter routine (2nd try).
Hi,
I don't know how many times I've written this but here it goes again:
The PID filter doesn't know what you are trying to control/regulate and it doesn't matter, all it does is crunch numbers. These numbers can represent pressure, lightlevel, voltage, current, position, velocity, torque, temperature, humidity, pH, whatever. It's just numbers and math as far as the PID filter is concerned and it'll close a loop around "anything" you want.
With that said, PID isn't the only type of regulator and may not always be the best method but that's not the point.
/Henrik.
-
Re: PID-filter routine (2nd try).
Quote:
Originally Posted by
andymuller
...And of course, to make a stable level of pressure in pipes when people use water.
...
P.S. I am beginner.
1. If you are a beginner, this may be a difficult project.
2. On a water pipe network you have to place your sensor on the far most distant point. But given that the pipes are not 100% rigid, you understand that near your pump, pressure will be much higher than the last water outlet.
Add to that, you have to find optimal values for the P, I and D, you see that it is not as easy as a-b-c.
Ioannis
-
Re: PID-filter routine (2nd try).
Quote:
Originally Posted by
Ioannis
1. If you are a beginner, this may be a difficult project.
2. O....
.... that it is not as easy as a-b-c.
Ioannis
Hello Ioannis,
Thank you very much in advance for your quick response and of course you have put your time to reply here. I appreciate.
I am beginner in PIC's world but I know what the PID is what the ziegler-nichols method says ;) Thank you buddy for your kidding ...haaa haaaa haaaa :wink: :biggrin: I agree with you: it is not easy such as counting a-b-c.... wonderful. lol
But your second mentioned point is a good point and thinkable because as long as sensor be closer to pump, the fluctuations be more and more, logically.
Regards,
P.S. I saw your website, I wish you all the best and good luck, dude.
-
Re: PID-filter routine (2nd try).
Hello Henrik,
Thank you very much in advance for your kind response.
After I sent my post here, I searched more at topic and I found another work of you here. The version is 1.5. If it be your last version or last has been published version?
Best regards & good luck
-
Re: PID-filter routine (2nd try).
Hi Andy,
Yes, version 1.5 posted here is the latest published version.
/Henrik.
-
Re: PID-filter routine (2nd try).
Quote:
Originally Posted by
HenrikOlsson
Hi Andy,
Yes, version 1.5 ...is the latest published version.
/Henrik.
Thanks a million, dude.
Good luck
-
Re: PID-filter routine (2nd try).
I suppose this is for Henrik.
When the ADC read value reaches the Setpoint, should'n the pid_out goto zero instead of staying for ever in a, relatively low, value?
Ioannis
-
Re: PID-filter routine (2nd try).
As far as this PID code goes this is by far the most common question I've received over the years....
If you have no integral gain then yes the output should (and will) be zero when the error is (and has been) zero for at least one cycle (depending on the derivative part of the regulator).
But most of the time you're using a PID regulator because you NEED the I and D parts as well so no, the output should NOT (necessarily) go to zero just because the error does.
When the error reaches zero the total output of the regulator will be whatever the I-term has contributed. If you want/need the output to be zero when the error is then you don't want/need the I-term. Lets take the old analogy of a car in cruise control going down the road, the setpoint is 70km/h and the throttle is 15%. The the car aproaches a hill which causes it to slow down (the error increases) so the proportinal term adds "effort" to the output in order to compensat but because the hill is steep it's not enough to drive (no pun inteneded) the error to zero so little by little the I-term adds "effort" to the output which makes the car produce more power to compensate to for the steep climb.
After a short while the car is back at 70km/h despite it being in this steep hill. Now everyone one that has asked me this question expects the output of the regulator to become zero because there is no error. But what do you think happens then?
/Henrik.