RobotBuilder Created Code

The Layout of a RobotBuilder Generated Project

../../../../../_images/robotbuilder-created-code-1.png ../../../../../_images/robotbuilder-created-code-2.png

A RobotBuilder generated project consists of a package (in Java) or a folder (in C++) for Commands and another for Subsystems. Each command or subsystem object is stored under those containers. At the top level of the project you’ll find the robot main program (Robot.java), the Operator Interface file (OI.java) and the RobotMap that contains the code to create all the subsystem components that were added to the robot description.

Autogenerated Code

// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=REQUIRES
requires(Robot.claw);
// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=REQUIRES
setTimeout(1);
// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=REQUIRES
Requires(Robot::claw);
// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=REQUIRES
SetTimeout(1);

When the robot description is modified and code is re-exported RobotBuilder is designed to not modify any changes you made to the file, thus preserving your code. This makes RobotBuilder a full-lifecycle tool. To know what code is OK to be modified by RobotBuilder, it generates sections that will potentially have to be rewritten delimited with some special comments. These comments are shown in the example above. Don’t add any code within these comment blocks, it will be rewritten next time the project is exported from RobotBuilder.

If code inside one of these blocks must be modified, the comments can be removed, but this will prevent further updates from happening later. In the above example, if the //BEGIN and //END comments were removed, then later another required subsystem was added in RobotBuilder, it would not be generated on that next export.

Main Robot Program

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class Robot extends TimedRobot {    // (1)

    Command autonomousCommand;

    public static OI oi;
    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS
    public static Claw claw;    // (2)
    public static Wrist wrist;
    public static DriveBase driveBase;
    public static Elevator elevator;
    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS

    public void robotInit() {    // (3)
        RobotMap.init();
        // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
        claw = new Claw();
        wrist = new Wrist();
        driveBase = new DriveBase();
        elevator = new Elevator();
        // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS

        oi = new OI();

        // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=AUTONOMOUS
        autonomousCommand = new AutonomousCommand();
        // END AUTOGENERAETED CODE, SOURCE=ROBOTBUILDER ID=AUTONOMOUS
    }

    public void disableInit() {}

    public void disabledPeriodic() {
        Scheduler.getInstance().run();
    }

    public void autonomousInit() {    // (4)
        // Schedule the autonomous command (example)
        if (autonomousCommand != null) autonomousCommand.start();
    }

    public void autonomousPeriodic() {    // (5)
        Scheduler.getInstance().run();
    }

    public void teleopInit() {
        if (autonomousCommand != null) autonomousCommand.cancel();
    }

    public void teleopPeriodic() {
        Scheduler.getInstance().run()
    }

    public void testPeriodic() {    // (6)
        LiveWindow.run()
    }
}
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include "Robot.h"

#include <hal/FRCUsageReporting.h>

#include <frc/Commands/Scheduler.h>
#include <frc/SmartDashboard/SmartDashboard.h>

  // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=INITIALIZATION
std::shared_ptr<Claw> Robot::claw;
std::shared_ptr<Wrist> Robot::wrist;
std::shared_ptr<DriveBase> Robot::driveBase;
std::shared_ptr<Elevator> Robot::elevator;
std::unique_ptr<OI> Robot::oi;
  // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=INITIALIZATION

void Robot::RobotInit() {
  // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
claw.reset(new Claw());
wrist.reset(new Wrist());
driveBase.reset(new DriveBase());
elevator.reset(new Elevator());
  // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
  // This MUST be here. If the OI creates Commands (which it very likely
  // will), constructing it during the construction of CommandBase (from
  // which commands extend), subsystems are not guaranteed to be
  // yet. Thus, their Requires() statements may grab null pointers. Bad
  // news. Don't move it.
  oi.reset(new OI());

  HAL_Report(HALUsageReporting::kResourceType_Framework,
    HALUsageReporting::kFramework_RobotBuilder);

  // Add commands to Autonomous Sendable Chooser
  // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=AUTONOMOUS


  chooser.SetDefaultOption("Autonomous Command", new AutonomousCommand());
  // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=AUTONOMOUS
  frc::SmartDashboard::PutData("Auto Modes", &chooser);
}

/**
 * This function is called when the disabled button is hit.
 * You can use it to reset subsystems before shutting down.
 */
void Robot::DisabledInit(){

}

void Robot::DisabledPeriodic() {
  frc::Scheduler::GetInstance()->Run();
}

void Robot::AutonomousInit() {
  autonomousCommand = chooser.GetSelected();
  if (autonomousCommand != nullptr)
    autonomousCommand->Start();
}

void Robot::AutonomousPeriodic() {
  frc::Scheduler::GetInstance()->Run();
}

void Robot::TeleopInit() {
  // This makes sure that the autonomous stops running when
  // teleop starts running. If you want the autonomous to
  // continue until interrupted by another command, remove
  // these lines or comment it out.
  if (autonomousCommand != nullptr)
    autonomousCommand->Cancel();
}

void Robot::TeleopPeriodic() {
  frc::Scheduler::GetInstance()->Run();
}

#ifndef RUNNING_FRC_TESTS
int main(int argc, char** argv) {
    return frc::StartRobot<Robot>();
}
#endif

This is the main program generated by RobotBuilder. There are a number of parts to this program (highlighted sections):

  1. This class extends TimedRobot. TimedRobot will call your autonomousPeriodic() and teleopPeriodic() methods every 20ms.

  2. Each of the subsystems is declared here. These are public static variables so that they can be referenced from throughout your robot program by writing Robot.<subsystem-name>.method(), for example Robot.elevator.setSetpoint(4).

  3. The subsystems are instantiated in the robotInit() method that is called after the constructor runs for this class. It is important to be create the subsystems after the constructor to avoid recursive loops. Also instance of the OI() class (for your operator interface) and the autonomous command are created here.

  4. In the autonomousInit() method which is called every 20ms, make one scheduling pass. That will call the isFinished() and execute() methods of every command that is currently scheduled.

  5. If there is an autonomous command provided in RobotBuilder robot properties, it is scheduled at the start of autonomous in the autonomousInit() method and canceled at the end of the autonomous period in teleopInit().

  6. In the teleopPeriodic method which is called every 20ms, make one scheduling pass.

RobotMap - Generation of Actuator and Sensor Objects

public class RobotMap {
    public static Jaguar DRIVE_TRAIN_LEFT_MOTOR;    // (1)
    public static Jaguar DRIVE_TRAIN_RIGHT_MOTOR;
    public static RobotDrive DRIVE_TRAIN_ROBOT_DRIVE;
    public static Ultrasonic DRIVE_TRAIN_ULTRASONIC;
    public static Victor ELEVATOR_MOTOR;
    public static AnalogChannel ELEVATOR_POTENTIOMETER;
    public static AnalogChannel WRIST_POTENTIOMETER;
    public static Victor WRIST_MOTOR;
    public static Victor CLAW_MOTOR;

    public static void init() {
        DRIVE_TRAIN_LEFT_MOTOR = new Jaguar(1, 2);
        LiveWindow.addActuator("Drive Train ", "Left Motor", DRIVE_TRAIN_LEFT_MOTOR);

        DRIVE_TRAIN_RIGHT_MOTOR = new Jaguar(1, 2);    // (2)
        LiveWindow.addActuator("Drive Train ", "Right Motor", DRIVE_TRAIN_RIGHT_MOTOR);

        DRIVE_TRAIN_ROBOT_DRIVE = new RobotDrive(DRIVE_TRAIN_LEFT_MOTOR, DRIVE_TRAIN_RIGHT_MOTOR);

        DRIVE_TRAIN_ROBOT_DRIVE.setSafetyEnabled(false);    // (3)
        DRIVE_TRAIN_ROBOT_DRIVE.setExpiration(0.1);
        DRIVE_TRAIN_ROBOT_DRIVE.setSensitivity(0.5);
        DRIVE_TRAIN_ROBOT_DRIVE.setMaxOutput(1.0);

        DRIVE_TRAIN_ULTRASONIC = new Ultrasonic(1, 3);

        ELEVATOR_MOTOR = new Victor(1, 6);
        LiveWindow.addActuator("Elevator ", "Motor", ELEVATOR_MOTOR);

        ELEVATOR_POTENTIOMETER = new AnalogChannel(1, 4);
        LiveWindow.addSensor("Elevator ", "Potentiometer", ELEVATOR_POTENTIOMETER)

        WRIST_POTENTIOMETER = new AnalogChannel(1, 2);
        LiveWindow.addSensor("Wrist ", "Potentiometer", WRIST_POTENTIOMETER)

        WRIST_MOTOR = new Victor(1, 5);
        LiveWindow.addActuator("Wrist ", "Motor", WRIST_MOTOR);

        CLAW_MOTOR = new Victor(1, 7);
        LiveWindow.addActuator("Claw ", "Motor", CLAW_MOTOR);
    }
}

The RobotMap is a mapping from the ports sensors and actuators are wired into to a variable name. This provides flexibility changing wiring, makes checking the wiring easier and significantly reduces the number of magic numbers floating around. All the definitions of sensors and motors from the robot description are generated here.

Notice that each sensor and actuator is added to the LiveWindow class (3) so that the can be automatically displayed when the SmartDashboard is set to LiveWindow mode. Also any properties for the particular sensor or actuator is set here to reflect the settings made in the robot description. (1)

Each of the references for the objects are declared and instantiated here (2, 3), but they are copied into every subsystem to make it easy and clean to write code that uses them.

OI Class - The Operator Interface

public class OI {
    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS
    public JoystickButton joystickButton;
    public JoystickButton joystickButton2;
    public Joystick gamePad;
    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS

    public OI() {
        // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
        gamePad = new Joystick(1);    // (1)

        joystickButton = new JoystickButton(gamePad, 1);    // (2)
        joystickButton.whenPressed(new OpenClaw());
        joystickButton2 = new JoystickButton(gamePad, 2);
        joystickButton2.whenPressed(new CloseClaw());

        // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
    }
}
  OI::OI() {
      // Process operator interface input here.
      // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
  gamePad.reset(new frc::Joystick(1));

  joystickButton2.reset(new frc::JoystickButton(gamePad.get(), 2));
  joystickButton2->WhenPressed(new CloseClaw());
  joystickButton.reset(new frc::JoystickButton(gamePad.get(), 1));
  joystickButton->WhenPressed(new OpenClaw());

      // SmartDashboard Buttons
      frc::SmartDashboard::PutData("CloseClaw", new CloseClaw());
      frc::SmartDashboard::PutData("OpenClaw", new OpenClaw());
      frc::SmartDashboard::PutData("Autonomous Command", new AutonomousCommand());

      // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
  }

  // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=FUNCTIONS

  std::shared_ptr<frc::Joystick> OI::getgamePad() {
     return gamePad;
  }

The code for all the operator interface components is generated here (1). In addition the code to link the OI buttons to commands that should run is also generated here (2).