PID Tuning for CANSparkMax

Our team is using NEO integrated encoder for our flywheel shooter and it is working fine. We used SysID to tune the values, and although the actual RPM reading may be inaccurate or delayed it is very consistent and that’s what matters, right?

Stable feedback gains for the integrated NEO encoder are small enough to be almost negligible; you’re running nearly pure feedforward.

An external encoder hooked up to the limit switch pins per the instructions on REV’s instructions, or hooked up to the RIO (this will require running PID control on the RIO, as well).

1 Like

Hi ohowe,

Could you walk me through how you guys tuned the PID using SysID. That would be a huge help.

Thanks,
Shaunak Sinha

SysID can be found using the launch tool menu in VSCode. For the flywheel you probably want to use the general mechanism config, Configure your SparkMax with CAN id, invert, and gearing (make sure encoder port is selected, not data port for encoder). Deploy and run all the tests as instructed. You can then analyze that data by loading the JSON file that was just created. The documentation page is very helpful while doing this (especially because I probably missed something). Those values then can be used with the SimpleMotorFeedforward class and PIDController in WPILib. You can change this to the onboard PIDF but you would have to do some unit conversion.

Hi Ohowe,

Thank you so much for this help, it really means a lot to me and my team.

I just have two questions if you don’t mind:

  1. Does sysid automatically generate the PID values for us or do we have to manually go through and change each value until we get the proper PID Values.

  2. If I want to set the PID values generated from SysID into the revsparkhardware client or using the CANSparkMAX PID controller would I have to do a unit conversion? If I do, do you know how I would do the unit conversion?

Once again, thank you so much for the help, it really means the world to me that your helping us out.

Thanks,
Shaunak Sinha

  1. Yes it does. The P value may require a bit of tuning however but in my experience it has worked “out of the box”.
  2. Looking at it I think it would just be dividing by 12 for the feedforward values as it is in volts and SparkMaxPID uses -1 to 1 but I haven’t tested it. I’m sure @Oblarg would know this as he is one the developers for SysID.

Thank you so much ohowe! I’m sorry for all the questions but I just have two more questions:

  1. To set up SysID, am I able to launch it via VScode like the same way you can deploy code to the robot?

  2. We have two NEO motors attached to the flywheel so do you think that would affect our PID tuning? If so do you have a recommendation on how we can go about this?

Thanks so much for the help, I truly appreciate it

  1. For launching SysID enter the command palette with Command+Shift+P and search start tools. Choose the WPILib: Start Tool option. Select SysID.
  2. You can add multiple motors in SysID so you should be able to characterize both of them (it will give you one pair of gains).

Ok thank you so much for the help! I will try and work on PID in the following days so is it ok if I could contact you for more help later on?

If that’s the case, could I get away with characterizing our shooter with external encoders to get accurate feedforward constants but then using the internal neo encoders during the actual match with a small kP?

There’s no need for external encoders for the characterization routine. You can shrink kP to make the response stable but the kP that works is so small that it does very little.

External encoders will fix the problem if you use them for feedback.

Oh, so they would give basically the same sysid feedforward values as the internal ones would?

Yeah, I am just trying to avoid having to wire those all the way to the shooters on our turret lol

@Oblarg, could you elaborate a little bit more about what you mean by “due to the hardcoded measurement delay”? PID control of a flywheel using the NEO integrated encoder was exactly what we were aiming for.

p.s. I’m a professional software developer, but do not deal with hardware/robotics outside of FRC. Thanks.

The SparkMAX has a hardcoded firmware filter that it uses to process the signal from the NEO’s internal hall effect sensor for the reported velocity readings. That filter introduces ~110ms of measurement delay.

If you hook an external encoder up to the limit switch pins on the SparkMAX you can reconfigure the filtering settings (they default to ~80ms of delay) to reduce it down to as low as 1ms (though encoder resolution may make this impractical).

In my own words: a flywheel spins too quickly for the internal encoder to be used as a reliable feedback sensor. Because of the filter, the velocity readings using the internal encoder is probably off by a medium-to-large factor.

But the internal encoder is fine for position closed-loop control.

Something like that… :slight_smile:

1 Like

Yep, that’s pretty much it. SysId can estimate the time constant of your flywheel so you can compare it to the signal delay (it estimates the signal delay, too).

1 Like

See this thread for a potential work around if you still want to use the internal encoder for velocity

Ooof. That’s a lot of information to digest for a Wednesday night. I’d take a summary :slight_smile:

I’m bookmarking the thread @FRC6302 . We still have several programming tasks to complete before our event in Montreal. Thanks for the tip.

So basically the work around is to bypass the hardcoded firmware filter for velocity readings by estimating the velocity using a delta in the position of the encoder, the standard main loop period, and a moving average.

In addition, a separate (Java) thread can be used to increase the frequency of the sampling.

Yeah basically. And you’ll get better results if you combine it with a state space model of your flywheel because it will account for the noise somewhat.

You can see my code here if you’d like:

I have a method in my Shooter subsystem that updates the velocity and then I call that method every 10 ms in Robot. I haven’t tested it yet though.

The only reason I am doing all this is so that we don’t have to hook up an external encoder to our shooters, which are on our turret, so the wires would have to be really long. So that may not apply to you

1 Like