root / trunk / code / projects / colonet / client / Colonet.java @ 633
History | View | Annotate | Download (40.1 KB)
1 | 32 | gtress | import javax.swing.*; |
---|---|---|---|
2 | 320 | gtress | import javax.swing.event.*; |
3 | import javax.imageio.*; |
||
4 | 32 | gtress | import java.awt.*; |
5 | import java.awt.image.*; |
||
6 | import java.awt.event.*; |
||
7 | import java.net.*; |
||
8 | import java.io.*; |
||
9 | 427 | gtress | import java.util.*; |
10 | 32 | gtress | |
11 | 320 | gtress | /**
|
12 | 531 | emarinel | * The Colonet Graphical User Interface Applet for use locally and over an internet connection.
|
13 | * @author Gregory Tress
|
||
14 | 527 | emarinel | *
|
15 | 531 | emarinel | * To generate javadoc on this file or other java files, use javadoc *.java -d doc, where doc
|
16 | * is the name of the folder into which the files should be written.
|
||
17 | 320 | gtress | */
|
18 | 579 | gtress | public class Colonet extends JApplet implements ActionListener, MouseInputListener, KeyListener, Runnable { |
19 | 320 | gtress | |
20 | 585 | gtress | // Used for painting
|
21 | 32 | gtress | final int BUFFER = 50; |
22 | final int RADIUS = 30; |
||
23 | 527 | emarinel | |
24 | 585 | gtress | // Used for the robot controller
|
25 | 590 | gtress | final int VECTOR_CONTROLLER_HEIGHT = 190; |
26 | final int VECTOR_CONTROLLER_WIDTH = 320; |
||
27 | 32 | gtress | |
28 | // Connection
|
||
29 | 527 | emarinel | JTextField txtHost;
|
30 | JTextField txtPort;
|
||
31 | JButton btnConnect;
|
||
32 | 414 | gtress | JButton btnGetXBeeIDs;
|
33 | 32 | gtress | JLabel lblConnectionStatus;
|
34 | 527 | emarinel | JTextArea txtInfo;
|
35 | 32 | gtress | JPanel panelConnect;
|
36 | JPanel panelServerInterface;
|
||
37 | 527 | emarinel | Socket socket;
|
38 | DataUpdater dataUpdater; |
||
39 | |||
40 | 32 | gtress | // Control
|
41 | JPanel panelControl;
|
||
42 | JTabbedPane tabPaneControl;
|
||
43 | JPanel panelRobotControl;
|
||
44 | JPanel panelRobotDirection;
|
||
45 | 320 | gtress | JPanel panelRobotDirectionButtons;
|
46 | 32 | gtress | JPanel panelRobotCommands;
|
47 | JButton btnF, btnB, btnL, btnR, btnActivate;
|
||
48 | 320 | gtress | JComboBox cmbRobotNum;
|
49 | JLabel lblBattery;
|
||
50 | 428 | gtress | JLabel lblSelected;
|
51 | 333 | gtress | BatteryIcon batteryIcon; |
52 | 320 | gtress | JPanel panelBattery;
|
53 | VectorController vectorController; |
||
54 | BufferedImage imageVectorControl;
|
||
55 | 427 | gtress | JButton btnAssignID;
|
56 | 428 | gtress | boolean setWaypoint;
|
57 | 429 | gtress | int setWaypointID;
|
58 | 428 | gtress | JButton btnCommand_MoveTo;
|
59 | 429 | gtress | JButton btnCommand_MoveAll;
|
60 | 320 | gtress | JButton btnCommand_StopTask;
|
61 | JButton btnCommand_ResumeTask;
|
||
62 | JButton btnCommand_ChargeNow;
|
||
63 | JButton btnCommand_StopCharging;
|
||
64 | 527 | emarinel | |
65 | 32 | gtress | // Task Manager
|
66 | JPanel panelTaskManager;
|
||
67 | JScrollPane spTaskManager;
|
||
68 | JPanel panelTaskManagerControls;
|
||
69 | JPanel panelTaskManagerControlsPriority;
|
||
70 | DefaultListModel taskListModel;
|
||
71 | JList taskList;
|
||
72 | JButton btnAddTask;
|
||
73 | JButton btnRemoveTask;
|
||
74 | JButton btnMoveTaskUp;
|
||
75 | JButton btnMoveTaskDown;
|
||
76 | 320 | gtress | JButton btnUpdateTasks;
|
77 | TaskAddWindow taskAddWindow; |
||
78 | 527 | emarinel | |
79 | 585 | gtress | // Webcam
|
80 | 320 | gtress | WebcamPanel panelWebcam; |
81 | 32 | gtress | GraphicsConfiguration gc;
|
82 | 320 | gtress | JTabbedPane tabPaneMain;
|
83 | 585 | gtress | WebcamLoader webcamLoader; |
84 | |||
85 | // Robots
|
||
86 | 531 | emarinel | volatile int selectedBot; //the user has selected this bot graphically |
87 | 556 | gtress | volatile java.util.Map <Integer, RobotIcon> robotIcons; //contains boundary shapes around bots for click detection |
88 | 320 | gtress | volatile int[] xbeeID; |
89 | 527 | emarinel | |
90 | 501 | gtress | Colonet self = this;
|
91 | 549 | gtress | volatile ColonetServerInterface csi;
|
92 | 579 | gtress | Thread paintThread;
|
93 | 32 | gtress | |
94 | public void init () { |
||
95 | 427 | gtress | // Set the default look and feel - choose one
|
96 | 574 | gtress | String laf = UIManager.getSystemLookAndFeelClassName(); |
97 | //String laf = UIManager.getCrossPlatformLookAndFeelClassName();
|
||
98 | 320 | gtress | //String laf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
|
99 | 531 | emarinel | try {
|
100 | UIManager.setLookAndFeel(laf);
|
||
101 | } catch (UnsupportedLookAndFeelException exc) { |
||
102 | System.err.println ("Warning: UnsupportedLookAndFeel: " + laf); |
||
103 | } catch (Exception exc) { |
||
104 | System.err.println ("Error loading " + laf + ": " + exc); |
||
105 | } |
||
106 | |||
107 | 32 | gtress | // We should invoke and wait to avoid browser display difficulties
|
108 | Runnable r = new Runnable() { |
||
109 | public void run() { |
||
110 | createAndShowGUI(); |
||
111 | } |
||
112 | }; |
||
113 | 531 | emarinel | |
114 | 32 | gtress | try {
|
115 | SwingUtilities.invokeAndWait(r);
|
||
116 | } catch (InterruptedException e) { |
||
117 | //Not really sure why we would be in this situation
|
||
118 | 320 | gtress | System.out.println("InterruptedException in init: " + e); |
119 | 32 | gtress | } catch (java.lang.reflect.InvocationTargetException e) {
|
120 | 320 | gtress | //This could happen for various reasons if there is a problem in createAndShowGUI
|
121 | e.printStackTrace(); |
||
122 | 32 | gtress | } |
123 | } |
||
124 | 527 | emarinel | |
125 | 32 | gtress | public void destroy () { |
126 | 633 | emarinel | if (csi != null) { |
127 | csi.disconnect(); |
||
128 | 570 | gtress | } |
129 | 32 | gtress | } |
130 | |||
131 | private synchronized void createAndShowGUI () { |
||
132 | 579 | gtress | paintThread = new Thread(this, "PaintThread"); |
133 | paintThread.start(); |
||
134 | 585 | gtress | |
135 | // Webcam
|
||
136 | 527 | emarinel | gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
|
137 | 320 | gtress | panelWebcam = new WebcamPanel();
|
138 | tabPaneMain = new JTabbedPane(); |
||
139 | 555 | emarinel | tabPaneMain.setFont(new Font("arial", Font.PLAIN, 16)); |
140 | 320 | gtress | tabPaneMain.add(panelWebcam, "Webcam");
|
141 | 527 | emarinel | |
142 | 585 | gtress | // Robots
|
143 | 428 | gtress | selectedBot = -1;
|
144 | 556 | gtress | robotIcons = new HashMap <Integer, RobotIcon> (); |
145 | 527 | emarinel | |
146 | 32 | gtress | // Connection area
|
147 | txtInfo = new JTextArea(); |
||
148 | txtInfo.setBorder(BorderFactory.createTitledBorder("Info")); |
||
149 | 470 | gtress | txtHost = new JTextField(this.getDocumentBase().getHost()); |
150 | 32 | gtress | txtHost.setBorder(BorderFactory.createTitledBorder("Host")); |
151 | txtPort = new JTextField("10123"); |
||
152 | txtPort.setBorder(BorderFactory.createTitledBorder("Port")); |
||
153 | btnConnect = new JButton("Connect"); |
||
154 | 555 | emarinel | btnConnect.setFont(new Font("arial", Font.BOLD, 16)); |
155 | 414 | gtress | btnGetXBeeIDs = new JButton("Get XBee IDs"); |
156 | 389 | gtress | getRootPane().setDefaultButton(btnConnect); |
157 | 32 | gtress | lblConnectionStatus = new JLabel("Status: Offline"); |
158 | panelConnect = new JPanel(); |
||
159 | panelConnect.setLayout(new GridLayout(6,1)); |
||
160 | panelConnect.add(lblConnectionStatus); |
||
161 | panelConnect.add(txtHost); |
||
162 | panelConnect.add(txtPort); |
||
163 | panelConnect.add(btnConnect); |
||
164 | 470 | gtress | //panelConnect.add(btnGetXBeeIDs);
|
165 | 32 | gtress | panelServerInterface = new JPanel(); |
166 | panelServerInterface.setLayout(new GridLayout(2,1)); |
||
167 | panelServerInterface.add(panelConnect); |
||
168 | 585 | gtress | panelServerInterface.add(txtInfo); |
169 | 527 | emarinel | |
170 | 32 | gtress | // Robot direction panel
|
171 | panelRobotDirection = new JPanel(); |
||
172 | 320 | gtress | panelRobotDirectionButtons = new JPanel(); |
173 | 555 | emarinel | |
174 | Font f = new Font(null, Font.PLAIN, 18); |
||
175 | btnF = new JButton("\u2191"); |
||
176 | btnF.setFont(f); |
||
177 | btnB = new JButton("\u2193"); |
||
178 | btnB.setFont(f); |
||
179 | btnL = new JButton("\u2190"); |
||
180 | btnL.setFont(f); |
||
181 | btnR = new JButton("\u2192"); |
||
182 | btnR.setFont(f); |
||
183 | btnActivate = new JButton("\u25A0"); |
||
184 | btnActivate.setFont(new Font(null, Font.BOLD, 36)); |
||
185 | |||
186 | 320 | gtress | panelRobotDirectionButtons.setLayout(new GridLayout(1,5)); |
187 | panelRobotDirectionButtons.add(btnActivate); |
||
188 | panelRobotDirectionButtons.add(btnF); |
||
189 | panelRobotDirectionButtons.add(btnB); |
||
190 | panelRobotDirectionButtons.add(btnL); |
||
191 | panelRobotDirectionButtons.add(btnR); |
||
192 | 527 | emarinel | |
193 | 341 | gtress | imageVectorControl = gc.createCompatibleImage(VECTOR_CONTROLLER_WIDTH, VECTOR_CONTROLLER_HEIGHT); |
194 | 320 | gtress | vectorController = new VectorController(imageVectorControl);
|
195 | panelRobotDirection.setLayout(new BorderLayout()); |
||
196 | 585 | gtress | panelRobotDirection.add(vectorController, BorderLayout.CENTER);
|
197 | 320 | gtress | panelRobotDirection.add(panelRobotDirectionButtons, BorderLayout.SOUTH);
|
198 | 527 | emarinel | |
199 | 32 | gtress | // Robot Control and Commands
|
200 | panelRobotCommands = new JPanel(); |
||
201 | 320 | gtress | panelRobotCommands.setLayout(new GridLayout(5,2)); |
202 | cmbRobotNum = new JComboBox(); |
||
203 | 333 | gtress | // Battery subset
|
204 | 514 | gtress | batteryIcon = new BatteryIcon(0); |
205 | 333 | gtress | lblBattery = new JLabel(batteryIcon); |
206 | 428 | gtress | lblSelected = new JLabel("None"); |
207 | // Command subset
|
||
208 | setWaypoint = false;
|
||
209 | 429 | gtress | setWaypointID = -1;
|
210 | 427 | gtress | btnAssignID = new JButton("Assign ID"); |
211 | 428 | gtress | btnCommand_MoveTo = new JButton("Move to ..."); |
212 | 429 | gtress | btnCommand_MoveAll = new JButton("Move all ..."); |
213 | 320 | gtress | btnCommand_StopTask = new JButton("Stop Current Task"); |
214 | btnCommand_ResumeTask = new JButton("Resume Current Task"); |
||
215 | btnCommand_ChargeNow = new JButton("Recharge Now"); |
||
216 | btnCommand_StopCharging = new JButton("Stop Recharging"); |
||
217 | panelRobotCommands.add(new JLabel("Select Robot to Control: ")); |
||
218 | panelRobotCommands.add(cmbRobotNum); |
||
219 | panelRobotCommands.add(new JLabel("Battery Level: ")); |
||
220 | panelRobotCommands.add(lblBattery); |
||
221 | 428 | gtress | panelRobotCommands.add(new JLabel("Selected Icon: ")); |
222 | panelRobotCommands.add(lblSelected); |
||
223 | 427 | gtress | panelRobotCommands.add(btnAssignID); |
224 | 429 | gtress | panelRobotCommands.add(new JLabel("")); |
225 | 428 | gtress | panelRobotCommands.add(btnCommand_MoveTo); |
226 | 429 | gtress | panelRobotCommands.add(btnCommand_MoveAll); |
227 | 427 | gtress | //panelRobotCommands.add(btnCommand_StopTask);
|
228 | //panelRobotCommands.add(btnCommand_ResumeTask);
|
||
229 | //panelRobotCommands.add(btnCommand_ChargeNow);
|
||
230 | //panelRobotCommands.add(btnCommand_StopCharging);
|
||
231 | 32 | gtress | panelRobotControl = new JPanel(); |
232 | panelRobotControl.setLayout(new GridLayout(2,1)); |
||
233 | panelRobotControl.add(panelRobotDirection); |
||
234 | panelRobotControl.add(panelRobotCommands); |
||
235 | 527 | emarinel | |
236 | 32 | gtress | // Task Manager
|
237 | panelTaskManager = new JPanel(); |
||
238 | panelTaskManager.setLayout(new BorderLayout()); |
||
239 | taskListModel = new DefaultListModel(); |
||
240 | taskList = new JList(taskListModel); |
||
241 | taskList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||
242 | taskList.setSelectedIndex(0);
|
||
243 | spTaskManager = new JScrollPane(taskList); |
||
244 | panelTaskManagerControls = new JPanel(); |
||
245 | 320 | gtress | panelTaskManagerControls.setLayout(new GridLayout(1,4)); |
246 | 32 | gtress | panelTaskManagerControlsPriority = new JPanel(); |
247 | panelTaskManagerControlsPriority.setLayout(new GridLayout(1,2)); |
||
248 | btnAddTask = new JButton("Add..."); |
||
249 | btnRemoveTask = new JButton("Remove"); |
||
250 | btnMoveTaskUp = new JButton("^"); |
||
251 | btnMoveTaskDown = new JButton("v"); |
||
252 | 320 | gtress | btnUpdateTasks = new JButton("Update"); |
253 | 32 | gtress | panelTaskManagerControlsPriority.add(btnMoveTaskUp); |
254 | panelTaskManagerControlsPriority.add(btnMoveTaskDown); |
||
255 | panelTaskManagerControls.add(btnAddTask); |
||
256 | panelTaskManagerControls.add(btnRemoveTask); |
||
257 | 320 | gtress | panelTaskManagerControls.add(btnUpdateTasks); |
258 | 32 | gtress | panelTaskManagerControls.add(panelTaskManagerControlsPriority); |
259 | panelTaskManager.add(spTaskManager, BorderLayout.CENTER);
|
||
260 | panelTaskManager.add(panelTaskManagerControls, BorderLayout.SOUTH);
|
||
261 | panelTaskManager.add(new JLabel("Current Task Queue"), BorderLayout.NORTH); |
||
262 | 320 | gtress | taskAddWindow = new TaskAddWindow();
|
263 | 527 | emarinel | |
264 | 32 | gtress | // Main control mechanism
|
265 | panelControl = new JPanel(); |
||
266 | panelControl.setLayout(new GridLayout(1,1)); |
||
267 | tabPaneControl = new JTabbedPane(JTabbedPane.TOP); |
||
268 | 555 | emarinel | tabPaneControl.setFont(new Font("arial", Font.PLAIN, 16)); |
269 | 341 | gtress | tabPaneControl.setPreferredSize(new Dimension(VECTOR_CONTROLLER_WIDTH, 0)); |
270 | 32 | gtress | tabPaneControl.addTab("Connection", panelServerInterface);
|
271 | tabPaneControl.addTab("Robots", panelRobotControl);
|
||
272 | 514 | gtress | //tabPaneControl.addTab("Tasks", panelTaskManager);
|
273 | 32 | gtress | panelControl.add(tabPaneControl); |
274 | 527 | emarinel | |
275 | 32 | gtress | |
276 | 320 | gtress | // Put all elements in the ContentPane
|
277 | 32 | gtress | this.getContentPane().setLayout(new BorderLayout()); |
278 | 320 | gtress | this.getContentPane().add(tabPaneMain, BorderLayout.CENTER); |
279 | 32 | gtress | this.getContentPane().add(panelControl, BorderLayout.EAST); |
280 | this.setVisible(true); |
||
281 | 559 | gtress | |
282 | // Disable components before connecting
|
||
283 | btnConnect.setText("Connect");
|
||
284 | lblConnectionStatus.setText("Status: Disconnected");
|
||
285 | btnF.setEnabled(false);
|
||
286 | btnB.setEnabled(false);
|
||
287 | btnL.setEnabled(false);
|
||
288 | btnR.setEnabled(false);
|
||
289 | btnActivate.setEnabled(false);
|
||
290 | cmbRobotNum.setEnabled(false);
|
||
291 | btnAssignID.setEnabled(false);
|
||
292 | btnCommand_MoveTo.setEnabled(false);
|
||
293 | btnCommand_MoveAll.setEnabled(false);
|
||
294 | 527 | emarinel | |
295 | 320 | gtress | /* Add all listeners here */
|
296 | // Task Management
|
||
297 | 32 | gtress | btnAddTask.addActionListener(this);
|
298 | btnRemoveTask.addActionListener(this);
|
||
299 | btnMoveTaskUp.addActionListener(this);
|
||
300 | btnMoveTaskDown.addActionListener(this);
|
||
301 | 320 | gtress | btnUpdateTasks.addActionListener(this);
|
302 | // Robot Control
|
||
303 | btnF.addActionListener(this);
|
||
304 | btnB.addActionListener(this);
|
||
305 | btnL.addActionListener(this);
|
||
306 | btnR.addActionListener(this);
|
||
307 | btnF.addKeyListener(this);
|
||
308 | btnB.addKeyListener(this);
|
||
309 | btnL.addKeyListener(this);
|
||
310 | btnR.addKeyListener(this);
|
||
311 | btnActivate.addActionListener(this);
|
||
312 | btnActivate.addKeyListener(this);
|
||
313 | cmbRobotNum.addKeyListener(this);
|
||
314 | 428 | gtress | btnCommand_MoveTo.addActionListener(this);
|
315 | 429 | gtress | btnCommand_MoveAll.addActionListener(this);
|
316 | 320 | gtress | btnCommand_StopTask.addActionListener(this);
|
317 | btnCommand_ResumeTask.addActionListener(this);
|
||
318 | btnCommand_ChargeNow.addActionListener(this);
|
||
319 | btnCommand_StopCharging.addActionListener(this);
|
||
320 | // Other
|
||
321 | 32 | gtress | btnConnect.addActionListener(this);
|
322 | 414 | gtress | btnGetXBeeIDs.addActionListener(this);
|
323 | 427 | gtress | btnAssignID.addActionListener(this);
|
324 | 527 | emarinel | panelWebcam.addMouseListener(this);
|
325 | 32 | gtress | } |
326 | 527 | emarinel | |
327 | 428 | gtress | public void paint (Graphics g) { |
328 | 531 | emarinel | super.paint(g);
|
329 | 428 | gtress | } |
330 | 527 | emarinel | |
331 | 429 | gtress | public void update (Graphics g) { |
332 | 531 | emarinel | paint(g); |
333 | 429 | gtress | } |
334 | 579 | gtress | |
335 | public void run () { |
||
336 | final int PAINT_DELAY = 300; |
||
337 | while (true) { |
||
338 | try {
|
||
339 | Thread.sleep(PAINT_DELAY);
|
||
340 | } catch (Exception e) { |
||
341 | System.out.println(e);
|
||
342 | return;
|
||
343 | } |
||
344 | repaint(); |
||
345 | } |
||
346 | } |
||
347 | 527 | emarinel | |
348 | /**
|
||
349 | 585 | gtress | * Gets the JTextArea used for displaying debugging information.
|
350 | 333 | gtress | *
|
351 | 585 | gtress | * @return the JTextArea where debugging information can be displayed.
|
352 | 527 | emarinel | */
|
353 | 585 | gtress | public JTextArea getInfoPanel () { |
354 | return txtInfo;
|
||
355 | 320 | gtress | } |
356 | 527 | emarinel | |
357 | /**
|
||
358 | 333 | gtress | * Parses a String containing BOM matrix information.
|
359 | 531 | emarinel | * The ColonetServerInterface receives lines of the BOM matrix. (For encoding
|
360 | * information, see the ColonetServerInterface documentation.) The entire matrix is passed
|
||
361 | 527 | emarinel | * to the client when requested. This method takes a string of the form
|
362 | 333 | gtress | * "[command code] [command code] [number of robots] [data0] [data1] ..."
|
363 | 527 | emarinel | * with tokens separated by spaces and containing no brackets.
|
364 | 333 | gtress | * The [command code]s are predefined values identifying this String as a BOM data
|
365 | 527 | emarinel | * String, [number of robots] is an integer, and the values that follow are
|
366 | 531 | emarinel | * the sensor readings of the robots in order, starting with robot 0. Only [number of robots]^2
|
367 | * data entries will be read. The matrix values are saved locally until the next String is parsed.
|
||
368 | 333 | gtress | *
|
369 | 527 | emarinel | *
|
370 | 333 | gtress | * @param line the String containing BOM matrix information.
|
371 | * @throws ArrayIndexOutOfBoundsException if there are fewer than [number of robots]^2 data entries in the String
|
||
372 | */
|
||
373 | 320 | gtress | public void parseMatrix (String line) { |
374 | 585 | gtress | txtInfo.setText("");
|
375 | 320 | gtress | String [] str = line.split(" "); |
376 | int num = Integer.parseInt(str[2]); |
||
377 | for (int i = 0; i < num; i++) { |
||
378 | for (int j = 0; j < num; j++) { |
||
379 | String next = str[3 + i*num + j]; |
||
380 | 531 | emarinel | if (next.equals("-1")) { |
381 | 585 | gtress | txtInfo.append("-");
|
382 | 531 | emarinel | } else {
|
383 | 585 | gtress | txtInfo.append(next); |
384 | 531 | emarinel | } |
385 | |||
386 | if (j < num - 1) { |
||
387 | 585 | gtress | txtInfo.append(" ");
|
388 | 531 | emarinel | } |
389 | 320 | gtress | } |
390 | 531 | emarinel | |
391 | if (i < num - 1) { |
||
392 | 585 | gtress | txtInfo.append("\n");
|
393 | 531 | emarinel | } |
394 | 136 | gtress | } |
395 | 510 | gtress | repaint(); |
396 | 136 | gtress | } |
397 | 527 | emarinel | |
398 | 420 | gtress | public void connect () { |
399 | 559 | gtress | if (csi != null) |
400 | return;
|
||
401 | csi = new ColonetServerInterface(self);
|
||
402 | csi.connect(txtHost.getText(), txtPort.getText()); |
||
403 | if (!csi.isReady()) {
|
||
404 | csi = null;
|
||
405 | return;
|
||
406 | } |
||
407 | webcamLoader = new WebcamLoader(self);
|
||
408 | dataUpdater = new DataUpdater();
|
||
409 | dataUpdater.start(); |
||
410 | webcamLoader.start(); |
||
411 | Runnable r = new Runnable() { |
||
412 | public void run () { |
||
413 | btnConnect.setText("Disconnect");
|
||
414 | lblConnectionStatus.setText("Status: Connected");
|
||
415 | btnF.setEnabled(true);
|
||
416 | btnB.setEnabled(true);
|
||
417 | btnL.setEnabled(true);
|
||
418 | btnR.setEnabled(true);
|
||
419 | btnActivate.setEnabled(true);
|
||
420 | cmbRobotNum.setEnabled(true);
|
||
421 | btnAssignID.setEnabled(true);
|
||
422 | btnCommand_MoveTo.setEnabled(true);
|
||
423 | btnCommand_MoveAll.setEnabled(true);
|
||
424 | } |
||
425 | }; |
||
426 | SwingUtilities.invokeLater(r);
|
||
427 | 420 | gtress | } |
428 | 527 | emarinel | |
429 | 420 | gtress | public void disconnect () { |
430 | 590 | gtress | try {
|
431 | dataUpdater.interrupt(); |
||
432 | } catch (Exception e) { |
||
433 | } |
||
434 | 559 | gtress | csi = null;
|
435 | Runnable r = new Runnable() { |
||
436 | public void run () { |
||
437 | btnConnect.setText("Connect");
|
||
438 | lblConnectionStatus.setText("Status: Disconnected");
|
||
439 | btnF.setEnabled(false);
|
||
440 | btnB.setEnabled(false);
|
||
441 | btnL.setEnabled(false);
|
||
442 | btnR.setEnabled(false);
|
||
443 | btnActivate.setEnabled(false);
|
||
444 | cmbRobotNum.setEnabled(false);
|
||
445 | btnAssignID.setEnabled(false);
|
||
446 | btnCommand_MoveTo.setEnabled(false);
|
||
447 | btnCommand_MoveAll.setEnabled(false);
|
||
448 | } |
||
449 | }; |
||
450 | SwingUtilities.invokeLater(r);
|
||
451 | 420 | gtress | } |
452 | 527 | emarinel | |
453 | 333 | gtress | /**
|
454 | * Parses a String containing a task queue update.
|
||
455 | * Format is currently not specified.
|
||
456 | * This method currently does nothing.
|
||
457 | *
|
||
458 | * @param line the String containing task queue update information.
|
||
459 | */
|
||
460 | 320 | gtress | public void parseQueue (String line) { |
461 | 585 | gtress | |
462 | 320 | gtress | } |
463 | 527 | emarinel | |
464 | 333 | gtress | /**
|
465 | * Parses a String containing XBee ID values.
|
||
466 | 531 | emarinel | * The ColonetServerInterface receives Strings of XBee information. (For encoding
|
467 | * information, see the ColonetServerInterface documentation.) This method takes
|
||
468 | 333 | gtress | * a string of the form "[command code] [command code] [number of robots] [id0] [id1] ..."
|
469 | 527 | emarinel | * with tokens separated by spaces and containing no brackets.
|
470 | 333 | gtress | * The [command code]s are predefined values identifying this String as an XBee
|
471 | 527 | emarinel | * ID String, [number of robots] is an integer, and the values that follow are
|
472 | 531 | emarinel | * the IDs of the robots in order, starting with robot 0. Only [number of robots]
|
473 | * will be read. The ID values are saved locally until the next String is parsed.
|
||
474 | 333 | gtress | * The purpose of having this list is to ensure that robots are properly identified for control purposes.
|
475 | 527 | emarinel | * This keeps robot identification consistent between sessions and prevents arbitrary assignment.
|
476 | 333 | gtress | *
|
477 | * @param line the String containing XBee ID information.
|
||
478 | * @throws ArrayIndexOutOfBoundsException if there are fewer than [number of robots] IDs in the String
|
||
479 | * @see ColonetServerInterface#sendXBeeIDRequest()
|
||
480 | */
|
||
481 | 320 | gtress | public void parseXBeeIDs (String line) { |
482 | String [] str = line.split(" "); |
||
483 | int num = Integer.parseInt(str[2]); |
||
484 | xbeeID = new int[num]; |
||
485 | 531 | emarinel | for (int i = 0; i < num; i++) { |
486 | 320 | gtress | xbeeID[i] = Integer.parseInt(str[i+3]); |
487 | 531 | emarinel | } |
488 | 527 | emarinel | |
489 | 320 | gtress | //update the list of robots to control
|
490 | //but save the old value first
|
||
491 | Object oldSelection = cmbRobotNum.getSelectedItem();
|
||
492 | cmbRobotNum.removeAllItems(); |
||
493 | 531 | emarinel | cmbRobotNum.addItem(new String(" All ")); |
494 | for (int i = 0; i < num; i++) { |
||
495 | 320 | gtress | cmbRobotNum.addItem(new String("" + xbeeID[i])); |
496 | 531 | emarinel | } |
497 | 320 | gtress | cmbRobotNum.setSelectedItem(oldSelection); |
498 | 510 | gtress | repaint(); |
499 | 320 | gtress | } |
500 | 527 | emarinel | |
501 | 333 | gtress | /**
|
502 | * Parses a String containing battery information.
|
||
503 | 531 | emarinel | * The ColonetServerInterface receives Strings of battery information. (For encoding
|
504 | * information, see the ColonetServerInterface documentation.) This method takes
|
||
505 | 333 | gtress | * a string of the form "[command code] [command code] [robot ID] [value]"
|
506 | 527 | emarinel | * with tokens separated by spaces and containing no brackets.
|
507 | 333 | gtress | * The [command code]s are predefined values identifying this String as a battery
|
508 | * information String, [robot ID] is an integer, and [value] is a battery measurement.
|
||
509 | * This updates the batery information for a single robot.
|
||
510 | *
|
||
511 | 527 | emarinel | *
|
512 | 333 | gtress | * @param line the String containing battery information.
|
513 | * @see ColonetServerInterface#sendBatteryRequest(int)
|
||
514 | */
|
||
515 | 320 | gtress | public void parseBattery (String line) { |
516 | 625 | gtress | int botNum, level;
|
517 | System.out.println("Got battery update:" + line); |
||
518 | try {
|
||
519 | String [] str = line.split(" "); |
||
520 | botNum = Integer.parseInt(str[2]); |
||
521 | level = Integer.parseInt(str[3]); |
||
522 | } catch (NumberFormatException e) { |
||
523 | System.out.println("Could not parse battery update"); |
||
524 | return;
|
||
525 | } |
||
526 | 531 | emarinel | |
527 | 561 | gtress | RobotIcon r = robotIcons.get(botNum); |
528 | if (r != null) { |
||
529 | 625 | gtress | r.battery = batteryIcon.convert(level); // set contextual battery meter
|
530 | batteryIcon.setLevel(level); // set solo battery meter
|
||
531 | System.out.println("Set " + r.id + " battery value to " + level); |
||
532 | 425 | gtress | } |
533 | 510 | gtress | repaint(); |
534 | 320 | gtress | } |
535 | 527 | emarinel | |
536 | 459 | gtress | /**
|
537 | 527 | emarinel | * Parses a String containing visual robot position information along with
|
538 | 459 | gtress | * canonical ID assignments.
|
539 | */
|
||
540 | public void parsePositions (String line) { |
||
541 | String [] str = line.split(" "); |
||
542 | 556 | gtress | java.util.Map <Integer, RobotIcon> newMap = new HashMap <Integer, RobotIcon> (); |
543 | 527 | emarinel | |
544 | 459 | gtress | for (int i = 2; i < str.length; i+=3) { |
545 | int id = Integer.parseInt(str[i]); |
||
546 | int x = Integer.parseInt(str[i+1]); |
||
547 | int y = Integer.parseInt(str[i+2]); |
||
548 | 470 | gtress | RobotIcon newIcon = new RobotIcon(id, x, y);
|
549 | 625 | gtress | // Save previous battery value
|
550 | if (robotIcons.get(id) != null) |
||
551 | newIcon.battery = robotIcons.get(id).battery; |
||
552 | 531 | emarinel | if (newIcon.id >= 0) { |
553 | newIcon.color = Color.GREEN;
|
||
554 | } |
||
555 | 556 | gtress | newMap.put(id, newIcon); |
556 | 459 | gtress | } |
557 | 556 | gtress | robotIcons = newMap; |
558 | 510 | gtress | repaint(); |
559 | 459 | gtress | } |
560 | 527 | emarinel | |
561 | 32 | gtress | //
|
562 | 320 | gtress | // MouseListener methods
|
563 | 32 | gtress | //
|
564 | 501 | gtress | public void mousePressed(MouseEvent e) { |
565 | 531 | emarinel | //Start a new Thread to handle the MouseEvent
|
566 | (new MouseHandler(e)).start();
|
||
567 | 579 | gtress | repaint(); |
568 | 501 | gtress | } |
569 | 320 | gtress | public void mouseExited(MouseEvent e) { |
570 | } |
||
571 | public void mouseEntered(MouseEvent e) { |
||
572 | } |
||
573 | public void mouseReleased(MouseEvent e) { |
||
574 | } |
||
575 | public void mouseClicked(MouseEvent e) { |
||
576 | } |
||
577 | public void mouseDragged(MouseEvent e) { |
||
578 | } |
||
579 | public void mouseMoved(MouseEvent e) { |
||
580 | } |
||
581 | 527 | emarinel | |
582 | 320 | gtress | //
|
583 | // KeyListener methods
|
||
584 | //
|
||
585 | public void keyPressed (KeyEvent e) { |
||
586 | 503 | gtress | //Start a new Thread to handle the KeyEvent
|
587 | 531 | emarinel | (new KeyHandler(e)).start();
|
588 | 579 | gtress | repaint(); |
589 | 181 | gtress | } |
590 | 320 | gtress | public void keyReleased (KeyEvent e) { |
591 | } |
||
592 | public void keyTyped (KeyEvent e) { |
||
593 | } |
||
594 | 527 | emarinel | |
595 | 320 | gtress | //
|
596 | // ActionListener method
|
||
597 | //
|
||
598 | public void actionPerformed (ActionEvent e) { |
||
599 | 501 | gtress | // Start a new Thread to handle the ActionEvent
|
600 | 510 | gtress | (new ActionHandler(e)).start();
|
601 | 579 | gtress | repaint(); |
602 | 501 | gtress | } |
603 | 527 | emarinel | |
604 | 501 | gtress | class MouseHandler extends Thread { |
605 | 531 | emarinel | MouseEvent e;
|
606 | 527 | emarinel | |
607 | 531 | emarinel | public MouseHandler (MouseEvent event) { |
608 | super("MouseHandler"); |
||
609 | this.e = event;
|
||
610 | } |
||
611 | 527 | emarinel | |
612 | 531 | emarinel | public void run () { |
613 | Point pt = panelWebcam.convertClick(e);
|
||
614 | 527 | emarinel | |
615 | 531 | emarinel | // If we are selecting a waypoint (destination) for a specific bot
|
616 | 556 | gtress | if (setWaypoint && setWaypointID >= 0) { |
617 | 531 | emarinel | setWaypoint = false;
|
618 | panelWebcam.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); |
||
619 | if (selectedBot < 0) { |
||
620 | return;
|
||
621 | } |
||
622 | 556 | gtress | |
623 | RobotIcon r = robotIcons.get(selectedBot); |
||
624 | if (r != null) { |
||
625 | r.destx = pt.x; |
||
626 | r.desty = pt.y; |
||
627 | if (csi != null) { |
||
628 | csi.sendAbsoluteMove(r.id, r.destx, r.desty); |
||
629 | 545 | gtress | } |
630 | 539 | emarinel | } |
631 | 527 | emarinel | |
632 | 531 | emarinel | return;
|
633 | } |
||
634 | 527 | emarinel | |
635 | 531 | emarinel | // Right-click also means we are moving a robot
|
636 | if (e.getButton() == MouseEvent.BUTTON2 || e.getButton() == MouseEvent.BUTTON3) { |
||
637 | if (selectedBot < 0) { |
||
638 | return;
|
||
639 | } |
||
640 | 527 | emarinel | |
641 | 556 | gtress | RobotIcon r = robotIcons.get(selectedBot); |
642 | if (r != null) { |
||
643 | r.destx = pt.x; |
||
644 | r.desty = pt.y; |
||
645 | if (csi != null) { |
||
646 | csi.sendAbsoluteMove(r.id, r.destx, r.desty); |
||
647 | 545 | gtress | } |
648 | 531 | emarinel | } |
649 | 527 | emarinel | |
650 | 531 | emarinel | return;
|
651 | } |
||
652 | 527 | emarinel | |
653 | 531 | emarinel | // If we are setting all waypoints
|
654 | if (setWaypoint) {
|
||
655 | setWaypoint = false;
|
||
656 | panelWebcam.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); |
||
657 | 596 | gtress | for (Map.Entry<Integer,RobotIcon> entry : robotIcons.entrySet()) { |
658 | RobotIcon r = entry.getValue(); |
||
659 | 531 | emarinel | r.destx = pt.x; |
660 | r.desty = pt.y; |
||
661 | } |
||
662 | return;
|
||
663 | } |
||
664 | 527 | emarinel | |
665 | 531 | emarinel | // Otherwise, we are selecting a bot, or doing nothing
|
666 | 596 | gtress | for (Map.Entry<Integer,RobotIcon> entry : robotIcons.entrySet()) { |
667 | RobotIcon r = entry.getValue(); |
||
668 | 531 | emarinel | if (r.contains(pt.x, pt.y)) {
|
669 | 545 | gtress | selectedBot = r.id; |
670 | lblSelected.setText("" + r.id);
|
||
671 | 503 | gtress | // Try to select the clicked bot, if its XBee ID is detected.
|
672 | for (int j = 1; j < cmbRobotNum.getItemCount(); j++) { |
||
673 | 545 | gtress | if (Integer.parseInt(cmbRobotNum.getItemAt(j).toString()) == selectedBot) { |
674 | 503 | gtress | cmbRobotNum.setSelectedIndex(j); |
675 | 531 | emarinel | } |
676 | 503 | gtress | } |
677 | return;
|
||
678 | 531 | emarinel | } |
679 | } |
||
680 | 527 | emarinel | |
681 | 531 | emarinel | } |
682 | 320 | gtress | } |
683 | 527 | emarinel | |
684 | 503 | gtress | class KeyHandler extends Thread { |
685 | KeyEvent e;
|
||
686 | 527 | emarinel | |
687 | 503 | gtress | public KeyHandler (KeyEvent event) { |
688 | super("KeyHandler"); |
||
689 | this.e = event;
|
||
690 | } |
||
691 | 527 | emarinel | |
692 | 503 | gtress | public void run () { |
693 | int code = e.getKeyCode();
|
||
694 | if (code == KeyEvent.VK_UP) { |
||
695 | vectorController.setMaxForward(); |
||
696 | vectorController.sendToServer(); |
||
697 | } else if (code == KeyEvent.VK_DOWN) { |
||
698 | vectorController.setMaxReverse(); |
||
699 | vectorController.sendToServer(); |
||
700 | } else if (code == KeyEvent.VK_LEFT) { |
||
701 | vectorController.setMaxLeft(); |
||
702 | vectorController.sendToServer(); |
||
703 | } else if (code == KeyEvent.VK_RIGHT) { |
||
704 | vectorController.setMaxRight(); |
||
705 | vectorController.sendToServer(); |
||
706 | } else if (code == KeyEvent.VK_S) { |
||
707 | vectorController.setZero(); |
||
708 | vectorController.sendToServer(); |
||
709 | } |
||
710 | } |
||
711 | } |
||
712 | 527 | emarinel | |
713 | 501 | gtress | class ActionHandler extends Thread { |
714 | 531 | emarinel | ActionEvent e;
|
715 | 527 | emarinel | |
716 | 531 | emarinel | public ActionHandler (ActionEvent event) { |
717 | super("ActionHandler"); |
||
718 | this.e = event;
|
||
719 | } |
||
720 | 527 | emarinel | |
721 | 531 | emarinel | public void run () { |
722 | Object source = e.getSource();
|
||
723 | 527 | emarinel | |
724 | 531 | emarinel | // General Actions
|
725 | if (source == btnConnect) {
|
||
726 | if (csi == null) { |
||
727 | connect(); |
||
728 | } else {
|
||
729 | disconnect(); |
||
730 | } |
||
731 | } else if (source == btnGetXBeeIDs) { |
||
732 | csi.sendXBeeIDRequest(); |
||
733 | } else if (source == btnAssignID) { |
||
734 | String message;
|
||
735 | 556 | gtress | if (selectedBot < 0) { |
736 | 531 | emarinel | message = "That robot is unidentified. Please specify its ID.";
|
737 | } else {
|
||
738 | 556 | gtress | message = "That robot has ID " + selectedBot + ". You may reassign it now."; |
739 | 531 | emarinel | } |
740 | String result = JOptionPane.showInputDialog(self, message, "Robot Identification", JOptionPane.QUESTION_MESSAGE); |
||
741 | if (result == null) { |
||
742 | return;
|
||
743 | } |
||
744 | int newID = -1; |
||
745 | try {
|
||
746 | newID = Integer.parseInt(result);
|
||
747 | } catch (Exception ex) { |
||
748 | csi.warn("Invalid ID.");
|
||
749 | return;
|
||
750 | } |
||
751 | // Assign new ID and update display
|
||
752 | 549 | gtress | if (csi != null) { |
753 | 556 | gtress | csi.sendIDAssignment(selectedBot, newID); |
754 | 549 | gtress | } |
755 | 556 | gtress | selectedBot = newID; |
756 | 545 | gtress | lblSelected.setText("" + newID);
|
757 | 531 | emarinel | } else if (source == btnF) { // Robot Movement Controls |
758 | vectorController.setMaxForward(); |
||
759 | vectorController.sendToServer(); |
||
760 | } else if (source == btnB) { |
||
761 | vectorController.setMaxReverse(); |
||
762 | vectorController.sendToServer(); |
||
763 | } else if (source == btnL) { |
||
764 | vectorController.setMaxLeft(); |
||
765 | vectorController.sendToServer(); |
||
766 | } else if (source == btnR) { |
||
767 | vectorController.setMaxRight(); |
||
768 | vectorController.sendToServer(); |
||
769 | } else if (source == btnActivate) { |
||
770 | vectorController.setZero(); |
||
771 | vectorController.sendToServer(); |
||
772 | } else if (source == btnCommand_MoveTo) { // Robot Commands (non-movement) |
||
773 | if (selectedBot < 0) { |
||
774 | return;
|
||
775 | } |
||
776 | panelWebcam.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); |
||
777 | setWaypoint = true;
|
||
778 | setWaypointID = selectedBot; |
||
779 | } else if (source == btnCommand_MoveAll) { |
||
780 | panelWebcam.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); |
||
781 | setWaypoint = true;
|
||
782 | setWaypointID = -1;
|
||
783 | } else if (source == btnCommand_StopTask) { |
||
784 | 527 | emarinel | |
785 | 531 | emarinel | } else if (source == btnCommand_ResumeTask) { |
786 | 527 | emarinel | |
787 | 531 | emarinel | } else if (source == btnCommand_ChargeNow) { |
788 | 527 | emarinel | |
789 | 531 | emarinel | } else if (source == btnCommand_StopCharging) { |
790 | 527 | emarinel | |
791 | 531 | emarinel | } else if (source == btnAddTask) { // Queue Management |
792 | taskAddWindow.prompt(); |
||
793 | } else if (source == btnRemoveTask) { |
||
794 | if (taskList.getSelectedIndex() >= 0) { |
||
795 | csi.sendQueueRemove(taskList.getSelectedIndex()); |
||
796 | } |
||
797 | csi.sendQueueUpdate(); |
||
798 | } else if (source == btnMoveTaskUp) { |
||
799 | csi.sendQueueReorder(taskList.getSelectedIndex(), taskList.getSelectedIndex() - 1);
|
||
800 | csi.sendQueueUpdate(); |
||
801 | } else if (source == btnMoveTaskDown) { |
||
802 | csi.sendQueueReorder(taskList.getSelectedIndex(), taskList.getSelectedIndex() + 1);
|
||
803 | csi.sendQueueUpdate(); |
||
804 | } else if (source == btnUpdateTasks) { |
||
805 | csi.sendQueueUpdate(); |
||
806 | } |
||
807 | 527 | emarinel | |
808 | 531 | emarinel | } |
809 | 32 | gtress | } |
810 | 527 | emarinel | |
811 | 32 | gtress | /*
|
812 | 531 | emarinel | * DataUpdater thread.
|
813 | * The purpose of this thread is to request data from the server at regular intervals.
|
||
814 | 32 | gtress | *
|
815 | */
|
||
816 | 320 | gtress | class DataUpdater extends Thread { |
817 | 633 | emarinel | final int DATAUPDATER_DELAY = 200; |
818 | 320 | gtress | public DataUpdater () {
|
819 | super("Colonet DataUpdater"); |
||
820 | } |
||
821 | 527 | emarinel | |
822 | 625 | gtress | public synchronized void run () { |
823 | 320 | gtress | while (true) { |
824 | try {
|
||
825 | //request more data
|
||
826 | if (csi != null && csi.isReady()) { |
||
827 | 539 | emarinel | csi.sendPositionRequest(); |
828 | 425 | gtress | csi.sendXBeeIDRequest(); |
829 | 633 | emarinel | for (Map.Entry<Integer,RobotIcon> entry : robotIcons.entrySet()) { |
830 | RobotIcon r = entry.getValue(); |
||
831 | int id = r.id;
|
||
832 | if (id >= 0) { |
||
833 | csi.sendBatteryRequest(id); |
||
834 | System.out.println("Sent battery request (" + id + ")"); |
||
835 | } |
||
836 | 425 | gtress | } |
837 | 320 | gtress | } |
838 | Thread.sleep(DATAUPDATER_DELAY);
|
||
839 | } catch (InterruptedException e) { |
||
840 | return;
|
||
841 | 625 | gtress | } catch (NullPointerException e) { |
842 | // This probably indicates that an object was destroyed by shutdown.
|
||
843 | return;
|
||
844 | 527 | emarinel | } |
845 | 320 | gtress | } |
846 | } |
||
847 | } |
||
848 | 527 | emarinel | |
849 | 320 | gtress | /*
|
850 | 531 | emarinel | * GraphicsPanel class
|
851 | * An extension of JPanel, designed for holding an image that will be repainted regularly.
|
||
852 | 320 | gtress | */
|
853 | class GraphicsPanel extends JPanel { |
||
854 | protected Image img; |
||
855 | 527 | emarinel | |
856 | 320 | gtress | public GraphicsPanel (Image img) { |
857 | 510 | gtress | this(img, true); |
858 | 136 | gtress | } |
859 | 527 | emarinel | |
860 | 341 | gtress | public GraphicsPanel (Image img, boolean isDoubleBuffered) { |
861 | 320 | gtress | super(isDoubleBuffered);
|
862 | this.img = img;
|
||
863 | } |
||
864 | 527 | emarinel | |
865 | 320 | gtress | public void paint (Graphics g) { |
866 | // Place the buffered image on the screen, inside the panel
|
||
867 | g.drawImage(img, 0, 0, Color.WHITE, this); |
||
868 | } |
||
869 | } |
||
870 | 527 | emarinel | |
871 | 320 | gtress | /*
|
872 | 531 | emarinel | * WebcamPanel class
|
873 | * Enables more efficient image handling in a component-controlled environment
|
||
874 | 320 | gtress | */
|
875 | class WebcamPanel extends JPanel { |
||
876 | 561 | gtress | final int BORDER = 16; // this is arbitrary. it makes the image look nice inside a border. |
877 | final int BATTERY_WIDTH = 50; |
||
878 | final int BATTERY_HEIGHT = 10; |
||
879 | 320 | gtress | volatile BufferedImage img; |
880 | 511 | gtress | BufferedImage buffer;
|
881 | 527 | emarinel | |
882 | 320 | gtress | public WebcamPanel () {
|
883 | 517 | gtress | super(true); |
884 | 320 | gtress | } |
885 | 527 | emarinel | |
886 | 506 | gtress | public synchronized void setImage (BufferedImage newimg) { |
887 | 320 | gtress | if (img != null) { |
888 | img.flush(); |
||
889 | 273 | gtress | } |
890 | 429 | gtress | System.gc();
|
891 | 320 | gtress | img = newimg; |
892 | 510 | gtress | repaint(); |
893 | 270 | gtress | } |
894 | 527 | emarinel | |
895 | 506 | gtress | public synchronized void paint (Graphics g) { |
896 | 533 | emarinel | if (img == null) { |
897 | 427 | gtress | return;
|
898 | 533 | emarinel | } |
899 | 527 | emarinel | |
900 | 511 | gtress | // Calculate scaling
|
901 | 470 | gtress | int maxWidth = getWidth() - 2*BORDER; |
902 | int maxHeight = getHeight() - 2*BORDER; |
||
903 | double widthRatio = 1.0 * maxWidth / img.getWidth(); |
||
904 | double heightRatio = 1.0 * maxHeight / img.getHeight(); |
||
905 | 504 | gtress | double scale = 0; |
906 | 470 | gtress | int newWidth = 0; |
907 | int newHeight = 0; |
||
908 | int x = 0; |
||
909 | int y = 0; |
||
910 | 527 | emarinel | |
911 | 531 | emarinel | if (widthRatio > heightRatio) { //height is the limiting factor |
912 | 533 | emarinel | scale = heightRatio; |
913 | newHeight = maxHeight; |
||
914 | newWidth = (int) (img.getWidth() * scale);
|
||
915 | y = BORDER; |
||
916 | x = (maxWidth - newWidth) / 2 + BORDER;
|
||
917 | 531 | emarinel | } else { //width is the limiting factor |
918 | 533 | emarinel | scale = widthRatio; |
919 | newWidth = maxWidth; |
||
920 | newHeight = (int) (img.getHeight() * scale);
|
||
921 | x = BORDER; |
||
922 | y = (maxHeight - newHeight) / 2 + BORDER;
|
||
923 | 427 | gtress | } |
924 | 527 | emarinel | |
925 | 511 | gtress | // Draw everything onto the buffer
|
926 | 512 | gtress | buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB); |
927 | 511 | gtress | Graphics2D bufferedGraphics = (Graphics2D)buffer.getGraphics(); |
928 | bufferedGraphics.setColor(Color.GRAY);
|
||
929 | bufferedGraphics.fillRect(0, 0, this.getWidth(), this.getHeight()); |
||
930 | 470 | gtress | Image imgScaled = img.getScaledInstance(newWidth, newHeight, Image.SCALE_FAST); |
931 | 511 | gtress | bufferedGraphics.drawImage(imgScaled, x, y, this);
|
932 | 527 | emarinel | |
933 | |||
934 | 505 | gtress | // Draw Identifiers and battery levels
|
935 | 515 | gtress | if (robotIcons != null) { |
936 | 533 | emarinel | bufferedGraphics.setStroke(new BasicStroke(2)); |
937 | 596 | gtress | for (Map.Entry<Integer,RobotIcon> entry : robotIcons.entrySet()) { |
938 | RobotIcon r = entry.getValue(); |
||
939 | 533 | emarinel | bufferedGraphics.setColor(r.color); |
940 | // Identifier circle
|
||
941 | int px = (int) (x + r.x * scale); |
||
942 | int py = (int) (y + r.y * scale); |
||
943 | bufferedGraphics.drawOval(px-RADIUS, py-RADIUS, 2*r.RADIUS, 2*r.RADIUS); |
||
944 | // Battery
|
||
945 | 561 | gtress | if (r.battery >= 0) { |
946 | 625 | gtress | int pixels = r.battery * BATTERY_WIDTH / 160; // 160 should be fully charged |
947 | if (r.battery > 50) |
||
948 | bufferedGraphics.setColor(Color.GREEN);
|
||
949 | else if (r.battery > 25) |
||
950 | bufferedGraphics.setColor(Color.YELLOW);
|
||
951 | else
|
||
952 | bufferedGraphics.setColor(Color.RED);
|
||
953 | 561 | gtress | bufferedGraphics.fillRect(px+20, py+20, pixels, BATTERY_HEIGHT); |
954 | 535 | emarinel | bufferedGraphics.setColor(Color.BLACK);
|
955 | 561 | gtress | bufferedGraphics.drawRect(px+20, py+20, BATTERY_WIDTH, BATTERY_HEIGHT); |
956 | } |
||
957 | 533 | emarinel | // If the robot has a destination, draw the vector
|
958 | if (r.destx >= 0) { |
||
959 | bufferedGraphics.drawLine(px, py, (int)(x + r.destx * scale), (int)(y + r.desty * scale)); |
||
960 | 531 | emarinel | } |
961 | 533 | emarinel | } |
962 | 320 | gtress | } |
963 | 527 | emarinel | |
964 | 428 | gtress | // Identify currently-selected robot
|
965 | 556 | gtress | RobotIcon r = robotIcons.get(selectedBot); |
966 | if (r != null) { |
||
967 | int px = (int) (x + r.x * scale); |
||
968 | int py = (int) (y + r.y * scale); |
||
969 | bufferedGraphics.setColor(Color.BLACK);
|
||
970 | bufferedGraphics.drawOval(px-RADIUS-6, py-RADIUS-6, 2*r.RADIUS+12, 2*r.RADIUS+12); |
||
971 | 515 | gtress | } |
972 | 527 | emarinel | |
973 | 511 | gtress | //Display buffered content
|
974 | 515 | gtress | g.drawImage(buffer, 0, 0, this); |
975 | 270 | gtress | } |
976 | 527 | emarinel | |
977 | 522 | gtress | /*
|
978 | 527 | emarinel | * Convert a click on the webcam panel to a coordinate that is consistent with the
|
979 | 522 | gtress | * original size of the image that the panel contains.
|
980 | */
|
||
981 | public Point convertClick (MouseEvent e) { |
||
982 | 532 | emarinel | if (img == null) { |
983 | return new Point(e.getX(), e.getY()); |
||
984 | } |
||
985 | |||
986 | 522 | gtress | // Calculate scaling
|
987 | int clickx = e.getX();
|
||
988 | 532 | emarinel | int clicky = e.getY();
|
989 | 522 | gtress | int maxWidth = getWidth() - 2*BORDER; |
990 | int maxHeight = getHeight() - 2*BORDER; |
||
991 | double widthRatio = 1.0 * maxWidth / img.getWidth(); |
||
992 | double heightRatio = 1.0 * maxHeight / img.getHeight(); |
||
993 | double scale = 0; |
||
994 | int newWidth = 0; |
||
995 | int newHeight = 0; |
||
996 | int px = 0; |
||
997 | int py = 0; |
||
998 | 527 | emarinel | |
999 | 531 | emarinel | if (widthRatio > heightRatio) { //height is the limiting factor |
1000 | 532 | emarinel | scale = heightRatio; |
1001 | newHeight = maxHeight; |
||
1002 | newWidth = (int) (img.getWidth() * scale);
|
||
1003 | py = clicky - BORDER; |
||
1004 | px = clickx - BORDER - (maxWidth - newWidth) / 2;
|
||
1005 | 531 | emarinel | } else { //width is the limiting factor |
1006 | 532 | emarinel | scale = widthRatio; |
1007 | newWidth = maxWidth; |
||
1008 | newHeight = (int) (img.getHeight() * scale);
|
||
1009 | px = clickx - BORDER; |
||
1010 | py = clicky - BORDER - (maxHeight - newHeight) / 2;
|
||
1011 | 522 | gtress | } |
1012 | 549 | gtress | py = (int) (py / scale);
|
1013 | px = (int) (px / scale);
|
||
1014 | 532 | emarinel | return new Point(px, py); |
1015 | 522 | gtress | } |
1016 | 270 | gtress | } |
1017 | 527 | emarinel | |
1018 | 270 | gtress | /*
|
1019 | 531 | emarinel | * WebcamLoader class
|
1020 | * Handles the loading of the webcam image.
|
||
1021 | 270 | gtress | */
|
1022 | 527 | emarinel | class WebcamLoader extends Thread |
1023 | 320 | gtress | { |
1024 | 567 | gtress | final int WEBCAMLOADER_DELAY = 250; |
1025 | 566 | emarinel | final String IMAGE_PATH = "http://128.2.99.176/colonet.jpg"; |
1026 | 527 | emarinel | |
1027 | 320 | gtress | URL imagePath;
|
1028 | 527 | emarinel | |
1029 | 320 | gtress | MediaTracker mt;
|
1030 | BufferedImage image;
|
||
1031 | 471 | gtress | Random rand;
|
1032 | 527 | emarinel | |
1033 | 320 | gtress | public WebcamLoader (JApplet applet) |
1034 | { |
||
1035 | super("ColonetWebcamLoader"); |
||
1036 | mt = new MediaTracker(applet); |
||
1037 | ImageIO.setUseCache(false); |
||
1038 | 471 | gtress | rand = new Random(); |
1039 | 270 | gtress | } |
1040 | 527 | emarinel | |
1041 | 470 | gtress | public void run () |
1042 | 320 | gtress | { |
1043 | 270 | gtress | while (true) { |
1044 | try {
|
||
1045 | 320 | gtress | Thread.sleep(WEBCAMLOADER_DELAY);
|
1046 | 527 | emarinel | if (image != null) |
1047 | 320 | gtress | image.flush(); |
1048 | 429 | gtress | System.gc();
|
1049 | 471 | gtress | try {
|
1050 | 567 | gtress | imagePath = new URL(IMAGE_PATH + "?rand=" + rand.nextInt(100000)); |
1051 | 535 | emarinel | } catch (MalformedURLException e) { |
1052 | System.out.println("Malformed URL: could not form URL from: [" + IMAGE_PATH + "]\n"); |
||
1053 | } |
||
1054 | 320 | gtress | image = ImageIO.read(imagePath);
|
1055 | // The MediaTracker waitForID pauses the thread until the image is loaded.
|
||
1056 | // We don't want to display a half-downloaded image.
|
||
1057 | mt.addImage(image, 1);
|
||
1058 | mt.waitForID(1);
|
||
1059 | mt.removeImage(image); |
||
1060 | // Save
|
||
1061 | panelWebcam.setImage(image); |
||
1062 | 270 | gtress | } catch (InterruptedException e) { |
1063 | return;
|
||
1064 | 320 | gtress | } catch (java.security.AccessControlException e) {
|
1065 | 389 | gtress | csi.warn("Could not load webcam.\n" + e);
|
1066 | 320 | gtress | return;
|
1067 | } catch (IOException e) { |
||
1068 | 585 | gtress | getInfoPanel().append("IOException while trying to load image.");
|
1069 | 320 | gtress | } |
1070 | 270 | gtress | } |
1071 | } |
||
1072 | 459 | gtress | } |
1073 | 527 | emarinel | |
1074 | 459 | gtress | /*
|
1075 | 531 | emarinel | * VectorController class
|
1076 | * Manages robot motion control graphically
|
||
1077 | 320 | gtress | */
|
1078 | 427 | gtress | class VectorController extends GraphicsPanel implements MouseListener, MouseMotionListener { |
1079 | 320 | gtress | int x, y, cx, cy;
|
1080 | 590 | gtress | final int WIDTH, HEIGHT; |
1081 | final int SIDE; |
||
1082 | final int BOT_SIZE = 70; |
||
1083 | final int WHEEL_SIZE = 15; |
||
1084 | 527 | emarinel | |
1085 | 320 | gtress | public VectorController (Image img) { |
1086 | super (img);
|
||
1087 | 590 | gtress | WIDTH = img.getWidth(null);
|
1088 | HEIGHT = img.getHeight(null);
|
||
1089 | cx = WIDTH/2;
|
||
1090 | cy = HEIGHT/2;
|
||
1091 | 320 | gtress | x = cx; |
1092 | y = cy; |
||
1093 | 590 | gtress | if (WIDTH < HEIGHT) {
|
1094 | SIDE = WIDTH; |
||
1095 | 535 | emarinel | } else {
|
1096 | 590 | gtress | SIDE = HEIGHT; |
1097 | 535 | emarinel | } |
1098 | 427 | gtress | this.addMouseListener(this); |
1099 | this.addMouseMotionListener(this); |
||
1100 | 320 | gtress | } |
1101 | 527 | emarinel | |
1102 | 320 | gtress | public void setPoint (int x, int y) { |
1103 | 535 | emarinel | if (isValidPoint(x, y)) {
|
1104 | this.x = x;
|
||
1105 | this.y = y;
|
||
1106 | } |
||
1107 | 320 | gtress | } |
1108 | 527 | emarinel | |
1109 | 320 | gtress | public boolean isValidPoint (int x, int y) { |
1110 | 590 | gtress | double xsq = Math.pow(1.0*(x - cx)/(SIDE/2), 2); |
1111 | double ysq = Math.pow(1.0*(y - cy)/(SIDE/2), 2); |
||
1112 | return (xsq + ysq <= 1); |
||
1113 | 320 | gtress | } |
1114 | 527 | emarinel | |
1115 | 320 | gtress | public void notifyMouseEvent (MouseEvent e, boolean send) { |
1116 | 535 | emarinel | if (!isValidPoint(e.getX(), e.getY())) {
|
1117 | 320 | gtress | return;
|
1118 | 535 | emarinel | } |
1119 | 559 | gtress | setPoint(e.getX(), e.getY()); |
1120 | repaint(); |
||
1121 | 535 | emarinel | if (send) {
|
1122 | 590 | gtress | Runnable r = new Runnable () { |
1123 | public void run () { |
||
1124 | sendToServer(); |
||
1125 | } |
||
1126 | }; |
||
1127 | (new Thread(r)).start(); |
||
1128 | 535 | emarinel | } |
1129 | 320 | gtress | } |
1130 | 527 | emarinel | |
1131 | 427 | gtress | public void mouseExited(MouseEvent e) { |
1132 | } |
||
1133 | public void mouseEntered(MouseEvent e) { |
||
1134 | } |
||
1135 | public void mouseReleased(MouseEvent e) { |
||
1136 | this.notifyMouseEvent(e, true); |
||
1137 | } |
||
1138 | public void mouseClicked(MouseEvent e) { |
||
1139 | this.notifyMouseEvent(e, false); |
||
1140 | } |
||
1141 | public void mousePressed(MouseEvent e) { |
||
1142 | } |
||
1143 | public void mouseDragged(MouseEvent e) { |
||
1144 | vectorController.notifyMouseEvent(e, false);
|
||
1145 | } |
||
1146 | public void mouseMoved(MouseEvent e) { |
||
1147 | } |
||
1148 | 527 | emarinel | |
1149 | 320 | gtress | public int getSpeed () { |
1150 | int dx = x - cx;
|
||
1151 | int dy = y - cy;
|
||
1152 | 590 | gtress | int s = (int) Math.sqrt( Math.pow(dx, 2) + Math.pow(dy, 2) ); |
1153 | int maxspeed = SIDE/2; |
||
1154 | return s * 512 / SIDE; |
||
1155 | 320 | gtress | } |
1156 | 527 | emarinel | |
1157 | /**
|
||
1158 | 341 | gtress | * Returns the angle of the control vector in positive degrees west of north,
|
1159 | * or negative degrees east of north, whichever is less than or equal to
|
||
1160 | * 180 degrees total.
|
||
1161 | */
|
||
1162 | 320 | gtress | public int getAngle () { |
1163 | int dx = x - cx;
|
||
1164 | int dy = cy - y;
|
||
1165 | 341 | gtress | // find reference angle in radians
|
1166 | 320 | gtress | double theta = Math.atan2(Math.abs(dx), Math.abs(dy)); |
1167 | 341 | gtress | // transform to degrees
|
1168 | theta = theta * 180 / Math.PI; |
||
1169 | // adjust for quadrant
|
||
1170 | if (dx < 0 && dy < 0) |
||
1171 | theta = 90 + theta;
|
||
1172 | else if (dx < 0 && dy >= 0) |
||
1173 | theta = 90 - theta;
|
||
1174 | else if (dx >= 0 && dy < 0) |
||
1175 | theta = -90 - theta;
|
||
1176 | else
|
||
1177 | theta = -90 + theta;
|
||
1178 | 320 | gtress | return (int) theta; |
1179 | } |
||
1180 | 590 | gtress | |
1181 | public int getMotorL () { |
||
1182 | if (getSpeed() == 0) |
||
1183 | return 0; |
||
1184 | int dx = x - cx;
|
||
1185 | int dy = (cy - y) * 255 / getSpeed(); |
||
1186 | int val = 0; |
||
1187 | // Dependent on quadrant
|
||
1188 | if (dx < 0 && dy < 0) |
||
1189 | val = -255;
|
||
1190 | else if (dx < 0 && dy >= 0) |
||
1191 | val = dy * 1024 / SIDE - 255; |
||
1192 | else if (dx >= 0 && dy < 0) |
||
1193 | val = dy * 1024 / SIDE + 255; |
||
1194 | else
|
||
1195 | val = 255;
|
||
1196 | 625 | gtress | // Normalize to 0-255
|
1197 | 590 | gtress | return val * getSpeed() / 255; |
1198 | } |
||
1199 | |||
1200 | public int getMotorR () { |
||
1201 | if (getSpeed() == 0) |
||
1202 | return 0; |
||
1203 | int dx = x - cx;
|
||
1204 | int dy = (cy - y) * 255 / getSpeed(); |
||
1205 | int val = 0; |
||
1206 | // Dependent on quadrant
|
||
1207 | if (dx < 0 && dy < 0) |
||
1208 | val = dy * 1024 / SIDE + 255; |
||
1209 | else if (dx < 0 && dy >= 0) |
||
1210 | val = 255;
|
||
1211 | else if (dx >= 0 && dy < 0) |
||
1212 | val = -255;
|
||
1213 | else
|
||
1214 | val = dy * 1024 / SIDE - 255; |
||
1215 | 625 | gtress | // Normalize to 0-255
|
1216 | 590 | gtress | return val * getSpeed() / 255; |
1217 | } |
||
1218 | 625 | gtress | |
1219 | private int eliminateDeadZone (int x) { |
||
1220 | final int START = 150; |
||
1221 | int val;
|
||
1222 | if (x == 0) |
||
1223 | return 0; |
||
1224 | if (x > 0) |
||
1225 | val = (int) ((1 - 1.0 * START / 255) * x + START); |
||
1226 | else
|
||
1227 | val = (int) ((1 - 1.0 * START / 255) * x - START); |
||
1228 | return val;
|
||
1229 | |||
1230 | } |
||
1231 | 527 | emarinel | |
1232 | 320 | gtress | public void paint (Graphics g) { |
1233 | 585 | gtress | // Clear image
|
1234 | 320 | gtress | g.setColor(Color.BLACK);
|
1235 | 590 | gtress | g.fillRect(0, 0, WIDTH, HEIGHT); |
1236 | 320 | gtress | ((Graphics2D)g).setStroke(new BasicStroke(1)); |
1237 | 585 | gtress | |
1238 | 590 | gtress | // Motor indicators
|
1239 | int motor1 = getMotorL() * BOT_SIZE / 512; |
||
1240 | int motor2 = getMotorR() * BOT_SIZE / 512; |
||
1241 | g.setColor(Color.YELLOW);
|
||
1242 | if (motor1 < 0) |
||
1243 | g.fillRect(cx-BOT_SIZE/2 - WHEEL_SIZE, cy, WHEEL_SIZE, -motor1);
|
||
1244 | else
|
||
1245 | g.fillRect(cx-BOT_SIZE/2 - WHEEL_SIZE, cy-motor1, WHEEL_SIZE, motor1);
|
||
1246 | if (motor2 < 0) |
||
1247 | g.fillRect(cx+BOT_SIZE/2, cy, WHEEL_SIZE, -motor2);
|
||
1248 | else
|
||
1249 | g.fillRect(cx+BOT_SIZE/2, cy-motor2, WHEEL_SIZE, motor2);
|
||
1250 | |||
1251 | 585 | gtress | // Watermark
|
1252 | g.setColor(Color.GRAY);
|
||
1253 | 590 | gtress | g.drawOval(cx-BOT_SIZE/2, cy-BOT_SIZE/2, BOT_SIZE, BOT_SIZE); |
1254 | g.drawRect(cx-BOT_SIZE/2 - WHEEL_SIZE, cy-BOT_SIZE/2, WHEEL_SIZE, BOT_SIZE); |
||
1255 | g.drawRect(cx+BOT_SIZE/2, cy-BOT_SIZE/2, WHEEL_SIZE, BOT_SIZE); |
||
1256 | 585 | gtress | |
1257 | // Targeting circle
|
||
1258 | 320 | gtress | g.setColor(Color.RED);
|
1259 | 590 | gtress | g.drawOval(cx-SIDE/2, cy-SIDE/2, SIDE, SIDE); |
1260 | 320 | gtress | ((Graphics2D)g).setStroke(new BasicStroke(2)); |
1261 | 585 | gtress | |
1262 | // Vector Line
|
||
1263 | 320 | gtress | g.setColor(Color.GREEN);
|
1264 | g.drawLine(cx, cy, x, y); |
||
1265 | g.fillOval(x-3, y-3, 6, 6); |
||
1266 | } |
||
1267 | 527 | emarinel | |
1268 | 320 | gtress | public void setMaxForward () { |
1269 | 590 | gtress | setPoint(cx, cy - (SIDE/2) + 1); |
1270 | 320 | gtress | } |
1271 | 527 | emarinel | |
1272 | 320 | gtress | public void setMaxReverse () { |
1273 | 590 | gtress | setPoint(cx, cy + (SIDE/2) - 1); |
1274 | 320 | gtress | } |
1275 | 527 | emarinel | |
1276 | 320 | gtress | public void setMaxLeft () { |
1277 | 590 | gtress | setPoint(cx - (SIDE/2) + 1, cy); |
1278 | 320 | gtress | } |
1279 | 527 | emarinel | |
1280 | 320 | gtress | public void setMaxRight () { |
1281 | 590 | gtress | setPoint(cx + (SIDE/2) - 1, cy); |
1282 | 320 | gtress | } |
1283 | 527 | emarinel | |
1284 | 320 | gtress | public void setZero () { |
1285 | setPoint(cx, cy); |
||
1286 | } |
||
1287 | 527 | emarinel | |
1288 | 320 | gtress | public void sendToServer () { |
1289 | 590 | gtress | // Determine destination ID
|
1290 | 320 | gtress | String dest = ColonetServerInterface.GLOBAL_DEST;
|
1291 | 425 | gtress | if (cmbRobotNum != null && cmbRobotNum.getSelectedIndex() > 0) { |
1292 | dest = (String)cmbRobotNum.getSelectedItem();
|
||
1293 | } |
||
1294 | 527 | emarinel | |
1295 | 590 | gtress | if (csi == null) |
1296 | return;
|
||
1297 | |||
1298 | String motor1_string;
|
||
1299 | String motor2_string;
|
||
1300 | 625 | gtress | int motor1 = eliminateDeadZone(getMotorL());
|
1301 | int motor2 = eliminateDeadZone(getMotorR());
|
||
1302 | 590 | gtress | |
1303 | if (motor1 > 0) { |
||
1304 | motor1_string = " 1 " + motor1;
|
||
1305 | } else {
|
||
1306 | motor1_string = " 0 " + (-motor1);
|
||
1307 | 320 | gtress | } |
1308 | 590 | gtress | if (motor2 > 0) { |
1309 | motor2_string = " 1 " + motor2;
|
||
1310 | } else {
|
||
1311 | motor2_string = " 0 " + (-motor2);
|
||
1312 | } |
||
1313 | |||
1314 | csi.sendData(ColonetServerInterface.MOTOR1_SET + motor1_string, dest); |
||
1315 | csi.sendData(ColonetServerInterface.MOTOR2_SET + motor2_string, dest); |
||
1316 | |||
1317 | /*
|
||
1318 | // Directional commands
|
||
1319 | if (x > cx && y == cy) { //move right
|
||
1320 | csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", dest);
|
||
1321 | csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", dest);
|
||
1322 | } else if (x < cx && y == cy) { //move left
|
||
1323 | csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", dest);
|
||
1324 | csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", dest);
|
||
1325 | } else if (x == cx && y > cy) { //move forward
|
||
1326 | csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 225", dest);
|
||
1327 | csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 225", dest);
|
||
1328 | } else if (x == cx && y < cy) { //move backward
|
||
1329 | csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 225", dest);
|
||
1330 | csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 225", dest);
|
||
1331 | } else if (x == cx && y == cy) { //stop!
|
||
1332 | csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 0", dest);
|
||
1333 | csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 0", dest);
|
||
1334 | }
|
||
1335 | */
|
||
1336 | |||
1337 | /*
|
||
1338 | // Atomic Directional commands
|
||
1339 | if (x > cx && y == cy) { //move right
|
||
1340 | csi.sendData(ColonetServerInterface.MOVE_R, dest);
|
||
1341 | } else if (x < cx && y == cy) { //move left
|
||
1342 | csi.sendData(ColonetServerInterface.MOVE_L, dest);
|
||
1343 | } else if (x == cx && y > cy) { //move forward
|
||
1344 | csi.sendData(ColonetServerInterface.MOVE_F, dest);
|
||
1345 | } else if (x == cx && y < cy) { //move backward
|
||
1346 | csi.sendData(ColonetServerInterface.MOVE_B, dest);
|
||
1347 | } else if (x == cx && y == cy) { //stop
|
||
1348 | csi.sendData(ColonetServerInterface.MOTORS_OFF, dest);
|
||
1349 | }
|
||
1350 | */
|
||
1351 | 320 | gtress | } |
1352 | 527 | emarinel | |
1353 | 270 | gtress | } |
1354 | 527 | emarinel | |
1355 | |||
1356 | |||
1357 | 32 | gtress | } |