はじめに
ラクス Advent Calendar 2019の10日目です。
昨日の記事は@choreiさんのVuetify公式ドキュメントの読み方でした。
今回の記事は、JavaのプログラムでArduinoを動かしてみたお話です。
Oracle Code One 2019 報告会で聴講したセッションに触発されて、Java + Arduinoで色々試してみました。
Arduinoとは
本題に行く前に、Arduinoについて軽く説明します。
Arduinoは、AVRというマイクロコンピュータと入出力ポートを備えた基板で、制御にArduino言語というCに似た言語を利用します。
※基板と言語を合わせてArduinoと呼ぶこともあるようです
制御するためのプログラムをスケッチと呼び、Arduino IDEを使ってPC上で作成することができます。
作成したスケッチをArduino IDEでコンパイルし、PCから基盤へ転送するのがArduinoで電子工作する基本的な流れです。
JavaでArduinoを動かす準備
Firmata 4jというライブラリを利用すると、JavaのプログラムからArduinoを簡単に動かすことができます。
Firmata 4jは、Firmataというプロトコルを使って、JavaのプログラムとArduinoとの通信を行うためのライブラリです。
ということで、JavaでArduinoを動かす準備をしましょう。
今回使った開発環境は、以下の通りです。
- Arduino
- 基盤
Arduino Uno - IDE
Arduino IDE
- 基盤
- Java
- JDK
1.8.0_131 - IDE
Eclipse Version Neon.3 Release (4.6.3)
- JDK
まずは、ArduinoでFirmataが使えるようにします。
Arduino IDEを起動し、スケッチ例
> Firmata
> StandardFirmata
を選択すると、Firmataによる通信を行う為のプログラムが表示されます。
あとは、表示されたプログラムをコンパイルして基盤に転送すれば、Arduino側の準備は完了です。
正直、おまじない程度に理解してます
次に、Javaのプロジェクトを作成します。
Firmata 4jはpom.xml
で導入できるようになっているので、今回はmavenでプロジェクトを作成しました。
プロジェクトを作成したら、Firmata 4jのリポジトリ > Installationにあるとおり、pom.xmlに依存関係を追加します。
これで、JavaのプログラムからArduinoを動かす準備はできました。
ただ、今回はスケッチを作成するように実装したかったので、専用のクラスを自作してみました。
package test1;
import java.util.ArrayList;
import java.util.List;
import org.firmata4j.IODevice;
import org.firmata4j.Pin;
import org.firmata4j.firmata.FirmataDevice;
/**
* スケッチの抽象クラス. <br>
* Arduino言語と同様、setUp, loopメソッドを実装する.<br>
* また、スケッチの継続条件をisContinuableメソッドで実装する.
*
* @author FlatMountain
*
*/
public abstract class AbstractSketch {
private IODevice device;
protected List<Pin> pins;
/**
* スケッチの実行フレーム(ms).
*/
protected int frame;
/**
* ArduinoをFirmata4jで操作できるようにする.
*/
private void initializeSketch() {
device = new FirmataDevice("xxx"); // ← Arduino IDEに表示されたポート名
try {
device.start();
device.ensureInitializationIsDone();
} catch (Exception e) {
throw new RuntimeException(e);
}
pins = new ArrayList<>();
for (int i = 0; i < device.getPinsCount(); i++) {
pins.add(device.getPin(i));
}
frame = 0;
}
/**
* Arduino言語のsetUpと同じように実装する.
*/
abstract protected void setUp();
/**
* Arduino言語のloopと同じように実装する.
*/
abstract protected void loop();
/**
* スケッチが継続できるか判定する.
*
* @return 継続できればtrue, できなければfalse.
*/
abstract protected boolean isContinuable();
/**
* Firmata4jの終了処理.
*/
private void finalizeSketch() {
try {
if (device.isReady()) {
device.stop();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* スケッチの実行処理. <br>
* loopメソッドの実行後、1msスリープする.
*/
public void execute() {
try {
this.initializeSketch();
this.setUp();
while (this.isContinuable()) {
this.loop();
Thread.sleep(1);
frame++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
this.finalizeSketch();
}
}
}
mainメソッドでは、抽象クラスの型で宣言した変数に実装クラスのインスタンスを代入して、execute
メソッドを実行するようにします。
package test1;
public class Main {
public static void main(String[] args) {
AbstractSketch sketch = new xxxxxx(); // ← ここで実装クラスのインスタンスを代入する
sketch.execute();
}
}
Arduino + JavaでLチカしてみた!
電子工作におけるHello WorldはLチカ1らしいので、初めにJavaでLチカをやってみます。
まずは、ArduinoにLEDランプを繋ぎます。
以下のように、抵抗入りLEDをArduinoへ繋ぎました。
※諸々の事情で回路図は貼れませんでした...
電子部品 | Arduino |
---|---|
LEDランプのアノード | 13ピン |
LEDランプのカソード | GND |
次にJava側の実装を行います。
スケッチの抽象クラスを継承して、Lチカを行うクラスを実装します。
Arduino Unoの13ピンはデジタル出力に対応しているので、org.firmata4j.Pin
クラスのsetValue
メソッドに、LEDランプがOnのとき1を、Offのとき0を渡してやると、Lチカが実現できます。
package test1;
import org.firmata4j.Pin;
/**
* Lチカのスケッチ.
*
* @author FlatMountain
*
*/
public class LEDFlash extends AbstractSketch {
private Pin pin;
/**
* 13ピンを出力モードに設定する.
*/
@Override
public void setUp() {
pin = pins.get(13);
try {
pin.setMode(Pin.Mode.OUTPUT);
pin.setValue(0);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 600msごとに13ピンのオン、オフを切り替える.
*/
@Override
public void loop() {
try {
if (frame % 600 == 0) {
long value = pin.getValue() == 1 ? 0 : 1;
pin.setValue(value);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 5秒間スケッチを実行する.
*/
@Override
public boolean isContinuable() {
return frame <= 600 * 5;
}
}
mainメソッドでLチカのスケッチを実行するよう実装すれば、Java側の実装は終わりです。
package test1;
public class Main {
public static void main(String[] args) {
AbstractSketch sketch = new LEDFlash();
sketch.execute();
}
}
あとは、PCとArduinoを接続して作成したMainクラスを実行すれば、ArduinoがLチカしてくれるはずです。
では、試しにEclipse上で実行してみましょう。
Arduino + JavaでLチカしてみた! pic.twitter.com/fVI5zzDmKi
— FM_Kz (@FMKz8) December 9, 2019
期待通りLチカすれば成功です。
Arduino + Javaでスイッチ入力してみた!
Firmata4jを使えば、Arduinoからの入力もJavaで受け取ることができます。
ということで、Arduinoに繋いだスイッチを押したとき、コンソールにメッセージを表示してみます。
まずは、Arduinoにタクトスイッチと330Ωの抵抗を繋ぎます。
今回は以下のように繋ぎました。
※分かりづらくてすみません
電子部品 | Arduino |
---|---|
タクトスイッチ(抵抗とつながっていない方の足) | 5V |
抵抗、タクトスイッチ | 13ピン |
抵抗(スイッチとつながっていない方の足) | GND |
次にJava側の実装を行います。
Lチカと同じように、スイッチ入力でコンソールへのメッセージ表示を行うクラスを実装します。
org.firmata4j.Pin
クラスのgetValue
メソッドは、スイッチが押されていれば1を、押されていなければ0を返します。
そこで、一つ前のループと今のループのgetValueの結果を判定すれば、スイッチが押されたときにメッセージを表示することができます。
package test1;
import org.firmata4j.Pin;
/**
* スイッチ入力のスケッチ.
*
* @author FlatMountain
*
*/
public class Switch extends AbstractSketch {
private Pin pin;
private boolean isPrevFrameSwitchOff;
/**
* 13ピンを入力モードに設定して、スイッチが押されていないことにする.
*/
@Override
public void setUp() {
pin = pins.get(13);
isPrevFrameSwitchOff = false;
try {
pin.setMode(Pin.Mode.INPUT);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* スイッチが押された瞬間、コンソールにメッセージを表示する.
*/
@Override
public void loop() {
try {
if (isPrevFrameSwitchOff && pin.getValue() == 1) {
System.out.println("Hello Aruino!");
}
isPrevFrameSwitchOff = pin.getValue() == 0;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 5秒間スケッチを実行する.
*/
@Override
public boolean isContinuable() {
return frame <= 600 * 5;
}
}
mainメソッドでスイッチ入力のスケッチを実行するよう実装すれば、Java側の実装は終わりです。
package test1;
public class Main {
public static void main(String[] args) {
AbstractSketch sketch = new Switch();
sketch.execute();
}
}
あとは、PCとArduinoを接続して作成したMainクラスを実行すれば、Arduinoがスイッチ入力待ちになるはずです。
入力待ち中にスイッチを押すと、コンソールにメッセージが表示されるはずです。
期待通りコンソールにメッセージが表示されれば成功です。
メッセージが「Hello Aruino!」になっているのはナイショ
おわりに
Firmata 4jを使ってみた感想ですが、自身が慣れ親しんだ言語、開発環境でArduinoを動かすプログラムを作成できたのがとても楽でした。
また、Javaでシリアル通信を実装してArduinoを動かす方法もありますが、自身の知見が足りないこともあり、Firmata 4jを使う方が断然楽に感じました。
Oracle Code One 2019 報告会で聴講したセッションだと、JUnitとArduinoを連動させるような実装もあったので、今度はそれに挑戦してみようと思います。
以上、「JavaでArduinoを動かしてみた!」でした。
明日もラクス Advent Calendar 2019をお楽しみに!
参考資料
-
LEDランプを点滅(チカチカ)させること ↩