SmartDashboard telemetry upload method?

Heyo,

I’m trying to program a Limelight camera for my team’s robot. I have programmed some telemetry that the robot should be able to access. The only issue is that, being new to FRC and robotics programming in general, I have no idea how to call the methods that would extract the data from the robot and upload them to the SmartDashboard.

If anyone else has done a vision system that uploads telemetry to SmartDashboard or something similar, how would one go about doing this? Where would I place the function calls? My first thought would be something like the periodic method calls in Robot.java, but I was informed that that wasn’t great because of potentially inconsistent calls.

Any help is appreciated, thanks.

I can’t make a good guess of what you want unless you post all of the code you have programmed so far and are asking for help with.

The trivial answer is HERE’S the SmartDashboard documentation but that is simple enough that maybe there is more than this to your question.

From what you write it appears that your robot code is accessing the LL. Just put those same variables on the SmartDashboard if those are the values you want to see.

Since this probably doesn’t answer your question post your code and tell us what LL values in your code you want on the SmartDashboard.

Periodic software is how the robot is controlled. Generally to maintain consistency you get all of your inputs at the beginning of the loop iteration, do your calculations and then toward the end of the loop iteration do the controls, logging, and monitoring displays. I’m only guessing here that’s what you are concerned with. For example, getting a mechanism’s position more than once in the loop iteration may get two different values which often is not what you want for accuracy. Exactly what were you told about inconsistent calls and are trying to avoid?

package frc.robot;

import edu.wpi.first.wpilibj.ADXRS450_Gyro;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;

public class Limelight {

    //initializes access to Limelight Data
    NetworkTable table = NetworkTableInstance.getDefault().getTable("limelight");
    NetworkTableEntry tx = table.getEntry("tx");
    NetworkTableEntry ty = table.getEntry("ty");
    NetworkTableEntry ta = table.getEntry("ta");
    ADXRS450_Gyro gyro = new ADXRS450_Gyro();

    //converts data to java double datatypes
    double x = tx.getDouble(0.0);
    double y = ty.getDouble(0.0);
    double area = ta.getDouble(0.0);

    //defines specific values
    final double limelightMountAngleDegrees = 25.0; 
    final double limelightLensHeightInches = 20.0; 
    final double goalHeightInches = 60.0; 

    double distanceFromLimelightToGoalInchesX;
    double targAngleY;
    double distanceFromLimelightToGoalInchesXY;


    public double findAngleY() {

        return targAngleY = limelightMountAngleDegrees + y; 

    }

    public double surfaceToAir() {

        double angleToGoalDegrees = limelightMountAngleDegrees + y;
        double angleToGoalRadians = angleToGoalDegrees * (Math.PI / 180.0);

        return distanceFromLimelightToGoalInchesXY = (goalHeightInches - limelightLensHeightInches / Math.sin(angleToGoalRadians));

    }

    public double surfaceToSurface() {

        double angleToGoalDegrees = limelightMountAngleDegrees + y;
        double angleToGoalRadians = angleToGoalDegrees * (Math.PI / 180.0);

        //calculate distance
        return distanceFromLimelightToGoalInchesX = (goalHeightInches - limelightLensHeightInches) / Math.tan(angleToGoalRadians);
        
    }

    public void telemetryUpdate() {

        SmartDashboard.putNumber("LimelightX", x);
        SmartDashboard.putNumber("LimelightY", y);
        SmartDashboard.putNumber("LimelightArea", area);
        SmartDashboard.putNumber("RunFromLimelight", distanceFromLimelightToGoalInchesX);
        SmartDashboard.putNumber("HypFromRobot", distanceFromLimelightToGoalInchesXY);
        SmartDashboard.putNumber("PitchFromRobot", targAngleY);

    }


}

Thanks for responding.

In theory, the calculations would be performed by the surfaceToAir, surfaceToSurface, and findAngleY methods and would all be pasted to the SmartDashboard by the telemetryUpdate method, alongside the raw tx, ty, and ta Limelight telemetry.

I essentially just need a way of calling these methods during the robot’s operation. If placing them in Robot.java under autonomousPeriodic() is the way, then that is what I’ll do. I just got a dismissive answer from my programmer about periodic calls sometimes not firing correctly/consistently. I however have no idea why that would be the case considering that its purpose is to periodically be called, giving a reliable way to consistently upload data during a specified mode.

It looks pretty good - you are right that you seem to have essentially everything you need - now to put it into the right place and order.

If you already have some periodic code (I don’t have your complete robot code) you could put the LL data acquisition there, too. In the mean time put it in your robotPeriodic() {}. I would call a new LL update method that contains at the least this code moved out of the class instantiation:


    double x;
    double y;
    double area;

public void acquire() {
    //converts data to java double datatypes
    x = tx.getDouble(0.0);
    y = ty.getDouble(0.0);
    area = ta.getDouble(0.0);
}

Then call each of the other methods as you need to get the values.

That seems to be the minimum to get you going but I’d tweak what you have a little.

First I’d check to make sure you have a new, valid set of data from LL with code similar to other LL data
double valid = tv.getDouble(Double.NaN);
then check for + or - 1..

Normally you would try to get all of your inputs as fast as possible at the beginning of the loop iteration and not do extra calculations until needed. Still, I see value in doing all your calculations early on since there aren’t many. That way all the information you need is calculated once at the right time and is always available anytime in the entire loop iteration. As it is now you have to make sure you run all of the calculation methods before the data is available for the SmartDashboard posting.

So I’d make a second method for all the calculations that you run immediately after all of your sensor inputs for the iteration. Then I suggest running telemetryUpdate() at the end of the iteration. If you are plotting your data then the telemetryUpdate() is fine but if it’s numbers for human consumption, displaying once every 50 or so iterations is adequate and much more efficient.

You could end up with something like this:

Limelight LL = new Limelight();

@Override
  public void robotPeriodic()
  {
    LL.acquire();
    LL.calculate();
    CommandScheduler.getInstance().run();
    LL.updateTelemetry();
  }
If you want to display in AdvantageScope

You could take a look at THIS example but caution! The Robot class is correct and works to view a USB camera and detect an AprilTag and compute the pose and display the pose (much more code than what you are going to use - my team probably will use the roboRIO for vision this 2025 season). The LL class has NOT BEEN TESTED! I’ve been working on updating to better methods and do not have a LL at home and haven’t used the current LL helper. The code is similar to what you have, does validation, displays data (after debugging if that’s needed), and maybe there are better LL methods to use now than what I use.