How to use SParkPIDController

Hi, this is my first time attempting any FRC programming. My team is trying to program swerve and we’ve been unable to use the PID controller provided by the SparkMax’s. We were previously using a different class (which I quite honestly can’t remember), and it had a simple calculate method where you just gave the current encoder reading and the setpoint, and it calculated the output. But with the new SparkMax class (SparkPIDController) there is no equivalent of the calculate method. How would one actually get a value from the PID?
Here’s the setup for the pid in case someone needs it (I really have no idea what you guys might need to help, sorry):
pid = turnMotor.getPIDController();
pid.setFeedbackDevice(turnEncoder);
pid.setPositionPIDWrappingEnabled(true);
pid.setPositionPIDWrappingMinInput(kPidMin);
pid.setPositionPIDWrappingMaxInput(kPidMax);
pid.setP(kP);
pid.setI(kI);
pid.setD(kD);
pid.setFF(kFF);
pid.setOutputRange(kPidMin, kPidMax);

This is our method that sets the motors:
public void setMotors(SwerveModuleState state) {
if (abs(state.speedMetersPerSecond) < 0.001) {
stop();
} else {
current = SwerveModuleState.optimize(state, new Rotation2d(getTurnPosition()));
driveMotor.set(current.speedMetersPerSecond/kMaxMeterPerSec);
//set turnMotor here
}
}

With the other one we just did pid.calculate() with the encoder reading and the setpoint, but now there’s no such method. Please if anyone can help it’d really help (my team is waiting on us :sob:)

You’re correct that the SparkPIDController doesn’t give you a way to calculate the output - that’s because you instead set it to a target, and it will automatically command the associated motor itself. The method you’re looking for is setReference. You pass it a target value and a ControlType (i.e. kVelocity, kPosition), and it handles setting the motor outputs.

pid.setReference(1000, ControlType.kVelocity);
1 Like

Hi thanks for the quick reply! I’ve tried testing the code without doing anything and it doesn’t move. It worked (for the most part) with the previous class, is there anything that I can do to troubleshoot? Sorry for my lack of knowledge

Without seeing more of the code, my initial guesses would be:

  • Double check you’re not trying to control turnMotor from anywhere else - calling set, setVoltage, etc anywhere else could override the PID.
  • This looks like it’s for a swerve turning motor, so a better test may be using ControlType.kPosition (and make sure you change the 1000 to a reasonable position for your mechanism!)
  • Your kP value might be too low to result in any visible output.

You can try logging the value from the encoder on the motor and the motor output to see if it’s trying to move/getting any sensor readings too.

For the first one, there’s nowhere in the code that uses the set method aside from a reset method we made, but that shouldn’t be something we’re worried about.
The third one, it’s at 2, although I’m not sure how to tune a PID yet.
As for that second one, what do you mean change 1000?
Also is there any code you’d want to see? The SwerveModule class?
Thanks for the help you’ve been giving btw
There’s one thing I’ve noticed:
I’m putting the desired value on the smartdashboard, and when the setreference method is commented it out, it works fine. But when I use the setReference method, it starts changing values for some reason? I’m very lost…

The default conversion factor for position is 1 so using 1000 for your PID controller with the mode kPosition will mean the motor will perform 1000 rotations.

The 1000 in my example is the target (i.e. setpoint) velocity. For your turning motor, you want to update that to be the target position or angle you’re trying to move your turnMotor to, and then update the ControlType to kPosition

What exactly are you referring to by the “desired value”? If you mean the position/angle you want to use for the PID, that should be what you’re passing as the first argument to setReference.

To debug what’s happening, output the values of turnMotor.getAppliedOutput() and turnEncoder.getPosition() to SmartDashboard so that you can see if the motor is trying to move and what the encoder position is. Unless the encoder value is already at your target position, you should be seeing some motor output. Your P value of 2 should cause your motors to react extremely fast (essentially full speed towards the target).

Once you’ve gotten the PID working, WPILib has some great pages on PID theory and tuning, including this interactive example.

Yes, the desired value was the parameter for the setRererence sorry if that wasn’t clear. We’ve just wrapped up here but I’ll check on what you wrote tomorrow and test it out. Thanks for the help.