ATOM TailBAT 190 mAh のバッテリーがどれくらい継続給電できるか簡単に検証したメモです。
背景
最近、ようやく ATOMS3 が使いこなせるようになってきて ATOM TailBAT 190 mAh のバッテリーがどれくらい継続給電できるかが知りたくなりました。
展示などでどういった充電サイクルと個数で臨めばいいかも見えてくるのでやってみます。
AtomS3 のプログラム
ということで、
- Wi-Fi を常時接続して
- ローカルネットワークの MQTT ブローカーに対して接続
- その MQTT に 60 秒に一度データを送り
- ディスプレイにその進捗状況を表示し
- どこまでデータを送り続けられるかをやってみる
という流れで、以下のようなプログラムを書きました。
#include "M5AtomS3.h" #include <WiFi.h> #include <WiFiMulti.h> WiFiMulti wifiMulti; #include <ArduinoJson.h> // バージョンは v6 で #include <WiFiClient.h> #include <PubSubClient.h> const char* ssid = "ssid"; const char* password = "password"; // MQTTの接続先のIP const char *endpoint = "endpoint"; // MQTTのポート const int port = 1883; // 今回使いたい MQTT のユーザー名 const char *mqttUsername = "mqttUsername"; // 今回使いたい MQTT のパスワード const char *mqttPassword = "mqttPassword"; // デバイスID char deviceID[50]; // トピックを保存するためのバッファを確保 char pubTopic[50]; char subTopic[50]; // プログラム名 #define FW_NAME "AtomS3_Wifi_Simple_Test" // ファームウェアバージョン #define FW_VERSION "1.0.1" // ArduinoJson v6 の記述で JSON を格納する StaticJsonDocument を準備 StaticJsonDocument<512> root; WiFiClient httpsClient; PubSubClient mqttClient(httpsClient); char pubJson[512]; // セットアップ管理 int setupFlag = 0; // 定期実行時間(ミリ秒) int executeTime = 60000; // 待ち時間処理 int previoueExecuteTime = 0; // 送信回数 int executeCount = 0; void setup() { auto cfg = M5.config(); AtomS3.begin(cfg); wifiMulti.addAP(ssid, password); AtomS3.Display.setTextDatum(TL_DATUM); AtomS3.Display.setCursor(0,0); AtomS3.Display.setTextSize(1); AtomS3.Display.println("[TEST]"); AtomS3.Display.println(FW_NAME); AtomS3.Display.println(FW_VERSION); delay(3000); Serial2.begin(9600, SERIAL_8N1, 5, -1); WiFi.mode(WIFI_STA); WiFi.setSleep(false); Serial.print("Connecting..."); AtomS3.Display.println("WiFi "); AtomS3.Display.print("."); while (wifiMulti.run() != WL_CONNECTED) { delay(500); Serial.print("."); AtomS3.Display.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(WiFi.SSID()); Serial.print("IP address: "); Serial.println(WiFi.localIP()); Serial.print("MAC address: "); Serial.println(WiFi.macAddress()); AtomS3.Display.setCursor(0,0); AtomS3.Display.clear(); AtomS3.Display.println("[TESTER]"); AtomS3.Display.println(FW_NAME); AtomS3.Display.println(FW_VERSION); AtomS3.Display.println("WiFi OK!"); // deviceID String macStr = String(WiFi.macAddress()); macStr.replace(":", ""); sprintf(deviceID, "%s", macStr); AtomS3.Display.print("ID "); AtomS3.Display.println(deviceID); AtomS3.Display.print("IP "); AtomS3.Display.println(WiFi.localIP()); // メッセージを知らせるトピック sprintf(pubTopic, "device/%s/pub", deviceID); // メッセージを待つトピック sprintf(subTopic, "device/%s/sub", deviceID); AtomS3.Display.println("----"); AtomS3.Display.print("pubTopic "); AtomS3.Display.println(pubTopic); AtomS3.Display.println("----"); mqttClient.setServer(endpoint, port); mqttClient.setCallback(mqttCallback); mqttClient.setBufferSize(512); connectMQTT(); delay(1000); AtomS3.Display.print("... 5 "); delay(1000); AtomS3.Display.print("4 "); delay(1000); AtomS3.Display.print("3 "); delay(1000); AtomS3.Display.print("2 "); delay(1000); AtomS3.Display.print("1 > GO!"); delay(1000); setupFlag = 1; } void connectMQTT() { // 起動してからの経過時間でシードを設定 randomSeed(millis()); // MQTT clientID のランダム化(名称重複対策) char clientID[40] = "clientID"; String rndNum = String(random(0xffffff), HEX); String deviceIDRandStr = String("client-"); deviceIDRandStr.concat(deviceID); deviceIDRandStr.concat("-"); deviceIDRandStr.concat(rndNum); deviceIDRandStr.toCharArray(clientID, 40); Serial.print("clientID "); Serial.println(clientID); AtomS3.Display.print("MQTT"); while (!mqttClient.connected()) { if (mqttClient.connect(clientID,mqttUsername,mqttPassword)) { Serial.println("MQTT Connected."); int qos = 0; mqttClient.subscribe(subTopic, qos); Serial.println("MQTT Subscribed."); // Connected message DynamicJsonDocument doc(512); doc["type"] = "connected"; doc["localIP"] = WiFi.localIP(); serializeJson(doc, pubJson); mqttClient.publish(pubTopic, pubJson); AtomS3.Display.println(" > OK!"); } else { Serial.print("Failed. Error state="); Serial.println(mqttClient.state()); // Wait 5 seconds before retrying delay(5000); } } } void mqttCallback (char* topic, byte* payload, unsigned int length) { String str = ""; Serial.print("Received. topic="); Serial.println(topic); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); str += (char)payload[i]; } Serial.print("\n"); // Deserialize the JSON dsocument DeserializationError error = deserializeJson(root, str); // Test if parsing succeeds. if (error) { Serial.print(F("deserializeJson() failed: ")); Serial.println(error.f_str()); return; } // } void mqttLoop() { if (!mqttClient.connected()) { connectMQTT(); } mqttClient.loop(); } void loop() { // 常にチェックして切断されたら復帰できるように mqttLoop(); // millis() を秒に変換 unsigned long ms = millis(); float seconds = ms / 1000.0; // 小数点以下2桁にフォーマットして表示 char buffer[10]; snprintf(buffer, sizeof(buffer), "%.2f", seconds); AtomS3.update(); AtomS3.Display.setCursor(0,0); AtomS3.Display.clear(); AtomS3.Display.println("[TESTER]"); AtomS3.Display.println("waiting..."); AtomS3.Display.print(buffer); AtomS3.Display.print(" sec"); // 定期実行 if(millis() - previoueExecuteTime > executeTime){ AtomS3.Display.println("---"); executeCount++; // Connected message DynamicJsonDocument doc(512); doc["type"] = "execute"; doc["localIP"] = WiFi.localIP(); doc["millis"] = millis(); doc["executeCount"] = executeCount; serializeJson(doc, pubJson); mqttClient.publish(pubTopic, pubJson); AtomS3.Display.println("---> send!"); AtomS3.Display.print("count :"); AtomS3.Display.println(executeCount); previoueExecuteTime = millis(); delay(1000); } delay(1000); }
受け取る Node-RED の仕組み
データを計測するのは、このようなフローです。
Aedes MQTT ブローカーのノードでローカルネットワークの MQTT ブローカーを作りつつ、購読したトピックからデータを受け取り、それをダッシュボードに表示する仕組みです。
たとえばこれは 8 回、つまり 8 分送った状況です。
実際どうだったか
さて、あとは TailBat を満充電して放置するだけです。
こんな結果になりました。最小値で 47 分。
だいたい最大値で 65 分という結果です。
10 回くらい複数の TailBat で試してこんな感じで、おおよそ 50 分程度は電池が持つというところになりそうです。
勝手に体感として「15 分くらいしかもたないでしょ」と思っていたので、良い意味で裏切られた結果になりました。
もちろん、これでサーボを動かしたり、他のデバイスと連携したり、ネットワークへのアクセス
頻度を高めたら変わってくるかとは思いますが、一つの基準が持てて良かったです。