CrocoDocs
CrocoDocs

Introduction

What is CrocoDocs?Season Breakdown

Getting Started

Programming in FTCJavaBlocksAndroid Studio

Control Systems

IntroductionJoystick MappingPID ControlMotion ProfilingKalman FilterLow-Pass Filter

Autonomous

IntroductionTime vs Encoder-Based MovementOdometryMotion PlanningPure PursuitSensor Fusion

Codebase Etiquette and Good Practices

IntroductionNaming ConventionsCode OrganizationComments and DocumentationTeam Collaboration

Libraries

LibrariesNextFTCPedro PathingFTC DashboardMercurialPanelsSloth

Sensors and Vision

Vision OverviewVision Basics

Android Studio

Power up your coding! ⚡

Android Studio — What It is and Why We Use It

Android Studio is a powerful integrated development environment (IDE) built by Google specifically for Android app development. In FTC robotics, we use Android Studio to write, test, and debug the code that runs on our robot's Control Hub or Robot Controller phone. It provides essential tools like code completion, syntax highlighting, and debugging features that make programming our robots much easier and more efficient than using a simple text editor.

Android Studio — Installation & Importing the FTC SDK

Make Sure You Have

  • Android Studio installed on your computer
  • Git installed (Android Studio uses Git behind the scenes)
  • Internet connection (to clone the repository from GitHub)

Installing Android Studio (Windows / macOS / Linux)

  1. Go to the official Android Studio download page and click Download Android Studio.

  2. Run the downloaded installer file:

    • On Windows: Double-click the .exe file and follow the setup wizard.
    • On macOS: Open the .dmg file and drag Android Studio into your Applications folder.
    • On Linux: Extract the downloaded archive and run studio.sh from android-studio/bin.
  3. Follow the setup instructions on screen and accept the default options. Android Studio will install the Android SDK and other necessary tools during setup.

  4. When finished, launch Android Studio. If it asks to install additional components (SDKs, tools, etc.), allow it to complete the download.

How to Import the FTC SDK Using Version Control (VCS)

  1. Open Android Studio. If it's already open on another project, go to File → Close Project so you see the Android Studio welcome screen.

  2. Click Get from Version Control or Check out from VCS. This lets you import a project directly from an online Git repository without the command line.

  3. Paste the FTC SDK GitHub URL:

    https://github.com/FIRST-Tech-Challenge/FtcRobotController.git

    This is the official FTC Android Studio project repository.

  4. Choose a Local Folder. Pick where you want the project to be saved on your computer — you can name the folder after your team or season.

  5. Click Clone. Android Studio will automatically download the project and open it.

  6. Trust & Open the Project. When prompted, click Trust Project or Open.

  7. Build / Sync Gradle. Android Studio will start syncing and building the project. This can take a minute — Gradle downloads everything the project needs in the background.

Where Your Code Goes

Once the project is opened and synced, locate the TeamCode module — this is where all your custom robot programs (OpModes) will live.

Typical folder tree:

TeamCode
 └─ src
     └─ main
         └─ java
             └─ org.firstinspires.ftc.teamcode

This org.firstinspires.ftc.teamcode package is where you create or paste your robot programs.

What You Now Have

After cloning and opening the project:

  • A full Android Studio project with at least two main modules:
    • FtcRobotController → contains the robot controller app and sample code
    • TeamCode → this is where your team's robot programs go

The TeamCode folder is the only place from which custom OpModes will be installed onto your robot controller device at runtime.

Programming Your Robot — The Basics

Now that you have Android Studio set up, let's cover the fundamentals of writing robot code for FTC.

Quick Notes for Beginners

You don't need to understand every Java concept right away — just focus on:

  • Classes (containers for your robot programs)
  • Methods (init, loop, runOpMode)
  • Variables (names for motors and sensors)
  • Gamepad inputs (how drivers control the robot)

You can learn more Java fundamentals later — but the above is enough to start coding a robot that moves and responds to controls.

What is an OpMode?

An OpMode (Operation Mode) is a program that runs on your robot. There are two main types:

  • TeleOp — Used during the driver-controlled period where humans control the robot with gamepads
  • Autonomous — Used during the autonomous period where the robot runs pre-programmed actions

Every OpMode you write will be a Java class that extends either LinearOpMode or OpMode.

Your First OpMode

Here's a simple TeleOp program that controls a drive motor with the gamepad:

package org.firstinspires.ftc.teamcode;

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

@TeleOp(name="Basic Drive", group="TeleOp")
public class BasicDrive extends LinearOpMode {
    
    // Declare motor variable
    private DcMotor driveMotor;
    
    @Override
    public void runOpMode() {
        // Initialize hardware
        driveMotor = hardwareMap.get(DcMotor.class, "drive_motor");
        
        // Wait for driver to press START
        waitForStart();
        
        // Run until driver presses STOP
        while (opModeIsActive()) {
            // Get gamepad input
            double power = -gamepad1.left_stick_y;
            
            // Set motor power
            driveMotor.setPower(power);
            
            // Display info on driver station
            telemetry.addData("Motor Power", power);
            telemetry.update();
        }
    }
}
package org.firstinspires.ftc.teamcode

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode
import com.qualcomm.robotcore.eventloop.opmode.TeleOp
import com.qualcomm.robotcore.hardware.DcMotor

@TeleOp(name = "Basic Drive", group = "TeleOp")
class BasicDrive : LinearOpMode() {
    
    // Declare motor variable
    private lateinit var driveMotor: DcMotor
    
    override fun runOpMode() {
        // Initialize hardware
        driveMotor = hardwareMap.get(DcMotor::class.java, "drive_motor")
        
        // Wait for driver to press START
        waitForStart()
        
        // Run until driver presses STOP
        while (opModeIsActive()) {
            // Get gamepad input
            val power = -gamepad1.left_stick_y.toDouble()
            
            // Set motor power
            driveMotor.power = power
            
            // Display info on driver station
            telemetry.addData("Motor Power", power)
            telemetry.update()
        }
    }
}

Understanding the Hardware Map

The hardwareMap is how you access your robot's hardware (motors, sensors, servos, etc.). Before you can use any hardware in code, you must:

  1. Configure it in the Robot Controller app — Give each device a name (e.g., "drive_motor")
  2. Retrieve it in your code — Use hardwareMap.get() with the exact same name
// Get a motor
DcMotor motor = hardwareMap.get(DcMotor.class, "motor_name");

// Get a servo
Servo servo = hardwareMap.get(Servo.class, "servo_name");

// Get a sensor
ColorSensor colorSensor = hardwareMap.get(ColorSensor.class, "color_sensor");
// Get a motor
val motor = hardwareMap.get(DcMotor::class.java, "motor_name")

// Get a servo
val servo = hardwareMap.get(Servo::class.java, "servo_name")

// Get a sensor
val colorSensor = hardwareMap.get(ColorSensor::class.java, "color_sensor")

Working with Motors

Motors are controlled by setting their power (a value from -1.0 to 1.0):

// Set motor to full speed forward
motor.setPower(1.0);

// Set motor to half speed backward
motor.setPower(-0.5);

// Stop the motor
motor.setPower(0);

// Set motor direction
motor.setDirection(DcMotorSimple.Direction.REVERSE);

// Set motor mode (using encoders or not)
motor.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
// Set motor to full speed forward
motor.power = 1.0

// Set motor to half speed backward
motor.power = -0.5

// Stop the motor
motor.power = 0.0

// Set motor direction
motor.direction = DcMotorSimple.Direction.REVERSE

// Set motor mode (using encoders or not)
motor.mode = DcMotor.RunMode.RUN_USING_ENCODER

Using the Gamepad

The gamepad1 and gamepad2 objects give you access to controller inputs:

// Joystick values (analog, -1.0 to 1.0)
double leftY = -gamepad1.left_stick_y;   // Forward/backward
double leftX = gamepad1.left_stick_x;    // Left/right
double rightY = -gamepad1.right_stick_y;
double rightX = gamepad1.right_stick_x;

// Button values (digital, true/false)
boolean aPressed = gamepad1.a;
boolean bPressed = gamepad1.b;
boolean xPressed = gamepad1.x;
boolean yPressed = gamepad1.y;

// Bumpers and triggers
boolean leftBumper = gamepad1.left_bumper;
boolean rightBumper = gamepad1.right_bumper;
double leftTrigger = gamepad1.left_trigger;   // 0.0 to 1.0
double rightTrigger = gamepad1.right_trigger; // 0.0 to 1.0

// D-pad
boolean dpadUp = gamepad1.dpad_up;
boolean dpadDown = gamepad1.dpad_down;
boolean dpadLeft = gamepad1.dpad_left;
boolean dpadRight = gamepad1.dpad_right;
// Joystick values (analog, -1.0 to 1.0)
val leftY = -gamepad1.left_stick_y.toDouble()   // Forward/backward
val leftX = gamepad1.left_stick_x.toDouble()    // Left/right
val rightY = -gamepad1.right_stick_y.toDouble()
val rightX = gamepad1.right_stick_x.toDouble()

// Button values (digital, true/false)
val aPressed = gamepad1.a
val bPressed = gamepad1.b
val xPressed = gamepad1.x
val yPressed = gamepad1.y

// Bumpers and triggers
val leftBumper = gamepad1.left_bumper
val rightBumper = gamepad1.right_bumper
val leftTrigger = gamepad1.left_trigger.toDouble()   // 0.0 to 1.0
val rightTrigger = gamepad1.right_trigger.toDouble() // 0.0 to 1.0

// D-pad
val dpadUp = gamepad1.dpad_up
val dpadDown = gamepad1.dpad_down
val dpadLeft = gamepad1.dpad_left
val dpadRight = gamepad1.dpad_right

Complete Robot Example

Here's a more complete example showing a basic drive system with multiple motors:

package org.firstinspires.ftc.teamcode;

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

@TeleOp(name="Complete Robot", group="TeleOp")
public class CompleteRobot extends LinearOpMode {
    
    // Declare hardware
    private DcMotor leftMotor;
    private DcMotor rightMotor;
    private DcMotor armMotor;
    private Servo clawServo;
    
    @Override
    public void runOpMode() {
        // Initialize all hardware
        leftMotor = hardwareMap.get(DcMotor.class, "left_motor");
        rightMotor = hardwareMap.get(DcMotor.class, "right_motor");
        armMotor = hardwareMap.get(DcMotor.class, "arm_motor");
        clawServo = hardwareMap.get(Servo.class, "claw_servo");
        
        // Reverse one motor for proper drive
        rightMotor.setDirection(DcMotor.Direction.REVERSE);
        
        // Wait for START
        telemetry.addData("Status", "Initialized");
        telemetry.update();
        waitForStart();
        
        // Main loop
        while (opModeIsActive()) {
            // Drive control (tank drive)
            double leftPower = -gamepad1.left_stick_y;
            double rightPower = -gamepad1.right_stick_y;
            
            leftMotor.setPower(leftPower);
            rightMotor.setPower(rightPower);
            
            // Arm control
            double armPower = -gamepad2.left_stick_y * 0.5; // Slower speed
            armMotor.setPower(armPower);
            
            // Claw control (open/close with buttons)
            if (gamepad2.a) {
                clawServo.setPosition(0.0); // Close
            } else if (gamepad2.b) {
                clawServo.setPosition(1.0); // Open
            }
            
            // Telemetry
            telemetry.addData("Left Power", leftPower);
            telemetry.addData("Right Power", rightPower);
            telemetry.addData("Arm Power", armPower);
            telemetry.addData("Claw Position", clawServo.getPosition());
            telemetry.update();
        }
    }
}
package org.firstinspires.ftc.teamcode

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode
import com.qualcomm.robotcore.eventloop.opmode.TeleOp
import com.qualcomm.robotcore.hardware.DcMotor
import com.qualcomm.robotcore.hardware.Servo

@TeleOp(name = "Complete Robot", group = "TeleOp")
class CompleteRobot : LinearOpMode() {
    
    // Declare hardware
    private lateinit var leftMotor: DcMotor
    private lateinit var rightMotor: DcMotor
    private lateinit var armMotor: DcMotor
    private lateinit var clawServo: Servo
    
    override fun runOpMode() {
        // Initialize all hardware
        leftMotor = hardwareMap.get(DcMotor::class.java, "left_motor")
        rightMotor = hardwareMap.get(DcMotor::class.java, "right_motor")
        armMotor = hardwareMap.get(DcMotor::class.java, "arm_motor")
        clawServo = hardwareMap.get(Servo::class.java, "claw_servo")
        
        // Reverse one motor for proper drive
        rightMotor.direction = DcMotor.Direction.REVERSE
        
        // Wait for START
        telemetry.addData("Status", "Initialized")
        telemetry.update()
        waitForStart()
        
        // Main loop
        while (opModeIsActive()) {
            // Drive control (tank drive)
            val leftPower = -gamepad1.left_stick_y.toDouble()
            val rightPower = -gamepad1.right_stick_y.toDouble()
            
            leftMotor.power = leftPower
            rightMotor.power = rightPower
            
            // Arm control
            val armPower = -gamepad2.left_stick_y.toDouble() * 0.5 // Slower speed
            armMotor.power = armPower
            
            // Claw control (open/close with buttons)
            if (gamepad2.a) {
                clawServo.position = 0.0 // Close
            } else if (gamepad2.b) {
                clawServo.position = 1.0 // Open
            }
            
            // Telemetry
            telemetry.addData("Left Power", leftPower)
            telemetry.addData("Right Power", rightPower)
            telemetry.addData("Arm Power", armPower)
            telemetry.addData("Claw Position", clawServo.position)
            telemetry.update()
        }
    }
}

Learning More

Want to dive deeper into Java for FTC? Check out this comprehensive free resource:

Learn Java for FTC — A free online book and GitHub repository that explains Java basics and FTC coding examples in a beginner-friendly way.

This book covers everything from Java fundamentals to advanced FTC programming concepts, making it perfect for teammates who are new to programming or want to strengthen their skills.

JavaBlocks

Drag, drop, and code! 🎨

Introduction

Master the fundamentals of robot control

On this page

Android Studio — What It is and Why We Use ItAndroid Studio — Installation & Importing the FTC SDKMake Sure You HaveInstalling Android Studio (Windows / macOS / Linux)How to Import the FTC SDK Using Version Control (VCS)Where Your Code GoesWhat You Now HaveProgramming Your Robot — The BasicsQuick Notes for BeginnersWhat is an OpMode?Your First OpModeUnderstanding the Hardware MapWorking with MotorsUsing the GamepadComplete Robot ExampleLearning More