Você está na página 1de 7

Control an Arduino from Java

November 13, 2013


3 Comments
You can communicate with and control an Arduino from Java
running on another computer.
You can run Java SE Embedded or Java ME on a Raspberry Pi, but the Arduino is a bit too
constrained to run Java directly. However, with the help of serial port communication
software, you can communicate with and control an Arduino from Java running on another
computer. Although the code to do so has been published on the Arduino site, it's still a little
tricky. In this blog, I'll go over how to make this work from different host operating systems,
as well as write an Arduino sketch to do something useful (thanks to Mike Riley for help with
the sketch).
First, locate and download the RXTX library. When you unzip the downloaded file, you'll
notice directories for various operating systems (OSs). Make note of which ones you're using,
as you'll need those specific files.
Next, create a new Java project in the IDE of your choice, and be sure to copy the following
RXTX files (from the download in the first step) into the project directory:
All OSs: RXTXcomm.jar
For Mac OS X: librxtxSerial.jnilib (from the Mac_OS_X subdirectory)
For Linux: librxtxSerial.so (from the correct Linux subdirectory)
For Solaris: librxtxSerial.so (from the correct Solaris subdirectory)
For Windows: rxtxSerial.dll (from the Windows subdirectory)
Next, modify your project's settings to include RXTXcomm.jar on the class path, and the path
to the native library in the command line via the -Djava.library.path parameter, like this:
?
1 java -Djava.library.path=/Users/ericjbruno/ArduinoTest1 -cp ./RXTXcomm.jar:./build/classes arduinotest1.ArduinoTest1
Connecting Via Java
The trickiest part of the code to get working is finding the correct serial port to connect to the
Arduino. This part varies by OS. On the Mac, the serial port should begin with
"/dev/tty.usbmodemXXXX". On Windows, it's usually "COM3", and on Linux, it will be one of
the "/dev/tty" or "/dev/usbdev/" ports. In the code, I've included an array of the
port Strings. Just comment out the ones not for your host OS, or better yet, add code to
detect your OS at runtime and use the proper String:
?
1
2
3
4
5
6
7
private static final String PORT_NAMES[] = {
"/dev/tty.usbmodem", // Mac OS X
"/dev/usbdev", // Linux
"/dev/tty", // Linux
"/dev/serial", // Linux
"COM3", // Windows
};
When the sample application (available for download here) starts up, it iterates through all of
the system ports looking for a match for your OS, and then attempts to connect to it:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Enumerate system ports and try connecting to Arduino over each
while (portId == null && portEnum.hasMoreElements()) {
CommPortIdentifier currPortId =
(CommPortIdentifier) portEnum.nextElement();
for (String portName : PORT_NAMES) {
if ( currPortId.getName().equals(portName)
|| currPortId.getName().startsWith(portName))
{
// Try to connect to the Arduino on this port
serialPort = (SerialPort)currPortId.open(appName, TIME_OUT);
portId = currPortId;
break;
}
}
}
If it finds a match, it will break out of the for and while loops, and then connect on that
port and configure it:
?
1
2
3
4
5
6
// set port parameters
serialPort.setSerialPortParams(
DATA_RATE, // 9600 baud
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
The last step in initialization is to add an event listener (more on this later) to receive events
from the Arduino, and tell it to call us back when there's data available:
?
1
2
3
// add event listeners
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
Running the code on my host system (a Macbook), I get the following output (I added some
tracing to the code to help):
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Experimental: JNI_OnLoad called.
Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version = RXTX-2.1-7
Trying:
port /dev/tty.Bluetooth-Serial-1
port /dev/cu.Bluetooth-Serial-1
port /dev/tty.Bluetooth-Serial-2
port /dev/cu.Bluetooth-Serial-2
port /dev/tty.EricsiPhone5-WirelessiAP
port /dev/cu.EricsiPhone5-WirelessiAP
port /dev/tty.Bluetooth-Modem
port /dev/cu.Bluetooth-Modem
port /dev/tty.Bluetooth-PDA-Sync
port /dev/cu.Bluetooth-PDA-Sync
port /dev/tty.usbmodem1411
Connected on port /dev/tty.usbmodem1411
If the classpath and library path settings are correct, the RXTX library will load and output the
version information at the top of the output above. Next, you can see the names of the serial
ports available on my Macbook, and how it finally finds a match and connects to port
"/dev/tty.usbmodem1411". We've now successfully connected to an Arduino from a Java
application, but to make this more fun, let's do something useful with this connectivity.
The Arduino Sketch
In this sample application, I plan to control a device from the Arduino via Java. To do so, I'm
using a PowerSwitch Tail, which takes low-voltage input to turn a connected AC device on/off.
Simply connect the PowerSwitch Tail to pins 13 and 2 (ground) on the Arduino as shown
below.

All we have to do now is send some data over the serial port to the Arduino to instruct it to
turn the PowerSwitch Tail on (along with the AC appliance plugged into it) by setting pin 13
high, and pin 2 low. To turn the appliance off, we just do the opposite. Here's the Arduino
sketch to make this happen (once you load this onto your Arduino you're good to go from
that point onward):
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int led = 13; // LED connected to digital pin 13
int pts = 2; // Powertail Switch 2 connected to digital pin 2
int recv = 0; // byte received on the serial port

void setup() {
// initialize onboard LED (led), Powertail (pts) and serial port
pinMode(led, OUTPUT);
pinMode(pts, OUTPUT);
Serial.begin(9600);
}

void loop()
{
// if serial port is available, read incoming bytes
if (Serial.available() > 0) {
recv = Serial.read();

// if 'y' (decimal 121) is received, turn LED/Powertail on
// anything other than 121 is received, turn LED/Powertail off
if (recv == 121){
digitalWrite(led, HIGH);
digitalWrite(pts,LOW);
} else {
digitalWrite(led, LOW);
digitalWrite(pts,HIGH);
}

// confirm values received in serial monitor window
Serial.print("--Arduino received: ");
Serial.println(recv);
}
}
As a side effect, turning pin 13 high also turns on an LED on the Arduino, which is useful for
debugging or if you don't have a PowerSwitch Tail.
To make this all work from Java, simply write the correct data (a 'y' in this case) as the
command to turn the LED and connected AC switch on, or any other data (i.e., 'n' or anything
really) to turn both off:
?
1
2
3
String data = "y";
output = serialPort.getOutputStream();
output.write( data.getBytes() );
The Arduino sketch also writes back to the host over the serial port to verify that it received a
command.The following code receives and processes these and other events (this method is
part of the RXTX SerialPortEventListener interface, which is provided as a listener in the
initialization code):
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public synchronized void serialEvent(SerialPortEvent oEvent) {
try {
switch (oEvent.getEventType() ) {
case SerialPortEvent.DATA_AVAILABLE:
if ( input == null ) {
input = new BufferedReader(
new InputStreamReader(
serialPort.getInputStream()));
}
String inputLine = input.readLine();
System.out.println(inputLine);
break;

default:
break;
}
}
catch (Exception e) {
System.err.println(e.toString());
}
}
Finally, to ensure that the serial port and Arduino are left in a state to communicate again,
make sure you close the serial port. This removes any filesystem locks on the host computer,
created to ensure only one device at a time communicates with the Arduino:
?
1
2
3
4
if ( serialPort != null ) {
serialPort.removeEventListener();
serialPort.close();
}
Other Important Steps
On UNIX-based systems, the RXTX library places its lock les in the folder /var/lock. If
this doesn't exist, communication will not work, although you won't receive any obvious
errors as to why. To create this directory if missing, open the terminal application and create
the lock directory as the root user or equivalent:
?
1 > sudo mkdir /var/lock
Enter your root or administrator password if prompted.
Finally, on UNIX-based systems, you may also need to run the Java application with root (or
equivalent) access to ensure the lock file can be created in /var/lock. Running the application
as a user with the proper privilege or via the sudo command will do the trick.
Programming an Arduino from Java has opened a whole new world for me. I've been able to
control sets of Arduinos from Java applications on a Raspberry Pi to do all sorts of fun and
useful things. For more fun Arduino projects, check out arduino.cc, Dr. Dobb's Mike Riley's
site, or Dr. Dobb's blogger Al Williams' posts on Arduino.
You can download the complete sample Java code here.
Happy coding!
In order to communicate with a comm port in Java, you need some implementation of the Java
Communications API. I can attest to RXTX, I have used it before to communicate with an Arduino.
Once you have your Java Communications implementation, it becomes fairly simple to
communicate with an Arduino:
CommPort arduino = getArduinoPort();
arduino.getOutputStream().write(1);

public CommPort getArduinoPort() {
Enumeration ports = CommPortIdentifier.getPortIdentifiers();
while(ports.hasMoreElements()) {
CommPortIdentifier identifier = (CommPortIdentifier)
ports.nextElement();
if(isArduino(identifier)) {
return identifier.open(getClass().getName(), 2000); // 2 second
timeout
}
}
return null;
}

public boolean isArduino(CommPortIdentifier identifier) {
// if you know the name of the port ahead of time you can
// compare it here with identifier.getName(), otherwise
// you can interface with the user like the Arduino IDE's
// serial monitor
}
The RXTX website also has other examples [2] which you might find useful.

Você também pode gostar