Skip to content

[Tutorial 1.5] Organizing your code

Colby Skeggs edited this page Nov 11, 2015 · 7 revisions

WARNING: THIS DOCUMENTATION IS FOR CCRE v2, NOT CCRE v3!

See the readme on the main page for the correct documentation.

Organizing your code

[Back to the previous tutorial]([Tutorial 1.4] Making your robot shift and use other pneumatics)

Current code

When we last left off, our code looked something like this:

package team1540;

import ccre.channel.BooleanStatus;
import ccre.channel.FloatInputPoll;
import ccre.channel.FloatOutput;
import ccre.ctrl.DriverImpls;
import ccre.igneous.Igneous;
import ccre.igneous.IgneousApplication;
import ccre.log.Logger;

/**
 * This is the core class of a CCRE project. The CCRE launching system will make
 * sure that this class is loaded, and will have set up everything else before
 * loading it. Make sure that main.properties is updated with the correct class
 * name for this to work properly.
 */
public class MyFirstRobot implements IgneousApplication {

    public void setupRobot() {
        // Robot setup code goes here.
        Logger.info("Hello, World!");
        FloatOutput leftDriveMotor = Igneous.makeTalonMotor(0, Igneous.MOTOR_FORWARD, 0.1f);
        FloatOutput rightDriveMotor = Igneous.makeTalonMotor(1, Igneous.MOTOR_FORWARD, 0.1f);
        FloatInputPoll leftDriveStick = Igneous.joystick1.getYChannel();
        FloatInputPoll rightDriveStick = Igneous.joystick2.getYChannel();
        DriverImpls.createSynchTankDriver(Igneous.duringTele, leftDriveStick, rightDriveStick, leftDriveMotor, rightDriveMotor);

        BooleanStatus shifter = new BooleanStatus(Igneous.makeSolenoid(1));
        shifter.setTrueWhen(Igneous.joystick1.getButtonSource(1));
        shifter.setFalseWhen(Igneous.joystick2.getButtonSource(1));
        shifter.toggleWhen(Igneous.joystick1.getButtonSource(2));

        Igneous.usePCMCompressor();
    }
}

Cleaning up

There are some parts of this code that are irrelevant for actual driving, so let's cut those out:

package team1540;

import ccre.channel.BooleanStatus;
import ccre.channel.FloatInputPoll;
import ccre.channel.FloatOutput;
import ccre.ctrl.DriverImpls;
import ccre.igneous.Igneous;
import ccre.igneous.IgneousApplication;

/**
 * This is the core class of a CCRE project. The CCRE launching system will make
 * sure that this class is loaded, and will have set up everything else before
 * loading it. Make sure that main.properties is updated with the correct class
 * name for this to work properly.
 */
public class MyFirstRobot implements IgneousApplication {
    public void setupRobot() {
        FloatOutput leftDriveMotor = Igneous.makeTalonMotor(0, Igneous.MOTOR_FORWARD, 0.1f);
        FloatOutput rightDriveMotor = Igneous.makeTalonMotor(1, Igneous.MOTOR_FORWARD, 0.1f);
        FloatInputPoll leftDriveStick = Igneous.joystick1.getYChannel();
        FloatInputPoll rightDriveStick = Igneous.joystick2.getYChannel();
        DriverImpls.createSynchTankDriver(Igneous.duringTele, leftDriveStick, rightDriveStick, leftDriveMotor, rightDriveMotor);

        BooleanStatus shifter = new BooleanStatus(Igneous.makeSolenoid(1));
        shifter.setTrueWhen(Igneous.joystick1.getButtonSource(1));
        shifter.setFalseWhen(Igneous.joystick2.getButtonSource(1));
        shifter.toggleWhen(Igneous.joystick1.getButtonSource(2));

        Igneous.usePCMCompressor();
    }
}

Making methods

While our code for this simple project is fairly short, we need to split larger projects up to make them more maintainable. One such way to do this is by splitting into multiple methods:

package team1540;

import ccre.channel.BooleanStatus;
import ccre.channel.FloatInputPoll;
import ccre.channel.FloatOutput;
import ccre.ctrl.DriverImpls;
import ccre.igneous.Igneous;
import ccre.igneous.IgneousApplication;

/**
 * This is the core class of a CCRE project. The CCRE launching system will make
 * sure that this class is loaded, and will have set up everything else before
 * loading it. Make sure that main.properties is updated with the correct class
 * name for this to work properly.
 */
public class MyFirstRobot implements IgneousApplication {
    public void setupRobot() {
        setupDriving();
        setupShifting();
        Igneous.usePCMCompressor();
    }

    private void setupDriving() {
        FloatOutput leftDriveMotor = Igneous.makeTalonMotor(0, Igneous.MOTOR_FORWARD, 0.1f);
        FloatOutput rightDriveMotor = Igneous.makeTalonMotor(1, Igneous.MOTOR_FORWARD, 0.1f);
        FloatInputPoll leftDriveStick = Igneous.joystick1.getYChannel();
        FloatInputPoll rightDriveStick = Igneous.joystick2.getYChannel();
        DriverImpls.createSynchTankDriver(Igneous.duringTele, leftDriveStick, rightDriveStick, leftDriveMotor, rightDriveMotor);
    }

    private void setupShifting() {
        BooleanStatus shifter = new BooleanStatus(Igneous.makeSolenoid(1));
        shifter.setTrueWhen(Igneous.joystick1.getButtonSource(1));
        shifter.setFalseWhen(Igneous.joystick2.getButtonSource(1));
        shifter.toggleWhen(Igneous.joystick1.getButtonSource(2));
    }    
}

For small programs, this may seem to make it slightly more complicated, but for larger programs such organization is critical.

In this example, I kept the compressor setup in the main method because it would be only a short single-line method.

Formatting your code

Eclipse comes with an excellent auto-formatting utility. Simply click on Source->Format to format the open file. (Or select the src directory and do the same to format everything.)

All code written by our team, including the CCRE, is formatted with this before going into the main repository. It makes everything consistent and smooths out many irregularities. If you want to use the same formatting settings that the CCRE uses, import the formatting profile CCRE_Formatter_Profile.xml into the workspace's formatting settings.

Minimizing your code

Often, shorter code is better code. This is not always true, but often is.

We can have shorter code by making the setupDriving() method into a single statement:

private void setupDriving() {
    DriverImpls.createSynchTankDriver(Igneous.duringTele,
            Igneous.joystick1.getYChannel(), Igneous.joystick2.getYChannel(),
            Igneous.makeTalonMotor(1, Igneous.MOTOR_FORWARD, 0.1f),
            Igneous.makeTalonMotor(2, Igneous.MOTOR_REVERSE, 0.1f));
}

Some people, myself included, prefer this to having lots of extra variables that are only used once. It's mostly a matter of preference.

Splitting code into multiple files

In even larger projects, such as those for competition robot code, it's important to split code up between multiple files as well as multiple methods. Our 2015 robot code, with approximately 3000 lines of code, was split up into 28 files, most of which are under 100 lines.

For example, you could put driving into its own file. (This is more helpful with longer drive code - such as our 251-line DriveCode.java from our 2015 robot code.)

// DriveCode.java
package team1540;

import ccre.channel.FloatInputPoll;
import ccre.channel.FloatOutput;
import ccre.ctrl.DriverImpls;
import ccre.igneous.Igneous;

public class DriveCode {
    public static void setup() {
        FloatOutput leftDriveMotor = Igneous.makeTalonMotor(1, Igneous.MOTOR_FORWARD, 0.1f);
        FloatOutput rightDriveMotor = Igneous.makeTalonMotor(2, Igneous.MOTOR_REVERSE, 0.1f);
        FloatInputPoll leftDriveStick = Igneous.joystick1.getYChannel();
        FloatInputPoll rightDriveStick = Igneous.joystick2.getYChannel();
        DriverImpls.createSynchTankDriver(Igneous.duringTele, leftDriveStick, rightDriveStick, leftDriveMotor, rightDriveMotor);
    }
}

// Part of MyFirstRobot.java
public void setupRobot() {
    DriveCode.setup();
    setupShifting();
    Igneous.usePCMCompressor();
}

With more complex modules, you may want to consider making the methods virtual instead of static and storing channels within the object.

Next: [Basic Autonomous]([Tutorial 1.6] Basic Autonomous)

Clone this wiki locally