Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / colonet / ColonetGUI / SimpleColonet.java @ 32

History | View | Annotate | Download (16.6 KB)

1

    
2
import java.awt.*;
3
import java.awt.event.*;
4
import java.applet.*;
5
import javax.swing.*;
6
import javax.swing.event.*;
7
import java.net.*;
8
import java.io.*;
9

    
10
/**
11
 *                Colonet: The Colony Control Applet.
12
 *                This applet provides a graphical control mechanism for the robot colony designed
13
 *                for web deployment.
14
 *
15
 *                @author Gregory Tress
16
 *                @version 0.1
17
 *
18
 */
19
public class SimpleColonet extends JApplet implements ActionListener, KeyListener, ChangeListener
20
{
21

    
22
        /*
23
        *   Graphical Applet Elements
24
        */
25

    
26
        ColonetServerInterface csi;
27
        DataListener datalistener;      
28
        
29
        // panelTop contains stuff on top
30
        JPanel panelTop;                                
31
        JPanel panelConnect;                        
32
        JTextField txtHost;                                
33
        JTextField txtPort;                                
34
        JButton btnConnect;                                
35
        
36
        // panelMove contains directional buttons for controlling the robot
37
        JPanel panelMove;
38
        JButton btnF, btnB, btnL, btnR, btnActivate;
39
        boolean isMoving;
40
        
41
        // panelCommands contains 
42
        JPanel panelCommands;
43
        JButton btnClearLog;
44
        JButton btnBuzzerOn;
45
        JButton btnBuzzerOff;
46
        JButton btnRequestBattery;
47
        JButton btnChangeOrbColor;
48
        JButton btnGetSensorData;
49
        JComboBox cmbRobotNumber;
50
        String robotNumber;
51
        
52
        JColorChooser chooser;
53
        JPanel panelChooser;
54
        
55
        JPanel panelBottom;
56
        JTextArea log;
57
        JScrollPane spLog;
58
        
59
        JPanel panelWebcam;
60
        WebcamLoader webcamLoader;
61
        boolean destroyed = false;
62
        
63
        /**
64
         * Sets up user control elements.
65
         * Specifies layout for all GUI elements,
66
         * attaches all ActionListeners, KeyListeners, and ChangeListeners, and
67
         * creates threads for loading webcam image and listening for incoming data.
68
         *
69
         */
70
        public void init () {
71
                Container content = getContentPane();
72
                content.setLayout(new GridLayout(2,1));
73
                
74
                txtHost = new JTextField();
75
                txtPort = new JTextField();
76
                btnConnect = new JButton("Connect");
77
                panelConnect = new JPanel();
78
                panelConnect.setLayout(new GridLayout(2,3));
79
                panelConnect.add(new JLabel("Host"));
80
                panelConnect.add(new JLabel("Port"));
81
                panelConnect.add(new JLabel(" "));
82
                panelConnect.add(txtHost);
83
                panelConnect.add(txtPort);
84
                panelConnect.add(btnConnect);
85
                panelConnect.setBorder(BorderFactory.createTitledBorder("Connection"));
86
                
87
                btnF = new JButton("Forward");
88
                btnB = new JButton("Back");
89
                btnL = new JButton("Left");
90
                btnR = new JButton("Right");
91
                btnActivate = new JButton("On/Stop");
92
                panelMove = new JPanel();
93
                panelMove.setLayout(new GridLayout(3,3));
94
                panelMove.add(new JLabel(""));
95
                panelMove.add(btnF);
96
                panelMove.add(new JLabel(""));
97
                panelMove.add(btnL);
98
                panelMove.add(btnActivate);
99
                panelMove.add(btnR);
100
                panelMove.add(new JLabel(""));
101
                panelMove.add(btnB);
102
                panelMove.add(new JLabel(""));
103
                panelMove.setBorder(BorderFactory.createTitledBorder("Movement Control"));
104
                
105
                btnClearLog = new JButton("Clear Log");
106
                btnBuzzerOn = new JButton("Buzzer On");
107
                btnBuzzerOff = new JButton("Buzzer Off");
108
                btnRequestBattery = new JButton("Request Battery");
109
                btnChangeOrbColor = new JButton("Change Orb Color");
110
                btnGetSensorData = new JButton("Get Sensor Data");
111
                String [] robotList = {"All   ", "0", "1", "2", "3", "4", "5"};
112
                cmbRobotNumber = new JComboBox(robotList);
113
                panelCommands = new JPanel();
114
                panelCommands.setLayout(new FlowLayout());
115
                panelCommands.add(btnBuzzerOn);
116
                panelCommands.add(btnBuzzerOff);
117
                panelCommands.add(btnClearLog);
118
                panelCommands.add(btnRequestBattery);
119
                //panelCommands.add(btnChangeOrbColor);
120
                panelCommands.add(btnGetSensorData);
121
                panelCommands.add(new JLabel("Robot # to control"));
122
                panelCommands.add(cmbRobotNumber);
123
                panelCommands.setBorder(BorderFactory.createTitledBorder("Commands"));
124
                
125
                chooser = new JColorChooser();
126
                chooser.setPreviewPanel(new JPanel());
127
                panelChooser = new JPanel();
128
                panelChooser.setLayout(new BorderLayout());
129
                panelChooser.add(chooser, BorderLayout.CENTER);
130
                panelChooser.setBorder(BorderFactory.createTitledBorder("Orb"));
131
                
132
                panelTop = new JPanel();
133
                panelTop.setLayout(new BorderLayout());
134
                panelTop.add(panelConnect, BorderLayout.NORTH);
135
                panelTop.add(panelMove, BorderLayout.WEST);
136
                panelTop.add(panelCommands, BorderLayout.CENTER);
137
                panelTop.add(panelChooser, BorderLayout.EAST);
138
                
139
                log = new JTextArea();
140
                spLog = new JScrollPane(log, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
141
                spLog.setBorder(BorderFactory.createTitledBorder("Log"));
142
                log.setEditable(false);
143
                
144
                panelWebcam = new JPanel();
145
                panelWebcam.setBorder(BorderFactory.createTitledBorder("Webcam"));
146
                
147
                panelBottom = new JPanel();
148
                panelBottom.setLayout(new GridLayout(1,2));
149
                panelBottom.add(spLog);
150
                panelBottom.add(panelWebcam);
151
                
152
                content.add(panelTop);
153
                content.add(panelBottom);
154
                
155
                txtHost.setText("roboclub1.frc.ri.cmu.edu");
156
                txtPort.setText("10123");
157
                isMoving = false;
158
                
159
                btnConnect.addActionListener(this);
160
                btnClearLog.addActionListener(this);
161
                btnBuzzerOn.addActionListener(this);
162
                btnBuzzerOff.addActionListener(this);
163
                btnRequestBattery.addActionListener(this);
164
                btnChangeOrbColor.addActionListener(this);
165
                btnGetSensorData.addActionListener(this);
166
                
167
                btnActivate.addActionListener(this);
168
                btnActivate.addKeyListener(this);
169
                btnF.addActionListener(this);
170
                btnF.addKeyListener(this);
171
                btnB.addActionListener(this);
172
                btnB.addKeyListener(this);
173
                btnL.addActionListener(this);
174
                btnL.addKeyListener(this);
175
                btnR.addActionListener(this);
176
                btnR.addKeyListener(this);
177
                
178
                chooser.getSelectionModel().addChangeListener(this);
179
                
180
                csi = new ColonetServerInterface(log);
181
                webcamLoader = new WebcamLoader(this);
182
                datalistener = new DataListener(log);
183
        }
184
        
185
        /**
186
         * Attempt to shut down the applet cleanly. 
187
         * Clean up leftover tasks when destroyed,
188
         * i.e., browser window is closed or appletviewer is stopped. 
189
         * This method attempts to pause the destruction of the applet for 1000ms.
190
         * If successful, other threads will have the chance to receive the shutdown
191
         * signal and stop. Otherwise catches an exception.
192
         */
193
        public void destroy ()
194
        {
195
                try {
196
                        destroyed = true;
197
                        //Wait for a second to give other threads a chance to be interrupted and return.
198
                        //This may not be necessary but it seems to prevent some browser crashes. 
199
                        Thread.sleep(1000);
200
                } catch (InterruptedException e) {
201
                        err("Interrupted exception in destroy()");
202
                }
203
        }
204
        
205
        public void actionPerformed (ActionEvent event) {
206
                Object source = event.getSource();
207
                
208
                if (source == btnConnect)
209
                {
210
                        csi.connect(txtHost.getText(), txtPort.getText());
211
                        webcamLoader.start();
212
                        datalistener.start();
213
                }
214
                else if (source == btnClearLog)
215
                        log.setText("");
216
                else if (source == btnBuzzerOn)
217
                {
218
                        csi.sendData(ColonetServerInterface.BUZZER_SET_FREQ + " 254", ColonetServerInterface.GLOBAL_DEST);
219
                }
220
                else if (source == btnBuzzerOff)
221
                {
222
                        csi.sendData(ColonetServerInterface.BUZZER_OFF, ColonetServerInterface.GLOBAL_DEST);
223
                }
224
                else if (source == btnRequestBattery)
225
                {
226
                        csi.sendRequest(ColonetServerInterface.BATTERY, ColonetServerInterface.GLOBAL_DEST);
227
                }
228
                else if (source == btnGetSensorData)
229
                {
230
                        SensorDataWindow sd = new SensorDataWindow(this);
231
                        Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
232
                        sd.setBounds(screenDim.width/4, screenDim.height/4, screenDim.width/2, screenDim.height/2);
233
                        sd.setVisible(true);
234
                }
235
                else if (source == btnActivate)
236
                {
237
                        isMoving = false;
238
                        csi.sendData(ColonetServerInterface.MOTORS_INIT, ColonetServerInterface.GLOBAL_DEST);
239
                        csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 0", ColonetServerInterface.GLOBAL_DEST);
240
                        csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 0", ColonetServerInterface.GLOBAL_DEST);
241
                }
242
                else if (source == btnF)
243
                {
244
                        isMoving = true;
245
                        csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
246
                        csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
247
                }
248
                else if (source == btnB)
249
                {
250
                        isMoving = true;
251
                        csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
252
                        csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
253
                }
254
                else if (source == btnL)
255
                {
256
                        isMoving = true;
257
                        csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
258
                        csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
259
                }
260
                else if (source == btnR)
261
                {
262
                        isMoving = true;
263
                        csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
264
                        csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
265
                }
266
        
267
        }
268
        
269
        public void stateChanged (ChangeEvent e) 
270
        {
271
                //Update the orb color
272
                int red = chooser.getColor().getRed();
273
                int green = chooser.getColor().getGreen();
274
                int blue = chooser.getColor().getBlue();
275
                csi.sendData(ColonetServerInterface.ORB_SET + " " + red + " " + green + " " + blue, ColonetServerInterface.GLOBAL_DEST);
276
        }
277
        
278
        
279
        /**
280
         * Display informational message box on the screen. Used for casual communicaton to the user.
281
         * @param text Text to display
282
         */
283
        private void msg (String text) {
284
                JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.INFORMATION_MESSAGE);
285
        }
286
        
287
        /**
288
         * Display warning message box on the screen. Used for minor alerts or exceptions.
289
         * @param text Text to display
290
         */
291
        private void warn (String text) {
292
                JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.WARNING_MESSAGE);
293
        }
294
        
295
        /**
296
         * Display error message box on the screen. Used for major errors or exceptions in the program.
297
         * @param text Text to display
298
         */
299
        private void err (String text) {
300
                JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.ERROR_MESSAGE);
301
        }
302
        
303
        public void keyPressed (KeyEvent e) {
304
                if (isMoving) return;
305
                try {
306
                        if (e.getKeyCode() == KeyEvent.VK_UP) {
307
                                log.append("Key: Up\n");
308
                                isMoving = true;
309

    
310
        csi.sendData(ColonetServerInterface.MOVE_AVOID + " 200 0 0", ColonetServerInterface.GLOBAL_DEST);
311

    
312
                                //sendData(MOTOR1_SET + " 1 200");
313
                                //sendData(MOTOR2_SET + " 1 200");
314
                        }
315
                        else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
316
                                log.append("Key: Down\n");
317
                                isMoving = true;
318
                                csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
319
                                csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
320
                        }
321
                        else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
322
                                log.append("Key: Left\n");
323
                                isMoving = true;
324
                                csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
325
                                csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
326
                        }
327
                        else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
328
                                log.append("Key: Right\n");
329
                                isMoving = true;
330
                                csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
331
                                csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
332
                        }
333
                        
334
                } catch (Exception ex) {
335
                        log.append("Error sending command.\n");
336
                }
337
        }
338
        
339
        public void keyReleased (KeyEvent e) {
340
                if (!isMoving) return;
341
                // if we are no longer pressing a direction key, stop the robot
342
                if (e.getKeyCode() == KeyEvent.VK_UP ||
343
                        e.getKeyCode() == KeyEvent.VK_DOWN ||
344
                        e.getKeyCode() == KeyEvent.VK_LEFT ||
345
                        e.getKeyCode() == KeyEvent.VK_RIGHT)
346
                        log.append("Stopping robot\n");
347
                        isMoving = false;
348
                        csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 0", ColonetServerInterface.GLOBAL_DEST);
349
                        csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 0", ColonetServerInterface.GLOBAL_DEST);
350
        }
351
        public void keyTyped (KeyEvent e) {
352
                
353
        }
354
        
355
        /**
356
         * Listens for incoming data from the colonet server. 
357
         * This includes responses to requests for robot data.
358
         */
359
        class DataListener extends Thread
360
        {
361

    
362
                JTextArea log;
363
                BufferedReader reader;
364

    
365
                /**
366
                 * Create a new DataListener that listens for incoming data on the specified socket.
367
                 * @param log TextArea to which incoming messages should be printed.
368
                 * @param socket Socket on which to listen for data.
369
                 */
370
                public DataListener (JTextArea log)
371
                {
372
                        super("Colonet DataListener");
373
                        this.log = log;
374
                }
375
                
376
                public void run ()
377
                {
378
                        String line;
379
                        log.append("Started listener for responses\n");
380
                        while (!destroyed)
381
                        {
382
                                try {
383
                                        if (csi.isReady())
384
                                        {
385
                                                line = csi.getBufferedReader().readLine();
386
                                                if (line != null) log.append("Message from server: " + line + "\n");
387
                                        }
388
                                        Thread.sleep(500);
389
                                } catch (Exception e) {
390
                                        warn("Error: " + e);
391
                                }
392
                        }
393
                }
394

    
395
        }
396

    
397

    
398
        class WebcamLoader extends Thread 
399
        {
400

    
401
                URL path;
402
                Image image;
403
                MediaTracker mt;
404
                int BUFFER = 16;  // this is arbitrary. it makes the image look nice.
405
                
406
                public WebcamLoader (JApplet applet)
407
                {
408
                        super("Colonet WebcamLoader");
409
                        try {
410
                                path = new URL("http://roboclub1.frc.ri.cmu.edu/ColonetGUI/webcam/colonet.jpg");
411
                        } catch (MalformedURLException e) {
412
                                err("MalformedURLException.\nCannot load webcam image.");
413
                        }
414
                        mt = new MediaTracker(applet);
415
                }
416
                
417
                public void run ()
418
                {
419
                        while (!destroyed) {
420
                                try {
421
                                        Thread.sleep(1000);
422
                                        if (destroyed) return;
423
                                        if (image != null) image.flush();
424
                                        image = getImage(path);
425
                                        mt.addImage(image, 1);
426
                                        mt.waitForID(1);
427
                                        panelWebcam.getGraphics().drawImage(image, 
428
                                                BUFFER,        //dx1 - the x coordinate of the first corner of the destination rectangle.
429
                                                BUFFER,        //dy1 - the y coordinate of the first corner of the destination rectangle.
430
                                                panelWebcam.getWidth() - BUFFER,         //dx2 - the x coordinate of the second corner of the destination rectangle.
431
                                                panelWebcam.getHeight() - BUFFER,        //dy2 - the y coordinate of the second corner of the destination rectangle.
432
                                                0,        //sx1 - the x coordinate of the first corner of the source rectangle.
433
                                                0,        //sy1 - the y coordinate of the first corner of the source rectangle.
434
                                                image.getWidth(null),        //sx2 - the x coordinate of the second corner of the source rectangle.
435
                                                image.getHeight(null),        //sy2 - the y coordinate of the second corner of the source rectangle.
436
                                                null        //observer - object to be notified as more of the image is scaled and converted.
437
                                                );
438
                                                
439
                                } catch (InterruptedException e) {
440
                                        //Closing the browser window will probably couse an InterruptedException.
441
                                        //I can't think of anything else to do than let it happen and then return.
442
                                        return;
443
                                } catch (java.security.AccessControlException e) {
444
                                        warn("java.security.AccessControlException in WebcamLoader.\n" + 
445
                                                "The image cannot be loaded from the specified location.\n" + 
446
                                                "Make sure you are accessing this applet from the correct server.");
447
                                        destroyed = true;
448
                                }
449
                        }
450
                }
451
        }
452
        
453
        class SensorDataWindow extends JFrame implements ActionListener
454
        {
455
        
456
                JApplet applet;
457
                JTextArea log;
458
                JScrollPane spLog;
459
                JButton btnClose;
460
                JPanel panelButtons;
461
                SensorDataLoader sdl;
462
        
463
                public SensorDataWindow (JApplet applet)
464
                {
465
                        super("Sensor Data");
466
                        this.applet = applet;
467
                        
468
                        log = new JTextArea();
469
                        log.setEditable(false);
470
                        spLog = new JScrollPane(log, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
471
                        spLog.setBorder(BorderFactory.createTitledBorder("Log"));
472
                        
473
                        Container content = this.getContentPane();
474
                        content.setLayout(new BorderLayout());
475
                        content.add(spLog, BorderLayout.CENTER);
476
                        
477
                        btnClose = new JButton("Close Window");
478
                        btnClose.addActionListener(this);
479
                        panelButtons = new JPanel();
480
                        panelButtons.setLayout(new FlowLayout());
481
                        panelButtons.add(btnClose);
482
                        content.add(panelButtons, BorderLayout.SOUTH);
483
                        
484
                        //start thread to continuously update data
485
                        sdl = new SensorDataLoader(this, this.applet);
486
                        sdl.start();
487
                        
488
                        //if the window is closed,
489
                        //make sure we stop the thread.
490
                        this.addWindowListener(new SensorDataWindowListener());
491
                        
492
                }
493
                
494
                public void actionPerformed (ActionEvent event)
495
                {
496
                        Object source = event.getSource();
497
                        if (source == btnClose)
498
                        {
499
                                this.setVisible(false);
500
                                sdl.stopMe();
501
                        }
502
                }
503
                
504
                class SensorDataWindowListener extends WindowAdapter
505
                {
506
                        public SensorDataWindowListener ()
507
                        {
508
                                super();
509
                        }
510
                        public void windowClosing (WindowEvent e)
511
                        {
512
                                sdl.stopMe();
513
                        }
514
                }
515
                
516
        }
517
        
518
        class SensorDataLoader extends Thread
519
        {
520
        
521
                SensorDataWindow window;
522
                JApplet applet;
523
                boolean running;
524
        
525
                public SensorDataLoader (SensorDataWindow window, JApplet applet)
526
                {
527
                        this.window = window;
528
                        this.applet = applet;
529
                }
530
                
531
                public void run ()
532
                {
533
                        running = true;
534
                        log.append("Sensor data loading started.\n");
535
                        while (running)
536
                        {
537
                                try {
538
                                        Thread.sleep(2000);
539
                                } catch (InterruptedException e) {
540
                                        err("InterruptedException in SensorDataLoader\n" + e);
541
                                }
542
                                log.append("<update data here ...>\n");
543
                        }
544
                        log.append("Sensor data loading stopped.\n");
545
                }
546
                
547
                public void stopMe ()
548
                {
549
                        running = false;
550
                }
551
        
552
        }
553
        
554
}