(Re-)Introducing Oblog: Quick, easy, annotation-based Shuffleboard API for Java teams

Build season 2020 is upon us, and I think it’s an excellent time to re-announce my Shuffleboard logging utility, Oblog.

Oblog has been updated for the 2020 season with extensive documentation, and offers teams a clean, powerful, low-overhead way to log their robot telemetry data on Shuffleboard.

Logging a value to shuffleboard is as simple as:

double exampleValue;

No mess, no fuss, almost no code footprint - simply annotate your existing fields (or getters) and watch your data automatically display and update on the dashboard!

Data-binding is also supported:

void setValue(double value) {
  // do whatever you want with the value here

Want to tune your PID loops from the dashboard? No problem! Just slap an annotation on your setter, and off you go.

Oblog supports all the same data types that SmartDashboard supports natively, plus offers additional functionality for extracting loggable values from complex data types.

Oblog additionally can automatically infer a tab/layout structure for your dashboard from the structure of your code - users have no need to manually spend time configuring their dashboard tabs.

As always, feedback, suggestions, and contributions are welcome!


Oblog has been updated to version 3.1.0!

The @Config annotation (and appropriate sub-annotations) now supports extraction of setters for data-binding from complex, non-Loggable types through the methodName and methodTypes parameters:

public class HasSetter {
  void setFoo(double foo) {
    // does whatever
@Config(methodName = "setFoo", methodTypes = {double.class})
HasSetter hasSetter;

The example project has also been updated to be much clearer, and is now almost identical to the WPILib 2020 FrisbeeBot example project.


Hey, we just started using Oblog and have a question:
We have a vision co-processor that sends values through network tables that are not added to Shuffleboard. Is it still possible to receive them in the robot code using Oblog?
If the answer is yes, we have a follow-up question: the values we need are published via a sub-table – is it possible to get them with Oblog that way?
Thank you!

Data binding to arbitrary values on NT is, unfortunately, not supported at the moment. I’ll look into adding an annotation that does this in the future.

If we will “drag” the wanted signals in an existing tab in shuffleboard, do you think it will work?

I very much doubt it; that would only change things on the Shuffleboard side.

OK, thank you!

I don’t understand where the configureLoggingAndConfig should go. In the documentation you say " For a command-based project, it will likely be RobotContainer.java ." but in the example program (command based) you have it in Robot.java. What are the tradeoffs here? Was this done consciously or is this a mistake?

The call will always go in RobotInit(). What varies is what object you pass to it as the rootContainer parameter. The example does, indeed, pass the instance of RobotContainer. Whichever object you pass will serve as the root node of Oblog’s recursive search for loggable containers/widgets.

1 Like

big fan

How does making something persistent work?

For example I have some PID values I want to tune with config. Is there a way to make sure they aren’t lost without changing code?

Oblog is only for logging/data-binding. There’s no way for it to enforce persistent config.

That said, it should not be hard to add a few lines of code to your setter of choice to have it simultaneously push the values to a file on the RIO, which can then be read at startup.

I strongly recommend hard-coding your tuning values once you have determined them, however - persistent adjustable values make it very easy for someone to nudge a value and then forget to change it back.

I think he’s talking about setting the persistent state in networktables, which does exactly what you described for you. https://first.wpi.edu/FRC/roborio/release/docs/java/edu/wpi/first/networktables/NetworkTableEntry.html#setPersistent()

Ah, I had forgotten that feature was added. I could probably add a boolean annotation parameter to enable that - again, though, I advise against using it in practice.

Im thinking of doing a wide scale implementation of this library. If i have my own classes, is the @Log annotation effective, or do they need to extend loggable (and potentially if i want to send them back, Sendable)?

1 Like

Oops sorry for tagging Log…

1 Like

In order for the Logger to see them, if they are not the root container, they must extend Loggable. Note that all the methods in Loggable are defaulted, however, so in the simplest case it’s as easy as simply adding implements Loggable to the class declaration.

If you don’t want to declare a class Loggable and annotate its fields (because, for instance, you may only want to log the output of a single method from it), you can always use the methodName parameter of the @Log annotation to extract a getter from a complex type.

1 Like

Ok thanks!

Is the TalonSRX (or maybe just all CAN motor controllers?) not supported?

If not do you have any recommendations for working with them?

WPI_TalonSRX ought to work. Anything that implements Sendable as a SpeedController would be usable. Looks like Oblarg just copied the docs from the Shuffleboard API, which only lists known implementations in WPILib