2016年12月30日金曜日

ubuntuからESP32にbluetooth接続して信号を送受信する方法


やり方が分かるまでに数日かかったので、方法を共有します。

全体像

この流れで説明します。
  1. 背景
  2. 使ったものの紹介
  3. ESP32のIDF(開発環境)の設定
  4. シリアル通信環境を構築
  5. BLEの操作環境を構築
  6. ESP32にbluetootn serverのプログラムを書き込み
  7. BLEデバイスとしてESP32を認識
  8. ESP32からBluetooth経由で信号を取得
  9. ESP32にBluetooth経由で信号を送信

背景

ESP32とはESP8266(500円位で買えるwifiモジュール)の後継機です。
ESP32はESP8266に比べて、デュアルコアでマルチタスクが可能、WiFiに加えてBluetoothも利用可能などの利点があります。

今回の記事の内容(Bluetooth経由での情報のやりとり)を行うにあたり、ネット上に情報が不足していると感じたので、今回の記事を残します。

使ったものの紹介

これらのものを利用しました。

ハードウェア

  • PC
    ubuntuを入れて使います。
  • ESP32開発ボード
    2016.11月頃にaliexpressで$25位で購入しました。
    2017.04.26時点では$10位で買えるようです。 aliexpress esp32
    秋月電子で売っているesp32開発ボードでも同じことができると思います。
  • USB microBケーブル
    PCとESP32開発ボードの接続に使います。
    手持ちのケーブルを利用しました。

ソフトウェア

  • ubuntu16.04
    linuxのディストリビューションのひとつです。
    この記事では64bit版を利用しています。
  • esp-idf
    esp32開発に必要な開発環境です。
    IDFは「Espressif IoT Development Framework」の略です。
  • bluez
    linuxからbluetoothデバイスのスキャンや接続ができるプログラムです。
    そのプログラムに含まれるhcitoolとgatttoolを今回利用しました。
  • screen
    unix系のPCでシリアル通信をするためのプログラムです。
    ESP32の動作確認に利用しました。

ESP32のIDF(開発環境)の設定

基本的にesp-idfのlinux向けのドキュメントに従ってubuntu16.04にIDFを設定します。

esp-idf/docs/linux-setup

作業フォルダを作成

ドキュメントに沿って「esp」というディレクトリをホームディレクトリに作成します。
このディレクトリの中にESP32に関連するファイルを置いていきます。
mkdir ~/esp

関連プログラムのインストール

IDFの実行に必要な関連プログラムをインストールします。
sudo apt-get install git wget make libncurses-dev flex bison gperf python python-serial

バイナリで公開されているファイルを設置

esp32を作っているメーガーが公開しているコンパイル済みのファイル(binary toolchain)をPCに設置します。
64ビット版のubuntuを使っているので、それ用のファイル使います。
cd ~/esp
wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz
tar -xzf xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz

ファイルを設置できたら、プログラムから呼べるようにパスを通します。
bachrcに下記の記述を追加します。
~/.bashrc
export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin

追加できたらターミナルを再起動するか、bashrcを下記のコマンドで再読み込みします。
source ~/.bashrc

IDFを設置

プログラムをダウンロードします。
cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git

ネットワークの都合などでダウンロードが途中で失敗した場合は、下記のコマンドでダウンロードを再開できます。
cd ~/esp/esp-idf
git submodule update --recursive

プログラムのダウンロードができたら下記の記述をbashrcに追加して、makeコマンド実行時にプログラムを呼べるようにします。
~/.bashrc
export IDF_PATH=~/esp/esp-idf

ESP32の開発環境を構築できました。

シリアル通信環境を構築

下記のコマンドでscreenをインストールします。
sudo apt-get install screen

コマンドでscreenを通してシリアル通信ができるようになりました。

BLEの操作環境を構築

下記のコマンドでbluezをインストールします。
sudo apt-get install bluez

hcitoolとgatttoolを使えるようになりました。

ESP32にbluetootn serverのプログラムを書き込み

bluetooth serverのプログラムIDFのサンプルプログラムに含まれています。

ビルド(コンパイル)

サンプルプログラムのディレクトリに移動して、下記のコマンドでビルドします。
cd ~/esp/esp-idf/examples/bluetooth/gatt_server/
make all

初めてビルドする場合は、下記のように設定画面が出ます。
サンプルプログラムの設定は、プログラムの意図する設定になっているので、左右矢印で「exit」を選択して、エンターを押して終了します。
(ちなみに、この設定画面は「make menuconfig」で表示できます。)


makeが成功すると、下記のようにビルドできたプログラムがずらずらと表示されます。


書き込み

ESP32の開発ボードとPCをUSB microBケーブルで接続します。


開発ボードのBOOTのボタンを押したままEN(リセットボタン)を押して、ESP32を書き込みモードにします。
開発モードで起動できたら、BOOTボタンは離しても大丈夫です。



ビルドしたプログラムのあるディレクトリでmake flashコマンドを実行すると書き込みが始まります。
cd ~/esp/esp-idf/examples/bluetooth/gatt_server/
make flash


1分位で書き込みが終了します。

書込みできたらENボタンを押すかUSBケーブルを挿し直すかして、ESP32を再起動すると、ESP32上でプログラムが動き始めます。

動作確認

ESP32をPCに接続した状態で下記のコマンドを入力すると、ESP32から出力されるログを確認できます。
screen /dev/ttyUSB0 115200

screenで接続した後にenボタンを押すと、gatt_serverの場合下記のようなログが出力されます。


エラーのような赤字が出力されますが、bluetoothの機能は動いているようです。

Bluetoothのアドレスもログに表示されます。


アドレスはモジュールによって異なりますが、今回使っているESP32のアドレスは「24:0A:C4:04:2C:AA」だと分かりました。

BLEデバイスとしてESP32を認識

下記のコマンドでhcitoolを使うとBLEデバイスをスキャンできます。
sudo hcitool lescan


「ESP_GATTS_DEMO」というデバイスがESP32です。
BLEデバイスとして動いていることを確認できました。

ESP32のBLEプロファイルを確認

下記のようにgatttoolを使うとBLEのGATTプロファイルなどを確認できます。
hcitoolで今回使っているESP32のアドレス、下記のコマンドでGATTに関するやりとりを開始できます。
gatttool -b 24:0A:C4:04:2C:AA -I

gatttoolを開けたら、情報を取得するために、接続します。
connect


helpで使い方を見れます。


> help
help                                           Show this help
exit                                           Exit interactive mode
quit                                           Exit interactive mode
connect         [address [address type]]       Connect to a remote device
disconnect                                     Disconnect from a remote device
primary         [UUID]                         Primary Service Discovery
included        [start hnd [end hnd]]          Find Included Services
characteristics [start hnd [end hnd [UUID]]]   Characteristics Discovery
char-desc       [start hnd] [end hnd]          Characteristics Descriptor Discovery
char-read-hnd   <handle>                       Characteristics Value/Descriptor Read by handle
char-read-uuid  <UUID> [start hnd] [end hnd]   Characteristics Value/Descriptor Read by UUID
char-write-req  <handle> <new value>           Characteristic Value Write (Write Request)
char-write-cmd  <handle> <new value>           Characteristic Value Write (No response)
sec-level       [low | medium | high]          Set security level. Default: low
mtu             <value>                        Exchange MTU for GATT/ATT

GATTの内容についてまだ理解できていないので、取得できた情報を記述します。

primary
[24:0A:C4:04:2C:AA][LE]> primary
attr handle: 0x0001, end grp handle: 0x0005 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0014, end grp handle: 0x001c uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0028, end grp handle: 0x002b uuid: 000000ff-0000-1000-8000-00805f9b34fb
attr handle: 0x002c, end grp handle: 0xffff uuid: 000000ee-0000-1000-8000-00805f9b34fb

characteristics
[24:0A:C4:04:2C:AA][LE]> characteristics 
handle: 0x0002, char properties: 0x20, char value handle: 0x0003, uuid: 00002a05-0000-1000-8000-00805f9b34fb
handle: 0x0015, char properties: 0x02, char value handle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0017, char properties: 0x02, char value handle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0019, char properties: 0x02, char value handle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb
handle: 0x0029, char properties: 0x1a, char value handle: 0x002a, uuid: 0000ff01-0000-1000-8000-00805f9b34fb
handle: 0x002d, char properties: 0x1a, char value handle: 0x002e, uuid: 0000ee01-0000-1000-8000-00805f9b34fb

char-desc
[24:0A:C4:04:2C:AA][LE]> char-desc 
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0002, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0003, uuid: 00002a05-0000-1000-8000-00805f9b34fb
handle: 0x0014, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0015, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0017, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0019, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb
handle: 0x0028, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0029, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x002a, uuid: 0000ff01-0000-1000-8000-00805f9b34fb
handle: 0x002b, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x002c, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x002d, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x002e, uuid: 0000ee01-0000-1000-8000-00805f9b34fb
handle: 0x002f, uuid: 00002902-0000-1000-8000-00805f9b34fb

characteristicsで確認できたuuidのchar-read-uuid
[24:0A:C4:04:2C:AA][LE]> char-read-uuid 00002a05-0000-1000-8000-00805f9b34fb
Error: Read characteristics by UUID failed: Attribute can't be read
[24:0A:C4:04:2C:AA][LE]> char-read-uuid 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0016   value: 45 53 50 5f 47 41 54 54 53 5f 44 45 4d 4f
[24:0A:C4:04:2C:AA][LE]> char-read-uuid 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0018   value: 00 00
[24:0A:C4:04:2C:AA][LE]> char-read-uuid 00002aa6-0000-1000-8000-00805f9b34fb
handle: 0x001a   value: 00
[24:0A:C4:04:2C:AA][LE]> char-read-uuid 0000ff01-0000-1000-8000-00805f9b34fb
handle: 0x002a   value: de ed be ef
[24:0A:C4:04:2C:AA][LE]> char-read-uuid 0000ee01-0000-1000-8000-00805f9b34fb
handle: 0x002e   value: de ed be ef

characteristicsで確認できたhandleのchar-read-hnd
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x0002
Characteristic value/descriptor: 20 03 00 05 2a
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x0015
Characteristic value/descriptor: 02 16 00 00 2a
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x0017
Characteristic value/descriptor: 02 18 00 01 2a
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x0019
Characteristic value/descriptor: 02 1a 00 a6 2a
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x0029
Characteristic value/descriptor: 1a 2a 00 01 ff
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x002d
Characteristic value/descriptor: 1a 2e 00 01 ee

characteristicsで確認できたvalue handleのchar-read-hnd
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x0003
Error: Characteristic value/descriptor read failed: Attribute can't be read
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x0016
Characteristic value/descriptor: 45 53 50 5f 47 41 54 54 53 5f 44 45 4d 4f
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x0018
Characteristic value/descriptor: 00 00
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x001a
Characteristic value/descriptor: 00
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x002a
Characteristic value/descriptor: de ed be ef
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x002d
Characteristic value/descriptor: 1a 2e 00 01 ee

ESP32からbluetooth経由で信号を取得

下記の情報読み取りコマンドに関して、対応するESP32のプログラムを見つけられました。
[24:0A:C4:04:2C:AA][LE]> char-read-uuid 0000ff01-0000-1000-8000-00805f9b34fb
handle: 0x002a   value: de ed be ef
または
[24:0A:C4:04:2C:AA][LE]> char-read-hnd 0x002a
Characteristic value/descriptor: de ed be ef

上記コマンド実行時は、screenで表示しているESP32のログに下記の情報が出力されます。
I (1370541) GATTS_DEMO: GATT_READ_EVT, conn_id 0, trans_id 26, handle 42

これは「~/esp/esp-idf/examples/bluetooth/gatt_server/main/gatts_demo.c」のESP_GADDS_READ_EVTに関するcaseで処理されているようです。


ESPの内部状態を配信したい場合、この周辺のプログラムが参考になるかもしれません。

ESP32にbluetooth経由で信号を送信

下記の情報送信コマンドに関しては、対応するESP32のプログラムを見つけられました。
ちなみに、下記のコマンドは「3939」を送信しています。
[24:0A:C4:04:2C:AA][LE]> char-write-req 0x002a 3939
Characteristic value was written successfully

上記コマンド実行時は、screenで表示しているESP32のログに下記の情報が出力されます。
I (1740351) GATTS_DEMO: GATT_WRITE_EVT, conn_id 0, trans_id 2, handle 42

I (1740351) GATTS_DEMO: GATT_WRITE_EVT, value len 2, value 00003939

これはreadと同じ「~/esp/esp-idf/examples/bluetooth/gatt_server/main/gatts_demo.c」のESP_GADDS_WRITE_EVTに関するcaseで処理されているようです。


受け取った情報を元にESPの振る舞いを変えるようなプログラムを書く場合、この周辺のプログラムの記述方法が参考になるかもしれません。

方法の共有は以上です。
間違いがありましたら、コメントなどで指摘していただけると嬉しいです。

参考

Flashing ESP32 with Template App
ESP32でのプログラムの書き込みを解説している動画です。
ツールの動きがわからない時に参考になりました。

HOW TO GET STARTED WITH THE ESP32
上記の動画を紹介している記事です。

BT LE FindMe profile in Bluez
hcitool利用の参考にしました。

Bluetooth Low Energy: listening for notifications/indications in linux
gatttool利用時の参考にしました。

更新履歴

2017/03/09
乾電池でも動くことを利点として紹介していましたが、ESP8266でもできそうなので、その説明を削除しました。

2017/03/17
binary toolchainのパスを現時点の最新版(xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz)に変更しました。
screenのインストールコマンドを追加しました。
gatt_serverファイルのパスを修正しました。

2017/04/24
gatt_serverのパスが古いままになっていた部分を修正しました。

2017/04/25
ESP32の解説がESP8266と混じって分かりにくく感じたので、単語の順序を変更しました。
bluetoothのアドレスに関する最初の具体的な記述を「BLEプロファイル」の部分から「動作確認」の部分に変更しました。

2017/04/26
ESP32の開発ボードの購入先がリンク切れになっていたので修正しました。
また、開発ボードの購入先として秋月電子のリンクを追加しました。

2017/06/18
primaryに関する情報が重複していたので、余計な部分を削除しました。

0 件のコメント :

コメントを投稿