マサルの備忘録

ハイオク仕様のトルクフルな備忘録

ArduinoとAndroidをBluetoothでデータの送受信をする話

スポンサーリンク

AndroidBluetooth
Arduinoと出会ったぁ〜。

f:id:domomasarudesu:20160208223846j:plain

この前買ったArduinoLeonardo互換機を使います

masaru.hateblo.jp

これです。
Leonardo互換といえども、
ピン配列はUnoに似てるので、
Bluetoothは以前作った
HC-06のシールドを使いまわします。

masaru.hateblo.jp

f:id:domomasarudesu:20160208224406j:plain

とりあえずシールドを刺してみました。
意外とイケる。

とりあえずコード書きますか

基本的な構成としては、
AndroidからBTで整数値をArduinoに送り、
Arduinoは受け取った数値をそのまま
Androidに返すだけのアプリ。

LeonardoはUSBのSerialの他に、
別途ソフトSerialが使えるので、
PCとArduinoを接続して
PCのシリアルモニタにLogを出力しつつ、
Bluetoothの方にもSerialで
入出力ができるようになってます。
素晴らしい。

まずはAndroid

はじめに、お決まりのPermission。

<uses-permission android:name="android.permission.BLUETOOTH"/>

つぎにJava
Activityに書くと長くなるので、
別クラスで書いてます。

public class BluetoothCommunicator {
    private static final UUID sUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    private boolean mIsRunning;

    private Activity mActivity;

    private BluetoothCommunicatorListener mListener;

    private BluetoothDevice mBluetoothDevice;

    private BluetoothSocket mBluetoothSocket;

    private InputStream mInputStream;

    private OutputStream mOutputStream;

    public BluetoothCommunicator(Activity activity, BluetoothCommunicatorListener listener) {
        mIsRunning = true;
        mActivity = activity;
        mListener = listener;

        findDevice();
        connectDevice();
    }

    public void writeMessage(final String str) {
        if (mOutputStream == null | TextUtils.isEmpty(str)) {
            return;
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mOutputStream.write(str.getBytes());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public void destory() {
        mIsRunning = false;
        mActivity = null;

        disconnectDevice();
    }

    private void findDevice() {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

        if (adapter == null) {
            return;
        }

        for (BluetoothDevice device : adapter.getBondedDevices()) {
            if ("HC-06".equals(device.getName())) {
                mBluetoothDevice = device;
                return;
            }
        }
    }

    private void connectDevice() {
        if (mBluetoothDevice == null) {
            return;
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    BluetoothSocket socket = mBluetoothDevice
                            .createRfcommSocketToServiceRecord(sUUID);
                    socket.connect();

                    mBluetoothSocket = socket;
                    mInputStream = socket.getInputStream();
                    mOutputStream = socket.getOutputStream();

                    byte[] buffer = new byte[1024];
                    int bytesRead;

                    while (mIsRunning) {
                        bytesRead = mInputStream.read(buffer);
                        final String message = new String(buffer, 0, bytesRead);

                        if (TextUtils.isEmpty(message.trim())) {
                            continue;
                        }

                        mActivity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                mListener.onReceive(message.trim());
                            }
                        });
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void disconnectDevice() {
        mListener = null;

        if (mBluetoothDevice == null) {
            return;
        }

        try {
            if (mBluetoothSocket != null) {
                mBluetoothSocket.close();
                mBluetoothSocket = null;
            }

            if (mInputStream != null) {
                mInputStream.close();
                mInputStream = null;
            }

            if (mOutputStream != null) {
                mOutputStream.close();
                mOutputStream = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

予めペアリング済みを想定。
Arduino側と似てるんですが、
Read側は、InputStreamを
Whileループでずっと監視。
ただし、バッファサイズは1024バイトしか
取ってなくて、それ以上のデータが来ることは
想定していません(笑)

そもそも1文字以上を連続して
やり取りするときは、
送受信でデータの終了文字とかを
決めておいたほうがイイかもしれません。

リスナーはこんな感じで、
単純なものです。これをActivity上で
実装して、よしなに表示してあげます。

public interface BluetoothCommunicatorListener {

    void onReceive(String str);
}

クラス名のネーミングセンスは
不問とさせて下さい。

つぎにArduino

こっちはスッゴイシンプル。

void setup() {
  // USB Serial
  Serial.begin(9600);

  // Bluetooth Serial
  Serial1.begin(9600);
}

void loop() {
  while (Serial1.available() > 0) {
    int input = Serial1.read();
    Serial1.write(input);
    Serial.println(input);
  }
}

たったこれだけ。
SerialはUSBとの通信。
Serial1はBTとの通信。
Arduino側は本当に簡単。
でも、こちらも複数文字のInputには
対応できてないので、
終端文字などを決めて実装する必要がある。

うごかしまーす

f:id:domomasarudesu:20160208231554p:plain

EditTextに文字入力させて、
そこに入力された文字を
BluetoothCommunicator#writeMessage()します。
ArduinoからAndroidへのInputは
先ほどのリスナーでうけとります。

説明が面倒なので、
このくらいにしますが、
いい感じでワークしてます。
今後は複数文字列に対応した
ペイロードをガッチガチに設計して、
いい感じの送受信を目指しますかね。