How does team this year decide when to shoot out a ball

In order to make the shoot more convenient, l guess that many teams in this year have used a system in code to decide when to shoot out a ball. l guess that it’s until your shooter has reached the desired speed that you make the shoot. So, my question is how do you do this in code. Since during our shooter tuning, we have an oscilliation within 20 rpm. l use an speed tolerance of 20 rpm to make sure that our shooter is around the desired speed and then l will enable the conveyor or the blocker to pass the ball to the shooter. However, l think this condition isn’t accurate enough since sometimes the condition can’t be met due to the oscilliation of the shooter. So, l am curious about how your team deals with this situation? By having an accurate shooter or by dealing with this situation in code?

Having an accurate shooter is step #1. The system you just outlined (running the indexer when your RPM is within a certain range) is exactly correct, and worked fine for us. A flywheel oscillating is usually not a huge thing - are you using PIDs on your flywheel? How are you tuning it?


Threshold and debounce makes the world go round!

final double THRESHOLD_DUR_SEC = 0.25;
final double THRESHOLD_TOLERANCE_RPM = 100;

double timerStart  = 0;


public void update(){
    // ...

    //get the current time (once)
    double curTime = Timer.getFPGATimestamp();

    runShooter = false; //default to not running

    if( Math.abs(desiredSpeed - actualSpeed) < THRESHOLD_TOLERANCE_RPM){
        // If we're running at a speed close enough to where we want to be running...
        if(curTime - timerStart > THRESHOLD_DUR_SEC){
            //AND we've been running close to where we want to be for long enough, run the shooter
            runShooter = true;
    } else {
        timerStart = curTime; // reset timer


1 Like

Turret tracks constantly and shooter wheels run constantly, operator turned on the shooter feeder when she was comfortable the balls would hit.

Shooter wheel speed was based on the size of image the limelight saw, there was a control loop running on the falcons to target and maintain the speed.

Pilot has an aim button (right bumper) that takes over steering and sets the launcher RPM based on the limelight calculated distance (thanks 6328 for that software).

By the time the robot is aimed the RPM is nearly always in the correct range. We don’t check that the RPM is correct. it’s a pretty aggressive control loop to get it spooled up quickly. We also have RPM control on the feeder wheel so that we get a consistent launch.


l am using P and F on my shooter.

Thanks for your advice! We have simliar solution to yours, but since our oscilliation is a little big, which is around 20 rpm, so l need to set the tolerance to be big enough to let the indexer to run. l think this isn’t accurate.

Thanks, but l think the falcon needs a time to get to the desired speed, so if your operator wrongly press the indexer button, the ball won’t be shooted to the hub accurately. So, l think a more accurate condition should be added. If you have other wise solutions which are not mentioned, please introduce them, thanks!

We are in the similar situations to yours! Can you share a link to the related code of 6328?

1 Like

It was only about a second and a half from zero, so for auto we just waited 2 seconds before shooting our auto balls. During teleop, the shooter was always running so getting up to speed only mattered when we were shooting 2 balls at a time, so we just slowed the feeder speed down until shots were consistent. It was still pretty quick. An ‘up to speed’ condition would work too, but this is one way to set it up without one and still shoot consistently.


l find that they do control the blocker’s speed in every point on the field, that’s really smarting! That equals to control the time the shooter needs to get to the desired speed l think. So, is this thought still available with an interpolation table? Has anyone tested it? Besides, can a too low speed still be able to pass the ball to the shooter?

tagging in @jonahb55, too

1 Like
// Called every time the scheduler runs while the command is scheduled.
public void execute() {


    if (m_shooter.getRPM() - ShooterConstants.kShooterRPMTolerance <= m_targetRPM
            && m_shooter.getRPM() + ShooterConstants.kShooterRPMTolerance >= m_targetRPM) {
        m_shooter.shooterState = ShooterState.VELOCITY_CONTROL_SPUN_UP;

    if (m_targetRPM != 0 && m_shooter.shooterState != ShooterState.VELOCITY_CONTROL_SPUN_UP) {
        m_shooter.shooterState = ShooterState.VELOCITY_CONTROL_SPINNING_UP;

// Called once the command ends or is interrupted.
public void end(boolean interrupted) {

    if (m_shouldStop) {
        m_shooter.shooterState = ShooterState.SLOWING_DOWN;

What we’ve used last year is checking the RPM to decide what state you should set the shooter subsystem as. We also had similar thing for our hood mechanism and turret, then if all mechanisms were in the required state the robot would shoot.

I believe the code @AllenGregoryIV is referenceing relates specifically to calculating the robot’s pose based on vision data (including distance to the target). We used a circle fitting algorithm that feeds into our odometry system. I’ve included some links below where I talk about how it works in our build thread.

This is useful specifically if you care about full field localization, since the pose will be accurate even if the target is at an angle. If you just need the distance to the target when you’re already aimed at it, using the angle or size of the target is much simpler.


Correct we used the circle finder to find a much more accurate distance from goal calculation. We then made a linear relationship between launcher speed and distance to get accurate shots.

Our code available here -

Briefly, Our operator got a haptic rumble on the controller when shooter was at target speed.

That’s cool, do you also use a xbox controller? If so, can you share the code of making a rumble on the controller?

1 Like

Thanks for sharing! l have had a look to your code, but l still can’t find where the circle finder is? Can you give a more specific link? Thanks? Besides, l want to make sure that once your robot is stop at a point on the field, will the distance you get from limelight oscilliating? Besides, l see that your swerve’s max angular speed is 3 * Math.PI, will this make the driver harder to control the swerve since l think this angular speed is too big?

I’ll have to call in some help from our programmers, yes Sure!

I think l have found it.

l will let my team mate test to see if it works well (If there is something wrong with my code, please tell me!). Thanks!

1 Like

We have a timer that starts when the PID controller reaches the setpoint and when it can sustain the desired speed ±15% for 0.5 seconds, our conveyor system then brings the cargo to the shooter wheels.

We also have another timer that starts when the microswitch which is right in between said conveyor system and shooter wheels reports as “not pressed”. It tells the motors to maintain their velocities for 1 second after the fact.

Good idea! Would you mind sharing your code?

Besides, will ±15% make the shoot unstable?

Here it is

We use robotpy and we haven’t touched it in a while so it’s quite messy but i believe you could do the same in java/c++.

The feedforward controller actually calculates the voltage, The PID is just there because feedforward does not have .atSetpoint() method. And as per the ±15% tolerance (which is really just 5 rpm because we don’t spin it faster than 30-50 rpm most of the time :smiley:) the feedforward works just great so we haven’t bothered to lower it.