Skip to content

Editing code in a nutshell

sbottingota edited this page Sep 8, 2024 · 4 revisions

🥜 Editing code: in a nutshell

Table of Contents
What's what in the code
Creating an OpMode
OpMode Examples
Creating a Component
Testing Code

What's what in the code

1. Click the bar above the files and select "Android" 2. Please see the following diagram for the useful code files we can edit. They will be commented with documentation.
image image The libs.brightonCollege folder is outdated and has been removed as it overcomplicates matters. In its place is a components folder for storing components as described below.
  1. There are also external libraries not visible in this view. To show one, Ctrl+Click a reference to it in the code.
  • com.arcrobotics.ftclib FTCLib - our main library for hardware, etc. [Docs] [Reference]
  • com.qualcomm.robotcore.hardware Hardware - Use FTCLib instead of these if you can. [Reference]

Creating an OpMode

❕ If you programmed in last year's team, the code would have been slightly different. To make things simpler, this year we are not using "our own library" and instead are using the default FTCLib way of doing things.

  1. Either:

a) Right-click the file and copy your OpMode from the external.samples folder, then paste it in our opModes folder (see above). Rename it (using PascalCaseWhereWordsAreJoinedLikeThis), click "OK", then comment out the @Disabled line (Ctrl+/)

1 2 3
image image image

or:

b) Right-click our opModes folder, create a new Java class, give it a name, and paste one of the templates below into the file. Click the first package line where an error may appear and then Alt+Enter and Enter, to fix it if necessary. Then, replace "<ClassName>" with the name you just used for the class.

1 2 3
image image image

OpMode Examples

Please click a heading to view the code.

Driver-Controlled (Iterative)

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.OpMode;

/**
 * TODO: Fill in
 * Description: [Fill in]
 * Hardware:
 *  [motor0] Unused
 *  [motor1] Unused
 *  [motor2] Unused
 *  [motor3] Unused
 *  [servo0] Unused
 *  [servo1] Unused
 *  [servo2] Unused
 *  [servo3] Unused
 * Controls:
 *  [Button] Function
 */
@TeleOp(name="<OpMode name>", group="<OpMode group name>")
public abstract class <ClassName> extends OpMode {
    // TODO: Declare class members here
    
    @Override
    public void init() {
        // TODO: Code to run once after `INIT` is pressed
    }

    @Override
    public void loop() {
        // TODO: Code to run repeatedly after `PLAY` is pressed
        CommandScheduler.getInstance().run(); // Trigger FTCLib commands if necessary
        telemetry.update(); // Update telemetry (output stream on Driver Station)
    }
}

Driver-Controlled (Linear)

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;

/**
 * TODO: Fill in
 * Description: [Fill in]
 * Hardware:
 *  [motor0] Unused
 *  [motor1] Unused
 *  [motor2] Unused
 *  [motor3] Unused
 *  [servo0] Unused
 *  [servo1] Unused
 *  [servo2] Unused
 *  [servo3] Unused
 * Controls:
 *  [Button] Function
 */
@TeleOp(name="<OpMode name>", group="<OpMode group name>")
public abstract class <ClassName> extends LinearOpMode {
    @Override
    public void runOpMode() {
        // TODO: Code to run once after the `INIT` button is pressed.
        waitForStart();
        // TODO: Code to run once after the `PLAY` button is pressed.
        while (opModeIsActive()) {
            // TODO: Code to run repeatedly after the `PLAY` button is pressed and until the `STOP` button is pressed.
            CommandScheduler.getInstance().run(); // Trigger FTCLib commands if necessary
            telemetry.update(); // Update telemetry (output stream on Driver Station)
        }
    }
}

Autonomous (Iterative)

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.OpMode;

/**
 * TODO: Fill in
 * Description: [Fill in]
 * Hardware:
 *  [motor0] Unused
 *  [motor1] Unused
 *  [motor2] Unused
 *  [motor3] Unused
 *  [servo0] Unused
 *  [servo1] Unused
 *  [servo2] Unused
 *  [servo3] Unused
 */
@Autonomous(name="<OpMode name>", group="<OpMode group name>")
public abstract class <ClassName> extends OpMode {
    // TODO: Declare class members here
    
    @Override
    public void init() {
        // TODO: Code to run once after `INIT` is pressed
    }

    @Override
    public void loop() {
        // TODO: Code to run repeatedly after `PLAY` is pressed
        CommandScheduler.getInstance().run(); // Trigger FTCLib commands if necessary
        telemetry.update(); // Update telemetry (output stream on Driver Station)
    }
}

Autonomous (Linear)

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;

/**
 * TODO: Fill in
 * Description: [Fill in]
 * Hardware:
 *  [motor0] Unused
 *  [motor1] Unused
 *  [motor2] Unused
 *  [motor3] Unused
 *  [servo0] Unused
 *  [servo1] Unused
 *  [servo2] Unused
 *  [servo3] Unused
 */
@Autonomous(name="<OpMode name>", group="<OpMode group name>")
public abstract class <ClassName> extends LinearOpMode {
    @Override
    public void runOpMode() {
        // TODO: Code to run once after the `INIT` button is pressed.
        waitForStart();
        // TODO: Code to run once after the `PLAY` button is pressed.
        while (opModeIsActive()) {
            // TODO: Code to run repeatedly after the `PLAY` button is pressed and until the `STOP` button is pressed.
            CommandScheduler.getInstance().run(); // Trigger FTCLib commands if necessary
            telemetry.update(); // Update telemetry (output stream on Driver Station)
        }
    }
}
  1. You're now ready to use the OpMode!

Creating a component

If you want to code a modular system like an arm, the drivetrain, an intake, etc., it is good practise to make a specific class in a specific file containing only that class in the components folder. Use Javadocs to describe each method's purpose (this linked way to generate them will work in Android Studio, which is a version of "IntelliJ").

Please click here for an example.

This is quite complicated - please don't feel you need to understand everything. Please just take away these key points:

  1. Everything contained in the component is inside its class, in a single file in the components folder, or imported as a separate class from a different folder.
  2. They are all documented.
  3. Wherever possible, FTCLib features are used to save time.
  4. Easily-understandable functions in the component like setTargetPosition can be called from an OpMode.

Path: TeamCode/src/main/java/org/firstinspires/ftc/teamcode/components/LiftComponent.java

package org.firstinspires.ftc.teamcode.components;

import com.acmerobotics.dashboard.config.Config;
import com.arcrobotics.ftclib.controller.PIDController;
import com.arcrobotics.ftclib.controller.wpilibcontroller.SimpleMotorFeedforward;
import com.arcrobotics.ftclib.hardware.motors.Motor;

// Old packages that no longer exist for this year, but you can find them in the brightonCollege repository and copy them over if needed.
import org.firstinspires.ftc.teamcode.libs.brightonCollege.motors.BCLibMotor;
import org.firstinspires.ftc.teamcode.libs.brightonCollege.motors.MotorVelocityController;
import org.firstinspires.ftc.teamcode.libs.brightonCollege.motors.TrapezoidalProfile;
import org.firstinspires.ftc.teamcode.libs.brightonCollege.motors.TrapezoidalProfileMotor;

/**
 * Lift with pulleys which lifts to a certain height
 */
@Config
public class LiftComponent {
    /**
     * An enum that contains the possible lift positions
     */
    public enum LiftPosition {
        GROUND(0),
        LOW(1200),
        MIDDLE(2050),
        HIGH(2550);

        private final int counts;
        LiftPosition(int counts) {
            this.counts = counts;
        }

        public double getCounts(){
            return this.counts;
        }
    }
    /**
     * The Core Hex Motor used to move the lift from the bottom
     * Static to allow it being read from the dashboard
     */
    public Motor motor;

    public final static double MAX_TICKS_PER_SECOND = 2000;


    public TrapezoidalProfileMotor trapezoidalProfileMotor;

    /**
     * The number of counts needed to reach the initial position
     */
    private final int initialPositionCounts;

    /**
     * Create a {@code LiftComponent}
     * @param motor The Motor used to move the lift
     */
    public LiftComponent(BCLibMotor motor, LiftPosition initialPosition) {
        MotorVelocityController motorVelocityController = new MotorVelocityController(motor,
                MAX_TICKS_PER_SECOND,
                new PIDController(0, 0, 0),
                new SimpleMotorFeedforward(120, 0.6, 0),
                (counts) -> 170
        );
        trapezoidalProfileMotor = new TrapezoidalProfileMotor(motorVelocityController, new TrapezoidalProfile(MAX_TICKS_PER_SECOND, 3000));
        // Reset the encoder counts to start from the initial position
        motor.resetEncoder();
        initialPositionCounts = initialPosition.counts;

        this.motor = motor;
        setTargetPosition(initialPosition);
    }

    /**
     * Start moving the motor to a given position
     * @param position The desired final position of the arm
     */
    public void setTargetPosition(LiftPosition position) {
        trapezoidalProfileMotor.setTargetPosition(position.counts - initialPositionCounts);
    }

    public void adjustTargetPosition(int changeCounts) {
        trapezoidalProfileMotor.setTargetPosition(this.motor.getCurrentPosition() + changeCounts);
    }

    /**
     * Runs the motor at the given speed in an appropriate mode. Needs to be called every tick
     */
    public void run(){
        trapezoidalProfileMotor.run();
    }
}

Testing Code

  1. Anywhere, when not connected to the robot, click "Build" to check that the code can compile.
1 - Build the project 2 - View the logs
image image
  1. Install the code onto the robot as shown here.

Finally, please make sure you save and upload your changes.

Clone this wiki locally