Class PositionMotor
java.lang.Object
com.crossbotics.ftchelper.mechanism.PositionMotor
- All Implemented Interfaces:
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
ConstructorsConstructorDescriptionPositionMotor(String name, com.qualcomm.robotcore.hardware.DcMotorEx motor) Wraps a motor you already set up (brake mode, encoder reset). -
Method Summary
Modifier and TypeMethodDescriptionvoidShows its state on the Driver Station: warnings first, then target and position; more in debug mode.static PositionMotorGets 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.doubleThe stick's power from the lastmanual(double)call (0 = not moving it by hand).getPid()The PID controller inside.doubleThe position now, in units.The safety layer inside (limits, switches, powers).doubleThe 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).voidgoTo(double value) Go to a position in units and hold it.voidGo to a named position and hold it.A step: go to a named position and wait until there (or the step timeout).voidhold()Holds the current position.holdWhenReleased(boolean hold) True (default): when the driver lets go of manual control, it holds where it is.booleanTrue when at this named position (within the tolerance).booleanTrue when holding a target and within the tolerance.booleanisHeld()True while the fence keeps it from its target (it waits at the fence's edge).booleanTrue while waiting to be homed on the lower switch.limits(double min, double max) The safe range, frommintomax, in units.lowerSwitch(com.qualcomm.robotcore.hardware.HardwareMap hardwareMap, String switchName) A lower limit switch, by its configuration name (a touch sensor).lowerSwitch(BooleanSupplier isPressed) A lower limit switch, read your own way (e.g.voidmanual(double power) Manual control, e.g.maxPower(double power) The most power it ever gets, 0 to 1.name()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).Adds a named position, in units, e.g.reversed()Positive power turns the other way.slowZone(double distance, double powerAtLimit) Slow down withindistanceunits of a limit, down topowerAtLimit(0 to 1), so it does not slam into the end of its travel.A step: start moving to a named position and go straight on (it keeps moving during the next steps).voidstepDown()One named position down.stepTimeout(double seconds) How long autonomous steps wait for a position before going on.voidstepUp()One named position up (by value).voidstop()Stops: no target, no power.tolerance(double units) How close counts as "there", in units.Puts the PID gains and every named position in the tuning menu, as "prefix/kP", "prefix/HIGH"...Use your own units instead of encoder ticks, e.g.voidupdate()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).upperSwitch(BooleanSupplier isPressed) An upper limit switch: while it is pressed, the motor will not go further up.voidzeroHere()Makes the current position zero (home by hand).
-
Constructor Details
-
PositionMotor
Wraps a motor you already set up (brake mode, encoder reset). Most teams usecreate(com.qualcomm.robotcore.hardware.HardwareMap, java.lang.String)instead.
-
-
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
Positive power turns the other way. Set this BEFORE limits and positions are used. -
units
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
The safe range, frommintomax, in units. The motor will not drive past it. -
slowZone
Slow down withindistanceunits of a limit, down topowerAtLimit(0 to 1), so it does not slam into the end of its travel. -
maxPower
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 (seeSafeMotor). -
lowerSwitch
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
An upper limit switch: while it is pressed, the motor will not go further up. -
pid
PID gains (see docs/modules/control.md; tutorial 07 tunes them on a lift). Gains work on UNITS of error, so afterunits(...)the same gains suit a motor with a different encoder.- Parameters:
kP- push harder the further away it iskI- push harder the longer it stays a little shortkD- calm it down when it moves fast (stops overshoot)kF- a steady extra push, e.g. to hold a lift up against gravity
-
tolerance
How close counts as "there", in units. Default: about 20 encoder ticks. -
position
Adds a named position, in units, e.g.position("HIGH", 2400). -
holdWhenReleased
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
How long autonomous steps wait for a position before going on. Default 3 s. -
tunable
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
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
"" 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 (unlessholdWhenReleased(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. -
fence
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
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 lastmanual(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. -
goToStep
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
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
True when at this named position (within the tolerance). -
getPosition
public double getPosition()The position now, in units. -
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
The safety layer inside (limits, switches, powers). -
getPid
The PID controller inside. -
name
Description copied from interface:SubsystemThe name shown in telemetry and in the hardware check. -
addTelemetry
Shows its state on the Driver Station: warnings first, then target and position; more in debug mode.- Specified by:
addTelemetryin interfaceSubsystem
-