Stopping the VisionThread without killing it entirely in Java

vision

#1

I recently built a system on my teams robot that enables me to switch between a raw UsbCamera display and a VisionPipeline with a button and only having to host one MjpegServer.

The remaining issue is that while this system works the VisionPipeline continues to run as if active when it’s not being displayed. I can’t just stop it due to the time it takes to make a new pipeline and it’s underlying classes.

I have tried simply using object-synchronized wait and notify calls on the thread but this, while it would work on a standard thread, kills the entire virtual machine due to an untraced error.

I continued to search for alternate options and was nearly successful in overriding elements of the class. I used reflection to obtain the object references of private final fields and overrode the public methods runOnce and runForever but due to the fact that an imported class, CameraServerSharedStore, appeared not to exist was once again unsuccessful. I had intended to override them to call my own duplicate runOnceInternal method that would do nothing if a boolean ‘on’ was set to true.

One of my final and more nearly successful attempts was to mimic the VisionThread’s internal constructor setup, passing the full constructor to one that took only a VisionRunner. I had intended to pass this VisionRunner via the super() method and store a reference to the object in my own CvVisionThread class so that I could call both VisionRunner.stop() and VisionRunner.runForever() as needed. A type conversion issue (the types we’re identical), however, prevented this method from working.

If it was the intent of WPI to lock down every aspect of their internal programming from team edits they were very successful, even to the point of hindering my development.

Several hours in I can’t think of other options and have come to see if anyone else can think or has successfully achieved this functionality.


#2

You could read an enabled variable in your pipeline process() function. E.g. something like:

public class MyPipeline implements VisionPipeline {
  public volatile boolean enabled;

  @Override
  public void process(Mat mat) {
    if (!enabled) return;
  }
}
...
MyPipeline myPipeline = new MyPipeline();
VisionThread visionThread = new VisionThread(camera,
              myPipeline, pipeline -> {
        // do something with result
});
...
// set myPipeline.enabled here based on joystick input

You’re correct that the VisionRunner class is perhaps a bit overconstrained in making m_cvSink private with no accessors, as I think the CvSink methods would answer most of your concerns (CvSink has setEnabled() and setSource() methods).


#3

Cant believe I missed that chasing down the convoluted options I looked at. Does the trick! Thanks.