SparkMax PIDControl not working

I’m trying to get PID velocity control and it doesn’t work. I have even built this simple code and it still doesn’t work. Can you identify the issue?

1 Like

Without any gains, you’re telling the controller to output nothing.

Start with FF, raise that until the velocity is near your target (use some sort of a plotter to verify this). Then add PID as you need.

1 Like

How much do I raise it by?

1 Like

Your P, I, D, and FF are all 0. Therefore your actual input will be zero, and the motor will si
t still. You have to set the coefficients to something that will make your motor move.

Anticipating a future problem, that has afflicted me and several others who have posted to Chief Delphi, to get close to where you want to be, you either have to have an accurate FF, or some value of I. However, I also note that you have set your limits to (0,1), so I’m guessing you might be doing what I (and others) are doing, which is basically going full speed until you get close, and then coasting. In that case, use FF to get just under your target, and a fairly high value of P.

I’m in the process of tuning ours, but for our first event, I had a P of 0.1, which basically meant that it was going full speed until I got within 10 RPM of the set point. That was a bit too high. There was a lot of oscillation, so I’ll work on that before competition number 2.

1 Like

It depends on the setup on the process variable and control variable that REV accepts (I’m only familiar with the CTRE ecosystem). Start very small (enough where it may not even move), like 0.1 or 0.01, and half or double that number until you’re at least near the right order of magnitude.

I wouldn’t recommend integral gain for velocity control or someone who isn’t familiar with PID control.

The FF is typically the anticipated value that would be needed to hit your set point.

In other words, figure out how much the input has to be to get to your intended speed by using the client software. Just move the duty cycle between 0 and 1 until it gets to your desired speed. Whatever duty cycle that is, that’s your FF.

1 Like

I updated the values to the following but the motor still does not move. I can move it using .set but .setReference is not working.

shooterPIDController.setP(0.1);
shooterPIDController.setI(0);
shooterPIDController.setD(0);
shooterPIDController.setIZone(0);
shooterPIDController.setFF(.1);
shooterPIDController.setOutputRange(0, 1);

A possible problem, and I emphasize possible, is that I see SetInverted(true). That really ought to work, but I am told that there is a strange thing about the spark max controller, which is that when it is set to inverted, the motor spins one way, but the encoder still counts as if it is not inverted. Meanwhile, the lights flash based on the input, not based on the inverted input. Anyway, it’s confusing.

And I don’t know what it does with set points.

But I do know what I did with our shooter motor to make it work. Ours is, also, inverted.

Instead of inverting the motor, I set my setpoint to be negative, and my output to be between -1 and 0, and my FF value negative. So your code would be

shooterPIDController.setP(0.1);
shooterPIDController.setI(0);
shooterPIDController.setD(0);
shooterPIDController.setIZone(0);
shooterPIDController.setFF(-0.1);
shooterPIDController.setOutputRange(-1, 0);

and then
shooterPIDController.setReference(-5000,ControlType.kVelocity);

and get rid of the setInverted(true) call.

It might be deciding that it really needs to apply -1 to get where it’s going, but it can’t because its min is 0. I don’t know if this is the case, but I know that’s what I did to make it work on our robot. As soon as I get a chance to test, I’ll figure it out, but our robot is currently disassembled for repairs. (No Bag Day really changes the way the season plays out.)

Oh, and, about that 0.1 in the P value…start with something smaller, just in case your motor setup doesn’t like full speed. Ease into it. Those values will have it at full speed until you reach 4990 RPM.

Interesting idea. I’ll try reversing the values and see what I get. I’ll have it try on Monday and I’ll let you know.

Take a look at our Velocity Closed-loop Control example: SPARK MAX Example Code

setInverted has worked perfectly for us, and should not behave as you described. I would not recommend doing this.

1 Like

Hey Rev, I have used your examples but it isn’t working. I’m sure this is user error somewhere but I can’t figure out why. Can you look at the code above and see the issue?

What do you recommend doing?

Well, it was a “might”. We made several different changes over the course of a few hours, and eliminating setInverted and using the negative numbers was the one that ended up working, but it followed quite a few other experiments. When my shooter is back together, I want to shift it back to setInverted, because the negative numbers aren’t nearly as intuitive.

A couple thoughts to help you debug:

  • Check the firmware: If you’re on a firmware below 1.5.1, things get weird and you probably can’t talk to the motor correctly.
  • I believe theshooterLeftMasterMotor.restoreFactoryDefaults();sets the can ID to zero. It’s likely you need to use the Rev Client over USB and reset the ID if you ever ran this on the motor.
  • Remove the shooterPIDController.setOutputRange(0, 1); until the shooter is moving, and add it back in later.
  • You need some sort of closed loop values for this to move. A good test value for F value is 1/5700.0, which is max output divided by the max free-speed of the Neo. If you feed it a reference of ~1500RPM, this gain will generate ~25% motor output. These values should get things moving so you can confirm the system is operating.

I figured it out!! Again, stupid user error. The problem was the CANSparkMax were instantiated with the word “final”. Final prevented the changing of any values. Removed “final” and everything is working now.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.