Class Aim
robot.aim(). It also turns the WHOLE robot toward the goal while the driver drives
(mode(), the same as robot.aimMode()), and tells how far off the aim is (for the
gamepad buzz, g1.rumbleWhenAimed()).
// Controls.java, inside buttons(...):
g1.rb.toggle(robot.aimMode()).says("aim the robot at the goal on/off"); // whole-robot aim
g1.rumbleWhenAimed(); // buzz: the closer, the stronger
public static class Aim { // Tunables.java (every line optional)
public static double goalX = 13, goalY = -13; // the goal on the field (odometry backup)
public static boolean mirrorForRed = false; // the robot's one setting (BIOBUZZ: false)
public static double turnKp = 0.02, turnKd = 0.002, maxTurnPower = 0.5, minTurnPower = 0, toleranceDeg = 2;
public static double cameraOffset = 0, rumbleDeg = 4;
public static double maxGoalDistance = 170, cameraOdometryAgree = 6; // inches: odometry sanity checks
public static boolean shootOnMove = false; // shooting while driving: off until tuned
public static double flightSec = 0.8, flightSecPerIn = 0, maxLeadIn = 24;
public static double shooterForwardIn = 0, shooterLeftIn = 0; // the shooter (turret pivot) from the centre
public static double cameraForwardIn = 0, cameraLeftIn = 0; // a camera on the body, from the centre
}
Whole-robot aim and a following turret are separate modes. Use one: a robot with a turret
that follows the goal (follows(camera) or followsOdometry()) aims with the turret;
robot.aimMode() is for a robot with no turret (or a turret that does not follow). Both at
once would chase the same error with two motors and swing back and forth, so
robot.aimMode() stops at INIT with a message on such a robot.
Camera first, odometry as a backup. While the camera sees the goal (a picture newer than
cameraMaxAgeMs, 150 ms), that is used. When it does not (the tag is blocked, out of view, a
bad picture), and the robot has an odometry(...) line and Tunables.Aim.goalX, goalY,
the goal's direction and distance are worked out from where the robot is (robot.pose()). The
Driver Station says which one is in use.
The goal point is in the same numbers as driveTo and the autonomous start spots:
seen from your drivers' wall, x inches to the right of the field's centre line, y inches from the
centre toward the far wall, written for BLUE. For RED with mirrorForRed = true (the default,
like autonomous) x is mirrored; a field turned half a turn between the alliances (BIOBUZZ) uses
mirrorForRed = false: the same numbers from the red wall. It is the robot's one setting
(RobotDefinition.mirrorForRed()): the autonomous and TeleOp's reset spot use it too. Put the point where the camera
measures to (the goal's tags), so the two distances agree and one shot table works for both.
The odometry is only as good as its pose. It must start right: autonomous's start spot,
carried into TeleOp. Without autonomous, TeleOp's pose would be (0, 0), the middle of the field, and
the robot would aim at the wrong place, so the odometry backup stays OFF until the pose was set
(autonomous ran in this match, or your code called robot.odometry().setPose(...)); the Driver
Station says so. It also stays off while the odometry says the goal is farther than
maxGoalDistance (170 in: more than the field allows, so the pose is wrong), and warns when the
camera and the odometry disagree by more than cameraOdometryAgree (6 in). INIT shows the
alliance and the mirrorForRed choice, so a wrong one is seen before the match.
Shooting on the move (shootOnMove = true, off by default: tune it on a real robot
first). The goal every part gets (goal(), the turret's, the launcher's distance) is then
corrected for the robot's motion: a camera picture is brought forward to now (the robot turned and
moved since it was taken), and the aim leads the shot by the robot's speed x the flight time, because
the piece keeps the robot's speed (see MovingShot). Needs odometry (the speed comes from it).
It works for a turret that follows the goal (camera on the turret or on the body, or odometry only)
and for whole-robot aim with a fixed shooter; the shooter and the camera need not be at the robot's
centre (shooterForwardIn, shooterLeftIn, cameraForwardIn, cameraLeftIn).
movingShotMode() switches it with a button.
Docs: docs/modules/robot.md (section "Aim"). Tutorial: docs/tutorials/start/09-shooter-and-camera.md
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic enumWhere the goal's direction and distance come from now. -
Method Summary
Modifier and TypeMethodDescriptionWhen the camera and the odometry both see the goal and their distances differ by more thanTunables.Aim.cameraOdometryAgree(6 in): a warning (the pose drifted, or the goal point is not where the camera measures to).doubleerrorDeg()How many degrees the aim is off now (any sign), NaN if unknown.The goal worked out from the odometry: its direction from the robot's front (degrees, counterclockwise + = to the LEFT, like a camera's bearing) and its distance from the robot's centre (inches).goal()The goal now: what the camera sees (the first camera with agoal(...)in Robot.java), or, when it does not see it, the goal worked out from the odometry.booleanTrue ifTunables.AimhasgoalXandgoalY(the odometry backup can work).booleanisAimed()True when aimed: whole-robot aim on and withintoleranceDeg, or a following turret that is aimed AT THE GOAL NOW (seeTurret.isAimed(): a goal seen this moment, homed, in range).booleanTrue while shooting on the move is on and the robot moves (faster than 2 in/s, or turning faster than 5 degrees per second): the aim is being led now.lead()The lead worked out last (degrees and inches, seeMovingShot.Result), or null if none in the lastcameraMaxAgeMs(shooting on the move off, no goal, no odometry).mode()Whole-robot aim, for a robot with no turret: while it is on, TeleOp turns the robot toward the goal and the driver keeps forward and sideways.Shooting on the move: while it is on, the goal every part gets is corrected for the robot's motion (the camera picture's age, and the lead for the flight time; seeMovingShot).Why the odometry backup is off now, in a few words for the Driver Station; "" when it works (or the robot has no odometry or no goal point: then there is nothing to warn about).doubleThe error that starts the buzz ofrumbleWhenAimed()(Tunables.Aim.rumbleDeg, default 4).source()Wheregoal()comes from now: CAMERA, ODOMETRY or NONE.static Aim.SourceCAMERA, ODOMETRY or NONE (null), for a target fromgoal()orfromOdometry().
-
Method Details
-
hasGoalPoint
public boolean hasGoalPoint()True ifTunables.AimhasgoalXandgoalY(the odometry backup can work). -
goal
The goal now: what the camera sees (the first camera with agoal(...)in Robot.java), or, when it does not see it, the goal worked out from the odometry. Null if neither. Check for null. -
source
Wheregoal()comes from now: CAMERA, ODOMETRY or NONE. -
sourceOf
CAMERA, ODOMETRY or NONE (null), for a target fromgoal()orfromOdometry(). -
fromOdometry
The goal worked out from the odometry: its direction from the robot's front (degrees, counterclockwise + = to the LEFT, like a camera's bearing) and its distance from the robot's centre (inches). Null if the robot has no odometry, the odometry is not ready,Tunables.Aimhas no goal point, the pose was never set (no autonomous, nosetPose), or the goal would be farther thanmaxGoalDistance(a wrong pose).odometryProblem()says which. -
odometryProblem
Why the odometry backup is off now, in a few words for the Driver Station; "" when it works (or the robot has no odometry or no goal point: then there is nothing to warn about). -
disagreement
When the camera and the odometry both see the goal and their distances differ by more thanTunables.Aim.cameraOdometryAgree(6 in): a warning (the pose drifted, or the goal point is not where the camera measures to). "" otherwise. -
movingShotMode
Shooting on the move: while it is on, the goal every part gets is corrected for the robot's motion (the camera picture's age, and the lead for the flight time; seeMovingShot). On from START whenTunables.Aim.shootOnMove = true; off (and nothing changes) otherwise. A button can switch it:g1.y.toggle(robot.aim().movingShotMode()). Needs odometry. -
lead
The lead worked out last (degrees and inches, seeMovingShot.Result), or null if none in the lastcameraMaxAgeMs(shooting on the move off, no goal, no odometry). -
isMovingShot
public boolean isMovingShot()True while shooting on the move is on and the robot moves (faster than 2 in/s, or turning faster than 5 degrees per second): the aim is being led now. -
mode
Whole-robot aim, for a robot with no turret: while it is on, TeleOp turns the robot toward the goal and the driver keeps forward and sideways. The driver's turn stick still wins: move it and the robot turns as the stick says; let go and the aim takes over again. Off at START.g1.rb.toggle(robot.aimMode()).- Throws:
IllegalStateException- if a turret follows the goal: whole-robot aim and turret-following are separate modes (both would chase the same error and swing back and forth)
-
errorDeg
public double errorDeg()How many degrees the aim is off now (any sign), NaN if unknown. With whole-robot aim on: the robot's front to the goal. Otherwise, a turret that is following: its error. Neither: NaN. -
isAimed
public boolean isAimed()True when aimed: whole-robot aim on and withintoleranceDeg, or a following turret that is aimed AT THE GOAL NOW (seeTurret.isAimed(): a goal seen this moment, homed, in range). Losing the goal makes it false at once, so a launcher gated on it never fires blind. Use it as a launcher check:.requireReady("aimed", () -> aim().isAimed()). -
rumbleDeg
public double rumbleDeg()The error that starts the buzz ofrumbleWhenAimed()(Tunables.Aim.rumbleDeg, default 4).
-