PID-filter routine (2nd try). - Page 2


+ Reply to Thread
Page 2 of 4 FirstFirst 1234 LastLast
Results 41 to 80 of 132
  1. #41
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Hi Robert,
    Why do you have the position reading and PID-calculation triggered by different interrupts? You should run the PID as soon as possible after getting the current position otherwise you're working with "old" information. One timer interrupt at: Get position, get setpoint, calculate error, run PID, set PWM, other housekeeping (if necessary) - done.

    Can't say for sure... Perhaps the glitch appears when the QEI position register wraps from MaxCNT to 0 and/or from 0 to MaxCNT. There's also this thread which discusses the HPWM and how to change the dutycycle without upsetting it but IIRC you're using the power control PWM module so it doesn't apply.

    Have you solved the other issue when the setpoint is 0 and the motor overshoots?

    /Henrik.

  2. #42
    Join Date
    May 2007
    Location
    Republic Serbia
    Posts
    105

    Thumbs up Like you meen I was rewrite

    Hi Henrik,
    Yes I was today put all in one interrupt (TMR1 , 16bit and make little trick)
    Interrupt fire at 10KHZ but I have counter variable wich increment every interrupt jump and if it not 10 then servo not operate over jump servo and pwm update but when that variable mach 10 servo will operate and reset variable to zero, that meen I have 10khz interrupt with 1khz servo drive.
    After that all work almost perfect but problem is still here and maybe it is in PWM update or I don't know - simple I am near it.
    We will see soon...
    Regards
    /Robert

  3. #43
    Join Date
    Nov 2009
    Location
    Dallas, Texas, USA
    Posts
    10

    Default PID with no negative values

    I need to get a simple PID application going using a PIC, and this PID include looks to be ideal for what I need to do.

    The system I'm working with doesn't incorporate an output device that accepts a direction bit. Everything is a positive variable i.e. the setpoint value, feedback value, and the output to the process (a value that I'll plug into a hardware PWM channel). Specifically, everything operates within the span of a WORD variable, 0-1023.

    If I'm properly interpreting how the routine works, I'll need to edit the include file to make the sign indicator passed to the include, currently B.0, a bit variable, and then do a sign determination in the main calling program to indicate if the error signal that I pass to the PID sub is below or above the setpoint.

    Likewise, I'll need to take the output of the PID include that gets passed back to the main process, and add/subtract the new output with the last output based on the direction bit, currently B.15.

    OR

    Can I simply make the direction variable passed to the PID a constant 1, and ignore the sign information returned from the routine?

    OR

    Do I have this all wrong?

    Thanks in advance for the help!

    Mike

  4. #44
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Hi Mike,
    There should be no need to edit the include file for this, I don't think.

    All you need to do is calculate the error and send it to the PID-filter, it determines if the error is positive or negative, calculates the "drive" and returns it in the variable PID_Out. You never need to pass any "direction-bit" TO the PID-routine.

    Now, if you're driving something like a heater where you can only deliver power in "one direction" (you can just add more or less heat, you can't remove it) then you simply look at the sign-bit of the PID_Out variable (PID_Out.15) and if it's set (meaning negative "drive" becuse the temperature is too high) you simply set the output to 0.

    OR (and this is probably a better aproach)

    Let's say you know that under normal conditions you need a duty cycle of ~30% to keep the temperature fairly constant. Now you look at the sign of the value in the PID_Out variable and depending on its state you either add or subtract the ABS value of PID_Out from whatever value corresponds to 30% duty cycle. Here you need to make sure you clamp the end value between 0 and 1023 before moving it to the duty cycle register.

    Does this make sense?

    /Henrik.

  5. #45
    Join Date
    Nov 2009
    Location
    Dallas, Texas, USA
    Posts
    10

    Default

    Thanks for the reply.

    Yes, makes sense to me. The process does accept a variable input, not on-off. It's a DC drive that I'm generating a reference voltage for using hardware PWM on a 18F2320 @ 40MHz. Sounds like this should work out fine.

    Once again, thanks!

    Mike

  6. #46
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Yes, what I meant with set the output to 0 was that if the ouput of the PID filter goes negative you "clamp" the dutycycle at 0 since you can't effectively have a negative drive with that system.

    In any case the second aproach should work better. Just a note though, in your first message you wrote:
    Likewise, I'll need to take the output of the PID include that gets passed back to the main process, and add/subtract the new output with the last output based on the direction bit, currently B.15.
    You don't add/subtract the PID filter output from the last output, you add/subtract it from the initial "steady state value". I guess you had that figured out but just in case.

    Let me know how it goes or if there's anything I can do.

    /Henrik.

  7. #47
    Join Date
    Nov 2009
    Location
    Dallas, Texas, USA
    Posts
    10

    Default

    The routine works like a champ!

    Did the first trial run-up today. No problem at all with mono-polar operation. A few tweaks on the constants and it's working great. Need to make a small hardware change in external circuitry, and it'll be wound up.

    Again, thanks! A very handy tool to hang onto.

  8. #48
    Join Date
    Nov 2009
    Location
    Dallas, Texas, USA
    Posts
    10

    Default

    A word of advise to anyone who needs to do PID control with a PIC, and is thinking of using this subroutine but is concerned about how well it works, you needn't worry. I used it to implement a fairly tough industrial application, and it worked like a champ. Highly recommended!

    Mike

  9. #49
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Thanks a bunch Mike, it's always nice to hear when things works out!

    If you don't mind (and are allowed) to disclose some details about the system I'd love to hear about it. Like what it is you're controlling, sensor, sampling rate, how you tuned it etc. I think it would make a nice post for future (and current) users of the PID-routine.

    I've been considering an update of the routine for quite some time, you gave me the motivation to move forward with it. I just need to get my PBP260 working on my main PC here (looks like an OS re-install is needed and I hate doing that). I'll try adding feed-forward and a few other things, mostly tailored towards motor-control although probably useful in other applications as well.

    Thanks again Mike!
    /Henrik.

  10. #50
    Join Date
    Nov 2009
    Location
    Dallas, Texas, USA
    Posts
    10

    Default

    The application was a rewind control on a rather elderly commercial printing press.

    The original setup was a commercial PID board made up of *many* op amps. At its best it was cranky acting when it was working well, and it had been going flaky for some time. When it finally failed, and I determined that it had chips on it that I had no idea how to get and that the OEM had discontinued the board long ago, I decided to replace it with a digital implementation.

    The system consists of a 50HP speed regulator DC drive and a control board that accepted an input from a pot set by the machine operator that determined the desired dancer position (check out Wiki or the like if you're not up on compressed air loaded printing press dancer rewind setups). A gear driven pot provided feedback from the dancer, indicating its position.

    The drive required a 0-15VDC reference signal. I built up a board consisting of a +18 and +5 supply. +5 supply was run out to the operator and dancer pots. Those two signals became setpoint and feedback, respectively, and were dumped directly into PIC A/D pins. Half of a LM358 op amp fed by a simple RC filter took the PIC PWM output, smoothed it, and raised it to 0-15VDC.

    My calling app sets the reference voltage to the drive to zero should the PID routine ever call for a negative, but that's probably superfluous.

    Took less than an hour to set up the P, I & D constants to achieve better dancer control than the original had *ever* provided.

    I have no doubt that the identical hardware, with no changes other than retuning in software, could do a perfectly acceptable job in any web material rewinding application. And speed regulator drives are simpler to set up, less expensive, and more readily available than the torque regulator drives that I've used in similar applications in the past.

    Again, thanks for your help and use of a very handy routine!

    Mike

  11. #51
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Thanks Mike!
    A 50HP DC drive...that's cool!

    /Henrik.

  12. #52
    Join Date
    Dec 2009
    Location
    Kalamazoo
    Posts
    42

    Default pid routine for h-bridge

    first of all, a big thanks to mr henrik for this wonderful code. it works, as i have it all set up right here.
    but instead of locked antiphase, im trying to implement a h-bridge powered by the two hpwm (forward/reverse motion)on a 18f4431.
    i have a lcd displaying variables like position, setpoint, dutycycle1(for hpwm0) and dutycycle2(hpwm1)

    Main: ; main loop

    LCDOUT $FE, $80, "POS=" ,DEC5 POSITION, " SP=" ,DEC5 SETPOINT
    LCDOUT $FE, $C0, "DUTY1=" ,DEC3 DUTY1, " DUTY2=" ,DEC3 DUTY2
    IF PORTB.3 = 0 then SETPOINT = SETPOINT + 1 ; Increment setpoint
    select case setpoint ; Circular count for Setpoint condition
    case is > 65535 ; Circular count for Setpoint condition
    setpoint = 0 ; reset setpoint
    POSCNTH=0 ; set counter for encoder, H bit ; reset QEI counter high byte
    POSCNTL=0 ; set counter for encoder, L bit ; reset QEI counter low byte
    end select
    ;SELECT CASE PID_ERROR
    IF POSITION<SETPOINT THEN ; End of Circular count for Setpoint condition
    pid_Error = setpoint - position
    ;GOSUB FORWARD
    ENDIF
    IF POSITION>SETPOINT THEN
    PID_ERROR = POSITION - SETPOINT
    endif

    gosub pid ; go to PID rutine
    DIRECTION = PID_OUT.15
    select case direction ; condition determine PWM
    case 0 ; condition determine PWM
    Duty1 = abs pid_out
    GOSUB FORWARD
    ;DUTY1 = 0 ; condition determine PWM
    case 1 ; condition determine PWM
    Duty2 = ABS pid_Out
    GOSUB BACKWARD
    ;DUTY2 = 0
    END SELECT

    goto Main ; do main loop

    sub forward turns on first hpwm and sub backward turns on second hpwm.

    here is the problem: if i increment/add to the setpoint, both duty cycles reset when position rolls over from 65535 to 0. i know its something to do with my integer math, and ive spent a whole week on this issue. im trying to implement a step/dir routine, for my cnc machine.

    any suggestion will be highly appreciated. thanks
    NAG CON WIFE!
    WIFE VAR MOOD

  13. #53
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Hi,
    I'm not sure I understand....sorry....

    First of all, the SETPOINT variable you have - is it declared as a LONG or as a WORD? If declared as a WORD then I'm not sure how this...
    Code:
    select case setpoint ; Circular count for Setpoint condition
    case is > 65535 ; Circular count for Setpoint condition
    ...will work or what it'll evalute to. A word variable will "automatically" wrap around from 65535->0 and from 0 to 65535. If setpoint is declared as a LONG that seems not needed since you're trying to reset it 0 once it goes above 2^16.

    Then there's this line:
    Code:
    IF POSITION pid_Error = setpoint - position
    Does it really compile like that?

    If you have code that compiles correctly, please post it and I promise I'll do my best to help you. You may also be interested in this thread

    /Henrik.

  14. #54
    Join Date
    Dec 2009
    Location
    Kalamazoo
    Posts
    42

    Default

    thanks for the quick reply

    the setpoint is a word variable, and resets itself from 65535 to 0 and vice versa.
    there must have been an error when i copied and pasted, because the sentence reads:

    pid_error = setpoint - position

    this is a very buggy piece of code, and when i get it working, im going to rearrange and clean it up good.
    NAG CON WIFE!
    WIFE VAR MOOD

  15. #55
    Join Date
    Aug 2009
    Posts
    7

    Default Motor speed control

    Hi to all.
    Come back after so many time.
    I run dc motor and use same code made no change.
    It controls the speed fine but i found that there is always a difference between reference signal and feedback signal.Due to this motor speed increase enough when we increase proportional gain.
    Is this is a problem or not ?

  16. #56
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Hello,
    If you really are controlling the speed of the motor and not the position then there shouldn't need to be any difference, if the speed never reaches the setpoint you need to increase the I-gain. That should make it come closer.

    If you use the "moving target" aproach, ie. you are in reallity controlling position then, as long as the motor is moving, there will always be a discrepency between the target and actual position, called following error. The speed however, should match the command , otherwise the following error would just grow larger and larger.

    /Henrik.

  17. #57
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default New version of incPID available.

    Hi,
    First, bugfix....
    I've discovered a bug/problem with the original incPID routine. When there's a persistant error present at the filter input the integrator for the I-term is supposed to accumulate and over time produce an output that will drive the error away. However, a small error in conjunction with low I-gain may actually never accumulate enough to produce an output signal like it's supposed to. This was due to truncation of the numbers during calculations. This version implements a fix for this issue.

    Be careful if you move from the previous version to this as the I-term may behave quite differently depending on how your particular application is set up. I've tested it here and it seems to work but please let me know if you find any problems.

    Second, new feature...Feed-forward
    While a PID filter by itself works on the difference between the "setpoint" and the "target" feed-forward works directly on the command signal. Let's say you're controling the speed of a motor, the friction in the bearings, brushes and in the load the motor is driving causes it to need a certain "baseline" amount of power for any given speed in order to compensate for its mechanical and electrical losses. Feedforward can provide this "baseline" which helps the actual filter and can increase the overall system response.

    There are three new "external" variables that you need to use with feed-forward:
    pid_Vel_Kff This is the velocity feedforward gain.
    pid_Acc_Kff This is the acceleration feedforward gain
    pid_Velocity_cmd This is the actual command signal.

    As motor control is my personal use for the incPID routine I've used the terms velocity and acceleration but it's applicable to whatever you are controling. Lets take an example where we want to control the temperature in an oven.
    By imperical testing you have determined that in order to maintain your desired temperature (lets say 150 degrees) under normal/optimal/stable conditions you need an "output" of 800 to your "powerstage". If you set pid_Vel_Kff to $0600 and pid_Vel_cmd to 150, this will result in a "baseline" output of 800. Then you calculate the difference between the setpoint (150) and the current temperature and send it to filter in pid_Error. The output from the actual PID-filter then gets added to or subtracted from that 800 number in order to compensate for any disturbances that occurs.

    The acceleration feedforward works in the same way as the derivative term of the PID filter but instead of acting on the derivative (ie. the difference) of pid_error it acts on the derivative of pid_Vel_cmd.

    More info is available in the file itself.

    I've tested this quite a bit but as always I'm sure there are things I've overlooked. If you have problems, please post in the thread and we'll try to work it out. If you don't have problems and it just works that's always nice to hear as well ;-)

    Sincerely,
    /Henrik.

    (Change file extension from .txt to .pbp and place it in your project folder or in the PBP installation folder).
    Attached Files Attached Files
    Last edited by HenrikOlsson; - 8th May 2010 at 18:03.

  18. #58
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default Example of what can be done with incPID.

    Hi,
    For anyone interested in motor control, here's a link to a Youtube video showing my latest project based on the PID code available in this thread. It's HP-UHU servo drive on which I've replaced the original UHU servo processor with my own "servo module" that I've made pin-compatible with the original chip.



    <object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/U-jrxK7u_34&hl=en_US&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/U-jrxK7u_34&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object>

    /Henrik.
    Last edited by ScaleRobotics; - 6th June 2010 at 17:12. Reason: embed video

  19. #59
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530

    Default Hp-uhu ?

    Henrik,

    You have done excellent work! I tried to look up the HP-UHU servo drive you used, but all I seemed to get was this link: http://www.cnczone.com/forums/showthread.php?t=67453. Is there more information on the servo drive you used somewhere else?

    Thanks,

    Walter

  20. #60
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Thanks Walter,
    That's its biggest drawback I'd say - the information about it being scattered around several threads on the CNCZone, there are some links in that thread you posted that will take you to other threads about it. There's also some info in this Wiki

    As you probably figured it's not a comercial drive, it was developed by a CNCZone member called Kreutz in effort to get a DIY drive for high(ish) voltage motors where the original UHU-circuit failed to deliver. Kits were made (and probably IS) available by Paul Harshman (tenmetalman) and Irfan Ulla, also on CNCZone at very reasonable prices.

    Being involved since the early stages of the HP-UHU's life I know it pretty well so if you have specific questions regarding it fire away and I'll do my best to answer them. Perhaps it's better to keep it separate from this thread though.

    Thanks!
    /Henrik.

    EDIT: Thank you for embedding the video by the way!
    Last edited by HenrikOlsson; - 6th June 2010 at 18:04.

  21. #61
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,128

    Default My first try on PID...

    Here is my first try on PID control. Obviously failed...

    At the attached schematic is the part of the circuit, essentialy a Voltage stabilizer. The PWM from the PIC drives the Power stage while from the output a voltage sample is returned to the ADC.

    Unfortunately there is no control at all. When Setpoint is 0 or 1023 the output is always high (pid_out is 511).

    Also I noticed that Direction bit is high when Voltage sample is higher than Setpoint. Is this correct?

    Test PIC is F887 driving the internal HPWM.

    Code:
    '**************************************************************************
    '**************************************************************************
    '**		
    '**		PWM Controller with voltage level feedback
    '**
    '**     21.11.2010, v.1.0
    '**
    '**     PID Control by Henrik Olsson
    '**************************************************************************
    '**************************************************************************
    
    DEFINE OSC 8
    
    OSCCON = %01110001 'SET SYSTEM CLOCK SWITCH BIT
    
    ;----- Configuration bits ------------------------------------------------
    
    @Line1 = _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_ON
    @Line2 = _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_ON & _INTRC_OSC_NOCLKOUT
    
    @ __CONFIG _CONFIG1, Line1 & Line2
    
    @ __CONFIG _CONFIG2, _WRT_HALF & _BOR40V
    
                	
    PORTA=0:PORTB=0:PORTC=0:PORTD=0:PORTE=0
    
    TRISA=%00101101
    TRISB=%00000000
    TRISC=%10000000
    TRISD=%00000011
    TRISE=%00000000
    
    OPTION_REG.0=1		'PSA0 PRESCALER SELECT 1:1 TO 1:256
    OPTION_REG.1=1		'PSA1
    OPTION_REG.2=1		'PSA2
    OPTION_REG.3=0		'PRESCALER TO: 1->WDT, 0->TMR0
    OPTION_REG.4=0		'T0SE SOURCE EDGE 1->H TO L, 0->L TO H
    OPTION_REG.5=0		'T0CS 1->FROM RA4, 0->FROM INT. CLOCK
    OPTION_REG.6=0		'INT EDGE SELECT 0->H TO L, 1->L TO H
    OPTION_REG.7=0		'PULL UP 1->DISABLE, 0->ENABLE
    
    WPUB = %00111111
    
    'DEFINE HSER_RCSTA 90h
    'DEFINE HSER_TXSTA 24h
    'DEFINE HSER_BAUD 19200
    'DEFINE HSER_CLROERR 1 ' Clear overflow automatically
    
    '************************* Define LCD parameters
    
    ADCON0 = %11000001
    ADCON1 = %10000000	'Set PORTA/E analog/digital, right justify result
    ANSEL  = %00101101  'lower port A as Analog input
    ANSELH = %00000000  'all others Digital inputs
    
    DEFINE ADC_BITS 10  'Number of bits in Adcin result
    DEFINE ADC_CLOCK 3  'ADC clock source (rc = 3)
    DEFINE ADC_SAMPLEUS 50
                         
    but_0           var portd.0
    but_1           var portd.1
    
    
    '**************************************************************************
    '****
    '****                            Initialization
    '****
    '**************************************************************************
    clear
    
    ADValue VAR WORD                     '<---This is your variable.
    Setpoint VAR WORD                    '<---This is your variable.
    Direction var PortB.7                '<---Direction bit to motor driver 
    
    p_gain      var word
    i_gain      var word
    d_gain      var word
    
    Setpoint=200
    
    INCLUDE "incPIDv1.5.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
    '    pid_Ki = $0080                     'Set Ki to 0.5
    '    pid_Kd = $0225                     'Set Kd to 2.14
        pid_Ti = 8                         'Update I-term every 8th call to PID
        pid_I_Clamp = 100                  'Clamp I-term to max 100
        pid_Out_Clamp = 511                'Clamp the final output to 511
         
      Start:
        Gosub analog                        'Get speed from tacho and setpoint pot - NOT SHOWN HERE.
        
        pid_Kp=p_gain:pid_Ki=i_gain:pid_Kd=d_gain
                                         
        pid_Error = Setpoint - value     'Calculate the error
    
        Gosub PID                          'Result returned in pid_Drive
    
        Direction = pid_Out.15             'Set direction pin accordning to sign
        pid_Out = ABS pid_Out              'Convert from two's comp. to absolute
        HPWM 1, pid_Out, 500             'Set PWM output
        
        'Just for monitoring
        serout2 portc.6,16468, [27,"[10;0H","P:",dec5 p_gain,"  I:",dec5 i_gain,"  D:",dec5 d_gain,"  PID out:",#pid_out,"    ",27,"[12;0H","Vout:",dec5 value,"  SP:",dec5 setPoint,"  pid_err:",dec5 pid_error, 27,"[14;0H","Direction: ",#direction]
    
    Goto Start                           '...and do it again.
    
    analog:
        adcin 0,value
        gosub average
        adcin 2,p_gain
        p_gain=p_gain<<2
        adcin 3,i_gain
        i_gain=i_gain>>2
        adcin 4,d_gain
        d_gain=d_gain<<2
        
        'Two digital inputs for setting Setpoint level
        if !but_0 then
            if Setpoint>0 then
                setpoint=setpoint-2
            endif
        endif
        if !but_1 then
            if Setpoint<1021 then
                setpoint=setpoint+2
            endif
        endif 
    return
    
    END
    I am using 3 Analog inputs to set the P,I,D values as it is clear from the analog subroutine.

    Whatever the values the pid_out stays at 511 and plays a litle at the point where Setpoint is almost equal to the Vout level.
    Any inputs welcome.

    Ioannis
    Attached Images Attached Images  
    Last edited by Ioannis; - 28th December 2010 at 22:34.

  22. #62
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959

    Default

    Ioannis,

    I think you need to limit the pid_Out values to only positive numbers, and discard the negative values instead of converting them to positive ones.

    The way you have it ... the more it tries to reduce the voltage, the higher the output goes.

    After it gosubs to the PID routine ... Try this ...
    Code:
        IF pid_Out.15 THEN pid_Out = 0   ' limit to positive values
        HPWM 1, pid_Out, 500             'Set PWM output
    DT

  23. #63
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Hi Ioannis,
    I'll just second what Darrel said. For unidirectional control, ie when you can only apply more or less power, not remove power from your "plant" you can't have the output swing negative (which the ABS convert to positive again).

    The example was for controlling a motor where the direction signal basically controls the polarity and the applied torque is controlled by a PWM signal corresponding to the absolute value of the PID signal. That way torque can be applied in both directions.

    In your case you can only apply more or less power, you can't 'reverse' or remove 'power'. Because of that you can't allow negative 'drive'.

    As fir the polarity of the direction bit, that's just a matter of matching it to the hardware I used at the time. If I reversed the polarity of the motor I'd have to reverse the "polarity" of the direction signal. Again, you don't need it in this application.

    /Henrik.

  24. #64
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,128

    Default

    Ok, thanks both. I was stupid.

    Now, I 've got a wonderful oscillator!

    No matter the level of P,I,D (except for 0) it does oscillate.

    I suppose it is a matter of tuning, but even with the trimmer as analog inputs to the P,I,D variables, it seems hard to fine tune it.

    When I think I done it, after a power cycle it start again at a rate of 2-5Hz.

    Ioannis

  25. #65
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959

    Default

    Whatever the values the pid_out stays at 511
    Oh, and clamp the output to 255 for the HPWM command.

    You may want to use 10-bit PWM for finer control.
    DT

  26. #66
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,128

    Default

    Hi Darrel.
    Yes I did clamp the output to 255 although it was not mentioned in my previous post.

    Quote Originally Posted by Darrel Taylor View Post
    You may want to use 10-bit PWM for finer control.
    Is this possible with PBP or do I have to mess directly with the PIC registers?

    My next step will be to use MiBAM, as I do not have hardware PWM on the final PIC.

    Ioannis

  27. #67
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Hi,
    Start with pid_Ki set to 0. Increase pid_Kp and "bump" the regulator (change the setpoint) do this a couple of times until you see it begin to overshoot or a tendency to oscillate.

    Increase pid_Kd in order to damp out the overshoot.

    Now you can try to increase pid_Kp even further, once again it will overshoot or start to osciallate, follow with pid_Kd.

    This should give you a stable loop but it will most likely never hit the actual setpoint. Slowly increase i pid_Ki to bring the value right up to the setpoint. Increasing pid_Ki will introduce an overshoot which you might should be able to reduce by further increasing pid_Kd.

    With that said it's crucial that you run the PID (read input, run PID, update output) at a constant interval. If the time between updates varies you won't get a stable output.

    /Henrik.

  28. #68
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,128

    Default

    Thanks Henrik.

    What is the range for the p,i,d variables?

    Or is it absolutely project dependant?

    Ioannis
    Last edited by Ioannis; - 29th December 2010 at 12:52.

  29. #69
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Hi,
    They are all WORD variables so 0-65535 in theory (each representing a gain of 0-255). However, there is no protection from, or detection of, overflow in the calculations that may be the result of very high gains and very large errors.

    /Henrik.

  30. #70
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959

    Default

    Quote Originally Posted by Ioannis View Post
    (10-bit PWM)
    Is this possible with PBP or do I have to mess directly with the PIC registers?

    My next step will be to use MiBAM, as I do not have hardware PWM on the final PIC.
    You might try HPWM10 for now. It's just like HPWM ... almost.
    http://www.picbasic.co.uk/forum/show...7805#post37805

    MIBAM is only 8-bit, but if you only have one output it'll be better to create a higher resolution interrupt driven PWM that could also be a time base for the PID loop.
    DT

  31. #71
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,128

    Default

    Thanks for the tips.

    By he way, comapring the MiBAM and Multi_SPWM which is lighter? I suppose Multi_SPWM.

    On my final board, PIC will be probably the old F819, so I do not have the luxary of HPWM.

    Maybe the Interrupt driven software and PID is the ultimte solution.

    Currently I am dancing, err, oscillating...

    Ioannis

  32. #72
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Hi Ioannis,
    At what frequency are you currently running the PID-loop?

    You have a fairly large timeconstant, 0.22s if I'm not entirely mistaken. Depending on the frequency you're running the loop at this might be a source for your instability. I'd try setting up a timer interrupt to get constant and predicatble timing and try running the PID-loop at something like 5Hz.

    The variables pid_P, pid_I and pid_D contains the "effort" each term contributes to the total output with. Those might be interesting to "watch" as you tune the loop.

    Also, you might gain quite a lot by using the velocity feed forward. For example, you can't possible get 12V output without feeding the circuit atleast a 50% dutycycle (provided the load doesn't regenerate etc). The velocity feedforward can help you provide this "baseline" output.

    If I'm not mistaken you would, for an output of 12V, get a return value from the ADC of ~430 and therefor the setpoint value for a 12V output is 430. To set the velocity feedforward so that it outputs a 50% dutycycle for a setpoint of 430 you set pid_Vel_kFF to 74(dec) because 128/430=0.29 (128 being the value for 50% dutycycle) and 74/256 = 0.29 (because the gain is expressed in 1/256 units).

    Finally you must also set the pid_Velocity_cmd variable to equal your setpoint value whenever you change it.

    Now the PID regulator only has to worry about "external disturbances" such as power supply voltage variation, load variation and so on.

    /Henrik.

  33. #73
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,128

    Default

    Hi Henrik.

    Hmm, I do not have a time base for the PID. It is in the close loop of the main. Sure is not predictable rate.

    Also I noticed that using a 470uF capacitor in the place of the 10uF help a lot, so your point of using a slow like 5Hz rate is a good one.

    I did not used the Velocity so far, it is a good poin also. Will try it an report.

    Thanks both for the help.

    Ioannis

  34. #74
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Hi,
    The very first thing to tend to, IMHO, is to make the update rate as stable as possible - it is very important for stability. If you haven't already seen it, here's a pretty good article on digital PID filter implementation. It's a good read even if you're not actually writing the PID filter code - just using it.

    Keep at it and keep us posted!

  35. #75
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,128

    Default

    I recall downloading that article, but did not read it. Will do.

    My pre-PID implementation was based on a loose control loop like this one:

    Code:
    if out_value < (setpoint - 1) then
        pwm_signal=pwm_signal+1
    endif
    
    if out_value > (setpoint + 1) then
        pwm_signal=pwm_signal-1
    endif
    It is a very simple idea that gives also a hysteresis of +/-2 points. So if the out_value is within the "dead band" nothing happens.

    The down side is that, depending on the overall loop it may take too long to reach the setpoint and also may do some oscillations also if there is delay getting the correct analog feedback.

    My first impressions using the PID is that has the potential to be very fast and accurate, despite the fact I did not managed to make it work reliable yet.

    Will come back after correcting the setup.

    Ioannis
    Last edited by Ioannis; - 30th December 2010 at 21:48.

  36. #76
    Join Date
    Oct 2005
    Location
    Stuttgart, Germany
    Posts
    24

    Default

    First of all, i would like to thank Mr. Olsson for his great work.
    Currently i'm working with the AC heater, driven by the SSR. This heater is very inertial and slow, in particular dropping the temperature.

    In order to drive it, i implemented some sort of rude PWM, which looks as following:

    ---------------------------------------------------------
    pid_Out_Clamp=200
    ' i also set the pid_Out value to 0 in case of direction flag is raised (pid_Sign = pid_Out.15 thing)

    loop:
    period=2000 'period of PWM in mS
    time_on=pid_Out*10 ' i feed to pid filter the temperature, not the ADC value, therefore multiplication in order to scale to the period. Or this is wrong and i should use pid_Out value directly?'
    HIGH portc.3
    PAUSE time_on
    time_off=period-time_on
    LOW portc.3
    PAUSE time_off
    LCDOUT ...
    GOTO loop
    -----------------------------------------------------------------

    Now, i have run a test and the filter seems to work, except it gives an overshoot on the beginning, but then stabilises 1-2 degrees below target.
    Now i would have to tune the gains and i tried to understand the explanation of the HEX format, but unfortunately it is not completely clear for me. Are you using this representation in order to have floating point values?

    I just can't get the inverse conversion algoritm from, let's say, 2.55 to HEX.
    As i undersand, in this case it would be $02..<-- here should come 0.55 part.
    So, using your example: "FF represents 1/256*255 or 0.996. If you'd feed it 102 from the ADConverter it would be the same as $0066 or a gain of 0.258."

    1/256*x=0.55 --> x=0.55/(1/256) -->140 --> convert to HEX -->8C
    Final result: $028C, or decimal 652 <--- is it correct??

  37. #77
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Hi,
    The gains are just numerical values like any other variable. Assigning values to the gain variables using hex doesn't, in itself, allow "floating point" but it makes it easier to visualise what the "real" gain is. Or perhaps not... ;-)

    Lets look at the proportional term:

    Lets say you set pid_Kp to $0280 (or 640 in decimal if you like). Now you calculate pid_Error to, lets say, 125 and send it to the filter. The filter will then calculate the proportional term to 125 */ 640 which is the same as 125*640/256=312. Or, put another way 640/256=2.5 and 125*2.5=312.

    If you set pid_kP to 102 (or $66) you'll get a gain 102/256=0.398 and an output, in the example above of 125*102/256=49 which is basically the same as 125*0.398.

    If you know you want a gain of 3.7 then simply multiply that value by 256 to get the value. 3.7*256=947. pid_Kp=947 or pid_Kp=$03B3. Where, in this case $03 means 3 and $B3 means $B3/$FF or 179/256=0.7 ie a gain of 3.7

    With the same error as above: 125*947/256=462 which is the same as 125*3.7=462.

    So, using HEX doesn't make it floating point per se, it's just another way of assigning values to the variables. Say you wanted a gain of 4, then pid_kP=$0400 is easier to understand then pid_Kp=1024 but they both result in the exact same thing.

    /Henrik.
    Last edited by HenrikOlsson; - 25th January 2011 at 17:11.

  38. #78
    Join Date
    Oct 2005
    Location
    Stuttgart, Germany
    Posts
    24

    Default

    Thanks for the prompt reply! Well, now it is clear for me, that it is clear for you
    And i also got now how it works. But for myself, i would use DEC values, they are much obvious, IMHO of course.

    But i do have one more question: what would be a good point to start with pid_I_Clamp?

    In your example code you had for pid_Out_Clamp 511 and pid_I_Clamp 100.
    If i have pid_Out_Clamp 200, would, say, 40 be a good starting point for pid_I_Clamp?
    Also for the sampling frequency you have ser every eight's, don't you think is to high in my case, with the period of 2 seconds?
    I ask it, because i just want to realy reduce the possible variables to Kp,d,i, before i start tuning them.

  39. #79
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,373

    Default

    Hi,
    Sure, use decimal if it makes more sense to you!

    Try with pid_I_Clamp at 40 or even lower to begin with. If you then get to a point where the temperature never reaches the setpoint you need to look into if it is because the I-term is saturating or you just need to increase the I-gain.

    As for the integrator sampling time I'd try setting that to roughly correspond to the settling time of whatever it is you're controlling. Ie. if run the system "open loop" and have a stable temperature and then increase the PWM dutycycle a couple of steps, how long does it take before the temperature settles at the new temperature? Set the integrator "sample divisor" so that the actual time roughly corresponds to the settling time.

    /Henrik.

  40. #80
    Join Date
    Mar 2009
    Posts
    653

    Default Re: PID-filter routine (2nd try).

    Cool Henrik, I think I may have a use for this

    Ok, this is a whole new area to me, here's what I think I've grasped wrt how this works ....

    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?!!

    Ok, what to do with pid_out?

    For my intended use, I want to control a 256 step digital SPI pot (which alters the magnitude of an analog signal - an AGC in essence)...I have a 'desired value' ADC sample (a simple 8 bit ADC sample of the wiper from a std analogue pot ittingt between VCC & Gnd) that I want the signal to 'hit', but obviously the digital pot needs to either increment or decrement towards getting the signal to meet the desired value - 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?

    What do I need to tweak with this bit...

    Code:
    Main_Loop:
        gosub adc
        pid_Error = Setpoint - ADValue      'Calculate the error
        Gosub PID                          'Result returned in pid_Drive
        Direction = pid_Out.15             'Set direction pin accordning to sign
        pid_Out = ABS pid_Out              'Convert from two's comp. to absolute
    how to control the  digital pot here?!!!
        Pause 10                           'Wait....
        Goto Main_Loop                  '...and do it again.
    I’m controlling my digital pot like thus…
    Code:
    write_VR1:    
        LOW CS    
        SSPBUF = VR1_Select   'put the command byte into SSPBUF
        gosub letclear
        SSPBUF = VR1_Position   'put the data byte into SSPBUF
        gosub letclear
        high CS
        RETURN
        
        letclear:  
        IF PIR1.3 = 0 Then letclear  ' wait for SPI interupt flag  
        PauseUs 10         ' 25uS fudge factor  
        PIR1.3 = 0        ' clear buffer full status
        Return
    I’m figuring it’s just a case of something like GOSUB write_VR1 & then within there having the data byte be pid_out?

    Hand holdng warmly accepted!
    Last edited by HankMcSpank; - 7th March 2011 at 01:36.

Similar Threads

  1. Darrel's latest 16 bit averaging routine?
    By jellis00 in forum mel PIC BASIC Pro
    Replies: 9
    Last Post: - 17th October 2009, 02:57
  2. 2nd order Low-pass passive RC filter on PWM
    By munromh in forum mel PIC BASIC Pro
    Replies: 6
    Last Post: - 29th January 2009, 20:03
  3. Atod Digital Filter
    By GeoJoe in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 2nd April 2008, 18:04
  4. PID controller in 16F737
    By joeri in forum mel PIC BASIC
    Replies: 8
    Last Post: - 24th June 2006, 12:39
  5. 2nd Order Digital Filter for 24-bit
    By sefayil in forum mel PIC BASIC
    Replies: 0
    Last Post: - 2nd December 2005, 22:55

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts