Shooting while driving / good shooting code

I want to try and create good shooting code. Currently, the only way to shoot I’m familiar with is having a lot of values for each shooting point, and interpolating between them. Though I’m sure this code works well when calibrated well, you can’t shoot while driving, and as a whole I’d love to hear some other ways.
For this, let’s assume we have a note shooter on some sort of axis, perfect pose estimation, and a pigeon2
If anyone has experience with this and has some good example code / can explain how one might achive good shooting code, I’d love to hear!

7 Likes

The core concept of shooting while moving is that whatever velocity your drivetrain has at the moment of shooting will be imparted to the note as initial velocity, in addition to what your shooter actually produces. Depending on shooter design (and the speed threshold for “too fast to shoot”), motion towards/away from the goal may be less important to account for than movement side to side.

1 Like

So subtract the robot’s forward velocity from the target tangential velocity of the shooter?

Orbit 1690 were talking about similar problem in they’re 2022 BTB

1 Like

There’s a great thread on this here:

I implemented this to the best of my understanding in our repo. Take a look at the aimAtPointCommand. Essentially what you want to do is offset your aim to account for the velocity of the robot that is perpendicular to the vector created between the robot and the desired point

4 Likes

These are more relevant when you shoot with physics calculations and not interpolating measurements, which is what OP is asking about.

1 Like

Don’t seem to find the class / a function for that command
Where is it in the repo?

1 Like

I was actually working on the a very similar problem of shooting at the speaker while the robot is moving at a constant velocity,
I took the approach of having everything relative to the robot,
basically you act as though you are trying to intercept a moving target (speaker) from a stationary turret (the robot) with a set projectile speed
then you calculate where the speaker will be at the intercept time, then use a method to shoot at a stationary speaker at any robot-relative x,y coordinate to fire as though the speaker was there.
basically you aim where the speaker will be and not where it is

I made a desmos demo of it: simulationTesting | Desmos
the desmos is based on the answer to this question on stack overflow: math - How to find the interception coordinates of a moving target in 3D space? - Stack Overflow
there were errors and limitations in the answer that haven’t been corrected, they are pointed out by epsilon delta in their comment on the answer
I hope this helps

4 Likes

I have some untested code that should do the same thing as the desmos program, although I optimized it by removing all the terms that are multiplied by 0 (ie the robots position since it will always be at the origin)


import java.util.Optional;

import com.spartronics4915.frc2024.Constants.AutoAimConstants;

import edu.wpi.first.math.geometry.Translation2d;

public class AutoAimFunctions {

    private static double pow(double a){return Math.pow(a, 2);}
    private static boolean check(double a) {return Double.isFinite(a) && a > 0;}

    public static Optional<Translation2d> movingAutoAim(
        Translation2d speakPos, //S0
        Translation2d speakVel //V0
    ){
        //the inputs are intended to be relative to the robot in terms of position and velocity, (ie if the robot was moving towards the speaker the speaker would have a velocity going towards the origin)
        //uses code from: https://stackoverflow.com/a/22117046/21621189, look in comments for errors and edge cases accounted for

        //a desmos visualization: https://www.desmos.com/calculator/ejg6jrsodq

        double kShooterSpeed = AutoAimConstants.kShooterSpeed; //s1

        double a = pow(speakVel.getX()) + pow(speakVel.getY()) - pow(kShooterSpeed);
        double b = 2 * ((speakPos.getX() * speakVel.getX()) + (speakPos.getY() * speakVel.getY()) /*- (P1.getX() * speakVel.getX()) - (P1.getY() * speakVel.getY())*/);
        double c = pow(speakPos.getX()) + pow(speakPos.getY()); /*+ (P1.x * P1.x) + (P1.y * P1.y) - (2 * P1.x * P0.x) - (2 * P1.y * P0.y)*/;
        
        if (a == 0) return Optional.empty();
        
        double t1 = (-b + Math.sqrt((b * b) - (4 * a * c))) / (2 * a);
        double t2 = (-b - Math.sqrt((b * b) - (4 * a * c))) / (2 * a);

        double t; //t = time at collision (from 0) in time unit of speakVel 

        if (!check(t1) && !check(t2)) {
            return Optional.empty();
        }else if (!check(t1) || !check(t2)){
            t = check(t1) ? t1 : t2;
        }else{
            t = Math.min(t1, t2);
        }

        Translation2d out = speakPos.plus(speakVel.times(t));

        return Optional.of(out); //outputs the speakerPos at the collision time relative to the robot, (rotation is based on the same as the input translate2ds)
    }

}
2 Likes

How do you know when the intercept will happen? Doesn’t it depend on how fast you’re shooting the game piece?

EDIT: I realized that the math assumes a fixed velocity for the projectile. Have you found that in your prototypes you always shoot at the same speed from every position, and that the average velocity of the notes stays constant from different distances?

1 Like

1706 did a great job explaining how their shooting while moving code worked in 2022. I’m assuming many teams will be taking a similar approach this year.

1 Like

One thing I didn’t fully understand in this code is the following:
The code calculates the time in the air from the current real distance interpolated in a table. However, once we calculate where the target will “move to” from the time in the air times the velocity, the distance from the target changes, thus changing the projectile’s time in the air.
Is this intended and just negligible? Maybe I’m missing something? Or should there be another way to calculate this?

The for loop in the code handles this, it basically can check the new time and rerun the math until it “converges” under an acceptable amount. I could draw out something tomorrow that might help.

2 Likes

Oh, I didn’t see that update in the post.
Was that accurate enough and consistent?

Yeah it was pretty good, we didn’t add that until after IRI but it seemed to make a large improvement for shots when moving towards/away from the goal where the shot time had large variance

I see, tysm!
I implemented this in code. One more question; how important is / why do you need to add the accel times the comp factor to the vel?
Also, how would one calibrate the comp factor?

The old accel comp factor was based on roughly the latency of the velocity measurement of the drivetrain, if you have better drive encoders (newer sparkmax firmware with reduced latency settings applied or Falcon/Kraken) you should be able to reduce this value significantly.

1 Like

Alright, so this is the shooting calculations class I ended up creating.
Would love if someone could maybe look at it to make sure everything is fine

1 Like

Have you tried it out yet?