M5StickCでの省電力ノウハウ

この記事はM5Stack Advent Calendar 2019 25日目の記事です。

概要

M5StickCを省電力で動かすための情報です。Arduino Coreで検証していますが、どんな環境でも使えると思います。

計測環境

M5StickCの5V IN端子にマルチメーター経由で電源を接続して、マルチメーターの電流計で計測しています。

誤差が出やすい環境ですので、数値の絶対値はあまり信用しないでください。また、外部電源を接続していますので、バッテリーにも多少充電されています。

AXP192の値との差

測定値消費電流(mA)
マルチメーター53.1
M5.Axp.GetVinCurrent() 外部電源電流57.5
M5.Axp.GetBatCurrent() バッテリー電流55.0

マルチメーターの値が一番低かったです。マルチメーターとAXP192の外部電源電流で4.4mAも差がありました。

外部電源を外して、バッテリー駆動にした場合には55mAでしたが、実際のところどの数字が正しいのかはわかりません。AXP192の計測自体で消費電流が変わってしまうので、本文ではマルチメーターの数値を元にしています。

初期状態での消費電流割合

機能消費電流(mA)
ESP32(CPU MAX)43.0
画面(12)20.4
5V DCDC1.3
MIC0.1
RTC0.1
AXP192 ADC0.1
AXP192基本機能1.4
ベース1.7
合計68.1

ざっくりとした、M5StickCの最低限のスケッチの場合の消費電流の割合です。

#include <M5StickC.h>
void setup() {
  M5.begin();
}
void loop() {
}

一番支配的なのがCPUで、その後画面になります。

このデータは、徐々にパラメーターを変えながら機能を無効にしていった差分をまとめたものになります。

CPU消費電流の下げ方 その1 delay()

状態消費電流(mA)差分(mA)
CPU MAX68.10
delay(1)53.3-14.8

loop()の中身にdelay()がない場合には、無限ループでloop()が呼び出されている状態ですので、中身がなくても電力を使ってしまいます。

delay(1)を入れることで約15mAの消費電流が下がりました。また、delayの数値をもっと大きくしても、あまり消費電流は下がりませんでした。

ただし、処理が増えて来ると消費電流はあがりますので、絶対的に消費電流を下げる方法ではありません。

CPU消費電流の下げ方 その2 setCpuFrequencyMhz()

状態消費電流(mA)差分(mA)
ESP32 240MHz(無線利用可)28.20
ESP32 160MHz(無線利用可)19.5-8.7
ESP32 80MHz(無線利用可)15.4-12.8
ESP32 40MHz8.4-19.8
ESP32 20MHz6.4-21.8
ESP32 10MHz5.6-22.6
CPU 電源供給OFF0-28.2

delay(1)をした状態でsetCpuFrequencyMhz()でCPU周波数を変更した場合の差分です。

無線を利用する場合には80以上を指定する必要があるので注意してください。また、処理がない場合の消費電流なので、重い処理をすることでより消費電流が増えます。

CPU電源供給OFFのみAXP192経由でDCDC1への電源共有をOFFにしています。この他にスリープすることでもう少し消費電力を減らすことが可能だと思います。

画面消費電流の減らし方

状態消費電流(mA)差分(mA)
LCD 明るさ1220.10.0
LCD 明るさ1114.2-5.9
LCD 明るさ109.0-11.1
LCD 明るさ94.2-15.9
LCD 明るさ81.0-19.0
LCD 明るさ70.2-19.9
OFF0.0-20.1

M5.Axp.ScreenBreath()で画面の明るさを変更した場合の消費電流です。OFFはAXP192でLDO2への電源供給をOFFにしています。

OFFにしても、明るさ7でもほとんど変わりませんので、OFFにするのであればなんとか読めることができる7を使ってもいいと思います。

ただし、8か9ぐらいの明るさがないと文字を読むのは難しい気がします。

5V OUT用DCDC(EXTEN端子)

ESP32のスリープを検証しているときに、思ったより駆動時間が伸びないので、なにか消費電流を使っているのだと思っていたのですが、5V OUT用のDCDCが1.3mA以上使っていました。測定する状況によって違うのですが、2mAぐらい計測された場合もあります。

M5StickCは80mhAのバッテリーを搭載しているので、1.3mAだとしても24時間で31.2mhAの電力を5V OUTのDCDCで使っていることになります。

利用しないのであればOFFにしておくことをおすすめします。OFFにするとバッテリー電圧がそのまま出力される状態になります。

OFFにするやり方は後ろにある検証用スケッチを参考にしてもらいたいですが、次バージョンのSDKで初期化時にOFFにするパラメーターが追加されています。

その他

AXP192基本機能の1.4mAは電源OFFにしないと減らすことはできません。その他の機能は0.1mA単位なので、減らしてもいいですが、それほど効果はないようです。

検証用スケッチ

#include <M5StickC.h>
int delayTime = 1;
void setup() {
  M5.begin();
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.printf("Current Test\n");
}
void loop() {
  while (Serial.available()) {
    String command = Serial.readString();
    command.trim();
    if (command == "") {
      // Skip
    } else if (command == "0") {
      delayTime = 0;
      Serial.print("Command : delayTime = ");
      Serial.println(delayTime);
    } else if (command == "1") {
      delayTime = 1;
      Serial.print("Command : delayTime = ");
      Serial.println(delayTime);
    } else if (command == "10") {
      delayTime = 10;
      Serial.print("Command : delayTime = ");
      Serial.println(delayTime);
    } else if (command == "100") {
      delayTime = 100;
      Serial.print("Command : delayTime = ");
      Serial.println(delayTime);
    } else if (command == "1000") {
      delayTime = 1000;
      Serial.print("Command : delayTime = ");
      Serial.println(delayTime);
    } else if (command == "5000") {
      delayTime = 5000;
      Serial.print("Command : delayTime = ");
      Serial.println(delayTime);
    } else if (command == "AXP") {
      Serial.println("Command : AXP");
      Serial.printf("AXP192 Status\n");
      Serial.printf("\n");
      Serial.printf("Battery\n");
      Serial.printf(" State:%6d\n"  , M5.Axp.GetBatState());      // バッテリーが接続されているか(常に1のはず)
      Serial.printf(" Warn :%6d\n"  , M5.Axp.GetWarningLevel());  // バッテリー残量警告 0:残あり, 1:残なし
      Serial.printf(" Temp :%6.1f\n", M5.Axp.GetTempInAXP192());  // AXP192の内部温度
      Serial.printf(" V(V) :%6.3f\n", M5.Axp.GetBatVoltage());    // バッテリー電圧(3.0V-4.2V程度)
      Serial.printf(" I(mA):%6.1f\n", M5.Axp.GetBatCurrent());    // バッテリー電流(プラスが充電、マイナスが放電)
      Serial.printf(" W(mW):%6.1f\n", M5.Axp.GetBatPower());      // バッテリー電力(W=V*abs(I))
      Serial.printf("ASP\n");
      Serial.printf(" V(V) :%6.3f\n", M5.Axp.GetAPSVoltage());    // ESP32に供給されている電圧
      Serial.printf("VBus(USB)\n");
      Serial.printf(" V(V) :%6.3f\n", M5.Axp.GetVBusVoltage());   // USB電源からの電圧
      Serial.printf(" I(mA):%6.1f\n", M5.Axp.GetVBusCurrent());   // USB電源からの電流
      Serial.printf("VIN(5V-In)\n");
      Serial.printf(" V(V) :%6.3f\n", M5.Axp.GetVinVoltage());    // 5V IN端子からの電圧
      Serial.printf(" I(mA):%6.1f\n", M5.Axp.GetVinCurrent());    // 5V IN端子からの電流
    } else if (command == "COUL_OFF") {
      Serial.println("Command : COUL_OFF");
      M5.Axp.DisableCoulombcounter();
    } else if (command == "COUL_ON") {
      Serial.println("Command : COUL_ON");
      M5.Axp.EnableCoulombcounter();
    } else if (command == "ADC_OFF") {
      Serial.println("Command : ADC_OFF");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x82);
      Wire1.write(0x00);
      Wire1.endTransmission();
      Wire1.beginTransmission(0x34);
      Wire1.write(0x83);
      Wire1.write(0x00);
      Wire1.endTransmission();
    } else if (command == "ADC_ON") {
      Serial.println("Command : ADC_ON");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x82);
      Wire1.write(0xff);
      Wire1.endTransmission();
      Wire1.beginTransmission(0x34);
      Wire1.write(0x83);
      Wire1.write(0xff);
      Wire1.endTransmission();
    } else if (command == "EXTEN_10_OFF") {
      Serial.println("Command : EXTEN_10_OFF");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x10);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() & ~(1 << 2);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x10);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "EXTEN_10_ON") {
      Serial.println("Command : EXTEN_10_ON");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x10);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() | (1 << 2);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x10);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "DCDC2_10_OFF") {
      Serial.println("Command : DCDC2_10_OFF");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x10);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() | (1 << 0);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x10);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "DCDC2_10_ON") {
      Serial.println("Command : DCDC2_10_ON");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x10);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() | (1 << 0);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x10);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "EXTEN_OFF") {
      Serial.println("Command : EXTEN_OFF");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() & ~(1 << 6);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "EXTEN_ON") {
      Serial.println("Command : EXTEN_ON");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() | (1 << 6);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "DCDC2_OFF") {
      Serial.println("Command : DCDC2_OFF");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() & ~(1 << 4);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "DCDC2_ON") {
      Serial.println("Command : DCDC2_ON");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() | (1 << 4);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "LDO3_OFF") {
      Serial.println("Command : LDO3_OFF");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() & ~(1 << 3);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "LDO3_ON") {
      Serial.println("Command : LDO3_ON");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() | (1 << 3);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "LDO2_OFF") {
      Serial.println("Command : LDO2_OFF");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() & ~(1 << 2);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "LDO2_ON") {
      Serial.println("Command : LDO2_ON");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() | (1 << 2);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "DCDC3_OFF") {
      Serial.println("Command : DCDC3_OFF");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() & ~(1 << 1);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "DCDC3_ON") {
      Serial.println("Command : DCDC3_ON");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() | (1 << 1);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "DCDC1_OFF") {
      Serial.println("Command : DCDC1_OFF");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() & ~(1 << 0);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "DCDC1_ON") {
      Serial.println("Command : DCDC1_ON");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() | (1 << 0);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x12);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "RTC_OFF") {
      Serial.println("Command : RTC_OFF");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x35);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() & ~(1 << 7);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x35);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "RTC_ON") {
      Serial.println("Command : RTC_ON");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x35);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() | (1 << 7);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x35);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "GPIO0_OFF") {
      Serial.println("Command : GPIO0_OFF");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x90);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() & ~(1 << 2);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x90);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "GPIO0_ON") {
      Serial.println("Command : GPIO0_ON");
      Wire1.beginTransmission(0x34);
      Wire1.write(0x90);
      Wire1.endTransmission();
      Wire1.requestFrom(0x34, 1);
      uint8_t state = Wire1.read() | (1 << 2);
      Wire1.beginTransmission(0x34);
      Wire1.write(0x90);
      Wire1.write(state);
      Wire1.endTransmission();
    } else if (command == "CPU_10") {
      Serial.println("Command : CPU_10");
      setCpuFrequencyMhz(10);
    } else if (command == "CPU_20") {
      Serial.println("Command : CPU_20");
      setCpuFrequencyMhz(20);
    } else if (command == "CPU_40") {
      Serial.println("Command : CPU_40");
      setCpuFrequencyMhz(40);
    } else if (command == "CPU_80") {
      Serial.println("Command : CPU_80");
      setCpuFrequencyMhz(80);
    } else if (command == "CPU_160") {
      Serial.println("Command : CPU_160");
      setCpuFrequencyMhz(160);
    } else if (command == "CPU_240") {
      Serial.println("Command : CPU_240");
      setCpuFrequencyMhz(240);
    } else if (command == "LCD_7") {
      Serial.println("Command : LCD_7");
      M5.Axp.ScreenBreath(7);
    } else if (command == "LCD_8") {
      Serial.println("Command : LCD_8");
      M5.Axp.ScreenBreath(8);
    } else if (command == "LCD_9") {
      Serial.println("Command : LCD_9");
      M5.Axp.ScreenBreath(9);
    } else if (command == "LCD_10") {
      Serial.println("Command : LCD_10");
      M5.Axp.ScreenBreath(10);
    } else if (command == "LCD_11") {
      Serial.println("Command : LCD_11");
      M5.Axp.ScreenBreath(11);
    } else if (command == "LCD_12") {
      Serial.println("Command : LCD_12");
      M5.Axp.ScreenBreath(12);
    } else if (command == "RESET") {
      Serial.println("Command : RESET");
      ESP.restart();
    } else {
      Serial.print("Command? : ");
      Serial.println(command);
    }
  }
  delay(delayTime);
}

シリアルモニタからコマンドを送信することで、状態が変わるスケッチです。

リアルタイム系無線利用時の省電力方針

常時無線通信を行う場合には、CPUクロックを80MHz以上にする必要があります。基本80で動かしたほうがよいと思います。

通信間隔は1秒でも0.1秒でも、それほど消費電流に差はないようです。1分ぐらいまで間隔をあけると消費電流は下がっていました。

無線方式には主にWi-FiとBluetooth、ESP-NOWがありますが、ESP-NOWが一番省電力です。反面受信側にもESP32が必要になるので、ノートパソコンなどで直接受信した場合にはBluetooth Serialの利用が手軽に使えます。

上記にリアルタイム系の通信継続時間を検証しているので、参考にしてみてください。

リアルタイム系無線利用時の推定動作時間の計算方法

状態差分(mA)
ESP-NOW 0.1秒間隔送信3.4
ESP-NOW 0.01秒間隔送信6.2

一番最初の表から基本となるプログラムの消費電流を計算し、上記の差分を足します。

上記のブログでは0.1秒間隔の場合56.6mAでした。

推定稼働時間 = 推定消費電流(mA) / バッテリー容量(80mhA) × 安全係数(0.8)

上記に当てはめると56.6 / 80 * 0.8で0.566時間(約34分)みたいに計算できます。最後の安全係数はバッテリーからのDCDCロスなどです。

実測だと37分ぐらい動いていましたので、そこから安全係数を逆算しています。ただしバッテリーがヘタると、もっと悪化しますので0.7ぐらいで計算しておいたほうが安全かもしれません。

ただ無線系はデータが少ないのと、結構測定データによって誤差があるので、実測してみるしかないかもしれません。

スリープ系無線利用時の省電力方針

ESP32がディープスリープで消費電流がなくなったとしても、AXP192が動き続けていますので、長時間の稼働は難しいです。

Wi-Fiアクセスポイントに接続する場合には、CPU周波数を240MHzで高速に通信を終わらせて、すばやく無線をOFFにしたほうが全体の消費電流が下がるパターンもあるようです。

上記の検証では半日しか動かすことができませんでした。AXP192の利用していない機能をOFFにすることでおそらく24時間前後の動作をすることは可能だと思いますが、AXP192自体で1.4mA程度消費電流がありそうなので、そのへんが限界だと思います。

さらなる長時間稼働のために

外部バッテリーを使うのが一番だと思います。

何個か外部バッテリー系HATが販売されていますがServo HATなどは、バッテリーを拡張するものではなく、外部接続したServoへの電源供給を目的としてものなので、外部バッテリーとしては利用できません。

バッテリー系のHATを利用してください。この記事にために先月末にバッテリー系HATを2種類注文しましたが、まだ到着していませんのでまだ私も使ったことがありません。

内蔵バッテリーが80mhAに対して、1000mhA以上のバッテリーを利用できると思うので、10倍以上の稼働時間になると思われます。

まとめ

マルチメーターは秒単位での消費電流変化しか測定できません。無線系はもっと短い時間で消費電流が変化しているので、あまり正しい数値が測定できていません。

シャント抵抗とオシロスコープなどを利用すれば、もう少し短い時間軸で測定が可能ですので、今後実験をしたいと思っています。

不明点や、調べてほしい点があったらブロクへのコメントかTwitterへ連絡お願いします。

コメント

  1. 虫まさみ より:

    重要な情報をありがとうございます。
    朝、エアコンを自動起動しようと思い、情報を探していたところこのサイトを見つけました。
    Raspberry pi 4 Node.js
    BLE 温度計 3台(switchbot x2,xiaomi x1)
    M5stickc + IR Unit + Mobile Battery 2000mAH(公証)
    でなんとか、自動起動にこぎつけました。省電力対策情報をこのサイトから取り入れ実験中です。3日あるいは4日に一回の充電で運用できるように調整してゆきたいと思います。
    現在、初回データ取得中です。進展がありましたら、バッテリー電圧の時間経過でも送付したいと思います。
    今後共、重要な情報提供お願いします。

    • たなかまさゆき より:

      長期運用の経験がないので、結果楽しみにしています!

      • 虫まさみ より:

        第一回目のテストが終わりそうです。
        3/26 23:28 にスタート3/29 20:00 で電池電圧 3.28vまで低下して、そろそろWiFi 接続ができなくなりそうです。メールアドレスを連絡いただければ電池電圧時間経過のPNG File を送付できます。
        もう少し持たせようと思っているので、液晶の明るさを7でトライ予定です。deepsleepから復帰したときに液晶が一旦明るくなるのが、気になるところです。
        現在のシステムはRaspberry piとM5stickcが通信(WiFi UDP)しながらIRでエアコンを制御しています。M5stickcはdeepsleepでほとんどお休み状態でWakeUpしたときにRaspberry piから次の指示(IR signal,deepsleep時間)をもらうようにしています。Raspberry pi はBLE温度計から温度情報を入手しながら、次の指示を考えています。
        夏のエアコン制御で本格的に使えるようにしたいと思っています。

        • たなかまさゆき より:

          おー、ありがとうございます
          できれば、ある程度実験が進んだらブログやQiitaなどで公開いただけると助かります
          本当はユーザー会とかで発表してほしいですが、コロナの影響でユーザー会とかはなかなか開催されなそう、、、

          省電力だけ考えると、ESP-NOWつかって受信側もESP32にしたほうが送信側のバッテリーライフは伸びそうですが、そうすると機材も増えてしまいます、、、

          画面のないATOMもそろそろ日本で発売されるはずなので、もうちょっと省電力系は調査してみたいと思います!

          • 虫まさみ より:

            液晶の明るさ7でのテストが終わりました。少し伸びて、3日と6時間でした。
            今回のテストは
            ・モバイルバッテリー:フル充電
            ・m5stickc: 空
            の状態でスタートしていますので、両方フルの状態では4日間程度は可動するのではないでしょうか。
             ボタンでのDeepsleepからの復帰、復帰条件の検出ができることがわかりましたので、
            完全OFFモード、外出モードなど組み込んで見たいと思います。
             今年、2月からのArduino挑戦で苦戦しています。VS Codeに感謝です。

          • たなかまさゆき より:

            結構伸びましたね!
            本体だけだとどうしても長期ってのは難しいので、バッテリーとの組み合わせが必要そうですね
            私ももう少し余裕がでたら長時間動作の実験してみたいと思います!

    • たなかまさゆき より:

      着実に進化していますね!
      私はまだATOMが届いていません。。。
      この状況ですから仕方ないですね
      もう購入してしまったので、国内販売は我慢しています、、、

  2. 虫まさみ より:

    朝の自動運転はなかなか便利だったので、しばらく連続して使って見る予定です。
    外出、帰宅機能は入れてみました。状態がよくわからなくなってしまうので、ビットマップで状態表示を入れてみたいと思います。
    夏の自動運転に向けて、フルシーズンバージョンを検討中です。

    • たなかまさゆき より:

      いいですねー
      もう少ししたらATOMも販売されるので、そっちのほうが長期運用は有利かもしれません
      ただし赤外線が内蔵していないのがネックですね

      • 虫まさみ より:

        常時電源が確保できるところに設置できるように、IR REMOTEのHigh Power化を目指すこととしました。ハードの自作まで足を突っ込んでしまうこととなりました。

        • たなかまさゆき より:

          おー、すごい!
          ATOM到着したら少し検証しようとしてますが、まだ海外から届かない、、、

          • 虫まさみ より:

            心待ちにしております。
            ATOMにはAxp192が搭載されて、Battery端子が出力されているかどうかが気になるところです。充電制御ができそうなので、一味違ったことができそうです。

          • 虫まさみ より:

            IR REMOTEのハイパワー化を行いました。とりあえず、常時電源が確保できるところに設置できるようになりました。はじめてブレッドボードを使いました。
            余裕を持った素子を選定したので壊れることはないと思います。動作状況の詳細を確認したいところですが、ツールが無いのでしょうがないですね。。。目視で動作確認できるように、赤外線LEDとパラに赤色LEDを入れ薄暗く点灯するようにしています。
             どうせ、Raspberry pi とUSBで接続するのであれば、信号のやり取りもSerialでと考え調査を開始しました。JSONでデータのやり取りをしているので、プログラムの構造はそれほど変更する必要なないのではないかと思います。
             ATOMが入手できるようになったら、変更しても良さそうです。

        • たなかまさゆき より:

          ATOMはバッテリー内蔵していないので、電源管理がないみたいですね
          その分5V端子に外から電源いれれば大丈夫みたいです
          3.3Vでも動くみたいですが、ちょっと実験しないと危なそうです

  3. あおいさや より:

    5V出力のDCDCの制御方法を探していて見つけました。
    貴重な調査結果とコードの公開をありがとうございます。

    EXTENの制御はアドレス0x10だと思うのですが、確かに中国語のデータシートには0x12にも記載がありますね。英語版のデータシートには記載がないので、0x10が本命だとは思いますが。
    0x12を叩いて何かわかったことがありますでしょうか?

    • たなかまさゆき より:

      英語版はみてないのでわからないですが、どっちでも大丈夫だったような、、、
      後日見直します

    • たなかまさゆき より:

      両方試したところ、同じ機能だった気がします
      どっち叩いても大丈夫かな?

      EXTEN_10_OFF
      EXTEN_10_ON

      だと0x10に投げていますね

  4. あおいさや より:

    わざわざ調べていただいてありがとうございます。同じ機能なんですね。
    自分で試せばお聞きするまでもなかったことにいま気がつきました。お手数おかけしました。

  5. RUNA より:

    推定稼働時間の計算について、
    >0.1秒間隔の場合56.6mAでした。
    >推定稼働時間 = 推定消費電流(mA) / バッテリー容量(80mhA) × 安全係数(0.8)
    上記に当てはめると56.6 / 80 * 0.8で0.63時間(35.7分)みたいに計算できます。
    が、理解できまんでした。
     56.6 / 80 * 0.8 = 0.56 なのですが、63時間になる経緯を 教えていただけませんでしようか

    • たなかまさゆき より:

      おっと、計算おかしいですね
      詳細覚えていませんが安全係数0.9で0.63675時間を本文だけもう少し安全係数とるかと0.8に変えたのかもしれません