Overview
An encoder is attached to the spindle, in my case a 1 pulse per revolution encoder. The position of the encoder is scaled using a HAL scale component from pulses per second to pulses per minute thereby giving RPMs. In my case since I had a single pulse per revolution I scaled by 60 to give spindle RPM. This spindle RPM is connected to the feedback pin of a HAL pid component. The commanded spindle RPM is connected to the command pin of the PID. The PID is tuned to use Pgain=0, Igain=1, Dgain=1. The output of the PID is added to the commanded spindle RPM and then fed into the pwmgen as the value of the pwm.
Update: I've managed to better tune my system by using Pgain=1, Igain=1, Dgain=0.5, maxoutput=1500 . The spindle doesn't overshoot too much and it oscillates down to the commanded RPM within 2 seconds.
Update: I haven't done this yet, but setting FF0=1 will enable you to not have to use the sum2 component since the commanded RPM will be automatically added into the output of the PID, but you will have to adjust the maxoutput to your real maxoutput, not the max amount of error allowed.
Hal file snippet
# -------------------------------------------------- # Closed Loop Spindle Control # -------------------------------------------------- # Initialize the encoder (spindle) loadrt encoder num_chan=1 addf encoder.update-counters base-thread addf encoder.capture-position servo-thread setp encoder.0.position-scale 1 setp encoder.0.counter-mode 1 # Initialize the PID loadrt pid num_chan=1 addf pid.0.do-pid-calcs servo-thread setp pid.0.Pgain 0 setp pid.0.Igain 1 setp pid.0.Dgain 1 setp pid.0.maxoutput 4000 # Initialize the pwmgen loadrt pwmgen output_type=0 addf pwmgen.update servo-thread addf pwmgen.make-pulses base-thread setp pwmgen.0.pwm-freq 1000.0 setp pwmgen.0.scale 4000 setp pwmgen.0.dither-pwm true # Initialize the scale # (This is used to scale the encoder pulse to RPM) # (In my case, i have 1 ppr so it is scaled by 60) loadrt scale count=1 addf scale.0 servo-thread setp scale.0.gain 60 # Initialize the sum2 loadrt sum2 count=1 addf sum2.0 servo-thread # Attach the motion.spindle-on to enable the pwmgen and the pid net spindle_enable motion.spindle-on => pwmgen.0.enable => pid.0.enable # Attach the encoder to the parallel port pin net parport_15_in parport.0.pin-15-in => encoder.0.phase-A => encoder.0.phase-Z # Attach the encoder to the motion and the scale net spindle_rev_count encoder.0.position => motion.spindle-revs net spindle_index_enable encoder.0.index-enable <=> motion.spindle-index-enable net encoder_raw_velocity encoder.0.velocity => scale.0.in # Attach the pid to the scale, motion, and sum net pid_feedback pid.0.feedback <= motion.spindle-speed-in <= scale.0.out net pid_command pid.0.command <= motion.spindle-speed-out => sum2.0.in0 net pid_output pid.0.output => sum2.0.in1 # Attach the pwmgen to the sum and the parallel port net pwmgen_value pwmgen.0.value <= sum2.0.out net pwmgen_out pwmgen.0.pwm => parport.0.pin-16-out