Ev3Control.java and RMIRegulatedMotor Class

This is where you talk about the EV3 software itself, installation issues, and programming talk.

Moderators: roger, gloomyandy, skoehler

Ev3Control.java and RMIRegulatedMotor Class

Postby huha » Mon Feb 17, 2014 7:07 pm

I am experiencing a problem with the RMIRegulatedMotor Stop(true/false) class.
I was using the Ev3control.java code and wanted to use the motor control as a remote on the PC.
In order to have minimum delay between the two motors I modified the stopMotors() method.

It looks like the true is always ignored. If I change motor1 and motor2 the robot makes a left turn instead a right turn after I release the mouse button from a forward move.

There is no problem (no turn) for the RegulatedMotor class if I stop the two motors. Here I can see the difference for true and false as expected.

Code: Select all
private void stopMotors() {//huha change stop all motors first to achieve equal stopping, afterwards close, motor 3 added
      try {
         if (motor0 != null) {
            motor0.stop(true);            
         }
         
         if (motor2 != null) {    //looks like the true is ignored. if I change order of motor 2 and 3 the direction for stopping changes from left to right
            motor2.stop(true); // i am not seeing a difference between false and true
         }
         if (motor1 != null) {
            motor1.stop(true);
         }
         if (motor3 != null) {
            motor3.stop(true);
         }

As I found that not all 4 motors were updated in the code I have modified the class and also included an automatic speed adjustment using getMaxSpeed(). I have attached the full java code

and marked my changes by "//huha change"

The control center is really great and gave me good learning for understanding leJos.

Complete modified Code for Ev3Control.java after line 1095 (the full code was too big to post):

Code: Select all

   /**
    * Create the control panel
    */
   private void createControlPanel() {
      JPanel motorsPanel = new JPanel();
      motorsPanel.setLayout(new BoxLayout(motorsPanel, BoxLayout.Y_AXIS));
      motorsPanel.add(createMotorsHeader());
      for (int i = 0; i < 4; i++) {
         motorsPanel.add(createMotorPanel(i));
      }
      JPanel buttonsPanel = new JPanel();
      controlPanel.add(motorsPanel);
      buttonsPanel.add(forwardButton);
      buttonsPanel.add(backwardButton);
      buttonsPanel.add(leftButton);
      buttonsPanel.add(rightButton);
      controlPanel.add(buttonsPanel);

      forwardButton.addMouseListener(new MouseAdapter() {
         public void mousePressed(MouseEvent e) {
            if (!aMotorSelected()) return;
            int[] speed = getSpeeds();
            move(speed[0], speed[1], speed[2], speed[3]);//huha change
         }

         public void mouseReleased(MouseEvent e) {
            stopMotors();
         }
      });

      backwardButton.addMouseListener(new MouseAdapter() {
         public void mousePressed(MouseEvent e) {
            if (!aMotorSelected()) return;
            int[] speed = getSpeeds();
            move(-speed[0], -speed[1], -speed[2], -speed[3]);//huha change
         }

         public void mouseReleased(MouseEvent e) {
            stopMotors();
         }
      });

      leftButton.addMouseListener(new MouseAdapter() {
         public void mousePressed(MouseEvent e) {
            if (!twoMotorsSelected()) return;
            int[] speed = getSpeeds();
            int[] multipliers = leftMultipliers();
            move(speed[0] * multipliers[0], speed[1] * multipliers[1], speed[2] * multipliers[2], speed[3] * multipliers[3]);//huha change
         }

         public void mouseReleased(MouseEvent e) {
            stopMotors();
         }
      });

      rightButton.addMouseListener(new MouseAdapter() {
         public void mousePressed(MouseEvent e) {
            if (!twoMotorsSelected()) return;
            int[] speed = getSpeeds();
            int[] multipliers = rightMultipliers();
            move(speed[0] * multipliers[0], speed[1] * multipliers[1], speed[2] * multipliers[2], speed[3] * multipliers[3]);//huha change
         }

         public void mouseReleased(MouseEvent e) {
            stopMotors();
         }
      });
   }
   
   /**
    * Return the number of motors selected
    */
   private int numMotorsSelected() {
      int numSelected = 0;
      
      for(int i=0;i<4;i++) {//huha change
         if (selectors[i].isSelected()) numSelected ++;
      }
      
      return numSelected;
   }
   
   /**
    * Return true iff exactly two motors selected and show message if not
    */
   private boolean twoMotorsSelected() {
      if (numMotorsSelected() != 2) {
         showMessage("Exactly two motors must be selected");
         return false;   
      }
      return true;
   }
   
   /**
    * Return true iff at least one motor selected and show message if not
    */
   private boolean aMotorSelected() {
      if (numMotorsSelected() < 1) {
         showMessage("At least one motor must be selected");
         return false;   
      }
      return true;
   }
   
   /**
    * Calculate speed multipliers for turning left
    */
   private int[] leftMultipliers() {
      int[] multipliers = new int[4];//huha change
      boolean firstFound = false, secondFound = false;
      
      for(int i=0;i<4;i++) {//huha change
         if (selectors[i].isSelected() && !firstFound) {
            firstFound = true;
            multipliers[i] = -1;
         } else if (selectors[i].isSelected() && !secondFound) {
            secondFound = true;
            multipliers[i] = 1;
         } else {
            multipliers[i] = 0;
         }         
      }
      return multipliers;
   }
   
   
   /**
    * Calculate the speed multipliers for turning right
    */
   private int[] rightMultipliers() {
      int[] multipliers = new int[4];//huha change
      boolean firstFound = false, secondFound = false;
      
      for(int i=0;i<4;i++) {//huha change
         if (selectors[i].isSelected() && !firstFound) {
            firstFound = true;
            multipliers[i] = 1;
         } else if (selectors[i].isSelected() && !secondFound) {
            secondFound = true;
            multipliers[i] = -1;
         } else {
            multipliers[i] = 0;
         }         
      }
      return multipliers;
   }
   
   /**
    * Download a file from the EV3
    */
   private void getFile(File file, String fileName, int size) {
      FileOutputStream out = null;
      try {
         out = new FileOutputStream(file);
         byte[] data = menu.fetchFile(fileName);
         out.write(data);
         out.close();         
      } catch (IOException e) {
         e.printStackTrace();
      }
   }

   /**
    * Show a pop-up message
    */
   public void showMessage(String msg) {
      JOptionPane.showMessageDialog(frame, msg);
   }
   
   /**
    * Update the sensor dials
    */
   private void updateSensors() {
      if (ev3 == null) return;
      batteryValue.setText("" + mv);
      s1Panel.update();
      s2Panel.update();
      s3Panel.update();
      s4Panel.update();
   }

   /**
    * Clear the files tab.
    */
   private void clearFiles() {
      programsFilesPanel.removeAll();
      programsFilesPanel.repaint();
      samplesFilesPanel.removeAll();
      samplesFilesPanel.repaint();
   }

   /**
    * Switch between EV3s in table of available EV3s
    */
   public void valueChanged(ListSelectionEvent e) {
      if (e.getValueIsAdjusting()) {
         int row = ev3Table.getSelectedRow();
         if (row < 0) return;      
         
      }
   }
   
   /**
    * Update connection status in the connections table
    */
   private void updateConnectionStatus(int row, EV3ConnectionState state) {
      model.setConnected(row, state);
      ev3Table.repaint();
      updateConnectButton(state != EV3ConnectionState.DISCONNECTED);
   }

   /**
    * Search for available EV3s and populate table with results.
    */
   private void search() {
      closeAll();
      clearFiles();
      updateConnectButton(false);
      
      Map<String,EV3Info> ev3s = new HashMap<String,EV3Info>();
      
        try {
            socket = new DatagramSocket(DEFAULT_PORT);
        } catch( Exception ex ) {
            showMessage("Failed to create datagram socket");
            return;
        }

        packet = new DatagramPacket (new byte[100], 100);

        long start = System.currentTimeMillis();
       
        while ((System.currentTimeMillis() - start) < 2000) {
            try {
                socket.receive (packet);
                String message = new String(packet.getData(), "UTF-8");
                String ip = packet.getAddress().getHostAddress();
                System.out.println("Adding " + ip);
                ev3s.put(ip, new EV3Info(message.trim(),ip));

            } catch (IOException ie) {
                showMessage("Failed to read discovery datagram");
            }
        }
       
        if (socket != null) socket.close();
       
        EV3Info[] devices = new EV3Info[ev3s.size()];
        int i = 0;
        for(String ev3: ev3s.keySet()) {
           EV3Info info = ev3s.get(ev3);
           devices[i++] = info;
           System.out.println("Found " + info.getName() + " " + info.getIPAddress());
        }
       
        model = new EV3ConnectionModel(devices, devices.length);
      ev3Table.setModel(model);
       TableColumn col = ev3Table.getColumnModel().getColumn(3);
       col.setPreferredWidth(150);
      ev3Table.setRowSelectionInterval(0, 0);
      ev3Table.getSelectionModel().addListSelectionListener(this);
   }

   /**
    * Close all connections
    */
   private void closeAll() {
      s1Panel.close();
      s2Panel.close();
      s3Panel.close();
      s4Panel.close();
      if (cvc != null) cvc.close();
      ev3 = null;
      menu = null;
   }

   /**
    * Toggle Connect button between Connect and Disconnect
    */
   private void updateConnectButton(boolean connected) {
      connectButton.setText((connected ? "Disconnect" : "Connect"));
   }

   /**
    * Stop the motors on the EV3 and update the tachometer values
    */
   private void stopMotors() {//huha change stop all motors first to achieve equal stopping, afterwards close, motor 3 added
      try {
         if (motor0 != null) {
            motor0.stop(true);            
         }
         
         if (motor2 != null) {    //looks like the true is ignored. if I change order of motor 2 and 3 the direction for stopping changes
            motor2.stop(false);
         }
         if (motor1 != null) {
            motor1.stop(false);
         }
         if (motor3 != null) {
            motor3.stop(true);
         }
         
         if (motor0 != null) {
            motor0.close();
            motor0=null;
         }
         if (motor1 != null) {
            motor1.close();
            motor1=null;
         }
         if (motor2 != null) {
            motor2.close();
            motor2=null;
         }
         if (motor3 != null) {
            motor3.close();
            motor3=null;
         }
      } catch (RemoteException e) {
         e.printStackTrace();
      }   
   }

   /**
    * Get an array of the tacho limit text boxes
    */
   private int[] getLimits() {
      int[] lim = new int[4];//huha change

      for (int i = 0; i < 4; i++) {//huha change
         try {
            lim[i] = Integer.parseInt(limits[i].getText());
         } catch (NumberFormatException nfe) {
            lim[i] = 0;
         }
      }
      return lim;
   }
   
   /**
    * Get an array of the speed slider values
    */
   private int[] getSpeeds() {
      int[] speed = new int[4]; //huha change

      for (int i = 0; i < 4; i++) { //huha change
         speed[i] = sliders[i].getValue();
         if (reversors[i].isSelected()) speed[i] = -speed[i];
      }
      return speed;
   }

   /**
    * Retrieve the sensor and battery values from the EV3
    */
   private void getSensorValues() {
      if (ev3 != null) {
         mv = ev3.getPower().getVoltageMilliVolt();
      }
   }

   /**
    * Connect to the EV3
    */
   private void connect() {
      String name;
      int row = ev3Table.getSelectedRow();
      if (row >= 0) {
         name =  (String) model.getValueAt(row, 2);
         System.out.println("Name is " + name);
         
         EV3ConnectionState state = (EV3ConnectionState) ev3Table.getValueAt(row, 3);
      
         if (state == EV3ConnectionState.CONNECTED) {
            closeAll();
            updateConnectionStatus(row, EV3ConnectionState.DISCONNECTED);
            return;
         }
      } else {
         name = nameText.getText();
      }
      
      if (name != null && name.length() > 0) {
         System.out.println("Connecting to " + name);
         try {
            menu = (RMIMenu) Naming.lookup("//" + name + "/RemoteMenu");
            ev3 = new RemoteEV3(name);
            s1Panel.setEV3(ev3);
            s2Panel.setEV3(ev3);
            s3Panel.setEV3(ev3);
            s4Panel.setEV3(ev3);
            cvc.connectTo(name, name, 0, true);
            if (row >= 0) updateConnectionStatus(row, EV3ConnectionState.CONNECTED);
            showFiles();
         } catch (RemoteException | MalformedURLException
               | NotBoundException e) {
            e.printStackTrace();
         }
      }
   }
   
   /**
    * Append data item to the data log
    */
   public void append(float x) {
      if (0 == recordCount % rowLength) theDataLog.append("\n");
      theDataLog.append(FORMAT_FLOAT.format(x) + "\t ");
      recordCount++;
   }
   
   /**
    * Delete selected files
    */
   private void deleteFiles() {
      frame.setCursor(hourglassCursor);
      try {
         for (int i = 0; i < fmPrograms.getRowCount(); i++) {
            Boolean b = (Boolean) fmPrograms.getValueAt(i,ExtendedFileModel.COL_DELETE);
            String fileName = (String) fmPrograms.getValueAt(i,ExtendedFileModel.COL_NAME);
            boolean deleteIt = b.booleanValue();
            if (deleteIt) {
               System.out.println("Deleting " + fileName);
               menu.deleteFile(fileName);
            }
         }
         fmPrograms.fetchFiles();
      } catch (Exception ioe) {
         showMessage("IOException deleting files");
      }
      frame.setCursor(normalCursor);
   }
   
   /**
    * Choose a file and update it. Remember directory last used.
    */
   private void upload() {
      JFileChooser fc = new JFileChooser(directoryLastUsed);
      int returnVal = fc.showOpenDialog(frame);
      
      if (returnVal == JFileChooser.APPROVE_OPTION) {
         File file = fc.getSelectedFile();
         directoryLastUsed = file.getParentFile();
         uploadFile(file);
      }
   }
   
   /**
    * Upload the specified file
    */
   private void uploadFile(File file) {
      frame.setCursor(hourglassCursor);
      try {
         FileInputStream in = new FileInputStream(file);
         byte[] data = new byte[(int)file.length()];
          in.read(data);
          System.out.println("Uploading " + file.getName());
         menu.uploadFile("/home/lejos/programs/" + file.getName(), data);
          in.close();
         fmPrograms.fetchFiles();
      } catch (IOException ioe) {
         showMessage("IOException uploading file");
      }
      frame.setCursor(normalCursor);
   }
   
   /**
    * Download the selected file
    */
   private void download() {
      int row = programsTable.getSelectedRow();
      if (row < 0) {
         noFileSelected();
         return;
      }
      
      String fileName = fmPrograms.getFile(row).fileName;
      int size = fmPrograms.getFile(row).fileSize;
      JFileChooser fc = new JFileChooser();
      fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
      fc.setSelectedFile(new File(fileName));
      
      int returnVal = fc.showSaveDialog(frame);
      if (returnVal == 0) {
         File file = fc.getSelectedFile();
         frame.setCursor(hourglassCursor);
         getFile(file, fileName, size);
         frame.setCursor(normalCursor);
      }
   }
   
   /**
    * Run the selected file.
    */
   private void runProgram() {
      int row = programsTable.getSelectedRow();
      if (row < 0) {
         noFileSelected();
         return;
      }
      String name = fmPrograms.getFile(row).fileName;
      
      System.out.println("Running " + name);
      try {
         menu.runProgram(name.replaceFirst(".jar", ""));
      } catch (RemoteException e) {
         e.printStackTrace();
      }
   }
   
   /**
    * Run the selected file.
    */
   private void runSample() {
      int row = samplesTable.getSelectedRow();
      if (row < 0) {
         noFileSelected();
         return;
      }
      String name = fmSamples.getFile(row).fileName;
      
      System.out.println("Running Sample  " + name);
      try {
         menu.runSample(name.replaceFirst(".jar", ""));
      } catch (RemoteException e) {
         e.printStackTrace();
      }
   }
   
   /**
    * Change the friendly name of the EV3
    */
   private void rename(String name) {
   }
   
   /**
    * Move the motors
    */
   private void move(int speed0, int speed1, int speed2, int speed3 ) {//huha change in function
      int[] lim = getLimits();
      // motor speed calculations are done first to achieve equal start of both motors
      
      try {
         if (ev3 == null) return;
         double maxSpeed = 100000000000000.0;//use a large start value
         int acceleration = 800;
         
         //determine smallest maxSpeed of all motors
         if (selectors[0].isSelected()) {
            motor0 = ev3.createRegulatedMotor("A", 'L');
            float max0Speed = motor0.getMaxSpeed();
            if (max0Speed < maxSpeed)
               maxSpeed = max0Speed;
         }
         if (selectors[1].isSelected()) {
            motor1 = ev3.createRegulatedMotor("B", 'L');
            float max1Speed = motor1.getMaxSpeed();
            if (max1Speed < maxSpeed)
               maxSpeed = max1Speed;
         }
         if (selectors[2].isSelected()) {
            motor2 = ev3.createRegulatedMotor("C", 'L');
            float max2Speed = motor2.getMaxSpeed();
            if (max2Speed < maxSpeed)
               maxSpeed = max2Speed;
         }
         if (selectors[3].isSelected()) {
            motor3 = ev3.createRegulatedMotor("D", 'L');
            float max3Speed = motor3.getMaxSpeed();
            if (max3Speed < maxSpeed)
               maxSpeed = max3Speed;
         }
                  
         if (selectors[0].isSelected()) {
            speed0 = (int)(0.5 + maxSpeed * speed0 / 100);
            motor0.setSpeed(speed0);
            motor0.setAcceleration(acceleration);
            System.out.println("Speed0 " + String.valueOf(speed0));
         }         
         if (selectors[1].isSelected()) {
            speed1 = (int)(0.5 + maxSpeed * speed1 / 100);
            motor1.setSpeed(speed1);
            motor1.setAcceleration(acceleration);
            System.out.println("Speed1 " + String.valueOf(speed1));
         }
         if (selectors[2].isSelected()) {
            speed2 = (int)(0.5 + maxSpeed * speed2 / 100);
            motor2.setSpeed(speed2);
            motor2.setAcceleration(acceleration);
            System.out.println("Speed2 " + String.valueOf(speed2));
         }         
         if (selectors[3].isSelected()) {
            speed3 = (int)(0.5 + maxSpeed * speed3 / 100);
            motor3.setSpeed(speed3);
            motor3.setAcceleration(acceleration);
            System.out.println("Speed3 " + String.valueOf(speed3));
         }
         
         //now start motors
         if (selectors[0].isSelected()) {
            if (lim[0] !=0) motor0.rotateTo(lim[0]);
             else if (speed0 > 0) motor0.forward(); else motor0.backward();
         }         
         if (selectors[1].isSelected()) {
            if (lim[1] !=0) motor1.rotateTo(lim[1]);
             else if (speed1 > 0) motor1.forward(); else motor1.backward();
         }
         if (selectors[2].isSelected()) {
            if (lim[2] !=0) motor2.rotateTo(lim[2]);
             else if (speed2 > 0) motor2.forward(); else motor2.backward();
         }         
         if (selectors[3].isSelected()) {
            if (lim[3] !=0) motor3.rotateTo(lim[3]);
             else if (speed3 > 0) motor3.forward(); else motor3.backward();
         }         
         
      } catch (IOException ioe) {
         showMessage("IOException updating control");
      }
   }
   
   /**
    * Play a tone
    */
   private void playTone() {
      try {
         ev3.getAudio().playTone((Integer) freq.getValue(), (Integer) duration.getValue());
      } catch (NumberFormatException nfe) {
         showMessage("Frequency and Duration must be integers");
      } catch (Exception ioe) {
         showMessage("Exception playing tone");
      }
   }
   
   /**
    * Reset the tachometer for a motor
    */
   private void resetTacho(JButton b) {
      RMIRegulatedMotor motor;
      
      if (ev3 == null) return;
      
      if (b == resetButtons[0]) motor = motor0;
      if (b == resetButtons[1]) motor = motor1;
      if (b == resetButtons[2]) motor = motor2;
      if (b == resetButtons[3]) motor = motor3;
      
      
      try {
         // TODO: add tacho stuff to RMIRegulatedMotor
      } catch (Exception ioe) {
         showMessage("IO Exception resetting motor");
      }
   }
   
   /**
    * Play a sound file
    */
   private void playSoundFile() {
      int row = programsTable.getSelectedRow();
      if (row < 0) {
         noFileSelected();
         return;
      }
      
      String fileName = fmPrograms.getFile(row).fileName;
      try {
         System.out.println("Playing file " + fileName);
         ev3.getAudio().playSample(new File("/home/root/lejos/samples/" + fileName));
      } catch (Exception ioe) {
         showMessage("IO Exception playing sound file");
      }
   }
   
   /**
    * Send I2C request
    */
   private void i2cSend() {
      int addr= ((Number)address.getValue()).intValue();
      
      try {
         Port p = ev3.getPort((String) sensorList.getSelectedItem());
         
         I2CPort i2c = p.open(RemoteI2CPort.class);
         
         int rLen = ((Number) rxDataLength.getValue()).intValue();
         byte[] reply = new byte[rLen];
         byte[] data = fromHex(txData.getText());
         
         i2c.i2cTransaction(addr, data, 0, data.length, reply, 0, rLen);
         
         if (rLen > 0) {
            String hex = toHex(reply);
            rxData.setText(hex);
         } else
            rxData.setText("null");
         
         i2c.close();
         
      } catch (Exception e) {
         showMessage("IO Exception sending txData: " + e);
         e.printStackTrace();
      }
   }
   
   /**
    * Convert a byte array to a string of hex characters
    */
   private String toHex(byte[] b) {
      StringBuilder output = new StringBuilder();
      for (int i = 0; i < b.length; i++) {
         if (i > 0)
            output.append(' ');
         byte j = b[i];
         output.append(Character.forDigit((j >> 4) & 0xF, 16));
         output.append(Character.forDigit(j & 0xF, 16));
      }
      return output.toString();
   }

   
   /**
    * Convert a string of hex characters to a byte array
    */
   private byte[] fromHex(String s) {
      byte[] reply = new byte[s.length() / 2];
      for (int i = 0; i < reply.length; i++) {
         char c1 = s.charAt(i * 2);
         char c2 = s.charAt(i * 2 + 1);
         reply[i] = (byte) (getHexDigit(c1) << 4 | getHexDigit(c2));
      }
      return reply;
   }
   
   /**
    * Convert a character to a hex digit
    */
   private int getHexDigit(char c) {
      if (c >= '0' && c <= '9') return c - '0';
      if (c >= 'a' && c <= 'f') return c - 'a' + 10;
      if (c >= 'A' && c <= 'F') return c - 'A' + 10;
      return 0;
   }
   
   /**
    * Format the file system
    */
   private void format() {
      try {
         menu.deleteAllPrograms();
         fmPrograms.fetchFiles();
      } catch (Exception ioe) {
         showMessage("IO Exception formatting file system");
      }
   }
   
   private void noFileSelected() {
      showMessage("No file selected");
   }
   
   private void setDefaultProgram() {
      int row = programsTable.getSelectedRow();
      if (row < 0) {
         noFileSelected();
         return;
      }
      
      String fileName = fmPrograms.getFile(row).fileName;
      try {
         menu.setSetting(defaultProgramProperty,"/home/lejos/programs/" + fileName);
      } catch (IOException ioe) {
         showMessage("IO setting default program");
      }
   }
   
   /**
    * Used for console viewer
    */
   public void logMessage(String msg) {
      System.out.println(msg);
   }
   
   /**
    * Used by console viewer
    */
   public void connectedTo(String name, String address) {
      System.out.println("Connected to " + name + "(" + address + ")");
   }

   /**
    * Used by console viewer
    */
   public void setStatus(String msg) {
      System.out.println("Status is " + msg);
   }

   /**
    * Used by console viewer
    */
   public void append(String value) {
      theConsoleLog.append(value);
      theConsoleLog.setCaretPosition(theConsoleLog.getDocument().getLength());
   }

   /**
    * Used by console viewer
    */
    public void updateLCD(byte[] buffer)
    {
       lcd.update(buffer);
    }
   
    private String getSetting(String key, String defaultValue) throws RemoteException {
       String val = menu.getSetting(key);
       if (val == null) return defaultValue;
       else return val;
    }
}

huha
New User
 
Posts: 19
Joined: Tue Sep 24, 2013 9:24 pm

Re: Ev3Control.java and RMIRegulatedMotor Class

Postby lawrie » Tue Feb 18, 2014 1:33 pm

Hi huha, I will look into these issues. All this code is a bit experimental at the moment: both the remote access code, and ev3tools. It is good to get some feedback on it.
I am not sure how useful the motor control in EV3Control is. I mainly included it as it was in the NXT version, and it as a good test of remote access.

Most of the leJOS developers are not very keen on the remote access APIs, as they think robots should be autonomous.

I still have not decided on the best way to do remote access. EV3Control uses Java RMI, but that does not work on Android. There is a start of a remote access API that uses object streams directly rather than using Java RMI (and which works on Android), but that is currently not very far advanced.

Remote access and ev3tools relies on the menu running on the EV3. I am not sure how many leJOS developers want to use the menu, or whether most would prefer to just use tools like ssh, scp, ant and maven, and run the EV3 without the menu.

Lawrie
lawrie
leJOS Team Member
 
Posts: 842
Joined: Mon Feb 05, 2007 1:27 pm

Re: Ev3Control.java and RMIRegulatedMotor Class

Postby huha » Tue Feb 18, 2014 8:11 pm

Hi Lawrie,
I found a cheat around by setting the motor speed to 0 instead of stopping them. Now both motors stop at the same time and there are no more turns.
Code: Select all
/**
    * Stop the motors on the EV3 and update the tachometer values
    */
   private void stopMotors() {//huha change stop all motors first to achieve equal stopping, afterwards close, motor 3 added
      try {
         
         //set the motor speed to 0 instead of stopping
         if (motor0 != null) {
            motor0.setSpeed(0);            
         }
         if (motor1 != null) {
            motor1.setSpeed(0);
         }
         if (motor2 != null) {   
            motor2.setSpeed(0);
         }         
         if (motor3 != null) {
            motor3.setSpeed(0);
         }
                  
         if (motor0 != null) {
            motor0.close();
            motor0=null;
         }
         if (motor1 != null) {
            motor1.close();
            motor1=null;
         }
         if (motor2 != null) {
            motor2.close();
            motor2=null;
         }
         if (motor3 != null) {
            motor3.close();
            motor3=null;
         }
      } catch (RemoteException e) {
         e.printStackTrace();
      }   
   }


I like the Ev3Control, because it offers similar test functions like the original lego monitor and the code is a great learning example for java (including the GUI).
With the modifications I did it works now perfect for me. I also like the simple interface for transferring files and starting the programs via the GUI on the PC.

The only thing I am missing is to emulate remotely a button press on the EV3. Is there a way to do that via the java code on the PC?

One more question: Is there a common space where users can post their project code? This forum does not allow file attachments and limits the code postings.

greetings,
huha
huha
New User
 
Posts: 19
Joined: Tue Sep 24, 2013 9:24 pm

Re: Ev3Control.java and RMIRegulatedMotor Class

Postby lawrie » Tue Feb 18, 2014 9:28 pm

I am glad that EV3Control is useful to you, but I don't think its a very good example of GUI design. There are a lot of GUI classes used, so it shows you how to use various types of control, but it is probably not a very good example of lots of them. The user interface needs a lot more work on it to make it look more professional and to be more intuitive.

The NXT version that I wrote never really got finished. The NXT version allowed you to connect to multiple bricks and switch between them by clicking on the relevant entry in the connection table. I plan to do that for the EV3 version, but I currently only have one EV3 brick, so I cannot test it.

EV3Control is also a bit random about when it creates controls. Some of them are created when the program starts, and some are not created until it connects to a brick. This really needs tidying up.

Some of the tabs are very unfinished, and need a lot more work on them. Feedback on what people would like to see it do would be useful.

Also the code is a bit of a sprawling mess, and needs more structure.

Have you tried the drag and drop to upload jar files or other files to the EV3? I think that is quite cool. I really need to make transferring a file from the EV3 to the PC by drag and drop work.

I also think being able to see the LCD screen on the Console tab is pretty cool. This is mainly a copy of the work Andy did for the NXT.

I would like to do remote button press, and will add that to the remote API when we have tidied up the Button class.

I also need to make starting and stopping programs remotely work better. Currently I think that if you start a program from EV3Control it hangs until the program finishes.

I have thought about adding a tab which is effectively an ssh terminal, so that you can run Linux commands, but that could be a bit dangerous for inexperienced users.

It would be better if a lot of these functions were part of an Eclipse plugin rather than in a separate utility.
lawrie
leJOS Team Member
 
Posts: 842
Joined: Mon Feb 05, 2007 1:27 pm

Re: Ev3Control.java and RMIRegulatedMotor Class

Postby lawrie » Thu Feb 20, 2014 5:37 pm

I think I have fixed most of the problems with motor control in EV3Control in the latest master source. It needs the latest version of ev3classes as well, and it is best to build a new version of EV3Menu as well, but this may not be necessary. It is necessary to reboot the EV3 so that the menu uses the new version of ev3classes.jar. Currently this all works with the 0.6.0 SD card, but the usual provisos apply: the latest version won't always work with the previous release and the latest version can sometimes have new bugs in it.

Motor D now works, starts and stops don't lurch to the left or right, and tacho counts are returned. Also the limit box works to some extent. Tacho counts are a bit strange as the motor is closed after each use and recreated for the next use, so tacho counts start again from zero for each new move.

The motor control in EV3Control isn't intended for serious use, but mainly for testing things without writing code.

The code assumes you are using the large motor. It should work reasonably for other motors but won't be optimal. I should include a drop-down to let you specify the motor type.
lawrie
leJOS Team Member
 
Posts: 842
Joined: Mon Feb 05, 2007 1:27 pm

Re: Ev3Control.java and RMIRegulatedMotor Class

Postby huha » Thu Feb 20, 2014 10:26 pm

Lawrie,
thanks - this is great, I will test this week end.
I have not used the drag and drop function before and now I like the EV3Control even more:)
This week my 10 year old son has done his first java program.
I think you really have lowered the complexity as much as possible for anyone to start learning java.
The wifi setup from Ev3Control is very helpful, as it is quite painful to enter long passwords from the menue. I have not tested it yet ( i was using putty and vi), but will do with the new version.
The autoconnect feature to the EV3 is very convenient.

On my wish list for the future additional items would be

- remote buttons of the EV3 on the LCD tab so that all buttons can be handled remote (as described before)

- on the file menu additional buttons for:
- stop program on EV3 (kill process)
- download and run (from a defined project folder)
- refresh file list on EV3 (currently deleting without selecting any files will do that)
- shut down (i had a few situations where the EV3 buttons were freezing and I had to use putty to shutdown)
- add a warning for the format function before deleting all files

lower priority, but would be nice:
- automatically poll the sensor values in a separate thread every second
- automatic detection of sensors (if possible)
huha
New User
 
Posts: 19
Joined: Tue Sep 24, 2013 9:24 pm

Re: Ev3Control.java and RMIRegulatedMotor Class

Postby huha » Fri Feb 21, 2014 7:08 am

Lawrie,
I downloaded the new version late last night and can confirm that all issues I observed before are now fixed.
Motor D is now working and the motors are stopping on a line - thanks!!!
huha
New User
 
Posts: 19
Joined: Tue Sep 24, 2013 9:24 pm

Re: Ev3Control.java and RMIRegulatedMotor Class

Postby lawrie » Fri Feb 21, 2014 8:22 am

Hi huha, Thanks for the suggestions. I will investigate them.

Lawrie
lawrie
leJOS Team Member
 
Posts: 842
Joined: Mon Feb 05, 2007 1:27 pm

Re: Ev3Control.java and RMIRegulatedMotor Class

Postby huha » Sun Mar 09, 2014 8:01 pm

Hi Lawrie,
the new control center in 0.0.7 is fantastic - a big thanks! I really like the shutdown and the stop program button.
The only issue i found was with the buttons in the console panel. They worked fine for the menu, but did not work in my program.
I was using
Code: Select all
import lejos.hardware.Button;
import lejos.hardware.lcd.LCD;


public class EV3FirstProgram {

   public static void main(String[] args) {
      LCD.clear();
        LCD.drawString("Hallo Peter", 0, 5);
        Button.waitForAnyPress();
        LCD.clear();
        LCD.refresh();

   }

}

Any ideas what I made wrong?
huha
New User
 
Posts: 19
Joined: Tue Sep 24, 2013 9:24 pm

Re: Ev3Control.java and RMIRegulatedMotor Class

Postby lawrie » Mon Mar 10, 2014 11:32 am

They currently only work in the menu. I think I mentioned that in the 0.7.0 announcement.

The problem is that the RMI objects run in the menu JVM process, and not the user process. The button simulation sets data that is local to that process. Most things work as they are accessed from the kernel modules that are shared by all processes.

I am not currently sure what the best solution to this is. We could send the simulated key press to the kernel module, so that all JVM processes see it. Another alternative is to run the user process in the same JVM as the menu. That would be quite a big change. Another possibility is for the menu, when it gets a simulated button press and a user program is running to send it to the user program in some way. I am still thinking about what the best solution is.
lawrie
leJOS Team Member
 
Posts: 842
Joined: Mon Feb 05, 2007 1:27 pm

Re: Ev3Control.java and RMIRegulatedMotor Class

Postby huha » Mon Mar 10, 2014 10:31 pm

Hi Lawrie,
sorry I missed that. Would be very cool if you could get this working in one of the next versions.
huha
New User
 
Posts: 19
Joined: Tue Sep 24, 2013 9:24 pm


Return to EV3 Software

Who is online

Users browsing this forum: Google [Bot] and 3 guests

more stuff