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ć.

build path

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");
	}
}
arduino java

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.

arduino ide

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:

hello world arduino

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:

arduino setup

i wynik z tej samej aplikacji co wcześniej:

console output

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.