Class Turret

java.lang.Object
com.crossbotics.ftchelper.launcher.Turret
All Implemented Interfaces:
Subsystem

public class Turret extends Object implements Subsystem
A turret: turns to an angle in degrees, never past its limits (so cables never wind up), and can hold a FIELD direction while the robot drives and turns.

 Turret turret = Turret.create(hardwareMap, "turret")
         .countsPerDegree(1479 / 360.0)            // encoder counts per turret degree
         .limits(-190, 190)                        // degrees; 0 = straight forward
         .homeSwitch(hardwareMap, "turret_home", 45)   // switch closes at 45 deg
         .pid(0.02, 0, 0.001, 0)
         .tolerance(1.0);

 turret.aimAt(30);                                  // robot-relative, counterclockwise +
 turret.aimField(90, ImuSetup.headingDeg(imu));     // hold field direction 90 while driving
 turret.aimBy(target.bearingDeg);                   // vision: turn by the target's bearing
 

Angles: 0 = robot forward, counterclockwise (left) is positive, like the IMU. Positive power must turn the turret counterclockwise (use reversed() if not). The signs are in docs/conventions.md.

The safe way round: with limits like -190..190 there can be two ways to reach an angle (e.g. 170 and -190 are the same direction). The turret picks the one inside the limits closest to where it is, and always moves there WITHOUT passing a limit. Asked for something outside the limits, it goes to the nearest limit and isOutOfRange() turns true. (Picture: docs/images/turret-limits.svg.)

Homing: with a home switch, the turret does not know its angle until the switch is seen once. Call home(double) (it turns slowly until the switch). Without a switch, it trusts startAngle(double) (the angle when the robot was turned on).

What turns it. A motor with its encoder (Turret(String, DcMotorEx)); a continuous-rotation (CR) servo with any encoder (Turret(String, DoubleConsumer, DoubleSupplier): a REV Through Bore on a motor port, or an absolute encoder read in degrees); or a standard servo that goes to an angle by itself (servo(String, PositionServo): its angle is where it was sent, and "arrived" is a time estimate). A slip ring lets it turn for ever: continuous().

Fence (fence(double, double)): a second, temporary range set every loop by the robot's interlock rules (two parts that must not be in the same space). The turret never turns past it; a target on the other side waits at its edge (isHeld()), or goes the other way round if the range allows.

Like every helper, the aim commands only set a target; update() turns the motor, a little every loop, using a PID controller (tutorial 07 explains PID). Tutorial 18 aims a turret with a camera. Docs: docs/modules/launcher.md

  • Constructor Summary

    Constructors
    Constructor
    Description
    Turret(String name, com.qualcomm.robotcore.hardware.DcMotorEx motor)
    Wraps a motor you already set up (brake, encoder reset).
    Turret(String name, DoubleConsumer power, DoubleSupplier counts)
    A turret turned by something that takes a power (a CR servo) with its angle from any encoder.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    Shows the angle and AIMED; warnings for faults, not homed, and out of range; the target in debug mode.
    void
    Only the warnings of addTelemetry(com.crossbotics.ftchelper.telemetry.RobotTelemetry) (a fault, not homed, a target out of range), for code that writes its own line for the turret (the robot module's Turret does).
    void
    aimAt(double robotDeg)
    Turns to a robot-relative angle (0 = forward, counterclockwise +), the safe way round.
    boolean
    aimAtTarget(TargetObservation target, boolean cameraOnTurret)
    Aims at a camera target, safely: only a FRESH picture is used, and each picture only once (an old or repeated picture would push the turret further and further).
    void
    aimBy(double deltaDeg)
    Turns BY an amount from where it is now.
    void
    aimField(double fieldDeg, double headingCcwDeg)
    Points at a FIELD direction, whatever way the robot faces.
    aimStep(double robotDeg, double timeoutSec)
    A step (autonomous): turn to a robot-relative angle and wait until aimed (or timeoutSec).
    cameraOffset(double deg)
    Where the target should sit in the camera's view when the LAUNCHER points straight at it, in degrees (positive = left of the camera's center), for a camera that is not centered on the launcher.
    No limits: the turret can turn round and round (a slip ring carries its wires).
    countsPerDegree(double counts)
    Encoder counts per degree of TURRET rotation (motor counts x gear ratio / 360).
    static Turret
    create(com.qualcomm.robotcore.hardware.HardwareMap hardwareMap, String name)
    Gets the motor (brake, encoder reset, plain power) and wraps it.
    double
    degreesOutOfRange(double robotDeg)
    How far past its limits a direction is, degrees: 0 if the turret can point there (some equal angle, + or - 360, is inside the limits), otherwise how far it is from the nearest limit, measured around the circle.
    The encoder counts the other way (a separate encoder whose count goes down while the turret turns counterclockwise).
    fence(double lo, double hi)
    A temporary range inside the limits, set every loop by an interlock rule (see the robot module's Interlock): the turret does not turn past it.
    fence(double lo, double hi, double upPower, double downPower)
    fence(double, double), and the most power it may use toward each side now.
    double
    The angle now (degrees, counterclockwise +).
    "" or a problem, e.g.
    double
    The upper limit, degrees (infinity when continuous()).
    double
    The lower limit, degrees (minus infinity when continuous()).
    double[]
    The angles the turret may be at now, {lowest, highest}: for a motor or CR servo turret its angle (both the same), for a servo turret everything between where it was and where it is going until it should have arrived (it cannot say where it is).
    double
    The angle it is going to (NaN if none).
    double
    The tolerance, degrees: isAimed() is true within this of the target.
    double
    getAngle() as -180..180 (for a continuous() turret, whose angle keeps counting).
    void
    home(double direction)
    Starts homing: turns slowly toward the switch until it closes.
    homeSwitch(com.qualcomm.robotcore.hardware.HardwareMap hardwareMap, String switchName, double angleDeg)
    A home switch by configuration name (touch sensor), closing at angleDeg.
    homeSwitch(BooleanSupplier isClosed, double angleDeg)
    A home switch read your own way (magnetic: () -> !channel.getState()).
    homingPower(double p)
    Power while homing, 0 to 1.
    homingTimeout(double seconds)
    Homing stops with a fault if the switch is not found within this many seconds.
    boolean
    True when homed, holding a target that is REACHABLE (not out of range), and within the tolerance.
    boolean
    True after continuous().
    boolean
    True while the fence keeps it from its target (it waits at the fence's edge).
    boolean
    True once the angle is known (switch seen, or there is no switch).
    boolean
    True while turning slowly to find the home switch.
    boolean
    True if the last aim was outside the limits (it went to the nearest limit instead).
    boolean
    True for a servo turret (servo): its angle is where it was sent (an estimate while it moves).
    boolean
    True while waitWhileUnknown(boolean) holds it still (its angle not known, the rule says wait).
    limits(double min, double max)
    The allowed range, degrees.
    void
    manual(double power)
    Manual control (a stick), -1 to 1.
    Marks the angle as known now (homed), e.g.
    maxPower(double p)
    The most power it ever gets, 0 to 1.
    maxTargetAgeMs(double ms)
    aimAtTarget(com.crossbotics.ftchelper.vision.TargetObservation, boolean) ignores camera pictures older than this (milliseconds).
    The name shown in telemetry and in the hardware check.
    pid(double kP, double kI, double kD, double kF)
    PID gains (see docs/modules/control.md).
    Positive power turns the other way.
    static Turret
    servo(String name, PositionServo servo)
    A turret on a standard servo that goes to an angle by itself (no encoder, no PID, no homing).
    double
    A servo turret: the angle it counts from before its first command (startAngle(double), or the middle of its range when none was given).
    servoStickSec(double seconds)
    A servo turret: seconds for the stick to turn it across its whole range at full stick (default 0.5).
    slowZone(double deg, double powerAtLimit)
    Slow down within deg of a limit, down to powerAtLimit (0 to 1).
    startAngle(double deg)
    The turret's angle when the robot is turned on (used when there is no home switch).
    void
    Stops: no homing, no target, no power.
    tolerance(double deg)
    Aimed when within this many degrees.
    void
    Once per loop: checks the home switch, picks the power (homing, stick or PID), applies the limits.
    waitWhileUnknown(boolean wait)
    Set every loop by an interlock rule: while true, a turret whose angle is not known yet (not homed, or a servo turret never sent anywhere) does not move at all: no homing (its time limit waits too), no stick, no first servo move.

    Methods inherited from class java.lang.Object

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

    • Turret

      public Turret(String name, com.qualcomm.robotcore.hardware.DcMotorEx motor)
      Wraps a motor you already set up (brake, encoder reset).
    • Turret

      public Turret(String name, DoubleConsumer power, DoubleSupplier counts)
      A turret turned by something that takes a power (a CR servo) with its angle from any encoder.
      
       DcMotorEx encoderPort = hardwareMap.get(DcMotorEx.class, "turret_enc");   // a Through Bore on a motor port
       Turret t = new Turret("turret", crServo::setPower, encoderPort::getCurrentPosition)
               .countsPerDegree(8192 / 360.0).limits(-90, 90);
       
      Parameters:
      name - shown on the Driver Station
      power - where the power goes, -1 to 1 (+ = counterclockwise; see reversed())
      counts - the encoder now, in counts (any start: startAngle(double) sets which angle it is)
  • Method Details

    • create

      public static Turret create(com.qualcomm.robotcore.hardware.HardwareMap hardwareMap, String name)
      Gets the motor (brake, encoder reset, plain power) and wraps it.
    • servo

      public static Turret servo(String name, PositionServo servo)
      A turret on a standard servo that goes to an angle by itself (no encoder, no PID, no homing). The servo needs its angles set up (PositionServo.degrees(double, double, double, double)) and its travel time (for "arrived").
      
       PositionServo s = PositionServo.create(hardwareMap, "turret").degrees(0.1, -90, 0.9, 90).travelTime(0.6);
       Turret t = Turret.servo("turret", s).limits(-90, 90);
       
    • isServo

      public boolean isServo()
      True for a servo turret (servo): its angle is where it was sent (an estimate while it moves).
    • reversed

      public Turret reversed()
      Positive power turns the other way. Use it if positive power turns the turret clockwise.
    • encoderReversed

      public Turret encoderReversed()
      The encoder counts the other way (a separate encoder whose count goes down while the turret turns counterclockwise). Not needed for a motor's own encoder (reversed() flips both).
    • continuous

      public Turret continuous()
      No limits: the turret can turn round and round (a slip ring carries its wires). It always takes the shortest way, and a direction is never "out of range". The angle keeps counting past 360 (getAngle()); getWrappedAngle() gives it as -180..180.
    • isContinuous

      public boolean isContinuous()
      True after continuous().
    • countsPerDegree

      public Turret countsPerDegree(double counts)
      Encoder counts per degree of TURRET rotation (motor counts x gear ratio / 360).
    • limits

      public Turret limits(double min, double max)
      The allowed range, degrees. May be wider than 360 total (e.g. -190..190). Ends continuous().
    • getMin

      public double getMin()
      The lower limit, degrees (minus infinity when continuous()).
    • getMax

      public double getMax()
      The upper limit, degrees (infinity when continuous()).
    • fence

      public Turret fence(double lo, double hi)
      A temporary range inside the limits, set every loop by an interlock rule (see the robot module's Interlock): the turret does not turn past it. A target outside it goes the other way round if an equal direction (+ or - 360) is inside both the limits and the fence, else it waits at the fence's edge (isHeld()). fence(-inf, +inf) or clearFence() removes it.
      Parameters:
      lo - lowest allowed angle now, degrees
      hi - highest allowed angle now, degrees
    • fence

      public Turret fence(double lo, double hi, double upPower, double downPower)
      fence(double, double), and the most power it may use toward each side now. An interlock rule lowers these as the turret comes near its fence fast (and sets 0 to brake), so it stops before the edge instead of coasting past it.
      Parameters:
      lo - lowest allowed angle now, degrees
      hi - highest allowed angle now, degrees
      upPower - the most power counterclockwise (toward higher angles) now, 0 to 1 (1 = no cap)
      downPower - the most power clockwise now, 0 to 1
    • waitWhileUnknown

      public Turret waitWhileUnknown(boolean wait)
      Set every loop by an interlock rule: while true, a turret whose angle is not known yet (not homed, or a servo turret never sent anywhere) does not move at all: no homing (its time limit waits too), no stick, no first servo move. From "anywhere" it could sweep through another part that is in its zone. Once its angle is known this does nothing (the fence(double, double) keeps it out).
      Parameters:
      wait - true = hold still while the angle is unknown
      Returns:
      this turret
    • isWaitingUnknown

      public boolean isWaitingUnknown()
      True while waitWhileUnknown(boolean) holds it still (its angle not known, the rule says wait).
    • clearFence

      public Turret clearFence()
    • isHeld

      public boolean isHeld()
      True while the fence keeps it from its target (it waits at the fence's edge).
    • markHomed

      public Turret markHomed()
      Marks the angle as known now (homed), e.g. after startAngle(double) from a remembered angle.
    • startAngle

      public Turret startAngle(double deg)
      The turret's angle when the robot is turned on (used when there is no home switch). Default 0. Call it after countsPerDegree and reversed(), since it uses the encoder reading.

      A servo turret: where it counts from before its first command (a stick, aimBy(double)). A servo says nothing about where it is, so send it there at START (aimAt(startAngle)) to make it true; without startAngle it counts from the middle of its range.

    • homeSwitch

      public Turret homeSwitch(com.qualcomm.robotcore.hardware.HardwareMap hardwareMap, String switchName, double angleDeg)
      A home switch by configuration name (touch sensor), closing at angleDeg. Skipped if missing.
    • homeSwitch

      public Turret homeSwitch(BooleanSupplier isClosed, double angleDeg)
      A home switch read your own way (magnetic: () -> !channel.getState()). () -> ... is a small piece of code handed over to run later (here: every loop).
    • homingPower

      public Turret homingPower(double p)
      Power while homing, 0 to 1. Default 0.2. Also the most manual power before homing.
    • homingTimeout

      public Turret homingTimeout(double seconds)
      Homing stops with a fault if the switch is not found within this many seconds. Default 5.
    • cameraOffset

      public Turret cameraOffset(double deg)
      Where the target should sit in the camera's view when the LAUNCHER points straight at it, in degrees (positive = left of the camera's center), for a camera that is not centered on the launcher. Used by aimAtTarget(com.crossbotics.ftchelper.vision.TargetObservation, boolean). Find it with the aim tuner. Default 0.
    • maxTargetAgeMs

      public Turret maxTargetAgeMs(double ms)
      aimAtTarget(com.crossbotics.ftchelper.vision.TargetObservation, boolean) ignores camera pictures older than this (milliseconds). Default 150.
    • pid

      public Turret pid(double kP, double kI, double kD, double kF)
      PID gains (see docs/modules/control.md). They work on degrees of error: kP = push harder the further off it points, kI = push more if it stays a little off, kD = calm it down when it turns fast (stops overshoot), kF = a steady extra push.
    • tolerance

      public Turret tolerance(double deg)
      Aimed when within this many degrees. Default 1.
    • maxPower

      public Turret maxPower(double p)
      The most power it ever gets, 0 to 1. Default 0.8.
    • slowZone

      public Turret slowZone(double deg, double powerAtLimit)
      Slow down within deg of a limit, down to powerAtLimit (0 to 1). Default 10 deg, 0.25 power.
    • aimAt

      public void aimAt(double robotDeg)
      Turns to a robot-relative angle (0 = forward, counterclockwise +), the safe way round.
    • aimField

      public void aimField(double fieldDeg, double headingCcwDeg)
      Points at a FIELD direction, whatever way the robot faces. Call it every loop with the current heading so it keeps pointing there while the robot turns.
      Parameters:
      fieldDeg - field direction, counterclockwise from where heading 0 points
      headingCcwDeg - the robot's IMU heading
    • aimBy

      public void aimBy(double deltaDeg)
      Turns BY an amount from where it is now. For camera targets use aimAtTarget(com.crossbotics.ftchelper.vision.TargetObservation, boolean) instead.
    • servoStartAngle

      public double servoStartAngle()
      A servo turret: the angle it counts from before its first command (startAngle(double), or the middle of its range when none was given). Motor turrets: the same as getAngle().
    • aimAtTarget

      public boolean aimAtTarget(TargetObservation target, boolean cameraOnTurret)
      Aims at a camera target, safely: only a FRESH picture is used, and each picture only once (an old or repeated picture would push the turret further and further). No fresh target = the turret holds where it is.
      Parameters:
      target - from camera.target(...) (may be null)
      cameraOnTurret - true if the camera turns with the turret, false if it is on the robot body
      Returns:
      true if this picture was used
    • manual

      public void manual(double power)
      Manual control (a stick), -1 to 1. Limits apply once homed. Before homing the angle is not known, so manual power is kept to the homing power. 0 = hold where it is.
    • home

      public void home(double direction)
      Starts homing: turns slowly toward the switch until it closes.
      Parameters:
      direction - +1 = counterclockwise, -1 = clockwise (the way the switch is)
    • update

      public void update()
      Once per loop: checks the home switch, picks the power (homing, stick or PID), applies the limits.
      Specified by:
      update in interface Subsystem
    • servoStickSec

      public Turret servoStickSec(double seconds)
      A servo turret: seconds for the stick to turn it across its whole range at full stick (default 0.5).
    • stop

      public void stop()
      Stops: no homing, no target, no power. It stays stopped until a new command.
      Specified by:
      stop in interface Subsystem
    • getAngle

      public double getAngle()
      The angle now (degrees, counterclockwise +). Meaningless until homed. A servo turret: where it was sent, or part way there while it moves (an estimate); NaN before its first command.
    • getWrappedAngle

      public double getWrappedAngle()
      getAngle() as -180..180 (for a continuous() turret, whose angle keeps counting).
    • getSweep

      public double[] getSweep()
      The angles the turret may be at now, {lowest, highest}: for a motor or CR servo turret its angle (both the same), for a servo turret everything between where it was and where it is going until it should have arrived (it cannot say where it is). Before a servo turret's first command: its whole range. Used by interlock rules.
    • getTargetAngle

      public double getTargetAngle()
      The angle it is going to (NaN if none).
    • isAimed

      public boolean isAimed()
      True when homed, holding a target that is REACHABLE (not out of range), and within the tolerance. Safe to use as a launcher ready check.
    • getTolerance

      public double getTolerance()
      The tolerance, degrees: isAimed() is true within this of the target.
    • degreesOutOfRange

      public double degreesOutOfRange(double robotDeg)
      How far past its limits a direction is, degrees: 0 if the turret can point there (some equal angle, + or - 360, is inside the limits), otherwise how far it is from the nearest limit, measured around the circle. Used to tell "just past the limit" from "behind the robot".
      Parameters:
      robotDeg - the direction, robot-relative, counterclockwise +
    • getFault

      public String getFault()
      "" or a problem, e.g. "homing failed: switch not found".
    • isOutOfRange

      public boolean isOutOfRange()
      True if the last aim was outside the limits (it went to the nearest limit instead).
    • isHomed

      public boolean isHomed()
      True once the angle is known (switch seen, or there is no switch).
    • isHoming

      public boolean isHoming()
      True while turning slowly to find the home switch.
    • name

      public String name()
      Description copied from interface: Subsystem
      The name shown in telemetry and in the hardware check.
      Specified by:
      name in interface Subsystem
    • aimStep

      public AutoStep aimStep(double robotDeg, double timeoutSec)
      A step (autonomous): turn to a robot-relative angle and wait until aimed (or timeoutSec).
    • addTelemetry

      public void addTelemetry(RobotTelemetry t)
      Shows the angle and AIMED; warnings for faults, not homed, and out of range; the target in debug mode.
      Specified by:
      addTelemetry in interface Subsystem
    • addWarnings

      public void addWarnings(RobotTelemetry t)
      Only the warnings of addTelemetry(com.crossbotics.ftchelper.telemetry.RobotTelemetry) (a fault, not homed, a target out of range), for code that writes its own line for the turret (the robot module's Turret does).