All pages
Powered by GitBook
1 of 7

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Programming - Controlling the Arm and Wrist

Setting up the Arm and Wrist Motors:

Setting the mode and target position for the motors

As part of our main loop, our arm and wrist motors are set to RUN_TO_POSITION mode with their TargetPosition set to the appropriate variable. Additionally, our arm and wrist motors are set to full power whenever they are moving.

Because our targetArm and targetWrist values change throughout our code, we include this as part of our loop rather than initialization.

Preset Movements

The GAMEPAD_INPUT_STATE function contains all our code for controlling the arm and wrist. Let's break it down by what each button does in our If/Else statement!

Pressing A/Cross

When the A/Cross button on the gamepad is pressed our currentState switches to INTAKE meaning our robot's arm will move down and wrist will unfold to be ready to pick up samples.

Pressing B/Circle

This section of code allows for a togglable state between two positions of our arm/wrist when B/Circle are pressed. Because we want this to be togglable and not require the button to be held, we want to have our robot check the state of the B/Circle button each loop.

The lastGrab variable will change between true or false based on the state of the button. If the driver holds down the B/Circle button its state will not update again until it is first released.

If B/Circle is pressed AND is not currently held then the robot will run a second if/then statement to determine which of the Wall positions the arm/wrist should move to.

With this statement the robot knows that if the arm is already at our WALL_GRAB preset it should move to unhook. The opposite is also true where if the arm/wrist is in the WALL_UNHOOK preset it will go back to grab.

Pressing Y/Triangle

This section functions similarly to B/Circle providing a togglable control for clipping a specimen!

In this case lastHook allows the robot to determine if the Y/Triangle button is being held before the robot moves between the two positions.

Pressing X/Square

When the X/Square button on the gamepad is pressed our currentState switches to LOW_BASKET meaning our robot's arm will move up and wrist will unfold to be ready to deposit samples in the low basket.

Pressing Left Bumper

It's always good to have a way to reset our robot if needed! By pressing left bumper, currentState will be set to INIT moving our robot back to its initilization configuration, like what might be used at the start of a match.

Manual Control

Beyond our preset movements, we want our robot to have refined control for the arm and wrist as we navigate the field.

Whenever we press a button on the d-pad our currentState will switch to MANUAL allowing the arm or wrist to move in increments until the button is released.

Because we have our motors set to "RUN_TO_POSITION" mode we can't just turn the power on for manual control. Instead we have the robot changing the position in the appropriate direction in chunks. Depending our your driver's preference, you may choose to adjust these values for quicker or more refined control!

By default, these position values are different in the OnBot Java and Blocks version of the provided code. This is due to a difference in how quickly OnBot Java loops through a program compared to Blocks.

Programming - OnBot Java Overview

While most of our example program is the same between Blocks and OnBot Java there are a couple differences and some cool parts to the OnBot Java code we want to point out here!

Using "enum" for variables

In the OnBot Java version of this code, we use something called "enum". This allows us to declare the variable name and have it treated as a unique value.

    private enum RobotState {
        INIT,
        INTAKE,
        WALL_GRAB,
        WALL_UNHOOK,
        HOVER_HIGH,
        CLIP_HIGH,
        LOW_BASKET,
        MANUAL
    }

For example: the robot interprets the variable "MANUAL" as one of the states within our switch case in OnBot Java.

With these variables defined we can now have all of our preset positions stored and easily updatable in our state machine:

 // State machine logic
            switch (currentState) {
                case INIT:
                    targetArm = ARM_POSITION_INIT;
                    targetWrist = WRIST_POSITION_INIT;
                    telemetry.addData("State", "INIT");
                    break;
                case INTAKE:
                    targetArm = ARM_POSITION_INTAKE;
                    targetWrist = WRIST_POSITION_SAMPLE;
                    telemetry.addData("State", "INTAKE");
                    break;

                case WALL_GRAB:
                    targetArm = ARM_POSITION_WALL_GRAB;
                    targetWrist = WRIST_POSITION_SPEC;
                    telemetry.addData("State", "WALL_GRAB");
                    break;

                case WALL_UNHOOK:
                    targetArm = ARM_POSITION_WALL_UNHOOK;
                    targetWrist = WRIST_POSITION_SPEC;
                    telemetry.addData("State", "WALL_UNHOOK");
                    break;

                case HOVER_HIGH:
                    targetArm = ARM_POSITION_HOVER_HIGH;
                    targetWrist = WRIST_POSITION_SPEC;
                    telemetry.addData("State", "HOVER_HIGH");
                    break;
                    
                case CLIP_HIGH:
                    targetArm = ARM_POSITION_CLIP_HIGH;
                    targetWrist = WRIST_POSITION_SPEC;
                    telemetry.addData("State", "CLIP_HIGH");
                    break;
                case LOW_BASKET:
                    targetArm = ARM_POSITION_LOW_BASKET;
                    targetWrist = WRIST_POSITION_SAMPLE;
                    telemetry.addData("State", "LOW_BASKET");
                    break;
                case MANUAL:
                    telemetry.addData("State", "MANUAL");
                    break;
            }

Our robot will switch states depending on which button on the gamepad is pressed for the arm/wrist!

Creating a Togglable Button

Within our program there are a few buttons set up to work like a toggle. This means the button only needs to be pressed once rather than held for the code to run. In our Starter Bot code, we're taking advantage of this toggle to have one button be able to do multiple things. For example, our claw can switch between open and closed with just the right bumper.

            // Toggle claw position when right_bumper is pressed
            if (gamepad1.right_bumper && !lastBump) {
                clawOpen = !clawOpen;
                if (clawOpen) {
                    claw.setPosition(CLAW_OPEN_POSITION);
                } else {
                    claw.setPosition(CLAW_CLOSED_POSITION);
                }
            }
            lastBump = gamepad1.right_bumper;

In other programming languages, you might have an option such as "on button pressed", however that's not available to us here so we have to be a little clever to mimic this concept. Our claw is using two simple variables to make this possible.

The variable clawOpen allows the servo to move between its two set positions. At the start of our program this is set to false, but will switch each time the right bumper is pressed.

Meanwhile the variable lastBump checks if the right bumper is currently being held down. If it is set to true, the button is held down so the claw will not move again until it is released, changing the value back to false, then pressed again.

Along with the claw, our robot is using a togglable button for retrieving specimens and hooking them on the high rung!

Full Code

            // Toggle claw position when right_bumper is pressed
            if (gamepad1.right_bumper && !lastBump) {
            //checks if right bumper is pressed AND has been released since last pressed
                clawOpen = !clawOpen;
            //switches the state of clawOpen, this is defined originally during initilization
                if (clawOpen) { 
                //if clawOpen = clawOpen  then open claw, else clawOpen = not clawOpen then close claw
                    claw.setPosition(CLAW_OPEN_POSITION);
                } else {
                    claw.setPosition(CLAW_CLOSED_POSITION);
                }
            }
            lastBump = gamepad1.right_bumper;
            //when right bumper is pressed this will set lastBump to true
package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.robot.Robot;
import com.qualcomm.robotcore.hardware.Servo;
import com.qualcomm.robotcore.robot.RobotState;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.CRServo;
import com.qualcomm.robotcore.util.Range;

@com.qualcomm.robotcore.eventloop.opmode.TeleOp(name="StarterBot_V1_Java", group="Linear Opmode")
public class StarterBot2025TeleOpJava extends LinearOpMode {

    // Declare OpMode members.
    private DcMotor leftDrive = null;
    private DcMotor rightDrive = null;
    private DcMotor arm = null;
    private DcMotor wrist = null;
    private Servo claw = null;
    private CRServo intake = null;


    // Arm and Wrist target positions for each state
    private static final int ARM_POSITION_INIT = 300;
    private static final int ARM_POSITION_INTAKE = 450;
    private static final int ARM_POSITION_WALL_GRAB = 1100;
    private static final int ARM_POSITION_WALL_UNHOOK = 1700;
    private static final int ARM_POSITION_HOVER_HIGH = 2600;
    private static final int ARM_POSITION_CLIP_HIGH = 2100;
    private static final int ARM_POSITION_LOW_BASKET = 2500;

    
    private static final int WRIST_POSITION_INIT = 0;
    private static final int WRIST_POSITION_SAMPLE = 270;
    private static final int WRIST_POSITION_SPEC = 10;


    
    // Claw positions
    private static final double CLAW_OPEN_POSITION = 0.55;
    private static final double CLAW_CLOSED_POSITION = 0.7;

    // Enum for state machine
    private enum RobotState {
        INIT,
        INTAKE,
        WALL_GRAB,
        WALL_UNHOOK,
        HOVER_HIGH,
        CLIP_HIGH,
        LOW_BASKET,
        MANUAL
    }

    // Initial state
    private RobotState currentState = RobotState.INIT;

    // Claw toggle state
    private boolean clawOpen = true;
    private boolean lastBump = false;
    private boolean lastHook = false;
    private boolean lastGrab = false;
    
    //target position
    private int targetArm = 0;
    private int targetWrist = 0;

    @Override
    public void runOpMode() {
        // Initialize the hardware variables.
        leftDrive  = hardwareMap.get(DcMotor.class, "leftDrive");
        rightDrive = hardwareMap.get(DcMotor.class, "rightDrive");
        arm = hardwareMap.get(DcMotor.class, "arm");
        wrist = hardwareMap.get(DcMotor.class, "wrist");
        claw = hardwareMap.get(Servo.class, "claw");
        intake = hardwareMap.get(CRServo.class, "intake");

        // Stop and reset encoders
        leftDrive.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        rightDrive.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        arm.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        wrist.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);

        // Set motors to use encoders
        leftDrive.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
        rightDrive.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
        
        // Set motor direction
        leftDrive.setDirection(DcMotor.Direction.REVERSE);
        rightDrive.setDirection(DcMotor.Direction.FORWARD);
        //Set zero power behavior
        wrist.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
        arm.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
        leftDrive.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.FLOAT);
        rightDrive.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.FLOAT);

        // Wait for the game to start (driver presses PLAY)
        waitForStart();

        // Run until the end of the match (driver presses STOP)
        while (opModeIsActive()) {

            // State machine logic
            switch (currentState) {
                case INIT:
                    targetArm = ARM_POSITION_INIT;
                    targetWrist = WRIST_POSITION_INIT;
                    telemetry.addData("State", "INIT");
                    break;
                case INTAKE:
                    targetArm = ARM_POSITION_INTAKE;
                    targetWrist = WRIST_POSITION_SAMPLE;
                    telemetry.addData("State", "INTAKE");
                    break;

                case WALL_GRAB:
                    targetArm = ARM_POSITION_WALL_GRAB;
                    targetWrist = WRIST_POSITION_SPEC;
                    telemetry.addData("State", "WALL_GRAB");
                    break;

                case WALL_UNHOOK:
                    targetArm = ARM_POSITION_WALL_UNHOOK;
                    targetWrist = WRIST_POSITION_SPEC;
                    telemetry.addData("State", "WALL_UNHOOK");
                    break;

                case HOVER_HIGH:
                    targetArm = ARM_POSITION_HOVER_HIGH;
                    targetWrist = WRIST_POSITION_SPEC;
                    telemetry.addData("State", "HOVER_HIGH");
                    break;
                    
                case CLIP_HIGH:
                    targetArm = ARM_POSITION_CLIP_HIGH;
                    targetWrist = WRIST_POSITION_SPEC;
                    telemetry.addData("State", "CLIP_HIGH");
                    break;
                case LOW_BASKET:
                    targetArm = ARM_POSITION_LOW_BASKET;
                    targetWrist = WRIST_POSITION_SAMPLE;
                    telemetry.addData("State", "LOW_BASKET");
                    break;
                case MANUAL:
                    telemetry.addData("State", "MANUAL");
                    break;
            }
            

            // Handle state transitions based on gamepad input
            if (gamepad1.a) {
                currentState = RobotState.INTAKE;
            } else if (gamepad1.b && !lastGrab) {
                if(currentState == RobotState.WALL_GRAB){
                    currentState = RobotState.WALL_UNHOOK;
                }else{
                    currentState = RobotState.WALL_GRAB;
                }
            } else if (gamepad1.y && !lastHook) {
                if(currentState == RobotState.HOVER_HIGH){
                    currentState = RobotState.CLIP_HIGH;
                }else{
                    currentState = RobotState.HOVER_HIGH;
                }
            } else if (gamepad1.x) { 
                currentState = RobotState.LOW_BASKET;           
            } else if (gamepad1.left_bumper) {
                currentState = RobotState.INIT;
            } else if (gamepad1.dpad_up){ //manual control
                currentState = RobotState.MANUAL;
                targetArm += 10;
            } else if (gamepad1.dpad_down){
                currentState = RobotState.MANUAL;
                targetArm -= 10;
            } else if (gamepad1.dpad_left){
                currentState = RobotState.MANUAL;
                targetWrist += 1;
            } else if (gamepad1.dpad_right){
                currentState = RobotState.MANUAL;
                targetWrist -= 1;
            }
            
            lastGrab = gamepad1.b;
            lastHook = gamepad1.y;

            // Toggle claw position when right_bumper is pressed
            if (gamepad1.right_bumper && !lastBump) {
                clawOpen = !clawOpen;
                if (clawOpen) {
                    claw.setPosition(CLAW_OPEN_POSITION);
                } else {
                    claw.setPosition(CLAW_CLOSED_POSITION);
                }
            }
            lastBump = gamepad1.right_bumper;

            // Control intake servo with triggers
            if (gamepad1.right_trigger>0.1) {
                intake.setPower(1.0);
            } else if (gamepad1.left_trigger>0.1) {
                intake.setPower(-1.0);
            } else {
                intake.setPower(0);
            }
            
            //DRIVE Split Arcade
            double drive = -gamepad1.left_stick_y;
            double turn  =  -gamepad1.right_stick_x;
            double leftPower    = Range.clip(drive + turn, -1.0, 1.0) ;
            double rightPower   = Range.clip(drive - turn, -1.0, 1.0) ;
    
            leftDrive.setPower(leftPower);
            rightDrive.setPower(rightPower);
            
            arm.setTargetPosition(targetArm);
            arm.setMode(DcMotor.RunMode.RUN_TO_POSITION);
            wrist.setTargetPosition(targetWrist);
            wrist.setMode(DcMotor.RunMode.RUN_TO_POSITION);
            arm.setPower(1);
            wrist.setPower(1);

            // Send telemetry data to the driver station
            telemetry.addData("Claw Position", clawOpen ? "Open" : "Closed");
            telemetry.addData("Arm Position", arm.getCurrentPosition());
            telemetry.addData("Arm Power", arm.getPower());
            telemetry.addData("Wrist Position", wrist.getCurrentPosition());
            telemetry.addData("Wrist Power", wrist.getPower());
            telemetry.update();
        }
    }
}

Programming TeleOp

Getting Started!

This year's Starter Bot program offers a slightly more technical solution than previous years. If your team is new to FTC, or in need of a review, we strongly recommend checking out our updated before diving in!

To begin, let's take a look at the configuration and actuators used in this year's design.

Configuration

Before getting started with programming we needed to create a . Below is an overview of how the robot is configured for the TeleOp code to function as expected:

Port Type
Port Number
Device Type
Name

Right click the file below and select "save link as". To put this configuration file on your robot, drag this file into the "FIRST" folder of your Control Hub's file system.

You will need to activate the configuration using the Driver Hub before proceeding.

Device Name
Device Type
Port

The 2024-25 REV DUO FTC Starter Bot is designed to use a split arcade drive for the default. Check out our page for the arcade drive version of the program.

In split arcade drive, the left joystick will control forward and reverse motion of the robot, and the right joystick will control turning. This is similar to how some RC cars are driven and video games are played.

Gamepad Input
Function

More information on programming gamepads for use with your robot can be found at .

Any updates to our example programs are documented in our

Quick Links

Motor

0

REV Robotics Ultraplanetary HD Hex Motor

arm

Motor

1

REV Robotics Core Hex Motor

wrist

Motor

2

REV Robotics Ultraplanetary HD Hex Motor

leftDrive

Motor

3

REV Robotics Ultraplanetary HD Hex Motor

rightDrive

Servo

4

Servo

claw

Servo

5

Continuous Servo

intake

arm

UltraPlanetary Gearbox Kit and HD Hex Motor

Motor/Encoder Port 0

wrist

Core Hex Motor

Right Joystick

Turn left and right

Left Joystick

Drive forward and reverse

A/Cross

Configuration File Download

Wiring Diagram

The Smart Robot Servo can be changed to

Gamepad Setup

Not all gamepads have buttons labeled the same way. Check the manufacturer's documentation for accurate button mapping.

2024-25 REV DUO FTC Starter Bot Gamepad Layout:

The REV USB PS4 Compatible Gamepad (REV-31-2983) has two remappable M-buttons on the back side of the controller. By default, these are mapped to circle and cross.

TeleOp Program Downloads

Blocks (v1.0.2):

Java (v1.0.1):

A version of the Blocks program without the arm and wrist motors moving to an initialization position is now available on start up on our

The following pages will be a deep dive into the Blocks code, grab your snorkel and let's get started!

Video Walkthrough

Upgrades
Check out FIRST's guide on uploading a Blocks program!
changelog.
StarterBot2025.xml
688B
Open
Wiring diagram for the 2024-25 Starter Bot
Starterbot2025TeleOpBlocks.blk
38KB
Open
StarterBot2025TeleOpJava.java
9KB
Open

Motor/Encoder Port 1

leftDrive

UltraPlanetary Gearbox Kit and HD Hex Motor

Motor/Encoder Port 2

rightDrive

UltraPlanetary Gearbox Kit and HD Hex Motor

Motor/Encoder Port 3

claw

Smart Robot Servo

Servo Port 4

intake

Smart Robot Servo - set to continuous mode

Servo Port 5

Intake Preset Position

  • Arm down, wrist out

B/Circle

Wall Grab and Unhook Preset Position

  • Arm up to grab, wrist in - first click

  • Arm up to unhook, wrist in - second click

Y/Triangle

Hover High and Clip High Preset Position

  • Arm up to low basket height, wrist in

  • Arm lower to clip, wrist in

X/Square

Low Basket Preset Position

  • Arm up to low basket height, wrist out

D-pad Up

Arm Up

D-pad Down

Arm Down

D-pad Left

Wrist Out

D-pad Right

Wrist In

Left Bumper

Reset arm/wrist to Initialization Position

Right Bumper

Claw toggle to open or close

Left Trigger

Reverse intake flaps

Right Trigger

Run intake flaps

Initialization and Variables
Creating Functions
Controlling the Arm and Wrist - Preset Positions
Controlling the Arm and Wrist - Manual Movement
Intake
Please see the product page for directions on remapping these buttons.
Tips & Tricks page.
Claw Toggle
Split Arcade Drive
Telemetry

Programming - Intake and Claw Toggle

Intake Control

When one of the triggers on the gamepad is pressed, it activates our GAMEPAD_INTAKE function. This simple if/then statement just checks which trigger is being pressed so our servo knows which way to rotate.

Because our servo is set to in our configuration, we have the ability to tell our servo to set a power instead of moving by position increments!

Claw Toggle Control

When the right bumper is pressed on the gamepad, the claw on the robot either opens or closed. This prevents the driver from having to hold down the button to maintain control of a picked up specimen!

Because togglable control is not natively available in the FTC SDK, we have to make use of a couple of variables to help the robot check the state of the claw's servo and the right bumper.

Similar to what's used in our arm control's presets, lastBump checks if the right bumper is being held down and won't accept another input until its been released.

Meanwhile, clawOpen allows the servo to shift between the two set positions based on where it has last moved to. You can adjust these values based on your specific robot to have the claw open more or less.

Programming - Creating Functions

This year in our Starter Bot Blocks code we are using "functions" for the first time.

Blocks Functions

What is a Function?

Functions act similar to a variable in that we are using one thing to represent another. However, where a variable typically is used in place of something short, such as a number or equation, a function can take the place of several lines of code.

This can be incredibly useful if there is a section of code we know will be repeated or to break apart our code into chunks for easy editing.

Below is a breakdown of our functions:

Function
Purpose

When using functions, our Blocks program becomes divided into different sections containing separate series of code:

So let's say we wanted to change how quickly our robot's arm moves during with the d-pad. With our functions organizing our code in chunks, it's easy to find the values we want to change:

Without the use of functions our code would end up a little long and clunky:

If we want to create a new function in our Blocks program, we start by pulling a block from the Functions menu:

Next we will replace "do something" with an appropriate name. Maybe in this case we are adding a new function for climbing:

Once our function is named it will appear in the "Functions" menu to be added to the main loop or wherever we need it within our code!

All that's left is to add whatever code we'd like to be within this function:

If the block is deleted this will remove the function from the "Functions" menu.

By default, the Starter Bot's program only references each function once during our loop. The following is intended to be an additional example for reusing functions throughout a program and as an additional educational resource!

Let's say we are working on an autonomous code where we want our robot to drive roughly in a square. Remember that autonomous means this code will move the robot on its own when play is pressed:

Next, let's say we need the robot to do something between one of the turns, such as move its arm or open a servo's claw. There's a couple of ways we could approach this without functions:

Already our code is getting a little long so let's move our side motion and turn into a function:

Now our loop may look like this:

When we test our code we may notice our robot isn't exactly driving in a square shape. Thankfully with our function in place we only need to change the needed value in one place:

This change to the function will be reflected anywhere DRIVE_AND_TURN used.

Give it a try by changing the right motor's power or the timer to refine your square!

GAMEPAD_INPUT_STATE

Contains the code related to the arm/wrist presets

GAMEPAD_INPUT_TOGGLE

Contains the code for the claw toggle

GAMEPAD_INPUT_MANUAL

Contains the code for manual control of the arm/wrist

GAMEPAD_INTAKE

Contains the code for running the servo on the intake

STATE_MACHINE

Contains all the preset positions for currentState

SPLIT_STICK_ARCADE_DRIVE

Contains the code for driving the robot

TELEMETRY

Contains the telemetry read out code

How do Functions appear in Blocks?

Creating a new Function in Blocks

The Starter Bot is able to climb the lower rung using the existing example program!

Additional Function Example

This program can be tested on the Starter Bot or another robot using the same configuration file! Create a new OpMode to begin. Ours is called FunctionsDemo.

If you are using the Starter Bot, make sure the arm is adjusted to not drag while the robot drives autonomously.

manual control
Starter Bot 2024-25 Example Code
Function for Manual Arm/Wrist control
This is intended as an example only and not actual use!
Functions menu in Blocks
Example function for climbing
New function block
New function added to our main code
Example of a simple code within our function
Simple program for driving in a square
Full code with claw opening after driving two sides
Function containing the code for driving and turning
Using functions to drive in a square
Code for controlling the robot's turn

Programming - Driving and Telemetry

Split Arcade Drive

This year's Starter Bot is designed for split arcade drive. This means the left joystick controls the forward and back motion while the right joystick allows for rotation.

Split Arcade Drive

By adding a "clip" block to our drive program, we determine the minimum and maximum number or equation can equal out to. This reduces the possibility of an error occurring in the scenario where the value equals something higher than 1 or lower than -1, the motor's max range, which may cause a missed input.

Telemetry

Telemetry helps our robot to communicate to use what it thinks it is doing.

As part of our telemetry function, we have our robot reading out the currentState variable letting us know if the arm/wrist are in manual mode or at one of our various preset positions.

Claw Position shows us if the claw is currently open or closed. The "test" block can be found under the logic menu!

Lastly, our robot provides the current position and power of the arm and wrist. This is helpful for if we need to change a preset or for adding new code using the encoders on the motors!

continuous mode
continuous mode using the SRS Programmer!
Hello Robot Programming Guide
configuration file
Click here to learn more about the configuration process.
Hello Robot - Using Gamepads

Programming - Initialization

Before the bulk of our program begins, we need to first establish our variables and tell our motors how we want them to run. This section of code will run once when the program is activated and before we hit "Play" on the Driver Hub.

Initialization Code

Drivetrain Motor Settings

Since the motors on our drive train are a mirror of each other, one needs to be set to run in reverse. In this case we have the leftDrive motor set to run in reverse.

By default, our drivetrain motors will not be using encoder data so we can set them to RUN_WITHOUT_ENCODER. Your team may choose to change this later when working on autonomous programming!

Establishing Variables

Variable states at program start

There are two parts to our variable set up in this year's Starter Bot program. Often times we use variables in place of a number or equation, but in this case we will be using them to help our robot move between functions in our code and determine preset arm/wrist positions.

Let's take a look at what all our variables do:

Variable
Purpose

In the OnBot Java version of this code, we use something called "enum". This allows us to declare the variable name and have it treated as a unique value.

For example: the robot interprets the variable "MANUAL" as one of the states within our switch case in OnBot Java. We'll discuss more about the switch case down below!

However, "enum" is not available in Blocks meaning we have to be a little clever to mimic this process. We created strings using the "text" block to do a similar thing. This will have the robot understand MANUAL equals the word "manual", which allows it to move between cases.

You'll notice the variable currentState appears throughout our program repeatedly. But what does it do?

This variable is what will allow our robot to switch between its various preset configurations based on what button is pressed on the gamepad. It's one variable that can be set to a number of different constant states. In comparison, our position variables will remain constant.

When we press one of the buttons on our gamepad it changes our currentState. In turn, this tells our arm and wrist on the robot to move to one of the predetermined positions seen below.

If we needed to update the position value for one of our presets, we can do so within this if/else statement and it will be reflected throughout the entire code without having the hunt down every instance it may be used.

MANUAL

Switches the arm and wrist to being manually controlled by the Dpad

INTAKE

Sets the arm and wrist to a preset position to intake game pieces

WALL_GRAB

Sets the arm and wrist to a preset position to pick up clipped specimens from human player

Variables: OnBot Java vs. Blocks

currentState Variable

Variables in Blocks using strings
Variables in OnBot Java using enum
Arm and Wrist Presets
To learn more about "What is a Variable?" check out our Hello Robot tutorial!

WALL_UNHOOK

Raises the arm from the wall (human player) position to remove clipped specimens

HOVER_HIGH

Sets the arm and wrist to a preset position to place specimens on the high rung

CLIP_HIGH

Moves the arm to clip specimens on the high rung

LOW_BASKET

Sets the arm/wrist to the needed high to score in the low basket

INIT

Resets the robot to its start up configuration

currentState

Switches the arm/wrist between the above preset positions and provides a readout for telemetry

clawOpen

Allows for the toggle control of the claw

lastBump

Allows for toggling the claw open or closed

lastHook

Allows for toggling between the two clip positions

lastGrab

Allows for toggling between the wall (human player) positions

Starter Bot Programming Walkthrough