概要
LTE-M Shield for ArduinoをESP-WROOM-32と組み合わせ、動作を確認した。画像の送信がどうにか行えそうな見通しが立った。
- 2021/09/18追記
- BG96へ一度に書き込むデータ量
- BG96とのボーレート変更
背景と目的
前回、SORACOMのIoT SIM plan-D D-300MBとLTE-M Shield for Arduinoを使って、データを送信することができた。今回は、ESP-WROOM-32(以下、ESP32)と組み合わせて、大きいサイズのデータを送れるか動作を確認する。
詳細
0. やりたいこと
1. 配線
ピンク字が接続先ESP32側端子の名前。基本的に電源とリセット端子とシリアル用GPIOだけ。GPIO16,17は、後述のHardwareSerialで使用する。
2. LTE-M Shield for Arduinoとの間のシリアルのボーレートをどのくらいまで上げられるか
前回、ArduinoUNOとの組み合わせでは57600bpsまで(SoftwareSerial使用)しか使えなかった。なので、ESP32と組み合わせてどのくらいまで使えるか試したところ、
HardwareSerialを使うことで、230400bpsで通信可能 (2021/09/18更新)
ということが分かった。関連するソースコードだけ抜き出せば、
#define BAUDRATE 230400 // 2021/09/18更新 #include <HardwareSerial.h> // オブジェクト作成 HardwareSerial LTE_M_shieldUART(2); // シリアルポートを渡す TinyGsm modem(LTE_M_shieldUART);
となる。ちなみに、SoftwareSerialでは、うまくいかなかった。低速なら動くかもしれないが。
また、230400bps以外に460800、921600を試してみたところ、うまく書き込めないのだが、ボーレート設定に対するレスポンスではOKが返ってきているので、もしかするとハードウェア周りを注意して実装すれば通信可能かもしれない。(今は実験のため、ブレッドボードや10cm弱の配線を使ってやっている。)
3. 画像ファイル等を想定した数100kB程度のデータが送信できるか確認する
LTE-M Shield for Arduinoを使ってやりたいこととして、カメラで撮影した画像の送信を考えている。以前作成した成長記録用カメラでは、1枚あたり200-300kBの画像となるのでこのくらいのサイズのデータを送信できるか試しておきたい。
今回は、カメラを動かす環境がないので、疑似画像データとして300kB程度の適当なjpgファイルのデータをソースコードに埋め込んで、それを読み取って送信してみることにした。条件は以下。
3.1 結果まとめ
- ESP32からLTE-M Shield for Arduinoへシリアルで送る際、1度に送信できるサイズは1460byte(2021/09/18更新)が限界らしい
- それ以上のデータを送りたい場合は、Serial.writeとSerial.flushを組み合わせて分割して書き込むとうまくいく(実はこのときも同じ問題にぶつかったためそのノウハウを活用)。しかし、細切れで渡すことで、ESP32からLTE-M Shield for Arduinoの実質の通信速度がだいたい10kB/s弱となった。(2021/09/18更新)
- レスポンスステータスコードが400になるが、SORACOM Beamからの転送先のAWSではちゃんとデータが受け取れている
3.2 分割して書き込む
今回画像データを送信するためBody部分が数100kBと大きい。(payloadという変数に入っている)したがって、以下のようにBody部分を1460byte(2021/09/18更新)に細切れにして送信している。
/* connect */ // 8888はSORACOM Beamエンドポイントの都合 if (!ctx.connect(ENDPOINT, 8888)) { CONSOLE.println(F("failed.")); delay(3000); return; } size_t contentLength = strlen(payload); CONSOLE.println(contentLength); /* send request */ char hdr_buf[511]; ctx.println(F("POST / HTTP/1.1")); sprintf_P(hdr_buf, PSTR("Host: %s"), ENDPOINT); ctx.println(hdr_buf); ctx.println("Connection: Close"); ctx.println(F("Content-Type: application/json")); sprintf_P(hdr_buf, PSTR("Content-Length: %d"), contentLength); ctx.println(hdr_buf); ctx.println(); // ボディ // 一度に大きなデータをprintlnするとうまくいかない // mバイトに分割してwriteする int m = 1460; // 1460byteが限界(2021/09/18更新) int i, j = 0; uint8_t * p = (uint8_t *) malloc(m); while (true) { for (i = 0; i < m; i++) { p[i] = payload[i + j * m]; if (i + j * m == contentLength - 1) break; } ctx.write(p, m); ctx.flush(); // CONSOLE.printf("j=%d, length=%d\n", j, i); // 確認用 if (i + j * m == contentLength - 1) break; j++; } // 空行を最後に ctx.println(); // 2つprintlnがないとだめ ctx.println();
3.3 一度に書き込めない理由
推測だが、LTE-M Shield for Arduinoの受信バッファのサイズではないかと考える。
https://auroraevernet.ru/upload/iblock/538/538e779e251d00d8aa99ebad4c479d5c.pdf
これかも。AT+QISENDコマンドで、1460byteまでしか一度に送信できなそう?
↓
2021/09/18 その通りだった。
3.4 レスポンスステータスコードが400
AWS側では正しく処理されているので、SORACOM Beamエンドポイントとして400を返しているように見える。送信できてしまったので、今回はとりあえずいいとして、いずれは解決したい。
まとめと今後の課題
LTE-M Shield for ArduinoとESP32を組み合わせて、シリアルの速度、大きなサイズのデータ送信を確認できた。通信速度が遅いことが課題としてあるので、今後解決できないか継続的に取り組む必要がある。ひとまず、通信速度は満足できるレベルではないが、一応どうにか画像の送信が実用になりそうなので、OKとする。(2021/09/18更新)