← Neuron Pathing

Subsystems & Public Methods

Neuron Pathing only knows about driving and following paths. Everything else on your robot (an intake, a shooter, an arm, a claw) is a subsystem: a small class that owns one mechanism's hardware, and a handful of methods you call from your OpModes. This page is the pattern for writing those, and for calling their public methods directly from both TeleOp and Autonomous alongside NeuronDrive.

This repo doesn't use a command-scheduler framework (like FTCLib's CommandScheduler); you just call a subsystem's public methods directly, in whatever order your OpMode needs. That's simpler to reason about for a first robot, and it's exactly the pattern NeuronDrive itself already follows. If your robot grows complex enough that manual sequencing gets unwieldy, a command-scheduler library is a reasonable next step, but start here.

Writing a subsystem

See TeamCode/.../subsystems/ExampleClaw.java for a working copy of this shape:

public class ExampleClaw {
    public enum State { OPEN, CLOSED }

    private final Servo servo;
    public State state = State.CLOSED;

    public ExampleClaw(HardwareMap hwMap, String servoName) {
        servo = hwMap.get(Servo.class, servoName);
        close();
    }

    public void open()  { servo.setPosition(OPEN_POS);  state = State.OPEN; }
    public void close() { servo.setPosition(CLOSED_POS); state = State.CLOSED; }
    public void toggle() { if (state == State.OPEN) close(); else open(); }

    public void update() { /* PID, timed sequence, telemetry (see below) */ }
}

The rules that make this pattern work:

Using subsystems in TeleOp

Construct every subsystem once, before waitForStart(), next to drive/localizer. Then in the loop: read gamepad buttons, call the matching subsystem method, and call update() on everything. See NeuronTeleOp.java:

NeuronDrive drive = new NeuronDrive(hardwareMap, localizer, trackWidthIn);
ExampleClaw claw = new ExampleClaw(hardwareMap);

waitForStart();
while (opModeIsActive()) {
    drive.drive(gamepad1);
    drive.update();

    if (gamepad1.aWasPressed()) claw.toggle();   // edge-detected: fires once per press
    claw.update();

    telemetry.addData("claw", claw.state);
    telemetry.update();
}

Use *WasPressed() (e.g. gamepad1.aWasPressed()) for anything that should fire once per button press, not once per loop iteration for the whole time it's held down.

Using subsystems in Autonomous

Subsystem calls just sit in the same sequence as your drive calls, in whatever order the auto needs. The only wrinkle: a move like drive.splineToPoint(...) doesn't block, so follow it with driveToTarget() (or call claw.update() inside your own wait loop) so subsystems that need per-loop updates keep running while the robot drives. See NeuronSplineAuto.java:

drive.splineToPoint(new Pose2D(24, 24, Math.toRadians(90)), false, false, 1, 0.8);
driveToTarget();          // blocks until the move finishes, still calling claw.update()

claw.open();
waitMs(300);              // a dwell, also still calling claw.update()

drive.goToPoint(new Pose2D(24, 0, 0), false, 0.6);
driveToTarget();

claw.close();

driveToTarget() and waitMs() are small private helper methods defined at the bottom of the OpMode (loop calling drive.update()/claw.update() until the move finishes or the timer's up). This is exactly what the Neuron Path Planner's "Full OpMode" output generates for you automatically. If you're pasting planner output into your own OpMode, copy these two helpers over once and every generated auto will compile against them.

Wiring your subsystem into the planner

The planner's shooter-pipeline actions (shoot/intake/gate/turret) are just this pattern, generated as text. To add your own subsystem as a quick-add action in the planner, open tools/neuron-path-planner.html and add an entry to const ACTIONS near the top of the <script> block, following the same shape as the existing entries; see the comment directly above it for the exact format.

← Tuning Troubleshooting →