Remote-controlled lego with LeJOS using EV3 controller

The last day of jCrete was with two hacking sessions - one on optimizing a NES emulator (if I got it correctly) and one on building a Lego and writing some software on LeJOS and EV3 controller (ARM processor inside).

This is what we did (@claudiotagliola did more than I have):

lego IMG_5263 IMG_5266

We used LeJOS, with LeJOS plugin for eclipse, initial code we got from Steven's presentation on the subject,  but we decided not to build the thing shown on the presentation.

We built a pretty bulky two-motor lego using snow-chains. We installed a server app that listened on a port and we sent it commands using a awt/swing app.

Videos:

Here's the code:

The app installed on the device:

package jcrete.hacking;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

import lejos.hardware.Button;
import lejos.hardware.Key;
import lejos.hardware.KeyListener;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
import lejos.utility.Delay;

/**
 * This was written on jCrete 2015 on a LeJOS session by Steven Chin.
 * 
 * We were given the task to build a lego and do something cool with it.
 * We built a pretty large tank and remote-controlled it via wi-fi with
 * simple socket commands.
 * 
 * For more info, go to https://mihail.stoynov.com/?p=2909
 * 
 * This is a mock server for testing if you don't have a lego at hand.
 * 
 * @author Nayden Gochev, jug.bg
 * @author Mihail Stoynov, jug.bg
 *
 */
public class E3vRemoteControlCarApp {

	static boolean isRunning = true;

	public static void main(String[] args) throws IOException {

		try (
				final EV3LargeRegulatedMotor leftMottor = new EV3LargeRegulatedMotor(MotorPort.B);
				final EV3LargeRegulatedMotor rightMottor = new EV3LargeRegulatedMotor(MotorPort.C);
				ServerSocket serv = new ServerSocket(19231);
				) {

			Socket socket = serv.accept();
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					socket.getInputStream()));

			// if we use the buttons on the device directly
			Button.UP.addKeyListener(new KeyListener() {

				@Override
				public void keyReleased(Key k) {
					leftMottor.stop(true);
					rightMottor.stop(true);
				}

				@Override
				public void keyPressed(Key k) {
					leftMottor.setSpeed(1500);
					leftMottor.setAcceleration(150);
					leftMottor.forward();
					rightMottor.setSpeed(1500);
					rightMottor.setAcceleration(150);
					rightMottor.forward();

				}
			});

			Button.DOWN.addKeyListener(new KeyListener() {

				@Override
				public void keyReleased(Key k) {
					leftMottor.stop(true);
					rightMottor.stop(true);
				}

				@Override
				public void keyPressed(Key k) {
					leftMottor.setSpeed(1500);
					leftMottor.setAcceleration(150);
					leftMottor.backward();
					rightMottor.setSpeed(1500);
					rightMottor.setAcceleration(150);
					rightMottor.backward();

				}
			});

			Button.RIGHT.addKeyListener(new KeyListener() {

				@Override
				public void keyReleased(Key k) {
					rightMottor.stop(true);
					leftMottor.stop(true);
				}

				@Override
				public void keyPressed(Key k) {
					rightMottor.setSpeed(1500);
					rightMottor.setAcceleration(150);
					rightMottor.forward();
					leftMottor.setSpeed(1500);
					leftMottor.setAcceleration(150);
					leftMottor.backward();
				}
			});

			Button.LEFT.addKeyListener(new KeyListener() {

				@Override
				public void keyReleased(Key k) {
					rightMottor.stop(true);
					leftMottor.stop(true);
				}

				@Override
				public void keyPressed(Key k) {
					rightMottor.setSpeed(1500);
					rightMottor.setAcceleration(150);
					rightMottor.backward();
					leftMottor.setSpeed(1500);
					leftMottor.setAcceleration(150);
					leftMottor.forward();
				}
			});

			Button.ESCAPE.addKeyListener(new KeyListener() {

				@Override
				public void keyReleased(Key k) {
				}

				@Override
				public void keyPressed(Key k) {
					E3vRemoteControlCarApp.isRunning = false;
				}
			});


			// we copied it from somewhere, not necessary
			Delay.msDelay(3000);


			// the listener with the while readline
			String line;
			while ((line = reader.readLine()) != "STOP" && isRunning) {
				System.out.println("RECIEVED " + line);
				switch (line) {
				case "UP-PRESS":
					leftMottor.setSpeed(1500);
					// leftMottor.setAcceleration(150);
					leftMottor.forward();
					rightMottor.setSpeed(1500);
					// rightMottor.setAcceleration(150);
					rightMottor.forward();
					break;
				case "UP-RELEASE":
					leftMottor.stop(true);
					rightMottor.stop(true);
					break;
				case "DOWN-PRESS":
					leftMottor.setSpeed(1500);
					// leftMottor.setAcceleration(150);
					leftMottor.backward();
					rightMottor.setSpeed(1500);
					// rightMottor.setAcceleration(150);
					rightMottor.backward();
					break;
				case "DOWN-RELEASE":
					leftMottor.stop(true);
					rightMottor.stop(true);
					break;
				case "LEFT-PRESS":
					rightMottor.setSpeed(1500);
					// rightMottor.setAcceleration(150);
					rightMottor.backward();
					leftMottor.setSpeed(1500);
					// leftMottor.setAcceleration(150);
					leftMottor.forward();
					break;
				case "LEFT-RELEASE":
					rightMottor.stop(true);
					leftMottor.stop(true);
					break;
				case "RIGHT-PRESS":
					rightMottor.setSpeed(1500);
					// rightMottor.setAcceleration(150);
					rightMottor.forward();
					leftMottor.setSpeed(1500);
					// leftMottor.setAcceleration(150);
					leftMottor.backward();
					break;
				case "RIGHT-RELEASE":
					rightMottor.stop(true);
					leftMottor.stop(true);
					break;
				case "STOP":
					E3vRemoteControlCarApp.isRunning = false;
					break;
				}
			}
		}
	}
}

 

The controller:

import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
 
import javax.swing.JButton;
import javax.swing.JFrame;
 
/**
/**
 * This was written on jCrete 2015 on a LeJOS session by Steven Chin.
 * 
 * We were given the task to build a lego and do something cool with it.
 * We built a pretty large tank and remote-controlled it via wi-fi with
 * simple socket commands.
 * 
 * For more info, go to https://mihail.stoynov.com/?p=2909
 * 
 * This is a mock server for testing if you don't have a lego at hand.
 * 
 * @author Nayden Gochev, jug.bg
 * @author Mihail Stoynov, jug.bg
 *
 */
public class Remote extends JFrame {
 
	private static final long serialVersionUID = -8402983606638099877L;
 
	private final JButton left;
	private final JButton right;
	private final JButton up;
	private final JButton down;
	private final JButton stop;
 
	private BufferedWriter pw;
 
	public static void main(String[] args) {
		Remote remote = new Remote();
		remote.setSize(500, 500);
		remote.setVisible(true);
	}
 
	public Remote() {
		try {
			Socket socket = new Socket("192.168.0.107", 19231);
//			Socket socket = new Socket("127.0.0.1", 19231);//for mocking
			pw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
 
		setLayout(new BorderLayout());
 
 
 
		left = new JButton("LEFT");
		this.getContentPane().add(left, BorderLayout.WEST);
		left.addMouseListener(new MouseAdapter() {
 
			@Override
			public void mouseReleased(MouseEvent e) {
				leftRelease();
//				System.out.println("LEFT-RELEASE\n");pw.flush();
			}
 
 
			@Override
			public void mousePressed(MouseEvent e) {
				leftPress();
//				System.out.println("LEFT-PRESS\n");pw.flush();
			}
 
 
		});
		right = new JButton("RIGHT");
		this.getContentPane().add(right, BorderLayout.EAST);
		right.addMouseListener(new MouseAdapter() {
 
			@Override
			public void mouseReleased(MouseEvent e) {
				rightRelease();
//				System.out.println("RIGHT-RELEASE\n");pw.flush();
			}
 
 
 
			@Override
			public void mousePressed(MouseEvent e) {
				rightPress();
//				System.out.println("RIGHT-PRESS\n");pw.flush();
			}
 
 
		});
		up = new JButton("UP");
		this.getContentPane().add(up, BorderLayout.NORTH);
		up.addMouseListener(new MouseAdapter() {
 
			@Override
			public void mouseReleased(MouseEvent e) {
				upRelease();
//				System.out.println("UP-RELEASE\n");pw.flush();
			}
 
 
 
			@Override
			public void mousePressed(MouseEvent e) {
				upPress();
//				System.out.println("UP-PRESS\n");pw.flush();
			}
 
 
		});
		down = new JButton("DOWN");
		this.getContentPane().add(down, BorderLayout.SOUTH);
		down.addMouseListener(new MouseAdapter() {
 
			@Override
			public void mouseReleased(MouseEvent e) {
				downRelease();
//				System.out.println("DOWN-RELEASE\n");
			}
 
 
 
			@Override
			public void mousePressed(MouseEvent e) {
				downPress();
//				System.out.println("DOWN-PRESS\n");
			}
 
 
		});
		stop = new JButton("STOP\n");
		this.getContentPane().add(stop, BorderLayout.CENTER);
		stop.addMouseListener(new MouseAdapter() {
 
			@Override
			public void mousePressed(MouseEvent e) {
				sendCommand("STOP");
			}
		});
 
		//keypad arrows work only if the focus is on the stop button
		//lame but that's life
		stop.addKeyListener(new KeyListener() {
			@Override
			public void keyTyped(KeyEvent event) {
				// TODO Auto-generated method stub
 
			}
 
			@Override
			public void keyReleased(KeyEvent event) {
				if(KeyEvent.VK_UP == event.getKeyCode()){
					upRelease();
				} else if(KeyEvent.VK_DOWN == event.getKeyCode()){
					downRelease();
				} else if(KeyEvent.VK_LEFT == event.getKeyCode()){
					leftRelease();
				} else if(KeyEvent.VK_RIGHT == event.getKeyCode()){
					rightRelease();
				}
			}
 
			@Override
			public void keyPressed(KeyEvent event) {
				if(KeyEvent.VK_UP == event.getKeyCode()){
					upPress();
				} else if(KeyEvent.VK_DOWN == event.getKeyCode()){
					downPress();
				} else if(KeyEvent.VK_LEFT == event.getKeyCode()){
					leftPress();
				} else if(KeyEvent.VK_RIGHT == event.getKeyCode()){
					rightPress();
				}
			}
		});
 
 
		pack();
	}
 
	private void downPress() {
		sendCommand("DOWN-PRESS");
	}
 
	private void sendCommand(String command) {
		try {
			pw.write(command+"\n");pw.flush();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}
 
	private void downRelease() {
		sendCommand("DOWN-RELEASE");
	}
 
	private void leftPress() {
		sendCommand("LEFT-PRESS");
	}
 
	private void upRelease() {
		sendCommand("UP-RELEASE");
	}
 
	private void leftRelease() {
		sendCommand("LEFT-RELEASE");
	}
	private void rightRelease() {
		sendCommand("RIGHT-RELEASE");
	}
 
	private void upPress() {
		sendCommand("UP-PRESS");
	}
 
	private void rightPress() {
		sendCommand("RIGHT-PRESS");
	}
}

 

Mock app to test the remote:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * This was written on jCrete 2015 on a LeJOS session by Steven Chin.
 * 
 * We were given the task to build a lego and do something cool with it.
 * We built a pretty large tank and remote-controlled it via wi-fi with
 * simple socket commands.
 * 
 * For more info, go to https://mihail.stoynov.com/?p=2909
 * 
 * This is a mock server for testing if you don't have a lego at hand.
 * 
 * @author Nayden Gochev, jug.bg
 * @author Mihail Stoynov, jug.bg
 *
 */
public class ServerMock {
	public static void main(String[] args) throws IOException {
		try (ServerSocket server = new ServerSocket(19231);) {
			Socket socket = server.accept();
			System.out.println("ACCEPTING");
			BufferedReader reader = new BufferedReader(
					new InputStreamReader(
							socket.getInputStream()));
	
			System.out.println(reader.readLine());
			String line;
			while ((line = reader.readLine()) != null) {
				System.out.println("RECIEVED " + line);
			}
		}
	}
}

Powering an external hdd on a raspberry pi or odroid

IMG_5449

I've had issues powering an external hdd on a raspberry pi or odroid. I had to buy Y-cable (Y-cable = branched USB cord for dual power).

I found out, that powering the raspberry pi or odroid on the normal USB supplies more power than on the mini/micro-USB they use. The micro/mini USB used for power has a fuse that cannot supply more than 1A, but powering via one of the USB typeA works fine. Of course you would need a Y-cable, because even the most powerful USB chargers cannot produce enough power on one port.

That's another point - most USB chargers say they produce 2A or 2.1A and the crappy ones produce .3A, the good ones go up to .9A. So everybody lies. But .9A is good enough with a Y-cable.

The PI/Odroid use like .5A, the drive uses .3A, but they spike to more than 1Amp.

jCrete

jCrete is an unconference organized by Heinz Kabutz (author of the Java Specialist newsletter).

*unconference - top people, informal talks, discussions instead of sessions (most in a restaurant or at the beach).

What I learned:

Unsafe is going to be available in jdk9 with a jre switch on startup. Oracle is working on isolating (boundary checks) the unmanaged heap so that

  • mistakes will not mess up the managed heap
  • mistakes will not cause a segmentation fault (crash the whole jvm, because someone is trying to read memory from another process)

Oracle might introduce a commercial GC with deterministic stop-the-world pauses.

G1 will become the default GC in jdk9.

I will update this accordingly with more info.

jdk1.8.0_25 internal compiler error

Screen Shot 2015-07-14 at 11.35.31

A bug report here: https://bugs.openjdk.java.net/browse/JDK-8065424

Information:Using javac 1.8.0_25 to compile java sources
Information:java: An exception has occurred in the compiler (1.8.0_25). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport) after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report. Thank you.
'xj-conc-j8'
Information:7/14/15, 11:22 - Compilation completed with 1 error and 0 warnings in 2s 319ms
Error:java: Compilation failed: internal java compiler error