Issues with Single Motor Flywheel PID controller


Our team (13765U) have been working on trying to implement a PID controller for our single motor flywheel. This is my first time using PID controller so I have spent the last week learning about the concept of PID’s and how to implement them. I have got to the point were I have a coded PID but we have run in to some issues. What happens is the flywheel starts to accelerate and then there is suddenly a loud vibration and grinding sound. After the ‘grinding’, the flywheel slows down significantly and then speeds up to similar RPM before ‘grinding’ again. Throughout all of this, the flywheel never reaches the desired 500rpm (about 460rpm when ‘grinding’ starts). I have read every forum I can find as well as every video but nothing that I have tried has helped. I am not sure if it is an issue with my code or if it is to do with the tuning. I am now at a dead end on what to do so I was hoping that someone could help us out.

Thanks in advance.

Here is the code:

float kp = 0.75;
float ki = 0.0075;
float kd = 0.2;

//PID variables//
float targetFlywheelSpeed = 500;
float error = 0;
float lastError = 0;
float totalError = 0;
float derivative = 0;
float P = 0;
float I = 0;
float D = 0;
float current = 0;
bool runFlywheelPIDLoop = false;
float currentFlywheelVelocity = 0;

void flywheelPID(void)
  while(runFlywheelPIDLoop == true)
    currentFlywheelVelocity = (FlyWheel.velocity(rpm));
    error = targetFlywheelSpeed - currentFlywheelVelocity;
    derivative = error - lastError;
    P = error * kp;

    if(error < 15 && error != 0)
      totalError += error;
      totalError = 0; 

    I = totalError * ki;
    D = derivative * kd;

    current = P + I + D;
    FlyWheel.spin(forward, current, volt); 
    lastError = error;
    error = 0;
    wait(20, msec);

The PID outputs the change in voltage, but you have it just as voltage. This means when you get close to the target speed, the PID outputs a smaller value because it knows you are close and shouldn’t speed up as much, but this results in your flywheel speed decreasing.

current = P + I + D;

should be:

current += P + I + D;
1 Like

Thanks for your suggestion. It helped to reduce vibrations slightly although they still occur. However, now the flywheel is reaching a higher rpm (around 600 which is higher than our target) and then vibrating causing the flywheel to deaccelerate to well below the target of 500rpm. I will try and mess around with the constants to see if anything improves but unfortunately the problem remains.

That would be a velocity which would technically work. Another approach would be to use a ff forward constant. In order for your PID to work effectively you need a feedforward value based on your target to make sure that if your error is zero your speed is not zero. Basically:

F=1.2*targetSpeed; //1.2 is a baseline for percent to volts adjust it to be whatever voltage you need to achieve a speed
Current = F+P+I+D;

1 Like

Thanks, however our issues definitely don’t cone from hardware. We run a blue motor overhead flywheel on a 1:3 gear ratio and running it at 100% worked just fine.
My theory (although I’m probably wrong) is that when the rpm goes over the target (because the target is not the max rpm the flywheel achieves), the PID calculates a negative voltage because the error is negative and so tells the motor to spin the other way, hence causing the vibrations. If my theory were to be right, would I solve this by tuning the constants to make sure it doesn’t overshoot or is there another way?

1 Like

I will definitely implement this. Thanks.

The P term in PID is based on how close you are to the target, so think about how big it would be in these situations:
Big error: The P term outputs a big value
Small error: The P term outputs a small value
So as the flywheel speed approaches the target speed, the output of the P term will go down, so the output of the PID will go down, so you move the motor with less voltage, so it starts getting slower despite not having reached the target voltage.
This also explains the “grinding” described by the OP, if the flywheel speed > the target speed, the error becomes negative, so the output of the PID is negative, so the flywheel tries to spin backwards, resulting in fast deceleration, making error positive, so it has fast acceleration. This would repeat very quickly causing the “…loud vibration and grinding sound”.

You probably just need to tune your PID more to fix this, or it could be a hardware problem like Tropical said

Hi so I am also part of 13765U and it is not a hardware issue, the flywheel is a blue motor with a 1 to 3 ratio to the flywheel. the vibrating noise it makes is the motor spinning in reverse, however the flywheel has to much inertia so it just jumps on the gears. the flywheel will spin up to 100 percent, and draws at max 10 wats when firing normally around 5. hopes this helps answer our question.

This is more complicated. There are definitely formulations of velocity PID that have an “outer integral” using the PID output as a delta in voltage. I am actually not sure in industry when controlling a flywheel which is the standard formulation. Its weirdly something people are not explicit about.

There is a logic to having the outer integral, it makes the results map to a more traditional driving straight PID.
P only will result in oscillation.
D helps alleviate the the oscillation because it damps changing velocity too quickly

And using feedforward is not exclusive to any formulation.
voltage = PID + ff
voltage = integral(PID) + ff
voltage = integral(PID + ff)
Though the third option admittedly seems a bit strange without some sort of motion profile.


That makes a little more sense. I suggest logging the voltages outputted by the PID controller to the VEXcode console and checking to see how much negative output is being applied.

You can do this in your while loop:

printf("Output: %f\n", forward);

Which will log the data to VEXCode’s terminal tab. From there, i’d look at how many negative volts are being applied. If its a very high negative number, then it sounds like its a tuning problem (kP too high causing oscillations of high magnitude, or kD too high most likely).

To clarify: By “very high negative number”, I mean numbers approaching or below -12, which is the maximum negaitve voltage that VEXcode allows motors to run at.

You might want to try using TBH instead of PID for your flywheel. It’s easier to tune, performs better in velocity control, and this is all there is

double error = rpm;
	double prev_error = rpm;
	double output = 0.0;
	double tbh = output;
	double gain = [some gain to tune];

		double currentSpeed = flywheel->get_actual_velocity();
		error = rpm - currentSpeed;
		output += gain * error;
		if (std::signbit(error) != std::signbit(prev_error))
			output = 0.5 * (output + tbh);
			tbh = output;
			prev_error = error;
	} while (std::abs(error) > 25.0 || std::abs(error - prev_error) > 20.0);

The last condition

(std::abs(error) > 25.0 || std::abs(error - prev_error) > 20.0)

just keeps the loop running if the RPM’s not there yet or it hasn’t settled (change in RPM is too high).