Simple opmode (walkthrough) - ftc8380/coding-guide GitHub Wiki
Let's take a look at a simple but real opmode, jumping through it together.
The code
package org.firstinspires.ftc.teamcode;
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.hardware.DcMotor;
@TeleOp
public class MattsExample extends OpMode {
private DcMotor myMotor;
@Override
public void init() {
telemetry.addData("Status", "Initialized");
myMotor = hardwareMap.get(DcMotor.class, "my_motor");
}
@Override
public void loop() {
if(gamepad1.dpad_up) {
myMotor.setPower(1.0);
} else if(gamepad1.dpad_down) {
myMotor.setPower(-1.0);
} else {
myMotor.setPower(0);
}
}
}
Can't touch this
package org.firstinspires.ftc.teamcode;
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.hardware.DcMotor;
This stuff gets generated by Android Studio on the fly as you code. Don't mess with it.
Declaring the opmode
@TeleOp
public class MattsExample extends OpMode {
The @TeleOp flag makes it so that our opmode shows up in the driver station under the Teleop section. If this were auto, you would use @Autonomous instead.
You should be familiar with how our own opmodes extend the OpMode class that FIRST gives us.
Declaring our motor
private DcMotor myMotor;
We're making a variable of type DcMotor. The DcMotor class contains a number of methods that we'll use in a sec.
You may notice that we're doing this outside of our methods and instead just in the main body of our opmode. When you declare a variable this way, Java programmers call it an instance variable, and instance variables are basically always preceded by the word private. The reason we're doing this is because both methods need to access it.
Methods have this property called scope where declaring a variable inside a method means that it only exists in that method. I wouldn't want to declare myMotor in our init method, because then I wouldn't be able to use it in loop. What I mean is
- Any variable used by multiple methods must be declared as a private instance variable
init
@Override
public void init() {
Again, we're overriding the default init method with our own. Whatever's in this method will be run once when INIT is pressed.
Telemetry
telemetry.addData("Status", "Initialized");
This prints "Status: Initialized" to the telemetry visible on the driver station. It's basically like printing to the console like you did when you wrote your first hello world program, and it's helpful for debugging.
Registering hardware
myMotor = hardwareMap.get(DcMotor.class, "my_motor");
We talked about myMotor earlier, now let's actually assign it a value. We will access the hardware map and ask it
- Give me the
DcMotornamed "my_motor"
hardwareMap.get() accepts the type of hardware you're getting, and the name. I want a DcMotor, so I pass in DcMotor.class. Net, remember that motors and sensors are given names when you configure your robot, as shown in the Android Studio guide, section 7. That's what "my_motor" represents in this case.
Why couldn't we just do this back when we first declared myMotor out side of the method? Well, the way Java works is that you're just not allowed to start assigning or accessing instance variables outside of a method. :/
loop
@Override
public void loop() {
Remember what this does? That's right - does whatever's in the brackets over and over again after you hit PLAY.
Gamepad
if(gamepad1.dpad_up) {
Unlike motors and sensors, you don't have to register controllers as FIRST just does that automatically. gamepad1 is the gamepad you register with START+A and gamepad2 is the one that uses START+B.
Here we're taking gamepad1 and accessing its dpad_up property, which happens to be a boolean true or false value. Therefore, our if statement will only execute if the DPAD UP button is pressed.
Setting motor power
myMotor.setPower(1.0);
Remember that myMotor is of type DcMotor, and all DcMotors have a setPower method. The method accepts any float value between -1 and 1. 0 for no power, and 1 for full power. Note that for motors, the positive direction is counterclockwise (you can reverse it, but let's not overcomplicate things yet).
Other conditions
} else if(gamepad1.dpad_down) {
myMotor.setPower(-1.0);
} else {
myMotor.setPower(0);
}
At this point, it should be pretty obvious what the else if block is doing, so let me just mention what's in the else. Note that if that else wasn't there, the motors would still spin if you released the buttons! When you set motor power, it keeps that power unless you set it to something else or stop the opmode.