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

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.

Oops, there seems to be something wrong with the link. :joy: l guess your repo is private.

A really accurate shooter! Do you also use falcon?

Yeah, seems like it was private. Does this work?

Nope, the front which the encoder is connected to is 2 redlines with a 3.25:1 speed gearbox that uses 3 inch plastic wheels; and the back one is a single 775pro with I believe 2 inch compliant wheels. It doesn’t have much mass and we aren’t exactly rich so we didn’t use an encoder for those.

1 Like

We have created a method that sets the rpm based on the distance calculated using our limelight. The ‘rpm’ variable is the desired rpm that is returned by that method. We have an if statement similar to yours that checks if the desired rpm is reached. If not, the Xbox controller doesn’t rumble. Here is the code:

if (Subsystems.shooterSubsystem.atRpm(rpm)) {

    RobotContainer.stick.setRumble(RumbleType.kLeftRumble, 1);

    RobotContainer.stick.setRumble(RumbleType.kRightRumble, 1);

  } else {

    RobotContainer.stick.setRumble(RumbleType.kLeftRumble, 0);

    RobotContainer.stick.setRumble(RumbleType.kRightRumble, 0);

1 Like