1212import java .awt .event .KeyListener ;
1313
1414import java .util .ArrayList ;
15+ import java .util .Arrays ;
16+ import java .util .List ;
1517import java .util .Map ;
1618import java .util .concurrent .CompletableFuture ;
1719import java .util .concurrent .ExecutionException ;
20+ import java .util .concurrent .ExecutorService ;
1821import java .util .concurrent .Executors ;
1922import java .util .concurrent .Future ;
2023import java .util .concurrent .ScheduledExecutorService ;
24+ import java .util .concurrent .ThreadFactory ;
2125import java .util .concurrent .TimeUnit ;
2226import javax .swing .JFrame ;
27+ import org .jetbrains .annotations .NotNull ;
2328
2429public class MrModule extends JFrame implements Runnable , KeyListener {
2530
31+ private ExecutorService steeringExec = Executors .newSingleThreadExecutor (new NamedThreadFactory ("steering" ));
32+ private ExecutorService speedExec = Executors .newSingleThreadExecutor (new NamedThreadFactory ("speed" ));
33+ private ExecutorService imageRGBExec = Executors .newSingleThreadExecutor (new NamedThreadFactory ("imageRGB" ));
34+ private ExecutorService imageBWExec = Executors .newSingleThreadExecutor (new NamedThreadFactory ("imageBW" ));
35+ private ExecutorService imageSimpleExec = Executors .newSingleThreadExecutor (new NamedThreadFactory ("imageSimple" ));
36+ private ExecutorService cameraImageExec = Executors .newSingleThreadExecutor (new NamedThreadFactory ("cameraReader" ));
2637 private PWMController driveSys = new ArduinoIO ();
27- private ArrayList <Module > modules = new ArrayList <>(); // Contains each module
38+ private List <Module > modules = new ArrayList <>(); // Contains each module
39+ private final WindowModule windowModule ;
40+ private final ArduinoModule arduinoModule ;
41+ private final ImageManagementModule imageManagementModule ;
42+ private final SpeedControlModule speedControlModule ;
43+ private final SteeringModule steeringModule ;
2844 private final CarControl carControl ; // A CarControl that holds data for each module
2945 private CarControl speedControl ; // A CarControl that holds data specifically for speed
3046 private CarControl steeringControl ; // A CarControl that holds data specifically for steering
47+ private long frameNumber = 0L ;
48+ private long lastTime = 0L ;
3149
3250 private boolean initialized = false ;
3351
@@ -49,7 +67,14 @@ private MrModule(boolean realCam, boolean hasWindow) {
4967 final int winHeight = carControl .getImageHeight ();
5068 carControl .updateWindowDims (getWidth (), getHeight ());
5169
52- createModules (hasWindow , winWidth , winHeight );
70+ // Create modules
71+ windowModule = createWindowModule (hasWindow , winWidth , winHeight );
72+ arduinoModule = new ArduinoModule (driveSys );
73+ imageManagementModule = new ImageManagementModule (winWidth , winHeight , carControl .getTile ());
74+ speedControlModule = new SpeedControlModule ();
75+ steeringModule = new SteeringModule ();
76+
77+ initializeModules (windowModule , arduinoModule , imageManagementModule , speedControlModule , steeringModule );
5378
5479 headlessInit ();
5580 }
@@ -59,7 +84,7 @@ private MrModule(boolean realCam, boolean hasWindow) {
5984 */
6085 private void headlessInit () {
6186 // driveSys = new ArduinoIO();
62- final ScheduledExecutorService executorService = Executors .newSingleThreadScheduledExecutor ();
87+ final ScheduledExecutorService executorService = Executors .newSingleThreadScheduledExecutor (new NamedThreadFactory ( "Frame Scheduler" ) );
6388 executorService .scheduleAtFixedRate (this , initDelay , Math .round (1000.0 / FPS ), TimeUnit .MILLISECONDS );
6489
6590 Future run = executorService .submit (this );
@@ -71,18 +96,8 @@ private void headlessInit() {
7196 }
7297 }
7398
74- private void createModules (boolean useWindowModule , int winWidth , int winHeight ) {
75- if (useWindowModule ) {
76- WindowModule windowModule = new WindowModule (winWidth , winHeight );
77- windowModule .addKeyListener (this );
78- modules .add (windowModule );
79- }
80-
81- modules .add (new ImageManagementModule (winWidth , winHeight , carControl .getTile ()));
82- modules .add (new SpeedControlModule ());
83- modules .add (new SteeringModule ());
84- modules .add (new ArduinoModule (driveSys ));
85- //modules.add(new LatencyTestModule());
99+ private void initializeModules (Module ... moduleArray ) {
100+ modules = Arrays .asList (moduleArray );
86101
87102 for (Module module : modules ) {
88103 module .initialize (carControl );
@@ -91,6 +106,17 @@ private void createModules(boolean useWindowModule, int winWidth, int winHeight)
91106 initialized = true ;
92107 }
93108
109+ private WindowModule createWindowModule (boolean useWindowModule , int winWidth , int winHeight ) {
110+ final WindowModule winModule ;
111+ if (useWindowModule ) {
112+ winModule = new WindowModule (winWidth , winHeight );
113+ winModule .addKeyListener (this );
114+ } else {
115+ winModule = null ;
116+ }
117+ return winModule ;
118+ }
119+
94120 /**
95121 * <p>
96122 * Update method is called once every FPS.
@@ -99,48 +125,69 @@ private void createModules(boolean useWindowModule, int winWidth, int winHeight)
99125 * run after ImageManagement process their respective image.
100126 * </p>
101127 */
102- private void update () {
128+ private void update (long frameNumber ) {
103129 //read the camera image, and update windowModule.
104- carControl .readCameraImage ();
105- carControl .setEdges (getInsets ());
106- modules .get (0 ).update (carControl );
107- modules .get (4 ).update (carControl );
130+ CompletableFuture <Void > cameraImage = CompletableFuture
131+ .runAsync (() -> {
132+ carControl .readCameraImage ();
133+ carControl .setEdges (getInsets ());
134+ windowModule .update (carControl );
135+ arduinoModule .update (carControl );
136+ }, cameraImageExec );
108137
109138 // FIXME: Does not print exceptions to console.
110- ImageManagementModule imageModule = ( ImageManagementModule ) modules . get ( 1 );
139+
111140 // Start Thread to get the RGB image. (for camera)
112- CompletableFuture <CarControl > futureRGBImage = CompletableFuture .supplyAsync (() -> {
113- carControl .setRGBImage (imageModule .getRGBRaster (carControl .getRecentCameraImage ()));
114- carControl .setRenderedImage (carControl .getRGBImage ());
115- return carControl ;
116- });
141+ final byte [] recentImage = carControl .getRecentCameraImage ();
142+
117143 // Start Thread to get the black and white image (for steering)
118- CompletableFuture <CarControl > futureBWImage = CompletableFuture .supplyAsync (() -> {
119- steeringControl .setRGBImage (imageModule .getBlackWhiteRaster (carControl .getRecentCameraImage ()));
120- return steeringControl ;
121- });
122- // Start Thread to get the simple image (for speed)
123- CompletableFuture <CarControl > futureSimpleImage = CompletableFuture .supplyAsync (() -> {
124- speedControl .setProcessedImage (imageModule .getSimpleColorRaster (carControl .getRecentCameraImage ()));
125- return speedControl ;
126- });
127-
128- // Call steering Module after futureBWImage is finished
129- CompletableFuture <Void > futureSteering = futureBWImage .thenAcceptAsync (carControl -> modules .get (3 ).update (carControl ));
144+ CompletableFuture <Void > futureSteering = cameraImage
145+ .thenApplyAsync (v -> setBWImage (recentImage ), imageBWExec )
146+ // Call steering Module after futureBWImage is finished
147+ .thenAcceptAsync (steeringModule ::update , steeringExec );
148+
149+ CompletableFuture <CarControl > futureRGBImage = CompletableFuture .completedFuture (null );
150+ if (frameNumber % 2 == 1 ) {
151+ futureRGBImage = cameraImage
152+ .thenApplyAsync (v -> setRGBImage (recentImage ), imageRGBExec );
153+ }
154+
130155 // Call speed module after futureSimpleImage is finished
131- CompletableFuture <Void > futureSpeed = futureSimpleImage .thenAcceptAsync (carControl -> modules .get (2 ).update (carControl ));
156+ CompletableFuture <Void > futureSpeed = CompletableFuture .completedFuture (null );
157+ if (frameNumber % 3 == 1 ) {
158+ // Start Thread to get the simple image (for speed)
159+ futureSpeed = cameraImage
160+ .thenApplyAsync (v -> setSimpleImage (recentImage ), imageSimpleExec )
161+ .thenAcceptAsync (speedControlModule ::update , speedExec );
162+ }
132163
133164 // Run when all finished.
134165 CompletableFuture .allOf (futureSpeed , futureSteering , futureRGBImage )
135166 .thenAccept (v -> paint ())
136167 .exceptionally (ex -> {
137- System . out . println ( ex .getMessage () );
168+ ex .printStackTrace ( );
138169 return null ;
139170 })
140171 .join ();
141172
142173 }
143174
175+ private CarControl setRGBImage (byte [] recentImage ) {
176+ carControl .setRGBImage (imageManagementModule .getRGBRaster (recentImage ));
177+ carControl .setRenderedImage (carControl .getRGBImage ());
178+ return carControl ;
179+ }
180+
181+ private CarControl setBWImage (byte [] recentImage ) {
182+ steeringControl .setRGBImage (imageManagementModule .getBlackWhiteRaster (recentImage ));
183+ return steeringControl ;
184+ }
185+
186+ private CarControl setSimpleImage (byte [] recentImage ) {
187+ speedControl .setProcessedImage (imageManagementModule .getSimpleColorRaster (recentImage ));
188+ return speedControl ;
189+ }
190+
144191 private void paint () {
145192 if (!modules .isEmpty ()) {
146193 for (Module module : modules ) {
@@ -151,16 +198,24 @@ private void paint() {
151198
152199 @ Override
153200 public void run () {
154- if (!initialized ) {
155- return ;
201+ if (initialized ) {
202+ //printElapsedTime();
203+ try {
204+ update (++frameNumber );
205+ //paint();
206+ } catch (Exception e ) {
207+ e .printStackTrace ();
208+ }
156209 }
210+ }
157211
158- try {
159- update ();
160- //paint();
161- } catch (Exception e ) {
162- e .printStackTrace ();
212+ private void printElapsedTime () {
213+ final long curTime = System .currentTimeMillis ();
214+ if (lastTime == 0 ) {
215+ lastTime = curTime ;
163216 }
217+ System .out .println ("Time: " + (lastTime - curTime ));
218+ lastTime = curTime ;
164219 }
165220
166221 public static void main (String [] args ) {
@@ -196,4 +251,16 @@ public void keyReleased(KeyEvent e) { }
196251 @ Override
197252 public void keyTyped (KeyEvent e ) { }
198253
254+ public static class NamedThreadFactory implements ThreadFactory {
255+ private final String name ;
256+
257+ public NamedThreadFactory (String name ) {
258+ this .name = name ;
259+ }
260+
261+ @ Override
262+ public Thread newThread (@ NotNull Runnable r ) {
263+ return new Thread (r , name );
264+ }
265+ }
199266}
0 commit comments