How to do Characterization for velocity control for Spark Max and NEO?

It looks like the FRC-Characterization tool is mostly focused on drive train characterization. I’ve been searching here for velocity control for a flywheel shooter driven by Spark Maxs and Neos, which is what ours is. One thread said to use the Simple Motor project type for a flywheel velocity control. There’s another option for Brushless NEOs, but it looks like from that point on, it’s focused on a drive train use case.

How should I proceed to determine the PID constants for velocity control for a flywheel shooter driven by SparksMax’s and Brushless NEOs?

You can use the simple motor project to characterize the flywheel, but you’ll have to convert the gains from units the tool uses to units that the Spark Max uses.

This is pretty simple: rev/sec to rev/min is just divide by 60.

The units for the tool are volt-sec per rad (assuming we’re talking about the proportional gain here for reference). We converted this to the Falcon units per Prateek’s post here: Falcon 500 Closed Loop Velocity

I’m not sure what the units for the gains are on the onboard Spark Max velocity loop.

Well I know it functions in a time unit of minutes and dividing by 60 worked for us. Try it if you find that your motor is consistently maxing out instead of going the setpoint.

You might still be off by a couple factors, namely not converting radians to rotations (off by a factor of 2*Pi). I’m not sure if the output units of the internal loop is duty cycle [-1,1] or volts [-12,12], so you might be off by a factor of 12 there as well.

Of course, if both of these things are true, you might only be off by a factor of 2*Pi/12 = ~0.5, which given flywheel mass and a whole bunch of other factors, means that your system might behave acceptably well anyway.

EDIT: Looks like you can set your rotations unit in the characterization tool, so it may be in rotations or radians, adjust your unit conversion accordingly.

We have the same setup – fly wheel shooter driven by SparkMaxes and Neos, 1:1 gear ratio – and used the frc-characterization tool for getting the kFF and kP values for using the SparkMax’s Velocity closed loop feature.

Here is what I did; there may be a simpler/better way to do this:

  1. $ frc-characterization simple-motor new
  2. Select Project Type: “SparkMax (Brushless/Neo)”
  3. set “motorPorts” values to the CAN ids of your motors
  4. Set “motorsInverted” : [False, True]
    This may be different in your case if both the motors are mounted in the same direction. Note that second value is relative to the first value.
  5. Set the team number, save the config, and Generate Project.
  6. Deploy Project & Launch Data Logger
  7. Launch Data Analyzer:
    a) Make sure Units is “Rotations”, Gain Settings Preset is “Spark Max”, Controller Type is “Spark”, and Loop Type is “Velocity”.
    b) Click on “Analyze Data”
  8. You will get 5 values – kS, kV, kA in the left pane and kP and kD in the right pane.

In the code, you have to calculate kFF and kP values for SparkMax’s (master) CANPIDController (we used zeros for all other parameters).

kP is one time calculation:
kP_RPM = char_kP_RPS / (kMaxVoltage * 60)
char_kP_RPS is the kP output from characterization tool. I used 12.0 for max voltage.

kFF is calculated using WPILIB’s SimpleMotorFeedForward class every time velocity setpoint is changed,:
m_feedforward = new SimpleMotorFeedforward(kS, kV, kA);
m_kFF = m_feedforward.calculate(m_velocitySetpoint / 60, kMaxRPM / 60) / (kMaxVoltage * kMaxRPM);

I used max rpm of 5700.


We set to rotations and after doing time conversions it is holding within 0.001 RPM of the setpoint. Or so the readout says.

Yeah that definitely seems suspect. In my experience a good flywheel controller is going to be +/- 20-30RPM, and at that point it won’t be the limiting factor in your shot accuracy.

1 Like

Keep in mind this was after leveling off and before we put any balls in. And I was just using smff.

Yeah, there might be some sort of resolution or discretization bug that you’re seeing. Could be related to how fast you’re sampling for velocity as well.

An example of this, say you have a flywheel geared 1:1 on a Neo, and to measure velocity you are sampling every 100ms (this seems to be the default value for kEncoderSampleDelta on the Spark Max). The Neo has 42 counts per revolution on it’s internal encoder. If your wheel moved the minimum detectable amount during one sampling period (1 count), then you’d measure 1/42 rev / 0.1s, or about 14.3 RPM. There are some things you could do with filtering to improve this resolution, but this is a good napkin-level calculation of the upper bound on how accurate it’s possible for your control loop to be.

I knew it was too good to be true :slight_smile:

Thanks very much for this detailed response. Unfortunately we’re having a deployment problem with the characterization project, which I’ve put in another post. Sigh.

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