Lesson 1: Motors and the Interative Robot

This lesson will introduce basic motor control, and class instantiation.

Class Setup

First, we need to set up our class so that it gets run by WPILib. You can do that like this:

import edu.wpi.first.wpilibj.IterativeRobot;

public class Lesson extends IterativeRobot {
    @Override
    public void robotInit() {

    }

    @Override
    public void teleopInit() {

    }

    @Override
    public void teleopPeriodic() {

    }
}

In the above code, robotInit will get called once by WPILib, when the robot starts. teleopInit will get called every time teleop starts (there's also a very similar method called autonomousInit; what do you think that does?). teleopPeriodic will get called every time the robot receives a message from the driver station, about every 20 milleseconds, or 50 times per second.

A structure like this will be in every robot you work on (usually the class is called Robot), but on larger codebases you will probably not directly interact with these methods.

Instantiating motors

In this example we're going to be controlling a TalonSRX motor controller, which will drive a motor. This is important to know because that's the motor controller class you have to use.

What do I mean by that? How do you use a motor controller class?

As you may know, we can instantiate (make a new instance, or object) of a class by using the new keyword. A basic example of making a new instance of a TalonSRX and storing it in a variable looks like this:

TalonSRX motor; // Make the variable
motor = new TalonSRX(14); // Instantiate a motor controller object on CAN ID 14

The idea here is that we have a variable which holds an instance of a TalonSRX class, and we have to make a new TalonSRX to put in it. An important piece of this to understand is that TalonSRX takes a parameter in its constructor (a constructor is like a special function that sets up a new instance of a class). This is the 14 in new TalonSRX(14). This 14 is the ID (on the CAN bus) of the motor controller; it's like an address for motors.

Moving motors

Now that we have a variable called motor that holds a TalonSRX object in it, we can call methods on it.

One of these methods is set, which is defined as the following: public void set(ControlMode mode, double outputValue). It sets the output of a motor.

This means that it's a method that other classes can access (public), that returns nothing (void), which takes a ControlMode, and an output value (a double).

If we set our control mode to ControlMode.PercentOutput, and our output value to 0.5, the motor will run at 50% power for as long as we call the set method with those parameters.

This would look like the following:

TalonSRX motor; // Make the variable
motor = new TalonSRX(14); // Instantiate a motor controller object on CAN ID 14
motor.set(ControlMode.PercentOutput, 0.5); // Run the motor at 50%

Putting it into our class

To put this all together, we have to fit it into our existing class.

First we need to instantiate our TalonSRX. We don't want to instantiate it every 20ms in teleopPeriodic, and we don't even want to instantiate it every time teleop starts (teleopInit), so we should put it in robotInit.

That would look like this:

@Override
public void robotInit() {
  TalonSRX motor = new TalonSRX(14);
}

Now we just call motor.set in teleopPeriodic (if we don't call set a lot the motor will stop). Right?

Wrong! How do we access motor in teleopPeriodic if it's only defined in robotInit? You can't... Unless you make it a member variable of your class, which means that all of the class's methods can access it.

That looks like this:

public class Lesson extends IterativeRobot {
  TalonSRX motor;

  // Methods go here
}

All of this together looks like this:

package com.spartronics4915.learnyouarobot;

import edu.wpi.first.wpilibj.IterativeRobot;

import com.ctre.phoenix.motorcontrol.can.TalonSRX;
import com.ctre.phoenix.motorcontrol.ControlMode;

public class Lesson extends IterativeRobot {
    TalonSRX motor;

    @Override
    public void robotInit() {
        motor = new TalonSRX(14); // Motor is CAN ID 14
    }

    @Override
    public void teleopInit() {

    }

    @Override
    public void teleopPeriodic() {
        motor.set(ControlMode.PercentOutput, 0.5); // Run the motor at 50%
    }
}

Extending knowledge

In this section we're going to ask you to do something without giving you the code.

Inverting our motor

Now that we have this set up, what if you want to reverse the output of the motor? You could just change 0.5 to -0.5, but we're lazy. Luckily, there's a method that will do this for us: setInverted. Just call motor.setInverted, and you can reverse the motor's output.

  • Now that you know that, go ahead and invert the motor's output.

Doing it again

What if we have another motor on CAN address 15, and we don't want to invert that motor but we do want to run it at 100%?

  • Go ahead and make a motorTwo variable, and set it to 100% in teleopPeriodic.

Incorporating driver input

How would we make this respond to driver input?

Let's introduce another class: Joystick

As you can see from that javadoc, the signature of Joystick's constructor looks like this

public Joystick(int port)

(This is not a method, which is why there's nothing specifying return type, like void, in the constructor signature)

That means we can instantiate a Joystick object on a port of our choosing. If you don't remember the syntax for instantiating objects, take a look at what we did to instantiate a TalonSRX object above.

There's just two other methods you should know: 1. getY, which gets the joystick's value on the Y-axis (forward and backward). 2. getRawButton, which gets the status of a button. This takes a parameter, so be sure to read the javadoc!

Before you do the following exercises, you will need to import the Joystick class by adding the following line to the top of your file:

import edu.wpi.first.wpilibj.Joystick;
  • Make it so that the first motor's output is based on the value of the joystick's Y-axis. You should instantiate your joystick on port 0.

    • Allow your second motor to be toggled by pressing a button. This means that when you press the button if the motor is on it turns off, and if the motor is off it turns on. You should check the value of button 1.

The above are the most difficult and least guided exercises. Be sure to ask questions and look up things you don't know.

Last updated