Skip to content
CrocoDocs
Starter GuideProgrammingEngineeringDesignPortfolio
Documentation

Introduction

IntroductionBIOBUZZ game overview

Getting started

Getting startedBlocksOnBot JavaAndroid StudioYour first OpModeJava basicsMotors and servosNonblocking codeDebugging robot code

Control systems

Control systemsJoystick mappingField-centric mecanum drivePID controlFeedforwardFlywheel velocity controlSystem identificationMotion profilingKalman filterLow-pass filter

Autonomous

AutonomousTimed and encoder movementOdometryLocalization troubleshootingMotion planningReliable autonomous sequencesPure PursuitSensor fusionAuto to TeleOp handoff

Season topics

Season topicsProjectile mathematicsTurret aimingShooting on the move

Code practices

Code practicesNaming conventionsCode organizationLoop timing and bulk readsFormattingComments and documentationTeam collaboration

Libraries

LibrariesNextFTCFTCLibSolversLibPedro PathingRoad RunnerFTC DashboardMercurial v2Mercurial v1PanelsSloth

Community software

Community softwareBlaze FTCOpenLoopHive Vision

Sensors and vision

Vision overviewVision basicsLimelight 3A
Starter Guide
Engineering
Design
Portfolio
Appearance

SolversLib

Install SolversLib core and run a command sequence with a responsive OpMode

SolversLib groups actions into commands that a scheduler advances during each loop. It is a maintained fork of FTCLib with its own packages, releases, and changes. Begin with a sequence that prints telemetry before adding moving hardware.

Version and setup

Checked 14 October 2026: the current published core artifact is 0.3.6. Recent source changes include a Pedro 3 migration, controller fixes, and a stop-during- lifecycle fix. These changes show recent maintenance; test compatibility with your robot configuration.

In an Android Studio project, add the repository and core dependency to the appropriate Gradle configuration:

repositories {
    maven { url 'https://repo.dairy.foundation/releases' }
}

dependencies {
    implementation 'org.solverslib:core:0.3.6'
}

The artifact group is org.solverslib, while imports begin with com.seattlesolvers.solverslib. If migrating from FTCLib, remove its core dependency and deliberately migrate the imports and lifecycle.

The optional pedroPathing and photon modules are separate dependencies. Core is enough for this exercise. The Pedro module's 0.3.6 line targets Pedro 3; older 0.3.5 examples use Pedro 2. Follow the matching module setup when adding path following.

Command lifecycle

An instant command performs one action when initialized. A wait command completes after its specified duration while the scheduler continues running. A sequential group starts each command after the previous one finishes.

Scheduling can initialize a command immediately. A command that sets power can therefore move hardware during INIT if scheduled there. In this example, initialize() prepares the OpMode and preRun() schedules the sequence after START.

CommandOpMode owns the runOpMode() lifecycle. Keep super.run() in an overridden run() method so the scheduler advances. Do not add a second runOpMode() or a separate waitForStart() to this subclass.

First sequence

Save this complete Java example as SolversCommandPreview.java in the TeamCode package shown below. It uses SolversLib 0.3.6 and FTC SDK 12, and prints telemetry without controlling a motor.

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.seattlesolvers.solverslib.command.CommandOpMode;
import com.seattlesolvers.solverslib.command.InstantCommand;
import com.seattlesolvers.solverslib.command.SequentialCommandGroup;
import com.seattlesolvers.solverslib.command.WaitCommand;

@TeleOp(name = "Solvers Command Preview")
public class SolversCommandPreview extends CommandOpMode {
    private String stage = "Waiting for START";

    @Override public void initialize() {
        telemetry.addLine(stage);
        telemetry.update();
    }

    @Override public void initialize_loop() {
        idle();
    }

    @Override public void preRun() {
        schedule(new SequentialCommandGroup(
                new InstantCommand(() -> stage = "First command"),
                new WaitCommand(1000),
                new InstantCommand(() -> stage = "Finished")
        ));
    }

    @Override public void run() {
        super.run(); // Runs the command scheduler.
        telemetry.addData("Stage", stage);
        telemetry.update();
        idle();
    }
}

Select the , press INIT, then START. The stage changes to First command, waits about one second, then changes to Finished. WaitCommand(1000) uses milliseconds. The wait is scheduler-driven; the OpMode loop still updates telemetry.

Change the wait to 2000 ms and repeat. Then press STOP during the wait. The framework handles its end/reset lifecycle in cleanup; the example does not need a separate scheduler thread.

Adding a mechanism

A command that operates a motor needs a subsystem requirement so conflicting commands cannot control the same hardware simultaneously. Define its completion condition and interrupted cleanup before adding it to a sequence. Cancellation should leave the in an intentional state; zero motor power alone may not support a vertical load.

Use FTCLib for a comparison of command composition, and nonblocking code for the underlying state-machine idea. SolversLib's APIs and lifecycle must still be checked independently of FTCLib examples.

Sources

  • SolversLib installation
  • SolversLib 0.3.6 source
  • Published core metadata · 0.3.6 source archive
  • Project licence notices · inherited source notice

FTCLib

Run a command sequence after START and clean up when it ends

Pedro Pathing

Build and test your first path with Pedro Pathing 3

On this page

Version and setupCommand lifecycleFirst sequenceAdding a mechanismSources