Class Launcher
- All Implemented Interfaces:
Subsystem,Toggleable
Indexer that feeds one
piece at a time once the speed is right.
launcher = add(Launcher.flywheel("launcher", "gobilda-5203-6000").feeder(Indexer.servo("indexer")));
launcher = add(Launcher.flywheel("launcher", "gobilda-5203-6000").feeder(Indexer.servo("indexer"))
.speedFromDistance(camera)); // speed from the camera's distance
public static class Launcher { // Tunables.java
public static double speedRpm = 2600, stepRpm = 100, readyBandRpm = 60, idleRpm = 0;
public static double[][] speedByDistance = {{24, 2200}, {48, 2550}, {72, 2900}}; // inches, rpm
public static double kP = 1.17, kI = 0.117, kD = 0, kF = 11.70, nominalVolts = 12.6; // Flywheel Finder
public static double trimStepPercent = 1, trimMaxPercent = 15; // optional: the speed trim
}
First run (no kF, no speedRpm written): the hub's gains start from the parts catalog for the
motor (Flywheel.startingPidf(double): kF 11.7, kP 1.17, kI 0.117 for a goBILDA 6000 RPM motor) and the
speed at 60% of its top speed (3600). INIT says so once; the Flywheel Finder and the Shot Tuner find the
real ones. A written number always wins.
Speed trim (a fix during a match, when every shot is a little short or long: a worn
wheel, different balls): trimBy(double) makes every shot speed (the table's or the
fixed one) that many percent faster or slower, kept to +/- trimMaxPercent (15) and to the
motor's top speed (then the Driver Station says "(motor limit)"). It starts at 0 at every INIT and is
the same for every table. The Driver Station shows Speed trim: +3% READY as the launcher's
first line. The trim used last time is remembered (until the robot app restarts) and offered at
INIT: "Trim last time: +3% (double-tap D-pad up after START to use it)"; it is never applied by
itself. The Shot Tuner never uses it (tables are recorded clean). If you trim the same way match
after match, the table is off: tune it again (or fold the trim into Tunables.java) instead.
Battery compensation (OFF by default; batteryCompensation = true with kF
turns it on — not yet proven on a real robot): the hub's F gain is scaled by nominalVolts / the battery now, so a low battery gets
the wheel back to speed after a shot as fast as a full one (see Flywheel.batteryCompensation(java.util.function.DoubleSupplier, double)).
fire() spins up if needed and feeds one piece as soon as the wheel is at speed (it gives
up after 3 s and says why). The driver can step the speed up and down (adjust(int)).
With speedFromDistance(com.crossbotics.ftchelper.robot.Camera), the speed comes from speedByDistance (blended between rows)
while the goal is seen; when the camera does not see it, from the odometry's distance (with an
odometry(...) line and Tunables.Aim.goalX, goalY, see Aim); with neither it
keeps the last speed. speedFromOdometry(): the odometry's distance only (no camera).
Several shot tables, one per game piece (they fly differently): every
speedByDistance... table in the section is one, named by the rest of its name.
public static double[][] speedByDistancePollen = {{24, 2100}, {48, 2450}, {72, 2800}}; // "pollen"
public static double[][] speedByDistanceNectar = {{24, 2400}, {48, 2800}, {72, 3200}}; // "nectar"
Switch with useTable(String) (a button, an action, an autonomous), nextTable(),
or let a sensor choose: tableFrom(java.util.function.Supplier). It starts on the plain
speedByDistance if there is one, else the first by name, or the one given to
startTable(String). The Driver Station shows the table in use.
A hood (hood(Hood)): the shot table's rows get a third number, the hood angle
({48, 2550, 12}), blended between rows like the speed; the launcher waits for the hood to
arrive before it feeds. Two-number rows still work (then the hood is set by hand). See Hood.
Suggested buttons (operator): LB spins up / down, RB fires one (hold it: keeps firing). D-pad
up/down: with the speed from the distance, the speed trim +/- trimStepPercent (1%); with a
fixed speed, +/- stepRpm; held, one more step every 0.25 s. Double-tap D-pad down: back to no
trim. Double-tap D-pad up: use last time's trim (only when there is one). D-pad right picks the next
shot table (with two or more). Each only when that button is free.
Docs: docs/modules/robot.md (section "Launcher"), docs/modules/launcher.md
-
Method Summary
Modifier and TypeMethodDescriptionvoidThe part's telemetry line; each module adds its own.voidadjust(int steps) Changes the speed bystepsxstepRpm(e.g.booleanTrue when the trimmed shot speed is cut to the motor's top speed (more trim up does nothing).voidThe button is let go: no more shots.doubleThe distance to the goal last used for the speed (inches), NaN if none yet.Where that distance came from last loop: CAMERA, ODOMETRY or NONE (keeps the last speed).The indexer that feeds it.voidfire()Fires one piece (spins up first if needed; feeds as soon as it is at speed).voidfire(int count) Firescountpieces, one after another.voidFor a held button, every loop: fires one piece, then the next as soon as that one is fed, for as long as the button is held (the launcher keeps its time between shots).static LauncherA launcher with its flywheel on this motor.hood()The hood given withhood(Hood), or null.The hood that sets how steep the shot leaves (Hood): its angle comes from the shot table's third column ({inches, rpm, hood}), and the launcher waits for it before feeding.voididle()Back to the idle speed (idleRpm, 0 = coast to a stop); cancels shots still waiting.booleanisReady()True when the wheel is at speed (and every other check passes).booleanTrue while shots are waiting or a piece is being fed.booleanTrue while it is spun up (or spinning up), false when idle.Last time's trim in words ("+3%"), while it is offered and not used yet; "" when there is none.voidThe next shot table (after the last, the first again), for a button.part()The launcher.Launcher inside, for anything this module does not offer.requireReady(String what, BooleanSupplier check) Another check before each piece is fed, e.g.voidBack to the Tunables speed: the trim to 0, theadjust(int)steps to 0, and the hood trim to 0.reversed()The flywheel turns the other way.voidsetTrim(double percent) Sets the speed trim to this many percent (0 = none), kept to +/-trimMaxPercent.shotAngle(double degrees) Which way a piece leaves the wheel, for the simulator: degrees up from the wheel shape's forward, seen from the side (45 = forward and up, 90 = straight up, 135 = backward and up).speedFromDistance(Camera camera) Sets the speed from this camera's distance to the goal (Tunables...speedByDistance).Sets the speed from the odometry's distance to the goal, with NO camera: where the robot is (robot.pose()) andTunables.Aim.goalX, goalY(seeAim).Speed from the distance to the goal: on from START whenspeedFromDistance(com.crossbotics.ftchelper.robot.Camera)orspeedFromOdometry()is used.doublespeedRpm()Tunables.Launcher.speedRpm: the speed with no shot table (RPM).Spins up at START (in autonomous and TeleOp), so it is at speed when the first shot is wanted.voidspinUp()Spins up to the shot speed and keeps it there.startTable(String name) The shot table to start with, by name ("pollen" forspeedByDistancePollen).voidstop()Stops all motion.A shot table by name, as Tunables.java has it ("pollen", "main"; case does not matter), or null if there is no such table.tableField(String name) The Tunables field a table came from ("speedByDistancePollen"), or null if there is no such table.Says which shot table some game-piece kinds use, fortableFrom(java.util.function.Supplier<java.lang.String>): e.g.Picks the shot table from your own code every loop, e.g.The shot table in use ("pollen", "main"), or null if there is none.Every shot table's name, in order ("main" first, then by name).doubleThe speed it is aiming for now, RPM.voidtoggle()Spins up if idle, idles if spinning.doubletrim()The speed trim now, percent (0 = none; +3 = 3% faster).voidtrimBy(double change) Trims the shot speed by this many percent more:trimBy(+2)= every shot 2% faster than the table (or the fixed speed) says,trimBy(-1)= 1% slower.voidupdate()Called once every loop.booleanUses the trim from last time (an earlier OpMode since the robot app started), if there is one: the Driver Station offers it at INIT ("Trim last time: +3%"); double-tap D-pad up uses it.voidUses this shot table from now on, e.g.
-
Method Details
-
flywheel
A launcher with its flywheel on this motor.- Parameters:
motor- the motor's configuration namemotorId- the motor's parts-catalog id (seeMotors), e.g. "gobilda-5203-6000"
-
hood
The hood that sets how steep the shot leaves (Hood): its angle comes from the shot table's third column ({inches, rpm, hood}), and the launcher waits for it before feeding.- Parameters:
hood- e.g.Hood.servo("hood")
-
hood
The hood given withhood(Hood), or null. -
feeder
The indexer that feeds it. Without one,fire()only spins up. -
shotAngle
Which way a piece leaves the wheel, for the simulator: degrees up from the wheel shape's forward, seen from the side (45 = forward and up, 90 = straight up, 135 = backward and up). For a wheel mounted level on the robot that is the robot's forward; on a turned part (an arm, a tilted slide) the angle turns with it.- Parameters:
degrees- e.g. 147 for a shot up and out of the back
-
spinAtStart
Spins up at START (in autonomous and TeleOp), so it is at speed when the first shot is wanted. LB (oridle()) still lets it coast down. -
reversed
The flywheel turns the other way. -
requireReady
Another check before each piece is fed, e.g..requireReady("turret aimed", () -> turret.isAimed()). While it is false the launcher waits (and gives up after 3 s, saying which check failed).- Parameters:
what- a few words for the Driver Stationcheck- true when ready
-
speedFromDistance
Sets the speed from this camera's distance to the goal (Tunables...speedByDistance). With anodometry(...)line andTunables.Aim.goalX, goalY, the odometry's distance is used while the camera does not see the goal. -
speedFromOdometry
Sets the speed from the odometry's distance to the goal, with NO camera: where the robot is (robot.pose()) andTunables.Aim.goalX, goalY(seeAim). Needs anodometry(...)line. -
startTable
The shot table to start with, by name ("pollen" forspeedByDistancePollen). Default: the plainspeedByDistanceif there is one, else the first by name. -
tableFrom
Picks the shot table from your own code every loop, e.g. a sensor that tells which game piece is loaded:.tableFrom(() -> robot.indexer.pieceName()). Each time its answer CHANGES to a table's name, that table is used (case does not matter); null or "" changes nothing. A button can still pick another table until the answer changes again. Call it in Robot.java (chained) or later.- Parameters:
tableName- gives a table's name ("pollen"), or null when it does not know
-
tableFor
Says which shot table some game-piece kinds use, fortableFrom(java.util.function.Supplier<java.lang.String>): e.g. with.tableFrom(pieces.nextKind()).tableFor("nectar", "RED_NECTAR", "BLUE_NECTAR")both NECTAR colours usespeedByDistanceNectar. A kind with the same name as a table needs no line ("POLLEN" uses "pollen"). "NONE" and "UNKNOWN" (fromPieces) never change the table.- Parameters:
table- the table's name ("nectar")kinds- the kinds that use it ("RED_NECTAR", "BLUE_NECTAR")
-
spinUp
public void spinUp()Spins up to the shot speed and keeps it there. -
idle
public void idle()Back to the idle speed (idleRpm, 0 = coast to a stop); cancels shots still waiting. -
isSpinning
public boolean isSpinning()True while it is spun up (or spinning up), false when idle. -
toggle
public void toggle()Spins up if idle, idles if spinning.- Specified by:
togglein interfaceToggleable
-
fire
public void fire()Fires one piece (spins up first if needed; feeds as soon as it is at speed). -
fire
public void fire(int count) Firescountpieces, one after another. -
fireWhileHeld
public void fireWhileHeld()For a held button, every loop: fires one piece, then the next as soon as that one is fed, for as long as the button is held (the launcher keeps its time between shots). Pair it withceaseFire()on release:g1.rb.hold(robot.launcher::fireWhileHeld, robot.launcher::ceaseFire). -
ceaseFire
public void ceaseFire()The button is let go: no more shots. The press's first shot still goes (a quick tap fires one, even while the wheel is still spinning up); a later shot still waiting is dropped. -
adjust
public void adjust(int steps) Changes the speed bystepsxstepRpm(e.g. +1 or -1 from a D-pad). Kept until the program ends; the Tunables value is not changed. -
trimBy
public void trimBy(double change) Trims the shot speed by this many percent more:trimBy(+2)= every shot 2% faster than the table (or the fixed speed) says,trimBy(-1)= 1% slower. Adds up, kept to +/-Tunables.Launcher.trimMaxPercent(15). From a button, an action (.then(() -> r.launcher.trimBy(+2))) or code. The same name as the hood's trim (Hood.trimBy(double)), which is in the hood's angle instead of percent. Starts at 0 at every INIT; the Tunables numbers are not changed. A fix for this match: if you need it every match, tune the table again.- Parameters:
change- percent to add, e.g. +1 or -1
-
setTrim
public void setTrim(double percent) Sets the speed trim to this many percent (0 = none), kept to +/-trimMaxPercent.- Parameters:
percent- e.g. 3 for 3% faster, -2 for 2% slower
-
resetTrim
public void resetTrim()Back to the Tunables speed: the trim to 0, theadjust(int)steps to 0, and the hood trim to 0. -
useLastTrim
public boolean useLastTrim()Uses the trim from last time (an earlier OpMode since the robot app started), if there is one: the Driver Station offers it at INIT ("Trim last time: +3%"); double-tap D-pad up uses it. Never runs by itself.- Returns:
- true if there was one to use
-
lastTrimOffered
Last time's trim in words ("+3%"), while it is offered and not used yet; "" when there is none. -
atMotorLimit
public boolean atMotorLimit()True when the trimmed shot speed is cut to the motor's top speed (more trim up does nothing). -
trim
public double trim()The speed trim now, percent (0 = none; +3 = 3% faster). -
speedMode
Speed from the distance to the goal: on from START whenspeedFromDistance(com.crossbotics.ftchelper.robot.Camera)orspeedFromOdometry()is used. -
useTable
Uses this shot table from now on, e.g.robot.launcher.useTable("nectar")forspeedByDistanceNectar(case does not matter). From a button, an action (.then(() -> r.launcher.useTable("nectar"))) or another part's code. A name with no table keeps the table in use and warns on the Driver Station (it never stops the robot in a match).- Parameters:
name- the table's name: the end of its Tunables name ("pollen"), or "main" forspeedByDistance
-
nextTable
public void nextTable()The next shot table (after the last, the first again), for a button. -
tableName
The shot table in use ("pollen", "main"), or null if there is none. -
tableNames
Every shot table's name, in order ("main" first, then by name). Empty before INIT or with none. -
tableField
The Tunables field a table came from ("speedByDistancePollen"), or null if there is no such table. -
table
A shot table by name, as Tunables.java has it ("pollen", "main"; case does not matter), or null if there is no such table. The Shot Tuner starts each table's speed from it. -
speedRpm
public double speedRpm()Tunables.Launcher.speedRpm: the speed with no shot table (RPM). NaN before INIT. -
distanceIn
public double distanceIn()The distance to the goal last used for the speed (inches), NaN if none yet. -
distanceSource
Where that distance came from last loop: CAMERA, ODOMETRY or NONE (keeps the last speed). -
isReady
public boolean isReady()True when the wheel is at speed (and every other check passes). -
isShooting
public boolean isShooting()True while shots are waiting or a piece is being fed. -
targetRpm
public double targetRpm()The speed it is aiming for now, RPM. -
part
The launcher.Launcher inside, for anything this module does not offer. -
update
public void update()Description copied from interface:SubsystemCalled once every loop. Do the hardware work here. Must be quick: no sleep, no waiting. While update() waits, the whole robot is frozen (no driving, no limits, no STOP). -
stop
public void stop()Description copied from interface:SubsystemStops all motion. Called at the end of every OpMode. -
addTelemetry
Description copied from class:ModuleThe part's telemetry line; each module adds its own.- Specified by:
addTelemetryin interfaceSubsystem- Overrides:
addTelemetryin classModule<Launcher>
-