Arduino and Java

See page history for list of all contributors.

Overview

The Arduino IDE itself is written in Java, and it can communicate to the serial port via the RXTX Java library. That library is very similar to the Java Communications API extension. Internally the IDE remembers which port and baud rate you used last time. Unfortunately that internal implementation can not be considered public API you can reliably use. So you will have to keep your own settings to remember which COM port your Arduino card is using.

This interface sample presumes that you already know how to compile and run Java code. There are plenty of other resources on the Internet to teach you to program in Java. Most serious Java programmers use a Java IDE to create Java programs, like the free Eclipse IDE, but this example provides information for the less frequent Java programmer.

Arduino Board Set Up

Before you begin interfacing with your Arduino board, you must have the Arduino IDE installed and configured. Once it is installed, try this simple sketch. You can use the Serial Monitor of the IDE to verify that the board is set up correctly.

 
void setup(){
  Serial.begin(9600);
}

void loop(){
  Serial.println("Hello world");
  delay(1000);
}

RXTX Library Set Up

If you installed the Arduino IDE, you already have the RXTX library installed for the next steps, and you may be able to skip this section and start with the sample Java code. If you installed a separate copy of the RXTX, you can do one of the following:

Platform indepedent (not require for Linux with the new method)

  • When starting Java, use the -Djava.library.path= command line argument to state where the JNI libraries are located. For example, you could use java -Djava.library.path=C:\rxtx-2.2pre2-bins\win32 SerialTest You should also ensure that the RXTXcomm.jar is in your CLASSPATH.

Windows 32-bit

  • Copy the win32/rxtxSerial.dll into C:\Windows\System32
  • Append the directory containing rxtxSerial.dll into your PATH environment variable.

Windows 64-bit

  • Copy the win64/rxtxSerial.dll into C:\Windows\SysWOW64
  • Append the directory containing rxtxSerial.dll into your PATH environment variable.

Linux

  • Download the last version of the rxtx java library at http://rxtx.qbang.org/wiki/index.php/Download.
  • Extract the package, open extracted files, go to Linux and choose the folder which correspond to your system configuration.
  • Copy all the files from the previous folder to /jre/lib/[machine type] (i386 for instance).
  • Copy RXTXcomm.jar from the main folder to /jre/lib/ext.

Mac OS X

  • Copy RXTXcomm.jar from the main folder to /Library/Java/Extensions
  • Copy the mac-10.5/librxtxSerial.jnilib (or, if this version does not work for you, obtain a 64 bit compiled version from http://blog.iharder.net/2009/08/18/rxtx-java-6-and-librxtxserial-jnilib-on-intel-mac-os-x/) and paste into /Library/Java/Extensions
  • Append the directory containing librxtxSerial.jnilib files into your DYLD_LIBRARY_PATH environment variable
  • See the other notes on Mac OS X below the sample java code.

Sample Java Code

Now that you have confirmed that the board is working, you are now ready to save and compile the following sample code. You should save it as SerialTest.java. You may need to modify the PORT_NAMES of this sample to use the correct COM port that you are using.

 
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import gnu.io.CommPortIdentifier; 
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent; 
import gnu.io.SerialPortEventListener; 
import java.util.Enumeration;


public class SerialTest implements SerialPortEventListener {
	SerialPort serialPort;
        /** The port we're normally going to use. */
	private static final String PORT_NAMES[] = { 
			"/dev/tty.usbserial-A9007UX1", // Mac OS X
                        "/dev/ttyACM0", // Raspberry Pi
			"/dev/ttyUSB0", // Linux
			"COM3", // Windows
	};
	/**
	* A BufferedReader which will be fed by a InputStreamReader 
	* converting the bytes into characters 
	* making the displayed results codepage independent
	*/
	private BufferedReader input;
	/** The output stream to the port */
	private OutputStream output;
	/** Milliseconds to block while waiting for port open */
	private static final int TIME_OUT = 2000;
	/** Default bits per second for COM port. */
	private static final int DATA_RATE = 9600;

	public void initialize() {
                // the next line is for Raspberry Pi and 
                // gets us into the while loop and was suggested here was suggested http://www.raspberrypi.org/phpBB3/viewtopic.php?f=81&t=32186
                System.setProperty("gnu.io.rxtx.SerialPorts", "/dev/ttyACM0");

		CommPortIdentifier portId = null;
		Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();

		//First, Find an instance of serial port as set in PORT_NAMES.
		while (portEnum.hasMoreElements()) {
			CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
			for (String portName : PORT_NAMES) {
				if (currPortId.getName().equals(portName)) {
					portId = currPortId;
					break;
				}
			}
		}
		if (portId == null) {
			System.out.println("Could not find COM port.");
			return;
		}

		try {
			// open serial port, and use class name for the appName.
			serialPort = (SerialPort) portId.open(this.getClass().getName(),
					TIME_OUT);

			// set port parameters
			serialPort.setSerialPortParams(DATA_RATE,
					SerialPort.DATABITS_8,
					SerialPort.STOPBITS_1,
					SerialPort.PARITY_NONE);

			// open the streams
			input = new BufferedReader(new InputStreamReader(serialPort.getInputStream()));
			output = serialPort.getOutputStream();

			// add event listeners
			serialPort.addEventListener(this);
			serialPort.notifyOnDataAvailable(true);
		} catch (Exception e) {
			System.err.println(e.toString());
		}
	}

	/**
	 * This should be called when you stop using the port.
	 * This will prevent port locking on platforms like Linux.
	 */
	public synchronized void close() {
		if (serialPort != null) {
			serialPort.removeEventListener();
			serialPort.close();
		}
	}

	/**
	 * Handle an event on the serial port. Read the data and print it.
	 */
	public synchronized void serialEvent(SerialPortEvent oEvent) {
		if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
			try {
				String inputLine=input.readLine();
				System.out.println(inputLine);
			} catch (Exception e) {
				System.err.println(e.toString());
			}
		}
		// Ignore all the other eventTypes, but you should consider the other ones.
	}

	public static void main(String[] args) throws Exception {
		SerialTest main = new SerialTest();
		main.initialize();
		Thread t=new Thread() {
			public void run() {
				//the following line will keep this app alive for 1000 seconds,
				//waiting for events to occur and responding to them (printing incoming messages to console).
				try {Thread.sleep(1000000);} catch (InterruptedException ie) {}
			}
		};
		t.start();
		System.out.println("Started");
	}
}

There are other methods to get data over the serial port, like via polling, but this event based method has very low CPU overhead because the listener is only called when data is available.

Alternatives

Ardulink

Ardulink is a complete, open source, java solution for the control and coordination of Arduino boards. Communication protocol, java SWING components collection, Network Server and more. It uses RXTX library for serial communication and Java libusb / libusb-win32 wrapper to communicate with boards without serial interface.

Ardulink has a ready SWING console able to drive Arduino in minutes.

The main Adulink java class is the Link class. In order to communicate with Arduino you have to retrieve a Link instance.

Link link = Link.getDefaultInstance();

or for instance

Link link = Link.createInstance("digisparkConnection", new DigisparkUSBConnection());

Then the connection

boolean connected = link.connect(comPort, baudRate); // comPort could be "COM19" for windows

Then send messages

link.sendPowerPinIntensity(pin, powerValue); // To PWM pins (analogWrite)
link.sendPowerPinSwitch(pin, IProtocol.POWER_HIGH); // to digitalWrite
link.sendCustomMessage("openDoor");
link.sendCustomMessage("goAhead");

or receive messages

link.addDigitalReadChangeListener(new DigitalReadChangeListener() {

	@Override
	public void stateChanged(DigitalReadChangeEvent e) {
		// do something
	}

	@Override
	public int getPinListening() {
		return 11;
	}
});

link.addRawDataListener(new RawDataListener() {

	@Override
	public void parseInput(String id, int numBytes, int[] message) {
		// do something
	}
});

more info here: http://www.ardulink.org

Use Sample Code

Windows

For Windows you can create a batch file called run.bat in the same directory as the sample code mentioned above. This batch file can be used on your system, but you may need to modify the paths to match the install locations of your Java and Arduino IDE on your system.

 
setlocal
set PATH=%PATH%;C:\Program Files (x86)\arduino-0017\
"C:\Program Files (x86)\Java\jdk1.6.0_12\bin\javac" -cp "C:\Program Files (x86)\arduino-0017\lib\RXTXcomm.jar" SerialTest.java
"C:\Program Files (x86)\Java\jdk1.6.0_12\bin\java" -cp "C:\Program Files (x86)\arduino-0017\lib\RXTXcomm.jar;." SerialTest
 

Basically, you will need to add the RXTXcomm.jar to your class path, and you will need to add the associated JNI interface DLL (rxtxSerial.dll) to your PATH. For other platforms, you will need to add the same JNI shared library to your run time path.

When you run the run.bat file, you should see the same results as the Arduino IDE Serial Monitor. You can use Ctrl+Break to stop the program.

MacOSX

Presuming that you are using the sample code above you may need to do the following steps.

1. Using the terminal, change to the directory containing the files to be compiled. Compile the file using (replace filename with your java class name):

 
javac -classpath RXTXcomm.jar:. SerialTest.java 

If you placed the RXTX libraries into /Library/Java/Extensions, the file can be compiled by simply using:

 
javac SerialTest.java

2. Now it is time to run the compiled source code. This requires inclusion of the JNI shared library into the library path by using the command below:

 
java -Djava.library.path=. -cp RXTXcomm.jar:. SerialTest

If you placed the RXTX jar and library in the /Library/Java/Extensions folder rather than the directory that contains the file to be compiled, the file can be run without the library path as shown below:

 
java SerialTest

3. The code should now run successfully and print the serial output to the screen (as with the Arduino serial monitor)

Mac OS X Architecture Matching Problems

If you get an error message telling you the library is not matching architecture it might be due to MacOSX Snow Leopard trying to execute the program in 64bit mode. If you run into this problem try the VM argument -d32 to force the java program to be executed in 32bit mode.

Mac OS X locking

If you encounter any issues with the port being unable to be locked, these instructions may help. If you set up the Arduino environment, this should not be an issue. This also does not seem to be an issue with RXTX version 2.2.

1. The RXTX library places its lock files in the folder /var/lock - which sometimes does not exist. Open terminal and Create the lock directory (as root) by using the following command:

 
sudo mkdir /var/lock

And enter your root password when prompted.

2. The appropriate permissions need to be applied to the /var/lock directory to allow the program to be run without being root. It is necessary to make sure you're in the group uucp and make sure the directory has group write permissions to uucp. Replace ‘username’ with your profile user name.

 
sudo dscl . -append /groups/_uucp GroupMembership username 
sudo chgrp uucp /var/lock 
sudo chmod 775 /var/lock 

A port in use exception (gnu.io.PortInUseException) with version 2.1-7 might also be solved by changing permissions using the sh script from jlog: http://jlog.org/rxtx-mac.html

Linux

  • You must have follow the steps in the Linux part before.
  • To compile just lunch "javac SerialTest.java".
  • Then type "java SerialTest" and it should work.

Transmitting data to the arduino from the computer.

In my experience, it seems that the Serial connection must be connected somewhere above 1 second (I have 1.5 seconds in my program) before a transmission can be made. It seems that for at least the atmega168 and diecimila, doing so ensures your transmission actually is transmitted. For doing that, Thread.sleep(delay) is used and delay is specified in milliseconds so I would use Thread.sleep(1500) after the Serial port is established. It seems this might be due to the program resetting when a serial connection is made, and the program has a necessary setup time.

The OutputStream comes with 3 different write methods to send data from the computer to the Arduino. In the above example, you could use output.write(String) to send data, as in output.write("Hello Arduino!"). There's also one that'll send an integer value and another that will transmit an array of Bytes.

I found on the arduino's program, to accurately receive the data instead of receiving non-intelligible "255" data points, I had to maintain a generous delay between the Serial.read() commands. I ended up using 20 ms for safe measure, but the actual necessary number is likely much lower and one could use a "255 filter" to extract meaningful data, assuming none of your meaningful data consists of the number 255.

The simple Serial.read() function will process a byte at a time, although there are more interesting read functions available.

Proper Port Handling

If you want to properly close the port, you should call the close() method on the serial port object upon program exit. This will prevent the port from being locked after your program exits. You may notice this issue on Linux and not Windows. The serial port's close method should be called from a method that is synchronized with the serialEvent method, which will prevent any exceptions from appearing during program shutdown.

Share