incPID Routine - Help Needed


Closed Thread
Results 1 to 40 of 64

Hybrid View

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


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Hi Barry,
    Either is fine - whatever works....
    Since you're only looking for velocity and not position (right?) you could either use the motion feedback module in Velocity Mode (something I've never done myself) or use a standard timer/counter as outlined earlier.

    As for the timer interrupt... A neat feature of the PCPWM module is that you can use IT (or rather its timer) to generate an interrupt every Nth PWM cycle. That's what the PostScale setting is for. But the available post scale ratios are limited so if your PWM frequency is high and you're looking for a low(ish) interrupt frequency it might not be the best to use.

    Again, either works.

    What's the lowest speed you expect to run the motor at?

    /Henrik.

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


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Thanks for the feedback Henrik.

    The PCPWM frequency is 8kHz and I would like to be able to slow the motor down to 60rpm (1 revolution per second) if possible. This would allow me to perform threading operations on my lathe at a safe speed (the ultimate use for this project is to re-power my 9x20 lathe).

    I also need a way of determining and displaying the rotational speed. I know this is possible by manipulating the data from the counter/timer but would it be simpler to use the period measurement function (input capture mode) of the Motion Feedback Module on the 18F2431? Have you, or any of the other forum members, had any experience using the period measurement function?

    Cheers
    Barry
    VK2XBP

  3. #3


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Hello Barry,

    I am working on a similar project and following this thread.

    A while back I found this code some where maybe here? Not sure who the author is?
    It calculates RPM using the 18F4431, but not using the velocity mode. Maybe you can use some ideas
    Code:
    '--------Program Desciption--------
    
    ' Program uses Timer0 Interrupt to average motor rpm over one minute.
    ' Motor power set by potentiometer before program begins.
    ' LCD display updates time, position count and average rpm every second.
    
    '---Review PicBasic Pro Command----
    
    ' The PicBasic Pro Compiler Manual is on line at:
    ' http://www.microengineeringlabs.com/resources/index.htm#Manuals 
    
    '---------PIC Connections----------
    
    '		18F4331 Pin			   Wiring
    '		---------			----------
    '         RA0(AN0)          Potentiometer, controls motor power
    '         RA3               Signal 1 from Encoder  
    '         RA4               Signal 2 from Encoder
    '         RB5               In Circuit Serial Programming (ICSP) PGM 
    '                           100K Resistor to GND 
    '         RB6               ICSP PGC (Clock)
    '         RB7               ICSP PGD (Data)
    '         RC0               Brake Motor 1 on Xavien XDDCMD-1 (Pin 1)
    '         RC1               PWM Motor 1 on Xavien XDDCMD-1 (Pin 2)
    '         RC3               Direction Motor 1 on Xavien XDDCMD-1 (Pin 3)
    '         RD4               LCD Data Bit 4
    '         RD5               LCD Data Bit 5
    '         RD6               LCD Data Bit 6
    '         RD7               LCD Data Bit 7
    '         RE0               LCD Register Select
    '         RE1               LCD Enable
    '         MCLR              4.7K Resistor to +5V & ICSP Vpp
    '         VDD               +5V
    '         VSS               GND
    '         OSC1 & OSC2       4 MHz Crystal w/ 2-22 pF Cap. to GND
    
    '----Xavien XDDCMD-1 Connections---
    
    '  Xavien 2x5 Header Pin	   Wiring    Pin Layout 2x5 Header
    '  ---------------------       ------    ---------------------  
    '                                             2 4 6 8 10   
    '   Pin 1 Motor 1 Brake         RC0           o o o o o
    '   Pin 2 Motor 1 PWM           RC1           o o o o o
    '   Pin 3 Motor 1 Direction     RC3           1 3 5 7 9
    
    ' See schematic at:
    ' http://cornerstonerobotics.org/schematics/18f4331_hpwm_motor_encoder.pdf
    
    '--Sample POSCNTH, POSCNTL Values and Corresponding Position Counter-- 
     
    '   position = 256 * POSCNTH + POSCNTL
    
    '  POSCNTH      POSCNTL     Position Counter
    '  -------      -------     ----------------
    '     0             0               0
    '     0             1               1
    '     1             0             255
    '     0           128             128
    '   128             0           32768
    '     0           255             255
    '   255             0           65280
    '   255           255           65535
    
    '-------------Defines--------------
        
        DEFINE LCD_DREG PORTD   ' Set LCD Data port
        DEFINE LCD_DBIT 4       ' Set starting Data bit to 4
        DEFINE LCD_BITS 4       ' Set LCD bus size to 4
        DEFINE LCD_RSREG PORTE  ' Set LCD Register Select port to E
        DEFINE LCD_RSBIT 0      ' Set LCD Register Select bit to 0
        DEFINE LCD_EREG PORTE   ' Set LCD Enable port to E
        DEFINE LCD_EBIT 1       ' Set LCD Enable bit to 1
        DEFINE LCD_LINES 2      ' Set number of lines on LCD to 2
        DEFINE LCD_COMMANDUS 2000   ' Set command delay time to 2000 us
        DEFINE LCD_DATAUS 50    ' Set data delay time to 50 us   
        DEFINE ADC_BITS 8       ' Set number of bits in result to 8
        DEFINE ADC_CLOCK 3      ' Set clock source (rc = 3)
        DEFINE ADC_SAMPLEUS 50  ' Set sampling time in us
        DEFINE CCP2_REG PORTC   ' Set HPWM Channel 2 port to C
        DEFINE CCP2_BIT 1       ' Set HPWM Channel 2 bit to 1
                                              
    '------------Variables-------------
    
        mot_pwr  var    byte        ' Declare mot_pwr variable, reserve byte
        pot_val  var    byte        ' Declare pot_val, reserve byte
        position var    word        ' Declare position, reserve word
        second   VAr    word        ' Declare second, reserve word
        ticks    var    byte        ' Declare ticks, reserve byte
        update   var    byte        ' Declare update, reserve byte
        rpm      var    word        ' Declare rpm, reserve word
        	 
    '----------Initialization----------
        
        CCP1CON = %00111111         ' Set Capture/Compare/PWM Module Control
                                    ' Register CCP1CON in PWM mode (bits 0-3),
                                    ' bits 4,5 set LSBs of 10-bit duty cycle,
                                    ' see 18F4331 datasheet page 151 +/-.
        ANSEL0 = %00000001          ' Set AN0 to analog, AN1-AN7 to digital,
                                    ' see datasheet page 249 +/-.
        ANSEL1 = %00000000          ' Set AN8 to digital, see datasheet
                                    ' page 249 +/-.   
        TRISA = %00011111           ' Set TRISA register, RA7-RA5 as outputs,
                                    ' RA4-RA0 as inputs, see datasheet
                                    ' page 107 +/-.
        LATA  = %00000000           ' Set all LATA register bits to 0.
        TRISB = %00000000           ' Set RB7-RB0 pins in PORTB as outputs.
        TRISC = %00000000           ' Set RC7-RC0 pins in PORTC as outputs.
        QEICON = %10001000          ' Set Quadrature Encoder Interface Control
                                    ' Register. See page 171 +/- for 
                                    ' encoder set up.
        T0CON = %11010101           ' Set TMR0 configuration and enable PORTB
                                    ' pullups. Set Timer0 Prescaler Select bits
                                    ' (bits 2-0) to 1:64 prescaler value. Timer0
                                    ' interrupt occurs every 256 us for a 
                                    ' 4 MHz crystal so 256us * 64 = 16.384ms.
                                    ' 16.384ms * 61 ticks = 0.9994 seconds.
                                    ' See Timer0 Control Register 18F4331
                                    ' datasheet page 135 +/-. 
        INTCON = %10100000          ' Enable Timer0 interrupts.
        ON INTERRUPT GoTo tickint   ' Jump to interrupt handler "tickint"
                                    ' after receiving an interrupt.                             
        PORTC.0 = 1                 ' Turn on brake.
        PORTC.1 = 0                 ' Set PWM bit for Channel 2 of HPWM to LOW.
        
            
    '-------------Main Code------------ 
    
        pause 500                   ' Pause to start up LCD
        PORTC.0 = 0                 ' Turn off brake
        PORTC.3 = 0                 ' Set direction of motor               
                                    ' If position value on LCD is in the 65,000s
                                    ' and counting down, then change the
                                    ' motor direction: PORTC.3 = 1.
        second = 0                  ' Set initial values for second and ticks.
        ticks = 0
        update = 1                  ' Enable first display
         
    ' Set counter starting position:                                    
                                    
        POSCNTH = 0                 ' Set counter for encoder, H bit
        POSCNTL = 0                 ' Set counter for encoder, L bit
                                    ' position = 256 * POSCNTH + POSCNTL
                                    ' With POSCNTH and POSCNTL = 0,
                                    ' position counter will start at 0.
                                    ' See table above for more sample values.
    
    ' Read motor power setting, set motor power before main loop: 
       
        ADCIN 0, pot_val            ' Read AN0 and store result in pot_val.
                                    ' This potentiometer (connected to AN0)
                                    ' sets the motor power.
        mot_pwr = 11 * pot_val / 16 + 77 
                                    ' mot_pwr = 11/16 * pot_val + 77
                                    ' (Can't write equation as 11/16 * pot_val
                                    ' since interger division truncates: any
                                    ' fractional part is discarded. Since 11
                                    ' and 16 are integers, 11/16 would be
                                    ' truncated to zero.)
                                    ' 77 is the minimum power to start motor.
                                    ' 11/16 is the slope of the line to give
                                    ' mot_pwr values from 77 to about 255.
                                    ' See graph & equation in schematic.
        HPWM 2, mot_pwr, 20000      ' Send PWM signal from RC1 to Pin 2 on
                                    ' the Xavien XDDCMD-1 DC motor driver.                                         
     loop:
                      
        if update = 1 then
        POSITION = 256 * POSCNTH + POSCNTL ' Read position
        rpm = 60 * (position/32) / second
                                    ' 60, (60 seconds/minute)
                                    ' position/32, number of revolutions
                                    '  (Our motor has 16 holes which generates
                                    '  32 position counts/revolution)
                                    ' second, number of seconds
                                     
    '       rev   60 seconds   position counts      1 revolution          1
    ' rpm = --- = ---------- *                 * ------------------ * ---------
    '       min    1 minute                      32 position counts   # seconds
            
        LCDOUT $FE, $80, "rpm=",dec5 rpm, "  s=", dec3 second   
                                    ' Display rpm and seconds on the first line
        LCDOUT $FE, $C0, "position = ",DEC5 POSITION
                                    ' Display position on second line
                                    ' Position will count to 65535, then
                                    ' cycle back to 0 and continue counting.
                                    ' in 5 decimal digits.
        update = 0                  ' Reset update to 0
        endif 
      
    ' After 60 seconds, shut down:
                    
        if second = 60 then gosub shut_down
                                    ' Stop program at 60 seconds
        goto loop:
    
    
        Disable                     ' Disable interrupts during interrupt handler
        
    ' Interrupt handler:
        
    tickint:
        ticks = ticks + 1           ' Count parts of a second
        if ticks < 61 then tiexit   ' Timer0 interrupt occurs every 256 us for
                                    ' a 4 MHz crystal so 256us * 64 = 16.384ms.
                                    ' 16.384ms * 61 ticks = 0.9994 seconds.
                                    ' (61 ticks per 0.9994 seconds)
                                    
        ' One second elapsed, reset ticks and update time:
                                    
        ticks = 0                   ' Reset ticks to 0
        second = second + 1         ' Add one second
        update = 1                  ' Permits LCD update
        tiexit: INTCON.2 = 0        ' Reset timer interrupt flag,
                                    ' (Reset Timer0 to 0 - next Timer0
                                    ' interrupt is in 16.384ms)
        resume
        
    ' End of interrupt handler
        
        enable                      ' Enable interrupts
      
    shut_down:
      
        PORTC.0 = 1                 ' Turn on motor controller brake
        
        end

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


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Hi Barry,
    Oh, only 8kHz PWM frequency....
    If using the PCPWM timer with a 1:16 postscale it would interrupt at 8k/16=500Hz which, I'd say would be fairly good for a large inertia system like a lathe spindle. BUT, I think the limited resolution of your spindle encoder will present you with some issue if you're simply going to count pulses for the duration of interrupt period. At 500Hz interrupt rate and 60rpm there will be a single count every ~8th interrupt and none in between - even at 100Hz interrupt rate the resolution will be quite limited at the low end.

    Still, this might work due to the high inertia but from the PID-filters point of view it's going to look like the spindle isn't moving at all, then all of a sudden it is moving, then it's not moving at all and so on. Depending on the tuning of the filter you're going to have a lot of ripple on the output which will result in some large torque variations in the motor - which will then get filtered by the inertia of system.

    I'm thinking that perhaps it would be better to use a capture module and measure the width of each input pulse instead of counting them over time.

    /Henrik.

  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

    Hi Henrik,

    Nothing is set in concrete on this project!
    8kHz is the PWM frequency now but it can be changed. I don't know what the down side would be, if any, to increasing the PWM frequency but I am willing to give it a go if it will help things overall.

    I chose 60 steps per revolution on the encoder wheel because a) it was easy to achieve and b) it made RPM calculation easy.
    I have now played with period measurements using the 18F2431's IC module so there is less reliance on the original step rate.

    Given the inertia of the final system, what would be the expectation for the number of steps per revolution, interrupt rate and minimum motor speed to achieve a nice, tight PID operation?

    Cheers
    Barry
    VK2XBP

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


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Hi Barry,
    The drawback with a switching frequency as low as 8kHz is that it is in the audible range, ie you or people around you can hear it "whine". The ripple current thru the motor will also be larger - which might or might not matter (think current limiting etc). Going to a higher switching frequency helps with both of the above points but introduces more switching losses in the H-bridge. Normal switching frequencies for motor control tends to be in the 20-50kHz range. but if 8kHz works for you I see no reason to change it.

    I can't give you a definitive answer to the second question. I could blame that on not knowing the inertia of your final system but honestly, even if I did I couldn't calculate that for you.

    If counting pulses, basically you want as much granularity as you can get at the lower end without overflowing the counter at the top end. If timing pulses it's the other way around, then you risk overflowing the timer at the low end.

    To illustrate an example: Lets, for easy of calculation, say that your interrupt rate is 60Hz. If you count pulses and the motor is turning 60rpm you'll get a single count each interrupt. But if its turning say 66rpm the PID filter would only notice that as an "extra" count every 10th interrupt. And when it notices that extra count IT thinks the motor is turning 120rpm (since 1 count per interrupt equals 60rpm). Now all of a sudden tit sees an error of 100% (where did THAT come from) when in reallity the error is 10%. Again, the inertia of the spindle will filter this to some degree but it's something to be aware of.

    Again, it might work just fine.

    /Henrik.

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


    Did you find this post helpful? Yes | No

    Default Re: incPID Routine - Help Needed

    Thanks for the sanity check Henrik.

    One of the reasons I chose 8kHz switching frequency is that I need to drive the H-Bridge via opto-couplers to achieve isolation between mains power and the controller.
    I have been able to achieve sub-10uS opto rise and fall times but need to apply 12uS dead-time for the PWM signal to alleviate MOSFET shoot-through. Increasing the switching frequency just isn't possible without losing a heap of top motor speed.

    After careful consideration I believe I might have been setting my sights a bit high on the final performance specifications. I have pulled back on the desired minimum rotational speed and will set it somewhere that is workable within the limits of the sample rate and the number of encoder pulses.

    I have also decided not to incorporate the RPM display into the main 18F2431 function. If need be I will add the RPM display at a later date using a dedicated setup.

    So now it is a matter of getting back to setting up the timer/counter arrangement and implementing the incPID routine. I will keep you updated with my progress.

    Cheers
    Barry
    VK2XBP

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