[leJOS][NXT] Bluetooth を使った送受信 ================================================================================ ※ このサンプルは leJOS 0.9.1 で作成している。 Bluetooth を使って、データを送受信する。 プログラムは以下の 3 つを作った。 Sender11 リモートデバイス側。NXT のセンサーから値を読んで、Bluetooth を使っ て相手(Receiver11)に送信する Receiver11 ローカルデバイス側。Sender11 から送られてきたデータを受信して、画 面に表示する。 SensorValues エンティティ。送受信時に使う NXT のセンサーの値を保持する。 Bluetooth では、データを送受信するときに、リモートデバイス側とローカルデバイス側 とで通信をする。このとき、リモートデバイス側のプログラム(Sender11)を先に起動して おく。 ■ リモートデバイス側 NXT の Esacape ボタン以外を押下したときに、各センサーの値を読み取って、相手の NXT に送信する。Esacape ボタンを押下したときは、プログラムを終了する。 □ Sender11.java --- import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import lejos.nxt.Button; import lejos.nxt.LCD; import lejos.nxt.LightSensor; import lejos.nxt.Motor; import lejos.nxt.SensorPort; import lejos.nxt.SoundSensor; import lejos.nxt.TouchSensor; import lejos.nxt.UltrasonicSensor; import lejos.nxt.comm.Bluetooth; import lejos.nxt.comm.NXTConnection; /** * NXTのセンサーからデータを取得し、Bluetoothを使って値を送信する。 * リモートデバイス側(先にこちらのプログラムを起動しておく) * leJOS 0.9.1 * @author marunomaruno * @version 1.0, 2012/03/14 * @since 1.0 */ public class Sender11 { public static void main(String[] args) throws Exception { // センサーを設定する TouchSensor touchSensor = new TouchSensor(SensorPort.S1); SoundSensor soundSensor = new SoundSensor(SensorPort.S2); LightSensor lightSensor = new LightSensor(SensorPort.S3); UltrasonicSensor ultrasonicSensor = new UltrasonicSensor(SensorPort.S4); // センサーが安定するまで待つ Thread.sleep(200); // ローカルデバイスとの通信を待つ LCD.drawString("Waiting...", 0, 0); NXTConnection connection = Bluetooth.waitForConnection(); // (1) // 接続できない場合、プログラムを終了する if (connection == null) { // (2) LCD.clear(); LCD.drawString("Connect fail", 0, 0); Button.waitForAnyPress(); System.exit(1); } // ローカルにもログをとっておく File file = new File("values.dat"); file.delete(); file.createNewFile(); DataOutputStream log = new DataOutputStream(new FileOutputStream( file)); // Bluetooth 用のデータストリームを取得する DataOutputStream out = connection.openDataOutputStream(); // (3) // センサー値を保持するオブジェクトを確保する SensorValues values = new SensorValues(); // (4) // ESCが押されたら終わり while (Button.waitForAnyPress() != Button.ID_ESCAPE) { try { // IDをカウントアップする values.id++; // センサーから値を取得する values.buttonId = Button.readButtons(); values.touch = touchSensor.isPressed() ? 1 : 0; values.sound = soundSensor.readValue(); values.light = lightSensor.readValue(); values.ultrasonic = ultrasonicSensor.getDistance(); values.tachoCountA = Motor.A.getTachoCount(); values.tachoCountB = Motor.B.getTachoCount(); values.tachoCountC = Motor.C.getTachoCount(); // データを画面に表示する LCD.clear(); values.print(System.out); // ログファイルに出力する values.write(log); // Bluetoothに出力する values.write(out); // (5) } catch (IOException e) { System.out.println(" write error " + e); } } // ログファイルを閉じる try { log.close(); } catch (IOException e) { LCD.drawString("Close Exception", 0, 0); LCD.drawString(e.getMessage(), 0, 1); Button.waitForAnyPress(); } // 通信を閉じる try { LCD.clear(); LCD.drawString("Closing... ", 0, 0); out.close(); // (6) connection.close(); // (7) } catch (IOException e) { LCD.drawString("Close Exception", 0, 0); LCD.drawString(e.getMessage(), 0, 1); Button.waitForAnyPress(); } // 終了メッセージを表示する LCD.clear(); LCD.drawString("Finished", 0, 0); Button.waitForAnyPress(); } } ---- (1) ローカルデバイスとの通信を待つ Bluetooth クラス の waitForConnection() メソッドを使って、ローカルデバイスとの通 信を待つ。通信があれば、待ち状態は解除され、BTConnection オブジェクトが返る。 なお、NXTConnection は、BTConnection のスーパークラス。 NXTConnection connection = Bluetooth.waitForConnection(); // (1) --- static BTConnection waitForConnection() 現在のデフォルトの PIN を使って取得する。 --- PIN は、ペアリングするときに使用する 4 桁の数字。デフォルトだと、「0000」または 「1234」。 □ Bluetooth クラス java.lang.Object lejos.nxt.comm.NXTCommDevice lejos.nxt.comm.Bluetooth Bluetooth 通信をあらわすクラス。 メソッド --- static BTConnection connect(RemoteDevice remoteDevice) static BTConnection connect(String target, int mode) static BTConnection connect(String target, int mode, byte[] pin) static RemoteDevice getKnownDevice(String fName) static ArrayList<RemoteDevice> getKnownDevicesList() static BTConnection waitForConnection() static BTConnection waitForConnection(int timeout, int mode) static BTConnection waitForConnection(int timeout, int mode, byte[] pin) --- □ BTConnection クラス java.lang.Object extended by lejos.nxt.comm.NXTConnection extended by lejos.nxt.comm.BTConnection Bluetooth の接続をあらわすクラス。つぎに示す NXTConnection クラスを継承している。 メソッド --- void closeStream() int getSignalStrength() void openStream() void setActiveMode(int mode) --- □ NXTConnection クラス java.lang.Object lejos.nxt.comm.NXTConnection 一般的な NXT leJOS の接続を表すクラス。 メソッド --- void close() DataInputStream openDataInputStream() DataOutputStream openDataOutputStream() InputStream openInputStream() OutputStream openOutputStream() --- (2) 接続できない場合、プログラムを終了する Bluetooth.waitForConnection() メソッドで、接続ができない場合は、null が返るので、 これをチェックする。 if (connection == null) { // (2) (3) Bluetooth 用のデータストリームを取得する このプログラムは、センサーから読み取ったデータを相手に送信する側なので、出力スト リームを開く。 DataOutputStream out = connection.openDataOutputStream(); // (3) (4) センサー値を保持するオブジェクトを確保する NXT のセンサーからの値は、SensorValues オブジェクトとして生成する。 SensorValues values = new SensorValues(); // (4) (5) Bluetooth に出力する SensorValues オブジェクトの write() メソッドに、Bluetooth の出力ストリーム・オブ ジェクトを渡して書き込む。 values.write(out); // (5) (6)(7) 通信を閉じる 通信が終わったら、出力ストリーム、接続ともに閉じる。 out.close(); // (6) connection.close(); // (7) ■ ローカルデバイス側 Bluetooth を使って送られてきたデータを受信して、その値を表示するプログラム。 リモートデバイス側の名前を指定して、相手を特定する。 □ Receiver11.java --- import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.bluetooth.RemoteDevice; import lejos.nxt.Button; import lejos.nxt.LCD; import lejos.nxt.comm.Bluetooth; import lejos.nxt.comm.NXTConnection; /** * Bluetoothを使って送られてきたデータを受信して、その値を表示する。 * ローカルデバイス側(先に、リモートデバイス側を起動しておく) * leJOS 0.9.1 * @author marunomaruno * @version 1.0, 2011/08/14 * @since 1.0 */ public class Receiver11 { public static void main(String[] args) throws Exception { // リモートデバイスと接続する LCD.drawString("Connecting...", 0, 0); // リモートデバイスのNXT名を設定する RemoteDevice device = Bluetooth.getKnownDevice("NXT名"); // (1) // リモートデバイスが見つからない場合、プログラムを終了する if (device == null) { LCD.clear(); LCD.drawString("No such device", 0, 0); Button.waitForAnyPress(); System.exit(1); } // 接続する NXTConnection connection = Bluetooth.connect(device); // (2) // 接続できない場合、プログラムを終了する if (connection == null) { LCD.clear(); LCD.drawString("Connect fail", 0, 0); Button.waitForAnyPress(); System.exit(1); } // データストリームを開く DataInputStream in = connection.openDataInputStream(); // (3) // ローカルにもログをとっておく File file = new File("values.dat"); file.delete(); file.createNewFile(); DataOutputStream log = new DataOutputStream(new FileOutputStream(file)); SensorValues values = new SensorValues(); // メッセージを受け取る try { while (Button.ESCAPE.isDown() != true) { // ストリームから値を読み込む values.read(in); // (4) // ログファイルに出力する values.write(log); // データを画面に表示する LCD.clear(); values.print(System.out); // 待つ Thread.sleep(200); } } catch (IOException e) { System.out.println(" write error " + e); } // ログファイルを閉じる try { log.close(); } catch (IOException e) { LCD.drawString("Close Exception", 0, 0); LCD.drawString(e.getMessage(), 0, 1); Button.waitForAnyPress(); } // 通信を閉じる try { LCD.clear(); LCD.drawString("Closing...", 0, 0); in.close(); connection.close(); } catch (IOException e) { LCD.drawString("Close Exception", 0, 0); LCD.drawString(e.getMessage(), 0, 1); Button.waitForAnyPress(); } LCD.clear(); LCD.drawString("Finished", 0, 0); Button.waitForAnyPress(); } } --- (1) リモートデバイスのNXT名を設定する Bluetooth クラスの getKnownDevice() メソッドを使って、相手のデバイス名を指定して、 接続先のデバイスを取得する。 RemoteDevice device = Bluetooth.getKnownDevice("NXT名"); // (1) リモートデバイスが見つからない場合は、null が返る。 Bluetooth クラスのメソッド --- static RemoteDevice getKnownDevice(String fName) static ArrayList<RemoteDevice> getKnownDevicesList() --- □ RemoteDevice クラス java.lang.Object javax.bluetooth.RemoteDevice リモートデバイスをあらわすクラス。 主なメソッド --- String getBluetoothAddress() String getDeviceAddr() int getDeviceClass() String getFriendlyName(boolean alwaysAsk) static RemoteDevice getRemoteDevice(Connection conn) boolean isAuthenticated() boolean isEncrypted() void setDeviceAddr(String deviceAddr) void setFriendlyName(String fName) --- (2) 接続する NXTConnection connection = Bluetooth.connect(device); // (2) 接続できない場合は、null が返る。 Bluetooth クラスのメソッド --- static BTConnection connect(RemoteDevice remoteDevice) static BTConnection connect(String target, int mode) static BTConnection connect(String target, int mode, byte[] pin) --- (3) データストリームを開く このプログラムは、Bluetooth から受信した値を画面に表示するので、入力ストリームを 開く。 DataInputStream in = connection.openDataInputStream(); // (3) (4) ストリームから値を読み込む SensorValues オブジェクトの read() メソッドに、Bluetooth の入力ストリーム・オブ ジェクトを渡して書き込む。 values.read(in); // (4) ■ エンティティ NXT のセンサーの値を管理するエンティティ・クラス。 入力ストリームや出力ストリームのオブジェクトを受け取ることで、そのストリームに対 する入出力も行う。 なお、データの値は int 値として送受信している。 管理している値はつぎのとおり。 ------------- ------------------------ フィールド名 意味 ------------- ------------------------ id ID buttonId ボタンのID touch タッチセンサーの値 sound 音センサーの値 light 光センサーの値 ultrasonic 超音波センサーの値 tachoCountA モーターAのタコカウント tachoCountB モーターBのタコカウント tachoCountC モーターCのタコカウント ------------- ------------------------ □ SensorValues.java --- import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.PrintStream; /** * NXTのセンサーの値を保持するエンティティ * leJOS 0.9.1, Android 2.2 * @author marunomaruno * @version 1.0, 2012/03/14 * @since 1.0 */ public class SensorValues { int id; // ID int buttonId; // ボタンのID int touch; // タッチセンサーの値 int sound; // 音センサーの値 int light; // 光センサーの値 int ultrasonic; // 超音波センサーの値 int tachoCountA; // モーターAのタコカウント int tachoCountB; // モーターBのタコカウント int tachoCountC; // モーターCのタコカウント /** * 値を表示する。 * @param out 表示するストリーム */ public void print(PrintStream out) { out.println(id); out.println(toSensorString()); out.println(toMotorString()); } /** * データを入力する。 * @param in 入力ストリーム * @throws IOException */ public void read(DataInputStream in) throws IOException { id = in.readInt(); buttonId = in.readInt(); touch = in.readInt(); sound = in.readInt(); light = in.readInt(); ultrasonic = in.readInt(); tachoCountA = in.readInt(); tachoCountB = in.readInt(); tachoCountC = in.readInt(); } /** * データを出力する。 * @param out 出力ストリーム * @throws IOException */ public void write(DataOutputStream out) throws IOException { out.writeInt(id); out.writeInt(buttonId); out.writeInt(touch); out.writeInt(sound); out.writeInt(light); out.writeInt(ultrasonic); out.writeInt(tachoCountA); out.writeInt(tachoCountB); out.writeInt(tachoCountC); out.flush(); } /** * すべてのセンサーの値からなる文字列を組み立てる。 * @return 組み立てた文字列 */ public String toSensorString() { StringBuilder sb = new StringBuilder(); sb.append("["); sb.append(buttonId); sb.append(", "); sb.append(touch); sb.append(", "); sb.append(sound); sb.append(", "); sb.append(light); sb.append(", "); sb.append(ultrasonic); sb.append("]"); return sb.toString(); } /** * すべてのモーターの値からなる文字列を組み立てる。 * @return 組み立てた文字列 */ public String toMotorString() { StringBuilder sb = new StringBuilder(); sb.append("["); sb.append(toMotorString(new int[]{tachoCountA})); sb.append(", "); sb.append(toMotorString(new int[]{tachoCountB})); sb.append(", "); sb.append(toMotorString(new int[]{tachoCountC})); sb.append("]"); return sb.toString(); } /** * 指定されたモーター値の配列からなる文字列を組み立てる。 * @param values 値の配列 * @return 組み立てた文字列 */ public String toMotorString(int[] values) { if (values.length == 0) { return "[]"; } StringBuilder sb = new StringBuilder(); sb.append("["); sb.append(values[0]); for (int i = 1; i < values.length; i++) { sb.append(", "); sb.append(values[i]); } sb.append("]"); return sb.toString(); } /* * (非 Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(id); sb.append("["); sb.append(toSensorString()); sb.append(", "); sb.append(toMotorString()); sb.append("]"); return sb.toString(); } } --- 以上