Creating Complex Custom Widgets for n00bs?

This year for Deep Space 2019, we are researching a co-driver concept where we want the co-driver to read the field and select on a shuffleboard “-esque” widget where we want to place the game piece. I envision there would be a top-down view of the half-map where we need choose the target and “execute” the command. This would essentially rotate the robot and have it start it’s vision routine and game-piece placement

My question, how do i even go about turning a picture of the field into a clickable chooser using shuffleboard.

Preface: check out the shuffleboard wiki and example plugins for instructions and examples on writing a shuffleboard plugin.

RoboRIO Code

I’d have an enum class for the possible target options you can select from (including a ‘null-ish’ value to use if nothing was selected on the dashboard).

public enum Target {
  NONE,
  ROCKET_HATCH_FAR,
  ROCKET_HATCH_NEAR,
  ROCKET_PORT,
  CARGO_HATCH_LEFT_FAR,
  CARGO_HATCH_LEFT_CENTER,
  CARGO_HATCH_LEFT_NEAR,
  CARGO_PORT_LEFT_FAR,
  // ... etc for the other targets
}
NetworkTableEntry targetEntry = Shuffleboard.getTab("Driver")
  .add("Target", "NONE")
  .withWidget("DeepSpaceTargetSelector")
  .getEntry();

// ... elsewhere ...

targetEntry.addListener(notification -> {
  String selected = notification.getEntry().getString("NONE");
  Target target = Target.valueOf(selected);
  // Tell the robot to move to the selected target somehow
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kUpdate);

Shuffleboard Plugin Code

Since this example is sending a String over NetworkTables, the widget has to use the builtin StringType data type - again, interpreting the string as an enum value to select from:

// Maps the String data to an enum value
dataOrDefault.map(Target::valueOf)

You’d have to have the same Target enum class present in both your robot project and in the shuffleboard plugin.

A widget for doing this would most likely have a ResizableImageView to display the half-field image and have it resize to fill as much space as possible in the widget.
I’d place it in a StackPane with a bunch of nodes above it to handle clicking on and highlighting the targets. You’d need to make sure the highlighting nodes are not managed (setManged(false) in code or managed="false' in FXML) so you can manually set their positions in the view. Adding some custom CSS would be nice to differentiate unselected targets from selected ones.

Helpful links

JavaFX documentation
JavaFX CSS reference guide
JavaFX FXML reference guide
Shuffleboard wiki
Shuffleboard example plugin projects

1 Like

On a semi-related note. I am a bit confused as how the custom data types work. I have created a RobotPose datatype which is very similar to the Point2D in the example you gave on the wiki. I also have that datatype on a widget which seems to be working in the preview window.

However, I am confused as to how to actually drag that widget on the shuffleboard. I tried to drag it onto a “double” field property from the network tables, but it didn’t do anything. I also tried dragging it onto nothing, but it wouldn’t let me place it. So, I’m guessing the network table data doesnt make the datatype of the widget. How would I set that up?

Thanks! This definitely helped us out. We noticed a quirky behavior (I’ll post logs if you’re interested).

We created a widget called pathSelector. In robotinit, we do the initial getEntry to add the value using our pathSelector widget to the driver tab

When we deploy code the widget works like a charm. When the robot is turned off and turned on again, the key, value pairs disappear from our shuffleboard sources index but NOT FRC outline viewer. Our only fix for this so far has been restarting robot code 2 -4 times on the field. FTAs get a little miffed that our robot is dancing on the FMS network. Oddly enough we haven’t tried closing shuffleboard and reopening.

I know we have given you sparse details but I’m wondering if this triggers anything in the back of your mind of what could possibly be going wrong.

Update: restarting shuffleboard worked… But it sucks to have to do this every time.