-
Notifications
You must be signed in to change notification settings - Fork 2
Usage
- Basic Usage
-
Types of Entries
- Publisher
- Subscriber
- Sendable
-
Entry Configuration
@Key@StructType@UnitConversion@AutoGenerateStruct
-
BadgerLogmethodsputValuegetValueputSendablecreateSelectorFromEnumcreateNetworkTablesButtonremoveNetworkTablesEntry
-
Wrappers
- Value
- Struct Value
- Subtable
- Sendable
- Common Issues
BadgerLog is designed to use annotations to generate custom NetworkTables wrappers that support some additional functionality. Annotations are the preferred method of using BadgerLog.
Some Notes before starting.
- Fields need to be initialized after the constructor
- Fields can not be final
- Fields can have any access modifier (public, private, protected)
- Fields may be either instance, or static fields
-
BadgerLog.updatemust be called in a periodic method. (usuallyRobot.robotPeriodic)
Given this, it is relatively easy to start creating entries.
The base annotation needed to mark a field to have an entry created is the @Entry annotation
Example base usage
@Entry(EntryType.PUBLISHER)
public int basicInteger = 1;Without specifying the key using the @Key annotation, the default is Enclosing Class/Field Name.
In this example, if the class the field was defined in was named ArmSubsystem then the final NetworkTables key would
be ArmSubsystem/basicInteger
The / in the key for NetworkTables specifies that it should use the table within the BadgerLog table named
ArmSubsystem and the entry named basicInteger.
It is also possible to annotate a publisher method with the following requirements.
- The method returns a valid type
- The method has no parameters
Example
@Entry(EntryType.PUBLISHER)
public int getSensorReading(){
return 1; // the sensor value
}This has the same key generation as the field annotation.
In this example, the publisher method is called every update loop and then the value is published to NetworkTables.
There are 3 options to generate entries for NetworkTables. Publishers, Subscribers, and Sendables. They all have different specifications and do different things.
Publisher entries take the value on the field and put it to NetworkTables. Changing the field's value in code, changes
it on NetworkTables.
This can be used with any type of field except those with the value of Sendable
Subscriber entries take the value from NetworkTables and set the field's value to it. Changing the value on NetworkTables changes the field's value.
This can be used with any type of field except those with the value of Sendable and additionally, unlike publishers,
cannot be used with the STRUCT StructType option.
Sendable entries use the defined Sendable.init method to create associated entries and tables. Natively supports using
both publisher and subscriber options.
This can be used with only the Sendable (or subclasses of it) field type.
BadgerLog allows for a high level of customization of each entry. This is done also through annotations, but are always optional and have a global default if missing.
Every (except @Key) annotation can be placed at the class or field level. The class level creates a 'default' configuration for the class. Field level annotations take priority over class level ones for configuration.
(@Key may not be used at the class level because it results in duplicate NetworkTables entries)
The @Key annotation allows for customization of the key used on NetworkTables.
Parameters: String - the key to use. (In the key portion of table/key on NetworkTables)
Changes: Key on NetworkTables
Usage Example
@Entry(EntryType.SUBSCRIBER)
@Key("AutoWaitTime")
public double waitTime = 0;This creates a double entry named AutoWaitTime under the containing classes name.
Using @Key removes the standard generation of the key from the field name
The @Key annotation additionally allows for instance specific values, referencing an instance
variable.
It is in the format of {Field Name}.
Usage Example
@Entry(EntryType.SUBSCRIBER)
@Key("{descriptor}")
public double moduleP = 0;
private String descriptor;
public SwerveModule(/*Other parameters */, String descriptor) {
// Other initialization code
this.descriptor = descriptor;
}The @Table annotation allows for customization of the table above the key used on NetworkTables.
Parameters: String - the table to use above the key. (In the table portion of table/key on NetworkTables)
Changes: Table on NetworkTables
Usage Example
@Entry(EntryType.SUBSCRIBER)
@Table("Auto")
public double waitTime = 0;This creates a double entry under the Auto table named waitTime.
Using @Table removes the standard generation of the table from the containing class
Similar to @Key, the @Table annotation allows for instance specific keys.
It is in the format of {Field Name}.
Usage Example
@Entry(EntryType.SUBSCRIBER)
@Table("Modules:{descriptor}")
public double moduleP = 0;
private String descriptor;
public SwerveModule(/*Other parameters */, String descriptor) {
// Other initialization code
this.descriptor = descriptor;
}This would create a new entry for every instance of the SwerveModule class. The entry would be under the
Modules: with the value of descriptor.
The {Field Name} must match the field name exactly as defined in the class.
Structs are a NetworkTables format for publishing structured data.
The @StructType annotation allows for customization of how a Struct type entry is created.
See Wrappers for an explanation of each type.
Parameters: StructType - the type of struct entry to use
Changes: How a struct entry is created
Usage Example
@Entry(EntryType.PUBLISHER)
@Struct(StructType.STRUCT)
public Rotation2d rotation2d = Rotation2d.fromDegrees(1306);This would publish the struct as a value-struct, using the default NetworkTables implementation of the StructEntry.
This could be changed to StructOptions.SUB_TABLE for subtable publishing or StructOptions.MAPPING for mapping
publishing.
The @UnitConversion annotation allows units to be converted to a different form of the same unit.
Parameters:
-
String- the unit to convert to -
String converterId- (Optional) the id of the converter to use with a mapping. Defaults empty
Usage Example
@Entry(EntryType.PUBLISHER)
@UnitConversion("meters")
public Distance height = Inches.of(10);This publishes a double entry of the height converted to meters. Subscribing works the same way but in reverse. The unit
String can be any form of the unit, case-insensitive.
// These all work
@UnitConversion("m")
@UnitConversion("meter")
@UnitConversion("METERS")
@UnitConversion("M")The @UnitConversion annotation also allows for itself to be placed multiple times on a field to specify the converters
to use for a more complicated mapping. Examples include Pose2d, Pose3d, Twist2d, and Twist3d.
The converterId is always translation for distance types and rotation for rotation types. It is only ever used
when there are more than one unit to convert at a time.
Usage Example
@Entry(EntryType.SUBSCRIBER)
@UnitConversion(value = "in", converterId = "translation")
@UnitConversion(value = "radian", converterId = "rotation")
public Pose2d robotPose = Pose2d.kZero;This converts any distance to inches and any rotation to radians in the Pose2d
The @AutoGenerateStruct annotation allows a struct to be generated from a record or enum class.
It is used as a marker for BadgerLog to use the generated struct instead of a mapping.
Parameters: boolean (Optional) whether to generate the struct or not. Defaults true
Changes: Marks the field to have a struct auto generated for it
Usage Example
@Entry(EntryType.SUBSCRIBER)
@AutoGenerateStruct
public CustomRecord record = new CustomRecord("value", 3);
public record CustomRecord(String value, int count) {
}This will automatically generate a struct for this, allowing it to be used with BadgerLog's struct publishing options.
BadgerLog provides a bunch of utility methods to allow for some unique interactions with NetworkTables.
The putValue method acts similarly to the EntryType.PUBLISHER for annotations. The only difference is that it
doesn't automatically generate the configuration from annotations. Useful for one time logging of specific fields,
but not recommended.
Usage Example
public void execute() {
BadgerLog.putValue("MoveArmCommand/Current Draw", /* the current draw */);
BadgerLog.putValue("MoveArmCommand/Arm Angle", /* the current angle */,
new Configuration().withConverter("", UnitConversion.createConverter("degrees")));
}The getValue method acts similarly to the EntryType.SUBSCRIBER for annotations. The only difference is that it
doesn't automatically generate the configuration from annotations. Useful for one time retrieving of specific keys,
but not recommended.
Usage Example
public void periodic() {
int kG = BadgerLog.getValue("Arm/kG", /* the initial value */);
int targetRotation = BadgerLog.getValue("Arm/Target Rotation", /* initial rotation */,
new Configuration().withStructType(StructType.SUBTABLE));
}The putSendable method acts similarly to the EntryType.SENDABLE for annotations. There is almost no difference in
its use, except that it allows for publishing a Sendable within a method. putSendable should not be called for the same key twice.
Usage Example
private Field2d field2d = new Field2d();
public void initializeOdometry() {
field2d.setRobotPose(/* pose data */);
BadgerLog.putSendable("Field2d", field2d);
}The createSelectorFromEnum method allows an enum's constants to be published as a SendableChooser. It takes the name
of each constant, and publishes it as a string.
By default, it will use the first constant defined in the Enum class, but can be specified with the method
overload.
public Robot() {
BadgerLog.createSelectorFromEnum("Robot/RobotModeSelector", RobotMode.class, RobotMode.AUTOMATIC,
(value) -> /* on changed */
);
}
public enum RobotMode {
MANUAL,
AUTOMATIC,
DISABLED
}The createNetworkTablesButton method allows a Trigger to be bound to a boolean on NetworkTables. The
createAutoResettingButton is similar, but resets back to false after being true for 0.25 seconds.
A special requirement of both methods: it cannot be called more than once with the same key
public Autos() {
BadgerLog.createNetworkTablesButton("Auto/IgnoreWaitTime", CommandScheduler.getInstance().getDefaultButtonLoop())
.onTrue(/* some command */);
BadgerLog.createAutoResettingButton("Auto/ResetOdometry", CommandScheduler.getInstance().getDefaultButtonLoop())
.onTrue(/* some command */);
}The removeNetworkTablesEntry method allows for the unpublishing of an entry. It removes the entry completely from
updating and NetworkTables.
BadgerLog contains wrappers around NetworkTables entries to enable more customization and features.
Defined by ValueEntry. Enables the use of the mapping system, allows the conversion of any type into a valid
NetworkTables type.
Defined by StructValueEntry. Publishes the struct as is, using the NetworkTables struct implementation.
Does not work with Elastic (Support for structs doesn't exist).
Defined by SubtableEntry. Generates every entry needed to create a struct-like view. Creates relative tables for each
field defined in the struct.
Defined by SendableEntry. Registers the Sendable with the SendableRegistry and updates it.
Likely is a cause of some other issue, check the warnings in the console.
The configuration was invalidated. Caused by some other issue.
A key referencing an instance field was wrong. Check that the key matches the field's name exactly.
A field was final when it cannot be. Remove the final modifier
A field was not initialized after startup. Make sure the field is either initialized in the constructor or when the field is defined.
The struct references an invalid type. Check the struct's schema.
The schema referenced something that was not expected. Check the schema
Known issue with autogenerated structs for enums. They can only be published using the STRUCT publishing option
The default converter should not be used with multiple converters. Make sure each converter is defined.
The unit specified in the converter doesn't exist in any form. Change it to a known form of the unit.
The unit converter doesn't match the id defined in the mapping. Only 2 used are translation and rotation.
Recursive records are not supported.
The type doesn't have an associated mapping with it. Either change the type, or create a mapping for it.
Known issue with the STRUCT type. Switch to the SUB_TABLE type for it to work.
Make sure the type of the field/method value matches the type you want.
Common mistake
// wrong (long type)
double value = BadgerLog.getValue("key", 0);
// correct (double type)
double value = BadgerLog.getValue("key", 0.0);
double value = BadgerLog.getValue("key", 0D);Javadoc can be found on Jitpack