-
Notifications
You must be signed in to change notification settings - Fork 3
Tutorial 01: Getting the robot to drive
Getting the robot to drive is the FRC equivalent of "hello world." For now, I'll focus on getting things up and running, and getting familiar with how a project is laid out, without sweating what every last bit of syntax means. Once we're comfortable with that, we can look at how things work in general. If I reference a term or idea that I don't expect you to know, I'll say "whatever that means" to let you know.
If you haven't already, clone the quickstart project. Compile it and make sure you can deploy it to the robot. You'll know it's working when... absolutely nothing happens. Ok, but make sure you at least aren't getting any error messages yet.
In this project, look in the src
directory, in the
org.usfirst.frc.team69.robot
package. There are three files
already:
-
Robot.java
: This is the "main file" of the project. Unlike in a desktop program, you don't have to write amain()
method. Instead, you override the methods inRobot
. You won't be messing with this file much, except for when you need to add a new subsystem (whatever that means). -
OIMap.java
: OI stands for "Operator Interface." This file describes how joysticks and buttons are layed out. As of right now, it should be empty, save for a few comments. -
RobotMap.java
: This file lists what hardware is connected to the robot, and what port everything is on. This should also be empty.
To get the robot to drive, we need to do a few distinct things:
- Tell the code about the motors (what ports? what kinds?)
- Tell the code about the joysticks (what ports? what kinds?)
- Create a subsystem (whatever that means), consisting of the drive motors.
- Create a command (whatever that means), which checks the value of the joysticks and sets the speed of the motors accordingly.
- Set the command we created to always run.
If this seems like a lot, don't worry! This is on the level of "to make a peanut butter and jelly sandwitch, you need to open the jar, then stick the knife in, then scoop some peanut butter onto the knife, and so on."
You might need to ask someone for help with this. It could be four distinct ports for each wheel, or it could just be two, for left/right. Even if there are four motors, and four speed controllers, we may use a "Y" PWM cable, to control it from just two ports on the robot.
In RobotMap.java
, add the following code (adjusting for what you
found in step 0, of course):
public class Robot {
public static class Drive {
@Port(type = Type.PWM) public static final int LEFT_MOTOR = 0;
@Port(type = Type.PWM) public static final int RIGHT_MOTOR = 1;
}
}
If you're not used to putting classes in classes, or annotations like
@Port
, fear not! This file is just a big list of constants. The
nested classes are just to organize things, like folders on your hard
drive.
Also, after this paragraph, I'm not going to mention import
statements, but they are something you need. In Eclipse, Ctrl-Shift-O
will automatically set the imports to what they need to be. Get in
the habit of doing this frequently.
Now head over to OIMap.java
, and add the following code:
public class OIMap {
@MapJoystick(port = 0, role = Role.LEFT_DRIVER, type = Type.LOGITECH_2_AXIS)
public static class LeftDriver {
}
@MapJoystick(port = 1, role = Role.RIGHT_DRIVER, type = Type.LOGITECH_2_AXIS)
public static class RightDriver {
}
}
Again, the numbers you put for port, and the value of type, may differ, depending on your situation.
Create a new class, DriveSubsystem
, in the
org.usfirst.frc.team69.robot.subsystems
package. This class should
extend subsystem. Add some objects corresponding to the motors on the
drivetrain. The exact class depends on the type of motors you're
using. Add a RobotDrive
object as well. For example, if I've got
two VictorSP's:
public class DriveSubsystem extends Subsystem {
private VictorSP leftMotor = new VictorSP(RobotMap.Drive.LEFT_MOTOR);
private VictorSP rightMotor = new VictorSP(RobotMap.Drive.RIGHT_MOTOR);
private RobotDrive robotDrive = new RobotDrive(leftMotor, rightMotor);
@Override
protected void initDefaultCommand() {
// TODO Auto-generated method stub
}
}
(Pro tip: checking "inherited abstract methods" in Eclipse will do some of this for you.)
We made a new class, but a class is no good without an instance of it
somewhere. Add a static instance to Robot.java
:
public class Robot extends HYPERRobot {
public static DriveSubsystem drive;
@Override
protected void initSubsystems() {
drive = new DriveSubsystem();
}
// ... other stuff not shown ...
}
Head back over to DriveSubsystem.java
, and add the following
wacky-looking method:
public Command driveCmd() {
return QuickCommand.continuous(this, () -> {
robotDrive.tankDrive(Robot.oi.leftDriver(), Robot.oi.rightDriver());
});
}
Without going into too much detail, we can see this method returns
something of type Command
(but I haven't told you what that is
yet). Writing () -> { ... }
lets me pass a block of code as an
argument. The QuickCommand.continuous
method takes a block of code,
and returns a Command
that says "keep running this over and over, as
long as you can". Inside this block, we use the robotDrive
variable
we made earlier. We read the current state of the joysticks, and set
the motors accordingly.
This looks awkward, but is actually a pretty common pattern for us. If you've ever programmed something with a user interface before, you may have seen something like (made up code incoming):
myButton.whenClicked(() -> { System.out.println("I've been clicked!"); });
We're almost there! We just need to set the drive command to always
run. Remember that initDefaultCommand()
method that Eclipse
generated for us? Let's fill that in:
@Override
protected void initDefaultCommand() {
setDefaultCommand(driveCmd());
}
Hit compile and admire your hard work. Make sure to run on blocks first, so you don't destroy someone else's hard work!