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

Mercurial v1

Commands, requirements, and a timed motor example for legacy Mercurial v1

Legacy version

Mercurial v1 is the older command-based framework. Use this guide for existing v1 projects. For the newer API, see Mercurial v2.

Overview

Mercurial v1 is a command-based framework from Dairy Foundation. Its command API models actions with lifecycle methods, requirements, and run states; command groups and a scheduler coordinate those actions. The ecosystem also includes libraries such as Core, Util, and Pasteurized, but the modules and setup depend on the release and project template.

Version and installation

This example uses dev.frozenmilk.mercurial:Mercurial:1.0.3. Keep the compatible Core, Util, and Pasteurized dependencies from your v1 project setup. The v1 documentation and Dairy project templates describe how those modules fit together.

Core concepts

  • Commands describe setup, repeated execution, completion, and cleanup behavior.
  • Requirements identify resources a command needs so the scheduler can handle conflicting commands.
  • Run states control when a command may be scheduled, such as initialization or active .
  • Command groups combine actions sequentially, in parallel, or conditionally.
  • Subsystems organize the hardware and behavior owned by a .

Motor example

Configure an unloaded as testMotor. Save the selected complete class as MercurialMotorTest.java or .kt, adding your TeamCode package declaration before its imports. This example uses v1 1.0.3 and the compatible Dairy setup described above.

import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.util.ElapsedTime;
import dev.frozenmilk.mercurial.Mercurial;
import dev.frozenmilk.mercurial.commands.Lambda;

@Autonomous(name = "Mercurial: Timed Motor Test")
@Mercurial.Attach
public class MercurialMotorTest extends OpMode {
    private DcMotor motor;
    private final ElapsedTime timer = new ElapsedTime();
    private final Object motorRequirement = new Object();
    private Lambda runMotor;

    @Override
    public void init() {
        motor = hardwareMap.get(DcMotor.class, "testMotor");
        motor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
        runMotor = new Lambda("Run motor briefly")
            .setInit(timer::reset)
            .setExecute(() -> motor.setPower(0.15))
            .setFinish(() -> timer.seconds() >= 1.0)
            .setEnd(interrupted -> motor.setPower(0.0))
            .setRequirements(motorRequirement);
    }

    @Override
    public void start() {
        runMotor.schedule();
    }

    @Override
    public void loop() {
        telemetry.addData("Elapsed seconds", "%.2f", timer.seconds());
        telemetry.update();
    }

    @Override
    public void stop() {
        if (motor != null) motor.setPower(0.0);
    }
}
import com.qualcomm.robotcore.eventloop.opmode.Autonomous
import com.qualcomm.robotcore.eventloop.opmode.OpMode
import com.qualcomm.robotcore.hardware.DcMotor
import com.qualcomm.robotcore.util.ElapsedTime
import dev.frozenmilk.mercurial.Mercurial
import dev.frozenmilk.mercurial.commands.Lambda

@Autonomous(name = "Mercurial: Timed Motor Test")
@Mercurial.Attach
class MercurialMotorTest : OpMode() {
    private lateinit var motor: DcMotor
    private val timer = ElapsedTime()
    private val motorRequirement = Any()
    private lateinit var runMotor: Lambda

    override fun init() {
        motor = hardwareMap.get(DcMotor::class.java, "testMotor")
        motor.zeroPowerBehavior = DcMotor.ZeroPowerBehavior.BRAKE
        runMotor = Lambda("Run motor briefly")
            .setInit { timer.reset() }
            .setExecute { motor.power = 0.15 }
            .setFinish { timer.seconds() >= 1.0 }
            .setEnd { _: Boolean -> motor.power = 0.0 }
            .setRequirements(motorRequirement)
    }

    override fun start() {
        runMotor.schedule()
    }

    override fun loop() {
        telemetry.addData("Elapsed seconds", "%.2f", timer.seconds())
        telemetry.update()
    }

    override fun stop() {
        if (::motor.isInitialized) motor.power = 0.0
    }
}

Hardware mapping and command construction happen in init(). Scheduling happens in start(). The command resets its timer once, requests low motor power on each execution, and finishes after one second. Its end callback removes power whether it finishes normally or is interrupted. The OpMode's stop() also writes zero.

The shared motorRequirement identifies the resource. Reuse that same object in other commands controlling this motor so requirements can prevent conflicts. Do not create a fresh marker for each command and expect them to exclude one another.

Test , START, command completion, and STOP on the robot before using the command in a larger routine.

Team fit

A command framework can make shared behaviors and sequences easier to compose, but it adds concepts and dependencies. Compare the framework with your team's experience, the current project template, and the level of support available before adopting it. A small robot can also be programmed directly with FTC SDK OpModes.

Sources

  • Mercurial documentation
  • Command overview
  • Mercurial v1 source
  • Dairy FTC Gradle plugins
  • Dairy project templates
  • Dairy Foundation
  • pinned v1 source

Mercurial v2

Programs, sequences, and concurrent robot tasks with Mercurial v2

Panels

Install Lazar's Panels, send browser telemetry, and tune bounded configuration values

On this page

OverviewVersion and installationCore conceptsMotor exampleTeam fitSources