Writing a TeleOp program - TeamBEASTFTC/SkyStone GitHub Wiki
Writing your first basic TeleOp program!
Hey all! Are you ready to give your robot some life?
Friendly Note
In this guide, you'll go through the basics of writing a TeleOp program - a TeleOp program is the program which is run which allows for the drivers to control the robot using the gamepads.
For this guide, it will be assumed you already have the HardwareSetup class (our Hardware class) as part of your package
If you have not, feel free to copy it from the teamcode folder, note:
If you are copying our Hardware class, you will have to change the mapping for your hardware!
(The mapping is the connecting of the variables from the phone configuration (of which port has what motors/servo etc.) with the variable for the program to use).
If you all pass that step, let's begin!
Choppy's TeleOp skeleton
@TeleOp(name = "ChoppyTeleOp", group = "Linear Opmode")
public class ChoppyTeleOp extends LinearOpMode {
private ElapsedTime runtime = new ElapsedTime();
HardwareSetup choppy = new HardwareSetup();
// have all your main variables here
@Override
public void runOpMode() {
telemetry.addData("Status", "Initialized");
telemetry.update();
choppy.init(hardwareMap, telemetry, false, false);
// Wait for the game to start (driver presses PLAY)
waitForStart();
runtime.reset();
// run until the end of the match (driver presses STOP)
while (opModeIsActive()) {
telemetry.addData("Status", "Run Time: " + runtime.toString());
telemtry.update();
// Do something!
}
}
}
Phew that's a lot! That's a basic structure or outer shell of what a TeleOp program can look like. You can also do without the runtime - but that's something we've added for niceties (you can cope, don't worry, I believe in you!).
Breaking down the shell
Now let's break it down and build on it to get the robot moving (yeah, I know...it doesn't even move yet!)
@TeleOp(name = "ChoppyTeleOp", group = "Linear Opmode")
If you've read the how to autonomous guide then you would already know what this does. If you've forgotten, that's ok! :)
Basically, the @TeleOp tells the phone this is a TeleOp program. This means it will be displayed with all the other TeleOp programs on the phone and it does not have a count down timer like the Autonomous programs have.
The name = "ChoppyTeleOp"
tells the program what the phone should display as the program's name. As per practice, this is usually the file's name.
The group is a grouping of the programs, again for the phone.
public class ChoppyTeleOp extends LinearOpMode
This line creates a "class" which will be run by the phone when this program is selected. make sure the name, eg ChoppyTeleOp
is the name of your file/class, if you don't Android Studio will let at you until you fix it.
private ElapsedTime runtime = new ElapsedTime();
This line is pretty cool. It creates a timer! To use it, you first reset it like:
runtime.reset();
We do that above too, check it out! Once it is reset, it will start counting... tick, tock, tick...
runtime.toString()
This is the magical line that will save you headaches if you wanna use the timer. It will convert the time into a String format (a format of general text that is not a number or code). This way you can use it with telemetry, check that out too:
telemetry.addData("Status", "Run Time: " + runtime.toString());
telemetry.update();
giving choppy a body!
HardwareSetup choppy = new HardwareSetup();
The infamous choppy command! Let choppy be created!!
I am going to copy some stuff from the how to autonomous guide, so if you've read that, skip ahead while I try and explain this simple one-liner.
What this does is it do a lot of the setup for you. All the code is written within a file called HardwareSetup and you basically get to copy all of it and place it within a variable called choppy (this can be whatever you want it though).
Think of it like you have an infinite amount of toolboxes. You say "hey I want a toolbox", and then you say: "I'll name you choppy".
Within this toolbox there's a lot of tools! Duh...
To use these tools ou need to say choppy.toolName. This is like first saying, "I want that toolbox and then I want to use that tool."
However, these "tools" will require information from you, think of it like giving the tool the batteries it needs to run.
These are called parameters and within Android Studio you should be prompted with what these are. Let's go through a couple of these tools. choppy.init(hardwareMap, telemetry, vuforia_program, driveEncoder) This does the initialisation of the robot's hardware behind the scenes. This does the "mapping" between the variable for each piece of hardware within our code and its corresponding variable we gave it on the phone (the phone variable is where we say: Servo Controller Port 1 = LFoundationHook).
The hardwaremap
is just a variable you pass through.
The telemetry
allows us to do telemetry calls (calls to the phone's screen with text for us to read).
The vuforia_program
is a true or false. So you literally type true or false for this one. This tells the program if it needs to setup the phone's camera for computer vision or not. Leaves this to false if you do not plan on doing computer vision.
The driveEncoder
is just another true/false depending on whether the drive motor encoders have been plugged in or not. If it's set to false the encoder functions will not run.
Giving life to choppy with controls
If you skipped ahead, rejoin now!
while (opModeIsActive()) {}
The magic command you are looking for is this one. Inside these curly brackets is where choppy breaths! Let's dig into what you can do!
Moving motors
Commonly in TeleOp you are not using encoders (if you don't know what those are, don't stress). What I am trying to say is, commonly your motors will be controlled with power being activated or deactivated upon a button being pressed on a gamepad.
Moving a motor
choppy.driveBR.setPower(power);
This black magic tells choppy to turn the Back Right motor by a value of power
this can be any double-digit integer between -1 and 1. Easy right!
Now all we need to do is get feedback from the gamepads to make changes to this power.
Getting feedback from the gamepads
One thing you may notice, there are two gamepads! And guess how you can refer to them within the program...
gamepad1
and gamepad2
Pretty obvious no?? :)
Note: these are not configured within the hardawre class, so you do not need to do choppy.gamepad1
*
Now to access the corresponding buttons you just say (using gamepad1 as an example, but this is the same for gamepad 2):
gamepad1.button_name
So for example, getting if the x button is pressed would be:
gamepad1.x
The a button would be:
gamepad1.a
and so on...
Bumpers
The bumpers names are either right_bumper
or left_bumper
.
The Dpad, the cross with the up, down, right and left which is on the right of the gamepad can be accessed by calling dpad_whicheverDirectionYouWant
. Eg.
gamepad1.dpad_up
will tell me if the up button is pressed on gamepad 1.
Joystick
There are two joysticks on each controller. They are called stick_left
or stick_right
.
Now the joystick is different from## the others. It returns a value from 0-1 depending on where it is.
Imagine a unit circle - that's a circle with a radius of one. Here's one in case you're clueless:
The x and y pair is what can be gained from calling the joystick. How?
Simply add _y
or _x
to which joystick you are using. Eg.
gamepad1.stick_left_y
This would return the y value of gamepad1's left joystick. Pretty cool hey!
Note: the values from the joysticks are flipped, so positive is negative and negative is positive. So just remember to put a negative sign in front of it if you are using the joystick.
eg.
-gamepad1.stick_left_x
For a full list of all the commands and what they return, make sure to check out FTC's official docs.
Using the feedback from the game controllers
Now that we know how to get feedback from our very talented drivers, we have to send that information to the robot so we can score some points!
Simply you would do something similar to:
double servoPower = 0; // should be at the beginning where I said //variable, 0 is a default value here but it can be anything
if (gamepad2.y){
//close servo
servoPower = -0.2;
} else if (gamepad2.x) {
servoPower = 0.7; //vrandom values which simulate the power for closing or opening our servos
//open servo
} else{
servoPower = 0; //if neither of the above buttons are being pressed, what value do you want?
// you do not necessarily need this if you've set the variable's value above your if, as we've done
// it helps readability though
}
choppy.LFoundationHook.setPower(servoPower); //doing something with that value!
Final example
There we go! Want another example? I'll remove the complications with the variable this time and show you how you could use the dpad to move the robot forwards or backwards.
//driving with the dpad
if (gamepad1.dpad_up) {
telemetry.addLine("gamepad1.dpad_down");
telemetry.update();
choppy.driveTR.setPower(1);
choppy.driveTL.setPower(1);
choppy.driveBL.setPower(1);
choppy.driveBR.setPower(1);
} else if (gamepad1.dpad_down) {
telemetry.addLine("gamepad1.dpad_up");
telemetry.update();
choppy.driveTR.setPower(-1);
choppy.driveTL.setPower(-1);
choppy.driveBL.setPower(-1);
choppy.driveBR.setPower(-1);
// please note we are using omni wheels, so this lets us "shuffle"
} else if (gamepad1.dpad_left) {
telemetry.addLine("gamepad1.dpad_left");
telemetry.update();
choppy.driveTR.setPower(1);
choppy.driveTL.setPower(-1);
choppy.driveBL.setPower(1);
choppy.driveBR.setPower(-1);
} else if (gamepad1.dpad_right) {
telemetry.addLine("gamepad1.dpad_right");
telemetry.update();
choppy.driveTR.setPower(-1);
choppy.driveTL.setPower(1);
choppy.driveBL.setPower(-1);
choppy.driveBR.setPower(1);
} else{
// if none of the dpad buttons are being pressed, don't move the robot!
choppy.driveTR.setPower(0);
choppy.driveTL.setPower(0);
choppy.driveBL.setPower(0);
choppy.driveBR.setPower(0);
}
Voila! How does that feel! Feel free to browse any of our files which have the characters TeleOp within its name. They may not all be great, but you might pick something up!
and of course...