Tetrix

Overview: 
Learn about Interfaces which are definitions of the fields and methods implementing classes must expose.
Objectives: 

Understand Interfaces and be able to use them when appropriate.

Content: 

Just as a class is a description of an object, an Interface is a description of a class. An Interface defines the fields (variables) and methods that a class must provide (public access) to users of the class. The Interface does not define how a class derives the value of a field or the result of a method, only that a class that implements an Interface must expose that Interface's fields and methods. As such, the Interface defines a public facing API that the class provides. Interfaces are also called Contracts, in that the Interface defines a contact or agreement (in terms of the fields and methods exposed) between the class and users of the class.

One power of Interfaces is that any class that implements an Interface can be used where ever that Interface is defined as a required data type. This concept is best explained by an example.

A simplifed view of the PIDController class in the FRC library shows a constructor that takes two classes as input, a PIDSource object and a PIDOutput object. PIDSource and PIDOutput are both Interfaces. Digressing for a moment, a simplified PIDController needs two things to perform its function. An input or process control value that will be used by the PIDController to compute an output value, which must be sent to some other class for action. Now in most cases the input value will come from an encoder and the output value will go to a motor. You could define the PIDController class constructor as Public PIDController(Encoder enc, Motor motor). There are two problems with this. First, the PIDController class and the Encoder and Motor classes have not agreed on how data will pass between the Encoder and PIDController class and how data will pass between the PIDController and Motor class. The second issue is that the PIDController as defined will only work with Encoders and Motors. What if we wanted to use some other classes as the input and output objects? Interfaces solve both of these problems.

The simplified PIDController class constructor actually looks like this: Public PIDController(PIDSource source, PIDOutput output). PIDSource and PIDOutput are Interfaces and they define what fields and methods are required for any class that wants to act as a PID source or PID output object. These Interfaces define the contract between the PIDController class and any class wanting to act as a PID source data provider or a PID output data consumer. The example Interfaces look like this:

A class implementing the PIDSource Interface must provide a method defined as double pidGet(). That method must return the current input value to be used by the PIDController. Since any class passed into the PIDController constructor for input must implement the PIDSource Interface, the PIDController now knows what method to call on the source object reference variable to get the input value. For instance, the Encoder class implements PIDSource and as such must provide the method pidGet() along with its other methods. When pidGet() is called, the Encoder returns the current tick count. So an Encoder object can be passed to the PIDController constructor. But so can any other class that implements PIDSource. A class implementing an Interface would look like this:

Any class that implements PIDOuput must provide the pidWrite(double value) method. That method when called, will take the passed value and perform some action with it. The PIDController knows that any class implementing PIDOutput will have  the pidWrite() method and so it knows how to send the output value it has calculated from the input, by calling the pidWrite method on the output object reference variable. The Motor class implements PIDOutput and provides the pidWrite(double value) method and sets it's motor power from the value. So a Motor object can be passed to the PIDController constructor as an output object. But so can any other class that implements PIDOutput.

Classes can implement more than one Interface along with any other fields or methods they wish. Interfaces are very powerful and allow a class expecting an Interface (like PIDController) to work with any number of other classes that implement that Interface.

Note that Interfaces only define the expected fields and methods to be exposed by the implementing class. The actual implementation (code) is contained in the class implementing the Interface.

Like many things in Java (and other languages), this is a basic introduction to Interfaces. There is a lot more to Interfaces which you can read about here. This lesson should be enough to understand Interfaces and use them in your robot code.

 

Navigation:

Interfaces

Just as a class is a description of an object, an Interface is a description of a class. An Interface defines the fields (variables) and methods that a class must provide (public access) to users of the class. The Interface does not define how a class derives the value of a field or the result of a method, only that a class that implements an Interface must expose that Interface's fields and methods. As such, the Interface defines a public facing API that the class provides.

Overview: 
Explore the use of PID controllers to manage motors.
Objectives: 

Understand what a PID controller is and how to use one to control robot motors.

Content: 

With the test robot used to develop this course, there is a problem with the previous examples of turning under gyro or IMU control. When turning at a constant power setting and setting the power to zero when the target angle is reached, depending on motor configuration, gear ratio, robot weight and the turn power, the robot will most likely not stop quick enough to be on the desired angle. This is called overshoot. On our test robot, a 90 degree turn would end up being 110-120 degrees. Fixing this can be tricky to do manually but there is an automated way to better control the turn.

To do this we will use a software routine called a PID controller. PID stands for Proportional, Integral, Derivative. The idea behind a PID controller is to take the desired state value (90 degrees in our turn example), compare that to the actual (feedback) state value (the current gyro or IMU angle) and apply factors to the difference (called the error) that produce a proportional output value. So in our example we start out turning away from zero towards 90 degrees at the full power we specify. As the turn progresses, the angle of turn is fed to the PID controller routine which measures error and produces a value (the turn power) at or near the starting (full) power. As the turn gets closer to 90 degrees, the PID routine starts to return smaller and smaller values thus reducing the power being applied and slowing the rate of turn. In theory this reduction in power and slowing rate of turn will eliminate the overshoot. The PID controller can also apply a tolerance margin that indicates when the actual value is within some percentage of the target to further control robot motors.

A similar example is to use a PID controller to compute the power correction needed to make the robot drive in a straight line. Here the target is zero (gyro not deviating from direction we are traveling) and any change in the measured angle will result in a correction value calculated by the PID controller.

A PID controller can take a lot of tuning to get the desired result but once you get a feel for how they work you can tune them fairly quickly and by using all three of the PID factors you can get quite fine control over motors. 

There are many resources and discussions of PID online. Here, here and here are some resources to start with to investigate PID further. The FIRST forums on programming have extensive discussions of PID in robot applications.

The example below takes the previous DriveAvoidImu example and uses two PID controller instances to manage straight driving and the 90 degree turn on obstacle contact. The PID controller class itself is an inner class inside the example. It would be an obvious candidate to be moved to a utility class.

 

Navigation:

Exercise: Using a PID Controller

With the test robot used to develop this course, there is a problem with the previous examples of turning under gyro or IMU control. When turning at a constant power setting and setting the power to zero when the target angle is reached, depending on motor configuration, gear ratio, robot weight and the turn power, the robot will most likely not stop quick enough to be on the desired angle. This is called overshoot. On our test robot, a 90 degree turn would end up being 110-120 degrees. Fixing this can be tricky to do manually but there is an automated way to better control the turn.

Overview: 
Learn about the REV Hub's built-in IMU or Internal Measuring Unit and how to use it.
Objectives: 

Understand the REV Hub's built-in IMU and how to use it.

Content: 

The REV Expansion Hub has a built-in IMU, or Intertial Measurement Unit. This is a sensor that can measure acceleration (movement) in several axis. It can be used in place of an external gyro. The IMU is not used in quite the same way as the gyro but is similar. Note: you must configure the IMU on I2C channel 0, port 0. Here is the DriveAvoid example converted to use the IMU in place of the MR gyro.

 

Navigation:

Exercise: Using the REV IMU

The REV Expansion Hub has a built-in IMU, or Intertial Measurement Unit. This is a sensor that can measure acceleration (movement) in several axis. It can be used in place of an external gyro. The IMU is not used in quite the same way as the gyro but is similar. Note: you must configure the IMU on I2C channel 0, port 0. Here is the DriveAvoid example converted to use the IMU in place of the MR gyro.

 

Exercise: Using Vuforia - VuMarks

Vuforia is a library of classes included in the FTC SDK that supports using the RC phone camera to locate objects in the cameras field of view and return actionable information to your program. That information may allow your robot to locate and navigate to a visual target, locate an object or recognize images. In this lesson we are focusing on a feature of Vuforia called VuMarks. A VuMark is an image that is like a bar code. Contained in the image is encoded information.

Overview: 
Learn about the Vuforia vision API and how to locate and identify VuMarks.
Objectives: 

Understand of how to use Vuforia to locate VuMarks.

Content: 

Vuforia is a library of classes included in the FTC SDK that supports using the RC phone camera to locate objects in the cameras field of view and return actionable information to your program. That information may allow your robot to locate and navigate to a visual target, locate an object or recognize images. In this lesson we are focusing on a feature of Vuforia called VuMarks. A VuMark is an image that is like a bar code. Contained in the image is encoded information. For instance, in the Relic Revcovery game, the temple images might look identical but each has identifying information (left, right and center) encoded in hexagonal dots. Vuforia can be used to detect the VuMark images when in the camera field of view and read the encoded information and return it to your program. Your program can then determine the relic stacking scheme to gain the most points.

There are several examples in the FTC SDK examples section, but here is a simplified example. This example makes the VuMark finding code generic, meaning it can be used for any VuMark, and puts that code in its own class. This makes the opMode itself simple, it just looks for a VuMark and when found, converts the VuMarks id information to the form (enum) used by the Relic Recovery game. The example also shows X (left/right), Y (up/down) and Z (distance) offsets of the center of the Vumark image in relation to the center of the camera field of view.

 

Navigation:

Overview: 
Learn about timing issues in robotics programming.
Objectives: 

Understand the speed of program execution on a robot and what that means for your program. Understand how to write code that does not fail due to timing issues.

Content: 

When programming robots (or any other real-time system), it is very important to understand how the speed realm of the robot differs from your own. When we look at our robot program, we see the while loop that we use to perform the read-environment/make-decision/act repeating pattern. We tend to think of this loop as happening slowly or at least as we might think of going through these operations.

The reality is that the robot will execute the while loop in our program thousands of times per second. The robot operates much faster than you think. This can lead to bugs in your programs in some situations.

Consider the example code below. The purpose of the program is to perform two actions controlled by the gamepad buttons. The program will count each time your press button A and on each press of button B, toggle a boolean variable from true to false. Download the program in Android Studio and test it on your robot.

So what happened? When you pressed the A button the immediate result is the program counted hundreds or thousands of button presses. Why? Because while the A button press seemed to you to be quick, on the program's time scale the button was down for many repeats of the while loop, and it counted each loop. Same for the B button. The setting of the boolean value bButton seems erratic and definately not a toggle each time the button is pressed. Again, due to the fact that your idea of a button press and the program's idea of a button press are quite different.

What do we do about this? We have to write code to handle this situation and convert the many button presses seen by the while loop into one logical press and act only when the one logical press happends. Here is the example program modified to handle the timing problems:

Download this program into Android studio and try it out. You should see the button presses now handled correctly.

The use of the variables aButtonPressed and bButtonPressed to track the state of the button is called latching.

 

Navigation:

Exercise: Timing Considerations

When programming robots (or any other real-time system), it is very important to understand how the speed realm of the robot differs from your own. When we look at our robot program, we see the while loop that we use to perform the read-environment/make-decision/act repeating pattern. We tend to think of this loop as happening slowly or at least as we might think of going through these operations.

Pages