Only this pageAll pages
Powered by GitBook
1 of 47

FTC Kickoff Concepts

Loading...

INTO THE DEEP 2024-25

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

CENTERSTAGE 2023-2024

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

POWERPLAY 2022-2023

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Freight Frenzy - 2021-2022

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Ultimate Goal - 2020-2021

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Programming TeleOp

Getting Started!

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

Configuration

Port Type
Port Number
Device Type
Name

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

Configuration File Download

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.

Wiring Diagram

Device Name
Device Type
Port

arm

UltraPlanetary Gearbox Kit and HD Hex Motor

Motor/Encoder Port 0

wrist

Core Hex Motor

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

Gamepad Setup

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.

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:

Gamepad Input
Function

Right Joystick

Turn left and right

Left Joystick

Drive forward and reverse

A/Cross

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

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):

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

Quick Links

Video Walkthrough

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.

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

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:

Variables: OnBot Java vs. Blocks

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.

currentState Variable

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.

Programming - Creating Functions

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

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:

How do Functions appear in Blocks?

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

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

Creating a new Function in Blocks

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:

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

Additional Function Example

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!

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.

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!

2024-25 REV DUO FTC Starter Bot

We're looking forward to see what teams create this year!

Documentation Links

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!

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:

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

The Smart Robot Servo can be changed to !

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.

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

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

Any updates to our example programs are documented in our

Variable
Purpose
Function
Purpose

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:

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

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

We are excited for the 2024-2025 FTC Game, INTO THE DEEP℠ presented by RTX and reveal our Starter Bot! Utilizing just the and the , this starter bot is the culmination of analyzing the game, prototyping, and technical documentation. The REV DUO FTC Starter Bot is designed to give teams a starting point for building their robot, while leaving room for iteration, revision, and adaptation to the game’s challenges.

Hello Robot Programming Guide
configuration file
Click here to learn more about the configuration process.
continuous mode using the SRS Programmer
Upgrades
Hello Robot - Using Gamepads
Please see the product page for directions on remapping these buttons.
Check out FIRST's guide on uploading a Blocks program!
changelog.

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

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

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

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.

            // 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

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

Full Code

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();
        }
    }
}
Starter Bot Programming Walkthrough
Initialization and Variables
Creating Functions
To learn more about "What is a Variable?" check out our Hello Robot tutorial!
FTC Starter Kit V3.1
DUO Control Bundle
Intake
Claw Toggle
Controlling the Arm and Wrist - Preset Positions
Controlling the Arm and Wrist - Manual Movement
manual control
Split Arcade Drive
Telemetry
Tips & Tricks page.

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.

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 - Controlling the Arm and Wrist

Setting up the Arm and Wrist 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 - 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.

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!

Upgrades!

Dual Gamepads

There are many ways to split robot control across two gamepads. We recommend testing different combinations with your team to decide what feels the most comfortable to you!

This version of the program is intended to be just one example for using two gamepads. Arm and wrist control has been moved to a second gamepad while the main gamepad handles driving and the servos on the intake and claw.

The associated gamepad for a button input can be changed at any time by clicking on the block's dropdown:

Arcade Drive

In this example code, we changed our drive function to only be on the left stick!

When changing a function name this will automatically change throughout the entire code to reflect the new name.

Mecanum Drive

For Mecanum Drive each wheel has an individual motor!

Upgrading from the FTC Starter Kit V3.1 to Mecanum Drivetrain V2:

The following additional parts are needed:

Example Mecanum Drive Program

How a Mecanum Drivetrain is programmed largely depends on the driver's preference for how the controller is configured.

In our provided example, the left joystick controls forward/back and strafe then the right joystick controls turning. This code is based on the sample provided by FIRST in Blocks (BasicOmniOpMode).

Mecanum Demo Blocks Code:

Mecanum Configuration File:

Mecanum Configuration - Control Hub and Expansion Hub

Port Type
Hub
Port Number
Device Type
Name

Motor

Control Hub

0

REV Robotics Ultraplanetary HD Hex Motor

frontLeft

Motor

Control Hub

1

REV Robotics Ultraplanetary HD Hex Motor

backLeft

Motor

Control Hub

2

REV Robotics Ultraplanetary HD Hex Motor

frontRight

Motor

Control Hub

3

REV Robotics Ultraplanetary HD Hex Motor

backRight

Servo

Control Hub

4

Servo

claw

Servo

Control Hub

5

Continuous Servo

intake

Motor

Expansion Hub

0

REV Robotics Core Hex Motor

wrist

Motor

Expansion Hub

1

REV Robotics Ultraplanetary HD Hex Motor

arm

Mecanum Code Breakdown

Before diving into mecanum, double check the direction your motors and wheels are turning. They may need to be reversed if you're experiencing jittering or inverted controls!

At the very beginning of our program the drivetrain motors are set to RUN_WITHOUT_ENCODER.

We need to create some new variables in order to use mecanum. Let's break those down first:

Variable
Purpose

FB

Moving forward and backwards

Strafe

Strafing side to side

Turn

Turning left and right

leftFrontPower

Sets the front left motor power

rightFrontPower

Sets the front right motor power

leftBackPower

Sets the back left motor power

rightBackPower

Sets the back right motor power

max

This is used to check that our values do not exceed the expected range - similar to the "clip" block

At the beginning of the MECANUM_DRIVE function, our variables for each movement direction are being set to the value generated by the movement of the matching joystick axis.

Since we now have four motors in play, our equation for setting the appropriate power to each motor gets a little more complicated.

Our robot first needs to determine the combined movement of the left stick then calculate with the right stick's value. This allows for movement when the left joystick is at an angle, such as strafing along a diagonal!

Next, similar to our original drivetrain code, there's a chance a value may fall outside the range of the motor's power (-1 to 1). Therefore, we want our robot to check and bring those values back into range so we don't miss any inputs.

For our last step, our robot sets the power of each pair of motors based on all our calculations!

Tips, Tricks, & Upgrades Video Walkthrough

Building Tips & Tricks

Check out the following video for some Tips and Tricks when building the 2023-24 REV DUO FTC Starter Bot:

We strongly recommend checking that your wires are secure for the arm, gripper, and wrist and bound to a location where they cannot be sliced by extrusion or a pinch point.

Programming Breakdown

The following video provides a breakdown of the provided code example for the 2023-24 Starter Bot!

Build Tips & Tricks

Compatibility with Starter Kit V3

The 2024-25 REV DUO Starter Bot is designed to be built with the FTC Starter Kit V3.1, however there are only a few parts missing from the Starter Kit V3. Below is the list of parts you will need to add to your Starter V3 to make it compatible with the 2024-25 REV DUO Starter Bot.

Part number
Description
Quantity

REV-41-1124-PK100

1

REV-41-1600

1

REV-41-1491-PK4

2

REV-41-1493-PK4

1

REV-41-2702-PK4

2

Pre-Loading Brackets

UltraPlanetary Overtightening

Making the Chain and Master Links

Squaring Your Assembly

When assembling your Starter Bot, it is important to square up your shafts and extrusion. This will ensure your robot operates smoothly and effectively. To check if your assembly is square you can use a Square tool or if that is not available you can use something with a known 90 degree angle such as a sheet of paper.

Initializing Your Robot

The preset positions, such as "Intake" and "Low Basket," in the default Starter Bot code work using the built-in encoders of the motors. To ensure the robot moves to the correct position for these presets, make sure the robot is powered on while in its initialization orientation.

This orientation is pictured below: arm down and the wrist folded up.

Programing Your Smart Robot Servo

Wire Management

One of the most important steps for a reliable and safe robot is wire management. Wire management involves bundling and routing wires along a defined path to the electrical parts, such as servos and motors. Wires can bundled with zip ties, wrapped in tape, tucked into extrusion, and routed away from moving parts of your robot.

Pinch Points

There are points on the robot that can catch an unconstrainted wire and pinch it causing it to be damaged or disconnected. This is most noticeable with the gears on the arm and the servo wires, however, the arm still needs to move we can not completely constrain the wires.

We recommend using a length of extra wire to form a "service loop", like the one shown above. This loop keeps wires bundled together, and provides a predictable path of movement as your arm pivots.

Strain Relief

Minimizing stress on a wire connection, which is often a two-part connector on FTC Robots, is a great method to avoid wiring getting pulled loose within your control system! Proper strain relief ensures that the wires are not causing unnecessary stress on the connectors and that the connection remains snug.

To add strain relief to your wiring, secure the wire about one or two inches from the connector and leave a bit of slack on the connector side. This helps avoid unintentional tension that could damage the connector and allows for easy disconnection when needed for testing or replacing modules.

Be careful to not leave too much or too little slack on either end of the connection

  • Too little slack can cause the wires to pull apart

  • Too much slack can become an entanglement risk

Smart Tug

A "Smart Tug" is a test where you test your wiring by tugging on a wire with a reasonable amount of force to see if it comes undone. The Smart Tug simulates many common scenarios, including a wire getting caught on a field element, actuator, or another robot. It is a good practice to do this test any time you connect a wire to ensure it is fully seated in the connector and secure.

If you perform a Smart Tug on your wire and it becomes disconnected, you can use one of the above methods to secure the wire!

Starter Bot Programming TeleOp without Initialization

The provided program template for the 2024-25 Starter Bot has the robot move to initialization at the start of the program. However, in some situations the arm and wrist motor may never hit the designated starting position leading to oscillating movements, or the Control Hub may have been powered on in the wrong positions, which determines these motors' zeroes, leading to unexpected movement.

Below is a version of the TeleOp program that changes this initialization so the robot no longer moves until receiving input from the gamepad. This version is only available for the basic Blocks template and not for any upgrades. Read through the short guide below to learn more about the changes!

Download of Starter Bot Program without Initialization

Robot Start Up Position

When the program begins, the robot will first STOP_AND_RESET_ENCODER for the arm's HD Hex Motor and wrist's Core Hex Motor. Whatever position the arm and wrist are in will become the "zero" the presets are based around.

Left Bumper Reset

When pressing the left bumper on the gamepad, the arm and wrist will return to their start up position. To prevent this from also resetting the encoder, a new variable called ZEROING has been added to our STATE_MACHINE as seen below:

The call for the left bumper now looks like below:

Adjusting the STATE_MACHINE

Due to variations in the robot's structure and how team's decide to position it for start up, you will likely need to make some adjustments to your arm and wrist values within the STATE_MACHINE to fit your team's needs for the presets.

Some changes to the targetArm position have already been included, but we recommend using the telemetry readout on your Driver Hub to refine your movements!

Starter Bot - POWERPLAY

We hope the above downloads help provide a launching off point for new teams and veterans to see some ways to build using REV DUO parts!

Upgrades

Mecanum Drive

For Mecanum Drive each wheel has an individual motor!

Upgrading from the FTC Starter Kit V3 to Mecanum Drivetrain V2:

The following additional parts are needed:

Example Mecanum Drive Program

This example code uses a different configuration than the Starter Bot's provided code! Please make sure to update both your program and the configuration file through the Driver Station.

Adding Independent Wrist Movement

Below are a couple examples for adding wrist movement using the existing variables:

These examples are meant to replace the use of presets in favor of manual control of the arm and wrist.

Blocks:

Example 1:

This option functions similar to the gripper using the two preset positions. If "Up" on the Dpad is held down then the wrist will move and stay in the up position. When released, it will return down.

Example 2:

This option breaks the movement apart to move up or down when the matching button is pressed once on the Dpad. The button does not need to be held for it to remain in the set position.

OnBot Java:

Example 1:

Example 2:

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!

Upgrading to a (REV-45-2470) allows for new kinds of movement giving the robot the ability to strafe side-to-side across the field.

REV's Mecanum Drivetrain Kit V2

The FTC Starter Kit V3.1 can be

- QTY 2

- QTY 4

- QTY 1 (set of 4)

- QTY 1

(QTY 1) OR (QTY 2)

Add a block to change the set direction during initialization.

We recommend programming your Smart Robot Servos for the gripper and wrist using the upon completing your build.

There are many brackets used in the 2024-25 REV DUO Starter Bot, pre-loading these brackets with the appropriate screws and nuts make these steps easier. Pre-Loading is discussed in the . When pre-loading remember that the head of the Hex Cap screw should face the extrusion.

When you take care not to over-tighten the gearbox housing screws. Hand tight is enough to keep the gearbox assembled. If you overtighten the gears might bind leading to poor performance and possibly damage.

Roller chain is typically connected into a continuous loop. This can be done using a Chain Tool to press the pins in and out of the desired outer link as described in the build guide. An alternate way to make the chain is using a common roller chain accessory called a , or quick-release link. Two of these master links come in your FTC Starter Kit V3.1. Master links allow for easy chain assembly/disassembly without any special chain tools. Master links can typically be reused many times, but can become bent with multiple uses. At the point that master links become bent they should be discarded.

The 2024-25 REV DUO Starter Bot uses two Smart Robot Servos. The Intake servo needs to be programed in Continuous Rotation mode and the Claw servo needs to be programed in Default Operation with angular limits set. Use the to

Because of this, the arm and wrist should still start in a similar position as we recommended on the , which is ideal for a competition set up as well. Your team should consider marking or labeling your robot in some way to know always where the arm should be reset between runs of the program.

Remember if you change where you start your arm and wrist the zero for the motors will change. A breakdown of the .

For the POWERPLAY season FIRST asked us at REV to help develop an introduction robot for newer teams, completely built out of the FTC Starter Kit V3 (), that is able to play the game to some level of success. To design this robot we went through a similar process as we did with kickoff concepts and that works with our teams.

Starter Bot Links

Upgrading to a (REV-45-2470) allows for new kinds of movement giving the robot the ability to strafe side-to-side across the field.

The FTC Starter Kit V3 can be

- QTY 2

- QTY 4

- QTY 1 (set of 4)

- QTY 1

How a Mecanum Drivetrain is programmed largely depends on the driver's preference for how the controller is configured. If your team is new to Mecanum, we have a

Using the the wrist only moves when one of the preset arm/wrist buttons on the controller is pressed. Your team may decide to add independent wrist movement for more refined control.

2024-25 REV DUO Starter Bot Build Guide - PDF
Channel Drivetrain Build Guide
2024-25 Starter Bot CAD - Onshape
TeleOp Code and Configuration Instructions
Bill of Materials
Upgrade Suggestions
continuous mode
You can learn about arcade style of driving in Hello Robot!
Mecanum Drivetrain
upgraded to the Mecanum Drivetrain V
1 following this guide.
UltraPlanetary Gearbox Kit & HD Hex Motor
Ultra 90 Degree Gearbox
75mm Mecanum Wheel Set
M3 x 6mm HexCap Screws 50 Pack
Expansion Hub
SPARKmini Motor Controller
Full build instructions can be found here!
SRS Programmer
Click here for Our How To Video!
Channel Drivetrain build guide
assemble your UltraPlanetary
Master Link
SRS Programmer (REV-31-1108)
switch the operating modes.
positions can be found here as part of the main tutorial
default program
        //Indepedent Wrist 
         if (gamepad1.dpad_up) {
          wrist.setPosition(wristUpPosition);
        } else {
          wrist.setPosition(wristDownPosition);
        }
        //Indepedent Wrist 
         if (gamepad1.dpad_up) {
          wrist.setPosition(wristUpPosition);
        } 
         if (gamepad1.dpad_down) {
          wrist.setPosition(wristDownPosition);
        }
M3 x 20mm Hex Cap Screws - 100 Pack
UltraPlanetary Gearbox Kit & HD Hex Motor
M3 Standoff - 30mm - 4 Pack
M3 Standoff - 45mm - 4 Pack
Flap Wheel - 5mm Hex Bore - Medium (Dark Gray) - 4 Pack
REV-45-1883
Mecanum Drivetrain
upgraded to the Mecanum Drivetrain V
1 following this guide.
UltraPlanetary Gearbox Kit & HD Hex Motor
Ultra 90 Degree Gearbox
75mm Mecanum Wheel Set
M3 x 6mm HexCap Screws 50 Pack
Full build instructions can be found here!
demo code and breakdown available for Blocks.

Bill of Materials

Quick Links

  • Substructures

Full Bill of Materials (BOM) - Excel Download

Full Robot

PART NUMBER
PRODUCT NAME
QUANTITY

REV-11-1130

36" PWM Cable

2

REV-31-1302

12V Slim Battery

1

REV-31-1387

Switch Cable and Bracket

1

REV-31-1595

Control Hub

1

REV-31-1596

Driver Hub

1

REV-39-1865

Etpark Wired Controller for PS4

1

REV-41-1097

Smart Robot Servo

2

REV-41-1125

M3 x 35mm Hex Cap Screws

12

REV-41-1161

Zip Ties - 160mm - 50 Pack

1 Pack

REV-41-1163

Surgical Tubing - 3mm

1

REV-41-1190

90mm Omni Wheel

2

REV-41-1267

90mm Grip Wheel

4

REV-41-1300

Core Hex Motor

2

REV-41-1303

15mm Plastic Motion Bracket

4

REV-41-1305

15mm Plastic 90 Degree Bracket

26

REV-41-1315

15mm Gearbox Motion Bracket

2

REV-41-1317

15mm Bearing Pillow Block

4

REV-41-1319

15mm Plastic Servo Bracket

2

REV-41-1321

15mm Plastic Lap Corner Bracket

8

REV-41-1323

15mm Spacer

10

REV-41-1324

3mm Spacer

24

REV-41-1326

Through Bore Bearing - Short

16

REV-41-1327

Shaft Collars

29

REV-41-1328

Servo Shaft Adapter

2

REV-41-1329

Through Bore Bearing - Long

12

REV-41-1332

30 Tooth Plastic Gear

2

REV-41-1333

125 Tooth Plastic Gear

2

REV-41-1335

60 Tooth Plastic Gear

6

REV-41-1337

90 Tooth Plastic Gear

2

REV-41-1338

10 Tooth #25 Sprocket

8

REV-41-1348

5mm x 90mm Hex Shaft

6

REV-41-1349

5mm x 135mm Hex Shaft

4

REV-41-1359

M3 x 8mm Hex Cap Screws

192

REV-41-1360

M3 x 16mm Hex Cap Screws

16

REV-41-1361

M3 Nyloc Nuts

212

REV-41-1362

5mm x 400mm Hex Shaft

2

REV-41-1365

#25 Roller Chain - 10 ft

1

REV-41-1373

Hook and Loop Fastener - 13.5mm x 2mm

1

REV-41-1430

15mm Extrusion - 150mm - 45° Ends

2

REV-41-1431

15mm Extrusion - 225mm - 90° Ends

1

REV-41-1432

15mm Extrusion - 420mm - 90° Ends

8

REV-41-1433

15mm Metal Bent Core Hex Motor Bracket V2

4

REV-41-1492

M3 Standoff - 40mm

8

REV-41-1568

15mm Extrusion - 120mm - 90° Ends

2

REV-41-1600

UltraPlanetary Gearbox Kit & HD Hex Motor

2

REV-41-1621

UltraPlanetary Outside Mounting Bracket

2

REV-41-1687

U Channel Endcap

4

REV-41-1702

Tensioning Bushing - 39mm

8

REV-41-1762

45mm x 15mm C Channel - 408mm

4

REV-41-1767

45mm x 15mm C Channel - 248mm

1

REV-41-1839

450mm x 300mm x 4mm Corrugated Plastic Sheet

2

REV-41-1907

M3 X 8MM T-Slot Screw

40

Substructures

Tower

PART NUMBER
PRODUCT NAME
QTY

REV-41-1300

Core Hex Motor

2

REV-41-1315

15mm Gearbox Motion Bracket

2

REV-41-1317

15mm Bearing Pillow Block

2

REV-41-1323

15mm Spacer

2

REV-41-1324

3mm Spacer

4

REV-41-1327

Shaft Collars

2

REV-41-1332

30 Tooth Plastic Gear

2

REV-41-1359

M3 x 8mm Hex Cap Screw

4

REV-41-1361

M3 Nyloc Nuts

38

REV-41-1362

5mm x 400mm Hex Shaft

1

REV-41-1432

15mm Extrusion - 420mm - 90° Ends

4

REV-41-1433

15mm Metal Bent Core Hex Motor Bracket V2

4

REV-41-1907

M3 X 8mm T-Slot Screw

16

Arm

PART NUMBER
PRODUCT NAME
QTY

REV-41-1097

Smart Robot Servo

1

REV-41-1303

15mm Plastic Motion Bracket

1

REV-41-1305

15mm Plastic 90 Degree Bracket

8

REV-41-1317

15mm Bearing Pillow Block

2

REV-41-1319

15mm Plastic Servo Bracket

1

REV-41-1323

15mm Spacer

2

REV-41-1324

3mm Spacer

3

REV-41-1327

Shaft Collars

6

REV-41-1328

Servo Shaft Adapter

1

REV-41-1329

Through Bore Bearing - Long

3

REV-41-1333

125 Tooth Plastic Gear

2

REV-41-1335

60 Tooth Plastic Gear

2

REV-41-1349

5mm x 135mm Hex Shaft

1

REV-41-1359

M3 x 8mm Hex Cap Screws

48

REV-41-1360

M3 x 16mm Hex Cap Screws

8

REV-41-1361

M3 Nyloc Nuts

56

REV-41-1362

5mm x 400mm Hex Shaft

1

REV-41-1432

15mm Extrusion - 420mm - 90° Ends

2

REV-41-1568

15mm Extrusion - 120mm - 90° Ends

2

Gripper

PART NUMBER
PRODUCT NAME
QTY

REV-41-1097

Smart Robot Servo

1

REV-41-1125

M3 x 35mm Hex Cap Screws

12

REV-41-1303

15mm Plastic Motion Bracket

3

REV-41-1305

15mm Plastic 90 Degree Bracket

8

REV-41-1319

15mm Plastic Servo Bracket

1

REV-41-1321

15mm Plastic Lap Corner Bracket

4

REV-41-1323

15mm Spacer

4

REV-41-1324

3mm Spacer

1

REV-41-1326

Through Bore Bearing - Short

2

REV-41-1327

Shaft Collars

9

REV-41-1328

Servo Shaft Adapter

1

REV-41-1329

Through Bore Bearing - Long

5

REV-41-1335

60 Tooth Plastic Gear

4

REV-41-1337

90 Tooth Plastic Gear

2

REV-41-1349

5mm x 135mm Hex Shaft

3

REV-41-1359

M3 x 8mm Hex Cap Screws

20

REV-41-1360

M3 x 16mm Hex Cap Screws

8

REV-41-1361

M3 Nyloc Nuts

40

REV-41-1430

15mm Extrusion - 150mm - 45° Ends

2

REV-41-1431

15mm Extrusion - 225mm - 90° Ends

1

REV-41-1163

Surgical Tubing - 3mm

1

Starter Bot Changelog 2024-25

Changes made to any of the 2024-25 REV DUO FTC Starter Bot Documentation will be listed below. Check back for updates as the season progresses!

Drivetrain

General Drivetrain Considerations

Field Obstacles and Challenges

The grid of Junctions on the POWERPLAY field is the largest field obstacle for this season. Ground, Low, Medium, and High Junctions spaced in a 2ft grid can limit the amount of space your robot has to navigate the field. There are floor obstacles as well- the Ground Junctions. The Ground Junctions are 0.56in tall with a recessed portion that drivetrains can get stuck on if they do not have the necessary clearance. However, once a Cone has been scored on a Ground Junction, you can no longer drive over the Junction.

Robot Size Restrictions

Robot rules have mainly stayed the same for this years game. The main constraint is the starting 18" x 18" x 18" sizing requirement.

Drivetrain Options

While there are many types of drivetrains teams can build, getting a drivetrain up and running as quickly as possible to begin testing should be a priority. This year the two main drivetrains we considered were Differential Drive and Mecanum Drive.

Differential Drivetrain

Pros
Cons

More traction with the floor

Cannot strafe to easily align with game pieces or goals

Stock with the FTC Starter Kit V3

Mecanum Drivetrain

Pros

Cons

Easily move side to side for alignment

May have some trouble traversing the ground junctions

Lower to the ground with 75mm Wheels allowing for a more stable platform

Requires two extra motors and mecanum wheels

Other Options

In addition to changing the wheels, you can vary other parts of your drivetrain to change how effective it is for navigating the POWERPLAY field.

One way to do this is to change the size of your frame. If you shrink down your drivetrain, you will have more space to drive around the grid than if you built your robot to the full 18in X 18in dimensions. However, if you do this pay attention to the geometry of your other mechanisms as that will change too.

Starter Bot Drivetrain Update

Using either differential, mecanum, or another drivetrain for a robot will lead a team to success this season. For our prototyping and the final Starter Bot we used the channel drivetrain. In the video below we installed an optional mecanum upgrade to our Starter Bot to highlight it's maneuverability on this years field.

Game Elements

Cones

Red and blue rigid plastic cones are game pieces for this years POWERPLAY game. There are 60 cones total on the playing field, 30 red and 30 blue. The average weight of the cones is approximately: 2.55oz

Signal

Similar in size, shape, and weight to the cones, a signal is a non-scorable game piece used to indicate the randomization state. Robots can read the images on a signal, or a team-designed signal sleeve, for additional information at the start of a match.

A Signal is NOT a Cone and cannot be scored!

Beacon

Also known as the Team Scoring Element, a Beacon is a team-designed and manufactured scoring element that is used in the endgame portion of POWERPLAY. Beacons are used to cap and claim ownership of Ground, Low, Middle, and High Junctions.

Junctions

Junctions are the main location for scoring Cones to create a Circuit. There are four types of Junctions on the POWERPLAY playing field.

  1. Ground Junction: Plastic disc that is molded to hold Cones

  2. Low Junction: 13in spring-mounted pole

  3. Medium Junction: 23in spring-mounted pole

  4. High Junction: 33in spring-mounted pole

Junction locations on field

Navigation Images

The following images are displayed in different locations around the field perimeter and used for Navigation tasks.

Starter Bot - Programming Teleop

Basic Teleop Strategy

Our strategy for teleoperated mode was to make driving the robot as intuitive and precise as possible. Navigating carefully through the grid of Junctions is important for gameplay so we decided to use Split Arcade Drive this year.

Since the Junctions are mounted on springs and can move or change height freely, we found the best method to control the Lift mechanism was to not use preset levels. This allows us to easily raise cones to any height needed.

Configuration and Wiring

Before getting started with programming we needed to create a configuration file. 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

Motor

0

REVRoboticsCoreHexMotor

Lift (L)

Motor

1

REVRoboticsCoreHexMotor

Lift (R)

Motor

2

REVRoboticsUltraplantary

Drive (L)

Motor

3

REVRoboticsUltraplantary

Drive (R)

Servo

0

Servo, Continuous Rotation

Intake

I2C

0

IMU

imu

Wiring Diagram

Device Name/Function
Device Type
Port

Lift (L)

Core Hex Motor

Motor/Encoder Port 0

Lift (R)

Core Hex Motor

Motor/Encoder Port 1

Drive (L)

HD Hex Motor

Motor/Encoder Port 2

Drive (R)

Core Hex Motor

Motor/Encoder Port 3

Intake

Smart Robot Servo

Servo Port 0

Assigning Controls to a Gamepad/Controller

Items to consider when mapping out your gamepad:

  • What kind of input does the mechanism need?

  • What drivetrain are you using and what driving style do you want to use?

    • We decided the POWERPLAY Starter Bot would be driven with Split Arcade Drive for advantages in precision while driving.

  • Which input makes the most sense? Would pressing up on the d-pad be more intuitive for moving your arm up or down?

    • We chose to assign our D-Pad inputs to raising and lowering our lift and the right bumper to releasing Cones from the intake.

POWERPLAY Starter Bot controller layout:

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

Input

Function

Right Joystick

Turn Left and Right

Left Joystick

Drive Forward and Reverse

Right Bumper

Reverse Intake (Let go of Cones)

D-Pad Up

Raise Lift

D-Pad Down

Lower Lift

Programming Teleop - Blocks

Drive Code

We opted to use split arcade drive during the POWERPLAY season because it allows for forward and reverse movement without worrying about accidentally pushing the joystick in the X-Axis. The POWERPLAY field requires precise movements, and split arcade drive allows teams to have more control and precision.

Similar to the traditional arcade style driving tutorial, we will use the Dual Motor block to assign power values to our motors.

Remember to reverse one of the motors and negate the values on the Y-Axis of your joysticks.

Lift Code

For all of our button inputs we used an if/else statement. In the image below you can see the code for pressing the DPad. When DPadUp is pressed, both Core Hex Motors set power to -1, which moves the lift upwards. When DPadDown is pressed, the Core Hex Motors change their power to 0.8, which moves the lift downwards.

Remember that when it comes to coding your robot, the Y-Axis is -1 at its topmost point, and +1 at its bottommost point, unless you negate values.

Intake Code

The Starter Bot's compact active roller intake features one servo motor-driven roller paired with a free spinning roller. To make sure we keep a good grip on the Cone, the intake is always running inwards. This means we need to reverse the direction of the servo to release the Cone once the robot is in position to place it.

For the intake, we chose to use the RightBumper to control the direction and speed of the motor spinning the mechanism. In order to tell the intake to increase power when RightBumper is pressed, an if/else statement needs to be used.

As you can see, if you press the RightBumper, the intake sets its power to max. Otherwise, the intake power is set to 0.3.

Complete Blocks Program

Below is the complete Blocks Program for the POWERPLAY Starter Bot.

Alternative Control Hub Placement

If you are experiencing trouble wiring your Control Hub to the Core Hex Motors (REV-41-1300) driving the lift on your Starter Bot, try the following placement of your Hub.

Game Breakdown

Game Introduction

The 2022-2023 FTC season game is POWERPLAY. The POWERPLAY challenge features game elements such as Cones, Junctions, Substations, and Terminals. At the start of the match, each robot begins against their alliance wall and is able to be pre-loaded with one cone. Once the match starts, teams race to score cones and create circuits during the thirty second autonomous period followed by the two minute driver controlled period. During the last thirty seconds of the match called the end game, teams continue to score cones and have the opportunity to cap a junction with a beacon and park in their alliance's terminal for extra points. See the scoring summary below for more information on the game objectives.

Scoring Summary

The following table shows the possible scoring achievements and their point values. The table is a quick reference guide and not a substitute for a thorough understanding of the game manual. All achievements are scored at rest.

Field Layout

If you are unfamiliar with the game field structure the following view can give insight to the different elements and their locations.

Game Breakdown

The first step to any good FTC Game strategy is a full, in-depth understanding of the game. Strong knowledge of scoring achievements, point values, and game rules help teams develop a game strategy that maximizes their scoring ability. Once the knowledge is built the game can be broken down into data points for analysis.

A commonly used metric in the competitive robotics world is points per second. Basing your game strategy based on the amount of points you can gain per second (or even per game period), will help your team make the mechanical choices best for you!

Remember to always strategize and build within your resources! Not all teams will have access to the same resources, whether it is parts or people. A strategy that seems to yield the most points per second on paper may not be as successful as a strategy that focuses on maximizing accuracy.

The following section will breakdown the major scoring achievements of the game as well as provide some of the strategic considerations, we at REV noticed. While this breakdown may provide you with a basic knowledge of this years game it is always advised to consult Game Manual Part 2 to better understand the rules.

Autonomous

Navigating

Most FTC games include some sort of navigation or parking task in the autonomous period and this years game is no different. Typically, these are autonomous scoring achievements where a robot has moved to a particular portion of the field and parked. Adding to the navigation challenge this year is the Signal Bonus. Robots will earn extra points when parked completely in the designated zone as indicated by their signal.

Condition
Location
Points

Parked In

Substation

2

Parked In

Terminal

2

Parked Completely In

Signal Zone

10 - Field Supplied Signal 20 - Team Supplied Signal Sleeve

To understand the full break down of navigating, it helps to understand how Game Manual Part 2 defines In and Completely in. Once you have a grasp on how these concepts are defined you can make a decision about which navigation achievements will give you the most points per second, when compared against the rest of your autonomous strategy.

Cones

During the Autonomous period of POWERPLAY teams can also earn points by scoring cones. Cones scored in the autonomous period will earn additional points at the end of the Driver-Controlled Period if they remain in place.

Junction
Points

Ground Junction

2

Low Junction

3

Medium Junction

4

High Junction

5

Driver Controlled

Directly following the end of the Autonomous Period, Drive Teams have five (5) seconds plus a "3-2-1-go" countdown to prepare their Driver Stations for the start of the 2 minute Driver-Controlled Period. On the countdown word "go," the Driver-Controlled Period starts, and Drive Teams press their Driver Station start button to resume playing the Match.

Cones

During the Driver Controlled period teams strategically place cones on junctions to complete a circuit. All cones placed during the Driver-Controlled period are scored at rest after the match.

Junction
Points

Ground Junction

2

Low Junction

3

Medium Junction

4

High Junction

5

End Game

The last thirty seconds of the Driver-Controlled Period is called the End Game. Driver-Controlled Period Scoring can still take place during the End Game and this is when the Beacon (team scoring element) is introduced into the Playing Field.

Junction Ownership

Alliances can earn points for owning a junction by fulfilling one of two conditions:

Condition
Points

Having the top scored Cone on a Junction

3

Capping a Junction with a Beacon

10

If both conditions are met, a beacon will take precedence over the top scored cone and the alliance will receive 10 points

Circuit

A completed Circuit earns 20 points for the alliance. Only one circuit can be awarded per match.

See the example of a completed circuit (Red Alliance) and a partial or incomplete circuit (blue) below.

Navigating

Robots that end the match parked in either of the Alliance's terminals will earn 2 points.

Intake

POWERPLAY's rules limit robots to possessing a maximum of one corresponding Alliance Cone or one corresponding Alliance Beacon at a time, so, a major component of your points per second strategy should be the intake. Intakes come in many different forms, so we brainstormed some concepts and put them through the first stages of the engineering design process to help us decide if they met our gameplay requirements.

Requirements

  • Touch it, Own It - Be able to quickly intake and control elements

  • Pick Up One Only - reduce the chances of picking up more than one element by using the exterior rather than interior as a grip point

  • Adaptability - ability to pick up a cone against a wall on a cone stack as well as in the open from a substation or on the field

  • Release It - be able to release the element with ease whether by mechanical movement or by automation

First Round of Prototyping

Simple Gripper

We started with a simple gripper that has one pivot joint. The simple gripper has two stationary compliant wheels on the moving arm that grip the cone. This design is actuated by a servo and its low profile allows for cones to be picked up close to the wall.

Passive Intake

We also wanted to explore passive options for an intake. This passive intake works with free-spinning rollers at the end of two arms that are mounted with surgical tubing. The flexibility of the surgical tubing allows the arms to stretch around the cones as the rollers lock them in. Because this intake is passive and grabs a cone from the side, a bit of assistance from the field wall to keep the cone in place while grabbing is necessary. This may be an issue with intaking cones that are in the middle of the field.

Active Roller Intake

The active roller intake uses two sets of wheels powered by servo motors that roll the cones into a held position. The space needed to mount the servos and gear them correctly for the intake wheels causes this intake to be a bit bulkier than the others. Depending on what structural material you use, the frame can also be heavier which will need to be taken into consideration when building a lift.

Second Round of Prototyping

Compact Active Roller Intake

For our final intake design we took inspiration from the Active Roller Intake to create a version that could get closer to the wall and pick up cones from the cone stacks. This compact active roller intake features one servo motor driven roller paired with a free spinning roller. This provides the same amount of control as the two roller intake with about half the footprint. Because of the smaller size, this intake is also easier for your lift to move.

Bonus: Cone Flipper

A bonus mechanism we prototyped was a cone righting device. With cones getting dropped or knocked over, it might be a useful tool to have on your robot if your intake can only pick up an upright cone. Our idea was to mount compliant wheels on a rotating roller that is hinged to allow the cone to rotate into position.

Game Breakdown

Game Introduction

The 2021-2022 FTC game is Freight Frenzy. The Freight Frenzy challenge features game elements such as freight, shipping hubs, carousels, warehouses, barriers and ducks! Each robot starts against the Playing Field wall adjacent to the Alliance Station and must be in possession of of Box piece of freight. From there each team will progress through the thirty second autonomous period followed by the two minute long driver controlled period. The last thirty seconds of the match is the end game period. Each period has different scoring achievements. See the scoring summary excerpt from Game Manual Part 2 for more information on the game objectives.

Scoring Summary

If you are unfamiliar with the game the following field view can give insight to the field elements.

Game Breakdown

The first step to any good FTC Game strategy is a full, in-depth understanding of the game. Strong knowledge of scoring achievements, point values, and game rules help teams develop a game strategy that maximizes their scoring ability. Once the knowledge is built the game can be broken down into data points for analysis.

A commonly used metric in the competitive robotics worlds is points per second. Basing your game strategy based on the amount of points you can gain per second (or even per game period), will help your team make the mechanical choices best for you!

Remember to always strategize and build within your resources! Not all teams will have access to the same resources, whether it is parts or people. A strategy that seems to yield the most points per second on paper may not be as successful as a strategy that focuses on maximizing accuracy.

The following section will breakdown the major scoring achievements of the game as well as provide some of the strategic considerations, we at REV noticed. While this breakdown may provide you with a basic knowledge of this years game it is always advised to consult Game Manual Part 2 to better understand the rules.

Autonomous

Navigating

Most FTC games include some sort of navigation or parking task in the autonomous period. Typically, these are autonomous scoring achievements where a robot has moved to a particular portion of the field and parked there.

This year there are four potential navigation achievements.

To understand the full break down of navigating, it helps to understand how Game Manual Part 2 defines In and Completely in. Once you have a grasp on how these concepts are defined you can make a decision about which navigation achievements will give you the most points per second, when compared against the rest of your autonomous strategy.

Carousel

Each alliance's carousel starts with a duck placed on it in the pre-match setup. This duck can be delivered to the field by rotating the carousel. We tested the carousel and took a look at the rules to factor in all considerations for this scoring achievement.

The first thing to take a look at is the rules constraining and defining carousel interaction and delivery. Deliver is a glossary term defined in section 4.4 Game Definitions of Game Manual Part 2. Information on the carousel can be found in Game Specific Rule 7 <GS7> and delivery restrictions are in Game Specific Rule 9 <GS9> of Game Manual Part 2. One of our main concerns with the constraints, particularly in the autonomous period is that the definition of delivered specifically states that in order for a duck to be considered delivered "the Sweeper Plate must knock the Duck or Teams Shipping Element off of the carousel onto the playing field floor." Which implies that a properly delivered duck must enter the playing field by making contact with the sweeper plate.

Paying attention to the rules for delivery is crucial for maximizing points per second. But why? After testing the carousel we quickly realized that the speed at which the carousel is rotated, affects whether the duck enters the playing field. Spin the carousel too fast and the duck flies off of the carousel before it can be knocked off by the sweeper plate. Finding the speed the carousel can be rotated that allows the duck to be properly delivered and maximize points per second is crucial for this scoring achievement.

The final consideration we'd like to make is for traditional events. There is only one duck that is deliverable in autonomous. When also considering that travel time to the carousel affects the points per second of the delivery score, we think that going for this scoring achievement is maximized if your robot starts on the side of the field closest to the carousel.

Autonomous Bonus

In Freight Frenzy the randomization factor includes being able to identify which Barcode position a duck (or Team Shipping Element) is in and using that information to correctly place the Pre-Loaded Box onto the correct level of the Alliance Shipping Hub.

The following table highlights some of the ways to analyze the Barcode:

While Vuforia will likely be easier to tune to the Duck game element over the Team Shipping Element, using the Team Shipping Element is worth more points.

Placing Freight

Each robot is required to start with a pre-loaded box. Even if you are unable to properly read the Barcode location at the start of the match, placing the pre-loaded box onto the same level every round, yields a 33% chance of getting the autonomous bonus. This is in addition to the points gained from placing a piece of freight on Alliance Shipping Hub, which is the same amount of points regardless of the level it is placed on.

Driver Controlled

Since the only scoring achievement in the Driver Controlled period is placing Freight in one of the designated areas the main strategy is efficiency and accuracy. As we said its always about maximizing points per second!

Freight

The main scoring opportunity in the Driver Controlled period is placing Freight. A robot can control one freight at a time, per game specific rule <GS8>. Score freight by placing freight completely in the Alliance Specific Storage Unit, on one of the levels of the Alliance Shipping Hub, or on the Shared Shipping Hub.

There are a few considerations to make when deciding on your strategy for placing Freight:

Balancing

At the end of the match additional points may be awarded depending on whether your Alliance Shipping Hub is balanced or the Shared Shipping Hub is unbalanced in your alliances favor. Understanding how to identify the weight difference, and decide how that may effect your strategy.

GS5 and Warehouse Operations

Rule GS5 defines the expectations for each robot in regards to Warehouse Operations. In order for a Freight to be consider legally removed from the Warehouse, each piece of Freight must follow the Warehouse Operations

  1. Start Completely Out of the Warehouse, then

  2. Drive Completely In the Warehouse, then

  3. Collect one (1) piece of Freight, then

  4. Drive Completely Out of the Warehouse with the collected Freight.

End Game

During End Game you can continue to gain points by placing Freight or do one of the End Game specific tasks.

Duck and Team Shipping Element Delivery

In end game, ducks and team shipping elements can be introduced to the field by rotating the carousel, similar to the autonomous task. Delivering a duck or team element is worth 6 points a piece. Removing the ducks from autonomous from the overall count, nine ducks (or team elements) can be scored in end game. That's a potential of 54 points in the end game period just for delivering ducks. Obviously this score is reliant on being able to score all nine in the end game period, which would require that the delivery process take around three seconds to complete per duck.

Capping

Capping involves taking the Team Shipping Element and attempting to score it on top of the center pole above level 3, or on another capped team shipping element. Accuracy is key with this scoring achievement.

Shipping Hub Status

Shipping Hub Status focuses on where the Shipping Hubs are at, at the conclusion of a match. If the Alliance Shipping Hub is balanced at the end of the match you receive 10 points. If the Shared Shipping Hub is Unbalance you receive 20 point.

After looking at Game Manual Part 2, we believe the best strategy for the Shared Hub is to try to maintain balance as you are placing objects. This way you do not have to scramble at the end of the match to try to balance it.

Parking

Parking is also considered where the robot is at the end of the match. Calculating how long it would take you to get from one side of the field to the Warehouse will help you decide if the potential points per seconds are worth the points you would have to give up to park.

Drivetrain

General Drivetrain Options

Before diving into the specific obstacles in the Freight Frenzy game that may impact drivetrain design, lets first consider some of the game agnostic information on drivetrains.

Robot Size Restrictions

Robot rules, outside of the weight limit, have mainly stayed the same. The main constraint is the 18" x 18" x 18" sizing requirement.

Drivetrain Options

While there are many types of drivetrains teams can build, getting a drive train up and running as quickly as possible should be an overall goal. With this in mind there were two main drivetrains we considered utilizing for Freight Frenzy; Differential Drive or Mecanum Drive.

Differential Drivetrain

Mecanum Drivetrain

Either choice for a team will lead them to success this season. For our prototyping we went with the channel drivetrain to make modifications.

Field Obstacles and Challenges

Many FTC teams recycle drivetrains from season to season, whether for cost or ease of design reason. The requirements surrounding the warehouse, such as the barriers and the warehouse procedures, shakes up the standard design expectations for drivetrains in FTC.

There are two options for getting around the barriers: Going around or going over.

Going Around

Each barrier is roughly 13.7 inches from the playing field wall. To go around the barrier a drivetrain must be less than 13.7 inches wide. Creating a drivetrain that meets the size parameter creates constraints in the overall size of the robot. While this is a perfectly valid solution to the problem, we wanted to find a solution that could be made from a Starter Kit, and did not require structural components to be cut down.

Going Over

The poles of the barriers are roughly 1.26" from the floor with a roughly 3.5" gap between each pole. If we compare these dimensions against the standard FTC kit drivetrains, the drivetrains do not have the clearance to get over the barrier. Using our C Channel we were able to create a solution to this clearance issues.

Rather than seat the wheel shafts within the bearing holes on the Channel pattern, we used the extrusions slots and bearing pillow blocks to host the wheel shaft. By doing this we get approximately 2 inches of clearance, which gives us the clearance necessary to get over the barrier.

Carousel Mechanism

As we stated in the Game Breakdown, delivering ducks during the end game is a potential of 54 points. At 6 points per duck this is an equivalent action to scoring in the third level of the Shipping Hub. The Carousel itself is pretty similar to the Control Panel from the 2020 FIRST Robotics Competition game, Infinite Recharge, and is a good starting point for inspiration for a mechanism.

Requirements

  • Reliable - consistently interfaces with the rim of the carousel to do a full delivery

  • Balance of power - can rotate the carousel quickly without tossing the duck off

  • Simple - achieves the task without needing to be overly complex

Grip Wheel Mechanism

We focused on creating one carousel mechanism, the grip wheel mechanism. The reason we focused so intently on this particular mechanism was that we wanted a mechanism that was easy to build. Powering a grip wheel with a servo we were able to produce the necessary traction to transmit motion to the carousel.

This mechanism met our needs and requirements for rotating the carousel. However, it does take the mechanism about six second to fully rotate the carousel, bringing our total points per second to about one. You may want to get a low speed motor, like the Core Hex Motor, to provide a bit more speed to the mechanism than the servo. Obviously be cautious of the speed, as we have mentioned in the previous sections.

Starter Bot - Freight Frenzy

We hope the above downloads help provide a launching off point for new teams and veterans to see some ways to build using REV parts!

Game Elements

Freight

This years game comes with a series of different game elements that fall into the Freight category: Cargo, Boxes, and Ducks. Each type of freight varies in size, shape, and material, which may effect mechanism design. An added challenge to calculate for is that boxes come in three different weight classes.

Cargo

Cargo is a standard Wiffle Ball, used in past seasons of FTC (such as Rover Ruckus). From past seasonwe know that the material for the cargo is going to be a rigid plastic.

Boxes

Boxes (also known as an FTC Blocks) are also making a reappearance this season along with the Wiffle Ball. Boxes are 2" x 2" x 2" cubes made of polypropylene, a rigid plastic material.

One of the key components of Boxes is that they come in different weight classes: Light, Medium, and Heavy. Pre-load Boxes fall in the same weight class as Light Boxes

Box weights can have a massive advantage in the balancing or unbalancing of the Shipping Hub. It will also affect mechanism design as you will have to account for any additional work your mechanism will have to perform to pick and place one of the heavier boxes.

Ducks

Ducks are somewhat of an outlier this season. From what we can tell they are a standard rubber duck, which makes the much more pliable than the other game elements. When designing for a mechanism you may need to do additional intake testing.

Shipping Hubs

In Freight Frenzy there are two Game Elements under the classification of Shipping Hub. Both the Alliance Shipping Hub and the Shared Shipping Hub, are 21" tall, structures, that balance on on a rounded base. On of the key objectives of gameplay is the status of the Shipping Hubs at the end of each match. To gain this scoring achievement the Alliance Shipping Hub must be balanced and the Shared Shipping Hub must be unbalanced in the favor of your alliance

Alliance Shipping Hub

The Alliance Shipping Hub has three scoring levels, for placing freight. The image above explains the diameter of each level as well as its distance from the playing field floor. This information is good to know for design of a Freight delivery mechanism. However, one other consideration to make is the difference in diameter between each level.

For instance, level 1 and level 2 have a 3 inch different in diameter. Which means that, since all levels are centered around a center pole, level 1 and level 2 have a difference of 1.5 inches all the way around the Shipping Hub. A robot will need to be able to account for the difference when attempting to reach another level.

Finally, the dimensions surrounding the top of the center pole of the Shipping Hub are need to calculate for capping a Team Shipping Element. After some analysis, we believe one of the best designs for a Team Shipping Element would be to create something that can be capped on the 1.3" diameter of the center pole, while also have roughly the same dimensions so that it can be easily capped on top of.

Shared Shipping Hub

Unlike the Alliance Shipping Hub, the Shared Hub only has one scoring level. The focus with this particular Shipping Hub is unbalancing it in your alliances favor.

Carousel

The Carousel is an alliance specific Game Element located in the corner of the Audience Side and Alliance Station Side of the field. To deliver ducks to the field, a robot must rotate the carousel until the sweeper plate knocks the duck onto the field. Robots can only interact with the rim of the carousel in order to rotate it.

Barriers

Another Challenge of Freight Frenzy are the Barriers. In order to access the Warehouses and the Shared Shipping Hub, robots must cross over the barriers or move through the 13.7" to 13,75" space between the edge of the barrier and the field wall.

Each Barrier is made up of two poles connected by the end pieces as shown above. Somethings to be aware of when deciding on your drivetrain design:

  • The Center to Center Distance between poles (4.5 inches)

  • The Distance from the playing field floor to the top of the poles (1.26 inches)

  • The distance from the playing field floor to the top of the end pieces (2.2 inches)

Starter Bot - CENTERSTAGE

We are excited for teams to get started building the 2023-24 REV DUO FTC Starter Bot! Please keep this page bookmarked for future updates and more ideas for building a robot that can play the 2023-2024 FTC Game, CENTERSTAGE.

Documentation Links

Build Guide - PDF Download

Version
Release Date & Notes

v1.0.0 - Build Guide

9/09/24

  • Initial Release

v1.0.0 - Code and Configuration

9/09/24

  • Java Code Initial Release

  • Blocks Code Initial Release

  • Configuration File Initial Release

v1.0.0 - Bill of Materials

9/09/24

  • Initial Release

v1.0.1 - Blocks Code

9/10/24

  • Blocks Code updated to remove excess block within the "intake" movement

  • Fixed inverse drive controls

v1.0.1 - Upgrades

9/10/24

v1.0.1 - OnBot Java Code

9/12/24 Corrected the OnBot Java file name

v1.0.2 - Upgrades

9/12/24

v1.1.0 - Build Guide

9/13/24

  • Fixed BOM errors

  • Corrected some screw length errors

  • Added missing spacers

  • Reworked steps for ease of use

v1.0.0 - Tips and Tricks

9/13/24

v1.0.2 - Blocks Code (including upgrades)

9/17/24 Fixed turning being inverted (Graphics in the tutorial reflect this change)

v1.0.3 - Upgrades

9/20/24 Mecanum Code breakdown added

v1.0.1 - Tips and Tricks

11/25/24

Using a differential or tank drivetrain, like our is a solid option for teams.

Using a gives teams some extra maneuverability on the field by allowing the chassis to move omni directionally.

Also consider raising your drivetrain with pillow blocks if you need more clearance to get over obstacles. This is similar to what we did with the .

For more in depth information on the configuration process check out !

Joysticks and Triggers input to your code allowing you to adjust the speed of a motor based on the pressure applied to the trigger or position of the joystick.

Buttons, Bumpers, and D-Pad provide to your code and are ideal for triggering a action such as rotating a motor to a set position.

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

This section makes the assumption that you have learned some of the FTC programming basics by going through the guide. If you have not gone through this guide please walk through it before proceeding.

In we covered how to program arcade drive with one joystick. For this example, we will be programming arcade drive using two joysticks. This type of drive is called "split arcade". 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.

The control of our lift arm is done by running two Core Hex Motors () on a Reverse Virtual Four Bar Linkage. Unlike the joystick, the DPad on a gamepad inputs are Boolean data, FALSE/TRUE. In order to tell the arm to move when DPad Up or DPad Down are selected, an if/else statement needs to be used.

For a more in depth explanation of the game check out the official Game .

In general, navigation during autonomous is a very achievable goal. While you may have to consider some obstacles, like the junctions, using our Hello Robot - Encoder Navigation guides for and , you can easily create the code needed to meet many of the navigation achievements.

Want to take a look at how to navigate in autonomous. Check out our guide for more information.

For a more in depth explanation of the game check out

If you are participating in remote events check out

In general, navigation during autonomous is a very achievable goal. While you may have to consider some obstacles, like the barriers, using our Hello Robot - Encoder Navigation guides for and , you can easily create the code needed to meet any of the navigation achievements.

This year we decided to take a look at how to navigate in autonomous. Check out our guide for more information.

Using a differential or tank drivetrain, like the , is a solid option for teams.

Using a gives teams some extra maneuverability on the field by allowing the chassis to move omni directional.

For the Freight Frenzy season FIRST asked us at REV to help develop an introduction robot for newer teams, completely built out of the FTC Starter Kit V3 (), that is able to play the game to some level of success. To design this robot we went through a similar process as we did with kickoff concepts and that works with our teams.

The carousel spins with relative ease. The main issue with the carousel and duck delivery is the risk of ducks falling off of the carousel before they are pushed off by the sweeper plate. This happens when the carousel spins too quickly, flinging the duck off of carousel. We discussed the considerations for this in the section.

POWERPLAY Starter Bot CAD Assembly - Onshape
POWERPLAY Starter Bot Build Guide
Starter Bot Programming - Teleoperated Mode
Starter Bot Blocks Program Download
Channel Drivetrain
Mecanum Drivetrain
Freight Frenzy Starter Bot
Hello Robot - Configuration
floating point data
boolean data
Hello Robot - Using Gamepads
Hello Robot
Hello Robot- Basics of Programming Drivetrains
REV-41-1300
Click here to download the POWERPLAY Starter Bot Blocks code.
FIRST Tech Challenge Game and Resources LINK
Manual Part 2- Section 4.4 Gameplay
Blocks
Java
Programming Autonomous
Full Robot Bill of Materials
Tower
Arm
Gripper

Parked In

Alliance Storage Unit

3

Parked Completely In

Alliance Storage Unit

6

Parked In

Warehouse

5

Parked Completely In

Warehouse

10

Accuracy

Complexity

Vuforia

Most Accurate

Complex

Distance Sensor

May loose accuracy depending on changes in environment

Complexity depends on use case

Pros

Cons

More traction with the floor

Can not strafe to align with game piece or goal

Stock out of FTC Starter Kit V3

Pros

Cons

Move side to side for alignment

May have trouble getting over the barrier

Lower to the ground with 75mm Wheels

Requires two extra motors and mecanum wheels

Diameter

Weight

Quantity on Field

2.75 in

1.8 oz.

20

Box Type

Weight

Quantity on Field

Pre-Load

0.9 oz

4

Light

0.9 oz

26

Medium

3.3 oz

20

Heavy

4.8 oz

10

Height

Width

Length

Weight

Quantity on Field

2.2125 in

2.0 in

2.0 in

0.6 oz

20

Game Manual Part 2 - Traditional Events Section 4.5 Gameplay .
Game Manual Part 2 - Remote Events Section 4.5 Gameplay .
Blocks
Java
Programming Autonomous
Channel Drivetrain
mecanum drivetrain
REV-45-1883
Added additional function information to the tutorial
Added arcade drive example code!
Added two gamepad control example code!
Full Mecanum Demo Code released for the 2024-25 Starter Bot
Added information about Starter Kit V3 Compatibility
New version of the TeleOp program available without the initialization!
Game Breakdown
Introducing the 2023-24 REV DUO FTC Starter Bot
2023-24 REV DUO FTC Starter Bot Walkthrough Video

Starter Bot Downloads

Drivetrain

Drivetrains are one of the first mechanisms that teams typically build and start development on. There are few changes to the robot rules that are needed to consider when designing a drivetrain

Field Layout and Obstacles

Ultimate Goal provides a flat field with little in the way for a robot to maneuver through out the field of play. Rings are re-introduced into the field through a drop on the side of the goals by a human player. Rings will likely be rolling along the field and sitting flat when hitting a robot or another object like a field wall. While the rings themselves are compliant it doesn't seem like they are easily trapped inside of a drivetrain.

Robot Size Restrictions

Robot rules, outside of the weight limit, have mainly stayed the same. The main constraint is the 18" x 18" x 18" sizing requirement.

Drivetrain Options

While there are many types of drivetrains teams can build, getting a drive train up and running as quickly as possible should be an overall goal. With this in mind there were two main drivetrains we considered utilizing for Ultimate Goal; Differential Drive or Mecanum Drive.

Differential Drivetrain

Pros

Cons

Can hold ground when getting rings

Can not strafe to align with game piece or goal

More traction with floor

Stock out of FTC Starter Kit V3

Mecanum Drivetrain

Pros

Cons

Move side to side for alignment

May have trouble getting rings against other

Lower to the ground with 75mm Wheels

Requires two extra motors and mecanum wheels

Either choice for a team will lead them to success this season. For our prototyping of intakes we went with a Mecanum Drivetrain mainly so it would sit lower to the ground.

Intake

Manipulating the ring game piece during play is a key for success in this year's challenge. Intakes can take many forms but we would want to try a few concepts and see how the meet some of our requirements.

Requirements

  • Touch it, own it - Be able to quickly touch the rings and have control of them

  • Pick up multiple - Be able to handle multiple of the rings coming in at a time

  • Ability to hand-off to a conveyor/shooter

Two concepts to try as 15 minute prototypes are a pinch intake and a roller intake.

Pinch Intake

Basic idea is to have a servo with a pivot to pick up the rings. Ability to lift up the intake and put it down on top of other rings in position to carry up to 3 is another requirement.

We took the intake that we made last season for SKYSTONE and tried it out with the rings. Surprisingly it didn't need much adjustment to pick up the rings. Holding multiple rings was possible however the grip on the pinch decreased with the more rings used. If using a pinch intake teams may want to consider picking up from the inside diameter of the ring and finding some ways to hold onto a compliant piece like the ring.

With the difficulty of picking up multiple rings for carrying we chose to look at another option for intakes as well.

Roller/wheel Intake

Another way is to have a roller or wheeled intake. With the size of the game piece relative to the size of the robot and the number of game pieces a robot could hold, we chose to go with a horizontal roller intake and to iterate on this concept.

The real quick test of this concept was stacking 90mm Traction wheels across a simple 15mm Extrusion frame. We direct drove the wheel roller with a Core Hex Motor as a proof of concept. This worked well as the traction wheels had enough grip to pick up the ring game pieces. Picking off of a stack of pieces could be challenging and something needed in future iterations.

This is the design we chose to iterate off of to find a better solution. Next steps were to mount this to a drivetrain to see how it performed.

Pasta Roller Intake

When we started the process of developing the intake we were thinking of styles used in the 2017 FIRST Robotics Competition game STEAMWORKS as inpsiration. In that game a gear, which was a flat game piece like the ring, was picked up individually and delivered to another location on the field. Curious to see if a "Pasta Roller" intake would work we started tinkering on a drivetrain to see what we could come up with.

Final Design

Utilizes one large roller to pull the ring in, one small roller to knock the front edge of the ring up, and one small roller to redirect the ring into the robot. This utilizes an open front of the robot to move the ring into a location where a conveyor or indexing system could live.

The large front roller is connected to an arm that is free to rotate, which introduces some compliance into the system. Since the rings have some compliance to them we could hard connect this to a specific location. Furthermore, a ridgid mounted intake didn't allow for the "kicking" of the ring up the back to rollers and into the drivetrain. Another option is to keep the "drop down" behavior and have the intake pushed further forward. This would allow for the outer large roller to store inside the start configuration and deploy once the match begins to give extra space. This option also could allow for more wheels and wider roller for better ability to pick up rings.

Design Considerations

The HD Hex Motor is running an UltraPlanetary with a 5:1 ratio. This is four times faster than the 20:1 ratio that the drive motors have. It is important for the intake speed to be faster than the driving surface speed so that the intake is able to pick up rings while the drivetrain is moving towards or away from the game piece.

Pieces of corrugated plastic were used as an easy way to direct rings from the wide front intake to the narrower rear rollers. The ring needs some way to be centered on the indexing mechanism, and corrugated plastic is an easy and effective way to create such a mechanism and comes in the FTC Starter Kit V3.

Other options

Rollers on the sides (i.e. parallel to the ground, on either side of the ring) could also be used, but it is more difficult to package:

  • The rollers have to fit within the 18” footprint limit but still reach out enough to grab the wheels

  • Adding compliance to the system is more difficult to achieve with side rollers, unless the rollers have some sort of compliant finger.

  • Power the side rollers is also a packaging/power issue as with the current design all rollers are powered off of the same motor.

Starter Bot - Programming Teleop

Basic Teleop Strategy

Our strategy for teleoperated mode was to make driving the robot as intuitive as possible. Having certain actions pre-programmed and assigned to buttons, like moving the arm into position to score on level 2 of the Shipping Hubs, will make the robot easier to control.

We decided to have buttons assigned to all 3 levels of the Shipping Hubs while scoring from the front and levels 2 and 3 from the back of the robot. Another decision we made was to have the intake motor controlled by the triggers. We chose to control the intake this way so that we could drive and pick up Freight at the same time.

Configuration and Wiring

Before getting started with programming we needed to create a configuration file. 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

Motor

0

REVRoboticsUltraplantary

LeftDrive

Motor

1

REVRoboticsUltraplantary

RightDrive

Motor

2

REVRoboticsCoreHexMotor

Arm

Motor

3

REVRoboticsCoreHexMotor

Intake

Servo

0

Servo

DuckSpinner

I2C

0

IMU

imu

Wiring Diagram

Device Name/Function
Device Type
Port

LeftDrive

HD Hex Motor

Motor/Encoder Port 0

RightDrive

HD Hex Motor

Motor/Encoder Port 1

Arm

Core Hex Motor

Motor/Encoder Port 2

Intake

Core Hex Motor

Motor/Encoder Port 3

DuckSpinner

Smart Robot Servo

Servo Port 0

Assigning Controls to a Gamepad/Controller

Items to consider when mapping out your gamepad:

  • What kind of input does the mechanism need?

  • What drivetrain are you using and what driving style do you want to use?

    • We decided the Freight Frenzy Starter Bot would be driven tank style.

  • Which input makes the most sense? Would pressing up on the d-pad be more intuitive for moving your arm up or down?

    • We chose to assign our backwards scoring presets to the bumpers because we liked the idea of backwards controls being on the back of the controller.

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

Freight Frenzy Starter Bot controller layout:

Input

Function

Right Joystick

Right Side Drive Motor

Left Joystick

Left Side Drive Motor

Right Trigger

Intake In

Left Trigger

Intake Out

Right Bumper

High Level (Back Scoring)

Left Bumper

Mid Level (Back Scoring)

A / ✕

Intake Ground Position

B / ◯

High Level (Front Scoring)

Y / △

Mid Level (Front Scoring)

X / ☐

Low Level (Front Scoring)

D-Pad Right

Duck Spinner Counter Clockwise

D-Pad Left

Duck Spinner Clockwise

Programming Teleop - Blocks

Drive Code

Remember to reverse one of the motors and set the correct direction for forward movement of your robot. In our code we needed to reverse both motors with the dual drive block.

Freight Delivery Mechanism Control Code

For all of our button inputs we used an if/else statement. In the image below you can see the first two sections, one for setting the position of the arm to the ground and one for setting it to the height of level 1 on the Shipping Hub.

Carousel and Intake Mechanisms Control Code

For the intake, we chose to use the triggers to control the speed of the motor spinning the mechanism. Since the triggers are easy to accidentally bump when holding the controller we decided we would only count the action as active if it was more than half way pressed. You can see this in the blocks intake mechanism code where the value of the right/left trigger is compared to 0.5.

Complete Blocks Program

Below is the complete Blocks Program for the Freight Frenzy Starter Bot.

Programming Teleoperated - OnBot Java

Drive Code

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;


@TeleOp

public class StarterKitRobotTank extends LinearOpMode {
    private DcMotor LeftDrive;
    private DcMotor RightDrive;


    @Override
    public void runOpMode() {
        LeftDrive = hardwareMap.get(DcMotor.class, "LeftDrive");
        RightDrive = hardwareMap.get(DcMotor.class, "RightDrive");
 
        telemetry.addData("Status", "Initialized");
        telemetry.update();
        // Wait for the game to start (driver presses PLAY)
        waitForStart();
        
        // run until the end of the match (driver presses STOP)
        while (opModeIsActive()) {
            //DRIVETRAIN CODE
            double leftAxis = -gamepad1.left_stick_y;
            double rightAxis = -gamepad1.right_stick_y;
            
            double leftPower = -leftAxis;
            double rightPower = rightAxis;
            
            LeftDrive.setPower(leftPower);
            RightDrive.setPower(rightPower);
            
            telemetry.update();
            }
        }
    }

Be sure to reverse one of the motors and set the correct direction for forward movement of your robot. In our code we needed to reverse both motors with the dual drive block.

Freight Delivery Mechanism Control Code

For all of our button inputs we used the if/else statement shown below:

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;


@TeleOp

public class StarterKitRobotTank extends LinearOpMode {
    private DcMotor ArmMotor;
    private DcMotor IntakeMotor;


    @Override
    public void runOpMode() {
        ArmMotor = hardwareMap.get(DcMotor.class, "Arm");
        ArmMotor.setTargetPosition(0);
        ArmMotor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        
        ArmMotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
        
        int ArmTarget = 0;

        telemetry.addData("Status", "Initialized");
        telemetry.update();
        // Wait for the game to start (driver presses PLAY)
        waitForStart();
        
        // run until the end of the match (driver presses STOP)
        while (opModeIsActive()) {
            //MECHANISM CODE
            
            if (gamepad1.a) {
                ArmTarget = 0; //On the ground for starting and intaking
            }
            else if (gamepad1.x) {
                ArmTarget = 120; //Low level on the goal
            }
            else if (gamepad1.y) {
                ArmTarget = 260; //Mid level on the goal
            }
            else if (gamepad1.b) {
                ArmTarget = 410; //High level on the goal
            }
            else if (gamepad1.right_bumper) {
                ArmTarget = 1420; //High level on the goal scoring backwards
            }
            else if (gamepad1.left_bumper) {
                ArmTarget = 1570; //Mid level on the goal scoring backwards
            }
            
            //stuff for arm position control
            ArmMotor.setTargetPosition(ArmTarget);
            ArmMotor.setPower(1);
             
            telemetry.addData("Arm Position", ArmMotor.getCurrentPosition());
            telemetry.update();
            }
        }
    }

Carousel and Intake Mechanisms Control Code

For the intake, we chose to use the triggers to control the speed of the motor spinning the mechanism. Since the triggers are easy to accidentally bump when holding the controller we decided we would only count the action as active if it was more than half way pressed. This is what the statementgamepad1.right_trigger>0.5)?1:((gamepad1.left_trigger>0.5)?-1:0); is used to achieve.

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;


@TeleOp

public class StarterKitRobotTank extends LinearOpMode {
    private DcMotor IntakeMotor;


    @Override
    public void runOpMode() {
       IntakeMotor = hardwareMap.get(DcMotor.class, "Intake");
        
   
        telemetry.addData("Status", "Initialized");
        telemetry.update();
        // Wait for the game to start (driver presses PLAY)
        waitForStart();
        
        // run until the end of the match (driver presses STOP)
        while (opModeIsActive()) {
            //MECHANISM CODE
            
            double IntakePower = (gamepad1.right_trigger>0.5)?1:((gamepad1.left_trigger>0.5)?-1:0);
            
            IntakeMotor.setPower(IntakePower);
                         
            telemetry.update();
            }
        }
    }

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.hardware.Servo;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;


@TeleOp

public class StarterKitRobotTank extends LinearOpMode {
    private Servo DuckSpinner;


    @Override
    public void runOpMode() {
         DuckSpinner = hardwareMap.get(Servo.class, "DuckSpinner");


        telemetry.addData("Status", "Initialized");
        telemetry.update();
        // Wait for the game to start (driver presses PLAY)
        waitForStart();
        
        // run until the end of the match (driver presses STOP)
        while (opModeIsActive()) {
            //MECHANISM CODE
            
            double SpinnerPower = gamepad1.dpad_left?1:(gamepad1.dpad_right?0:0.5);
           
            DuckSpinner.setPosition(SpinnerPower);
             
       
            telemetry.update();
            }
        }
    }

Complete OnBot Java Program

Below is the complete OnBot Java Program for the Freight Frenzy Starter Bot.

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.hardware.Servo;
import com.qualcomm.robotcore.hardware.Blinker;
import com.qualcomm.robotcore.hardware.Gyroscope;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.util.ElapsedTime;


@TeleOp

public class StarterKitRobotTank extends LinearOpMode {
    private Blinker Control_Hub;
    private Gyroscope imu;
    private DcMotor LeftDrive;
    private DcMotor RightDrive;
    private DcMotor ArmMotor;
    private DcMotor IntakeMotor;
    private Servo DuckSpinner;


    @Override
    public void runOpMode() {
        Control_Hub = hardwareMap.get(Blinker.class, "Control Hub");
        imu = hardwareMap.get(Gyroscope.class, "imu");
        LeftDrive = hardwareMap.get(DcMotor.class, "LeftDrive");
        RightDrive = hardwareMap.get(DcMotor.class, "RightDrive");
        ArmMotor = hardwareMap.get(DcMotor.class, "Arm");
        ArmMotor.setTargetPosition(0);
        ArmMotor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        
        ArmMotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
        
        IntakeMotor = hardwareMap.get(DcMotor.class, "Intake");
        
        DuckSpinner = hardwareMap.get(Servo.class, "DuckSpinner");
        
        int ArmTarget = 0;

        telemetry.addData("Status", "Initialized");
        telemetry.update();
        // Wait for the game to start (driver presses PLAY)
        waitForStart();
        
        // run until the end of the match (driver presses STOP)
        while (opModeIsActive()) {
            //DRIVETRAIN CODE
            double leftAxis = -gamepad1.left_stick_y;
            double rightAxis = -gamepad1.right_stick_y;
            
            double leftPower = -leftAxis;
            double rightPower = rightAxis;
            
            LeftDrive.setPower(leftPower);
            RightDrive.setPower(rightPower);
            
            //MECHANISM CODE
            
            double IntakePower = (gamepad1.right_trigger>0.5)?1:((gamepad1.left_trigger>0.5)?-1:0);
            
            double SpinnerPower = gamepad1.dpad_left?1:(gamepad1.dpad_right?0:0.5);
            
            if (gamepad1.a) {
                ArmTarget = 0; //On the ground for starting and intaking
            }
            else if (gamepad1.x) {
                ArmTarget = 120; //Low level on the goal
            }
            else if (gamepad1.y) {
                ArmTarget = 260; //Mid level on the goal
            }
            else if (gamepad1.b) {
                ArmTarget = 410; //High level on the goal
            }
            else if (gamepad1.right_bumper) {
                ArmTarget = 1420; //High level on the goal scoring backwards
            }
            else if (gamepad1.left_bumper) {
                ArmTarget = 1570; //Mid level on the goal scoring backwards
            }
            
            //stuff for arm position control
            ArmMotor.setTargetPosition(ArmTarget);
            ArmMotor.setPower(1);
            
            IntakeMotor.setPower(IntakePower);
            
            DuckSpinner.setPosition(SpinnerPower);
             
            telemetry.addData("Arm Position", ArmMotor.getCurrentPosition());
            telemetry.update();
            }
        }
    }

Conveyor

Once the rings are in the robot we need a way to store and then move them to the shooter to score points. One way to accomplish this is to create a conveyor belt system to move the game piece.

Requirements

  • No jamming - pieces are pretty compliant so worried they will be easier to jam up

  • Able to move vertically a plus - geometry of the 18" cube leaves a bit of a space constraint.

  • Power off of one motor or servo- need to limit the number of motors used here to save for other applications

Round Belt - Top/Bottom Belting

One of the first thoughts for moving the game pieces was to use pulleys with round belt. This is a good option as it gives flexibility where the pulleys are located as the belting is cut to length and then barbs are put in. One of the first sketches had belting on the top and/or bottom of the ring to move it along.

We chose to make a simple test rig with pulleys and round belt with using cardboard as a bottom floor for the prototype. The rings move pretty well through the system this way, however there was some slipping and concerns on the belting having enough compression in the middle over a longer run.

Side Belting

The next idea was to build a side belting with the pulleys and round belt. This would move the whole disk over as the belting was moving. We wanted to go with a bit of a thicker belt so transitioned to using GT2 Timing Belts to transfer the rings. This solution worked fairly well in testing.

Final Design

The final design uses 3mm GT2 belts mounted to extrusion to press on either side of the ring to bring from one location to another. The mechanism functions well at any angle up to 90 degrees, and even a little past 90 if need be.

The mechanism is driven by a single HD Hex Motor with a 20:1 reduction. This mechanism could probably go faster with a smaller reduction but would need more testing. Driving this with a servo(s) is also possible. The servo is slower, but the speed of this mechanism is not critical assuming you are moving pieces while aligning for a shot.

Notice that the flange of the GT2 pulleys extends past the thickness of the belt. In addition to changing the compression of the belt against the ring, the flange also has a very low coefficient of friction on the game piece. We found it was important to ensure that the pulley flanges didn't touch the game piece.

In order to get rid of the flange but keep the belt retained on the pulley, we used 30mm traction wheels on either side of the pulley middle section. These traction wheels have a good coefficient of friction against the game piece, and do not protrude past the thickness of the belt as much as the pulley flanges do.

Design Considerations

Friction: Friction is very important for pulling the ring up the feeder. The friction of the GT2 belts works well, but the friction of the round polybelt with only a single belt is not as good. If using polybelt multiple belts are likely needed.

Compression: There is a balance between the amount of compression the ring is seeing as it passes by a pulley versus the amount of compression it sees as it is in the middle of the belt. The amount of normal force, and thus the amount of friction, that the belt can exert on the ring greatly decreases in the middle of the belt. The extrusion side of the C-Channel could be used to have infinite adjustability on the mechanism to find the distance that has the perfect amount of compression. Once this is determined, the hole pattern of the c channel can be used to fix everything in place

Belt Length: Another important consideration is the length of the belt. On a long belt, the amount of normal force that the belt can exert on the ring is greatly reduced in the middle compared to a shorter belt. For this reason, two shorter belts are used in series rather than a single longer belt.

Game Piece

In the Ultimate Goal game there are two major game pieces: rings and wobble goals. In this section we will discuss dimensions of the elements and some of the scoring opportunities

Ring

Dimensions

The ring image above from Game Manual Part two is a drawing of the ring dimensions. We took the time as well to collect the weight of each ring and put all the dimensions in the table below.

Height

0.75

inches

Inner Diameter

3

inches

Outer Diameter

5*

inches

Weight

1.02*

ounces

The outer diameter of each ring is 5 inches with a manufacturing tolerance of plus or minus 0.25 inches.

Our testing yielded the weight as being 1.02 ounces with a tolerance of plus or minus 0.5 ounces

Material and Flexibility

The ring game piece is made of a flexible foam material, somewhat similar to the material of stress ball or foam volleyball. We do no know what the material is for sure but we do know that the ring is a very flexible, compliant element. In our video on game pieces Greg demonstrates the flexibility of the ring by squeezing it in several different directions.

So far in our testing it seems like the ring bounces back into its original shape if manipulated. We also haven't been able to damage the ring in significant way. That being said, we think there is potential for the rings to be damaged in a competition environment.

Tower Goal

Now that we have gone over the dimensions of the rind and the flexibility, we can consider the dimensions of the tower goal and power shot.

Goal

Height

Width

High

5 in

16 in

Mid

12 in

23 in

Low

8 in

23 in

Power shot

5 in

1 in

Each tower goal is different size. The change in size means that each goal (and the power shots) come with a different calculation to maximize the accuracy of a launch. For instance, the mid goal is the largest of the three goals and thus has the most area for accuracy.

We mentioned in our game strategy that in autonomous it may be more beneficial to score in the high tower goal rather than attempt to hit the power shots. Even though both elements are five inches in heights the total area for the high goal is significantly more than that of the power shot. The rate of a ring consistently going in the high goal is much higher than for scoring the power shot.

Wobble Goal

Dimensions

The sizing dimensions of the wobble goal can be seen in the image below. We weighed 3 of the wobble goals we had at the REV office and found them to be consistently around 14.5 ounces in weight.

Weight

14.5 ounces

We recommend treating the Wobble Goals like the weight one pound, during your design process. If you intend to pick the wobble from the pole keep in mind that the weight of the wobble goal is distributed mostly towards the bottom of the goal. The weight distribution of the wobble goal is important to torque calculations.

Material

Something to consider when designing mechanism for the Wobble Goal: the top cap of the goal is not completely attached to the pole. Though it takes some force that cap and come off. Be aware of that possibility if you are intended to grab the wobble goal by the top of the pole.

Programming Autonomous

Basic Autonomous Strategy

When we were planning for this years kickoff concept one thing we really wanted to address was the accessibility of autonomous scoring achievements. Certain barriers of entry to autonomous programming keep teams from scoring points during the autonomous period. What are these barriers? In our experience as FTC alumni and mentors, time and programming knowledge are the major reasons teams don't create autonomous programs. If a team feels like they don't have the time or skills, programming an autonomous can seem overwhelming. However, many autonomous scoring achievements, like navigation, are easily obtainable objectives that do not require a deep knowledge of programming.

After identifying this as a goal, analyzing the game, and laying out what a starter bot would look like; we decide to explore what a basic autonomous would be for the Freight Frenzy season. There are two major task we feel are achievable.

  • Placing the Pre-Load Box on level 1 of the Alliance Shipping Hub

  • Navigating to the Warehouse

As you may recall from the Game Breakdown, each robot must start with a pre-loaded box. For this season's randomization element, a robot determines what position the barcode is in and places the pre-loaded box on the corresponding level of the shipping hub. Using a vision component, like a webcam, to determine the position of the barcode is a more advanced programming concept. However, since placing freight on any level of the alliance shipping hub is worth 6 points (regardless of level), we think that placing the block on the 1st level of the shipping hub is an attainable task. This objective also comes with a 33% chance of getting the autonomous bonus.

Once we decided on placing the pre-loaded box the next decision to make was where to navigate: the warehouse or the storage unit. We chose the warehouse for a few different reasons. Parking in or completely in the warehouse is worth more points that parking in or completely in the storage unit. The warehouse also has a larger surface area than the storage unit, which means that less tuning is needed to get completely in.

We want to start with these two tasks for ease of access reasons. The important thing with programming is to work incrementally. Setting starting tasks allows us to focus on one section of the autonomous at a time, rather than get overwhelmed attempting to solve all the pieces. After tuning and working our autonomous to the point that we want, we can look at other tasks, like adding duck delivery to our lists of tasks.

Autonomous Path

Once we identified what objectives we wanted to achieve in autonomous we created a a basic path. We decided to have the robot start on the red alliance side of the field near the carousel. From there we identified the following basic elements of the path:

  1. Go to shipping hub and drop off the pre-loaded box

  2. Head towards Warehouse and straighten out

  3. Drive into warehouse and park

This path design is for a red alliance autonomous. Adjustments will need to be made to create blue alliance autonomous.

We know from our mockups for the basic starter kit robot that we want a differential drivetrain, single jointed arm, and roller intake. A differential drivetrain combined with limited the amount of space between the shipping hub and the field wall, makes turning in that space difficult. There is also a risk of the arm knocking into the shipping hub. Taking into consideration what the basic robot design was we knew we needed to make some adjustments to our path.

  • Path 1

    • Drive towards shipping hub

    • Turn slightly

  • Path 2

    • Lift arm to level 1 height

    • Get closer to shipping hub while arm is still lifted

    • Outtake pre-loaded box

  • Path 3

    • Reverse towards towards storage unit

    • Turn slight to angle towards warehouse

  • Path 4

    • Drive into warehouse

    • Park

Programming Autonomous - Blocks

Like with the Encoder Navigation guide, we created several constant variables to convert from encoder ticks per rotation of the HD Hex Motors (drivetrain motors) to ticks per millimeter traveled. We further converted this value to ticks per inch traveled. TheDRIVE_GEAR_REDUCTION variable was created by following the same guidelines from the Total Gear Reduction formula; using our planned gear ratios for the motor gearboxes and for transmitting motion to the wheels.

Another change we made was to howrightTarget and leftTarget are calculated. To reduce the need to useSTOP_AND_RESET_ENCODER mode before each path, we instead take the current position of the motor encoders and add the calculate ticks needed to go to target to the current position.

Once we had a general idea of the first path down and tested, we knew we were going to have to repeat the following segment of code for each path that requires the robot to drive.

This is a rather large segment of code, while duplicating it would allow us to repeat it, we decided instead to move it into a function. Functions in programming, much like mathematical functions, are a set of instructions that are bundled together to reach a particular goal. Since we are using the same (or similar) set of instructions to create each drive path, we can reduce clutter by creating a function that allows us to repeat these actions over and over again.

Lets start by creating a function called drive.

Before creating our function we looked at what information in our instructions needs to be editable. Each path will have a different target distance and we may want to change the speed the robot is running. Knowing this we create three parameters:power, leftInches, andrightInches. By adding parameters we are requiring that each instance of the function must be given a value for power (or speed) and the number of inches we want each motor to move.

Now that we have the basics of our function we can add in the motor code.

The parameter that we pass through the function act similar to variables. We used the rightInches and leftInches parameters to help us calculate the target position. We also use power to set speed.

With the function created we removed the motor code from our main op mode and reference the function instead. To confirm the function worked as expected we passed the parameter we knew lined up with the first path.

The leftInches and rightInches parameters are set to different values. We did this so that the robot would move in a relatively straight line and then turn slightly. For more information on the part speed and direction play in how drivetrains move, check out our Robot Navigation guide.

From here we can work to create our other paths. We know the next action we need to make is to lift the arm and hold that position. We know that RUN_TO_POSITION alone will not hold the arm for the amount duration needed to move forward and outtake the pre-loaded box. So we used the elapsed time function to do path 2.

We did some testing with the elapsed time solution. While it was able to score consistently, there are some flaws with this solution. Since path two is included in a loop the reference to our function, repeats itself; meaning that the drivetrain moves forward twice before the condition of the loop is met. In general, a flaw of using elapsed time, is that basing movement on time isn't a guarantee for consistency. That being said, in testing and refining our code to our robot we were able to score the pre-loaded box about 80% of the time. This met our basic standard for our autonomous.

Once we had path two figured out, we were able to do some basic testing to create paths 3 and 4 using our function.

This basic code allowed us to achieve our basic autonomous strategy. Bare in mind that we generated the power, rightInches, leftInches, and elapsed time numbers doing basic testing with our Class Bot and then made some assumptions from the other mechanisms we made. You will need to make adjustments based on your own mechanisms and hardware components To fine tune this code for your robot, test the code and adjust the number accordingly for the best results. Good luck!

Programming Autonomous - OnBot Java

@Autonomous
public class FreightFenzy_REDAuton1 extends LinearOpMode {

  private DcMotor RightDrive;
  private DcMotor LeftDrive;
  private DcMotor Arm;
  private DcMotor Intake;
  
  //Convert from the counts per revolution of the encoder to counts per inch
  static final double HD_COUNTS_PER_REV = 28;
  static final double DRIVE_GEAR_REDUCTION = 20.15293;
  static final double WHEEL_CIRCUMFERENCE_MM = 90 * Math.PI;
  static final double DRIVE_COUNTS_PER_MM = (HD_COUNTS_PER_REV * DRIVE_GEAR_REDUCTION) / WHEEL_CIRCUMFERENCE_MM;
  static final double DRIVE_COUNTS_PER_IN = DRIVE_COUNTS_PER_MM * 25.4;
    
  @Override
  public void runOpMode() {

    RightDrive = hardwareMap.get(DcMotor.class, "RightDrive");
    LeftDrive = hardwareMap.get(DcMotor.class, "LeftDrive");
    Arm = hardwareMap.get(DcMotor.class, "Arm");
    Intake = hardwareMap.get(DcMotor.class, "Intake");

   // reverse left drive motor direciton
    LeftDrive.setDirection(DcMotorSimple.Direction.REVERSE);
    
    waitForStart();
    if (opModeIsActive()) {
      // Create target positions
      rightTarget = RightDrive.getCurrentPosition() + (int)(30 * DRIVE_COUNTS_PER_IN);
      leftTarget = LeftDrive.getCurrentPosition() + (int)(15 * DRIVE_COUNTS_PER_IN);
      
      // set target position
      LeftDrive.setTargetPosition(leftTarget);
      RightDrive.setTargetPosition(rightTarget);
      
      //switch to run to position mode
      LeftDrive.setMode(DcMotor.RunMode.RUN_TO_POSITION);
      RightDrive.setMode(DcMotor.RunMode.RUN_TO_POSITION);
      
      //run to position at the desiginated power
      LeftDrive.setPower(0.7);
      RightDrive.setPower(0.7);
      
      // wait until both motors are no longer busy running to position
      while (opModeIsActive() && (LeftDrive.isBusy() || RightDrive.isBusy())) {
      }
      
      // set motor power back to 0 
      LeftDrive.setPower(0);
      RightDrive.setPower(0);
        }
     }
 }

Like with the Encoder Navigation guide, we created several constant variables to convert from encoder ticks per rotation of the HD Hex Motors (drivetrain motors) to ticks per millimeter traveled. We further converted this value to ticks per inch traveled. TheDRIVE_GEAR_REDUCTION variable was created by following the same guidelines from the Total Gear Reduction formula; using our planned gear ratios for the motor gearboxes and for transmitting motion to the wheels.

Another change we made was to howrightTarget and leftTarget are calculated. To reduce the need to useSTOP_AND_RESET_ENCODER mode before each path,; we instead take the current position of the motor encoders and add the calculate ticks needed to go to target to the current position.

Once we had a general idea of the first path down and tested, we knew we were going to have to repeat the following segment of code for each path that requires the robot to drive.

if (opModeIsActive()) {
      // Create target positions
      rightTarget = RightDrive.getCurrentPosition() + (int)(30 * DRIVE_COUNTS_PER_IN);
      leftTarget = LeftDrive.getCurrentPosition() + (int)(15 * DRIVE_COUNTS_PER_IN);
      
      // set target position
      LeftDrive.setTargetPosition(leftTarget);
      RightDrive.setTargetPosition(rightTarget);
      
      //switch to run to position mode
      LeftDrive.setMode(DcMotor.RunMode.RUN_TO_POSITION);
      RightDrive.setMode(DcMotor.RunMode.RUN_TO_POSITION);
      
      //run to position at the desiginated power
      LeftDrive.setPower(0.7);
      RightDrive.setPower(0.7);
      
      // wait until both motors are no longer busy running to position
      while (opModeIsActive() && (LeftDrive.isBusy() || RightDrive.isBusy())) {
      }
      
      // set motor power back to 0 
      LeftDrive.setPower(0);
      RightDrive.setPower(0);
  }
  

This is a rather large segment of code, while duplicating it would allow us to repeat it, we decided instead to move it into a function. Functions in programming, much like mathematical functions, are a set of instructions that are bundled together to reach a particular goal. Since we are using the same (or similar) set of instructions to create each drive path, we can reduce clutter by creating a function that allows us to repeat these actions over and over again.

Lets start by creating a function called drive.

//drive function
private void drive() {

  }

Before creating our function we looked at what information in our instructions needs to be editable. Each path will have a different target distance and we may want to change the speed the robot is running. Knowing this we create three parameters:power, leftInches, andrightInches. By adding parameters we are requiring that each instance of the function must be given a value for power (or speed) and the number of inches we want each motor to move.

// drive function intakes 3 parameters
private void drive(double power, double leftInches, double rightInches) {

  }

Now that we have the basics of our function we can add in the motor code.

private void drive(double power, double leftInches, double rightInches) {
    int rightTarget;
    int leftTarget;

    if (opModeIsActive()) {
     // Create target positions
      rightTarget = RightDrive.getCurrentPosition() + (int)(rightInches * DRIVE_COUNTS_PER_IN);
      leftTarget = LeftDrive.getCurrentPosition() + (int)(leftInches * DRIVE_COUNTS_PER_IN);
      
      // set target position
      LeftDrive.setTargetPosition(leftTarget);
      RightDrive.setTargetPosition(rightTarget);
      
      //switch to run to position mode
      LeftDrive.setMode(DcMotor.RunMode.RUN_TO_POSITION);
      RightDrive.setMode(DcMotor.RunMode.RUN_TO_POSITION);
      
      //run to position at the desiginated power
      LeftDrive.setPower(power);
      RightDrive.setPower(power);
      
      // wait until both motors are no longer busy running to position
      while (opModeIsActive() && (LeftDrive.isBusy() || RightDrive.isBusy())) {
      }
      
      // set motor power back to 0
      LeftDrive.setPower(0);
      RightDrive.setPower(0);
    }
  }

The parameter that we pass through the function act similar to variables. We used the rightInches and leftInchesparameters to help us calculate the target position. We also use power to set speed.

With the function created we can remove the motor code from our main op mode and reference the function instead. To confirm the function worked as expected we passed the parameter we knew lined up with the first segment.

  @Override
  public void runOpMode() {

    RightDrive = hardwareMap.get(DcMotor.class, "RightDrive");
    LeftDrive = hardwareMap.get(DcMotor.class, "LeftDrive");
    Arm = hardwareMap.get(DcMotor.class, "Arm");
    Intake = hardwareMap.get(DcMotor.class, "Intake");
   
   // reverse left drive motor direciton
    LeftDrive.setDirection(DcMotorSimple.Direction.REVERSE);
    
    waitForStart();
    if (opModeIsActive()) {
    
      // segment 1 
      drive(0.7, 30, 15);
    }
}

The leftInches and rightInches parameters are set to different values. We did this so that the robot would move in a relatively straight line and then turn slightly. For more information on the part speed and direction play in how drivetrains move, check out our Robot Navigation guide.

From here we can work to create our other paths. We know the next action we need to make is to lift the arm and hold that position. We know that RUN_TO_POSITION alone will not hold the arm for the amount duration needed to move forward and outtake the pre-loaded box. So we used the elapsed time function to do segment 2.

 static final double HD_COUNTS_PER_REV = 28;
 static final double DRIVE_GEAR_REDUCTION = 20.15293;
 static final double WHEEL_CIRCUMFERENCE_MM = 90 * Math.PI;
 static final double DRIVE_COUNTS_PER_MM = (HD_COUNTS_PER_REV * DRIVE_GEAR_REDUCTION) / WHEEL_CIRCUMFERENCE_MM;
 static final double DRIVE_COUNTS_PER_IN = DRIVE_COUNTS_PER_MM * 25.4;
 
 //Create elapsed time variable and an instance of elapsed time
 private ElapsedTime     runtime = new ElapsedTime();
waitForStart();
    if (opModeIsActive()) {
      
      //segment 1
      drive(0.7, 30, 15);
      
      runtime.reset(); // reset elapsed time timer
      
      //segment 2 - lift arm, drive to shipping hub, outtake freight
      while (opModeIsActive() && runtime.seconds() <= 7) {
        
        //lift arm and hold
        Arm.setTargetPosition(120);
        Arm.setMode(DcMotor.RunMode.RUN_TO_POSITION);
        Arm.setPower(0.3);
        
        //drive forward for 1 second
        while (runtime.seconds() > 2 && runtime.seconds() <= 3) {
          drive(0.4, 4, 4);
        }
        
        //run intake
        while (runtime.seconds() > 4 && runtime.seconds() <= 7) {
          Intake.setPower(-0.6);
        }
      
      // turn off arm and intake
      Arm.setPower(0);
      Intake.setPower(0);
    
      }

We did some testing with the elapsed time solution. While it was able to score consistently, there are some flaws with this solution. Since path two is included in a loop the reference to our function, repeats itself; meaning that the drivetrain moves forward twice before the condition of the loop is met. In general, a flaw of using elapsed time, is that basing movement on time isn't a guarantee for consistency. That being said, in testing and refining our code to our robot we were able to score the pre-loaded box about 80% of the time. This met our basic standard for our autonomous.

Once we had path two figured out, we were able to do some basic testing to create segments 3 and 4 using our function.

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.util.ElapsedTime;

@Autonomous(name = "FreightFenzy_REDAuton1 (Java)")
public class FreightFenzy_REDAuton1 extends LinearOpMode {

  private DcMotor RightDrive;
  private DcMotor LeftDrive;
  private DcMotor Arm;
  private DcMotor Intake;
  
  //Convert from the counts per revolution of the encoder to counts per inch
  static final double HD_COUNTS_PER_REV = 28;
  static final double DRIVE_GEAR_REDUCTION = 20.15293;
  static final double WHEEL_CIRCUMFERENCE_MM = 90 * Math.PI;
  static final double DRIVE_COUNTS_PER_MM = (HD_COUNTS_PER_REV * DRIVE_GEAR_REDUCTION) / WHEEL_CIRCUMFERENCE_MM;
  static final double DRIVE_COUNTS_PER_IN = DRIVE_COUNTS_PER_MM * 25.4;
  
  //Create elapsed time variable and an instance of elapsed time
  private ElapsedTime     runtime = new ElapsedTime();
  
  // Drive function with 3 parameters
  private void drive(double power, double leftInches, double rightInches) {
    int rightTarget;
    int leftTarget;

    if (opModeIsActive()) {
     // Create target positions
      rightTarget = RightDrive.getCurrentPosition() + (int)(rightInches * DRIVE_COUNTS_PER_IN);
      leftTarget = LeftDrive.getCurrentPosition() + (int)(leftInches * DRIVE_COUNTS_PER_IN);
      
      // set target position
      LeftDrive.setTargetPosition(leftTarget);
      RightDrive.setTargetPosition(rightTarget);
      
      //switch to run to position mode
      LeftDrive.setMode(DcMotor.RunMode.RUN_TO_POSITION);
      RightDrive.setMode(DcMotor.RunMode.RUN_TO_POSITION);
      
      //run to position at the desiginated power
      LeftDrive.setPower(power);
      RightDrive.setPower(power);
      
      // wait until both motors are no longer busy running to position
      while (opModeIsActive() && (LeftDrive.isBusy() || RightDrive.isBusy())) {
      }
      
      // set motor power back to 0
      LeftDrive.setPower(0);
      RightDrive.setPower(0);
    }
  }


  @Override
  public void runOpMode() {

    RightDrive = hardwareMap.get(DcMotor.class, "RightDrive");
    LeftDrive = hardwareMap.get(DcMotor.class, "LeftDrive");
    Arm = hardwareMap.get(DcMotor.class, "Arm");
    Intake = hardwareMap.get(DcMotor.class, "Intake");

 
    LeftDrive.setDirection(DcMotorSimple.Direction.REVERSE);
    
    waitForStart();
    if (opModeIsActive()) {
      
       //segment 1
      drive(0.7, 30, 15);
      
      runtime.reset(); // reset elapsed time timer
      
      //segment 2 - lift arm, drive to shipping hub, outtake freight
      while (opModeIsActive() && runtime.seconds() <= 7) {
        
        //lift arm and hold
        Arm.setTargetPosition(120);
        Arm.setMode(DcMotor.RunMode.RUN_TO_POSITION);
        Arm.setPower(0.3);
        
        //drive forward for 1 second
        while (runtime.seconds() > 2 && runtime.seconds() <= 3) {
          drive(0.4, 4, 4);
        }
        
        //run intake
        while (runtime.seconds() > 4 && runtime.seconds() <= 7) {
          Intake.setPower(-0.6);
        }
      
      // turn off arm and intake
      Arm.setPower(0);
      Intake.setPower(0);
      
      //segment 3 - reverse to get better angle 
      drive(0.7, -15, -30);
      
      //segment 4 - drive into warehouse
      drive(1, 90, 90);
    }
  }
}

This basic code allowed us to achieve our basic autonomous strategy. Bare in mind that we generated the power, rightInches, leftInches, and elapsed time numbers doing basic testing with our Class Bot and then made some assumptions from the other mechanisms we made. You will need to make adjustments based on your own mechanisms and hardware components. To fine tune this code for your robot, test the code and adjust the number accordingly for the best results.

Autonomous Wrap Up

The above walkthrough should give you the basic information to get started with programming your own autonomous. We recommend testing and tuning your code to make sure everything works consistently. Once you have a functioning code, explore different ways you can add on this code to elevate it. The starting position for the path puts you in a great place to deliver the duck, which can easily be reworked into your path. Also it is worth considering what your alliance partner may do in a match to better optimize the code.

Freight Delivery Mechanisms

Once we decided on a way to intake and outtake components, we needed to decide how to place freight on the various levels of the shipping hub. That line of thought brought us to our next game challenge question: what kind of mechanism do we need to score on each of the three levels. From there we brainstormed requirements and came up with a few different Freight Placement Mechanisms.

Requirements

  • Bare a Light Load - The mechanism has to be able to handle the load of an intake and a piece of freight.

  • Mounting Point - has a mounting point for an intake

  • Score All Three Levels - The mechanism has to be able to score on any of the three alliance shipping hub levels with ease

  • Simple, repeatable, reliable - we want something that is easy to build and consistently scores the required levels

Conveyor

In our kickoff concepts for the 2021 FTC game Ultimate Goal, we explored conveyor mechanisms to move the major game element between an intake and a shooter. This year, we wanted to explore how a conveyor mechanism could be used to intake, transfer, and outtake freight.

We created a simple conveyor mechanism using carboard and Timing Belts and Pulleys. We then attached it to a drivetrain. Right away we realized that the conveyor would not act as intake. In order to mitigate this we could attach a top roller intake to the mechanism and power it from the same motor that powers the conveyor. However, we noticed some other issues with this design that did not meet our requirements.

  • The conveyor is set to shipping hub level 3 and can not move to level 1 or 2

  • Does not consistently score at any level

  • Struggles to work with boxes

With the faults in mind we decided to scrap this idea, rather than develop it further.

Elevator

After scrapping the conveyor idea, we wanted to explore using our Linear Motion Kit to create an elevator. We made a few modifications to at two stage continuous lift to create the elevator below.

The graphic above showcases the lift on a drivetrain to show one of the ways it could (or would) be mounted.

We focused on some small changes to the lift to enhance performance, such as adding more Double Sided Sliders to the assembly to increase stability. However, the main change we made we spooled the string for the life. By sandwiching the string between the two sides of a GT2 Pulley, we were able to ensure that the string would stay secured while powering the mechanism.

To set the string in the pulley, pull the string through the wholes of the pulley so that one end of the string is sandwiched between the two pulleys. Ties of the other of the string and secure the assembly with bolts.

While the optimizations to the elevator worked in our favor as far as performance of the elevator, the elevator still did not meet our outlined requirements. Elevator mechanisms take time to make sure they are working smoothly that we didn't have as much time to optimize during the weekend.

Single Jointed Arms

As soon as we began brainstorming for Freight Frenzy, we realized that our Class Bot would be a good model for a pick and place game. The main reason for this realization is the fact that the Class Bot features a single jointed arm.

What makes a single jointed arm desirable as a mechanism this season? Lets consider a similar season to answer this question. Rover Ruckus required teams to intake components like the cargo and boxes (known in that season as silver and gold minerals), and place them inside a lander to score. The main difference between Rover Ruckus and Freight Frenzy is the height of lander versus the height of the alliance shipping hub. To score in the lander the robot needed to be able to extend to a height of ~29.5 inches from the game field floor, whereas level 3 of the alliance shipping hub is 16.25 inches from the game field floor.

In Rover Ruckus to reach the required height for scoring many teams created several stage linear motion mechanisms, linear motion mechanism attached to an arm, or multijointed arms. With Freight Frenzy the scoring height requirement is much shorter than that of Rover Ruckus. All three levels of the shipping hub are within the 18 by 18 by 18 inch frame requirement for the robot. Meaning that a robot with a single jointed arm within the frame requirement can easily score on each level of the alliance shipping hub.

Ultimately a single jointed arm with an intake mounted to it, is one of the simplest solutions to Freight Frenzy. We knew from experience that the class bot arm along would struggle to bare the load of an intake like the roller intakes we discussed previously. To solve this we decided to explore some sturdier options.

Above is one of our first drafts of a single jointed arm. C Channel provides an elevated torsional strength over extrusion, allowing the arm to withstand larger loads. The Channel also gives us more options for mounting an intake.

However, this version of the arm was heavier than we wanted, which may cause balance issues with the robot. This is easily solved with some counter balancing, but we wanted to see if we could create a more optimized version.

Four Bar Linkage

One of the issues with a single jointed arm is the positioning of the intake on the arm relative to the goal or playing field. This is something to consider with any pick and place type game like Freight Frenzy as the orientation of the intake matters for placement. Four Bar Linkages are one way to have the orientation of the intake stay constant through out the movement of the of the arm.

This specific implementation of a four bar linkage allows for the arm to be very light. The L Beams on the end of the linkage provide a number of mounting locations for an intake or claw. The linkage itsefl is connected to mounting points on the L Beams with Ball Joint Rod Ends with the stand offs connected back to the channel uprights in a similar manner.

Game Strategy

Game Introduction

The 2020-2021 FTC game is Ultimate Goal. The Ultimate Goal challenge features game elements such as rings, wobble goals, and tower goals. Each robot starts the match on the start line and must be in possession of an alliance specific Wobble goal. From there each team will progress through the thirty second autonomous period followed by the two minute long driver controlled period. The last thirty seconds of the match is the end game period. Each period has different scoring achievements. See the scoring summary excerpt from Game Manual Part 2 for more information on the game objectives.

Scoring Summary

If you are unfamiliar with the game the following field view can give insight to the field elements.

Game Strategy

The first step to any good FTC Game strategy is a full, in-depth understanding of the game. Strong knowledge of scoring achievements, point values, and game rules help teams develop a game strategy that maximizes their scoring ability. Once the knowledge is built the game can be broken down into data points for analysis.

A commonly used metric in the competitive robotics worlds is points per second. Basing your game strategy based on the amount of points you can gain per second (or even per game period), will help your team make the mechanical choices best for you!

The following section will highlight what we at REV saw as the best strategy for game plan. This choice was based on maximizing points per second.

Remember to always strategize and build within your resources! Not all teams will have access to the same resources, whether it is parts or people. A strategy that seems to yield the most points per second on paper may not be as successful as a strategy that focuses on maximizing accuracy.

Autonomous

As always, the autonomous period comes with a lot of different opportunities for scoring. This gives teams a broad range of scoring achievements to choose from. After analyzing the scoring opportunities we decided on a basic 4 part Autonomous strategy.

Launch the Pre-Loaded Rings

The highest point gain overall from the autonomous period is Launching all three rings into the tower goal (High) or at the power Shot. After some basic analysis, we determined a team could launch into the high goal at the start of autonomous before moving on to complete the other autonomous tasks.

Scoring Achievement

Points per Ring

Total Possible Points

High Tower Goal

12

36

Power Shot

15

45

While knocking back all three power shots get teams 45 total points during the autonomous period, there are a couple of reasons the high tower goal may be more beneficial to teams.

In our live stream we found that the high tower goal was a much more consistent scoring achievement. The tower goal is larger than the individual power shots and thus has a higher rate of scoring success. The larger scoring interface also means that teams will not have worry too much about robot location on the field to shoot. Early on in the season as teams are working on an iterating their robots, we think the high goal will yield more points per second than the power shot.

Analyze the Starter Stack

Once the rings have been launched the next scoring opportunity is moving the Wobble Goal to the appropriate target zone. In order to accomplish this task teams will need to take time to analyze the randomized starter stack.

The following table highlights some of the ways to analyze the starter stack:

Accuracy

Complexity

Vuforia

Most Accurate

Complex

Distance Sensor

Won't be able to differentiate as well between 1 and 4 rings

Complexity depends on use case

Once you've analyzed the starter stack, it will maximize time during Driver Controlled period to try to pick up the starter stack ring(s). When Driver Controller period starts those additional rings are ready to be scored.

Move the Wobble Goal

Even if analyzing the starter stack takes time to get accurate, moving the wobble goal to the same target zone every time has a 33% chance of success.

Moving the wobble goal to a specific part of the field can be accomplished by making small changes to the PushbotAutoDrive sample codes available through the FTC SDK.

Navigating

Driver Controlled

Since the only scoring achievement in the Driver Controlled period is scoring into the tower goals the main strategy to is efficiency and accuracy. As we said its always about maximizing points per second!

Human Player

Its important in this game period to keep a few things in mind: rules and the human player. Knowing the rules will help minimize penalties, which this year reduce your alliances overall score. The human player will be the person responsible for make sure that rings are continuously cycling back onto the field. A good strategy for every team is to ensure you understand the role of the human player and build your strategy around their speed.

Rings

Its also very important to analyze and understand how the rings behave once they are returned to the field. The rings have to hit the playing field floor before they are considered legally in play. We did some testing and found that once the rings hit the floor they had the velocity behind them to roll to the audience side of the field. Obviously the faster you pick up these rings the faster the turn around on scoring them.

Once you have analyzed how far the rings can role and what the best strategy for picking them up there is one particular game specific rules to take into consideration

GS 12

Rings must be launched into the mid and high tower goal from behind the launch line. If your intent is to score into either of these goals and the rings are rolling far enough over the line the best strategy may be letting the rings come to you.

With all that said the best strategy we can find is minimizing ring recycle time. While the high goal may be worth more points than the mid or low goal, we believe that no goal is counted out. Test your field, your rings, and your human player to make a decision on the best strategy for your team.

End Game

  • Wobble goal delivered to the start line or to the drop zone

  • Driver Controlled scoring opportunities (scoring in the tower goal) continues

  • Launching at the power shots

  • Scoring rings on the wobble goal

Wobble Goal Delivery

Delivering the wobble goal to the drop zone is worth 20 points per wobble goal delivered. The wobble goals are light but this strategy will likely require an elevator or lift that can move the wobble goal over the field wall into the drop zone. Though it is worth 20 points its important to consider the speed of this activity and the following questions

  • How many seconds does this take?

  • Is it a higher return of points per second to deliver the wobble goal to the start line and focusing on scoring rings?

Launching at the Power Shots

Successfully scoring all three power shots in end game yields 45 points. There are some of the same limitations to this as there were in autonomous. Accuracy is key.

Scoring rings on the Wobble Goal

As we went through analyzing the game we were not able to conclusively decide whether this scoring achievement was valuable. If you are able to score into the high goal with a certain amount of speed and accuracy; it seems like continuing to do so in end game would be more advantageous. However, a team that primarily scores in the low or mid goal may benefit from scoring rings on the wobble goal in end.

The other benefit is that rings scored on the wobble goal are out of play, which will starve the field of rings.

Bill of Materials

Full Bill of Materials (BOM) - Excel Download

Full Robot

Part Number
Description
QTY.

REV-31-1302

12V Slim Battery

1

REV-31-1387

Switch Cable and Bracket

1

REV-31-1595

Control Hub

1

REV-31-1596

Driver Hub

1

REV-31-2983

REV USB PS4 Compatible Gamepad

1

REV-41-1097

Smart Robot Servo

2

REV-41-1124

M3 x 20mm Hex Cap Screw

4

REV-41-1125

M3 x 35mm Hex Cap Screw

4

REV-41-1147

High Strength Hex Hub

3

REV-41-1166

Battery Holder Plate

1

REV-41-1190

90mm Omni Wheel

2

REV-41-1267

90mm Grip Wheel

4

REV-41-1291

HD Hex Motor

3

REV-41-1600

UltraPlanetary gearbox Kit & HD Hex Motor

3

REV-41-1303

15mm Plastic Motion Bracket

3

REV-41-1304

15mm Plastic Rod End Bracket

4

REV-41-1305

15mm Plastic 90 Degree Bracket

15

REV-41-1308

15mm Plastic 30 Degree Bracket

4

REV-41-1317

15mm Bearing Pillow Block

11

REV-41-1319

15mm Plastic Servo Bracket

2

REV-41-1321

15mm Plastic Lap Corner Bracket

15

REV-41-1323

15mm Spacer

3

REV-41-1324

3mm Spacer

28

REV-41-1326

Through Bore Bearing - Short

21

REV-41-1327

Shaft Collars

33

REV-41-1328

Servo Shaft Adapter

1

REV-41-1329

Through Bore Bearing - Long

15

REV-41-1333

125 Tooth Plastic Gear

2

REV-41-1334

45 Tooth Plastic Gear

4

REV-41-1335

60 Tooth Plastic Gear

3

REV-41-1337

90 Tooth Plastic Gear

1

REV-41-1338

10 Tooth #25 Sprocket

8

REV-41-1339

15 Tooth #25 Sprocket

2

REV-41-1343

40 Tooth #25 Sprocket

2

REV-41-1347

5mm x 75mm Hex Shaft

2

REV-41-1348

5mm x 90mm Hex Shaft

6

REV-41-1359

M3 x 8mm Hex Cap Screw

262

REV-41-1360

M3 x 16mm Hex Cap Screw

38

REV-41-1361

M3 Nyloc Nut

234

REV-41-1362

5mm x 400mm Hex Shaft

5

REV-41-1365

#25 Roller Chain

6

REV-41-1431

15mm Extrusion - 225mm

7

REV-41-1432

15mm Extrusion - 420mm - 90° Ends

7

REV-41-1433

15mm Metal Bent Core Hex Motor Bracket V2

3

REV-41-1491

M3 Standoff - 30mm

6

REV-41-1492

M3 Standoff - 40mm

8

REV-41-1493

M3 Standoff - 45mm

2

REV-41-1621

UltraPlanetary Outside Mounting Bracket

2

REV-41-1623

UltraPlanetary Bent Mounting Bracket

3

REV-41-1687

U Channel Endcap

4

REV-41-1702

Tensioning Bushing - 39mm

8

REV-41-1762

45mm x 15mm C Channel - 408mm

4

REV-41-1767

45mm x 15mm C Channel - 248mm

2

REV-41-1828

Aluminum Servo Horn V2

1

REV-41-1839

450mm x 300mm x 4mm Corrugated Plastic Sheet

1

REV-41-2702

DUO Flap Wheels (medium)

7

REV-41-1373

Hook and Loop Fastener, 13.5mm x 2m

2

REV-41-1161

Black Zipties

4

Substructures

Intake

Part number
Description
QTY.

REV-41-1359

M3 x 8mm Hex Cap Screws

25

REV-41-1360

M3 x 16mm Hex Cap Screws

4

REV-41-1361

M3 Nyloc Nuts

17

REV-41-1362

175mm cut Hex Shaft

1

REV-41-1327

Shaft Collars

2

REV-41-1329

Through Bore Bearing, Long

2

REV-41-1493

M3 Standoff - 45mm

2

REV-41-1491

M3 Standoff - 30mm

2

REV-41-2702

Flap Wheels - Medium

7

REV-41-1334

45 Tooth Plastic Gear

1

REV-41-1335

60 Tooth Plastic Gear

1

REV-41-1321

15mm Plastic Lap Corner Bracket

1

REV-41-1305

15mm Plastic 90 Degree Bracket

2

REV-41-1317

15mm Bearing Pillow Blocks

2

REV-41-1319

15mm Plastic Servo Bracket

1

REV-41-1097

Smart Robot Servo

1

REV-41-1828

Aluminum Servo Horn V2

1

REV-41-1431

15mm Extrusion - 225mm

3

REV-41-1839

Custom Cut Corrugated Plastic

1

Forearm

Part number
Description
QTY.

REV-41-1432

15mm Extrusion - 420mm - 90° Ends

2

REV-41-1431

15mm Extrusion - 225mm

5

REV-41-1321

15mm Plastic Lap Corner Bracket

10

REV-41-1359

M3 x 8mm Hex Cap Screw

48

REV-41-1360

M3 x 16mm Hex Cap Screw

14

REV-41-1361

M3 Nyloc Nut

54

REV-41-1433

15mm Metal Bent Core Hex Motor Bracket V2

3

REV-41-1317

15mm Bearing Pillow Block

3

REV-41-1097

Smart Robot Servo

1

REV-41-1319

15mm Plastic Servo Bracket

1

REV-41-1328

Servo Shaft Adapter

1

REV-41-1305

15mm Plastic 90 Degree Bracket

1

REV-41-1303

15mm Plastic Motion Bracket

3

REV-41-1491

M3 Standoff - 30mm

4

REV-41-1347

5mm x 75mm Hex Shaft

2

REV-41-1327

Shaft Collars

7

REV-41-1326

Through Bore Bearing - Short

3

REV-41-1324

3mm Spacer

8

REV-41-1304

15mm Plastic Rod End Bracket

4

REV-41-1335

60 Tooth Plastic Gear

2

REV-41-1125

M3 x 35mm Hex Cap Screw

4

REV-41-1329

Through Bore Bearing - Long

3

REV-41-1300

Core Hex Motor

1

REV-41-1362

5mm x 400mm Hex Shaft

1

REV-41-1343

40 Tooth #25 Sprocket

2

REV-41-1339

15 Tooth #25 Sprocket

2

REV-41-1365

#25 Roller Chain - 62 Link Loop

2

Tower

Part number
Description
QTY.

REV-41-1767

45mm x 15mm C Channel - 248mm

1

REV-41-1432

15mm Extrusion - 420mm

3

REV-41-1431

15mm Extrusion - 225mm

2

REV-41-1359

M3 x 8mm Hex Cap Screws

46

REV-41-1360

M3 x 16mm Hex Cap Screws

15

REV-41-1361

M3 Nyloc Nuts

56

REV-41-1362

400mm Hex Shaft

2

REV-41-1326

Through Bore Bearings, Short

4

REV-41-1329

Through Bore Bearings, Long

6

REV-41-1317

15mm Bearing Pillow Blocks

6

REV-41-1327

Shaft Collars

10

REV-41-1324

3mm Spacer

4

REV-41-1147

High Strength Hex Hub

3

REV-41-1333

125 Tooth Plastic Gear

2

REV-41-1334

45 Tooth Plastic Gear

3

REV-41-1333

90 Tooth Plastic Gear

1

REV-41-1600

UltraPlanetary Gearbox & HD Hex Motor Kit

1

REV-41-1433

15mm Metal Bent Core Hex Motor Bracket

3

REV-41-1308

15mm Plastic 30 Degree Bracket

4

Starter Bot - INTO THE DEEP

Introducing the 2024-25 REV DUO FTC Starter Bot!

This year's 2024-2025 REV DUO FTC Starter Bot is here to help as your team DIVEs into the season. Actively intake samples to deliver them to the low basket or observation zone, grab and hook specimens on the upper chamber, and ascend to the lower rung!

Refine the robot's movement with manual controls of the arm and wrist as you journey INTO THE DEEP℠.

2024-25 REV DUO FTC Starter Bot Walkthrough

Documentation Links

Programming Teleop

Configuration

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

Configuration file download

To put this configuration file on your robot, drag this file into the "FIRST" folder of your Control Hub's file system.

Wiring Diagram

Gamepad Setup

Items to consider when mapping out your gamepad:

  • What kind of input does the mechanism need?

  • What drivetrain are you using and what driving style do you want to use?

    • We decided our robot for CENTERSTAGE would be driven with Split Arcade Drive for advantages in precision while driving.

  • Which input makes the most sense?

    • There are multiple buttons in play for this year's Starter Bot. Both bumpers control the gripper's ability to pick up Pixels. The wrist servo is bound to the "A/Cross" and "B/Circle" buttons for rotating between the intake and home position. Lastly, this year's arm is controlled by the triggers.

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

2023-24 REV DUO FTC Starter Bot Gamepad Layout:

Programming Teleop - Blocks

Let's break down the Blocks Code for CENTERSTAGE!

Establishing Variables:

This year's Starter Bot makes use of a lot of variables.

Setting Up Encoders:

This code runs AFTER the initialization is activated, but BEFORE the play button is clicked.

This section allows the encoder on the arm Core Hex Motors to be reset to zero on start up and establishes their default behavior. Additionally, this sets two of the motors to run in reverse, one on the drivetrain and one of the arm motors.

This code will run ONCE after the play button is activated.

This section acts as an additional check for resetting the arm's power and position as well as setting the Core Hex Motors to "RUN_TO_POSITION" mode as default when the play button is clicked.

Split Arcade Drive:

The following sections all run REPEATEDLY in the "while loop" once the play button is activated.

Let's begin with programming our Split Arcade Drive. This code will take input from the right and left joysticks to determine the robot's movement. The left joystick controls forward and back, while the right stick controls left and right turning movement.

Manual Arm Movement:

The triggers on the controller determine the direction of the arm's rotation. The arm's power is determined by how far down both triggers are pressed. Additionally, the if/then statement switches the arm between manual drive and being ready to run the preset positions.

Arm and Wrist Preset Positions:

There are three preset positions for the arm and wrist on the Starter Bot- intake, home, and scoring.

Re-zero Encoder:

When you re-zero the encoder the arm and wrist should be in the HOME position.

Watchdog to Shutdown Motor in Home Position:

This check prevents the Core Hex Motors from continuing to run while in home position to prevent potential overheating.

Let's take a closer look at all the parts of this if/then statement:

This if/then statement will only run if all the following are met:

  • The arm is not currently moving in manual mode from the triggers being pressed

  • The motors are actively on

  • The left Core Hex Motor's current and target position are less than or equal to the threshold (currently set to five)

    • Home position's value is set to 0 while Intake is set to 10

Gripper Controls:

When either or both of the bumpers on the controller are held down the gripper will open fully. When released it will return to the closed position to secure the fingers around the pixel.

Programming Teleop - OnBot Java

Full Robot Code

To use this code with your Starter Bot, copy and paste it into a new OnBot Java OP Mode!

Using a differential or tank drivetrain, like the , is a solid option for teams.

Using a gives teams some extra maneuverability on the field by allowing the chassis to move omni directional.

For more in depth information on the configuration process check out !

Joysticks and Triggers input to your code allowing you to adjust the speed of a motor based on the pressure applied to the trigger or position of the joystick.

Buttons, Bumpers, and D-Pad provide to your code and are ideal for triggering a action such as rotating a motor to a set position.

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

This section makes the assumption that you have learned some of the FTC programming basics by going through the guide. If you have not gone through this guide please walk through it before proceeding.

In we covered how to program arcade drive with one joystick, for this example we will be programming tank drive using two joysticks. The right joystick input will control forward and reverse motion of the right side motor and the left joystick will control the left motor in the same way. Similar to the arcade style driving tutorial, we will use the Dual Motor block to assign power values to our motors. This time, the motor's power value will be based on the Y-axis input from each joystick, as shown below.

The control of our freight delivery arm is done by running the Core Hex Motor () to a specific position. We measured the number of encoder ticks needed to reach each of the five positions we had planned for our arm: low level, mid level, high level, high level from the back of the robot, and mid level from the back of the robot. For detailed instructions on how to measure encoder ticks on your robot and use the RUN_TO_POSITION block see .

The carousel mechanism is driven by a Smart Robot Servo (), therefore the programming is slightly different for continuous motion. First, we programmed the Smart Robot Servo with the SRS Programmer () to be in continuous mode. You can reference the for a tutorial on how to switch modes on your Smart Robot Servo. Make sure you are using a set position servo motor control block. Use as an in-depth guide. We added this into the end of our long if/else statement as seen below.

This section makes the assumption that you have learned some of the FTC programming basics by going through the guide. If you have not gone through this guide please walk through it before proceeding.

In we covered how to program arcade drive with one joystick, for this example we will be programming tank drive using two joysticks. The right joystick input will control forward and reverse motion of the right side motor and the left joystick will control the left motor in the same way. The main difference this time is the motor's power value will be based on the Y-axis input from each joystick, as shown below.

The control of our freight delivery arm is done by running the Core Hex Motor () to a specific position. We measured the number of encoder ticks needed to reach each of the five positions we had planned for our arm: low level, mid level, high level, high level from the back of the robot, and mid level from the back of the robot. For detailed instructions on how to measure encoder ticks on your robot and use the ArmTarget = statement see .

The carousel mechanism is driven by a Smart Robot Servo (), therefore the programming is slightly different for continuous motion. First, we programmed the Smart Robot Servo with the SRS Programmer () to be in continuous mode. You can reference the for a tutorial on how to switch modes on your Smart Robot Servo. Instead of using a motor.setPower statement we will be using motor.setPosition to make the servo rotate. You can find more information on how to program servos on the page.

Bottom View showing the Chain Run to

This section makes the assumption that you have learned some of the FTC programming basics by going through the guide. If you have not gone through this guide please walk through it before proceeding.

In the, we covered how to useRUN_TO_POSITION to create paths for the Class bot. We decided to use the same basic concepts to create the path for the Freight Frenzy autonomous. To start we created the code for the first path.

This section makes the assumption that you have learned some of the FTC programming basics by going through the guide. If you have not gone through this guide please walk through it before proceeding.

In the , we covered how to useRUN_TO_POSITION to create paths for the Class bot. We decided to use the same basic concepts to create the path for the Freight Frenzy autonomous. To start we created the code for the first path.

If you are new to FTC programming check out our to learn the basics of programming within the FTC SDK.

For a more in depth explanation of the game check out .

If you are participating in remote events check out .

We are assuming based on the language provided in Game Manual Part 2 that the Rings in the Starter Stack are not playable until the start of the Driver Controlled period. This is not called out in the Game Specific Rules. Please keep up to date with the for more clarity on this ruling.

Navigation is the final step to the 4 part autonomous strategy. Using the PushbotAutoDrive sample codes mention in the step, all teams should be able to navigate to and park over the launch line.

The from game manual part 2 includes the following end game scoring opportunities:

The 2024-25 REV DUO Starter Bot is designed to be built using the FTC Starter Kit V3.1 () and DUO Control Bundle ().

The 2024-25 REV DUO Starter Bot is designed to be built using the FTC Starter Kit V3.1 () and DUO Control Bundle ().

Port Type
Port Number
Device Type
Name

For more in-depth information on the configuration process check out !

Device Name
Device Type
Port

Joysticks and Triggers input to your code allowing you to adjust the speed of a motor based on the pressure applied to the trigger or position of the joystick.

Buttons, Bumpers, and D-Pad provide to your code and are ideal for triggering an action such as rotating a motor to a set position.

Gamepad Input
Function

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

This section makes the assumption that you have learned some of the FTC programming basics by going through the guide. If you have not gone through this guide please walk through it before proceeding.

In we covered how to program arcade drive with one joystick. For this example, we will be programming arcade drive using two joysticks. This type of drive is called "split arcade". 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.

Variable
Purpose

in your kit for accurate gripper and wrist movement!

Controller Button
Position

This section makes the assumption that you have learned some of the FTC programming basics by going through the guide. If you have not gone through this guide please walk through it before proceeding.

In we covered how to program arcade drive with one joystick. For this example, we will be programming arcade drive using two joysticks. This type of drive is called "split arcade". 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.

Starter Bot Build Guide - PDF
Starter Bot CAD Assembly - STEP
Starter Bot Autonomous Programming - Online
Starter Bot Teleop Programming - Online
Starter Bot Teleop Blocks Code
Starter Bot Teleop OnBot Java Code
2023-24 REV DUO Starter Bot Build Guide - PDF
2023-24 Starter Bot CAD - Onshape
Teleop Code and Configuration Instructions
Bill of Materials
Channel Drivetrain
mecanum drivetrain
Hello Robot - Configuration
floating point data
boolean data
Hello Robot - Using Gamepads
Hello Robot
Hello Robot- Basics of Programming Drivetrains
REV-41-1300
Hello Robot - Arm Control
REV-41-1079
REV-31-1108
SRS Programmer Basics
Hello Robot - Servo Basics
Click here to download the Freight Frenzy Starter Bot Blocks code.
Hello Robot
Hello Robot- Basics of Programming Drivetrains
REV-41-1300
Hello Robot - Arm Control
REV-41-1079
REV-31-1108
SRS Programmer Basics
Hello Robot - Servo Basics
Hello Robot
Hello Robot - Encoder Navigation
Hello Robot
Hello Robot - Encoder Navigation
Hello Robot programming guide
Game Manual Part 2 - Traditional Events Section 4.5 Gameplay
Game Manual Part 2 - Remote Events Section 4.5 Gameplay
FTC Q&A forum
REV-45-3529
REV-35-2709
Move the Wobble Goal
scoring summary

Motor

0

REV Robotics Ultraplanetary HD Hex Motor

rightDrive

Motor

1

REV Robotics Ultraplanetary HD Hex Motor

leftDrive

Motor

2

REV Robotics Core Hex Motor

rightarm

Motor

3

REV Robotics Core Hex Motor

leftarm

Servo

0

Servo

wrist

Servo

1

Servo

gripper

rightDrive

UltraPlanetary Gearbox Kit and HD Hex Motor

Motor/Encoder Port 0

leftDrive

UltraPlanetary Gearbox Kit and HD Hex Motor

Motor/Encoder Port 1

armright

Core Hex Motor

Motor/Encoder Port 2

armleft

Core Hex Motor

Motor/Encoder Port 3

wrist

Smart Robot Servo

Servo Port 0

gripper

Smart Robot Servo

Servo Port 1

Right Joystick

Turn Left and Right

Left Joystick

Drive Forward and Reverse

Right and/or Left Bumper

Gripper Close

A/Cross

Arm & Wrist Move to Home Position

  • Arm Down, Wrist Up

B/Circle

Arm & Wrist Move to Intake Position

  • Arm Down, Wrist Down

Y/Triangle

Arm & Wrist Move to Scoring Position

  • Arm Back, Wrist Up

Option

Zero Encoder for Arm

Left Trigger

Lower Arm

Right Trigger

Raise Arm

homearmposition

Tells the arm where it should sit when set to "home position"

armIntakePosition

Tells the arm where it should sit to intake pixels

armScorePosition

Tells the arm where it should be for scoring

manualMode

Used for checks of if the arm is being manually controlled with the triggers or using the preset positions

armShutdownThreshold

Used in the watchdog check for if the motors are running and when to shutdown

wristUpPosition

Sets the value for when the wrist is in the up position

wristDownPosition

Sets the value for when the wrist is in the down position

gripperClosedPosition

Sets the default gripper position

gripperOpenPosition

Sets the position for where the gripper should move to when the bumpers are pressed

running

Used in the watchdog check for if the motors are in "run_to_position" mode

A/Cross

Arm moves to the down position, Wrist moves up

B/Circle

Arm moves to the down position, Wrist moves down

Y/Triangle

Arm moves up to behind the robot, Wrist moves to up - the arm should adjust to its final scoring position

/* Copyright (c) 2017 FIRST. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted (subject to the limitations in the disclaimer below) provided that
 * the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this list
 * of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice, this
 * list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.
 *
 * Neither the name of FIRST nor the names of its contributors may be used to endorse or
 * promote products derived from this software without specific prior written permission.
 *
 * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS
 * LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.hardware.Servo;
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.util.ElapsedTime;
import com.qualcomm.robotcore.util.Range;

@TeleOp(name="Starter Bot 2024", group="Iterative Opmode")

public class StarterBot2024Teleop extends OpMode
{
    // Declare OpMode members.
    private ElapsedTime runtime = new ElapsedTime();
    private DcMotor leftDrive = null;
    private DcMotor rightDrive = null;
    private DcMotor armLeft = null;
    private DcMotor armRight = null;
    private Servo gripper = null;
    private Servo wrist = null;
    
    private boolean manualMode = false;
    private double armSetpoint = 0.0;
    
    private final double armManualDeadband = 0.03;
    
    private final double gripperClosedPosition = 1.0;
    private final double gripperOpenPosition = 0.5;
    private final double wristUpPosition = 1.0;
    private final double wristDownPosition = 0.0;
    
    private final int armHomePosition = 0;
    private final int armIntakePosition = 10;
    private final int armScorePosition = 600;
    private final int armShutdownThreshold = 5;

    /*
     * Code to run ONCE when the driver hits INIT
     */
    @Override
    public void init() {
        telemetry.addData("Status", "Initialized");

        leftDrive  = hardwareMap.get(DcMotor.class, "leftDrive");
        rightDrive = hardwareMap.get(DcMotor.class, "rightDrive");
        armLeft  = hardwareMap.get(DcMotor.class, "armLeft");
        armRight = hardwareMap.get(DcMotor.class, "armRight");
        gripper = hardwareMap.get(Servo.class, "gripper");
        wrist = hardwareMap.get(Servo.class, "wrist");

        leftDrive.setDirection(DcMotor.Direction.FORWARD);
        rightDrive.setDirection(DcMotor.Direction.REVERSE);
        leftDrive.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.FLOAT);
        rightDrive.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.FLOAT);
        
        armLeft.setDirection(DcMotor.Direction.FORWARD);
        armRight.setDirection(DcMotor.Direction.REVERSE);
        armLeft.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        armRight.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        armLeft.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
        armRight.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
        armLeft.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
        armRight.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
        armLeft.setPower(0.0);
        armRight.setPower(0.0);

        telemetry.addData("Status", "Initialized");
    }

    /*
     * Code to run REPEATEDLY after the driver hits INIT, but before they hit PLAY
     */
    @Override
    public void init_loop() {
    }

    /*
     * Code to run ONCE when the driver hits PLAY
     */
    @Override
    public void start() {
        runtime.reset();
        
        armLeft.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        armRight.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        armLeft.setTargetPosition(armHomePosition);
        armRight.setTargetPosition(armHomePosition);
        armLeft.setPower(1.0);
        armRight.setPower(1.0);
        armLeft.setMode(DcMotor.RunMode.RUN_TO_POSITION);
        armRight.setMode(DcMotor.RunMode.RUN_TO_POSITION);
    }

    /*
     * Code to run REPEATEDLY after the driver hits PLAY but before they hit STOP
     */
    @Override
    public void loop() {
        double leftPower;
        double rightPower;
        double manualArmPower;
        
        //DRIVE
        double drive = -gamepad1.left_stick_y;
        double turn  =  gamepad1.right_stick_x;
        leftPower    = Range.clip(drive + turn, -1.0, 1.0) ;
        rightPower   = Range.clip(drive - turn, -1.0, 1.0) ;

        leftDrive.setPower(leftPower);
        rightDrive.setPower(rightPower);
        
        //ARM & WRIST
        manualArmPower = gamepad1.right_trigger - gamepad1.left_trigger;
        if (Math.abs(manualArmPower) > armManualDeadband) {
            if (!manualMode) {
                armLeft.setPower(0.0);
                armRight.setPower(0.0);
                armLeft.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
                armRight.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
                manualMode = true;
            }
            armLeft.setPower(manualArmPower);
            armRight.setPower(manualArmPower);
        }
        else {
            if (manualMode) {
                armLeft.setTargetPosition(armLeft.getCurrentPosition());
                armRight.setTargetPosition(armRight.getCurrentPosition());
                armLeft.setPower(1.0);
                armRight.setPower(1.0);
                armLeft.setMode(DcMotor.RunMode.RUN_TO_POSITION);
                armRight.setMode(DcMotor.RunMode.RUN_TO_POSITION);
                manualMode = false;
            }
            
            //preset buttons
            if (gamepad1.a) {
                armLeft.setTargetPosition(armHomePosition);
                armRight.setTargetPosition(armHomePosition);
                armLeft.setPower(1.0);
                armRight.setPower(1.0);
                armLeft.setMode(DcMotor.RunMode.RUN_TO_POSITION);
                armRight.setMode(DcMotor.RunMode.RUN_TO_POSITION);
                wrist.setPosition(wristUpPosition);
            }
            else if (gamepad1.b) {
                armLeft.setTargetPosition(armIntakePosition);
                armRight.setTargetPosition(armIntakePosition);
                armLeft.setPower(1.0);
                armRight.setPower(1.0);
                armLeft.setMode(DcMotor.RunMode.RUN_TO_POSITION);
                armRight.setMode(DcMotor.RunMode.RUN_TO_POSITION);
                wrist.setPosition(wristDownPosition);
            }
            else if (gamepad1.y) {
                armLeft.setTargetPosition(armScorePosition);
                armRight.setTargetPosition(armScorePosition);
                armLeft.setPower(1.0);
                armRight.setPower(1.0);
                armLeft.setMode(DcMotor.RunMode.RUN_TO_POSITION);
                armRight.setMode(DcMotor.RunMode.RUN_TO_POSITION);
                wrist.setPosition(wristUpPosition);
            }
        }
        
        //Re-zero encoder button
        if (gamepad1.start) {
            armLeft.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
            armRight.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
            armLeft.setPower(0.0);
            armRight.setPower(0.0);
            manualMode = false;
        }
        
        //Watchdog to shut down motor once the arm reaches the home position
        if (!manualMode &&
        armLeft.getMode() == DcMotor.RunMode.RUN_TO_POSITION &&
        armLeft.getTargetPosition() <= armShutdownThreshold &&
        armLeft.getCurrentPosition() <= armShutdownThreshold
        ) {
            armLeft.setPower(0.0);
            armRight.setPower(0.0);
            armLeft.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
            armRight.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
        }
        
        //GRIPPER
        if (gamepad1.left_bumper || gamepad1.right_bumper) {
            gripper.setPosition(gripperOpenPosition);
        }
        else {
            gripper.setPosition(gripperClosedPosition);
        }

        telemetry.addData("Status", "Run Time: " + runtime.toString());
        telemetry.addData("Gamepad", "drive (%.2f), turn (%.2f)", drive, turn);
        telemetry.addData("Motors", "left (%.2f), right (%.2f)", leftPower, rightPower);
        telemetry.addData("Manual Power", manualArmPower);
        telemetry.addData("Arm Pos:",
            "left = " + 
            ((Integer)armLeft.getCurrentPosition()).toString() + 
            ", right = " +
            ((Integer)armRight.getCurrentPosition()).toString());
        telemetry.addData("Arm Pos:",
            "left = " + 
            ((Integer)armLeft.getTargetPosition()).toString() + 
            ", right = " +
            ((Integer)armRight.getTargetPosition()).toString());
    }

    /*
     * Code to run ONCE after the driver hits STOP
     */
    @Override
    public void stop() {
    }

} 
provided program

Starter Bot Changelog

Changes made to any of the 2023-24 REV DUO FTC Starter Bot Documentation will be listed below. Check back for updates as the season progresses!

Version
Release Date & Notes

v1.0.0 - Build Guide

9/15/23

- Initial Release

v1.0.0 - Code and Configuration

9/15/23

- Java Code Initial Release - Configuration File Initial Release

v1.0.0 - Bill of Materials

9/15/23

- Initial Release

v1.0.1 - Build Guide

10/27/23 -Tower BOM Updated to remove excess qty. -Arm Step 7: Added the 15mm Spacers to the Get Section -Gripper Step 1: 90 Tooth Gear not 60 Tooth -Gripper Step 7: 12 M3 X 35mm not M3 X 16mm -Gripper Step 7: Added note for flex in 90 Brackets

v1.0.1 - Bill of Materials

10/27/23

-Tower BOM Updated to remove excess qty.

REV-45-3529
REV-35-2709
Hello Robot - Configuration
floating point data
boolean data
Hello Robot - Using Gamepads
Hello Robot
Hello Robot- Basics of Programming Drivetrains
You will need to program your servos with the SRS Programmer
Hello Robot
Hello Robot- Basics of Programming Drivetrains

Lifts

The varying heights of the Junctions create a challenge for placing cones that can be solved with a vertical movement from your robot. When designing these lifts, we decided to try three popular categories of Lifts used commonly in FTC: Linear Lifts, Single Jointed arms, and a Four Bar Linkages.

Requirements

  • Simple, Reliable, Compact - we want something that fits within the 18"x18"x18" starting requirement, is easy to build and consistently scores at all levels

  • Bear a Light Load - The mechanism has to be able to handle the load of the intake and a single cone or Beacon.

Lift Prototypes

Elevator

We started exploring designs with our Linear Motion Kit. We made a few modifications to the two stage continuous lift to create the elevator below. While it is fairly easy to build and deploy, this lift is not capable of reaching the high junctions. However, you may be able to add on another stage to gain more height. Also, the Linear motion kit can be used for horizontal motion too, as seen in our Lift Prototypes video above.

Single Jointed Arms

A Single Jointed Arm is one of the simplest solutions for a lift. We knew from past experience that this arm would struggle to reach the high junctions and fit within the 18"x18"x18" size restraint. It is important to pay attention to your geometry calculations when building a Single Jointed Arm so you can maximize your reach. This version of the arm was also a little heavier than we wanted, which may cause balance issues with a more narrow or smaller drivetrain.

Four Bar Linkage

Four Bar Linkages are very similar to Single Jointed Arms because they both pivot around a single point. You will run into similar issues with what height they can reach so be sure to pay attention to your geometry calculations! However, Four Bar Linkages are unique because they maintain the orientation of the object they are lifting. This is very useful for POWERPLAY when lifting a standing cone. As the lift rises, the cone will remain parallel to the plane it started in, remaining upright.

Reverse Virtual Four Bar

A Reverse Virtual Four Bar Linkage is a two-stage lift where the second stage is actuated by a four bar arm. Because the lift folds back on itself, you can reach almost twice as high as a single jointed lift. The Virtual Four Bar is created by the chain and it helps keep the end of the lift traveling along one plane. This keeps whatever you are raising in an intake oriented correctly for the whole lift.

The Kickoff Concepts team really liked this lift so we mounted our Compact Active Roller Intake to the end for our Starter Bot testing. It is mounted on a hinge so that the lift will keep the cones upright, but we will still have the needed compliance for lining up to intake cones.

2024-25 REV DUO Starter Bot Build Guide - PDF
Channel Drivetrain Build Guide
2024-25 Starter Bot CAD - Onshape
TeleOp Code Tutorial and Configuration Instructions
Bill of Materials
Upgrades!
2024-25 REV DUO Starter Bot Changelog
Compatibility with Starter Kit V3

Intake

Since Freight Frenzy's possession and control rule limits robots to one piece of freight at a time, one of the keys for success is the intake mechanism. Intakes can take many forms, so we brainstormed some concepts and put them through the engineering design process to help us decide on an intake that met our gameplay requirements

Requirements

  • Touch it, own it - Be able to quickly intake and control freight

  • Adaptable - Be able to pick up all the different types of freight

  • Pick up one - reduces the chances of picking up more than one freight

  • Release it - be able to outtake the element with ease

Scoop Intake

Once we identified our requirements for an intake, one of things to come to mind as a potential mechanism was some sort of gripper. We started with a Class Bot claw to do initial testing. However we had some issues with grabbing cargo and ducks.

With the variance in size and shape of each of the different types of freight, we decided to take inspiration from claw machine claws. However, while claw machine claws are capable of picking up objects of different sizes and shapes, they aren't great at retaining objects. By playing with the idea of a claw machine we came up with the idea to create a scoop mechanism. The idea was to have a mechanism attached to a cage. The scooper extends out to direct freight into the cage and retain them in place while the robot moves to a shipping hub.

After designing and building the mechanism, we put it to the test to determine if it met our requirements. The scoop was great at directing and intaking the cargo, but struggled to intake the boxes and ducks. There are a few fixes to this design that would get it to work more efficiently, such as replacing the servo with a motor to get more power on the scoop. While, this alternative may elevate the design to more successfully grab the other freight, lets explore some of other options.

Roller Intakes

To evolve our intake into something that meets the requirements we set, we took a look at the prior FTC games that the cargo and boxes were used in, particularly the 2019 game Rover Ruckus. One of the most common and efficient intake types during those seasons were some sort of roller intake.

We used an intake prototype from last years kickoff concepts, and iterated three total designs: one with traction wheels, one with a corrugated plastic flapper, and one with surgical tubing. We tested each roller intake to determine over all compliance and effectiveness. From this we found that the flapper was the the relatively level of compliance we needed.

We used a sheet of corrugated plastic that leverages behind each type of freight to intake and outtake them. The benefit of using corrugated plastic as the intake is the ability to adjust compliance. In our case we cut our corrugated plastic piece so that the side that interfaces most with freight is parallel to the ridges of the plastic. We then folded along the ridges of the plastic. This made the corrugated plastic more compliant, which increased the intakes speed and accuracy.

We still wanted to evolve our designs and find a better more robust intake. So after this initial test we went back to the drawing board to further iterate.

Side Roller Intake

After trying out the Scoop Intake, we decided to explore roller intakes. One of the benefits of roller intakes over grip intakes, like the Scoop, are their ability to direct game elements. This time we took inspiration from car wash rollers. The side rollers on car washes not only clean the car, but help direct it along the track.

Using this idea we created the "Side Roller Intake". The Side Intake utilizes two rollers, both made using a combination of REV Sprockets and Polycord.

During the testing process the Side Roller Intake, grabbed and released boxes quickly and efficiently. However, in order to grab cargo, the cargo had to be pushed up against a wall; otherwise the intake knocked cargo out of the way rather than intaking it.

In the Ultimate Goal season we explored side rollers and had some concerns about how they packaged into the robot. Some of those same concerns came up with the intake.

  • Size - Side Roller was difficult to package within the limits of our drivetrain

  • Weight - The weight of the Side Roller, when attached to an arm, caused instability

There were some other issues with this design including: lack of mounting space to attach the intake to an arm and the fact that the arm picks up more than one game element. To address these issues, move standoffs to decrease the size of the storage for the intake or add other structural components to mount off of.

Building the Sprocket Wheel Assembly

Belt segments should be a bit longer than needed. It’s easier to cut down than replace the loop.

  1. Add 20mm screws in the corners of the motion pattern on a 32 Tooth Metal sprocket

  2. Create three polybelt loops using zipties. Place them on alternating screws.

  3. Add a 26 Tooth Plastic Sprocket to the assembly. Then create and add the three more polybelt loops, on the opposite screws to where the bottom loops were places.

  4. Add another 32 Tooth Metal Sprocket and nuts to the assembly

  5. Cut the zipties and pull the belts so each loop rests against the screw and is equal distance from the others.

  6. Tight screws until belts a significantly compressed and can not shift around at all.

Top Roller Intake

We decided to create a top roller intake as well. Choosing to do a top roller allowed us to gain the benefits of a roller intake while taking up less space than the side roller intake.

The top roller intake we created uses our compliant wheels with a 5mm Hex Insert. We also created a spring loaded jaw using M3 Standoffs and surgical tubing. The compliance and strength of this mechanism meets all of our requirements. It is able to intake and outtake all three freight quickly and and reduces the chance of picking up more than once piece of freight.

For this design we powered the scoop using a Smart Robot Servo (). We wanted to use the servo programmer on the Smart Robot Servo to have an operating range of 180 degrees for the scoop mechanism. To do this we utilized an Aluminum Double Servo Arm () and a Flat Beam to create a linkage.

REV-41-1097
REV-41-1820
688B
StarterBot2025.xml
38KB
Starterbot2025TeleOpBlocks.blk
9KB
StarterBot2025TeleOpJava.java
38KB
Starterbot2025TeleOpBlocksTwoGamepad.blk
38KB
Starterbot2025TeleOpBlocksArcade.blk
49KB
Starterbot2025Mecanum.blk
978B
StarterBotMecanum.xml
40KB
Starterbot2025TeleOpBlocksNoInit.blk
50KB
2023-24 REV DUO FTC Starter Bot BOM v1.0.1.xlsx
7KB
Starter Bot 2024-25 BOM.xlsx
733B
StarterBot2024.xml
37KB
Starterbot2024TeleOPBlocks.blk
Copy of the full Blocks code!
Wiring diagram for the 2024-25 Starter Bot
Initialization Code
Variable states at program start
Variables in Blocks using strings
Variables in OnBot Java using enum
Arm and Wrist Presets
Blocks Functions
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
Setting the mode and target position for the motors
Split Arcade Drive
Switching arm control to gamepad 2
Arcade Drive Code
Motors are set to RUN_WITHOUT_ENCODER are the beginning of the code
Our mecanum drive function
Forward/back is on left Y, strafe on left X, and turning on right X
Calculating motor power
Making sure our power range is between -1 to 1
Setting motor power
STATE_MACHINE with INIT change
ZEROING position
When LeftBumper is pressed the arm and wrist move to ZEROING
Updated STATE_MACHINE
REV's Mecanum Drivetrain Kit V2
2023-24 REV DUO FTC Starter Bot
2023-24 REV DUO FTC Starter Bot Arm
2023-24 REV DUO FTC Starter Bot Gripper
POWERPLAY Starter Bot Drive Code (Blocks)
POWERPLAY Starter Bot Lift Code (Blocks)
POWERPLAY Starter Bot Intake Code (Blocks)
POWERPLAY Starter Bot Complete Code (Blocks)
2023-24 REV DUO FTC Starter Bot
2024-25 REV DUO FTC Starter Bot
2024-25 REV DUO Starter Bot
2023-24 Starter Bot Gamepad Control Bindings
Variables for the 2023-24 Starter Bot
Arcade Split Drive Code
Freight Frenzy Starter Bot
Concept Sketch for Pinch Intake
Concept Sketch for Roller Intake
Gamepad layout
Blocks tank drive code
Blocks freight delivery arm code
Blocks intake mechanism code
Blocks carousel mechanism code
Full blocks code for the Freight Frenzy Starter Bot
Game Manual Part 2
Game Manual Part 2

Flywheel Launcher

One of the strategic goals laid out was to score in the high goal from the starting location. Designing a flywheel launcher was the direction we chose to prototype.

Requirements

  • No jamming - pieces are pretty compliant so worried they will be easier to jam up

  • Score from starting location - need to reach the goal from the starting location to match strategy

  • Shoot consistently - be able to hit the same spot repeatedly to make alignment easier

Shooter Design

We chose the linear shooter because it was the simplest to construct and package in the time required.

There are three types of launchers we wanted to test with the rings: single fly wheel, double flywheel, and a single flywheel with accelerator wheel.

First Prototype

The first prototype used an UltraPlanetary Gearbox on an HD Hex Motor that was mounted to extrusion. Compression plays a role in the speed the rings exit the launcher however this stayed constant as the gear ratios were swapped out. Testing for the mechanism is in the video below.

Final Design

The goal of this mechanism was to have a powerful launcher that could consistently make a full-court toss into the high goal. We deemed that it was necessary to launch the ring as close to laser-like as possible to make aiming and programming easier. This necessitated beefing up the framework, adding ball bearings, and having the UltraPlanetary Gearbox running as a direct drive onto the HD Hex Motor.

An important concept to understand when designing a launcher is that the game piece will generally fly better the longer the amount of time that it is being accelerated. For this reason, this mechanism uses two motors, both on 1:1 ratios. Each motor directly drives one grip wheel. The first wheel accelerates the ring to a certain speed, and the second motor accelerates the ring from that speed to a very fast final speed. To add weight to the flywheel 86 Tooth Metal Gears were inset to the wheel allowing it to keep inertia when it was in contact with a ring.

The ring rolls against the 15x30mm extrusion as it is being accelerated by the wheel. The compression of the ring against the grip wheels can be adjusted by sliding the 15x30mm extrusion along the bottom extrusion rails. An adjustable amount of compression is an important factor when designing prototypes. This mechanism was designed robustly because any amount of compliance in the system will likely result in inconsistencies in the shot.

1:1 Ratio on the Motors

Getting the 1:1 ratio on the motors is simple! The following table is a list of all REV products needed to get the 1:1 ratio for one motor.

Part Number

Description

Qty

UltraPlanetary 550 Motor Plate

1

UltraPlanetary Female 5mm Hex Output Cartridge

1

UltraPlanetary 550 Motor Pinion Gear

1

UltraPlanetary Hardware Pack (M3 x 10mm)

6

UltraPlanetary Hardware Pack (M3 x 8mm Button Head)

2

The 550 Motor Pinion Gear comes pre-pressed onto the HD Hex Motors that come with UltraPlanetary Gearbox and HD Hex Motor Kit.

If you have an HD Hex Motor that is not from an UltraPlanetary Kit you will have to remove the pinion pre-pressed on the motor and then press the 550 Motor Pinion onto the motor.

Many FRC teams in 2013 fired frisbees into similar goals, and this design was common among them. Teams like , , and used this shooter with success.

Other mechanisms could also inspire shooting methods. could also be effective, as would shooters with a instead of a straight wall.

254
2791
399
Clay Pigeon Shooters
rounded wall
REV-41-1607
REV-41-1604
REV-41-1608
REV-41-1609
REV-41-1609