Proper shuffleboard widget display help

Hi!

I was wondering how everyone is using 2019 shuffleboard network table entries.

We put all of our code (2 widgets worth) in robotinit. This allows us to make prematch time decisions for sandstorm. Sometimes, however, the network tables entry doesn’t populate at robot init. When we used the .exists() method on the entry we are still getting positive readings.

Our only solution is to restart robo code a couple times and hope it works. This gets the ftas mad at us because our robot status keeps changing in the FMS.

Any help is appreciated.

Can you post relevant code that you’re using? Really you shouldn’t have to do much with the more lower level network tables if you just use the methods in the Shuffleboard class.

Also, as another fix, restarting shuffleboard should work fine as well. I find that it works best especially after altering something on shuffleboard such as a position or removing a widget entirely.

1 Like

The code started off like this:
robotInit()
{
SmartDashboard.PutString(“PathSelected”,"");
}
That yielded intermittent issues where the value could not be found on the sources on shuffleboard.

We then attempted what was found here (FRC website)
public static pathSelector;
robotInit()
{
ShuffleboardTab tab = new Shuffleboard.getTab(“DriveTab”;
pathSelector =
tab.add(“pathSelector”, “”)
.getEntry();
}

This STILL had intermittent issues so we THEN added the following code to robotPeriodic:

robotPeriodic {
if !pathselector.exists()
{
pathSelector =
tab.add(“pathSelector”, “”)
.getEntry();
}

Still no dice. There might be some random coding errors… doing this from memory since I don’t have access to actual code…

For what you want to do, I would use a SendableChooser in that case since it seems like you want to select from options.

If you really do want to have free text input, that’s probably the way to go. I’ll look into some of those methods tomorrow and see if I can help you out.

We created a custom widget that fills this field in. Thanks for taking a look. my guess, is that because this is in robotInit, the robot tries to load values before there is even a network. However, I doubt we can put this anywhere else (we want to be manipulating these settings before, and during the match)

While I would assume the .exists() method should work, maybe try looking at some of the other methods such as .isValid() or .getType() or .getValue() and check for something against those. Maybe even try .getString(null) and if that returns null, then you know that it doesn’t exist.

It seems like you’re doing everything correct, but when I run into a problem like this I just start trying other things to see if that fixes it.

1 Like

The issue persists to today. It’s been so long that I forgot to reply: I found out that the value exists in network tables but shuffleboard has problems finding it. We have to restart shuffleboard and it works…

Can you post your current code? It generally sounds like you are writing to NetworkTables properly, but the code you are using to get the value is only calling it once. When you restart the robot, it sounds like you are getting into a race condition where the pulls what you put/selected in NetworkTables before it gets refreshed on the code reboot.

That’s exactly what seems like it’s happening heres our code (follow the pathSelected variable):

package frc.robot;
 
import com.ctre.phoenix.ILoopable;
 
import edu.wpi.cscore.VideoSource;
import edu.wpi.first.cameraserver.CameraServer;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.networktables.NetworkTableType;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.TimedRobot;
import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.wpilibj.shuffleboard.BuiltInWidgets;
import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard;
import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab;
import frc.robot.CANLed.*;
 
public class Robot extends TimedRobot 
{
 
  public static ShuffleboardTab tab;
  public static DriveTrain driveTrain;
  public static Manipulator manipulator;
  public static Diagnostics diagnostics;
  public static Choosers choosers;
  public static PathChooser pathChooser = new PathChooser();
  public static NetworkTableEntry pathSelected, hatchBallSelected, hatchLeft, hatchRight;
  public static boolean isDeleted = false;
 
  @Override
  public void robotInit() 
  {
    driveTrain = new DriveTrain();
    manipulator = new Manipulator();
    diagnostics = new Diagnostics();
    choosers = new Choosers(driveTrain, manipulator);
 
    tab = Shuffleboard.getTab("driverTab");
    pathSelected = tab.add("PathSelected", "").withWidget("PathSelector").withSize(7,6).withPosition(3, 0).getEntry();
    hatchBallSelected = tab.add("hatchBallSelected","").withWidget("BigButtonsWidget").withSize(3,2).withPosition(0,0).getEntry();
 
    //hatchInBoolean = tab.add("Hatch In",false).withSize(3,2).withPosition(0,3).getEntry();
    hatchLeft = tab.add("Hatch in L", choosers.robotMap.hatchButton.get()).withPosition(11,0).withSize(1,1).withWidget(BuiltInWidgets.kBooleanBox).getEntry();
    hatchRight = tab.add("Hatch in R", choosers.robotMap.dumbHatchButton.get()).withPosition(11,1).withSize(1,1).withWidget(BuiltInWidgets.kBooleanBox).getEntry();
 
    for (ILoopable loop : TaskList.FullList) {
			Schedulers.PeriodicTasks.add(loop);
    }
    
 
  }
  
  @Override
  public void robotPeriodic() 
  {
    
    choosers.letterButtons();
 
    diagnostics.toSmartDashboard();
 
    pathChooser.stringToPath(pathSelected.getString(""));
 
    diagnostics.getForwardMode();
    
    diagnostics.ultrasonicSensorReading(); 
 
    Schedulers.PeriodicTasks.process();
    
    diagnostics.limelightValues();
 
    choosers.updatePath();
    
    choosers.setManipulatorMode();
 
    diagnostics.resetGyro();
 
    hatchRight.setBoolean(choosers.robotMap.hatchButton.get());
    hatchLeft.setBoolean(choosers.robotMap.dumbHatchButton.get());
 
  }

You mentioned you created a custom Shuffleboard widget? What does that code look like?

Does this link work for you?

1 Like

If you don’t need a custom Shuffleboard widget, you can use something like this:

  ShuffleboardTab testTab = Shuffleboard.getTab("TestTab");
  ComplexWidget stringChooser;
  SendableChooser<String> pathList = new SendableChooser<>();

  public void robotInit() {
    // You need at least one default option, otherwise the code will crash when it tries to pull a null string in robotPeriodic();
    pathList.addDefault("Drive Straight", "driveStraight");
    pathList.addOption("Score Cargo Ship Hatch", "scoreCargoShipHatch");

    stringChooser = testTab.add("PathSelected", pathList)
            .withWidget(BuiltInWidgets.kComboBoxChooser)
            .withSize(7,6)
            .withPosition(3, 0);
    testTab.add("hatchBallSelected","")
            .withWidget(BuiltInWidgets.kComboBoxChooser)
            .withSize(3,2)
            .withPosition(0,0)
            .getEntry();
  }

  public void robotPeriodic() {

     pathChooser.stringToPath(pathList.getSelected());
  }

Otherwise, it sounds like your custom widget might not be updating its selected index/value when it changes. See how the official ComboBoxChooserWidget is coded.

Thanks for the reply. I’m not entirely sure it’s a widget thing due to the fact that the string isn’t
even available in shuffleboard to drag and drop.

Oddly enough it’s in the outline viewer.

The only thing different I see about this is we are trying to pull values from shuffleboard rather than push. When we pull values, we first have to create the key in robot init once (and hope that the single push was successful), when we push, we just push periodically push in our periodic methods, making it not a big deal that shuffleboard missed one update.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.