Vision Subsystem Best Practices

I thought PathPlanner uses the same origin regardless of red or blue. So you just always use blue. Does the transpose just swap sides of the field right to left?

@vyang2968 @eddieD

I think @jdaming’s example is really good. If you are using PathPlannerLib, use it’s built-in alliance mirroring and use Limelight’s wpiblue and wpired botposes.

@eddieD Contact page on the website. I would recommend trying to flash without any other power applied. We will send a new one immediately if you can’t flash. Sent a dm. Thanks


You can use it that way, but it has an option to mirror the paths for both sides which works well with either the red or blue pose respectively

A post was merged into an existing topic: Introducing Limelight 3

You really should not have nested subsystems in the command-based framework. Use a normal class.

Remember that the point of Subsystem (and, by extension, SubsystemBase) is hardware mutexing for commands. There’s really no other reason to use it.

1 Like

Nested subsystems? Did I miss something.

You have a reference to a subsystem inside of a subsystem. This is fundamentally dangerous; it lets you bypass the requirement system (even without meaning to).

It doesn’t make sense for vision to be a subsystem to begin with; it has no hardware that needs mutex guarding.

I didn’t review the code in question, but the limelight is hardware. It has settings that can be mutated, such as the pipeline. For us, we have a limelight that does retroreflective tape targeting, and object detection. It can only do one of these things at a time.


This can be appropriate if you are actually using the mutex guarding to prevent simultaneous access to the pipeline settings and mediate all such usage through Commands (as you would do with other subsystems). The periodic method (used in the above code) doesn’t do this, though, and using Subsystem purely to get access to a periodic call is inappropriate.

There are two different issues here:

  1. Using a passed in subsystem vs. passing in consumers/suppliers.
  • Passing in a subsystem is simple
  • It gives future flexibility as you have access to everything
  • It is dangerous and could break any number of things mostly related to unintended behavior of the subsystem passed in.
  • It is hard to debug as when the subsystem is passed around there are a lot more places it could be accessed. “spooky action at a distance”
  1. Using a regular Java object vs. a subsystem
  • Allows you to use a mutex to lock pipelines if needed
  • Has a built in periodic section that is helpful
    Java Object
  • Very easy to setup for a single pipeline.
  • Simple except for the setup of a periodic call which needs to come all the way from Robot

If you are just using Vision for your drivetrain it is probably easiest to treat the camera as a sensor that is a part of your drivetrain. You can have the drivetrain call this java object and both the problems above go away. If you need multiple pipelines, want something that can be read from multiple subsystems, or any other complications you should consider the above.

1 Like

I am a fan of suppliers vs subsystem being passed in. Though admittedly sometimes the ease of just getting the subsystem from the container wins out.

As for the use of Subsystem when a mutex isn’t required this points out the need for a daemon object. Something that can run and do tasks in the background. As has been pointed out this can be achieved through the Robot addPeriodic, but a convenience class that has a periodic and automatically adds itself would be nice.

Because of the delays in processing the JSON data from the Limelight getResults function we changed our vision subsystem to be a normal class and have a method call from the end of the vision classes’s constructor that starts a new thread with the vision loop inside it and then create one instance of the Vision class as an object inside of our drivetrain subsystem.