ValleyLib¶
ValleyLib is a modern, command-based robotics library for FIRST Tech Challenge (FTC), heavily inspired by WPILib and FTCLib. It brings the proven command-based programming paradigm from FRC to FTC, with first-class support for Pedro Pathing, the Panels dashboard, and desktop simulation.
If you have written FRC code with WPILib — or FTC code with FTCLib — you will feel at home immediately. If you haven't, the Quickstart walks you through everything from scratch.
Season note
2.0.0 is the first ValleyLib release for BIOBUZZ, the 2026-2027 FTC season — it targets FTC SDK 12 and Pedro Pathing 3. Teams still on DECODE should stay on 1.0.8; see the Changelog for what changed and the Pedro migration guide for how to move.
Why command-based?¶
Traditional FTC OpModes tend to grow into giant loop() methods full of if statements and state machines. Command-based programming replaces that with two simple building blocks:
- Subsystems represent your hardware (drivetrain, intake, lift, ...). They expose high-level actions and own their motors and sensors.
- Commands represent behavior (drive forward, run the intake for 2 seconds, follow a path, ...). They have a well-defined lifecycle and can be composed like Lego bricks.
A central CommandScheduler runs everything, enforces that two commands never fight over the same subsystem, and runs default commands (like joystick driving) whenever a subsystem is idle.
// An entire autonomous routine, readable top to bottom:
driveCommand
.until(robot::atTarget)
.andThen(intakeCommand.withTimeout(1.0))
.finallyDo(() -> drive.stop());
The two modules¶
| Module | Contents | Platform |
|---|---|---|
valleyLib-core |
The command framework: Command, CommandScheduler, Subsystem, command groups, decorators, and the AutoDsl autonomous builder. |
Pure Java — runs on desktop for tests and simulation. |
valleyLib-ftc |
Everything FTC-specific: CommandOpMode, gamepad/trigger bindings, motor wrappers, PID/feedforward controllers, telemetry, and Pedro Pathing integration. |
Android (FTC SDK). |
This separation means your command logic can be unit-tested and simulated on your laptop without a robot — see Desktop Simulation & Testing.
Feature overview¶
-
Fluent Command API — every command supports decorators like
withTimeout,until,unless,andThen,alongWith,raceWith,deadlineWith,repeatedly, and more. → Decorators -
Command groups & factories — sequential, parallel, race, deadline, and conditional groups, plus the
Commandsfactory class for quick one-liners. → Command Groups -
Automatic scheduling — subsystem requirements, default commands, lifecycle listeners, safe interruption, and requirement-carrying subsystem factories (
drive.run(...),intake.startEnd(...)), all handled by one scheduler. → Scheduler / Subsystems -
Gamepad triggers — WPILib-style
Triggerbindings (onTrue,whileTrue,toggleOnTrue, ...) that auto-register with the loop poller, with Xbox and PlayStation naming, deadbands, and response curves. → Gamepads / Triggers -
Hardware wrappers — FTCLib-style
Motor,MotorEx, andMotorGroupwith built-in encoders, velocity/position control, and GoBILDA presets. → Hardware -
Control theory toolbox — a full
PIDFControllerfamily plus WPILib'sSimpleMotorFeedforward. → Control -
Pedro Pathing, command-based —
PedroSubsystem,FollowPathCommand, and a path-first autonomous DSL that replaces state machines entirely. → Pedro Pathing -
Telemetry & logging — one
FtcTelemetryBusthat mirrors data to the Driver Station and the Panels dashboard, plus automatic command lifecycle logging. → Telemetry -
Autonomous DSLs — declarative builders (
AutoDsl,PedroAutoDsl) with markers, waits, conditionals, and parallel actions. → AutoDsl -
Finite state machines — a first-class
StateMachinecommand: enum states, per-state commands, enter/exit hooks, condition/finish/timeout/global transitions, and terminal states — replacesswitch(pathState)loops entirely. → State Machines -
Desktop simulation —
simulationPeriodic()hooks and a simulation mode on the scheduler for hardware-free iteration. → Simulation
At a glance: a complete TeleOp¶
@TeleOp(name = "My TeleOp")
public class MainTeleOp extends CommandOpMode {
private DriveSubsystem drive;
private IntakeSubsystem intake;
private CommandGamepad driver;
@Override
protected void initialize() {
drive = new DriveSubsystem(hardwareMap);
intake = new IntakeSubsystem(hardwareMap);
driver = CommandGamepad.forLogitechF310(gamepad1);
}
@Override
protected void configureBindings() {
// Joystick driving whenever nothing else uses the drivetrain
drive.setDefaultCommand(drive.run(() ->
drive.tankDrive(driver.leftY(), driver.rightY())));
// Hold A to intake, hold B to eject — bindings register themselves
driver.a().whileTrue(intake.startEnd(intake::in, intake::stop));
driver.b().whileTrue(intake.startEnd(intake::out, intake::stop));
}
@Override
protected void run() {
telemetryBus.put("Drive", "active");
}
}
That's the whole OpMode. No manual follower.update(), no telemetry bookkeeping, no state machine — CommandOpMode handles the loop.
Where to go next¶
- Installation — add ValleyLib to your TeamCode project via JitPack.
- Quickstart — build your first subsystem, robot container, and OpMode.
- Commands — learn the core abstraction everything else builds on.
- Finite State Machines — how to express cycles, loops, and overrides as a
StateMachinecommand. - API Summary — a one-page index of every public class in the library.