High School

Explore programming Servos.

Understand Servos and how to program them.


Now lets look at using servos to control robot functions. The wheel motors we used in the previous exercises simply run at whatever power level they are set at. Servos are different in that they have a defined range of motion and you control them by setting the location in that range you want the servo to move to. Once in that position, servos resist movement. Servos are typically used for arms and grippers.

Servo positions range from 0 to 1 representing 100% of the servo's range of motion. When you build your robot, you will have to experimentally determine how the position values map to the arm and gripper servos in terms up up/down and open/closed.

Note that there are also continuous servos which run just like regular motors. You set the power and direction and the servo runs in that mode until set to something different.

In this exercise, we will have three servos on our robot, one will raise and lower an arm. In our hardware configuration we name this servo "arm_servo". At the end of the arm is a simple gripper which is opened and closed by a second servo named "grip_servo". The third servo is a continuous servo named "cont_servo". We use buttons on the controller to move the servos. Lets extend our Tank Drive example to operate these servos:

Copy and paste this code into a new OpMode called DriveWithGripper and demonstrate servo control on your robot.
We operate the regular servos by adding or subtracting a small amount to the servo position when a gamepad button is depressed. We have to montior the position and not go over or under the servo min/max. For the continuous servo we just set the power with appropriate sign to rotate the servo in response to the left and right D-pad buttons.
Note that the increment and decrement of the servo position variables show the two different ways to add or subtract with a numeric variable.
Here is more detailed information about servos on the Modern Robotics website.
When you test this code you will see that displaying double or float values may result in a very large number  being displayed due to the nature of these data types in Java. By default, if a double or float has places right of the decimal point, all of those places will be displayed. We can trim that down using the format function of the String class. Here we call String.format(formatstring, variable) where the format string tells Java we will be displaying a floating point number and we only want to show 2 places right of the decimal point. You can comment out the original lines and uncomment the lines with String.format() to see how this works. Finally, addData() has built in support for formatting the message so you don't have to use String.format(). Try all 3 ways. Here is a detailed discussion of formatting variables into strings for output.


Explore adding logging of debugging information to a file on the controller phone and then pulling that file back to the PC for examination.

Add the provided logging utility source code to your project and then understand how to use logging in your programs.


We are now going to take a look at logging (also called tracing) as a tool to debug our robot programs. Logging is recording useful information from the robot program to a disk file on the EV3 controller. You can then download that file to your PC and examine it. It can be very useful to record information while your robot is running during a match so you can look at it afterwards and see what took place. If you have not read the general lesson on Logging, you should do that now.

To get started, we need to get the provided logging code into your robot controller project. In the teamcode package, create a new class called Logging. Click here to open the logging class code. Copy the code and paste it into the new Logging class you just created. This adds the logging class to your project and makes it available for use in your OpModes.

Now we are going to copy the DriveCircleTouch example and add logging to it. Create a new class in the teamcode package called DriveCircleLogging. Copy the code below into that class.

Now lets discuss the changes made to implement logging. We added a constructor method to this class and in that method call Logging.Setup(). This initializes the logging system. We then write a message to the log file with the Logging.log() method. We then added other messages recording the progress of the OpMmode.

The logging class will write the messages to a file called Logging.txt in the top directory of the controller phone. You can use ADB (Android Debug Bridge) to download that file from the phone. Open the terminal window at the bottom of Android Studio. Copy and paste  this command into the terminal window and press enter:

ZTE: adb pull //storage/sdcard0/Logging.txt c:\temp\robot_logging.txt
MOTO G: adb pull sdcard/Logging.txt c:\temp\robot_logging.txt

his will pull the file from the phone into the PC directory specified. You can then view the file with Notepad.

Run the program 3 times, once letting it run the 5 seconds and stop on timeout. Then  run again and press the touch button before the 5 seconds passes. Last, run it and click the Stop button on the Driver Station before time runs out. Then pull the Logging.txt file back to your PC and take a look. It should look like this:

<0>02:43:46:360 DriveCircleLogging.<init>(DriveCircleLogging.java:25): Starting Drive Circle Logging
<1>02:43:46:377 DriveCircleLogging.runOpMode(DriveCircleLogging.java:41): waiting for start
<1>02:43:47:286 DriveCircleLogging.runOpMode(DriveCircleLogging.java:49): running
<1>02:43:53:299 DriveCircleLogging.runOpMode(DriveCircleLogging.java:68): timeout
<1>02:43:53:301 DriveCircleLogging.runOpMode(DriveCircleLogging.java:81): out of while loop
<1>02:43:53:312 DriveCircleLogging.runOpMode(DriveCircleLogging.java:91): stopFlag=true, i=3, d=3.750000
<1>02:43:53:314 DriveCircleLogging.runOpMode(DriveCircleLogging.java:93): done
<0>02:43:54:647 ========================================================================
<0>02:43:54:650 DriveCircleLogging.<init>(DriveCircleLogging.java:25): Starting Drive Circle Logging
<2>02:43:54:662 DriveCircleLogging.runOpMode(DriveCircleLogging.java:41): waiting for start
<2>02:43:55:305 DriveCircleLogging.runOpMode(DriveCircleLogging.java:49): running
<2>02:43:57:456 DriveCircleLogging.runOpMode(DriveCircleLogging.java:74): button touched
<2>02:43:57:464 DriveCircleLogging.runOpMode(DriveCircleLogging.java:81): out of while loop
<2>02:43:57:480 DriveCircleLogging.runOpMode(DriveCircleLogging.java:91): stopFlag=true, i=3, d=3.750000
<2>02:43:57:483 DriveCircleLogging.runOpMode(DriveCircleLogging.java:93): done
<0>02:43:59:727 ========================================================================
<0>02:43:59:733 DriveCircleLogging.<init>(DriveCircleLogging.java:25): Starting Drive Circle Logging
<3>02:43:59:755 DriveCircleLogging.runOpMode(DriveCircleLogging.java:41): waiting for start
<3>02:44:00:937 DriveCircleLogging.runOpMode(DriveCircleLogging.java:49): running

Note the log message that uses format specifiers to merge variable data into the log message. You can read more about formatting here.

One final thing to note. Looking at the trace, we can see that when we pressed the Stop button on the DS, the trace ends immediately and the code after the while block is not executed. Yet it is when we end on timeout or button touch. The reason is that when the Stop button is pressed, the built in controller app code that runs your code throws an exception. That exception stops OpMode execution. This is done to make sure your OpMode does not run after the Stop button is pressed. However, this prevents your code from doing anything after the Stop button is pressed. There might be some clean up or perhaps logging that you would like to do before your OpMode ends. If so, you can run code after the while block by wrapping the while block in a try/catch block:

Catching the exception allows you to execute code after the OpMode has been signaled to stop. Note that if you do this, you are responsible for making sure your OpMode performs no action that could be construed as gaining an advantage in the game and you should make sure your code does end in a timely manner.



Explore using the Touch Sensor device to gather information about the robot's environment.

Understand how to use the Touch  Sensor to gather information about the robot's environment.


Lets look a using sensors by starting with the simple touch sensor. This is simply a button that can be used to signal your code that something has happened by pushing the button. We will add a REV Robotics Touch Sensor to the robot and plug it into digital port 0-1 on the Expansion Hub. We modify our controller phone configuration to identify digital port 1 as a  Rev Touch Sensor and name it touch_sensor. Why did we use port 1 instead of 0? It has to do with the way the ports are wired. More about that here.

We will take the earlier DriveCircle exercise and modify it to use the touch sensor to determine when to stop driving:

Copy and paste this code into a new OpMode class called DriveCircleTouch and demonstrate your robot driving in a circle. It should keep driving until you press the touch sensor button or 5 seconds pass. Note the use of the while loop to run the robot while watching for 5 seconds to pass and also watching for the touch sensor button press. The TouchSensor isPressed() function returns false when not pressed and true when pressed. For us to continue to run while not pressed, we invert the result of the isPressed() function by preceeding it with the ! (invert) operator.

When using the REV Robotics touch sensor, you can also access the sensor as a digital (input) device. Here is the above code sample modified to use the REV sensor as a digital input:

Connecting the touch sensor as a digital input or other digital device to the REV Hub has some nuances. Be sure to read the discussion here.



Explore an example program that uses the Xbox controller to drive in Arcade (one joystick) mode.

Understand driving under joystick control using one joystick to control both motors (Arcade mode).


Lets look at another style of motor control (driving) called arcade. In arcade mode, a single joystick controls both forward/backward motion but also left and right. This allows the robot to be driven with one finger, typically the thumb.

In arcade mode, the joystick y axis controls the forward and reverse motion of the robot. You will need to set both motors to the power level indicated by the y axis deflection. That controls forward and backward motion. So how do we turn? We use the x axis (side to side) deflection to cause the motors to run at different speeds by adding the x value to one motor power level and subtracting the x value from the other motor power level. Here is the code:

Here we are using the x and y axis deflection values from the right joystick only. We combine the x and y values to get the motor power setting. Again, which side is added to and which is subtracted from is determined by your motor gearing which determines the rotation direction of the motor. In our test case negative y axis values make the motors turn in the direction that yields forward motion. Since the joystick x axis returns negative values for left deflection, for a left turn (for example) we subtract the x value from the left motor (minus a minus) yielding a positive value for the left motor (backward) and add a negative yielding a negative value for the right motor (forward). If no y deflection is present, the left motor turns backward and the right forward and the robot spins left. When you add some y deflection the spin turns into an arc.

Arcade driving is more complex to understand and program and more difficult to operate but may make sense for some robots and some drivers.

This sample and the previous one introduces the idle() method which is part of the super class LinearOpMode. When you program a loop as we have here, it is possible and likely for that loop to run without interruption, monopolizing the phone cpu  and causing other parts of the robot controller application, like the part that communicates with the driver station phone for example, to be starved for cpu time and not function. The idle() method interrupts your loop momentarily and allows the other classes in the robot controller app to get some cpu time to perform thier functions before resuming your loop.

Copy and paste this code into a new class called DriveArcade, compile and demonstrate arcade mode driving.



Explore driving the robot with two joysticks (Tank mode) on a controller.

Understand Tank mode driving and using input from two joysticks to drive the robot.


Now lets look at a teleop example. Here we will use the joysticks on one of the Xbox controllers to drive the robot. We will use tank style driving. In tank mode each joystick controls the motor on one side of the robot. Moving the joystick forward or backward will cause the motor on the corresponding side of the robot to turn in that direction and the power level will be determined by how much the joystick is moved off of center. In this mode, to drive straight you have to move each joystick the same amount. Varying the deflection of the joysticks causes the robot to turn. Here is the code:

Here we are using the built-in reference variable for the left gamepad. We are interested in the y axis which is forward and backward.The joysticks return negative values when pushed forward and positive when pushed backward. The test robot also uses negative values to go forward so you can set the motor power directly from the joystick y axis value. If your robot needs positive values to go forward, you would need to reverse the sign of the y axis value.

We also introduce an object in the FTC SDK API, Range. This object exposes a number of static functions (don't need an instance) useful in robot control. Since the motor power level ranges from -1 to +1, we will use the range.clip() function to apply those limits to the right and left values to make sure the input never exceeds the allowed power values. While the values returned from the joystick should never actually exceed the motor power limits, it is good practice to be sure.

Finally, we use the built-in function opModeIsActive() to determine when we should stop the driving loop and exit the program. This function returns true when the OpMode is running and false when stopped.

Copy and paste this code into a new class called DriveTank, compile and demonstrate tank mode driving.

At this point, you are probably getting tired of disconnecting your controller phone from the robot and connecting it to your PC with a USB cable to deploy your code. There is a better way, deploying over WiFi. Check out this lesson.



Instructions on deploying code to the robot controller over WiFi instead of USB cable.

Understand how to deploy code over WiFi.


As you have no doubt learned, deploying code with a USB cable is time consuming and means taking the controller phone off the robot. When you are developing actual robot code, you will be doing this a lot. There is a better way.

You can deploy your code over a WiFi network instead of using a cable. This is much quicker and leaves the controller phone on the robot. Here are the instructions on how to do it using either a WiFi router or WiFi Direct.

With a local area network created by a WiFi router, you can connect your development PC to and the robot controller phone to that network. On the phone, go to Settings, WiFi, and select the local network created by the router and connect to it. You should mark it to automatically connect. After connecting, on the lower right of the available WiFi networks display is a three dot menu. Open it and go to Advanced. Scroll to the bottom looking for the IP Address. This is the address assigned to the phone by the router. This IP address needs to be that same value every time the phone connects. If you see this not happening, you will need to configure the router's DHCP component to assign a fixed IP address to the phone's hardware (MAC) address (shown above the IP address).

When this is done, upload the attached text file (Configure Wireless with ADB.txt) to a location on your development PC. Edit the file to reflect your phone's assigned IP address. Save the file and then rename it to change the extension from .txt to .bat. This will make it an executable command file. You should also create a shortcut to this file on your desktop as you will be running this command file often. Running this command (when connected via USB as discussed below) starts the Android Debug Bridge (ABD) app running on the phone and configures it to provide communication between the phone and your PC over WiFi.

With all this done, you attach the phone to the PC with the USB cable. When the PC has recognized the phone, run the command file. This will enable communication with the phone over the WiFi network using the phone's IP address. When the command file has completed, disconnect the phone and place on the robot. Now, when you compile in AS, the networked controller phone will be available as a deployment target. Compiled code will be sent to the phone over the network connection.

You can also use the WiFi Direct network created by the robot controller phone when the controller app is running instead of a router. On the controller app go to the settings menu and select Program & Manage. On the next screen you will see the name of the network created by the phone. On your development PC, connect to that network name and use the network pass code displayed on the phone. The IP address shown on the phone (without the :8080) should be used in the Configure Wireless with ADB command file. You will still need to connect the phone with a USB cable and run the command file to get ADB running. After that you can disconnect the cable and deploy code over the WiFi Direct connection.


Attached Resource: 


Explore making a robot drive in a circle.

Understand how to make curved turns.


Now lets look at an example that drives the robot in a circle. The key idea here is that if you drive the motors in the same direction but at different power levels (speeds) the robot will drive in an arc and if it runs long enough that arc becomes a circle. Here is the code:

Copy and paste this code into a new OpMode class called DriveCircle and demonstrate your robot driving in a circle. You will need to adjust the power levels and sleep time to complete the circle. The power levels and time will depend on the motor placement and gearing of your robot.



Explore how to make turns in robot code by programming the robot to drive in a square pattern.

Understand how to make the robot turn right angles and how to use time delays.

Now lets expand on the previous example. This OpMode shows changing direction, use of a for loop and time delays to drive in a square pattern by programming only two of the moves needed (drive straight then turn).

Note that the robot steers or changes direction by varying the motor power being applied to each side. If the motors are not turning at the same power level in the same direction, the robot will turn. This is called skid steering.
Copy and paste this code into a new OpMode class called DriveSquare and demonstrate your robot driving in a square. You may need to adjust the sleep times to get accurate 90 degree turns to complete the square. Note that because of the use of the for loop and the code design that moves forward then turns for each of the four parts of the square, the robot will turn one extra time. An exercise for you is to modify the program to eliminate the extra turn.


Explore example code that shows how to drive a robot forward and then stop.

Understand basic motor control and work through an exercise in actually programming a robot.


So lets do some actual robot programming. Assuming you have constructed a simple robot chassis with two DC motors driving two wheels, one on the left and one on the right side of the robot, we will also assume you have configured the controller phone for this hardware and named the motors left_motor and right_motor. Given all this, we can write a simple LinearOpMode to drive the robot forward for 2 seconds and then stop:

Notice the method call rightMotor.setDirection(DCMotor.Direction.REVERSE). Since the motors are on opposite sides of the robot, for both wheels to turn the same direction and generate forward motion, one of the motors must turn in the opposite of its normal direction. Here we select the right motor and reverse the direction of any power setting we give it. Now both motors will turn in the same direction relative to the front of the robot. You may have to experiment to determine which motor should be reversed. Note the use of the enum data type exposed by the DCMotor class: Direction.REVERSE. We could have figured out what constant value to use here to indicate reverse direction but the enum makes it very easy to set the correct value. You can see the other choices by typing a period right after Direction which causes AS to show you the available choices.

Note that if your robot actually drives backwards, you need to reverse the sign of the power value in the SetPower() method calls. SetPower accepts values in the range of -1.0 to +1.0 with 0 being no power. The sign controls the direction, forward or backward. Note that forward and backward are relative to the way you have your motors mounted and what gearing you use to connect the motors to the wheels, not mention the idea of which end of your robot you define as the "front". For each robot you build you will have to experimentally determine the appropriate sign for "forward".
Note the use of the sleep() method. This causes your program to wait (block or delay) for the number of milliseconds specified. 1000 milliseconds equals 1 second. The power settings on your motors will remain in effect during the wait.
Note that after each call to telemetry.addData(), we call telemetry.update(). Update sends any preceeding data added with the addData method to the Driver Station. In Linear OpModes you must call telemetry.update() to send telemetry data to the DS. In regular OpModes, this update is done automatically when the loop() or init_loop() methods end.
You can now go into Android Studio to the ftc_app-master project. Locate the org.firstinspires.ftc.teamcode package node under TeamCode\java in the project navigation pane. Right click on package and select New, then Java Class. Give the class the name DriveForward. This will create a new empty class file in the opmodes directory. Double click that class file to open it in the editor window. Copy all the code above and paste into the class file replacing all of the existing contents.

The OpMode is registered with the FtcRobotContoller app with the @Autonomous annotation before the class name. This categorizes the OpMode as Autonomous and puts it in a group called "Exercises". You can un-comment the @Disabled annotation to remove the OpMode from the list of OpModes that appear on the Driver Station without having to remove the class from the project.

Note the annotation @Overrides on the runOpMode() function. This tells the Java compiler that we intended to have this runOpMode() function replace the function with the same name in the base OpMode class.
Next unplug your controller phone from the robot and plug it into your PC. When the phone is recognized click the green arrow button (top center of the AS menu bar). This will launch the compile and deployment process. You will be prompted to select your phone on a list of deployment targets and approve the download of the program. Two notes: the downloaded program is called an APK in Android parlance, and the first compile you do after starting AS make take some time whereas subsequent compiles should be quick. When the download has completed, the new controller app on your phone should restart.
Now plug the controller phone back into the robot. When the controller and driver station phones have connected and the controller has connected to the robot, you can look at the OpMode list on the driver station app. You should see DriveForwardThenStop in the OpMode list. Select it as the current OpMode. Press Init and then press Start to test your program. Your robot should drive forward for 2 seconds and then stop. You should see the telemetry messages at the bottom of the driver station app.
You can now experiment with different power settings and directions and different amounts of time by changing the program, compiling and deploying to the robot.
Note that in addition to the Java and FTC SDK documentation mentioned earlier, if you have questions about a class or method you can place the cursor over the name of an instance of that class or method and press ctrl-q. This will open a window that will contain any documentation available for the selected item.


Explore how physical robot hardware devices are mapped to names that can be used in programs to access those devices.

Understand robot hardware mapping including controller phone configuration files and how to access hardware devices in software via the mapping scheme.


A key function of the FTC SDK, and of any robotics API, is to provide access to the physical hardware of a robot to the software. A way must be provided to allow programmers to identify, in software, hardware devices on the robot so that they can write programs that interact with that hardware. On the Tetrix/FTC platform, this is called hardware mapping.

Hardware mapping consists of two parts, hardware configuration on the controller phone and hardware mapping in your OpMode class.

When the controller phone is attached to the robot's Core Power Distribution Module, the various control modules and devices plugged into the modules should be recognized by the phone. This is called scanning, and it is performed each time the phone is connected (or the robot is powered on). This set of hardware information is called a configuration. You may have more that one configuration stored on the phone. You access the configuration by clicking the three vertical dots in the upper right corner of the controller app main screen. On the menu, select Settings and then Configure Robot. If you already have one or more configuration files, they will be listed. If you have no configuration files, you will shown a list of the hardware controllers recognized by the controller app.

We will get into the details of the hardware configuration in a moment. Once a configuration has been created, when you are done you click Save Configuration at the bottom of the controller hardware list. This will save the configuration into a file, which you will be prompted to assign a name. After that you will see the list of available configuration files. For each file, you can Edit (change), Activate or Delete. Click Activate to make the selected configuration the current active configuration, which will be displayed in the title bars of each screen. Then use the back button to return to the main screen. The controller will make sure it can reach each controller module in the configuration and if there are no problems, the main screen should display Robot Status as running and Op Mode as Stop Robot, with no error messages below that. The controller is now ready to run the robot.

When editing a hardware configuration you access each controller module and for each hardware device recognized by that module, assign a unique name by which you will access that device in your programs. You can also assign more meaningful names to the controller modules themselves though this is generally not needed. 

When you click on a motor or servo controller, you will see a list of the ports the controller has. You will have plugged motors or servos into these ports when constructing your robot. On the list, check the attached box next to a port if you have attached a device to that port. Then assign a meaningful name to that device. For instance, if you have the motor on the left side of your robot plugged into port 1, you could assign the name left_motor to port 1. This name is what you will use in your OpMode to control that motor. So configuration is all about telling your software which hardware devices (motors, servos, sensors) are on your robot, which port they are plugged into and assigning the device a name by which it will be known in your program.

Here is a lesson that describes the configuation process in more detail.

New for 2017-18 season is the Rev Robotics Expansion Hub. This device replaces the 3 controller modules of the Modern Robotics control scheme. You plug all your motors and sensors into the Expansion Hub(s) (Hubs can be daisy-chained). The process of creating the hardware configuration file on the controller phone is very much the same as with the Modern Robotics modules, but there is just one control module, the Hub. Here is a detailed discussion of creating the hardware configuration file for the Expansion Hub.

Once you have a hardware configuration file defined and active on your controller phone, you can proceed to the software side of hardware mapping.

In order to control your robot, you will need to create objects that control each of your hardware devices and connect the objects to the actual hardware devices. This is done through the hardwareMap static classes. For example, lets say our robot has two DC motors, named left_motor and right_motor in the phone configuration and we want to control them in code:

Here we create two DCMotor type reference variables and then use the hardwareMap.dcMotor static class and call its method get with the names we assigned in our hardware configuration file. The get method creates a DCMotor object and maps it to the appropriate motor controller port and returns a reference to the object into leftMotor or rightMotor reference variables. Now we can control those motors using the various methods available on the DCMotor class like setPower(), which sets the power level of the motor.

This code appears in your OpMode class. The motor definitions typically are at the top of your class. The hardware mapping should occur in your initialization section, either in the init_loop() function of a regular OpMode or before the waitForStart() call in a linear OpMode. The setPower() calls would appear in your loop() method for a regular OpMode or after waitForStart(), to control actual robot movement.

There is a class for every hardware device and the hardwareMap package has subclasses to map every device. You will need to review the FTC API documentation to become familiar with the device classes available and the fields and methods each class has.

In this manner we map all of a robots hardware devices to object instances of the appropriate class. We then use the object instances to interact with the devices.

Note that the OpMode classes (that you extend) provide built-in access to the Xbox controllers through the variables gamepad1 and gamepad2. This means you don't have to do the hardware mapping for the controllers.