Untangling a String with a Thread (see what I did there…?)
Note: This is a way to process strings as part of WPILibs Command Based Programming Framework…for use with First Robotics. It’s also applicable anytime you have to process information on a separate thread of execuction….I had to learn this a few years ago when processing FIX Messages from the Intercontinental Exchange.
Our FRC team set out to improve the Robot’s vision processing; an off season activity. We found the integration between our OpenMV and the Roborio was, well…confused. We had a really basic json message being passed down the wire from the eyes to the brain.
So what’s a nice way to manage the messages the Roborio reads from the serial port?
What about an ExecutorService with an ArrayBlockingQueue?
Figured it might be a good opportunity to teach/learn about work queues, threads, etc.
So….
Create an ExecutorService (I’m using a single thread for this example…tune as required)…this is a way for Java to manage the creation of threads:
private ExecutorService executorService = Executors.newFixedThreadPool(1);
And then create a queue to place your String in for processing:
private ArrayBlockingQueue visionReaderQueue= new ArrayBlockingQueue(1000,true);
The (1000,true) constructor means your queue can hold 1,000 messages and your want them to be FIFO (first in, first our…the order is guaranteed)
These two fields would be on your Command. Then create a Runnable class called something like “VisionQueueReader”
import java.util.concurrent.ArrayBlockingQueue;
public class VisionQueueReader implements Runnable {
private ArrayBlockingQueue queue;
public VisionQueueReader(ArrayBlockingQueue queue) {
this.queue = queue;
}
@Override
public void run() {
while (!Thread.interrupted()) {
try {
String messageFromQueue = queue.take();
//Here is where you do whatever processing on the json you need to…chance are this class might also have a Static reference to the Subsystem waiting for the message
} catch (InterruptedException e) {
break;
//this gets tripped when you shut the ExecutorServiceDown…the loop ends
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
}
}
and finally…in your command that drops the Strings on to the queue, you need to cleanly shut down the Executor service when the system is shutting down
executorService.shutdownNow();
To start the ExecutorService…in either the init or constructor of your command:
executorService.submit(new VisionQueueReader(visionMessageQueue));
so you basically have this ArrayBlockingQueue waiting for strings….when you put a string on, the queue being managed and run by the ExecutorService grabs it and processes it within its run method.
I think this would be a cleaner way to manage that thread resource and guarantee it’ll stick around rather than spend the resources spinning up another…it also guarantees the order in which the messages come off the queue.
Now, this is just another implementation and subject to scrutiny…try it, see if it works. While you do, ask yourself how you might test it vs. your implementation.