工作と競馬

電子工作、プログラミング、木工といった工作の記録記事、競馬に関する考察記事を掲載するブログ

カテゴリ:11.電子工作(IoT) > 11.3 ESP-WROOM-xx

概要

KiCadとFusion PCBで基板を作ってみた。


背景と目的

KiCadとFusion PCBで基板を作りたくなったので、やってみる。


詳細

0.方針

KiCadの使い方は、Web上にたくさんあるし、本も出ているのでそれを参考にするとして、とりあえず作ってちゃんとうごいたという記録をする。なお、手元にこちらの本があるので参考になった。


1.KiCadで設計

今回作成するのは、ESP-WROOM-32を使った簡単なダッシュボタンとする。

  • ESP-WROOM-32
  • 単3乾電池2本で駆動
  • ボタンは3つ

いきなりだが、作成した回路は以下。ESP-WROOM-32の部品データは、Web上に転がっていると思ったが、意外と見つけるのに苦労したので結局自分で作った。

少し説明しておくと、

  • J2、J4はジャンパ接続部だが、接続した状態でボタンを操作することで、EN、IO0のレベルが変化し、プログラム書き込みモードに入ることができるようになっている。
  • ボタンを押したときにL→Hとなるようにし、スリープ解除トリガになるようにしている。

という感じ。

sch

基板レイアウトは以下。基板設計の知識はないので、見様見真似だが、一般的注意は守ったつもり。

手はんだを想定しているがESP-WROOM-32モジュールの高さ以下で押さえたいので、トランジスタ、コンデンサなどの部品は表面実装型を選択。なので、トランジスタは(SC-59,JEITA)というパッケージのものが見当たらなかったので作成。抵抗はリード部品でも問題ない。タクトスイッチのボタン部分は背が高くてもいいので、手に入りやすいこちらを使用。

pcb


2.Fusion PCBに発注

Fusion PCBは、どうやらスイッチサイエンスPCBの委託先のようだが、かなり安い。今回作る基板は、10cm×5cmに収まり、10枚で十分なので、ただ、表面処理を一応鉛フリー半田レベラーを選択したので、$12.9となった。そして、悲しいことに配送料のほうが高く、$19.15を取られ、全部で$32.05ドル。

2018/7/30に発注したところ、31日には in Productionとメールが届いた。8/3には、出来上がって発送した旨のメールが届いた。というわけで、実質2,3日で発送される様子。ただ、海外から船便?で配送という感じなので、そこから1週間後の8/10に到着。まあ、2週間程度なのでよしとする。


3.出来上がった基板と動作確認

出来上がったものは、以下。当然ながら、目視の限りおかしなところはない。

DSC_0488

さっそく、部品実装してみたのが、以下。1.27mmピッチのESP-WROOM-32を手半田するのはうまくいくか不安だったが、大して難しくなかった。

DSC_0489

そして、Arduinoで、プログラムを書き込んで動作を確認したところ、所望の動作をした!というわけで、自作のIoTダッシュボタンが完成。家中に置いて使える。(ただし、Web側のシステム構築を何もしていない。IFTTTやMicrosoft Flowあたりを使うと簡単にできるかな。)


4.ケースに入れる

タカチのTW5-3-9を使うのを想定して基板を作成しているので、ケースに入れてみた。まずまずよい感じに収まっているのではないだろうか。ボタンが小さいのが少し気になるが、まあいいだろう。

DSC_0490


まとめ

KiCadとFusion PCBで基板を作り、ちゃんと出来上がった。今後も、Fusion PCBを使って基板づくりをしたい。

概要

ESP-WROOM-32からデータをAmbientに送信して可視化することができた。


背景と目的

先日、ESP-WROOM-32にDHT22を接続して温度、湿度を計測することができた。そこで、計測データをWeb上に送信して可視化してみたい。


詳細

1.可視化手段=Ambient

可視化するには、有料、無料含めて様々なものがあるが、今回は無料で使えるAmbientというサービスを使ってみる。私は初めて使うのだが、Web上に情報がさまざまあるため、始めやすそうだ。


2.Ambientのユーザー登録

こちらから、メールアドレスとパスワードだけで登録ができた。ログインすると、コンソール画面になるので、Myチャネルから、チャネルの作成をしておく。そうすると、チャネルID、リードキー、ライトキーなどがもらえる。


3.ESP-WROOM-32のコーディング

3.1 ライブラリの準備

[[サンプル>]]などを参考に、進めてみた。まず、Ambient接続用のArudinoライブラリがあるので、こちらダウンロード。表示がESP8266とあるが、気にしない。Arduinoのライブラリフォルダに置く。


3.2 コーディング

こちらなどを参考に、書いてみた。1分間隔で、DHT22の計測値を送信している。また、注意が必要なのは、WiFiClientSecureは使えない。(Ambientのエンドポイントが、HTTPだからか?)

#include 
#include "Ambient.h"
#include "DHTesp.h"

unsigned int channelId = 数字;
const char* writeKey = "Ambientのコンソールで確認";
const int GPIO_DHT22 = 33;

WiFiClient client; // WiFiClientSecureではだめ
Ambient ambient; // Ambient
DHTesp dht; // DHT22

void setup() {
  
  Serial.begin(115200);
  
  Serial.println("Attempting to connect to SSID: " + String(YOUR_SSID));
  WiFi.begin(YOUR_SSID, PASSWORD); // Wi-Fiモジュールの初期化
  while (WiFi.status() != WL_CONNECTED) {
      Serial.print(".");
      delay(1000); // 1秒ずつ待つ
  }
  Serial.println("Connected to " + String(YOUR_SSID)); // 接続成功通知
  
  // Ambientの初期化
  bool tf = ambient.begin(channelId, writeKey, &client);
  if (!tf) {
    Serial.println("ambient.begin failed.");
  }

  // DHT22初期化
  dht.setup(GPIO_DHT22, DHTesp::DHT22);

}

void loop() {

  // 計測
  TempAndHumidity newValues = dht.getTempAndHumidity();

  // 結果表示
  Serial.println(" T:" + String(newValues.temperature) + " H:" + String(newValues.humidity));

  // データのセット
  ambient.set(1, newValues.temperature); // 温度
  ambient.set(2, newValues.humidity); // 湿度
  
  // 送信
  Serial.println("send...");
  bool tf = ambient.send();
  if (!tf) {
    Serial.println("ambient.send failed.");
  }
  delay(60 * 1000);

}


4.動作確認

コンソールで、送信先チャネルを選び、グラフを作成。今回は、湿度と温度それぞれを時系列で表示してみた。グラフの設定も、送信したデータが表示されている。※なお、途中から大きく数字が変わっているが、前半はダミーのいい加減な数値を送信したためで、後半は本物のセンサ計測値。

(どうでもいいけど、コンソールのデザインのBootstrap感がすごい。まあ、嫌いじゃないけど。)

20180712221733


まとめ

ESP-WROOM-32からデータをAmbientに送信して可視化することができた。非常に簡単なので、ぜひ今後も利用していきたい。

概要

ESP-WROOM-32で、スリープからスイッチを押して復帰するプログラムを作成し、正しく動作することを確認した。


背景と目的

ESP-WROOM-32で、複数のスイッチのうちいずれかを押したらスリープから復帰させ、なおかつどれが押されたか認識したい。なので、サンプルプログラム等を参考に、プログラムを組み動作確認してみる。


詳細

0.試す条件

  • ESP-WROOM-32 DevKit-C
  • スイッチをGPIO32,34,35に接続(押したらHIGH)


1.コーディング

今回やりたいことは、

  • 3つのスイッチのいずれかを押したら、sleepから復帰し、押されたスイッチを認識する

である。ドキュメントを読む限り、External wakeup (ext1)でできそうだ。そして、サンプルプログラムがあるので、基本骨格は、ExternalWakeUp.inoとして、いくつか変更を加える。

なお、

  • ESP_EXT1_WAKEUP_ALL_LOW = 監視対象のGPIOすべてがLOW
  • ESP_EXT1_WAKEUP_ANY_HIGH = 監視対象のGPIOいずれかがHIGH

といういずれかの動作モードしか選べないので、スイッチを押すとLOWになる複数の入力のいずれかを検出というのは難しい。(手元にそういう構成で作ってしまったハードがあって使えないことが分かりがっかり。。。)

まず、スイッチを接続するGPIOピンが3つあるので、

#define BUTTON_PIN_BITMASK 0xD00000000 // 2^32, 2^34 2^35なので、0b1101 0000 ...

とする。そして、wakeupのトリガになったピンが分かるように、esp_sleep_get_ext1_wakeup_statusなる関数を用いて、シリアルにピン番号を表示する関数を作成し、setup関数内で、print_wakeup_reasonの後に呼び出す。

void print_wakeup_pin(){

  uint64_t wakeup_pin = esp_sleep_get_ext1_wakeup_status();

  if (wakeup_pin & 0x100000000) {
    Serial.println(32);
  }
  if (wakeup_pin & 0x400000000) {
    Serial.println(34);
  }
  if (wakeup_pin & 0x800000000) {
    Serial.println(35);
  }
  
}

そして、ext0を無効、ext1を有効にするため、setup関数内で、

//esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1);
//If you were to use ext1, you would use it like
esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK, ESP_EXT1_WAKEUP_ANY_HIGH);

とする。なお、悲しいことにサンプルプログラムは、古いAPIを修正し忘れたのか、esp_deep_sleep_enable_ext1_wakeupという間違った関数名になっていてそのままではエラーになるので、esp_sleep_enable_ext1_wakeupに修正すること。


2.動作確認

上記変更をしたプログラムを書き込み立ち上げると、

Boot number: 1
Wakeup was not caused by deep sleep
Going to sleep now

となり、wakeupではない旨とsleepに移行した旨が表示される。そして、GPIO32に接続したスイッチを押したところ、

Boot number: 2
Wakeup caused by external signal using RTC_CNTL
32
Going to sleep now

となり、正しく押したSWを認識できている。34、35も同様だった。ということで正しく動作することが分かった。

また、消費電流もスイッチを押した直後少し増えて、スリープになったら減少(電源のメータの読みなのでいい加減)したのでちゃんと動いていそう。


まとめ

正しく動作させることができた。

概要

MicroPythonの開発環境を整え、ESP-WROOM-32で動くか試した。無事Lチカが動いた。


背景と目的

トランジスタ技術2018年5月号に、MicroPythonなるものが紹介されている。マイコンプログラムをPythonで組めるようだ。私は普段Pythonを使う機会が多く、慣れているので、マイコンプログラミングもPythonでできるとよいと思う。なので、とりあえずLチカを試しにやってみる。


詳細

1.環境整備

詳しい方法は、トランジスタ技術2018年5月号など各種書籍を参考にするとして、私がやった手順をメモっておく。今回は、

  • Windows10 PC上に環境構築
  • ESP-WROOM-32 Dev Kit Cを使用

という条件だ。

1.1 MicroPythonのダウンロード

githubのリポジトリからクローニング。

cd C:/Users/MyName/Documents
git clone https: //github.com/micropython/micropython.git MicroPython
1.2 ESP32用MicroPythonファームウェアのダウンロード

以下から、最新版をダウンロード。保存先はどこでもいいが、わかりやすいように1.3のToolと同じ場所に置いた。

https://micropython.org/download#esp32

1.3 Flash Download Toolのダウンロード

EspressifのWebサイトより、ツールをダウンロード。

https://www.espressif.com/sites/default/files/tools/flash_download_tools_v3.6.4_0.rar

RAR形式なので、解凍注意。


1.4 ampyのインストール

ampyは、ESP32のFlashメモリに書き込みを行うためのツール。

PCにPythonが既にインストールされている前提で、pipで以下を実行。

pip install adafruit-ampy

2.コンソールモードで実行

どうやら、シリアルコンソールで対話的にプログラムを実行できるようなので、やってみる。

2.1 ファームウェアの書き込み

ESP32開発ボードをUSBでPCに接続する。

Flash Download Toolを起動し、ESP32 Download Toolというボタンをクリックする。次に、立ち上がったツールで、1.2でダウンロードしたファームウェアを選択し、書き込み先先頭アドレスを0x1000と指定。シリアルポートとボーレートを115200bpsに設定して、STARTボタンを押す。プログレスバーが伸びきったら、書き込み完了。

20180417215812

2.2 コンソールモードで実行

Tera Termなどのシリアルコンソールアプリで、接続先COMポートをボーレートを115200bpsで開くと、以下のような表示となる。お馴染みのPythonコンソールだ。

20180417220148

ここで、以下のように入力。

from machine import Pin
io12 = Pin(12, Pin.OUT)
io12.value(1)

すると、GPIO12に接続されたLEDが点灯!まずは、コンソールモードでGPIOが制御できた。


3.プログラム作成

Lチカのコードを作成してみる。ファイル名は、main.pyとする。どうやら、ESP32起動後boot.py、main.pyの順に実行される仕組みのようだ。

GPIO12に、LEDを接続し、HIGHで点灯。1秒周期で点滅させる。

# coding: utf-8
from machine import Pin
import time

# ピンの設定
io12 = Pin(12, Pin.OUT)

# 1秒周期で点滅
while True:
    io12.value(1)
    time.sleep(0.5)
    io12.value(0)
    time.sleep(0.5)


4.書き込み

先ほど作成したmain.pyをampyを使って書き込む。コマンドプロンプトで、以下を実行。シリアルポート名とボーレート、ファイル名を指定。

ampy -p COM3 -b 115200 put main.py

ちなみに、ampyで書き込みを行うと当り前だがコンソールモードが実行できなくなる。またコンソールモードが使いたい場合、

ampy -p COM3 -b 115200 rm main.py

で、main.pyを削除すればよいようだ。


5.動作確認

リセットボタンを押したところ、プログラムが動き始め、LEDが点滅した。どうやらちゃんと書き込めたようだ。というわけで、とりあえずMicroPython環境が整った。


まとめ

MicroPythonの開発環境を整え、ESP-WROOM-32で無事Lチカできた。次は、Wi-Fiなどを使えるようにしてみたい。

概要

クラウド側の実装を行い、Google Homeにしゃべりかけて照明スイッチを操作するシステムが完成した。


背景と目的

前回に引き続き、クラウド側の実装を行い、システムとして仕上げる。


詳細

1.構想

クラウドとしては、

  • IFTTTでGoogleアシスタントチャンネルをトリガ、Webhooksチャンネルをアクションとする
  • Webhooksチャンネルでは、AWSのAPI Gatewayで作ったエンドポイントをたたく
  • API GatewayからLambda関数を呼び出す
  • Lambdaで、リクエスト内容に応じて、AWS IoTにトピックをパブリッシュする

という構成にする。こうすれば、Google Homeに話しかけることでAWS IoTへトピックがパブリッシュされ、サブスクライブ中のESP32にデータが届き、サーボモータが動くはずだ。


2.IFTTT

以前作成したのと同様に、アプレットを作成する。詳細は省くが、だいたい以下のようなイメージ。OK, Google。電気つけて。と言うと、AWS側のエンドポイントをたたければよい。

20180208224053

20180208224314


3.AWS

3.1 API Gateway

詳細は省くが、POSTでJSONを受け取るエンドポイントを用意。

3.2 Lambda

詳細は省略するが、API Gatewayが受け取ったイベント引数のJSONを処理して、AWS IoTサーバにトピックをパブリッシュするというイメージ。

# coding: utf-8

import boto3

TOPIC = 'ESP32がサブスクライブしているトピック名'

client = boto3.client('iot-data')

def lambda_handler(event, context):

    resp = client.publish(
        topic=TOPIC,
        qos=0,
        payload=event["operation"]
    )
    
    return 'Hello from Lambda'
3.3 AWS IoT

デバイスを1つ用意し、ESP32を接続する。(第2回での実装時に実施済み)

ここまでで、デバイスハードウェア、デバイスソフトウェア、クラウドとすべてのシステム要素が完成。


4.動作確認

以下の動画(若干音量が小さいので上げてください)のように、Google Homeにしゃべりかけてみたところ、電気が消えた!というわけで成功!シャキッ!という結構喧しい音がするのは愛嬌。


まとめ

市販品には絶対にあり得ないシステム構成だが、Google Homeで制御できる家電が増えてうれしい。

概要

ESP-WROOM-32のソフトウェアを作成し、インターネット経由でサーボモータが動かせるようにした。


背景と目的

前回のハードウェア製作に続き、ESP32のソフトウェアを作成する。


詳細

1.仕様

  • ESP-WROOM-32のPWMにて、サーボモータSG92Rをコントロール
  • ESP-WROOM-32をAWS IoTと接続し、あるトピックをサブスクライブ
  • 受信したペイロードに応じて、サーボモータを動かす


2.ソフトウェア

2.1 esp-idfをアップデート

本筋とは関係ないが、久しぶりESP-IDFを使うので、こちらに従い最新版にアップデート。

cd esp\esp-idf
git pull
git submodule update --init --recursive
2.2 プロジェクトを作成

今回は、AWS IoTと、サーボモータを使うので、esp-idfのサンプルであるesp-idf\examples\protocols\aws_iot\subscribe_publishを基本として、arduino-esp32をコンポーネントとして組み込み、サーボライブラリを使ってサーボモータを駆動する。

cd esp\iot_servo_switch
mkdir components
git clone https:// github.com/espressif/arduino-esp32.git arduino
cd arduino
git submodule update --init --recursive
cd ../main/certs

certsフォルダには、AWS IoTデバイスのaws-root-ca.pem、certificate.pem.crt、private.pem.keyの3つを格納。(ただし、subscribe_publishサンプルをそのまま使う場合のファイル配置である)


2.3 ソースコードを編集

arduino-esp32を使えるようにするため、こちらに従ってcppソース化。サーボモータ駆動用のPWM制御モジュールを使うので、esp32-hal-ledc.hをインクルード。ledcSetup、ledcAttachPinで、PWM制御用GPIOポートを初期化。

// main.cpp

// arduino-esp32関連
#include "Arduino.h"
#include "WiFi.h"

// サーボモータ関連
#include "esp32-hal-ledc.h"

// -------------------------
// 省略
// -------------------------

extern "C" void app_main()
{
    // Arduino初期化
    initArduino();
    
    // Wi-Fiの初期化
    initialise_wifi();

    // サーボ用PWMの設定
    ledcSetup(1, 50, 16); // channel 1, 50 Hz, 16-bit depth
    ledcAttachPin(18, 1); // GPIO18に割り当て
    ledcWrite(1, deg2pw(90, 16));

#ifdef CONFIG_MBEDTLS_DEBUG
    const size_t stack_size = 36*1024;
#else
    const size_t stack_size = 36*1024;
#endif
    xTaskCreatePinnedToCore(&aws_iot_task, "aws_iot_task", stack_size, NULL, 5, NULL, 1);
}

なお、deg2pwは、角度[deg]を与えてパルス幅に変換する作業用関数。

// 角度をパルス幅に変換
int deg2pw(int deg, int bit)
{
    double ms = ((double) deg - 90.0) * 0.95 / 90.0 + 1.45;
    return (int) (ms / 20.0 * pow(2, bit));
}

そして、サブスクライブ時のコールバック関数iot_subscribe_callback_handlerを編集。ペイロードを解析し、内容に応じてPWM信号の幅を変えて、実装の詳細は割愛するが、イメージとしては以下のように、ペイロードがONなら正方向、OFFなら逆方向にサーボモータ軸を一定角度回して戻す。この動作により、軸に付けたホーンの先が、ボタンをたたくような動作になる。

void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
                                    IoT_Publish_Message_Params *params, void *pData) {

    // ペイロードの解析
    const char op1[10] = "ON";
    const char op0[10] = "OFF";
    char s[10] = {'\0'};
    snprintf(s, (int) (params->payloadLen + 1), "%s", (const char *)params->payload);

    // 動かす
    if (strcmp(s, op1) == 0) {
        // ONなら点灯
        ledcWrite(1, deg2pw(140, 16)); // 正方向に回す
    } else if (strcmp(s, op0) == 0) {
        // OFFなら消灯
        ledcWrite(1, deg2pw(40, 16)); // 逆方向に回す
    } else {
        // それ以外は何もしない
    }
    // 一定期間待つ
    vTaskDelay(200 / portTICK_RATE_MS);
    // 戻す
    ledcWrite(1, deg2pw(90, 16));

}
2.4 make menuconfig

menuconfigでいくつか設定を行う。

  • AWS IoTのエンドポイント設定

以前の記事のとおり、AWS IoTのエンドポイントの設定をする

  • arduino-esp32の設定

"Autostart Arduino setup and loop on boot"を選択なしとする


2.5 書き込み

以下で書き込み。

make flash monitor


3.動作確認

以下が、サーボモータの先のホーンの動き。ボタンをたたけそうな感じがする。


まとめ

ESP32のソフトウェアが作成できた。次回は、クラウド側の設定を行う。

概要

Google Home、ESP-WROOM-32、サーボモータを使って、部屋の照明のスイッチを遠隔で無理やり動かすシステムを作る。第1回として、仕組みのハードウェア製作を行った。


背景と目的

以前、IRKitを使って、テレビやエアコンの電源をインターネット経由で操作できるようにしたが、照明も操作できるようにしたくなったので、やってみる。今回は、第1回としてハードウェアの製作を行う。


詳細

0.対象の照明

私の家の照明は、紐を引っ張っるか、壁にスイッチで点灯/消灯の操作をするタイプだ。なので、IRKitが使えない。なので、かなり強引だが、サーボモータで無理やりスイッチをたたくことにする。


1.回路

ネットにつながって、サーボモータが制御できれば良いので、ESP-WROOM-32と、小型サーボモータSG92Rを組み合わせることにした。設計した回路図は、以下。ESP32のGPIOは3.3Vなので、レベル変換をしてSG92Rの制御端子を駆動する。

回路図


2.機構

以下の写真の通り、ユニバーサル基板にサーボモータとESP32を固定して、基板の4隅に金具を折って作った爪を付けた。サーボモータの固定には、ロックタイを使用。これでも十分な強度だ。

DSC_0236

この爪をスイッチパネルと壁の隙間に差し込んで、固定できた。

DSC_0238


まとめ

ハードウェアが完成。次回は、ESP32側のソフトウェアを作成する。

概要

ESP-WROOM-32で、プログラムを書き込む容量を増やす方法をまとめた。


背景と目的

ESP-WROOM-32で、あるプログラムを書き込もうとしたところ、以下のように

"最大1310720バイトのフラッシュメモリのうち、スケッチが1333771バイト(101%)を使っています。"

と表示され書き込みができなかった。そこで、容量を増やす方法について調べ、実際に増やしてみる。


詳細

0.方法を知る

Web各所で情報を探し回ったところ、

などがあったが、いろいろ試行錯誤した結果、結論から言うと、以下の2手順が必要ということがわかった。

  • tools/partitions/default.csvの編集
  • boards.txtの編集

ということで、以下順に行う。


1.tools/partitions/default.csvの編集

default.csvを開くと、以下のような記述が出てくる。

# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x5000,
otadata,  data, ota,     0xe000,  0x2000,
app0,     app,  ota_0,   0x10000, 0x140000,
app1,     app,  ota_1,   0x150000,0x140000,
eeprom,   data, 0x99,    0x290000,0x1000,
spiffs,   data, spiffs,  0x291000,0x16F000,

app0からspiffsという4行分を編集する。プログラム書き込み領域を0x20000 = 131072byte増加させることにすると、

# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x5000,
otadata,  data, ota,     0xe000,  0x2000,
app0,     app,  ota_0,   0x10000, 0x160000,
app1,     app,  ota_1,   0x170000,0x160000,
eeprom,   data, 0x99,    0x2D0000,0x1000,
spiffs,   data, spiffs,  0x2D1000,0x12F000,

という感じで、app0とapp1のsizeを0x20000増やし、spiffsのsizeは0x40000減らす。また、app1、eeprom、spiffsのoffsetをそれぞれ0x20000だけずらせばよい。


2.boards.txtの編集

arduino-esp32のrootにあるboards.txtを開くと、10行目くらいにある

esp32.upload.maximum_size=1310720

という記述がある。書き込み時に

"最大1310720バイトのフラッシュメモリのうち、・・・"

の数値だ。これを所望のサイズに変更する。今回は、先ほどpartitions/default.csvで0x20000 = 131072byte増加させたので、こちらも同様に1310720 + 131072となるように変更。

esp32.upload.maximum_size=1441792

3.動作確認

上記の作業をして、プログラム書き込みを行ったところ、以下のように最大サイズが変更され、以前収容できなかったプログラムを書き込むことができた。というわけで成功。

最大1441792バイトのフラッシュメモリのうち、スケッチが1333771バイト(92%)を使っています。


まとめ

ESP-WROOM-32で、プログラムを書き込む容量を増やすことができた。

概要

arduino-esp32を使って、ESP-WROOM-32でiBeaconをスキャンすることができた。


背景と目的

以前、esp-idfを使ってiBeaconをスキャンできたが、Arduino用SDKのarduino-esp32では難しかった。しかし、最新版では、BLE_scanというサンプルコードが追加されており、これを使えばiBeaconのスキャンができそうだ。なので、やってみる。


詳細

1.方針

2017/10/14時点でarduino-esp32には、どうやらNeil Kolbanさんという人が親切にも作ってくれたESP32_BLE_Arduinoというサンプルが含まれているようなので、ありがたく使用させていただく。BLE_scanというサンプルコードは、BLEデバイスをスキャンしてアドバタイジングデータを取得できるようなので、iBeaconだけを検出するようにちょっと変更してみる。


2.コーディング

2.1 iBeaconを扱うクラス

まず、iBeaconを扱うための処理をまとめておいたほうがいいと思ったので、BLEAdvertisedDeviceという型の変数を受け取って、iBeaconか判断し、iBeaconであれば、uuid、major、minor、rssiを読み取って保持するクラスを作成。細かい処理はlibraries\BLE\src\BLEAdvertisedDevice.cppあたりを参考にした。

// iBeaconを扱うクラス
class iBeacon
{
private:
  String uuid;
  uint16_t major;
  uint16_t minor;
  int rssi;
public:
  bool createByAdvertisedDevice(BLEAdvertisedDevice advertisedDevice); // BLEAdvertisedDeviceからデータを組み立てる
  String getUUID() { return uuid; }
  uint16_t getMajor() { return major; }
  uint16_t getMinor() { return minor; }
  int getRSSI() { return rssi; }
};

// BLEAdvertisedDeviceからデータを組み立てる
bool iBeacon::createByAdvertisedDevice(BLEAdvertisedDevice advertisedDevice) {

  char work[7];
  
  // 16進データをもらう
  String hexString = (String) BLEUtils::buildHexData(nullptr, (uint8_t*)advertisedDevice.getManufacturerData().data(), advertisedDevice.getManufacturerData().length());
  // iBeaconかチェック
  if (hexString.substring(0, 8).equals("4c000215")) {
    // iBeaconのとき
    uuid =  hexString.substring(8, 16) + "-" + 
            hexString.substring(16, 20) + "-" + 
            hexString.substring(20, 24) + "-" + 
            hexString.substring(24, 28) + "-" + 
            hexString.substring(28, 40);  
    ("0x" + hexString.substring(40, 44)).toCharArray(work, 7);
    major = (uint16_t) atof(work);
    ("0x" + hexString.substring(44, 48)).toCharArray(work, 7);
    minor = (uint16_t) atof(work);
    rssi = advertisedDevice.getRSSI();
    return true;
  } else {
    // iBeaconじゃないとき
    return false;
  }
}
2.2 Arduinoプログラム

次に、サンプルを上記のiBeaconクラスを使って修正。uuid、major、minor、rssiをシリアルに出力する。

#include "BLEDevice.h"
#include "BLEUtils.h"
#include "BLEScan.h"
#include "BLEAdvertisedDevice.h"

int scanTime = 2; //In seconds

/*
ここに、上記のiBeaconクラスを記述
*/

BLEScan* pBLEScan;

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice advertisedDevice) {
      // アドバタイジングデータを受け取ったとき
      iBeacon ibcn;      
      if (ibcn.createByAdvertisedDevice(advertisedDevice)) {
        char uuid[37];
        ibcn.getUUID().toCharArray(uuid, 37);
        Serial.printf("UUID: %s, Major: %d, Minor: %d, RSSI: %d \n", uuid, ibcn.getMajor(), ibcn.getMinor(), ibcn.getRSSI());
      }
    }
};

void setup() {
  Serial.begin(115200);
  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan(); //create new scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
}

void loop() {
  BLEScanResults foundDevices = pBLEScan->start(scanTime);
}

3.動作確認

上記のプログラムを動かしてみたところ、以下のようになった。ちゃんとiBeaconを検出できている。が、フラッシュメモリをかなり消費する。これはもともとのサンプル自体が大きいためだ。なので、メモリ不足に注意が必要。

UUID: 00000000-1ae9-1001-b000-001c4d6465e, Minor: 1, Minor: 4, RSSI: -66

まとめ

arduino-esp32を使って、ESP-WROOM-32でiBeaconをスキャンすることができた。esp-idfを使わないで済む場面がまた1つ増えてよかった。

概要

ESP-IDFのversion2.1で、WiFiとBluetoothを同時に使用しようとしたら、変数名/関数名が被っていてコンパイルエラーが出たので、どうにか修正してみた。


背景と目的

ESP-IDFのversion2.1(2017/09/06での最新版)において、WiFiとBluetoothを同時に使用しようとすると、

20170907021644

というエラーが起きてしまう。そこで、これを解消する。


詳細

1.状況

ESP-IDFのversion2.1(2017/09/06での最新版)において、WiFiとBluetoothを同時に使用しようとすると、

  • WiFi制御系のesp-idf/components/lwip/include/lwip/apps/dhcpserver.h
  • Bluetooth制御系のesp-idf/components/bt/bluedroid/osi/include/list.h

の2つがインクルードされるが、

  • dhcpserver.hでlist_nodeのという変数の型が定義されている
  • list.hでlist_nodeという関数が定義されている

ため、コンパイルエラーを生じてしまう。

具体的には、

  • dhcpserver.hでは、
typedef struct _list_node {
	void *pnode;
	struct _list_node *pnext;
} list_node;
  • controller.hでは、
// Returns the value stored at the location pointed to by the iterator |node|.
// |node| must not equal the value returned by |list_end|.
void *list_node(const list_node_t *node);

なので、これらの名前が被らないように、変更してやればよい。ライブラリを修正するのは少し気が引けるが、エラーが出ていては始まらないし、どうせ自分の開発環境だから弄るのは自由なので、とにかく修正してみよう。


2.修正

方針としては、どちらかの名前を変えればいいのだが、dhcpserver.hの変数の型名list_nodeを変更するほうが簡単そうなので、こちらを変更する。具体的には、まあ何でもいいのだが、例えばLIST_NODEという大文字にしてみる。

typedef struct _list_node {
	void *pnode;
	struct _list_node *pnext;
} LIST_NODE;

すると、dhcpserver.cでもともとlist_nodeという型の変数を参照しているものがすべて参照不可能になりエラーが出るので、テキストエディタ等で、dhcpserver.c内の"list_node"を"LIST_NODE"に置換する。


3.コンパイルしてエラーが出ないことを確認

2の修正を施したものを、再度コンパイルしてみると、無事エラーが消えてコンパイル成功!というわけで、2の作業によって問題が回避できた。

ところで、このような問題は、そのうち修正版が出るだろうが、とりあえず、今はその場しのぎで対応しておくことにする。


まとめ

ESP-IDFのversion2.1でのコンパイルエラーを解消できた。

このページのトップヘ