Class PositionMotor

java.lang.Object
com.crossbotics.ftchelper.mechanism.PositionMotor
All Implemented Interfaces:
Subsystem

public class PositionMotor extends Object implements Subsystem
A motor that moves something to named positions and holds it there: a lift, an arm, a slide, a motor-driven claw. Everything from tutorials 07, 08 and 12 in one helper.

How it works, in short: a button only CHOOSES a target ("go to HIGH"). Then, once per loop, update() looks at where the motor is now (from its encoder, a sensor that counts how far the motor shaft has turned, in "ticks") and gives the motor just enough power to get there and stay there. The part that picks that power is a PID controller (tutorial 07 explains PID step by step).


 PositionMotor lift = PositionMotor.create(hardwareMap, "lift")
         .limits(0, 2600)                       // safe range (encoder ticks unless you set units)
         .lowerSwitch(hardwareMap, "lift_bottom")
         .slowZone(250, 0.2)
         .pid(0.004, 0, 0.0002, 0.05)
         .position("DOWN", 0)
         .position("LOW", 800)
         .position("HIGH", 2400)
         .tunable("Lift");                      // gains and positions in the tuning menu

 controls.bindPress(Pad.G2, Btn.Y, () -> lift.goTo("HIGH"))       // a button
         .bindPress(Pad.G2, Btn.DPAD_UP, lift::stepUp);
 routine.step("Lift up", lift.goToStep("HIGH"));                 // an autonomous step
 // every loop (or put it in a Subsystems group):
 lift.manual(-gamepad2.left_stick_y);   // the stick takes over; let go = hold where it is
 lift.update();
 

Positive power must move toward the larger positions (up / out). Check it with the hardware check. Safety comes from SafeMotor: limits, the switch, homing and the slow zone. Software limits do not replace a hard stop (rule R105 B in 2026-27). Docs: docs/modules/mechanism.md (and docs/guides/non-blocking.md for why commands never wait)

  • Constructor Summary

    Constructors
    Constructor
    Description
    PositionMotor(String name, com.qualcomm.robotcore.hardware.DcMotorEx motor)
    Wraps a motor you already set up (brake mode, encoder reset).
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    Shows its state on the Driver Station: warnings first, then target and position; more in debug mode.
    create(com.qualcomm.robotcore.hardware.HardwareMap hardwareMap, String name)
    Gets the motor (brake, encoder reset, plain power) and wraps it.
    fence(double lo, double hi)
    A second, temporary range inside the limits, in units, set every loop by an interlock rule (two parts that must not be in the same space).
    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 stick's power from the last manual(double) call (0 = not moving it by hand).
    The PID controller inside.
    double
    The position now, in units.
    The safety layer inside (limits, switches, powers).
    double
    The target, in units (NaN = none: no target, or the stick is moving it).
    What it is doing, for telemetry: the target's name, "hand" (the stick is moving it), "hold" (holding a spot with no name) or "none" (no power).
    "" or the last setup/command problem (missing switch, unknown position name).
    void
    goTo(double value)
    Go to a position in units and hold it.
    void
    goTo(String positionName)
    Go to a named position and hold it.
    goToStep(String positionName)
    A step: go to a named position and wait until there (or the step timeout).
    void
    Holds the current position.
    holdWhenReleased(boolean hold)
    True (default): when the driver lets go of manual control, it holds where it is.
    boolean
    isAt(String positionName)
    True when at this named position (within the tolerance).
    boolean
    True when holding a target and within the tolerance.
    boolean
    True while the fence keeps it from its target (it waits at the fence's edge).
    boolean
    True while waiting to be homed on the lower switch.
    limits(double min, double max)
    The safe range, from min to max, in units.
    lowerSwitch(com.qualcomm.robotcore.hardware.HardwareMap hardwareMap, String switchName)
    A lower limit switch, by its configuration name (a touch sensor).
    A lower limit switch, read your own way (e.g.
    void
    manual(double power)
    Manual control, e.g.
    maxPower(double power)
    The most power it ever gets, 0 to 1.
    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; tutorial 07 tunes them on a lift).
    position(String positionName, double value)
    Adds a named position, in units, e.g.
    Positive power turns the other way.
    slowZone(double distance, double powerAtLimit)
    Slow down within distance units of a limit, down to powerAtLimit (0 to 1), so it does not slam into the end of its travel.
    startStep(String positionName)
    A step: start moving to a named position and go straight on (it keeps moving during the next steps).
    void
    One named position down.
    stepTimeout(double seconds)
    How long autonomous steps wait for a position before going on.
    void
    One named position up (by value).
    void
    Stops: no target, no power.
    tolerance(double units)
    How close counts as "there", in units.
    tunable(String prefix)
    Puts the PID gains and every named position in the tuning menu, as "prefix/kP", "prefix/HIGH"...
    units(double ticksPerUnit, String unitName)
    Use your own units instead of encoder ticks, e.g.
    void
    Does the real work, once per loop: reads the switches, then sends the motor the power that moves it toward the target (or the stick's power, or none).
    An upper limit switch: while it is pressed, the motor will not go further up.
    void
    Makes the current position zero (home by hand).

    Methods inherited from class java.lang.Object

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

  • Method Details

    • create

      public static PositionMotor create(com.qualcomm.robotcore.hardware.HardwareMap hardwareMap, String name)
      Gets the motor (brake, encoder reset, plain power) and wraps it. Wrong name = clear error.
    • reversed

      public PositionMotor reversed()
      Positive power turns the other way. Set this BEFORE limits and positions are used.
    • units

      public PositionMotor units(double ticksPerUnit, String unitName)
      Use your own units instead of encoder ticks, e.g. degrees for an arm or inches for a slide. Set this FIRST: limits, positions, tolerance and slow zone are then in these units.
      Parameters:
      ticksPerUnit - encoder ticks per unit (measure it: move 90 degrees, read the ticks, divide)
      unitName - shown in telemetry, e.g. "deg"
    • limits

      public PositionMotor limits(double min, double max)
      The safe range, from min to max, in units. The motor will not drive past it.
    • slowZone

      public PositionMotor slowZone(double distance, double powerAtLimit)
      Slow down within distance units of a limit, down to powerAtLimit (0 to 1), so it does not slam into the end of its travel.
    • maxPower

      public PositionMotor maxPower(double power)
      The most power it ever gets, 0 to 1.
    • lowerSwitch

      public PositionMotor lowerSwitch(com.qualcomm.robotcore.hardware.HardwareMap hardwareMap, String switchName)
      A lower limit switch, by its configuration name (a touch sensor). Skipped if not in the configuration. Pressing the switch also sets the position to 0 ("homing"); until that happens the motor may only go down, slowly (see SafeMotor).
    • lowerSwitch

      public PositionMotor lowerSwitch(BooleanSupplier isPressed)
      A lower limit switch, read your own way (e.g. a magnetic switch: () -> !channel.getState()). () -> ... is a small piece of code we hand over to run later: SafeMotor runs it every loop.
    • upperSwitch

      public PositionMotor upperSwitch(BooleanSupplier isPressed)
      An upper limit switch: while it is pressed, the motor will not go further up.
    • pid

      public PositionMotor pid(double kP, double kI, double kD, double kF)
      PID gains (see docs/modules/control.md; tutorial 07 tunes them on a lift). Gains work on UNITS of error, so after units(...) the same gains suit a motor with a different encoder.
      Parameters:
      kP - push harder the further away it is
      kI - push harder the longer it stays a little short
      kD - calm it down when it moves fast (stops overshoot)
      kF - a steady extra push, e.g. to hold a lift up against gravity
    • tolerance

      public PositionMotor tolerance(double units)
      How close counts as "there", in units. Default: about 20 encoder ticks.
    • position

      public PositionMotor position(String positionName, double value)
      Adds a named position, in units, e.g. position("HIGH", 2400).
    • holdWhenReleased

      public PositionMotor holdWhenReleased(boolean hold)
      True (default): when the driver lets go of manual control, it holds where it is. False: it gets no power when let go (it may drift or fall).
    • stepTimeout

      public PositionMotor stepTimeout(double seconds)
      How long autonomous steps wait for a position before going on. Default 3 s.
    • tunable

      public PositionMotor tunable(String prefix)
      Puts the PID gains and every named position in the tuning menu, as "prefix/kP", "prefix/HIGH"... Call it LAST in the setup chain (after all positions). See docs/modules/tuning.md.
    • goTo

      public void goTo(String positionName)
      Go to a named position and hold it. An unknown name (a typo) does nothing and shows a warning, so a typo in a button never stops the OpMode in a match.
    • getWarning

      public String getWarning()
      "" or the last setup/command problem (missing switch, unknown position name).
    • goTo

      public void goTo(double value)
      Go to a position in units and hold it.
    • stepUp

      public void stepUp()
      One named position up (by value). From between positions, the next one above.
    • stepDown

      public void stepDown()
      One named position down. From between positions, the next one below.
    • manual

      public void manual(double power)
      Manual control, e.g. a stick, -1 to 1. Any non-zero value cancels the target. Call it every loop with the stick value (0 when the stick is let go). When it goes back to 0, it holds where it is (unless holdWhenReleased(false)).
    • hold

      public void hold()
      Holds the current position.
    • stop

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

      public PositionMotor fence(double lo, double hi)
      A second, temporary range inside the limits, in units, set every loop by an interlock rule (two parts that must not be in the same space). It does not move past it: a target beyond it waits at its edge (isHeld()) and goes on when the fence moves. fence(-inf, +inf) removes it.
    • fence

      public PositionMotor 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 part comes near its fence fast (and sets 0 to brake), so it stops before the edge instead of coasting past it.
      Parameters:
      lo - lowest target allowed (units; -infinity = none)
      hi - highest target allowed (units; +infinity = none)
      upPower - the most power toward higher positions now, 0 to 1 (1 = no cap)
      downPower - the most power toward lower positions now, 0 to 1
    • isHeld

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

      public double getTarget()
      The target, in units (NaN = none: no target, or the stick is moving it). For interlock rules.
    • getManualPower

      public double getManualPower()
      The stick's power from the last manual(double) call (0 = not moving it by hand).
    • zeroHere

      public void zeroHere()
      Makes the current position zero (home by hand).
    • update

      public void update()
      Does the real work, once per loop: reads the switches, then sends the motor the power that moves it toward the target (or the stick's power, or none). Never waits.
      Specified by:
      update in interface Subsystem
    • goToStep

      public AutoStep goToStep(String positionName)
      A step: go to a named position and wait until there (or the step timeout). Only for autonomous: the step waits on purpose, and keeps updating every mechanism while it waits.
    • startStep

      public AutoStep startStep(String positionName)
      A step: start moving to a named position and go straight on (it keeps moving during the next steps).
    • isAtTarget

      public boolean isAtTarget()
      True when holding a target and within the tolerance.
    • isAt

      public boolean isAt(String positionName)
      True when at this named position (within the tolerance).
    • getPosition

      public double getPosition()
      The position now, in units.
    • getTargetName

      public String getTargetName()
      What it is doing, for telemetry: the target's name, "hand" (the stick is moving it), "hold" (holding a spot with no name) or "none" (no power).
    • isWaitingForHoming

      public boolean isWaitingForHoming()
      True while waiting to be homed on the lower switch.
    • getSafeMotor

      public SafeMotor getSafeMotor()
      The safety layer inside (limits, switches, powers).
    • getPid

      public PidController getPid()
      The PID controller inside.
    • 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
    • addTelemetry

      public void addTelemetry(RobotTelemetry t)
      Shows its state on the Driver Station: warnings first, then target and position; more in debug mode.
      Specified by:
      addTelemetry in interface Subsystem