So I want to get into some more advanced programming this year, and you know what that means, PID. I was wondering two things: what is it and where can I get started. I think I have a general idea of what it is but I just need a little clarification.
There’s a variety of different resources you can access - notably examples of PID on this website as well as a youtube series of tutorials done by MartinMaVEXForever. Type in “site:www.vexforum.com PID” into Google and you’ll likely find what you’re looking for.
PID is an example of a control loop that uses three elements in the algorithm to get to the target value. The basics of any control loop is measuring how far away am I from where I want to be? And you do this continuously.
A control loop in Vex evaluates many many times per second. Every 20ms is about what you can expect because the motors like that update rate. So every 20ms you say "hey, how far away I am from where I want to be? And in PID you also compute, where was I last time, and have I ever been near where I want to be?
The PID is three different elements in this type where you have:
proportional - apply motor strength relative to being further away from target. This lets you “glide in” to the target value as it gets smaller as you approach the target value.
integral - applies more power based upon how far away you have historically been in sum (hence the integral as it adds up the error over time). This helps create the holding power of an arm on your robot to overcome gravity. The integral adds a wee bit of power each loop around and then once you go over your threshold, it takes a wee bit away each time around. (more about this later)
derivative - applies correction if you “are coming in too hot.” Where was I last time relative to where I am going? Hmm. Let’s pump the brakes a bit or turn on the afterburners.
So the three types of factors apply each and every time slice to adjust the motor based upon the sensor readings.
Add the P + I + D components to get your new motor power that time slice.
Getting the right values for the P + I + D constants is the real trick. The other trick is to not let the integral take over the conversation. You have to cap the “I” contribution to about 20%-30% of the power the motor depending upon the situation.
So once you get that part and do some more research we can talk about tuning. As a badly tuned PID is not good.
Download and follow along with this guide. It explains everything very well to someone who has never used PID before, and provides code examples too.
Credit for the guide goes to George Gillard.
Also look into tasks or multithreading in RobotC or PROS because, very often, they are used along with PID control loops.
Yes, be careful with integral windup, but in most static cases, like holding an arm up, the integral is 100% of the output when you hit your target and have 0 error so don’t limit it to a lower percentage.
Here is the document I used to easily create our arm PID. It gives a great step-by-step instructions on how to easily make your own PID and explains the different components very well.
I think they were referring to 20-30% of the total power output potential of the motor, I agree that may not be the best way to do it. My PIDs check if the input is saturated (whether or not the PID wants to supply more than 127 power), and if so, it won’t integrate. This means that it’ll only start to accumulate once it could potentially make a difference. You could also set some sort of error limit (don’t integrate unless error <= x).
What I’ve done at times is to let P have the priority, so if the output of Kperror > 100% (127/-127 for VEX) then it only uses P and resets the integrator. Otherwise, it allows the integrator to accumulate up to a value but clamps it so that Kperror + Ki*integral is = 100% at most. This will continuously reset/limit the integrator as needed but allow for quick P response.
To get everyone on the same page, here is how PID is most frequently defined:
OutputPower = P + I + D where P = Kp * error = Kp *(target_position - current_position) I = Ki * sum_of(error values over some period of time) D = Kd * current_rate_of_change_in_the_error_value
And this is the graphical representation from PID_controller wikipedia page:
First of all, classic PID algorithm is very generic and was designed primarily for small corrections and keeping the process on target (around some setpoint) for mostly continuous linearish systems. For example, keeping the room at set temperature, or keeping the ship on course while wind or waves are slowly changing, or keeping robot arm at certain angle.
The PID in its simplest form was never intended to be used for large transitions with non-linear dependencies. If it seems to be working for people using it in non-linear VEX applications it is because with all the clipping of power levels (to +/-127) and managing integral windup (as @TriDragon described in the previous post) you are no longer dealing with pure PID but with something different.
If you read George Gillard’s PID article that @Colossus linked above you will notice how P or D terms need only one paragraph each, while discussion of the I term takes multiple pages to explain.
At some point managing Integral term begins to look like some sort of the art or black magik to people just starting to learn PID. But, trust me, there is no magik involved.
However, when you are dealing with anything more complex than very simple linear system, you need to be less generic and more specific controlling it. I am sure somebody as experienced with PID as @TriDragon or @Team80_Giraffes could give you multiple examples on how PID needs to be applied slightly differently to different processes in order to achieve stable results.
I am going to give you several examples further below, but first I would like to define PID in terms of energy flow through the system. You will see how it will make sense as we go through the examples.
P - corresponds to how fast or forcefully you need to react to unpredictable changes
I - corresponds to the amount of the unexpected resistance or energy losses in the system
D - corresponds to the estimated amount of the inertia or kinetic energy stored in the system
The reason words “error”, “unpredictable”, “unexpected”, and “unknown” are frequently used when talking about PID is because PID Controller is a feedback loop, which reacts when the system is deviating from the expected target. It usually complements feedforward controller that deals with known and predictable variables. The formula that corresponds to the combined controller (PID+C) frequently looks like this:
OutputPower = P + I + D + C
where C is a constant (base) power level predicted by feedforward controller as nesessary to stay on target.
For example, when you drive a car on the highway and press cruise control button, it will take current throttle value and will use it as the base power. Then, depending if road goes uphill or downhill, PID will either increase or decrease the throttle in order to maintain the desired speed.
In another example, for those who remembers NbN season, we used to calculate base power to run flywheels at target speed as some experimentally determined value plus correction based on the battery level: C = SomeBasePower + Bcoefficient * CurrentBateryVoltage. Here feedforward portion of the controller would deal with known variables (decreasing battery voltage) and PID would take care of unknowns, like slowdown when the ball went through the launcher or unexpected increase in friction in the system (i.e. robot run into the wall and something got slightly misaligned).
The next example is the classic VEX clawbot:
Let say it needs to pick either 1 lbs or 2 lbs objects and raise the arm from lower position (45 deg) to either horizontal position (90 deg), upper 45 (135 deg), or to the top vertical position (180 deg).
While the task seems to be very simple you would struggle to get stable results with a naive implementation of PID (that doesn’t have a feedforward controller) and trying to fit square (linear) peg into a round (non-linear) hole.
Would anyone like to guess potential issues? How would you address them?
Hint 1: think about what are the “knowns” and what would be “unknowns”.
Hint 2: if you know basic trigonometry, then writing feedforwad controller is a one-liner and a piece of cake.
@technik3k I am not a programmer but I think I know some of the issues in using basic PID on a non-linear lift.
When the clawbot arm is at the lower (45 deg) position and lifting something up, the motors have to put in most of the work to move the object. However once the arm reaches the horizontal position, the motors will have to supply all of the power to overcome the rotational inertia of lifting the object. Once the arm is past horizontal, the power the motors need to supply to keep the arm moving at a constant rate decreases. This is because the force normal of the lifting arm carries more and more of the weight of the object the farther up it goes. So since the motors need to supply less power at different parts of the lift, maybe you could use a potentiometer to tell the program what angle the arm is at, and use different kP, kI, and kD values? Again I am not a programmer but this seems to work in my head.
@Easton, you pretty much identified all the important points that need to be taken into account when designing our lift algorithm!
Lets assume that the shoulder has potentiometer that tells you arm’s angle and there are elastics that take care of the arm’s own weight. Also, lets assume the friction in the shoulder joint and force necessary to accelerate the arm itself are small compared to the forces required to lift and accelerate the game object.
Then, if arm could move all the way to the bottom (vertically pointing down at theta=0deg), the only force you need to start moving would be the force to accelerate the game object, while the shoulder joint will provide the force to support the weight of the object. As the arm moves from the bottom position, the force of gravity will require motors to contribute more and more power to move the object up, while the proportion of the power going toward object acceleration would decrease as the object speed stabilizes.
If you think about it in terms of energy flow, then the power that motors pump into the system goes toward object’s kinetic energy (accelerating it), object’s potential energy (lifting it up) and some small portion converting into heat via friction in the shoulder and geartrain.
As the arm reaches horizontal position, the load on the motors from the force of gravity will reach the maximum and object may start decelerating if motors could not put out enough power to counteract gravity. Lets assume that motors are geared down enough to hold arm at 90 deg without overheating PTCs and burning out.
Then, if you continue moving upward past 90 deg angle, the load on motors due to the object’s weight will lighten and pretty much get to zero at the top (180 deg). If you don’t reverse the power to the motors, the arm will overshoot and keep moving past 180deg, first using object’s kinetic energy to overcome friction and then even accelerating as it starts falling and converting its potential energy into kinetic…
Let’s assume that we are not planning to move at high velocity and would be done with accelerating game object after about first 10-15 deg of lifting.
What would be the torque at the shoulder from 10" arm’s holding 1 lbs object at 60 deg angle?
Can you provide a simple formula for that?
In my first PID loop I actually had the same thought when I was tuning constants for our MOGO lift. In one situation, you are lifting the mogo and the weight of the lift against gravity, and in another situation, you are simply moving the lift down with the assistance of gravity. I ended up using two sets of constants for lifting and lowering the mogo. This being my first PID loop, I do not know if that was common practice or not. Any thoughts?
Edit: Noooo! @technik3k beat me by a few seconds
converted inches to meters, and pounds to N:
but since the vex motors are in in/lbs…
Is that the right equation?
Yes, creating and tuning separate sets of PID coefficients for multiple target points (and directions of movement) would be a possible way to do it if you don’t model the force of gravity explicitly. However, if you need to stop at multiple target points you may end up with tedious re-calibration task every time you changes something on your lift.
By modelling as much of the known physics as possible you both make the calibration task easier as well as getting more precise movement, because your PID only needs to take care (estimate) of truly unknown variables.
Yes, f = sin(theta) * someCoefficient was the equation I was looking for!
Now we need to determine our knowns and unknowns.
Can we estimate the motor control value that is necessary to hold the arm at 90 or 135 deg ?
Hint 1: it is a trick question
Hint 2: when you send control value to the motor you don’t really set its speed or power level, you only control its duty cycle (i.e. percentage of the time it is connected to the battery). Then the difference between back-EMF voltage (proportional to its actual speed) and effective voltage coming out of motor controller determines the torque that the motor generates.
The previous paragraph may sound complicated and hard to model, but the good thing is that it is very easy to take into account just by collecting few experimental points: https://vexforum.com/t/velocity-control-using-just-battery-voltage/32823/1
Wow, that completely changes the way, I was going to program my lift! I was planning on just looking at the error between the current angle of the lift and the target angle. Introducing this: = sin(theta) * someCoefficient, equation is such a good idea. My question now is, how I would factor this calculation into the PID loop? Would it go into the error calculation or one of the PID terms?
sin(90) * 10in * 1lb = 8.9 in(lbs)
Standard Vex motors have 15 inlbs of torque (I think?). Also, to account for the 1:7 ratio of the Claw Bot’s arm, then:
8.9 in(lbs)/7 = 1.271 in(lbs)
1.271 in(lbs) / 15 in(lbs) = 0.08473
That would take about 8.5% of the Vex motor’s max torque so I would apply 8.5% of the vex motor’s max control value:
127*0.085 ≈ 11 motor control value
So, if I were to get a base value to hold the arm at 90° then I would apply 11 motor control value to the motor. Using the same process, I would use a base value of 1 to hold the arm at 135°. Wow! That is a huge difference!
Hmm… it, probably, couldn’t be that small, because MC29 have non-linear control function:
And you would need to run it through some sort of the value remapping function (search for TrueSpeed array or polynomial)
I would expect the base power control values for 45, 135, and 90 deg to fall somewhere between 15…25 control values, but still if you need to stop your arm precisely just few control value points could make the difference between completing the move in minimum time and oscillating for another 1 sec around target point.
There is still the trick part of the question, that I will not reveal for a few hours to let people think about it for a while…
Ok, so the trick part of the question was that original “game rules” were specifying that you have to lift either 1 lbs or 2 lbs game object.
We (humans) frequently overlook such things, because it is obvious to us which game object it is, but robot doesn’t have our senses. This was one of the “unknowns” that a simple algorithm may stumble on.
It may seem like not such a big deal, because if you throw enough motors on this problem, with plenty of power margin, and adapt aggressive value for Kp the robot will have no problem lifting either game object with or without advanced modelling.
However, this will matter if you are looking for minimal settling time for non-linear lifts like schlucas and/or could not spare too many motors. Actually more advanced modelling will help even more naturally linear lifts like DR4B if you are trying to push them very close to their hardware speed limit.
So, how do you turn “unknowns” into “knowns”?
As @Team80_Giraffes mentioned in the post above, PID could naturally “learn” holding force to overcome gravity by integrating “I”. The problem is that it takes time to “learn” this way and, in addition, to holding force “I” needs to learn about decreasing battery level and any excessive friction in the system.
If you set Ki too high - you lose stability and may get oscillations, and if you set Ki too low - it will take more time to accumulate correct value. You want to figure out a way to get good estimate for holding power faster than conservative Ki could naturally integrate.
Here is how I would do it:
First of all, you run all calibration experiments at some fixed battery voltage and then scale all power levels, depending on the actual battery voltage, similar to techniques found in this thread: https://vexforum.com/t/velocity-control-using-just-battery-voltage/32823/1
This will take battery voltage from the “unknown” to “known” column and offload your PID from compensating for that. It will still be doing minor corrections but the scaling will save you precious settling time.
The claw grabs an unknown game object while resting at 45 deg angle. You start lifting by increasing motor power from 0 to 100 in increments of 20 power units every 20 msec to be gentle on motor gears and PTCs.
Let say by the time arm reaches 55 deg angle the game object is guaranteed to be fully off the ground and motors are running at full power. At this point you start you “measuring interval” and keep running motors at 100 power.
You measure the time arm sweeps between 55 and 85 deg. This is you “measuring interval” Then your code will compare this number to experimental data and should be able to easily determine if claw is carrying 2 lbs object, 1 lbs object, or no object at all.
For example, if your experimentally determined average times for no object is 0.2 sec, for 1 lbs object - 0.5 sec and for 2 lbs - 0.9 sec.
Then, if you just measured time of 0.55 sec, it would mean that you are carrying 1 lbs object with slightly increased friction in the system (vs last calibrated values) or, perhaps, one of the rubber bands snapped and you have less lift assist from the elastics. For extra credit you may want to have multiple measurement intervals and see how various mechanical anomalies would affect the timing at different angles. Just don’t choose intervals too small or you get large round-off errors.
Based on these findings you could initialize default holding (base) power (to maintain 90 deg position) as well as the crude initial value for “I”. This will also determine how aggressively you should be dropping motor power and when you need to start deceleration (this would be your motion planning)
Only when you start dropping motor power and decelerating you could start estimating fine value of “I” based on 90 deg specific Ki. You still wouldn’t engage PID to drive motor power as you keep decelerating using the pre-planned motion profile.
At some point in that deceleration (let say half-way or you could experiment when exactly) your PID will take over controlling motor power. This will let you tune your Kp and, optionally, Kd for a very narrow interval around 90 deg (i.e +/- 5 deg) and would give you a chance for very prescise arm movements.
If you need to stop at other setpoints you would need to calibrate your deceleration profile and Kp, Ki, and Kd for at least a couple of other points and then fit a polynomial to see if you could get away with just interpolating the values instead of calibrating them in multiple points. My guess is that if your lift is not crazy complex, than having three calibration points is good enough.
In general, if you could build your lift as linear as possible (DR4B), have uniformly tensioned rubber bands (claculator), and then model as much physics as possible, before handing it over to PID, you should have no problems doing 2 cps or even better
This ones really good and provides some sample robotc code.
@technik3k I have found #4 above at measuring things at 90 degrees gives the max force but modeling the effects of the rubber bands non-linearity gets tricky on you. The rubber bands are generally nice and stretched at the 90 degree position but if you go further up, then the contribution is less and makes for different force contributions.
PID constants for your most common positions has been the best I have seen. Most times the same sets work across the board, but when you want to get from up to down real fast without a bounce (or more like a hard slam on the floor) a new set of constants can help a ton. Luckily the game objects are not heavy this year to make the mass of the arm all that variable.
Also in trying to measure the potentiometer vs angle, it is not always linear so make a function in Excel from a bunch of measured values of angle to pot value. Let Excel tell you the best fit function.
You can keep modeling this stuff forever!
Yes, I agree that you cannot model everything 100% accurately. But even if simple model takes you 80 or 90% of the way it will make it 5 to 10 times easier for PID to handle the remaining 10% - 20% of uncertainty.
I thought, I read before (but couldn’t find relevant thread now) that Team 80 compiled a spreadsheet with unique PID coefficients and initial hold power for the height of every Skyrise section, and then had a clever way of adjusting them all at once, without re-calibrating at every point, if you had changed the elastics on the lift.
I just wanted to underscore one more time why it would be mistake for beginners to try to use the same set of PID coefficients for full range. It might seem to work at first if you give it plenty of motor power. But in most cases gravity adds a lot of asymmetry to the system as well as geometry and elastics could easily make it non-linear.
Having even a very simple model complementing PID would allow you to achieve the same results with less motors and, in most cases, be more accurate and faster at the same time.