Arduino i Java
Jakiś czas temu pomyślałem, że nie samą Javą człowiek żyje i fajnie byłoby pobawić się nieco elektroniką. Wybór padł na Arduino, na którym w teorii można w prosty sposób zbudować bardzo ciekawe projekty od robotów po system automatyki domowej. Zakupiłem zestaw startowy, który przyszedł do mnie dokładnie wczoraj i nie byłbym sobą, gdybym nie spróbował go skomunikować z Javą. Na początek podłączamy "gołe" Arduino poprzez USB, instalujemy Arduino IDE z odpowiednimi sterownikami i to tyle. Następnie musimy pobrać bibliotekę RXTXi dołączyć ją do swojego projektu lub dodać odpowiednie zależności w Mavenie. W paczce znajdują się także dodatkowe natywne biblioteki, które należy dołączyć.
Na początek polecam uruchomić poniższy program, który w przypadku wykrycia podłączonego Arduino wyświetli nam informację o porcie poprzez który możemy się komunikować (w przypadku problemów z biblioteką żaden port nie zostanie wykryty):
import gnu.io.CommPortIdentifier;
import java.util.Enumeration;
public class FirstTest {
public static void main(String[] args) {
System.out.println("Program started");
CommPortIdentifier serialPortId;
Enumeration enumComm;
enumComm = CommPortIdentifier.getPortIdentifiers();
while (enumComm.hasMoreElements()) {
serialPortId = (CommPortIdentifier) enumComm.nextElement();
if (serialPortId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
System.out.println(serialPortId.getName());
}
}
System.out.println("Finished successfully");
}
}
Na Arduino wgrajmy prosty program, który co sekundę będzie zwracał poprzez Serial Port napis "Hello World". Arduino programuje się w języku C, jednak znając Javę lub jakikolwiek inny język poradzimy sobie bez problemu:
void setup(){
Serial.begin(9600);
}
void loop(){
Serial.println("Hello world");
delay(1000);
}
W Arduino IDE znajdujemy potwierdzenie tego, że wszystko działa jak należy, pozostaje nam jedynie napisać aplikacje w Javie, która odbierze dane.
Na oficjalnej stronie Arduino można znaleźć prosty przykład kodu, z którego najważniejszą dla nas informacją jest implementacja interfejsu SerialPortEventListener , który to posiada metodę serialEvent(SerialPortEvent event) . Wykorzystuje ona mechanizm zdarzeń, czyli coś co znamy m.in. z Javy FX (EventHandler ) i pozwala na nasłuchiwanie sytuacji, gdy zaczną do nas napływać jakieś informacje. Jest to z naszej perspektywy rozwiązanie o tyle dobre, że w bardzo małym stopniu angażuje CPU i aplikacja może sobie np. cały czas działać w tle. Kod po usunięciu zbędnych z naszego punktu widzenia śmieci przedstawia się tak jak poniżej. ArduinoReader.java
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ArduinoReader implements SerialPortEventListener {
SerialPort serialPort;
// Na windowsie domyślnie posługujemy się portem COM3
private static final String PORT_NAME = "COM3";
private BufferedReader input;
/** 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() {
CommPortIdentifier portId;
try {
portId = CommPortIdentifier.getPortIdentifier(PORT_NAME);
// otwieramy i konfigurujemy port
serialPort = (SerialPort) portId.open(this.getClass().getName(),
TIME_OUT);
serialPort.setSerialPortParams(DATA_RATE, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
// strumień wejścia
input = new BufferedReader(new InputStreamReader(
serialPort.getInputStream()));
// dodajemy słuchaczy zdarzeń
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
} catch (Exception e) {
System.err.println(e.toString());
}
}
public synchronized void close() {
if (serialPort != null) {
serialPort.removeEventListener();
serialPort.close();
}
}
/**
* Metoda nasłuchuje na dane na wskazanym porcie i wyświetla je w konsoli
*/
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());
}
}
}
public static void main(String[] args) throws Exception {
ArduinoReader main = new ArduinoReader();
main.initialize();
Thread t = new Thread() {
public void run() {
try {
Thread.sleep(1000000);
main.close();
} catch (InterruptedException ie) {
}
}
};
t.start();
System.out.println("Started");
}
}
Po uruchomieniu aplikacji widzimy oczekiwany wynik w konsoli Eclipse:
Dalej nie ma problemu z tym, żeby na Arduino zbudować prosty czujnik światła i te wartości odczytywać w naszej aplikacji napisanej w Javie:
int lightPort = 0;
int lightValue = 0;
void setup(){
pinMode(lightPort, INPUT);
Serial.begin(9600);
}
void loop(){
lightValue = analogRead(lightPort);
Serial.println(lightValue);
delay(1000);
}
Układ:
i wynik z tej samej aplikacji co wcześniej:
Widzimy, że w zależności od zmieniającego się natężenia światła zmienia się opór fotorezystora, a tym samym odczyt w programie. Dalej takie dane można oczywiście wykorzystywać do monitorowania pory dnia, zapisywać je na komputerze, wysyłać na serwer, z którym później możemy się łączyć z aplikacji napisanej np. w Androidzie - ogranicza nas tylko wyobraźnia. Java zdecydowanie nie jest rozwiązaniem idealnym do komunikacji z Arduino, ale jak widać da się. Osobiście po jednym dniu zabawy z tą płytką jestem zachwycony i polecam każdemu. Na blogu pojawi się na pewno jeszcze nie jeden wpis poświęcony Arduino - w kolejnym zajmiemy się biblioteką Ardulink.
Dyskusja i komentarze
Masz pytania do tego wpisu? Może chcesz się podzielić spostrzeżeniami? Zapraszamy dyskusji na naszej grupie na Facebooku.