Linear vs Non-linear PID I values

This is going to be super technical, but I have always found the integral value of PIDs to be particularly problematic in VEX (velocity limited systems), and want to try and fix it.

A team member and I were discussing using non-linear models when adding error to the integral, like multiplying it by coefficients from a bell curve or piece wise function (or possibly just bounding it). This is to prevent integral spooling since the motors we use so quickly approach max velocity, and the derivative can never properly build to a useful value. When tuning using a linear model, we realized that either the integral was well tuned for only small errors or large errors, but there was no useful middle-ground.

Has anyone tested or found resources on altering how the integral is processed in their feedback loop? … or is this just over complicating things…

Fyi we currently multiply the error value before adding it to integral using a coefficient that is a (somewhat inverse) function of the derivative value, such that when there is a sizable derivative value, the integral is basically unchanged. Since there is no need for a running integral when the robot is in constant motion, we prevent the addition of values to our integral function, but still have the flexibility to rapidly affect the motor value when a small error is introduced to a nearly stationary system.

Considering a piecewise P-loop (constant minimum speed or typical P-loop) is sufficient for almost everything in VRC, I would indeed say a nonlinear model would be overcomplication. However, that doesn’t mean the concept shouldn’t be pursued, and I would be quite interested in seeing the results of this investigation.

Yes, those observations match out experience as well. And in order not to complicate things we try to stick with PID+C controllers similar to what @Barin said.

The trick would be to come up with the good value for “C”, sometimes called constant or holding power.

Since the PID comes up a lot around this time in the season, I don’t want to repeat here everything that was written in the older threads:

The quick summary would be that if you use pure PID to control your system, then “I” needs to estimate or “learn” amount of the resistance or power losses in the system that motors need to overcome. Depending on what you are trying to control, learning from zero could take a long time and may not even work for the wide range of target values using a single set of coefficients.

For example, estimating holding power for the arm holding weight at various angles is quite different from estimating “I” for drivetrain, where friction losses depend on the weight of the game objects that the robot is carrying.

My approach would be to use some sort of the feedforward model for calculating value of “C” or approximation for the initial value for “I” first, even if it gets you 80-90% of the way, and then use PID feedback controller to take care of the remaining 10-20%.

This way, in vast majority of cases, feedforward model takes care of the non-linear portion of the curve, and PID controller only needs to handle a small span around the target, which we could assume to be linear given the large tolerances that are acceptable for what we are doing here.

You didn’t specify in the original post what you are applying PID to, but since you mentioning large errors, I would guess that you are likely dealing with some sort of a lift where holding force would be:

f = sin(theta) * someCoefficient


similar to this example: The fabled PID - UNOFFICIAL Tech Support - VEX Forum

The simplest way to reduce the large errors would be to add feedforward controller based on the above formula.

Another approach would be to make the hardware as linear as possible (DR4B) with uniformly tensioned rubber bands (calculator), and then still model some physics, before handing it over to the PID.

One or some of the issues that you’re seeing may be partially due to the nonlinear relationship between motor duty cycle setting (the value you set the motor to in programs) and motor output speed. This can cause control loops to not quite behave the way you’d want depending on what speed they’re trying to run at (specifically low motor ouputs from {-40, 40} will cause spooling because they don’t move the motors). this thread demonstrates this issue and offers an approach that can help quite a bit.

Your approach to mitigating the integral component of your loops sounds interesting, but it does seem subotimal for preventing summing when a robot is in constant motion. I set up a summing band that I allow it to sum in. When its outside the bounds of the band it retains its value as opposed to resetting to zero. The right bounds for the bands and the correct gain seems to make my systems run really well with the benefit of having really a really clean and concise PID implementation.

Here’s a ROBOTC code snippet of the loop and data structure I use.


typedef struct {
	float Kp;
	float Ki;
	float Kd;
	float innerIntegralBand;
	float outerIntegralBand;
	float sigma;
	float lastValue;
	unsigned long lastTime;
	float lastSetPoint;
} PID;

float
pidCalculate (PID pid, int setPoint, int processVariable) {
	float deltaTime = (nPgmTime - pid.lastTime)/1000.0;
	pid.lastTime = nPgmTime;

	float deltaPV = 0;
	if(deltaTime > 0)
		deltaPV = (processVariable - pid.lastValue) / deltaTime;
	pid.lastValue = processVariable;

	float error = setPoint - processVariable;

	if(fabs(error) > pid.innerIntegralBand && fabs(error) < pid.outerIntegralBand)
		pid.sigma += error * deltaTime;

	if (fabs (error) > pid.outerIntegralBand)
		pid.sigma = 0;

	float output = error * pid.Kp
					+ pid.sigma * pid.Ki
					- deltaPV * pid.Kd;

	return output;
}

@technik3k I like your idea of adding a constant, and I will have to have our coders play with this idea to see just how it would work with everything. When it is finished we can set up sensors and use my digital physics lab equipment to measure the effectiveness of different coefficients for different stages of our process.

I like this idea of only allowing the integral to sum if it is within a band of values. It creates a more calculation-optimal and easy to understand solution. I will definitely work with our coders to investigate an appropriate band size. Thanks so much for these thorough answers.