Class MovingShot

java.lang.Object
com.crossbotics.ftchelper.vision.MovingShot

public final class MovingShot extends Object
The math for shooting while the robot drives and turns. Two fixes to where the goal is, both worked out from how the robot moves:
  1. The picture is old. A camera's picture is a few tens of milliseconds old by the time the code reads it. Since then the robot turned and moved, so the goal is no longer where the picture shows it. solve(double, double, double, double, double, double) turns the goal back by the robot's turn and moves it by the robot's motion over that time: the goal NOW.
  2. The piece keeps the shooter's speed. A piece shot from a robot driving sideways at 30 in/s also flies sideways at 30 in/s. If it is in the air for 0.8 s, it lands 24 in to the side. So aim at a point that far the OTHER way: the "virtual goal" = the goal minus the shooter's speed x the flight time. The launcher's speed comes from the virtual goal's distance too (the piece flies that far relative to the robot).

Where the shooter is. The shooter need not be at the robot's centre: shooterAt(double, double) says where it is (a turret's pivot, or a fixed launcher's exit). That changes three things: the distance is from the shooter, a turning robot swings an off-centre shooter sideways (more speed for the piece), and a fixed shooter to one side of the centre must turn the whole robot a little MORE than "face the goal" so that its own line passes through the goal. onTurret() says a turret aims the shot (the answer is a turret angle); without it the whole robot turns (the answer is how far to turn the robot).

One frame for everything, the robot's: x forward, y to the LEFT, from the robot's centre, angles counterclockwise + (positive = to the left), the same as a TargetObservation. The five-files robot does all this for you (docs/modules/robot.md, section "Aim", Tunables.Aim.shootOnMove); this class is the plain math, for your own code and tests.


 MovingShot shot = new MovingShot().shooterAt(-4, 0).onTurret().flightSec(0.7, 0).maxLeadIn(24);
 // The goal 60 in ahead of the robot's centre; the robot strafes RIGHT at 30 in/s (left speed -30),
 // no turn; the picture is 40 ms old.
 MovingShot.Result r = shot.solve(60, 0, 0, -30, 0, 0.040);
 // r.aimDeg: the turret angle (left of straight ahead: it leads); r.distanceIn: for the launcher's speed
 

What it leaves out (small for an FTC robot): the turret's own turn during the picture's age, air drag on the piece, and a change of the robot's speed during the flight. Docs: docs/modules/vision.md (section "MovingShot"), docs/tutorials/start/09-shooter-and-camera.md

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final class 
    What solve(double, double, double, double, double, double) gives: where to aim, how far to shoot, and how big the lead is.
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    flightSec(double sec, double perIn)
    How long a piece is in the air: sec + perIn x distance, seconds.
    maxLeadIn(double in)
    The most the aim point may move for the lead, inches (a safety cap).
    A turret aims the shot: MovingShot.Result.aimDeg is the turret angle.
    static double[]
    seenFrom(double bearingDeg, double distanceIn, double camForwardIn, double camLeftIn, double camYawDeg)
    Where a goal is from the robot's centre, from what a camera sees: {forward, left} inches.
    shooterAt(double forwardIn, double leftIn)
    Where the shooter is from the robot's centre: a turret's pivot, or where a fixed launcher's piece leaves.
    solve(double goalForwardIn, double goalLeftIn, double forwardInPerSec, double leftInPerSec, double turnDegPerSec, double latencySec)
    Brings a goal seen in an old picture forward to now, leads it for the flight time, and says where to aim the shooter.
    static double[]
    toRobotFrame(double fieldVx, double fieldVy, double headingDeg)
    The robot's speed over the field turned into the robot's own frame: {forward, left}, inches per second.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • MovingShot

      public MovingShot()
  • Method Details

    • shooterAt

      public MovingShot shooterAt(double forwardIn, double leftIn)
      Where the shooter is from the robot's centre: a turret's pivot, or where a fixed launcher's piece leaves. Inches. Default 0, 0 (the centre).
      Parameters:
      forwardIn - inches in front of the centre (negative = behind)
      leftIn - inches left of the centre (negative = right)
    • onTurret

      public MovingShot onTurret()
      A turret aims the shot: MovingShot.Result.aimDeg is the turret angle. Without it the whole robot turns.
    • flightSec

      public MovingShot flightSec(double sec, double perIn)
      How long a piece is in the air: sec + perIn x distance, seconds. Measure it with a slow-motion video (frames from leaving the shooter to reaching the goal, divided by the frame rate).
      Parameters:
      sec - the flight time, seconds (0 and perIn 0 = no lead: only the picture's age)
      perIn - extra seconds per inch of distance (0 = the same time at every distance)
    • maxLeadIn

      public MovingShot maxLeadIn(double in)
      The most the aim point may move for the lead, inches (a safety cap). 0 or less = no cap. Default 24.
    • solve

      public MovingShot.Result solve(double goalForwardIn, double goalLeftIn, double forwardInPerSec, double leftInPerSec, double turnDegPerSec, double latencySec)
      Brings a goal seen in an old picture forward to now, leads it for the flight time, and says where to aim the shooter.
      Parameters:
      goalForwardIn - the goal in front of the robot's centre when the picture was taken, inches
      goalLeftIn - the goal left of the robot's centre then, inches (see seenFrom(double, double, double, double, double))
      forwardInPerSec - the robot's speed forward, inches per second (see toRobotFrame(double, double, double))
      leftInPerSec - the robot's speed to the left, inches per second
      turnDegPerSec - how fast the robot turns, degrees per second, counterclockwise +
      latencySec - how old the picture is, seconds (0 for a goal worked out from the odometry now)
      Returns:
      where to aim and how far to shoot, now
    • seenFrom

      public static double[] seenFrom(double bearingDeg, double distanceIn, double camForwardIn, double camLeftIn, double camYawDeg)
      Where a goal is from the robot's centre, from what a camera sees: {forward, left} inches.
      Parameters:
      bearingDeg - the camera's bearing to it, degrees, counterclockwise + (left)
      distanceIn - the camera's distance to it, inches
      camForwardIn - where the camera is: inches in front of the centre
      camLeftIn - inches left of the centre
      camYawDeg - which way the camera faces from the robot's front (a turret's angle for a camera on it)
    • toRobotFrame

      public static double[] toRobotFrame(double fieldVx, double fieldVy, double headingDeg)
      The robot's speed over the field turned into the robot's own frame: {forward, left}, inches per second. The field frame is the library's (x right, y away from your drivers' wall).
      Parameters:
      fieldVx - speed toward +x (right), inches per second
      fieldVy - speed toward +y (away), inches per second
      headingDeg - the robot's heading, degrees, counterclockwise +, 0 = away from your wall
      Returns:
      {forward, left}