Not a control engineer

I'm building a robot that needs control better than I've ever needed to think about before. The details don't matter, suffice it to say I'm using the opportunity to learn about PID.

I think I understand the idea, but I'm having trouble getting a sample working. I coded a simple simulation of a CarBot in Python and am trying to use PID to keep it going in a straight line, but I'm not totally succeeding.

In fact, I'm not even succeeding with just a PI algorithm. Graphing the output (of sideways velocity, which is what I've chosen my variable to be) I see that it oscillates and then settles down, but not at the setpoint.

I've done a lot of manual tuning (maybe "messing around with the knobs" would be a better way to put it) and this is about the best I can get. Shouldn't I be able to hit the setpoint on the nose with PI?

(I realize this situation has no deadtime and thus no need of the D in PID--I'll add that once I get PI working. Also, there's some useless math in there--division by 1, subtraction of 0, etc--that's because I want to make sure I know where to put the real numbers later.)

#!/usr/bin/python

class Car: x_pos = 0 y_pos = 0 xv = 1 yv = 0

def Step(self): self.x_pos += self.xv self.y_pos += self.yv

self.yv += .001

def PrintPos(self): print self.x_pos, self.y_pos

def PrintYV(self): print self.yv

bot = Car()

last_y = 0 yi = 0 last_yv = 0

KP = .7 KI = 0.2 KD = 0.0

for t in range(100): bot.Step(); bot.PrintYV();

yv = (bot.y_pos - last_y)/1 yi = yi + (yv - 0)*1 yd = (yv - last_yv)/1

last_y = bot.y_pos last_yv = yv

# print yv, yi

bot.yv += (-(KP * yv + KI * yi - KD * yd))

Reply to
PhysicsGenius
Loading thread data ...

After some more thinking and poking around, I think I'm just expecting too much when I say I should "be able to hit the setpoint on the nose". I hit .001, which is pretty close. And even if I extend my simulation out to 1e5 time steps it stays there solidly.

H> I'm building a robot that needs control better than I've ever needed to

Reply to
PhysicsGenius

Genius,

If you do the math, you will see that a linear system with an integrator in the loop makes overshoot inevitable. Overshoot is not only awkward, it wastes energy. Appropriate nonlinearity can eliminate overshoot from second-order systems at least, and thinking along those lines can lead you to better configurations than PID. For starters, read my blurb at

formatting link
Jerry

Reply to
Jerry Avins

The increments accumulated in the integrator approach zero as the position approaches the setpoint. If you build the integrator with an insufficient number of digits the integration will stall (accumulate zeros instead of infinitesimal increments) at some small error.

Reply to
John Popelish

I'm not an expert on this, but I don't think "number of digits" is a problem with Python. If you run the program I posted and view the output, you'll see a LOT of digits there. It seems more like it just gets locked in around .001.

Reply to
PhysicsGenius

I understand "overshoot" to be how much I go over and then have to backtrack (not an issue I'm having), not a consistent, stable error (the issue I'm having).

If by "an integrator" you mean an integral term, I don't understand that either. I thought it was the derivative term that addressed overshoot while the integral term addresses persistent offset.

Overshoot is not only awkward,

Since I can't even get PID working (or at least I can't tell IF I have it working), I don't think I'm prepared to go off into even more theoretical territory yet.

Reply to
PhysicsGenius

Possibly because in your "Step" routine you're adding 0.001 to self.yv after you update the positions? You're servoing quite nicely to bot.y_pos not changing, which is what you've coded for -- and bot.yv is zero before each call to bot.Step().

Just a note: While you're pondering careful coding habits, you should also ponder the difference between "lots of digits" and "lots of meaningful digits".

Reply to
Tim Wescott

Translation: "Since I can't even get the race car smoothly into gear, I don't think I'm prepared to mess with a sedan." PIDs are among the most difficult boxes to tame, particularly as most descriptions are as far off the mark as the belief that an airplane's throttle controls speed and the elevators control climb. (In the steady state, it's the other way round.) There are useful insights to PIDs in Tim's Wescott's article

formatting link
I hope you don't mean "Don't bother me with theory, I just want it to work." Unless you introduce non-linearities of the right sort, the integrator term guarantees that the response to a command step will include overshoot. The theory is simple: while the output has not yet caught up to the command, the error will accumulate in the integrator. An error in the opposite direction, with equal product of error and time, will be needed to restore the integrator to balance. This is entirely apart from the integrator's altering the set point (re-set) to compensate for steady-state loads. Two simple non-linearities can largely fix this: disable the integrator if the error is large and dump it entirely if the integrated and actual errors differ in sign.

The derivative term applies damping if the phase isn't shifted too far. that tends to damp out oscillations, but it can also slow the recovery from overshoot enough to cause equal overshoot in the opposite direction. When recovery from overshoot results in a new overshoot not less than the last one, it's oscillating. A loop in which not only the error but also the command signal is differentiated performs poorly.

Jerry

Reply to
Jerry Avins

So when the error is .001, what is the integrated increment in one sample period? It has to be a tiny fraction of that. Can you specify double precision for the integrator and see if anything changes?

Reply to
John Popelish

In this I have to disagree with Jerry -- until you can get a simple linear model of a PID working you shouldn't worry about non-linear controllers. So delete that line where you add in the 0.001 velocity...

Now, in the real world you can easily build a system that will not be unconditionally stable _without_ anti-windup. You do not have such a system here, so you don't have to worry.

Reply to
Tim Wescott

Genius,

Go with Tim, but remember what I wrote for later. I confess that I had overlooked your not having any hardware yet.

To change the topic, below is a deliberate example of accurate but dishonest excerpting.

Jerry

Reply to
Jerry Avins

I know what the program part is doing and what meaningful digits are. But shouldn't the error be building up in the integrator and eventually be wiped out?

Reply to
PhysicsGenius

I was under the impression that PIDs were the bread and butter of control and that your original link was caviar. Apparently that's not the case.

If I just wanted it to work without knowing how, I wouldn't be doing this at all. It's just a fun project with no practical aspect at all.

I understand each of these words, but not all put together. I found that embedded.com article when I was searching before and it was one of the most helpful, being targetted at programmers instead of engineerings. Are there any other sources that slant this way? Most of the tutorials I've found online assume I already know a lot of control theory jargon and math, which I don't.

Reply to
PhysicsGenius

Aha, so this is what he meant by non-linear. Well, the real object I'm going to be controlling is non-linear in this sense, so I guess I *should* worry about a non-linear controller.

"Anti-windup", eh? I guess I'll have to re- (and re-re-re-) read your article to figure out what that means and how to add it.

Reply to
PhysicsGenius

Jerry's link is one (fairly good) way to implement anti-windup in PID controllers. There are worse ways -- including the one in my Embedded Systems paper, but in that case I felt that an anti-windup scheme that was easy to understand was better than one that would generally perform better but add more memes to be absorbed (and words against an already crowded word count).

There are some other (hopefully) useful articles on my website -- in particular you may find

formatting link
to be useful, but don't let that stop you from reading the rest.

Reply to
Tim Wescott

Good

Yes, and it is. If you trace _carefully_ through the code you'll see that the integrator is just the right value so that when the Step() function is called the y velocity is zero -- but then the Step() function adds 0.001 to that y velocity, which is what you are seeing and wondering about.

It isn't a control problem -- it's a garden-variety bug in your code.

Reply to
Tim Wescott

Oh, I see what you are saying. I was thinking it wasn't a bug because in a real device an acceleration can happen at any time, so it doesn't matter where I put it. But the situation here is that I'm accelerating just before *printing*, which gives the *illusion* that the PID isn't working when it really is.

I guess this is why I did it in software first. Thanks for the tip.

Reply to
PhysicsGenius

I definitely need the lower meme count version.

Is there a version of the PID/PhD article with the images inline?

Reply to
PhysicsGenius

Not that I can distribute, unfortunately -- ESP owns the rights. When I get the chance I need to write a version that I can call my own and post properly.

Reply to
Tim Wescott

...

In the real world, events happen simultaneously. In software that runs on one processor, that can sometimes be an illusion, but never real.

Jerry

Reply to
Jerry Avins

PolyTech Forum website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.