This guide lists C++ coding conventions/recommendations for use with WPILib-based robot programming. It is based on GeoSoft’s, WPILib’s, and conventions previously used in our code.
Conventions are grouped by topic, and each convention has an ID to make it easier to refer to. They are written using this layout:
S#. Short description
Example (if available)
Longer description and reasoning
The terms must, should, and can have special meaning. A must requirement must be followed, a should is a strong recommendation, and a can is a general guideline.
These non-C++ terms will commonly be used throughout the guide:
The goal of these conventions is to improve readability, which increases the maintanibility and quality of our code. Every specific case will not be listed, so use your own discretion. If you think something should look different as it is easier to read, then make it look different.
This section derermines how things should be named inside of code.
Indexer
, DriveLikeACar
speed
, turnRadius
Makes variables easy to distinguish from types.
k
.kMode
, kTurnSpeed
m
.mSpeed
, mDriveLeft
p
.pDriveTrain
, mpDriveTrain
If a member variable is also a pointer, then it should be labeled as both (mp
)
getSpeed()
, drive()
This excludes Initialize
, Execute
, End
, and IsFinished
.
Scratch variables used for temporary storage or indices and are best kept short. (like i
in a loop) A programmer reading it should be able to assume that its value is not used outside of a few lines of code.
This section determines how files should be organized.
MyClass.h
declares the class, MyClass.cpp
defines the class, and MyClass
is the name of the class
commands/intake/LowerIntake
, commands/intake/RaiseIntake
, commands/shooter/StopShooter
This keeps related files together and the commands folder unclutered.
This desction determines how code should be formatted.
void Shooter::toggleServo() {
if (mHoodIn) {
extendServo();
} else {
retractServo();
}
mHoodIn = !mHoodIn;
}
Indentation is used to emphasize the logical structure of the code. Tabs are standardized, more efficent, and can be configured to display at any chosen width.
The use of comments about what the code does should be minimized by making the code self-documenting, like appropriate naming and an explicit logical structure.
However, the code can only tell a reader how the code works. You should also include comments that tell the reader what the code is supposed to do.
if (condition) {
// ...
} else {
// ...
}
if (condition) doSomething();
This makes it clear that the single statement is the only one in the conditional.
a = (b + c) * d;
doSomething(a, b, c, d);
if (condition) {}
for (i = 0; i < 10; i++) {}
// Comment
pObject = *object;
object.a = 2;
b = pObject->b;
std::shared_ptr<NetworkTable> table = nt::NetworkTableInstance::GetDefault().GetTable("limelight");
double x = table->GetNumber("tx", 0.0);
double y = table->GetNumber("ty", 0.0);
double v = table->GetNumber("tv", 0.0);
// Aim only if a target is found
if (tv != 0.0) aimTarget(x, y);
A logical unit is a set of lines of code that fit together logically and contextually. Small units of code can make sense by themselves, but combining them with surrounding code can make it confusing to read. This also allows you to clearly have a comment for a specific unit.
// Related header file
#include "subsystems/Shooter.h"
// Libraries
#include <cmath.h>
#include <ctre/Phoenix.h>
#include <frc/Encoder.h>
// Additional project files
#include "Constants.h"
#include "subsystems/Indexer.h"