/* * RoombaCommPanel - * * Copyright (c) 2006 Tod E. Kurt, tod@todbot.com, ThingM * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA * */ package roombacomm; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.text.*; /** * A Panel containing controls for testing RoombaComm. * Normally put inside of a frame, for example see RoombaCommTest * */ public class RoombaCommPanel extends JPanel implements ActionListener,ChangeListener { JPanel ctrlPanel, selectPanel, buttonPanel, displayPanel; JComboBox portChoices; JComboBox protocolChoices; JCheckBox handshakeButton; JTextArea displayText; JButton connectButton; JSlider speedSlider; RoombaCommSerial roombacomm; public RoombaCommPanel() { super(new BorderLayout()); roombacomm = new RoombaCommSerial(); makePanels(); } public RoombaCommPanel(boolean debug) { super(new BorderLayout()); roombacomm = new RoombaCommSerial(); makePanels(); roombacomm.debug = debug; } /** * Set to 'false' to hide the "h/w handshake" button, which seems to be * only needed on Windows */ public void setShowHardwareHandhake( boolean b ) { handshakeButton.setVisible( b ); } /** */ public boolean connect() { String portname = (String) portChoices.getSelectedItem(); //roombacomm.debug=true; roombacomm.setWaitForDSR(handshakeButton.isSelected()); int i = protocolChoices.getSelectedIndex(); roombacomm.setProtocol((i==0)?"SCI":"OI"); connectButton.setText("connecting"); if( ! roombacomm.connect( portname ) ) { updateDisplay("Couldn't connect to "+portname+"\n"); connectButton.setText(" connect "); //roombacomm.debug=false; return false; } updateDisplay("Roomba startup\n"); roombacomm.startup(); roombacomm.control(); roombacomm.playNote( 72, 10 ); // C , test note roombacomm.pause( 200 ); connectButton.setText("disconnect"); connectButton.setActionCommand("disconnect"); //roombacomm.debug=true; updateDisplay("Checking for Roomba... "); if( roombacomm.updateSensors() ) updateDisplay("Roomba found!\n"); else updateDisplay("No Roomba. :( Is it turned on?\n"); return true; } /** */ public void disconnect() { roombacomm.disconnect(); connectButton.setText(" connect "); connectButton.setActionCommand("connect"); } /** * Play a (MIDI) note, that is, make the Roomba a musical instrument * notenums 32-127: * notenum == corresponding note played thru beeper * velocity == duration in number of 1/64s of a second (e.g. 64==1second) * notenum 24: * notenum == main vacuum * velocity == non-zero turns on, zero turns off * notenum 25: * blink LEDs, velcoity is color of Power LED * notenum 28 & 29: * spin left & spin right, velocity is speed * */ public void playMidiNote( int notenum, int velocity ) { updateDisplay("play note: "+notenum+","+velocity+"\n"); if( !roombacomm.connected() ) return; if( notenum >= 31 ) { // G and above if( velocity == 0 ) return; if( velocity < 4 ) velocity = 4; // has problems at lower durations else velocity = velocity/2; roombacomm.playNote( notenum, velocity ); } else if( notenum == 24 ) { // C roombacomm.vacuum( !(velocity==0) ); } else if( notenum == 25 ) { // C# boolean lon = (velocity!=0); int inten = (lon) ? 255:128; // either full bright or half bright roombacomm.setLEDs( lon,lon,lon,lon,lon,lon, velocity*2, inten ); } else if( notenum == 28 ) { // E if( velocity!=0 ) roombacomm.spinLeftAt( velocity*2 ); else roombacomm.stop(); } else if( notenum == 29 ) { // F if( velocity!=0 ) roombacomm.spinRightAt( velocity*2 ); else roombacomm.stop(); } } /** implement actionlistener */ public void actionPerformed(ActionEvent event) { String action = event.getActionCommand(); if( "comboBoxChanged".equals(action) ) { String portname = (String) portChoices.getSelectedItem(); roombacomm.setPortname(portname); int i = protocolChoices.getSelectedIndex(); roombacomm.setProtocol((i==0)?"SCI":"OI"); return; } updateDisplay(action+"\n"); if( "connect".equals(action) ) { connect(); return; } else if( "disconnect".equals(action) ) { disconnect(); return; } // stop right here if we're not connected if( !roombacomm.connected() ) { updateDisplay("not connected!\n"); return; } if( "stop".equals(action) ) { roombacomm.stop(); } else if( "forward".equals(action) ) { roombacomm.goForward(); } else if( "backward".equals(action) ) { roombacomm.goBackward(); } else if( "spinleft".equals(action) ) { roombacomm.spinLeft(); } else if( "spinright".equals(action) ) { roombacomm.spinRight(); } else if( "turnleft".equals(action) ) { roombacomm.turnLeft(); } else if( "turnright".equals(action) ) { roombacomm.turnRight(); } else if( "test".equals(action) ) { updateDisplay("Playing some notes\n"); roombacomm.playNote( 72, 10 ); // C roombacomm.pause( 200 ); roombacomm.playNote( 79, 10 ); // G roombacomm.pause( 200 ); roombacomm.playNote( 76, 10 ); // E roombacomm.pause( 200 ); updateDisplay("Spinning left, then right\n"); roombacomm.spinLeft(); roombacomm.pause(1000); roombacomm.spinRight(); roombacomm.pause(1000); roombacomm.stop(); updateDisplay("Going forward, then backward\n"); roombacomm.goForward(); roombacomm.pause(1000); roombacomm.goBackward(); roombacomm.pause(1000); roombacomm.stop(); } else if( "reset".equals(action) ) { roombacomm.stop(); roombacomm.startup(); roombacomm.control(); } else if( "power-off".equals(action) ) { roombacomm.powerOff(); } else if( "wakeup".equals(action) ) { roombacomm.wakeup(); } else if( "beep-lo".equals(action) ) { roombacomm.playNote( 50, 32 ); // C1 roombacomm.pause( 200 ); } else if( "beep-hi".equals(action) ) { roombacomm.playNote( 90, 32 ); // C7 roombacomm.pause( 200 ); } else if( "clean".equals(action) ) { roombacomm.clean(); } else if( "spot".equals(action) ) { roombacomm.spot(); } else if( "vacuum-on".equals(action) ) { roombacomm.vacuum(true); } else if( "vacuum-off".equals(action) ) { roombacomm.vacuum(false); } else if( "blink-leds".equals(action) ) { roombacomm.setLEDs( true,true,true, true,true,true, 255, 255 ); roombacomm.pause(300); roombacomm.setLEDs( false,false,false, false,false,false, 0, 128); } else if( "sensors".equals(action) ) { if( roombacomm.updateSensors() ) updateDisplay( roombacomm.sensorsAsString()+"\n"); else updateDisplay("couldn't read Roomba. Is it connected?\n"); } } /** implement ChangeListener, for the slider */ public void stateChanged(ChangeEvent e) { //System.err.println("stateChanged:"+e); JSlider src = (JSlider)e.getSource(); if (!src.getValueIsAdjusting()) { int speed = (int)src.getValue(); speed = (speed<1) ? 1 : speed; // don't allow zero speed updateDisplay("setting speed = "+speed+"\n"); roombacomm.setSpeed(speed); } } /** * */ void makePanels() { makeSelectPanel(); add( selectPanel, BorderLayout.NORTH ); makeCtrlPanel(); add( ctrlPanel, BorderLayout.EAST ); makeButtonPanel(); add( buttonPanel, BorderLayout.CENTER ); makeDisplayPanel(); add( displayPanel, BorderLayout.SOUTH ); //pack(); //setVisible(true); updateDisplay("RoombaComm, version "+RoombaComm.VERSION+"\n"); } void makeSelectPanel() { selectPanel = new JPanel(); // Create a combo box with protocols String[] protocols = {"Roomba 1xx-4xx (SCI)", "Roomba 5xx (OI)"}; protocolChoices = new JComboBox(protocols); String p = roombacomm.getProtocol(); protocolChoices.setSelectedIndex(p.equals("SCI")?0:1); //Create a combo box with choices. String[] ports = roombacomm.listPorts(); portChoices = new JComboBox(ports); portChoices.setSelectedIndex(0); for( int i=0; ih/w
handshake"); //Add a border around the select panel. selectPanel.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createTitledBorder("Select Roomba Type & Port"), BorderFactory.createEmptyBorder(1,1,1,1))); selectPanel.add(protocolChoices); selectPanel.add(portChoices); selectPanel.add(connectButton); selectPanel.add(handshakeButton); //Listen to events from the combo box. portChoices.addActionListener(this); connectButton.addActionListener(this); protocolChoices.addActionListener(this); } /** * */ void makeCtrlPanel() { JPanel ctrlPanel1 = new JPanel(new GridLayout(3,3)); JButton but_turnleft = new JButton(createImageIcon("images/but_turnleft.png","turnleft")); ctrlPanel1.add( but_turnleft ); JButton but_forward = new JButton(createImageIcon("images/but_forward.png","forward")); ctrlPanel1.add( but_forward ); JButton but_turnright = new JButton(createImageIcon("images/but_turnright.png","turnright")); ctrlPanel1.add( but_turnright ); JButton but_spinleft = new JButton(createImageIcon("images/but_spinleft.png","spinleft")); ctrlPanel1.add( but_spinleft ); JButton but_stop = new JButton(createImageIcon("images/but_stop.png", "stop")); ctrlPanel1.add( but_stop ); JButton but_spinright = new JButton(createImageIcon("images/but_spinright.png","spinright")); ctrlPanel1.add( but_spinright ); ctrlPanel1.add(new JLabel()); JButton but_backward = new JButton(createImageIcon("images/but_backward.png","backward")); ctrlPanel1.add( but_backward ); ctrlPanel1.add(new JLabel()); JLabel sliderLabel = new JLabel("speed (mm/s)", JLabel.CENTER); speedSlider = new JSlider(JSlider.HORIZONTAL, 0, 500, 200 ); speedSlider.setPaintTicks(true); speedSlider.setMajorTickSpacing(100); speedSlider.setMinorTickSpacing(25); speedSlider.setPaintLabels(true); speedSlider.addChangeListener(this); ctrlPanel = new JPanel(); ctrlPanel.setLayout( new BoxLayout(ctrlPanel, BoxLayout.Y_AXIS ) ); ctrlPanel.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createTitledBorder("Movement"), BorderFactory.createEmptyBorder(5,5,5,5))); ctrlPanel.add( ctrlPanel1 ); ctrlPanel.add( speedSlider ); ctrlPanel.add( sliderLabel ); but_turnleft.setActionCommand("turnleft"); but_turnright.setActionCommand("turnright"); but_spinleft.setActionCommand("spinleft"); but_spinright.setActionCommand("spinright"); but_forward.setActionCommand("forward"); but_backward.setActionCommand("backward"); but_stop.setActionCommand("stop"); but_turnleft.addActionListener(this); but_turnright.addActionListener(this); but_spinleft.addActionListener(this); but_spinright.addActionListener(this); but_forward.addActionListener(this); but_backward.addActionListener(this); but_stop.addActionListener(this); } /** * */ void makeButtonPanel() { buttonPanel = new JPanel( new GridLayout( 8,2 ) ); buttonPanel.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createTitledBorder("Commands"), BorderFactory.createEmptyBorder(5,5,5,5))); JButton but_reset = new JButton("reset"); buttonPanel.add( but_reset ); but_reset.addActionListener(this); JButton but_test = new JButton("test"); buttonPanel.add( but_test ); but_test.addActionListener(this); JButton but_power = new JButton("power-off"); buttonPanel.add( but_power ); but_power.addActionListener(this); JButton but_wakeup = new JButton("wakeup"); buttonPanel.add( but_wakeup ); but_wakeup.addActionListener(this); JButton but_beeplo = new JButton("beep-lo"); buttonPanel.add( but_beeplo ); but_beeplo.addActionListener(this); JButton but_beephi = new JButton("beep-hi"); buttonPanel.add( but_beephi ); but_beephi.addActionListener(this); JButton but_clean = new JButton("clean"); buttonPanel.add( but_clean ); but_clean.addActionListener(this); JButton but_spot = new JButton("spot"); buttonPanel.add( but_spot ); but_spot.addActionListener(this); JButton but_vacon = new JButton("vacuum-on"); buttonPanel.add( but_vacon ); but_vacon.addActionListener(this); JButton but_vacoff = new JButton("vacuum-off"); buttonPanel.add( but_vacoff ); but_vacoff.addActionListener(this); JButton but_blinkleds = new JButton("blink-leds"); buttonPanel.add( but_blinkleds ); but_blinkleds.addActionListener(this); JButton but_sensors = new JButton("sensors"); buttonPanel.add( but_sensors ); but_sensors.addActionListener(this); } /** * */ void makeDisplayPanel() { displayPanel = new JPanel(); displayPanel.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createTitledBorder("Display"), BorderFactory.createEmptyBorder(1,1,1,1))); displayText = new JTextArea(5,30); displayText.setLineWrap(true); DefaultCaret dc = new DefaultCaret(); // only works on Java 1.5+ //dc.setUpdatePolicy( DefaultCaret.ALWAYS_UPDATE ); displayText.setCaret(dc); JScrollPane scrollPane = new JScrollPane(displayText, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER ); displayPanel.add( scrollPane ); } public void updateDisplay(String s) { displayText.append( s ); displayText.setCaretPosition(displayText.getDocument().getLength()); } /** Returns an ImageIcon, or null if the path was invalid. */ protected static ImageIcon createImageIcon(String path, String description) { // yes, this is supposed to say "RoombaCommTest" java.net.URL imgURL = RoombaCommPanel.class.getResource(path); if (imgURL != null) { return new ImageIcon(imgURL, description); } else { System.err.println("Couldn't find file: " + path); return null; } } }