2 Limelight’s are causing loop overruns

My team has 2 limelight’s and every periodic we get the json results through limelight lib. This is causing loop overruns.

The code in my periodic:

    // Every periodic chooses the limelight to use based off of their distance from april tags
    LimelightResults frontLimelightResults = LimelightHelpers.getLatestResults(LimelightConstants.FRONT_LIMELIGHT_NAME);
    LimelightResults backLimelightResults = LimelightHelpers.getLatestResults(LimelightConstants.BACK_LIMELIGHT_NAME);
    LimelightTarget_Fiducial[] frontLimelightAprilTags = frontLimelightResults.targetingResults.targets_Fiducials;
    LimelightTarget_Fiducial[] backLimelightAprilTags = backLimelightResults.targetingResults.targets_Fiducials;

Log Data:

4:29:42.990 AM
   	Shuffleboard.update(): 0.000020s  	LiveWindow.updateValues(): 0.000012s  	robotPeriodic(): 0.076149s  	SmartDashboard.updateValues(): 0.000308s  Warning at edu.wpi.first.wpilibj.Tracer.lambda$printEpochs$0(Tracer.java:62): 	teleopPeriodic(): 0.000650s Warning  1  	teleopPeriodic(): 0.000650s
	SmartDashboard.updateValues(): 0.000308s
	robotPeriodic(): 0.076149s
	LiveWindow.updateValues(): 0.000012s
	Shuffleboard.update(): 0.000020s
  edu.wpi.first.wpilibj.Tracer.lambda$printEpochs$0(Tracer.java:62)    	DriveCommand.execute(): 0.012204s  	ManualClaw.execute(): 0.000574s  	VisionSubsystemImpl.periodic(): 0.031281s  	DriveSubsystemImpl.periodic(): 0.004829s  	buttons.run(): 0.000188s  	ArmSubsystemImpl.periodic(): 0.000019s  	ManualArm.execute(): 0.001679s  Warning at edu.wpi.first.wpilibj.Tracer.lambda$printEpochs$0(Tracer.java:62): 	ClawSubsystemImpl.periodic(): 0.000032s Warning  1  	ClawSubsystemImpl.periodic(): 0.000032s
	ManualArm.execute(): 0.001679s
	ArmSubsystemImpl.periodic(): 0.000019s
	buttons.run(): 0.000188s
	DriveSubsystemImpl.periodic(): 0.004829s
	VisionSubsystemImpl.periodic(): 0.031281s
	ManualClaw.execute(): 0.000574s
	DriveCommand.execute(): 0.012204s
  edu.wpi.first.wpilibj.Tracer.lambda$printEpochs$0(Tracer.java:62) 

How should I fix this?

The limelight lib is very heavy on data parsing and getting network tables data, try getting data for only the methods you use instead of the entire json dump if you aren’t using json dump specific data. This should probably be implemented in a separate vision subsystem.

The limelight getResults function is known to cause delays I believe. We just run our vision updates in a separate thread to avoid overruns in the main one.

1 Like

Do you have any example code on how I could do that?

1 Like

Sheriff-ChargedUp-2023/Vision.java at main · MAikenMagic1102/Sheriff-ChargedUp-2023 (github.com)

Our vision class is not a subsystem, but you will see we have a vision_thread method that gets called to create the thread and loop which is referenced in the vision constructor.

We only create a object reference to this class inside of our drivetrain subsystem so we are certain multiple vision threads won’t ever be made.

1 Like

That thread doesn’t have any “wait” does this cause you any CPU issues or anything?

None that I’ve seen, I can check later but it was running in the background of our entire event last weekend and we never had a problem. The nature of the limelight results coming back slowly in of itself is a delay.

1 Like

Maybe I missed something, but are you using any sort of mutex to prevent reading and writing vision results at the same time?

Unless the pose estimator has one, no there is not. I’ve yet to see any bad behavior with our method, but it is a fair point.

@JohnFogarty

  private static final Vector<N3> visionStdDevs = VecBuilder.fill(0.9,0.9, Units.degreesToRadians(0.9));
  //Values tried for Theta 0.1, 500 
  //(I think we want to ignore the camera pose's angles since they will always be wrong compared to gyro)

Correct me if I’m wrong, but my understanding of this code is you are trusting the vision measurement to have an angle accuracy of 0.9 degrees. That’s a very high confidence in the vision supplied angle. A value of 500 is > 360 and wouldn’t make much sense. The default that WPILib uses for vision measurements is 0.9 Radians which is about 51 degrees.

You may want to throw a lock around the shared data (I think it’s just the poseEst object). Race conditions have a nasty habit of not showing up until a very important match

I should say we had vision estimated alignment starting to work on our test grid in our shop but we did not use at competition yet because of camera mounting related issues. (We can see an april tag right in front of us on one camera but not the other, and then we still need to fix our measurements of camera → robot since they don’t report the correct position when we are in a known place we were going to try and fudge the camera → robot values to see if that helps.)

1 Like

Is this the kind of Lock you are referring to?

Lock Objects (The Java™ Tutorials > Essential Java Classes > Concurrency) (oracle.com)

Haven’t used a lock in Java in a while, but that looks right.

We will give this some thought tonight.

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html

I tried doing the thread thing and it stopped having loop overruns from the Vision subsystem. It caused cpu utilization to go to 100% which then caused other things to have loop overruns. How can I stop it from killing the cpu?

I would have to see your code to even have a guess. Like I stated we didn’t have that problem.

Our cpu usage is already incredibly high so that is probably the issue.

Ah that could be why, you can try adding a delay to the loop and see how that helps. 20-50ms

@Traptricker more specifically you want to put the thread to sleep for a period of time. Doing this allows the thread to not use CPU cycles until a specific amount of time has passed. You can checkout the following for details.

1 Like