Bang-bang using Talon-SRX and PID for a Shooter

Is this possible to use the Talon-SRX with a bang-bang algorithm so that the Talon checks the encoder value?
The encoder is connected to the Talon directly.
I want to do this in order to sample the encoder in a faster rate than regular code.

and another question:
What is better for getting a shooter to the target speed faster - Bang-bang or PID (using Talon SRX)?

Thank you.

Probably depends a lot on the mechnasim it’s attached to, and how precise you need it’s spin to be.

For instance, we have a 5 lb wheel that we have a CIMcoder + miniCIM running off a talon. When we remove power and leave the talon in coast mode, it maintains it’s speed pretty well (until it has any load obviously). It also takes a fair bit of effort to spin it up, so the bang-bang type method might actually be the preferred method. Functionally - I’d argue this is pretty much a crude PID control with a high P.

If you have a mechansim without that much inertia, under a higher load, or that you need more finely controlled - then PID is definitely a good way to go. I can say first hand that the talon has a lot of good documentation for Java. I think it does for Labview and C++ too: https://www.ctr-electronics.com/Talon%20SRX%20Software%20Reference%20Manual.pdf

It is also possible to simulate a bang-bang controller using PID, by setting the P gain very high and limiting the output so the motor can only try to move in the desired direction. This can be done using the Talon SRX API.

I’d assume that bang bang would theoretically spin up faster since it spins at full speed until it hits the target speed. However, when I tried it, when it got up to speed, the motor started making nasty noises when flickering on and off.

I found the PID + Feedforward (built into the SRX) to work great on speed control. In fact, I got great results with purely P and F. It spins up fast, goes right to the target speed, and doesn’t make the same disconcerting noises that I experienced with bang bang.

I guess the results of bang bang vary from system to system.

This is what we are currently using, though I have some experimental code that uses the pseudo-bang-bang I described before. Ours sits around ±50 RPM from the target, which turned out to be good enough for our shooter.

Also, this paper and its discussion has some good information about shooter control: http://www.chiefdelphi.com/media/papers/2663

*Bang-bang can be a good solution to shooter wheel speed control, but if you’re using the SRX via CAN with the encoder plugged into the SRX, I’d say definitely use the SRX’s built-in PIDF speed control, which updates at 1KHz (far faster than roboRIO does PID).

I’ve heard this happen when the motor controller was set to brake mode. Another possible reason: to much free play between motor shaft and wheel (gearbox, chains, etc). See this post.

Seconded.

Also, bang-bang control doesn’t have to modulate speeds from 0-1. One could modulate from 0.8-0.9, for example.

Yes, if you know for sure that that range is sufficient for all loads and tolerances you are likely to encounter.

And of course, setting upper and lower throttle levels removes the “no tuning required” advantage of bang-bang.

And limiting the upper number to anything less than full throttle removes “fastest spinup and recovery” argument for bang-bang.

All valid points, of course!

Perhaps the more useful parameter is the lower throttle limit, which would slow any oscillations in the system.

Agreed. In systems that

a) have insufficient inertia or excessive friction or windage,

and

b) are already running the controller as fast as practical

I have recommended trying that.

We are running a simple Bang-Bang in Java this year.
We are using separate thread to control the wheel. It measures the period of a single flag on the shooter wheel. We have two 775-Pro driving the wheel with a 60:19 reduction.

Here a a couple “gotcha’s” we encountered.
A 10ms control loop is too slow with this set up. Way too much overshoot. We went with a 5ms loop and overshoot is tolerable.
Running 2 775-Pros is overkill!
We run ours with one breaker removed for one of the motors. This helps reduce overshoot and gives us a backup in case something terrible happens.

Please provide more detail how you are obtaining the period.

For example:

a) sensor is configured as a counter object, and the 40MHz FPGA is giving you an exact period via getPeriod() in WPILib,

or

b) you are counting wheel revs, and dividing that into your nominal thread period,

or,

c) you are counting wheel revs, and dividing that into your measured thread period,

or

d) something else?

I ask because bang-bang does not like phase lag and/or jitter on your speed signal.

DISCLAIMER: I am not a Java programmer.

We are using a Banner photo sensor, I believe the model is Q12RB6LV, and a single piece of Retro tape in one section of our shooter wheel. The tape spans approximately a 50 deg arc. You can see it in the photo below near the bottom of the image.

I had our programmer work with the WPILib to figure out how to get the period of a pulsed signal. I believe the command he is using is getPeriod(), at least that rings a bell.
getPeriod() returns a value in seconds and has a resolution of 1ms. This limits the number of steps in RPM we can achieve to only 15, but that is more than enough for this game. The value we read is very consistent.

We usually target a period of .025 for our default shot, but will vary it with distance to as low as .010 as needed (10ms is basically full power all the time).

The psuedo code we use is:

if (getPeriod() <= .025)
{
MotorDrive = 0
}
else
{
MotorDrive = 1
}
wait (5ms)

I’d like to drill into this a bit deeper if you’d be willing to bear with me. What is the source for the “1ms resolution” statement?

Fair question.
This is my interpretation of:

getPeriod
public double getPeriod()
Get the Period of the most recent count. Returns the time interval of the most recent count. This can be used for velocity calculations to determine shaft speed.
Specified by:
getPeriod in interface CounterBase
Returns:
The period of the last two pulses in units of seconds.

That and the fact that the value getPeriod() produces only has 3 places to the right of the decimal point. ie. .020.

I have no problem being wrong in my interpretation, wouldn’t be the first time. But I can tell you this, our code works, and we use 3 decimal place values to control it.
Remember my disclaimer, Java is not a programming language I use.

We have 6 motors on our robot this year that use the velocity-control loop provided by the CAN Talon SRX at least some of the time. It works great and is dead simple to tune (RTM for details, but start with F from first principles or measurement then add some P until you’re happy…maybe D if you are feeling fancy).

1KHz control loop + internally low-pass filtered velocity measurement (basically a moving average filter over the last 32(?) dEncoderTicks/100ms) = I’m unlikely to use anything else for velocity control in FRC ever again