diff --git a/src/main/java/frc/team3128/Constants.java b/src/main/java/frc/team3128/Constants.java index 2fef06e..0774c4d 100644 --- a/src/main/java/frc/team3128/Constants.java +++ b/src/main/java/frc/team3128/Constants.java @@ -25,12 +25,6 @@ public class Constants { - public static class ShuffleboardConstants { - public static final int WINDOW_WIDTH = 100; - public static final int WINDOW_HEIGHT = 100; - public static final int SHUFFLEBOARD_TABS = 8; - } - public static class TrajectoryConstants { public static final Rotation2d HEADING = Rotation2d.fromDegrees(180); diff --git a/src/main/java/frc/team3128/autonomous/AutoPrograms.java b/src/main/java/frc/team3128/autonomous/AutoPrograms.java index f7e4185..8d4fa53 100644 --- a/src/main/java/frc/team3128/autonomous/AutoPrograms.java +++ b/src/main/java/frc/team3128/autonomous/AutoPrograms.java @@ -11,8 +11,6 @@ import static frc.team3128.commands.CmdManager.*; -import java.util.function.DoubleSupplier; - /** * Class to store information about autonomous routines. * @author Daniel Wang, Mason Lam @@ -43,7 +41,8 @@ private void initAutoSelector() { } public Command getAutonomousCommand() { - String selectedAutoName = NarwhalDashboard.getSelectedAutoName(); + String selectedAutoName = NarwhalDashboard.getSelectedAutoName(); // Priority to NarwhalDashboard + if (selectedAutoName == null) { selectedAutoName = NAR_Shuffleboard.getSelectedAutoName(); } final Command autoCommand; if (selectedAutoName == null) { diff --git a/src/main/java/frc/team3128/common/utility/NAR_Shuffleboard.java b/src/main/java/frc/team3128/common/utility/NAR_Shuffleboard.java index 2318b6c..571a0b1 100644 --- a/src/main/java/frc/team3128/common/utility/NAR_Shuffleboard.java +++ b/src/main/java/frc/team3128/common/utility/NAR_Shuffleboard.java @@ -1,6 +1,5 @@ package frc.team3128.common.utility; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.function.DoubleSupplier; @@ -10,81 +9,115 @@ import edu.wpi.first.math.controller.PIDController; import edu.wpi.first.networktables.GenericEntry; -import edu.wpi.first.networktables.NetworkTableEntry; import edu.wpi.first.util.sendable.Sendable; -import edu.wpi.first.wpilibj.interfaces.Gyro; import edu.wpi.first.wpilibj.shuffleboard.BuiltInLayouts; -import edu.wpi.first.wpilibj.shuffleboard.BuiltInWidgets; import edu.wpi.first.wpilibj.shuffleboard.ComplexWidget; import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardLayout; import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab; import edu.wpi.first.wpilibj.shuffleboard.SimpleWidget; import edu.wpi.first.wpilibj2.command.SubsystemBase; -import frc.team3128.subsystems.Elevator; -import frc.team3128.subsystems.Manipulator; -import frc.team3128.subsystems.NAR_PIDSubsystem; - -import static frc.team3128.Constants.ShuffleboardConstants.*; /** * Wrapper for {@link Shuffleboard} * @since 2022 RAPID REACT - * @author Mason Lam + * @author Mason Lam, Arav Chadha, Peter Ma */ public class NAR_Shuffleboard { /** * Storage class for NAR_Shuffleboard */ - private static class entryInfo { + private static class widgetInfo { - private GenericEntry m_data; - + private SimpleWidget m_widget; private Supplier m_supply; - - private SimpleWidget m_entry; - + private GenericEntry m_entry; + /** - * Creates a new entry Info + * Creates a new widgetInfo * - * @param entry Widget where the entry + * @param widget widget containing the entry * @param supply supplier updating the entry */ - public entryInfo(SimpleWidget entry, Supplier supply){ + public widgetInfo(SimpleWidget widget, Supplier supply){ + m_widget = widget; m_supply = supply; - m_entry = entry; - m_data = entry.getEntry(); + m_entry = widget.getEntry(); } public void update() { if(m_supply == null) return; - m_data.setValue(m_supply.get()); + m_entry.setValue(m_supply.get()); } } - private static HashMap> tabs = new HashMap>(); - public static HashMap entryPositions = new HashMap(); + private static final int WINDOW_WIDTH = 8; + private static final int WINDOW_HEIGHT = 4; + + private static HashMap> tabs = new HashMap>(); + private static HashMap widgetPositions = new HashMap(); + private static SimpleWidget[] autoWidgets; + private static String[] autoNames; + private static String selectedAutoName; + private static int prevAutoIndex; + /** - * Creates a new tab entry + * Creates a new tab * * @param tabName the title of the new tab */ private static void create_tab(String tabName) { - tabs.put(tabName, new HashMap()); - entryPositions.put(tabName, new boolean[WINDOW_WIDTH][WINDOW_HEIGHT]); // TODO: added this + tabs.put(tabName, new HashMap()); + widgetPositions.put(tabName, new boolean[WINDOW_WIDTH][WINDOW_HEIGHT]); // TODO: added this + } + + /** + * Displays a value in Shuffleboard (Only used for autofill) + * + * @param tabName the title of the tab to select + * @param name the name of the widget + * @param data the value to display + * @return SimpleWidget that can be modified + */ + public static SimpleWidget addData(String tabName, String name, Object data) { + for (int i = 0; i < WINDOW_HEIGHT; i++) { + for (int j = 0; j < WINDOW_WIDTH; j++) { + if (!widgetPositions.get(tabName)[j][i]) return addData(tabName, name, data, j, i, 1, 1); + widgetPositions.get(tabName)[j][i] = true; + } + } + return addData(tabName, name, data, 0, 0, 1, 1); + } + + /** + * Displays a value in Shuffleboard (Only used for autofill) + * + * @param tabName the title of the tab to select + * @param name the name of the widget + * @param supply the value to display + * @return SimpleWidget that can be modified + */ + public static SimpleWidget addData(String tabName, String name, Supplier supply) { + for (int i = 0; i < WINDOW_HEIGHT; i++) { + for (int j = 0; j < WINDOW_WIDTH; j++) { + if (!widgetPositions.get(tabName)[j][i]) return addData(tabName, name, supply, j, i, 1, 1); + widgetPositions.get(tabName)[j][i] = true; + } + } + return addData(tabName, name, supply, 0, 0, 1, 1); } /** * Displays a value in Shuffleboard * * @param tabName the title of the tab to select - * @param name the name of the entry - * @param data value to display - * @param x -coord of the entry starting from 0 - * @param y -coord of the entry starting from 0 - * @return simple widget that can be modified + * @param name the name of the widget + * @param data the value to display + * @param x coord of the widget starting from 0 + * @param y coord of the widget starting from 0 + * @return SimpleWidget that can be modified */ public static SimpleWidget addData(String tabName, String name, Object data, int x, int y) { return addData(tabName, name, data, x, y, 1, 1); @@ -94,11 +127,11 @@ public static SimpleWidget addData(String tabName, String name, Object data, int * Displays an updating value in Shuffleboard * * @param tabName the title of the tab to select - * @param name the name of the entry + * @param name the name of the widget * @param supply object supplier to constantly update value - * @param x -coord of the entry starting from 0 - * @param y -coord of the entry starting from 0 - * @return simple widget that can be modified + * @param x coord of the widget starting from 0 + * @param y coord of the widget starting from 0 + * @return SimpleWidget that can be modified */ public static SimpleWidget addData(String tabName, String name, Supplier supply, int x, int y) { return addData(tabName, name, supply, x, y, 1, 1); @@ -108,12 +141,12 @@ public static SimpleWidget addData(String tabName, String name, Supplier * Displays an updating value in Shuffleboard * * @param tabName the title of the tab to select - * @param name the name of the entry + * @param name the name of the widget * @param supply object supplier to constantly update value - * @param x -coord of the entry starting from 0 - * @param y -coord of the entry starting from 0 - * @param width -of the entry - * @param height -of the entry + * @param x -coord of the widget starting from 0 + * @param y -coord of the widget starting from 0 + * @param width -of the widget + * @param height -of the widget * @return simple widget that can be modified */ public static SimpleWidget addData(String tabName, String name, Supplier supply, int x, int y, int width, int height){ @@ -121,46 +154,45 @@ public static SimpleWidget addData(String tabName, String name, Supplier fillEntryPositions(x,y,width,height, tabName); if(tabs.get(tabName).containsKey(name)) { tabs.get(tabName).get(name).m_supply = supply; - return tabs.get(tabName).get(name).m_entry; + return tabs.get(tabName).get(name).m_widget; } - SimpleWidget entry = Shuffleboard.getTab(tabName).add(name,supply.get()).withPosition(x, y).withSize(width, height); - tabs.get(tabName).put(name, new entryInfo(entry,supply)); - return entry; + SimpleWidget widget = Shuffleboard.getTab(tabName).add(name,supply.get()).withPosition(x, y).withSize(width, height); + tabs.get(tabName).put(name, new widgetInfo(widget,supply)); + return widget; } /** * Displays a value in Shuffleboard * * @param tabName the title of the tab to select - * @param name the name of the entry + * @param name the name of the widget * @param data value to display - * @param x -coord of the entry starting from 0 - * @param y -coord of the entry starting from 0 - * @param width -of the entry - * @param height -of the entry + * @param x -coord of the widget starting from 0 + * @param y -coord of the widget starting from 0 + * @param width -of the widget + * @param height -of the widget * @return simple widget that can be modified */ - public static SimpleWidget addData(String tabName, String name, Object data, int x, int y, int width, int height) { if(!tabs.containsKey(tabName)) create_tab(tabName); fillEntryPositions(x,y,width,height,tabName); if (tabs.get(tabName).containsKey(name)) { - tabs.get(tabName).get(name).m_data.setValue(data); - return tabs.get(tabName).get(name).m_entry; + tabs.get(tabName).get(name).m_entry.setValue(data); + return tabs.get(tabName).get(name).m_widget; } - SimpleWidget entry = Shuffleboard.getTab(tabName).add(name,data).withPosition(x, y).withSize(width,height); - tabs.get(tabName).put(name, new entryInfo(entry,null)); - return entry; + SimpleWidget widget = Shuffleboard.getTab(tabName).add(name,data).withPosition(x, y).withSize(width,height); + tabs.get(tabName).put(name, new widgetInfo(widget,null)); + return widget; } /** * Displays sendable values, like subsystems and command, works on all classes that extend sendable * * @param tabName the title of the tab to select - * @param name the name of the entry + * @param name the name of the widget * @param data sendable value to display - * @param x x-coord of the entry - * @param y y-coord of the entry + * @param x x-coord of the widget + * @param y y-coord of the widget * @return sendable widget that can be modified */ public static ComplexWidget addSendable(String tabName, String name, Sendable data, int x, int y) { @@ -174,10 +206,10 @@ public static ComplexWidget addSendable(String tabName, String name, Sendable da * Displays sendable values, like subsystems and command, works on all classes that extend sendable * * @param tabName the title of the tab to select - * @param name the name of the entry + * @param name the name of the widget * @param data sendable value to display - * @param x x-coord of the entry - * @param y y-coord of the entry + * @param x x-coord of the widget + * @param y y-coord of the widget * @return sendable widget that can be modified */ public static ComplexWidget addSendable(String tabName, String name, Sendable data, int x, int y, int width, int height) { @@ -189,9 +221,21 @@ public static ComplexWidget addSendable(String tabName, String name, Sendable da catch(Exception e) { return null; } - // return addSendable(tabName, name, data, x, y).withSize(width,height); } + /** + * Adds video stream to shuffleboard + * + * @param tabName the title of the tab to select + * @param name the name of the widget + * @param cameraName sendable value to display + * @param URL x-coord of the widget + * @param x coord of the widget + * @param y coord of the widget + * @param width y-coord of the widget + * @param height y-coord of the widget + * @return sendable widget that can be modified + */ public static ComplexWidget addVideoStream(String tabName, String name, String cameraName, String URL, int x, int y, int width, int height) { try { if (!tabs.containsKey(tabName)) create_tab(tabName); @@ -209,30 +253,67 @@ public static ComplexWidget addVideoStream(String tabName, String name, String c } } - public static void addAutos(String[] autoNames) { + /** + * Displays auto paths on Shuffleboard and updates selected auto + * + * @param autos a String array with all auto names + */ + public static void addAutos(String[] autos) { + autoNames = autos; if (!tabs.containsKey("Autos")) create_tab("Autos"); + + autoWidgets = new SimpleWidget[autoNames.length]; ShuffleboardLayout autoLayout = Shuffleboard.getTab("Autos") .getLayout("Auto Names", BuiltInLayouts.kList) - .withSize(2,4); - // .withProperties(Map.of("Label position", "HIDDEN")); - for (int i = 1; i <= autoNames.length; i++) { - autoLayout.add(""+i, autoNames[i-1]); // Shuffleboard doesn't display elements in order of String[] names so we can't use an auto name's index to reference it + .withSize(2, 4) + .withProperties(Map.of("Label position", "HIDDEN")); + + for (int i = 0; i < autoNames.length; i++) { + autoWidgets[i] = autoLayout.add(autoNames[i], false).withWidget("Toggle Button"); + } + addData("Autos", "Auto", ()-> (updateAutoSelection() == null) ? "null" : updateAutoSelection(), 2, 0); // Continuously runs updateAutoSelection() + } + + /** + * Updates selectedAutoName and shuffleboard auto selection layout + * + * @param autos a String array with all auto names + */ + private static String updateAutoSelection() { + boolean isSelected = false; + for (int i = 0; i < autoNames.length; i++) { + if (autoWidgets[i].getEntry().getBoolean(false)) { + isSelected = true; + if (i == prevAutoIndex) { continue; } + if (prevAutoIndex != -1) { autoWidgets[prevAutoIndex].getEntry().setBoolean(false); } + prevAutoIndex = i; + selectedAutoName = autoNames[i]; + } + } + if (!isSelected) { + selectedAutoName = null; + prevAutoIndex = -1; } - // DoubleSupplier autoNumber = NAR_Shuffleboard.debug("Autos", "Selector", -1, 3, 0); - // var autoEntry = NAR_Shuffleboard.addData("Autos", "TOGGLE", false, 2, 0).withWidget("Toggle Button"); // TODO why use var vs SimpleWidget? - // debug = ()-> debugEntry.getEntry().getBoolean(false); - // NAR_Shuffleboard.addData(getName(), "DEBUG", ()-> debug.getAsBoolean(), 2, 1); + return selectedAutoName; } /** - * Creates a debug entry, allows user to edit variable from Shuffleboard + * Gets selectedAutoName + * + */ + public static String getSelectedAutoName() { + return selectedAutoName; + } + + /** + * Creates a debug widget, allows user to edit variable from Shuffleboard * * @param tabName the title of the tab to select - * @param name the name of the entry - * @param Default starting value for the entry - * @param x x-coord of the entry - * @param y y-coord of the entry - * @return DoubleSupplier containing the value in the entry + * @param name the name of the widget + * @param Default starting value for the widget + * @param x x-coord of the widget + * @param y y-coord of the widget + * @return DoubleSupplier containing the value in the widget */ public static DoubleSupplier debug(String tabName, String name, double Default, int x, int y) { if(!tabs.containsKey(tabName)){ @@ -246,8 +327,8 @@ public static DoubleSupplier debug(String tabName, String name, double Default, * Creates a quick PID Tuning setup * * @param tabName the title of the tab to select - * @param name the name of the entry - * @param prefix String that goes before PID entry names + * @param name the name of the widget + * @param prefix String that goes before PID widget names * @return HashMap with keys "KF","KP","KI","KD", and "SETPOINT" */ public static HashMap PID_Setup(String tabName, String prefix) { @@ -261,29 +342,29 @@ public static HashMap PID_Setup(String tabName, String pr } /** - * Get the value from an entry + * Get the value from an widget * * @param tabName the title of the tab to select - * @param name the name of the entry - * @return Object stored in the entry + * @param name the name of the widget + * @return Object stored in the widget */ public static Object getValue(String tabName, String name){ - return tabs.get(tabName).get(name).m_data.get().getValue(); + return tabs.get(tabName).get(name).m_entry.get().getValue(); } /** - * Get the Simple Widget object from an entry + * Get the Simple Widget object from an widget * * @param tabName the title of the tab to select - * @param name the name of the entry - * @return SimpleWidget stored in the entry + * @param name the name of the widget + * @return SimpleWidget stored in the widget */ public static SimpleWidget getEntry(String tabName,String name) { - return tabs.get(tabName).get(name).m_entry; + return tabs.get(tabName).get(name).m_widget; } /** - * Updates every entry + * Updates every widget */ public static void update() { for(String i : tabs.keySet()){ @@ -293,12 +374,21 @@ public static void update() { } } + /** + * Fills widget position array for a given tab + * + * @param x x-coord of the widget + * @param y y-coord of the widget + * @param width width of the widget + * @param height height of the widget + * @param tabName the title of the tab to select + */ private static void fillEntryPositions(int x, int y, int width, int height, String tabName) { if (x + width > WINDOW_WIDTH || y + height > WINDOW_HEIGHT) { throw new IllegalArgumentException("Widget Position Out of Bounds (" + x + "," + y + ") at Tab: " + tabName); } for (int i = x; i < x + width; i++) { for (int j = y; j < y + height; j++) { - if (entryPositions.get(tabName)[i][j]) { throw new IllegalArgumentException("Widget Position Overlapping (" + i + "," + j + ") at Tab: " + tabName); } - entryPositions.get(tabName)[i][j] = true; + if (widgetPositions.get(tabName)[i][j]) { throw new IllegalArgumentException("Widget Position Overlapping (" + i + "," + j + ") at Tab: " + tabName); } + widgetPositions.get(tabName)[i][j] = true; } } } diff --git a/src/main/java/frc/team3128/subsystems/Manipulator.java b/src/main/java/frc/team3128/subsystems/Manipulator.java index e173b86..47f060c 100644 --- a/src/main/java/frc/team3128/subsystems/Manipulator.java +++ b/src/main/java/frc/team3128/subsystems/Manipulator.java @@ -77,12 +77,12 @@ public void initShuffleboard() { NAR_Shuffleboard.addData("Manipulator", "ObjectPresent", ()-> hasObjectPresent(), 2, 0); NAR_Shuffleboard.addVideoStream("Manipulator", "VideoTest", "Gua", "mjpg:http://10.31.28.71:5800/", 0, 1, 3, 3); - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 6; j++) { - final int row = i; - final int col = j; - NAR_Shuffleboard.addData("TESTER", "X: " + i + " Y: " + j, ()-> NAR_Shuffleboard.entryPositions.get("Manipulator")[row][col] == true, i, j); - } - } + // for (int i = 0; i < 8; i++) { + // for (int j = 0; j < 6; j++) { + // final int row = i; + // final int col = j; + // NAR_Shuffleboard.addData("TESTER", "X: " + i + " Y: " + j, ()-> NAR_Shuffleboard.entryPositions.get("Manipulator")[row][col] == true, i, j); + // } + // } } } diff --git a/src/main/java/frc/team3128/subsystems/NAR_PIDSubsystem.java b/src/main/java/frc/team3128/subsystems/NAR_PIDSubsystem.java index 23907ce..181b5f8 100644 --- a/src/main/java/frc/team3128/subsystems/NAR_PIDSubsystem.java +++ b/src/main/java/frc/team3128/subsystems/NAR_PIDSubsystem.java @@ -18,7 +18,7 @@ /** * A subsystem based off of {@link PIDSubsystem} * @since 2023 CHARGED UP - * @author Mason Lam, Arav Chadha, Peter Ma + * @author Mason Lam */ public abstract class NAR_PIDSubsystem extends SubsystemBase { protected final PIDController m_controller; @@ -82,20 +82,9 @@ public void initShuffleboard(double kS, double kV, double kG) { this.kG = NAR_Shuffleboard.debug(getName(), "kG", kG, 3, 2); NAR_Shuffleboard.addData(getName(), "atSetpoint", ()-> atSetpoint(), 0, 2); - NAR_Shuffleboard.addData(getName(), "TestSendable", NAR_Shuffleboard.entryPositions.get(getName())[0][0] == true, 6, 3); // TODO test - pls delete - NAR_Shuffleboard.addData(getName(), "TestData", NAR_Shuffleboard.entryPositions.get(getName())[1][0] == true, 7, 3); // TODO test - pls delete NAR_Shuffleboard.addSendable(getName(), getName(), this, 4, 0); - // Print entryPositions: - // if (getName().equals("Wrist")) { // To ensure this check is done only once - // for (int i = 0; i < 8; i++) { - // for (int j = 0; j < 6; j++) { - // final int row = i; - // final int col = j; - // NAR_Shuffleboard.addData("TESTER", "X: " + i + " Y: " + j, ()-> NAR_Shuffleboard.entryPositions.get("Manipulator")[row][col] == true, i, j); - // } - // } - // } + NAR_Shuffleboard.addData(getName(), "TETS", ()-> getSetpoint()); }