![]() |
PID code questions
In the pid code from First's "Navigation" sample, there is something I don't understand.
The integral error is combined with "pid_time", which is unfamiliar to me, I thought the integrated error (sum) should just used as is. motor_info[motor].pwm = (KP_P * motor_info[motor].pos_error) + ((KI_P * motor_info[motor].pos_error_i)/pid_time) + (KD_P * motor_info[motor].pos_error_d); This pid_time variable is reset when the target position (or velocity) is changed, but the integral value is not also cleared. Won't that cause problems? |
Re: PID code questions
I'm not 100% sure, but it seems like that's their way of guarding against integral windup.
In case you (or another reader) isn't familiar with integrator windup, From this website Quote:
By not resetting your integral term it seems like you're basically saying "I've been trying to reach my target for a long time, and therefore applying extra power" even though you're now moving to a new target. It feels like this should mess up your first cycle with a new target. It should correct itself on the second time through the loop when you recalculate your integral term, but it seems like you could have a huge overshoot on the first cycle. Consider this example. Code:
* Using Kp = 1, Ki = 1 for the sake of argumentCan somebody with a better understanding chime in to help explain? |
Re: PID code questions
Quote:
|
Re: PID code questions
Quote:
|
Re: PID code questions
Quote:
|
Re: PID code questions
Quote:
-Kevin |
Re: PID code questions
Everytime I see reference to a PID loop, I can't help but think it's a bit overkill for a lot of what we're doing. Control systems aren't my expertise so I'm not sure how accurate my statements are. At least for drive train applications, there seems to be enough friction in the system that you'd only need to use a proportional controller. Overshoot and oscillation just won't be large problems then. I say this because a proportional controller was working perfectly fine for us for driving to the tetra the other day. Is it just because the gain wasn't set very high? Or is it overkill?
Matt |
Re: PID code questions
Quote:
Last year we used on/off control (if left, go right; if right, go left....there were speeds for close/far) on our crab weels, which caused them to oscillate quite a bit when the wheels were not in contact with the ground. Our test was to try to get the wheel overshoot as little as possible in that configuration, while getting them there as quickly as we could. We started with simple proportional control. That worked fine, except for the fact that it was undershooting. This was because as the wheel got closer to the target, the speed slowed so much that the motor couldn't turn the wheels. To remedy this we added an integral control. This helped to give the motor the extra boost that it needed as it got close to the target. We added some derivative control just to see how it affected things, but didn't see significant difference. The way that it ended up being tuned when we gave up showed an overshoot of a few degrees, then locked into position. I'm sure that we could have gotten it to have less if we had spent more time on it. Getting back to Matt's question, when we had the robot on the ground, the added friction on the wheels helped things lock into place using simple control, but that same application without the friction needed the additional control. It all depends on the application and what kind of performance that you need. |
Re: PID code questions
Quote:
As someone else pointed out, dividing by a time term helps (but does not completely eliminate) windup. You are right, set_pos() and set_vel() really should clear the integral term. However, if you look at the way we used the code in robot.c, we always call set_pid_stop() which does clear all the terms. |
Re: PID code questions
Quote:
Well, not really. The gyro turn is not really a PID loop it is just turning until it moves to the correct orientation within an error band. We set the error band pretty tight so it overshot just a little. Check out cmd_turn() in robot.c. |
Re: PID code questions
Quote:
Plus now there are a few hundred more people out there that know that PID control is nothing magic. In fact its pretty simple stuff. Enjoy... |
Re: PID code questions
Quote:
|
Re: PID code questions
Quote:
If I'm calling set_vel() every 26ms from my Default_Routine(), am I destroying the I term of the PID control loop? Because I'm resetting pid_time so often? Would it be better to not reset pid_time? -SlimBoJones... |
Re: PID code questions
Maybe. It would be a simple matter to add a check so that if it's the same value as last time, don't do anything.
|
Keep your Eye on the I
I have not checked the code yet to see if this is in the standard code, but I urge everyone who uses the I part of PID to make sure you put in a term that does not let the integral term build up when the robot is disabled.
Before we had this feature, we had countless times where the robot would do an erratic jump up or down as soon as it was enabled. The problem was that if someone moved the arm or the controls when the robot was disabled and the robot stayed disabled for any period of time, the integral term would build up and then cause a step jump as soon as the robot was able to move. It was dangerous. It was spooky. And... ...we broke ourselve more that once as the robot thrashed around. The ghosts went away when we kept the integral term from building up when the robot was disabled. ACTUALLY, while I am on the topic, the most reliable method we had was to add two subrountines to our code: IveJustBeenEnabled() and IveJustBeenDisabled()* These two routines are good coding practice and should be part of the default code (imho). You'd be surprised how many robot freakouts are caused by folks not taking care of business when the enter or leave the enabled state. These two make integral wind up due to being disabled a non-issue: just zero the integral term as soon as you are enabled. While you are at it, perhaps you want to set the desired state equal to the current state until someone does something appropriate on the OI like maybe put their finger on the deadman button. Joe J. *These two have close cousins: IveJustEnteredAutonMode() and IveJustLeftAutonMode(), MatchJustBegun(), MatchJustEnded(), etc -- again these sort of routines should be required coding! |
Re: PID code questions
There's a simple solution:
Double-integrate the difference between the previous error and the current error, then (optionally) divide by time. And as for the reset, the I value should be reset at the same time as the time counter. |
| All times are GMT -5. The time now is 15:36. |
Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi