incPID Routine - Help Needed


Closed Thread
Results 1 to 40 of 64

Hybrid View

  1. #1
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,624


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Ioannis,
    Not sure I understand.... it will toggle LED1 once every second which means it will blink at 0.5Hz - isn't that what I wrote?

    Barry,
    Excellent! I wouldn't check IntCount in the main routine like that. Instead I'd check IntCount in the ISR and set a flag (UpdateDisplay or whatever). The main routine then checks this flag, executes the code and resets the flag. The reason for this is that when the code grows the Main routine may "miss" the when IntCount=0 (depending on what else it has to do and how long it takes). If you instead use the flag/semaphore method the Main routine WILL see that it's time to update display - when it gets around to it.

    OK, now that you have a stable time base and the pulses counted in hardware it's time to add in the PID again. The ISR would look something like:
    Code:
    ISR:
    
        T1CON.0 = 0                         ' Stop timer
        TMR1_Temp.HighByte = TMR1H          ' Get current "time"
        TMR1_Temp.LOWBYTE = TMR1L
        TMR1_Temp = TMR1_Temp + TMR1_Reload ' Add reload value to get correct interval
        TMR1H = TMR1_Temp.HIGHBYTE          ' Move result back to timer 
        TMR1L = TMR1_Temp.LOWBYTE
        T1CON.0 = 1				' Start timer
    
        ' Get the current motor velocity
        newCount =  TMR0 - oldCount
        oldCount = TMR0
    
        ' Calculate error and run PID
        pid_Error = SetPoint - newCount
        GOSUB PID
    
        IntCount = IntCount + 1             ' Increment interrupt counter
        If IntCount = 9 THEN
            UpdateDisplay = 1
            IntCount = 0
        ENDIF
    
    @ INT_RETURN
    Your setpoint in this case is pulses per interrupt period, not actual frequency in Hz.

    And the Main routine perhaps something like:
    Code:
    UpdateDisplay VAR BIT
    Main:
       If UpdateDisplay THEN
         'LCDOUT.....
         'LCDOUT.....
       UpdateDisplay = 0
    Goto Main
    This is untested but I'm sure you'll get the idea.

    /Henrik.

  2. #2
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    4,170


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Ooops, yes Henrik. Sorry about that. Thought it was 0.5 second and not Hz as you stated.

    Ioannis

  3. #3
    Join Date
    Jan 2011
    Location
    Sydney, Australia
    Posts
    172


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    OK, now I am a little confused....
    You said that Setpoint now becomes pulses per interrupt period but how is this referenced to the ADCin result of my speed set trimpot?
    Shouldn't the setpoint always be derived from the setting of the speed set trimpot and the error be calculated from the pulses per interrupt period?

    Cheers
    Barry
    VK2XBP

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


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Yes, what I mean is that if you previously had your setpoint scaled directly in Hz it now needs to be scaled in pulses/interrupt period.

    /H.

  5. #5
    Join Date
    Jan 2011
    Location
    Sydney, Australia
    Posts
    172


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    OK. Now I understand.
    Setpoint was previously read via ACDin (0-1023).
    ADValue was scaled in pulses per 100ms (approx 0-550)

    In the new setup, variable NewCount (replacing ADValue) can range from 0-255 so I propose to convert the ADCin result from 10-bit to 8-bit
    Setpoint = Setpoint>>2
    so that the error term does not get too large and gain terms can be kept to a manageable size.

    I will let you know how things pan out after tonight's round of experimants.

    Cheers
    Barry
    VK2XBP

  6. #6
    Join Date
    Jan 2011
    Location
    Sydney, Australia
    Posts
    172


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Things have been going too well for too long. A crach and burn situation was iminent!
    Things started falling apart once I pieces everything together.

    For starters, should I be able to use the serial LCD (debug statements) on RA5 with the DT-interrupts and counters on TMR0 and TMR1?
    The LCD screen is completely garbled.

    I have modified the circuit so that the three ADCin pots for Kp, Kd and Ki terms are on AN4, AN5 and AN6 and the encoder wheel pulse train is fed to M0CKI (pin 11). Circuit diagram is attached here incPID_16F684_V6.pdf

    I am in the process of cleaning up the program (making the PID routine as an included file as per Henrik's suggestion). I will post the code soon.

    In the mean time, any comments regarding the use of the serial LCD with DT-interrupts happening in the background would be greatly appreciated.

    Cheers
    Barry
    VK2XBP

  7. #7
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,624


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Hi Barry,
    I touched this issue in a previous reply. The command you're using to communicate with the display (DEBUG) is a bit-banged command, it relies on software timing to generate the correct baudrate. When you add interrupts to the mix the interrupt code will "steal" time from the rest of the program. So if a DEBUG statement is executing when the interrupt fires the timing WILL be off.

    The usual cure to this problem is to use HSEROUT instead of DEBUG but that requires a PIC with an USART which the '684 doesn't have :-(
    The easiest thing to try is probably to split the messages to the LCD up in several pieces and send them one by one. Or even write the message to an array and use DEBUG to send one byte at the time from that array, disabling/enabling the interrupt system between each byte.

    Something like this perhaps:
    Code:
    ArrayWrite myString,[$FE,1,"P: ", #pid_Kp, " I: ", #pid_Ki", "D: ", #pid_Kd"
    
    For i = 0 to 16  'Or how many chars to send
      @ INT_DISABLE TMR1_INT
      DEBUG myString[i]
      @ INT_ENABLE TMR1_INT
    NEXT
    Now, I very rarely use DEBUG so I'm not sure it can handle arrays like this but I think it should. The "best" approach would probably be to switch to a PIC with an USART though.

    /Henrik.

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

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