![]() |
Speed PID Function
As far as I know PID Control is normally applied to move a motor, ei. an arm or wheel to a set target/position/distance.
What I NEED to implement is a speed based PID method. I input a rate. In my java encoder.java class it lists a method getRate(); I suspect this works by returning......a rate which I could use to set my speed. from the rate/speed I input... I need to implement a PID method so when voltage drops or a ball passes through the shooter I am using, the POWER % will increase to compensate to allow the shooter to hold a constant SPEED. |
Re: Speed PID Function
If you perform a search on "velocity speed control" you will find all the formulas you require derived for you by a mentor from team 341. He also does an excellent job explaining how a velocity pid differs from a positional pid.
|
Re: Speed PID Function
Can you provide a link I can't find the exact page.
I saw something about Jaguar 2012 using PID.....I use Victors it shouldn't matter right. :O mostly because I am not a fan of the current flow fail-safe on the Jags. |
Re: Speed PID Function
Quote:
Here are some links which may be of interest: http://www.chiefdelphi.com/forums/sh...80&postcount=7 http://www.chiefdelphi.com/forums/sh...5&postcount=15 http://www.chiefdelphi.com/forums/sh...28&postcount=6 http://www.chiefdelphi.com/forums/sh...04&postcount=3 http://www.chiefdelphi.com/forums/sh...7&postcount=34 http://www.chiefdelphi.com/forums/sh...7&postcount=29 |
Re: Speed PID Function
Quote:
|
Re: Speed PID Function
Quote:
When a PID derived for position passes the set point, it reverses the motor. Reversing a motor on a spinning wheel going at 4000 rpm can have negative consequences. The derivations are different. Once you see the final formula, you will understand why position PID and velocity PID are different. |
Re: Speed PID Function
Quote:
|
Re: Speed PID Function
You need to use and encoder to "measure" the Back EMF of the motor.
BackEMF = EncoderRPM * 12V/(12V Free RMP) Motor output = Control Output + BackEMF This essentially linearizes the motor to act as a torque source. Now you can set up a standard PID with RPM as input. and Plug in the output to the equation : Motor output = Control Output + BackEMF. |
Re: Speed PID Function
I've been looking at the PID drive example in the FRC Java example projects.
SO. what I AM understanding is instead of putting distance in as the SETPOINT you would put the rate. Now what I'm also understanding is that the Error HAS to be 0. because you never want to stop the motor once you've reached your target velocity. I'm a client side coder once I have enough examples I can make my own functions and classes from that. I'm confused as to what BACK EMF is? Code:
/*----------------------------------------------------------------------------*/ |
Re: Speed PID Function
@BornaE:
The BackEMF term seems to react in the wrong direction to disturbances or changes in setpoint. For example, if a change in load causes the motor speed to decrease, this causes the BackEMF term to decrease as well, instead of holding fast (as might be desired). Or suppose there is a step decrease in setpoint. Instead of immediately decreasing (as might be desired), the BackEMF term will only decrease as the PID overcomes it and slows down the motor. Also, at steady state, the BackEMF term provides only the voltage necessary to hold speed for an unloaded system. So the PID must contain an integrator to make up the difference. Why not just replace the BackEMF term with the expected voltage* necessary to achieve the desired speed ? Read the links provided in post #4. They provide further detail. * As might be the case with a spinning wheel shooter for example where the load is predictable and the expected volts vs speed curve can be known. You can determine this voltage empirically by just reading the PWM from the dashboard. |
Re: Speed PID Function
I understand the theoretical stuff with the PID now.
I just need some psuedo-code or something to help me implement it. I'm currently clueless. |
Re: Speed PID Function
Quote:
http://www.chiefdelphi.com/forums/sh...15&postcount=5 |
Re: Speed PID Function
Code:
Code:
because actually using a rangefinder is exactly what I'm going to be doing in the end. |
Re: Speed PID Function
Quote:
Code:
previous_error = setpoint - process_feedback |
Re: Speed PID Function
I just ran a test with my encoder and I get a HUGE amount of oscillation when I'm just pulling the number from the getRate() method even when I'm running at a constant speed.
I can't get a RPM reading with this much oscillation. |
Re: Speed PID Function
Quote:
|
Re: Speed PID Function
Quote:
|
Re: Speed PID Function
http://www.chiefdelphi.com/media/photos/37282?
I am running the Victor at 35% |
Re: Speed PID Function
Quote:
I don't know if the rate implementation has changed since then. Your noise seems a little higher then what I saw before, but that could easily be explained by differences in setup. Saying that you're running a Victor at 35% doesn't answer Ether's question without also defining what motor you're using. In your chart, what are the units for "data". |
Re: Speed PID Function
this is where my confusion lies.
I thought the getRate function was reading the RPM's I guess not. I looked at the method itself and it shows that the equation for getRate is... setdistanceperpulse/getPeriod or right now for me. 1/the time between each pulse What my software mentor told me is that what were going to do is probably sample from the getRaw data encoder function. since we are getting 2.5 revolutions per second @ 35% power based on a test I did. since there are 1440 pulses per revolution. |
Re: Speed PID Function
Well, from a test I have done today, the encoder that came with the KOPs from a previous year outputs 250 ± 5 for every revolution. So it is not directly 360 degrees. Keep that in mind. What I am doing is just using the raw output and getting the RPM from that.
|
Re: Speed PID Function
Yeah I'm going to be using the RAW from now on as well.
I forget...is there is a way of subtracting consecutive samples and dividing them by 2 to find the rate. |
Re: Speed PID Function
Quote:
1 RPM = 1/60 rev/sec = 1440/60 pulses/sec = 24 pulses/sec So RPM = (delta_pulses/dt)/24 ...where delta_pulses is the change in the raw count from the previous cycle, and dt is the cycle time in seconds. Don't forget: you must scale your setpoint to the same units as your process_variable. |
Re: Speed PID Function
Quote:
If your cycle time is 20 milliseconds (TeleOp) and you have 1440 pulses/rev, then to get RPM you would take the difference in pulses and divide by 24*0.02 = 0.48 |
Re: Speed PID Function
The encoder returns 1440 per REV.
I am getting about 2.5-2.7 REVS a second. |
Re: Speed PID Function
In post #24, "cycle time" is not the time it takes for your encoder to rotate once.
it is the delta time between the two GetRaw() readings you are subtracting to get "delta_pulses" (the change in pulse count). if you are running the PID in TeleOp, that would be approximately 20 milliseconds. |
Re: Speed PID Function
I just got a VERY constant rate from using this function I wrote.
Code:
public void getSpeed(){ |
Re: Speed PID Function
Quote:
|
Re: Speed PID Function
Quote:
If it's getting reset, you're only getting a new speed every 10 cycles. If it's not, then once it becomes non-zero it stays that way, and you re-zero the counter every cycle so the filter does nothing (except skew the calculation). What you want is a circular buffer (ring buffer) that you populate each cycle and use each cycle to get a new speed, like this: Code:
public void getSpeed(){ |
My mentor explained to me this way.
Your first 9 values are going to be very skewed so wait until you have at least 9 values in your array before you start averaging. Now counter is a pointer variable it ONLY points to a position in the array. I add all the values and get an average every time after 9 samples. I haven't tested changing speeds yet. Only constants. |
Re: Speed PID Function
Quote:
Show your code to your mentor and ask him. |
I just saw what you meant you are right. My bad.
|
My mentor sent me this.
Quote:
|
Re: Speed PID Function
Quote:
Quote:
Another option is to use an IIR filter instead of FIR. It's simpler and it's tunable: Code:
public void getSpeed(){ Quote:
|
Re: Speed PID Function
Am I stupid.
Or is the CAN Jaguar functions built to do all of this for me. |
Re: Speed PID Function
Quote:
I don't know what kind of noise filtering, if any, the Jag does on the encoder signal. Others on this forum have studied the Jag firmware source code (freely available) and may be able to answer. |
Re: Speed PID Function
Quote:
avg(n) = avg(n) + (sample(n) -sample(n-L))/L where L is the length of the average. Essentially before you overwrite the oldest sample, you calculate the difference and then overwrite and compute the new average. |
Re: Speed PID Function
Quote:
Although the bigger question here is, do they really need a filter at all? If they're reading the encoder delta counts every execution cycle and dividing by the cycle period, there's already a whole lotta averagin' goin' on (except at very low speeds). |
Re: Speed PID Function
Quote:
For our team, we plan to bypass getRate() and derive encoder rate by (encoder – encoder_last)/T where T is the loop update time. Our typical wheel speed is 2000 rpm or 33.3 rps . The encoder has 250cnts per rev so there are about 8333 cnts/sec. With a 20 ms loop, there are 167 cnts per cycle. If 1 pulse is missed, it is less than .6% error. The code wheel slit phase errors are being averaged over half of the wheel so much of the high frequency phase variations that would affect getRate() are averaged out. |
Re: Speed PID Function
Our team was also getting wild fluctuations with velocity, with an error range of upwards of 300 RPM and spikes that extend well past 1000 RPM beyond our setpoint. This was unacceptable for our PID control loop, so our mentor suggested we implement a moving average/median filter to smooth out the graph and get rid of those nasty rate spikes. We also changed the encoder rate to k1X instead of k4X (default).
We are working with the command-subsystem in Java, so this should might help those that are working with PIDSubsystems (which our Shooter class is). We only changed the returnPIDInput() method. The result was an incredibly smooth graph, fluctuating within an acceptable range that can be tuned with the P constant (and maybe D depending on how close to the value we get). Here is a picture of repeated tests. In the above picture, there were 5 tests separated by the deep drops to zero (First 4 were set to 1000RPM, the last set to 2000RPM0. You can see how much smoother the fluctuation of RPM is (the fluctuation that still persists is a result of a much-needed PID constant tuning). As stated earlier, we went from a 300-1000 RPM spike/fluctuation to one less than 100 RPM. We also played around with the sampling size, and we chose 20. It did not affect cRIO CPU usage very much at all. 100 sampling size provided no advantage from what we saw compared to 20. Here is our implementation of the returnPIDInput() Code:
private double[] samplingValues = new double[HW.SAMPLING_SIZE];Hope this helps, David K. Team Spectrum FRC#3847 |
Re: Speed PID Function
Quote:
If I am reading this correctly, you are doing the following: 1) Using GetRate() to grab the "instantaneous" (consecutive-count) rate from the FPGA, and then Have you tried any of the suggestions in earlier posts in this thread, such as: a) Instead of using GetRate(), read the encoder counts instead, and divide by the sampling time (as explained in post39), or |
Re: Speed PID Function
Here is a note on precalculating PID gains without a simulation. The note has the full derivation.Excerpt:
Note: Precomputing PID gains for a velocity shooter using pole/zero placement I wanted to post some formula’s for deriving P and I gains for a velocity PID control loop such as a shooter used in the 2012 Rebound Rumble game. Assumptions: a) motor L/R time constant is small relative to motor control frequencies. b) The motor first order time constant tau_m is known. c) The input speeds are normalized to the maximum motor speed, w_max. w_max = 12v/ke*60/2pi rpm which is approx w_free of the motor. d) The desired motor response time constant, tau_d, is smaller than the motor tau_m by a factor of r. Then the integral gain KI is given by KI = 1/tau_d and the proportional gain KP is given by KP = r = tau_m/tau_d ; If the integral computation of the PID loop doesn’t contain a dt factor (i.e it is just an error accumulation) as is typical of the WPILIB PIDcontroller then the KI must be multiplied by the PID update period. KI_WPILIB = T/tau_d where T is the PID period. If you are feeding back RPM then the gains must be divided by w_max. Example: The 599 shooter wheel has an open loop time constant tau_m = .68 sec We want to have a tau_d = .33 sec which means the error should be around 1% of the target by 1 second (three time constants). During autonomous this would be the delay before we can shoot. KI = 1/tau_d = 3. KP = tau_m/tau_d = 3*.68 = 2.04 ; For WPILIB we want KI_WPILIB = T*KI = .05*3 = .15 ; KP remains the same. The shooter has a w_max = 5614 rpm so if the feedbacks are not normalized then KP and KI must be divided by w_max. or KP = 2.04/5614 = 3.63 e-4 ; KI_WPILIB = .15/5614 = 2.49e-5 ; Thats it. The main factor limiting the value of KP is the magnitude of the noise on the RPM feedback signal. Typically after filtering this can get down to 1% of the RPM. KP multiplies the noise so to keep the noise below 5% then the max KP would be 5. |
Re: Speed PID Function
I wanted to sum this information up for some of the team members (since a couple of the kids on my team didn't understand a lot of things in this post).
First - the getrate implementation (at least in labview) oscillates because it has a very short time period. To obtain a more stable rate, you canput the calculation function in periodic tasks and run it at its own loop speed. This function should be: (current encoder count - past encoder count) / loop time = count rate To smooth this rate further, you can average the samples over several loops, or you can extend the time (calculate the count over 2 or three loops and the time over 2 or three loops). Both may give you somewhat delayed results, depending on your loop rate. Next, a speed PID varies mainly in that you need to send the setpoint from the last speed loop into the new loop and modify THAT value. This prevents wheel reversal. The derivation from Jared on team 341 can be found here: http://www.chiefdelphi.com/forums/sh...7&postcount=13 It shows the derivation and implementation of a velocity PID loop. |
Re: Speed PID Function
Quote:
Are there some fairly simple tests that a team could do to obtain this number? Or do you recommend calculating, and if so it might be helpful to do a blog entry on that or post some example calculations here. |
Re: Speed PID Function
Quote:
Quote:
Quote:
|
Re: Speed PID Function
May I suggest using a different unit than RPM? The input is in the range of hundreds and thousands, but the output is from -1 to 1. If you were to use FPS instead, which would be 0 to 14 FPS or so at maximum, you will get more stable outputs since you do not have to use such tiny constants.
|
Re: Speed PID Function
Quote:
|
Re: Speed PID Function
Quote:
Of course, always check your inputs and outputs to be in range. |
Re: Speed PID Function
Quote:
This note on Velocity PID controller addresses your questions on how to obtain the open loop motor time constant tau_m. If testing is available always use that source since there is really no such thing as a spec motor. However, I use spec data to precompute gains since the gains will be adjusted anyway when we optimize the loop gains during integration testing. Often , very little adjustment is needed. The note also comments on various ways to implement a PID loop in software. |
Re: Speed PID Function
Quote:
A couple of suggestions: The figure is barely readable. Can you upsize the resolution, or provide a vector graphic option? Also, you might want to clarify that what you are calling the "motor time constant tau_m" is not the time constant of the motor itself, but the time constant of the plant (motor plus whatever it is driving). It's slightly confusing on first reading. |
Re: Speed PID Function
Quote:
|
Re: Speed PID Function
Quote:
The following is an excerpt from a post dated 01-14-2012 in the thread titled 2012: Tuning the Jaguar's Speed Control PID Loop : Quote:
|
Re: Speed PID Function
It has been a while since I looked at the JAG cpp ... what is the actual limit they impose? The WPILIB PID integrator limits are ok.
Also, since I have been nursing a cold over the weekend, I decided to expand a little more on the PID loop driving a torque controller. This is a subcase of the PID with feedforward but it has a nice topology that allows direct control of torque. This is basically the back emf approach discussed earlier in this thread. I wanted to show a method for precalculating PID gains in this case. Note: Velocity PID loop driving a torque input I also cleaned up the velocity control loop figure and added a few comments to my last notes. The addiditons are mostly highlighted in color. |
Re: Speed PID Function
Quote:
|
Re: Speed PID Function
Quote:
v_out = v_in*(1 - exp(- t/tau_d) . The % error as a function of time is err% = 100*exp(-t/tau_d); t= tau_d , err%= 37 t=2*tau_d, err% = 14 t=3*tau_d, err% = 5 t=4*tau_d, err% = 2 t=5*tau_d, err% = .7 So to meet the 5% in 1 second we needed 3 time constants to elapse which means 1 sec = 3*tau_d. So tau_d = .333 seconds and that in turn drives r the ratio of tau_m/tau_d. It is important to note that you must have excess torque to take advantage of the gain increase caused by the PID loop. Our nominal target speed for the key is around 2000 rpm. So we designed the the max speed to be 2.5 times the nominal. In general, you have a feeling for how much you want to speed up the response of your system. It is this ratio that determines r. Of course r has bounds like any amplified system. I like to keep it under 5 and nominally about 3. Edit: The pole/zero placement method I described gives you a lot of gain margin so usually the limiting factor is not stability but rather system saturation caused by large command changes or noise in the command signal. Saturation makes the system nonlinear and the response can no longer be predicted by tau_d. High frequency noise is amplified by KP and can be unevenly rectified by saturation causing a bias offset the error signal and unwanted current transients. So it is difficult to generalize about what gains are tolerable. I know 254 has lots of experience with PID loops and you might share what your experiences are relative to tolerable gains in a velocity loop. |
| All times are GMT -5. The time now is 08:53. |
Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi