Skip to content

Getting Started

joelg236 edited this page Jun 21, 2013 · 10 revisions

ATALibJ programs start at GamePeriods. The only code inside of GamePeriods that the programmer should write is the constructor. Change the new IterativeRobotAdapter("Null") to a new instance of your robot mode. If you want to implement your own mode choosing mechanism, be careful about modifying GamePeriods.

Writing Robot Modes

There are 6 options for robot modes.

The base interface of all other robot modes. You should use this interface if you will take advantage of every method inside of it. It contains Iterative style methods.

An exception-safe executor of robot modes. You can't extend this class, and it every mode is wrapped in it by default in GamePeriods. There isn't many cases where you would want to use this mode.

The base of an iterative-style robot. Contains init, periodic and end methods for every mode. The init method is called once before starting the mode, the periodic method is called in a periodic loop every 20ms during the mode and the end method is called once at the very end of the mode.

An adapter class that lets you choose which methods you need and implement them in your robot mode. If you are not using every method in IterativeRobot, you should be using this class.

The base of a simple-style robot. Contains one method per mode, and executes it once when the mode starts. Every method should loop until the mode is over, doing whatever is necessary in that mode.

An adapter class that lets you choose which methods you need and implement them in your robot mode. If you are not using every method in SimpleRobot, you should be using this class.

Writing Modules

A Module is an element of the robot that performs a function. It has init(), enable(), disable() and isEnabled() methods. These do pretty much what they describe.

Before writing your module, make sure you're not re-inventing the wheel. Check the edu.first.module package to ensure there is not a module already made for the purpose you need. Almost all wpilibj classes are wrapped as modules, as well as some highly-used controllers like bang-bang.

Structure of a Module

Most modules should be able to take advantage of StandardModule. The only reason why it wouldn't is if you need to extend another class. In that cass, implement Module yourself. Be sure to adhere to the contracts set in its documentation.

Standard Structure

Modules should emulate the structure of the ATALibJ modules. A standard module looks like this:

public class ExampleModule extends Module.StartardModule {

    public void init() {
        // Performs functions to ensure the module can be enabled and functional
    }

    public void enableModule() {
        // Performs functions to allow the module to work
    }

    public void disableModule() {
        // Performs the functions to reverse `enableModule()`
    }

    public void foo() {
        // Use `ensureEnabled()` when the function requires the module to be enabled (manipulates the module)
        ensureEnabled();
    }

    public void changeSetting(double setting) {
        // Changes setting
        // Changing settings of a module should not use `ensureEnabled()` simply because it does not do anything harmful
    }
}

Module contract

The general contract for all modules is as follows:

  • Modules contain methods specific to their purpose, but do not expose their composed instances for security reasons

  • Modules are "ready" to work when init() has been called, and its functions will work after enable() is called.

  • "Settings" of a module, AKA its internal state, are changeable even when disabled.

  • Between calling enable() and disable(), isEnabled() will return true. Only enable() and disable() can effect the output of isEnabled()

  • If a function is called while the module is disabled, the function should throw an IllegalStateException.

  • Calling any of the methods more than once in a row will not behave differently because of it.

  • The state of isEnabled() should be thread-safe and only return true when it is completely enabled.

Writing Subsystems

A Subsystem is a collection of modules that performs some kind of function. A subsystem should perform some kind of action(s) that would be impossible for the individual modules themselves to do. Subsystems are things like "arms", "shooters" and "compressors". They are elements of the robot with multiple components which act together.

Subsystems look like this:

public class ExampleSubsystem extends Subsystem {
    private final ExampleModule module;
    private final ExampleModule module2;

    public ExampleSubsystem(ExampleModule module, ExampleModule module2) {
        super(new Module[] {module, module2});
        this.module = module;
        this.module2 = module2;
    }

    public void foo() {
        module.foo();
        module2.foo();
    }
}

The subsystem combines two ExampleModule instances to perform foo() on both of them. This is an example of the "group" structure for subsystems. Groups take multiple modules and performs functions on all instances.

Modules passed into the constructor of a subsystem are enabled and disabled along with the subsystem. If you have the intention of keeping a module enabled even when the subsystem it is a part of is disabled, usually you should rethink your structure. It is possible to just not pass the module in the constructor, but you should be aware of the risks that come with that. If a module is not disabled along with the subsytem it is a part of, the user has no guarantee about the system's enabled state. That is particularly dangerous if nothing is in place to disable the module. Be sure that you are safe with modules inside of a subsystem.

Writing Controllers

A Controller is a looping virtual mechanism that runs a method at a specific rate. It is useful for things like PID controllers. Controllers should look like this:

public class ExampleController extends Controller {
    public ExampleController() {
        super(0.02, Controller.LoopType.FIXED_RATE);
    }

    public void run() {
        System.out.println(MathUtils.random());
    }
}

Although this is a completely useless controller, it is still valid. It will print a random number every 20ms. In the constructor, double values are considered seconds, and int values are considered hertz.

Some default controllers have already been written in ATALibJ. It's most likely the case that you will use these and never need to write your own controller. They are found here.

Clone this wiki locally