Skip to content

Mechanisms

A Mechanism is one subsystem: an arm, a claw, a drivetrain. It holds the hardware for that subsystem, the commands that move it, and any logic that has to run every loop.

interface Mechanism {
fun periodic() {}
val defaultCommand: Command get() = infinite {}
fun instant(action: Runnable): CommandBuilder
fun infinite(action: Runnable): CommandBuilder
fun coroutine(body: suspend CommandScope.() -> Unit): CoroutineCommandBuilder
}

Runs once per loop, for every mechanism listed in your NextRobot’s mechanisms set. Put anything here that has to run no matter which command is active: reading a sensor, or a PID loop holding a position.

Both build an Ivy command and call requiring(this) on it, so the scheduler knows the command owns this mechanism. Two commands can never drive the same hardware at the same time. instant runs its action once. infinite re-runs its action every loop until something cancels it.

Kotlin has a third: coroutine { } builds a coroutine command requiring this mechanism, for anything with steps in it.

The command that runs whenever nothing else has claimed the mechanism. NextFTC schedules it when the OpMode starts, at the lowest possible priority, so any real command you bind takes over and the default resumes once that command ends. The default default does nothing, so override it only if idle should mean something specific: holding an arm at its current position, or zeroing a motor’s throttle.

class Claw : Mechanism {
val servo = NextServo("clawServo")
fun open() = instant { servo.position = 0.2 }
fun close() = instant { servo.position = 0.8 }
}

Here’s an intake that stops itself once a distance sensor says it has a game piece. The check lives in periodic(), so it happens whether or not the intake command is running:

class Intake : Mechanism {
val motor = NextMotor("intakeMotor")
val sensor = NextDistanceSensor("intakeSensor")
override fun periodic() {
sensor.update()
if (sensor.isWithinDistance(2.0)) {
motor.throttle = 0.0
}
}
fun run() = instant { motor.throttle = 1.0 }
}

periodic() only runs if the mechanism is in your NextRobot’s mechanisms set. Forgetting to add it there is the usual reason this kind of code seems to do nothing.