Skip to content
j-james edited this page Jan 21, 2020 · 2 revisions

Naming Conventions

  • Member variables should be prefixed with a lowercase m, ex. mVariableName.
  • Static member variables should be prefixed with a lowercase s, ex. sVariableName.
  • Any constants or "magic numbers" should go in Constants.java, inside their own subclass.
    • Subclasses divide the Constants file up into manageable sections - subsystems, controls, characterization, etc.
      • This is to simplify both navigation and imports - for why this is helpful, see our 2019 Constants file.
    • The convention for naming these variables is kDescriptorFunction (ex. kWinchId or kFlywheelVelocity), provided they're within a subclass.
    • All Constants must be final.

Code Review

The "code flow" you want to follow goes like this:

Create an actionable Issue ==> Categorize your issue ==> Write code ==> Submit a pull request

Your issues should include a succinct title and a description outlining what you need to do. Once you've created it, please categorize your issue (on the right side) by assigning a milestone, project column, and at least one assignee.

When submitting a pull request, you must do three things (otherwise it will be rejected!):

  1. Verify your code compiles through Gradle - either select Run a command in Gradle in the command palette then enter build, or run ./gradlew build in a terminal.
  2. Run the autoformatter to ensure it complies with Spartronics formatting conventions (four space indent, opening brackets on the same line as the code).
  3. Request review from one of the admins (either a mentor or a student leader).

After you request review on your pull request, the person reviewing will either merge it or request changes. Once you've addressed their requests, you can update your pull request by simply pushing to your fork. Please be sure to close your issue when your pull request is completed.

Subsystem Conventions

  • Public methods within subsystems should be in camelCase, short, and unambiguous. (ex. the Climber subsystem currently contains extend(), retract(), winch(), and stop())
  • Those API methods should be low-level enough to only do a specific functionality, but not low enough to encourage code duplication.
    • For example, a spin(double speed) method is a bad idea for a subsystem - multiple commands will have to set the same value, making modifications difficult. An intake(), reverse(), and stop() methods are much better, as speeds other than the intake and reverse speed won't be used.
    • Along the same vein, an unjam() method is also inappropriate. Unjamming an intake would consist of rapidly reversing and unreversing it, while measuring the voltage drop. A command is better suited for the purpose.
  • A general-functionality stop() method is often useful (not required - but strongly recommended).
  • Accessors (a method that exposes a sensor or another private field) should start with get, ex. getWinchVoltage().
  • logInitialized() should be used, alongside a try/catch statement, to report the state of initialization in the constructor and fail gracefully if any hardware is missing.

Logging

Logging is a very helpful way to diagnose the behavior of your system. Since some of our code runs 50 times each second, you must take care to avoid creating a tsunami of log messages. Not only are they hard to read on the console, but they can actually impact robot performance since they consume network bandwidth. Even if the messages aren't visible in the driver station they may still be impacting performance and stability in a negative fashion. Please follow these guidelines.

  • If you are developing a subsystem, use the Subsystem methods for logging since it prepends your subsystem's name on all logging messages. logDebug() is generally the most valuable for debugging. During competition, the messages will not be generated and won't impact performance. logNotice(), logWarning() and logError() should be used in all cases where we want drivers (and programmers) aware of malfunction.

  • Since you'll be using the standard log message, you don't need to include your subsystem name. So this: logDebug("closing") is preferred over this logDebug("harvester closing")

  • If you are developing outside a Subsystem, you may need to access the Logger directly and invoke its associate level-specific methods. Please make sure to prepend your message text with some prefix that makes it obvious where the message came from.

  • To avoid logging, you can employ SmartDashboard to broadcast/update a state.

  • Logging successful construction, initiation and completion conditions is very helpful for on-the-field diagnoses and since these events are occasional, they don't represent any bandwidth

SmartDashboard

SmartDashboard is a simple and powerful tool to communicate bidirectionally between driver station, roborio and coprocessors like jetson and raspi. As with logging, SmartDashboard traffic consumes bandwidth and when overused can negatively impact robot performance. Some bandwidth-heavy dashboard state is deemed valuable enough to remain active during competition. IMU Heading and Drive Odometry may fall into this category. Since SmartDashboard entries aren't guaranteed to be visible to driverstation, we must remain vigilant and ensure that only the desired traffic is generated.

  • If you are developing a subsystem, please use these methods: dashboardPutString(), dashboardPutNumber() and dashboardPutBoolean() since they prepend the subsytem name following a convenient convention.

  • If your are developing outside a Subsystem, please follow its field-naming convention. Prepend field names with a prefix that signifies the message origin. Our convention is that the prefix follows path-like syntax, MyPrefix/. This makes it easy to go to our Dashboard's NetworkTables page and enter the prefix string into the filter field.

  • SmartDashboard fields become first-class entities when we build a specific presentation for them in our web-based GUI. At this point, names are semi-locked, if you wish to change them you must coordinate the change in both robot and dashboard code concerns. Please use logNotice for all such events. For example, we log the transition into and out of auto and teleop.

Utility functions

There are a number of useful utility functions to help make code more readable and consistent. Here are a few samples:

Fuzzy equality: boolean Util.epsilonEquals(double a, double b, double epsilon)

To compare a target value to a current value with a tolerance for small inaccuracies:

if (Util.epsilonEquals(myPotentiometer.get(), targetValue, .1)) {
    // we're close enough
}

Value clamping: double Util.limit(double val, double min, double max)

To constrain an input value to a legal range of values:

double x = Util.limit(myPotentiometer.get(), .1, .4);