PID Control

I am right now looking at the possibility of using PID code for a few things which I will not go into too much detail about. But one thing I would like to attempt is a balancing robot, I have search google, the forums, and read the white papers, I am planning on asking Matt Krass next time he isn’t busy and when I see him around campus.

I understand the basic concept, but one of my main questions about a PID loop for a balancing robot, is for a nicely tuned PID loop how much oscilation would there be?

And the other scenario I didn’t understand was if a robot is trying to go a certain amount of distance. Since the error builds up how much would it have to overshoot before it will eventually settle at the same spot? Or would you use just a PD loop for this and instead of having the error build up if your stuck just look at the change. And just have the coefficient be the inverse of the error so the slower it is changing the faster your gonna try to move and the faster it is changing the slower your gonna move. So if you get stuck, then launch forward you would slow down faster back to the velocity you trying to maintain.

Any insight would be wonderful. This summer this will be a HUGE part of my code. So Any and all help is very much appreciated, Thanks!

-John

One way to deal with the buildup of error for the I term is to implement anti-windup in you control loop. Basically this limits the effects of the huge error at the beginning of your motion.

There are many ways of implementing this in practice. One way is simply to turn off your I term (as in not summing the error) until your error is small enough.

Another way is to have an error buffer that will only store so many values before it overwrites them (Limiting the error buildup). The error buffer is summed for your I term implementation. This way the large error at the beginning of the motion will be overwritten by the time the motion is nearly complete (for large movements).

Finally, I terms generally have a slow response and are used to eliminate very small steady state error. In an application such as a balancing robot, a PD loop will respond much faster albeit with some steady state error.

There is much more than this to PID control, but it’s late. Hope that this helped.

The way we’ve handled it is that we reset the I term once the robot has settled in place. That way, it is used when necesary, and turns itself off when it hits the target.

Edit: something to the extent of
if(error > -n && error < -n){
I = 0;
output = 0;
}

Is that what majority of code does for the Intergral part, just reset it once the target is reached? This is one of the only parts I have always been consfused about, because you you have a huge buildup (even if it is capped) your always going to overshoot. Becuase I would still like to have it in there incase lets say i get stuck on a piece of string (just an example) then it will increase the motors until the string breaks.

The other thing I need more help with is the derivative constant, should I make the constant negative? because if it it positive then when you have a big change your just gonna add even more to the output.

thanks,
John

First a couple tips
First of all I would look at Kevin’s 2005 navigation code. It has files in it (pid.c & pid.h) that can serve as a good base (I moded it significantly) for generic PID control, plus the structs make it easy to reuse for multiple loops.

Second if you are going to try to install this in Atlanta I recommend using pots or the EEPROM (if you already have that working) to set the P, I & D constants since time is a major factor and it take too long to redownload to change constants.

Third if you are using the Camera as your main sensor, realize that the camera doesn’t give you data every loop (about every 3 loops) so set the last error and error only when you get new data from the camera so it calculates the D error correctly.

Fouth, the on the Victor 884s the deadzone center point is 132 or 133 (PWM_ZERO is 132 in Kevin’s code) not 127. Keep this in mind so your robot doesn’t favor forward or backward. Also be careful reversing direction of motors in code (for simplicity I just swap wires)

I personally set the I error to 0 when it is on target and when it overshoots (error changes direction since it may never be “on target” when it goes past).
You may want to use I only when your close to target as has been suggested (I prefer not to).

The derivative term works in the oppose direction as the other 2 term. It damps oscillation and effectively sets a speed limit on your motion (it will also resist external impulse but that was more important last year). Be careful not to “overdamp” the system to where you need to set P and I very high to overcome D.

Good luck I’ll be in Atlanta if you need any help,
-Brian

Ahh, if only that were legal.
I can’t quote a rule number, but I recall having trouble with inspection in 2004 due to that.

Anyway, there’s another technique to have your I term go to 0 - integrate over time, rather than indefinitely. Keep a queue of error values and sum them every loop, or sum them as you go along and subtract values before you overwrite. This creates a term which is a hybrid of I and P. This will help overcome friction, but will not overcome gravity, springs, or other forces which are present when the system is at rest.


// Disclaimer: This code has not been tested. Read and think about it.
#define I_TIME 39
//I_TIME is the number of loops to integrate over
int iQPos = 0;
int iQueue[I_TIME]; // declare the queue

...
// Inside your initialization routine
for (iQPos=0; iQPos<I_TIME; iQPos++)
  iQueue[iQPos] = 0; // Initialize all to 0.

...
// inside of your PID code
I += error;
iQPos = (iQPos+1)%I_TIME; // Increment and loop if we get to the end.
I -= iQueue[iQPos];
iQueue[iQPos] = error;

In theory, you shouldn’t need to cap I… when at rest, I is a constant (because the system will automagically set I itself). I gets bigger, and bigger, and then less and less gradually increase (increasing, concave down). If theres an overshoot, I gets smaller (because its subtracted).

Also, when tuning the PID, start with P, then I, then D. Its very helpful to drastically change the constants, for instance, when we were tuning our arm’s PID, we started just incrementing P by just 2s… when it was divided by 32? anyhow, relatively no change. When we began testing, we didn’t notice any change in the robot, sometimes even a change for the worse (giving us a false assumption that what we’re doing was bad…)

(back to the original post)

There probably wouldn’t be a frightful amount of oscillation, have you ever rode a Segway? If you tuned it to perfection, there would always be oscillation. It would probably be to your advantage, however, to have a nearly balanced robot to begin with, with a very low center of gravity.

If I was building a self balancing robot, I would use a PID loop, and then use some sort of cap for the I… for instance, if the robot is moving at its maximum speed, then I can no longer increase, only decrease, or remain constant.

Hope this helps!

Do not do this.

The integral term takes care of the low frequency to DC part of control. If you remove the I part when you are at rest, you will always be slightly off.

Imagine you are attempting to control the position of a pendulum such that it sticks out perfectly horizontal. The pendulum has finite mass, and you have a force driver at the pivot point. Note that motors are not ideal force drivers, they have funny curves.

Implement Proportional control only. This is exactly equivalent to making your force driver into a rotational spring. If you let it go, it will oscillate about the 90* home point. Eventually, it will come to a stop from friction in the mechanical system. If you had perfect bearings, it oscillate for ever.

Well that sucks. Lets add Derivative control. This is exactly equivalent to adding a damper to your spring. This term always adds force opposite to the direction of motion. Since work is force dot distance, this is a negative amount of energy. This will dampen the oscillations, and it will come to rest much sooner. Effectively, you put more friction in (sort of… - we are off by one rank)

Put look! It came to rest 10 degrees lower than you told it to. The blasted thing is drooping!

Why? Well, we have a spring and a damper fighting gravity. If the system were at rest where you told it to be, both P and D (spring and damper) would contribute no force, but gravity would. Naturally, it falls until P is large enough to counteract gravity.

This is where I comes in. It sees P and D failing to do the whole job, so it slowly gets angry and pushes the arm back up. NOW it will rest where it is supposed to. Remember though, at steady state ONLY the I term is active. P and D are both 0.

In summary:
P and I are both conservative terms. Only D removes energy from the system.
D handles high frequency stuff, I handles the low frequency stuff, and P is somewhere in between (actually, it has a flat spectral response).

If you really want to make the system “impure”, i would suggest tying I to D nonlinearly. Perhaps I shouldn’t be doing much while you are still trying to sprint to the set point.

Eric

Emphasis mine

Since the wire swapping happens at the speed controller output it is legal. I’ve been inspecting since 2003 and I don’t recall output wire swapping ever being illegal.

I won’t be in Atlanta and I am not doing this for my team, I am inquiring for my own project. I have a robot that I am working on being GPS controlled, and I may or may not use PID Loops for that ( I don’t believe it is entirely neccessary for some parts). The robot that I am (it is at home I get to start again after college lets out) building has 14 inch wheels, good for off road driving, and they stick out past the ends of the frame, so anyway it falls it will beable to drive. I was thinking one cool thing to add is to make it balance, since the wheels stick out past the frame it is very possible. And I have a pnuematic compressor and solenoid and cyclinder I would like to put on so I can hit a balance button and it pushed it self up and starts to balance. I think it is unneeded in the project but it will be pretty cool. Like if I bring it to a team demo, you just see a robot driving around, but then it goes from 4 wheels flat to a 2 wheel tall!? I just think it would look cool and help me learn how to program some more complicated stuff. I will probally be posting more threads and posting pictures of the progress once I get started up again, so look for it around the end of may. Should be pretty cool.

More suggestions for reducing integral wind-up (or my $.02):

  • Only add to it when the motor can actually driver (ie, !disabled_mode)
  • At the end of the loop (before you save the I value), multiply it be a fraction, eg:
static_I = (long)I * 8L / 10

This means that big values last longer than little ones, but it also decreases the possibility of big values building up. Tweak the 0.8 value.

Another reason why I isn’t always desired to be reset once error=0 is in the case where you have a two wheeled platform that you want to travel in one line.

Ensuring that both wheels turn the same amount is not enough to ensure that the robot goes in ONE line, it just ensures that the orientation of the robot is the same.

To have a robot that goes straight, the wheels have to turn the same amount in the same period, I can “remember” all the differences between wheel positions and then make the proper corrections.

There is an algorithm that works just like this in “Mobile Robots from Inspiration to Implementation”

Also, for a balancing robot, lower COG is not necessarily better. A higher COG gives the robot more rotational inertia and therefore harder to throw off balance.

A higher COG might even be better, think about this… is it easier to balance a broom on your finger with the brushpart up or the brush part on the finger… (its easier to balance with higer CG if you were wondering…)