PID Issue

We are trying to use PID on LabVIEW for the first time, and are having difficulties getting it to work. I’ve read the tutorials and threads, so I understand how it’s supposed to function. We have encoders on the left and right wheels of a tank drive practice bot. We convert the rotation rate of each wheel into a linear speed in inches/sec. We feed that into a PID as the Process Variable. On the Front Panel of Teleop, we have a control to enter the desired speed for each wheel as the Setpoint. We set the maximum output to +/- 1, and feed that into a Tank Drive. A screen shot of the code is attached.

We put both Setpoints to 25 in/s, which is about one rotation per sec. When we set all 3 gains to 0, the wheels don’t turn (of course). When the P gain increases above 0.003 the wheels begin to turn slowly, but not at the Setpoint. When the gain gets above 0.007, the wheels ramp up directly to full speed (+/- 1); the encoder velocity (process variable) goes to about 250 in/s. Its basically all or nothing. Adjusting the Setpoint higher or lower has no effect. If the P gain goes above 0.2, the wheels switch rapidly between +1 and -1, flipping back and forth. Adding gain to I or D only makes matters worse.

Clearly there is too much gain if we’re maxxing out at P=0.007. The robot is on blocks, so there’s no real load on the wheels; shouldn’t it work anyway? (We don’t want to put it on the ground when it’s acting crazy.) Do we leave the dt(s) input empty? Is there something else we are missing?

Any advice would be appreciated. Thanks.

Placing the robot on the floor might surprise you with how well-behaved it becomes. You’re trying to tune a velocity PID when the system is essentially unloaded. As you have discovered, such a system is very unstable. There is not enough damping to keep it from immediately overshooting the set point and oscillating wildly.

If you put some load on the wheels, you will get much better results. You could also try to introduce some artificial inertia into the system by limiting the rate of change of the motor commands.

This makes me think you may have a sign issue in the math. ** Do not set it on the floor until you check for this** or else you might damage something or someone.

Run the test you described above again and compare your axis value and your rate value. Do they have the same sign (i.e. are both positive or both negative?). If they have different signs, your controller will become unstable (i.e. the speed will quickly ramp up to full speed). In this case, you will need to negate the encoder rates, then try again. The controller should become well behaved after that.

One other thing: are you scaling the axis values from -1 to 1 to a value in in/sec?

Thank you both for your reply. I will check the +/- sign on the controller first, and if that doesn’t fix it, I’ll put it on the floor and see if it tracks better. I can’t do it until Saturday, but I’ll let you know how it turns out.

We currently aren’t using the joystick with the PID, only target numbers entered from a control on the front panel. If/when we do add the joystick, we will do a conversion, as you suggest.

I didn’t look closely enough at your code before, but now I see that you might have a fundamental problem. Think about what happens when the wheel speed matches the rate you’re commanding. What’s the output of the PID function going to be?


That’s not what you want to tell the motors. I think the simplest fix would be to “integrate” the output of the PID in order to make things work right. Instead of feeding it to the Tank Drive directly, use the PID output to add to or subtract from the motor speed command. That way, when the feedback and setpoint are the same, the motor will continue at its current speed.

Another way to do it is possible, but it isn’t as simple to implement when using the “Academic PID” that LabVIEW provides.