PID Problems

Recently I programmed a PID controller in RobotC for a two turbo motor single flywheel launcher. While the PID itself has increased its spin-up rate, it has had a few kinks. The main two problems with the PID is that it is not taking the kp ki and kd into affect and is instead using a value other than the ones I have set, along with that it is also not using the target Rpm that I set for it instead it is using a value that I cannot see. Here is my code if anyone has a few suggestions on how I could fix these problems they would be greatly appreciated.


// in pre auton
void launcher(int speed){ // Function for apply the determined speed
	motor[launch1] = speed;
	motor[launch2] = speed;
}

float velocity;
task VelocityMeasure //My velocity measure task runs constantly
{
	float prevelocity1;
	float msvelocity;
	SensorValue[ncoder] = 0;
	wait1Msec(100);
	prevelocity1 = SensorValue[ncoder];
	wait1Msec(100);
	msvelocity = (SensorValue[ncoder] - prevelocity1)/200;
	velocity = msvelocity*60000;
	}
float target; //target Rpm
task PIDlauncherControl() // The PID task
{
	float Kp = 1;
	float Ki = 1;
	float Kd = 1;
	int error;
	int proportion;
	int integralRaw;
	float integral;
	int lastError;
	int derivative;
	float integralPowerLimit = 100; //The integral limit
	int finalpower;
	while(true){
		error = target-velocity;
		proportion = Kp*error;
if(error != 0){
			integralRaw = integralRaw + error;
		}
		else
			integralRaw = 0;
		if(integralRaw>integralPowerLimit)
			integralRaw = integralPowerLimit;
		if(integralRaw< -integralPowerLimit)
			integralRaw = - integralPowerLimit;
		integral = Ki * integralRaw;
		derivative = Kd*(error - lastError);
		lastError = error;
		finalpower =+ proportion + integral+derivative;
		launcher(finalpower);
		wait1Msec(200);
		}
	}
// the rest is in user control
startTask(VelocityMeasure);
		if(vexRT[Btn8D] == 1){
			stopTask(PIDlauncherControl);
			motor[launch1] = 0;
			motor[launch2] = 0;
		}
		if(vexRT[Btn8R] == 1){
			target = 100;
			startTask(PIDlauncherControl);
		}

I don’t really know, but is it possible that your mixed use of float and int might be causing some math errors? For example, you declare

float Kp = 1;

when maybe it should be
float Kp = 1.0 ;

Also maybe what could happen: if you assign the results of a calculation to an integer, and the calculation is using floats or results in decimals, perhaps the result is being rounded off?

Thank you for your response I’ll try that

Why would you want float instead of int? Wouldn’t int Kp =1; work and save space?

So I read through your program and it implements a velocity PID loop and I’m not sure what is the problem. Can you clarify your symptoms? When you say that kp isn’t used do you mean if kp ki kd are all set to 0 that the the motors never turn on? Can you also include the top ROBOTC generated motor information?

Programmers might want Kp as a float because they might want to tune their PID later on. Tuning the PID might require the K values to be non-integers.

The problem that i have found with my PID is that I can not tune it or change the target Rpm as long as the kp ki and kd are all above zero the number I change them to has no affect on the PID also no matter what the target value is it always spins at the same speed. However if I set the K’s equal to zero the launcher does not turn at all.
Here is the motor and sensor info


#pragma config(Sensor, dgtl1,  ncoder,         sensorQuadEncoder)
#pragma config(Sensor, dgtl3,  ultrason,       sensorSONAR_inch)
#pragma config(Motor,  port1,           frontL,        tmotorVex393HighSpeed_HBridge, openLoop, reversed)
#pragma config(Motor,  port2,           launch1,       tmotorVex393TurboSpeed_MC29, openLoop, reversed) 
#pragma config(Motor,  port3,           launch2,       tmotorVex393TurboSpeed_MC29, openLoop)
// the two launcher motors
#pragma config(Motor,  port4,           intake1,       tmotorVex393HighSpeed_MC29, openLoop)
#pragma config(Motor,  port5,           midR,          tmotorVex393HighSpeed_MC29, openLoop, reversed)
#pragma config(Motor,  port6,           backR,         tmotorVex393HighSpeed_MC29, openLoop)
#pragma config(Motor,  port7,           midL,          tmotorVex393HighSpeed_MC29, openLoop, reversed)
#pragma config(Motor,  port8,           backL,         tmotorVex393HighSpeed_MC29, openLoop)
#pragma config(Motor,  port9,           intake2,       tmotorVex393TurboSpeed_MC29, openLoop, reversed)
#pragma config(Motor,  port10,          frontR,        tmotorVex393HighSpeed_HBridge, openLoop)

Give me an example of what velocity you were seeing on the ROBOTC debugger.

Or what gear ratio do you have between the motor and the encoder?

Edit:Also your velocity calculations are wrong by a factor of 2. So I think your code is pretty much always seeing the error as huge.
Try changing the divide by 200 to be divide by 100.

The encoder is up at the top of the wheel which is a 9:1 gear ratio from the motor do you think I need to be dividing the encoder value by 9 and the reason the motor is turning at max speed is because the PID is calculating the power to be nine times what it should be for the target because of this gear ration and the motor is taking the large value and changing it to its maximum power?

I just changed the 200 to a 100 and set the target to 10 but it was still hitting at the same place as when the target is a 100

Okay so knowing it is 9:1 try setting target to 300 and making
Kp 0.1
Ki 0
Kd 0.
The velocity at unloaded full speed should be several hundred so error is going to be incredibly large. A kp of 1 would mean run at well over full power.

Just tried it and the launcher speed changed for sure, then i moved the target to 600 and it increased thanks for the help I am going to try to tune it now and find the right target thanks for all the help !

I noticed in your code that you had:

I think you meant:

But I’m glad that you have the syntax error. Don’t do a += with your PID output power. It should be:

Also, don’t do this:

For your flywheel, it completely kills the integral when you actually get to speed. The integral is what will keep you accurate and not battery level dependant.

Everything you say here does not really apply.
Power += is exactly what you would want for a Velocity PID controller. If you did not then 0 error would make you run at 0 power. 0 error should make you not change your power. Also the extremely rare case that error=0 you don’t want integral to keep adding on power to your flywheel.

Little calculus explanation. Velocity is derivative of position so you need to take the integral of your pid output to get power. Read integral as sum.

I understand the Calculus.

It definitely applies, it doesn’t matter if it position or velocity, I went through all of this here:
https://vexforum.com/t/pid-controller-help/30718/1

The only way to get 0 error is to have the integrator wind up to the motor value that gives you 0 error. However, using += moves the integration to the the motor power variable and ruins what the PID was supposed to do.

The problem is that it makes the traditional way everyone is being taught to tune PID awkward. That is, start with Ki and Kd at 0, find a value of Kp that works, etc. I’m not disagreeing that the idea works, and I still have not done a comparison on a real system, it just seems easier to think of the control value being a delta from some nominal motor drive value.

Perhaps you could do a tutorial with a real flywheel and explain how the initial constants were chosen and how you tuned from that point.

Collin does a nice job of showing each piece of the PID in his paper. There are a lot of ways to tune a loop, but the method shown in his link is a good start. D can sometimes be a great noise generator so I really don’t use it that often, it just depends upon the response time you are looking for. Definitely take a look at the graph showing what happens to the P, I and D terms as you approach steady state. I is the term that allows the constant velocity you are looking for.

It shouldn’t really be different, except that the += method has the Coefficients mis-labeled. For a beginning team with just flywheel control, start with P, take the gain up until it oscillates, back it until it doesn’t (plus some), then add I and adjust it’s gain until you get pretty good response, within a second. This is all just a starting point,

Of course, all of this depends upon the sensor type and the gear ratio.

I’ll try to put together an example from our flywheels

Remember that it is really Out = P+I+D+C, so if you have pre-knowledge about a nominal power, you can put it into C. Otherwise the I portion will learn it over some time period. If you put a C in that is too large, then I will end up negative, which isn’t a bad thing.

+= is not what you would want for a Velocity controller. As an example for this, just use Kp, let Ki and Kd = 0. In the += implementation, the output will come up to a value that gives you 0 error because it accumulated. This should never be the case for a P only controller. It will always have error unless it has an infinite gain, since Out = Kp * error. What is done in the += case of this is that you call it Kp, but it is really Ki.

In the proper case of Out = PID, why would 0 error make you change your output power?

Thank you Tabor, Jpearman, Tri-Dragon, and everyone else, all your suggestions have helped me fix the errors so the PID is currently working, but any other suggestions you might have on how to improve my PID code would be greatly appreciated!