年明けはじめてのSPRESENSEネタです。SPRESENSEはいろいろ機能が多いので、一通り試すだけでもなかなか終わりません。今回は低消費電力の切り札”DeepSleep”を試してみました。




せっかくなら実用的なものをと思い、GPSとの組み合わせてスケッチを書いてみました。クロックも32MHzにして低消費電力にしています。



#include <GNSS.h>
#include <LowPower.h>
#include <RTC.h>

static SpGnss Gnss;

void setup()
{
int resut;

Serial.begin(115200);
RTC.begin();

LowPower.begin();
LowPower.clockMode(CLOCK_MODE_32MHz);
bootcause_e bc = LowPower.bootCause(); /* get boot cause */

sleep(3);
Gnss.begin();
Gnss.select(GPS);
Gnss.select(GLONASS);
Gnss.select(QZ_L1CA);
Gnss.select(QZ_L1S);

if ((bc == POR_SUPPLY) || (bc == POR_NORMAL)) {
Serial.println("Power on reset");
Gnss.start(COLD_START);
} else {
Serial.println("Wakeup from deep sleep");
RtcTime now = RTC.getTime();
// Print the current clock
printf("%04d/%02d/%02d %02d:%02d:%02d\n",
now.year(), now.month(), now.day(),
now.hour(), now.minute(), now.second());

SpGnssTime gnss_time;
gnss_time.year = now.year();
gnss_time.month = now.month();
gnss_time.day = now.day();
gnss_time.hour = now.hour();
gnss_time.minute = now.minute();
gnss_time.sec = now.second();
gnss_time.usec = now.nsec() / 1000;
Gnss.setTime(&gnss_time);
Gnss.start(HOT_START);
}

}

void loop()
{
if (!Gnss.waitUpdate(-1)) return;

SpNavData NavData;
Gnss.getNavData(&NavData);

/* print satellites count */
Serial.print("numSat: " + String(NavData.numSatellites) + " ");

/* update RTC time */
RtcTime gps_time(NavData.time.year
, NavData.time.month
, NavData.time.day
, NavData.time.hour
, NavData.time.minute
, NavData.time.sec
, NavData.time.usec * 1000 /* RtcTime requires nsec */);

Serial.print(String(gps_time.year()) + "/"
+ String(gps_time.month()) + "/"
+ String(gps_time.day()) + " "
+ String(gps_time.hour()) + ":"
+ String(gps_time.minute()) + ":"
+ String(gps_time.second()) + " ");

/* When time is different more than 1 sec, update RTC time */
if (abs(RTC.getTime() - gps_time) >= 1) {
RTC.setTime(gps_time);
Serial.print(" * Updated RTC time * ");
}

/* print position data */
if (NavData.posFixMode == FixInvalid && NavData.posDataExist == 0) {
Serial.print("No Position");
} else {
static int g_loop = 0;
Serial.print("Lat=" + String(NavData.latitude, 6));
Serial.print(", Lon=" + String(NavData.longitude, 6));

unsigned long passed_time;
Serial.println("");
passed_time = millis();
Serial.println("POSITION FIXED TIME: " + String(passed_time));

if (g_loop > 10) {
// Go to deep sleep during about 60 seconds
Gnss.saveEphemeris();
Gnss.stop();
Gnss.end();
passed_time = millis();
Serial.println("Go to deep sleep... " + String(passed_time));
LowPower.deepSleep(60);
}
++g_loop;
}
Serial.println("");
}




このスケッチの流れは次のようになっています。

setup 関数内
(1)LowPower.bootCause() で起動要因を取得
(2)電源投入直後の場合は、Gnss エンジンを COLD_START
(3)DeepSleepからの復帰の場合は、RTCから時間を取得、設定したら、
   Gnss エンジンを HOT_STARTします。
   Gnss エンジンは、保存されている衛星情報(Ephemeris)を読み込み、
   現在時刻を参照して、衛星位置を推測して素早く衛星を補足します。(恐らく)

loop 関数内
(1)位置情報を取得します
(2)RTCの時刻と衛星の時刻が1秒以上違いがあったら、RTC時刻を更新します
(3)10回(10秒間)位置情報を取得したら、
   衛星情報(Ephemeris)を保存して、Gnssエンジンを停止します。
   そのあと、60秒間の DeepSleep をセットします。


動作させた際のログは次のようになりました。


Power on reset
numSat: 0 1980/1/6 0:0:1 * Updated RTC time * No Position
numSat: 4 1980/1/6 0:0:2 No Position
... snip ...
numSat: 5 2020/1/26 9:58:1 * Updated RTC time * Lat=3x.xxxxxx, Lon=13x.xxxxxx
POSITION FIXED TIME: 36045

numSat: 5 2020/1/26 9:58:2 Lat=3x.xxxxxx, Lon=13x.xxxxxx
POSITION FIXED TIME: 36059

numSat: 5 2020/1/26 9:58:3 Lat=3x.xxxxxx, Lon=13x.xxxxxx

... snip ...

numSat: 5 2020/1/26 9:58:12 Lat=3x.xxxxxx, Lon=13x.xxxxxx
POSITION FIXED TIME: 46058
Go to deep sleep... 46526
Wakeup from deep sleep
2020/01/26 09:59:18
numSat: 5 2020/1/26 9:59:21 Lat=3x.xxxxxx, Lon=13x.xxxxxx
POSITION FIXED TIME: 8062

numSat: 5 2020/1/26 9:59:22 Lat=3x.xxxxxx, Lon=13x.xxxxxx
POSITION FIXED TIME: 9062

numSat: 5 2020/1/26 9:59:23 Lat=3x.xxxxxx, Lon=13x.xxxxxx
POSITION FIXED TIME: 10062

... snip ...

numSat: 5 2020/1/26 9:59:32 Lat=3x.xxxxxx, Lon=13x.xxxxxx
POSITION FIXED TIME: 19439
Go to deep sleep... 19958
Wakeup from deep sleep
2020/01/26 10:00:39
numSat: 5 2020/1/26 10:0:42 Lat=3x.xxxxxx, Lon=13x.xxxxxx
POSITION FIXED TIME: 8063

numSat: 5 2020/1/26 10:0:43 Lat=3x.xxxxxx, Lon=13x.xxxxxx
POSITION FIXED TIME: 9063

... snip ...

numSat: 6 2020/1/26 10:0:53 Lat=3x.xxxxxx, Lon=13x.xxxxxx
POSITION FIXED TIME: 19063
Go to deep sleep... 19577
Wakeup from deep sleep
2020/01/26 10:02:00
numSat: 5 2020/1/26 10:2:3 Lat=3x.xxxxxx, Lon=13x.xxxxxx
POSITION FIXED TIME: 8062



測定するまでの時間にばらつきはありますが、きちんとディープスリープが動いているようです。これで電力は大幅に削減できそうです。肝心のディープスリープの電力はスタックオーバーフローで次のような議論がありました。


Sony Spresense Deep Sleepでの電力
https://ja.stackoverflow.com/questions/55366/sony-spresense-deep-sleep%e3%81%a7%e3%81%ae%e9%9b%bb%e5%8a%9b


μAレベルまで落とせるようですが、工作必要ですね。さて、5000円をおじゃんにする覚悟で試してみるか。悩む…
(´-ω-`)


関連記事
SPRESENSE の Low Power ライブラリをバッテリー給電で試してみた!
https://makers-with-myson.blog.ss-blog.jp/2019-12-08

SPRESENSE の Low Power ライブラリをUSB給電で試してみた!
https://makers-with-myson.blog.ss-blog.jp/2019-12-01

SPRESENSE の RTC をGPS 時計に設定して時報アプリを作ってみた!
https://makers-with-myson.blog.ss-blog.jp/2019-11-24

SPRESENSE のNMEA 出力をNMEAモニターで確認してみた!
https://makers-with-myson.blog.ss-blog.jp/2019-11-17