全てのページ
GitBook提供
1 / 1

PAL_AMB

アクトの機能

  • 環境センサーパル AMPIENT SENSE PAL を用い、センサー値の取得を行います。

  • コイン電池で動作させるための、スリープ機能を利用します。

アクトの使い方

必要なTWELITE

アクトの解説

インクルード

setup()

ここでは、ボード上の4ビットDIP SWのうち3ビットを読み出して子機のIDとして設定しています。0の場合は、ID無しの子機(0xFE)とします。

LEDの設定を行います。ここでは 10ms おきに ON/OFF の点滅の設定をします(スリープを行い起床時間が短いアプリケーションでは、起床中は点灯するという設定とほぼ同じ意味合いになります)。

このアクトではもっぱら無線パケットを送信しますので、TWENET の設定では動作中に受信回路をオープンにする指定(TWENET::rx_when_idle())は含めません。

ボード上のセンサーはI2Cバスを用いますので、バスを利用開始しておきます。

loop()

このアクトでは、1ms周期で呼び出させる(アプリケーションループの呼び出しタイミングは不定期な遅延が発生します)TickTimerのイベントを起点としてセンサーの読み出しや送信要求を行います。TickTimer.available()がtrueになったときに処理を行います。これによりおよそ1msごとにif節内の処理を行います。

	if (TickTimer.available()) {

ボード上のセンサーは .sns_LTR308ALS または .sns_SHTC3 という名前でアクセスでき、このオブジェクトに操作を行います。センサーの完了待ちを行います。まだセンサーの取得が終わっていない場合(.available()がfalse)はセンサーに対して時間経過のイベント(.process_ev(E_EVENT_TICK_TIMER))を送付します。

		if (!brd.sns_LTR308ALS.available()) {
			brd.sns_LTR308ALS.process_ev(E_EVENT_TICK_TIMER);
		}

		if (!brd.sns_SHTC3.available()) {
			brd.sns_SHTC3.process_ev(E_EVENT_TICK_TIMER);
		}

上記2つのセンサーがavailableになった時点で、無線送信などの処理を行います。

		if (brd.sns_LTR308ALS.available() 
						&& brd.sns_SHTC3.available() && !b_transmit) {

送信手続きについては他のアクトのサンプルと同様です。ここでは、再送1回、再送遅延を最小にする設定になっています。

	pkt << tx_addr(0x00)  // 親機0x00宛
		<< tx_retry(0x1)    // リトライ1回
		<< tx_packet_delay(0, 0, 2); // 遅延は最小限

パケットにセンサーデータを書き込み際に、センサーデータを取得しています。センサーの値を取得するメソッドはセンサーごとに違います。

	// prepare packet payload
	pack_bytes(pkt.get_payload() 
		, make_pair(FOURCHARS, 4)  
		, uint32_t(brd.sns_LTR308ALS.get_luminance()) // luminance
		, uint16_t(brd.sns_SHTC3.get_temp_cent())
		, uint16_t(brd.sns_SHTC3.get_humid_per_dmil())
	);

照度センサーは.get_luminance() : uint32_tで得られます。

温湿度センサーは以下のように取得できます。

  • .get_temp_cent() : int16_t : 1℃を100とした温度 (25.6 ℃なら 2560)

  • .get_temp() : float : float値 (25.6 ℃なら 25.6)

  • .get_humid_dmil() : int16_t : 1%を100とした湿度 (56.8%なら 5680)

  • .get_temp() : float : float値 (56.8%なら 56.8)

得られた値のうち温度値は int16_t ですが、送信パケットのデータ構造は符号なしで格納するため、uint16_tにキャストしています。

送信が成功すれば b_tansmit を trueにし、u8txidに送信パケットの識別IDを格納し、完了待ちします。送信が失敗すれば sleepNow() によりスリープします。

	// do transmit
	MWX_APIRET ret = pkt.transmit();

	if (ret) {
		u8txid = ret.get_value() & 0xFF;
		b_transmit = true;
	}
	else {
		// fail to request
		sleepNow();
	}

loop() 中 b_transmit が true になっている場合は、送信完了チェックを行い、完了すれば sleepNow() によりスリープします。

// wait to complete transmission.
if (b_transmit) {
    if (the_twelite.tx_status.is_complete(u8txid)) {        
        Serial << "..transmit complete." << mwx::crlf << mwx::flush;

        // now sleeping
        sleepNow();
    }
}

送信完了に確認は the_twelite.tx_status.is_complete(u8txid) で行っています。u8txidは送信時に戻り値として戻されたID値です。

startSensorCapture()

ボード上のセンサーの取得を開始します。多くのセンサーは、取得を開始してから完了するまで数msから数十msの時間を必要とします。

void startSensorCapture() {
	auto&& brd = the_twelite.board.use<PAL_AMB>();

	// start sensor capture
	brd.sns_SHTC3.begin();
	brd.sns_LTR308ALS.begin();
	b_transmit = false;
}

5行目で、温湿度センサー SHTC3 のデータ取得を開始します。

6行目で、照度センサー LTR308ALS のデータ取得を開始します。

7行目は、送信完了フラグをクリアします。

sleepNow()

スリープに入る手続きをまとめています。

void sleepNow() {
	uint32_t u32ct = 1750 + random(0,500);
	Serial << "..sleeping " << int(u32ct) << "ms." << mwx::crlf << mwx::flush;

	the_twelite.sleep(u32ct);
}

ここでは、起床までの時間を乱数により 1750ms から 2250ms の間に設定しています。これにより他の同じような周期で送信するデバイスのパケットとの連続的な衝突を避けます。

周期が完全に一致すると、互いのパケットで衝突が起き通信が困難になります。通常は時間の経過とともにタイマー周期が互いにずれるため、しばらくすると通信が回復し、また時間がたつと衝突が起きるという繰り返しになります。

3行目、この例ではシリアルポートからの出力を待ってスリープに入ります。通常は消費エネルギーを最小化したいため、スリープ前のシリアルポートの出力は最小限(または無し)にします。

スリープ前にflushを行うと、出力が不安定になる場合があります。

スリープに入るには the_twelite.sleep() を呼びます。この呼び出しの中で、ボード上のハードウェアのスリープ前の手続きなどが行われます。たとえばLEDは消灯します。

パラメータとしてスリープ時間をmsで指定しています。

TWELITE PAL では、必ず60秒以内に一度起床し、ウォッチドッグタイマーをリセットしなければなりません。スリープ時間は60000を超えないように指定してください。

wakeup()

スリープから復帰し起床すると wakeup() が呼び出されます。そのあとloop() が都度呼び出されます。wakeup()の前に、UARTなどの各ペリフェラルやボード上のデバイスのウェイクアップ処理が行われます。例えばLEDの点灯制御を再始動します。

void wakeup() {
	Serial	<< mwx::crlf
			<< "--- PAL_AMB:" << FOURCHARS << " wake up ---"
			<< mwx::crlf
			<< "..start sensor capture again."
			<< mwx::crlf;
	startSensorCapture();
}

ここではセンサーのデータ取得を開始しています。

応用編

より安全な実装

より安全な実装として、このアクトでは以下の例外処理を強化します。

  • センサー取得部分でavailableにならなかった場合の例外処理が記述されてません。

  • 送信完了待ちで送信完了が通知されない場合の例外処理が記述されていません。

上記いずれもタイムアウト処理を行います。現在の時間は millis() により取得できます。

uint32_t t_start;

  // 時間待ちの処理を開始した時点でタイムスタンプを保存
  t_start = millis();

...

  // loop() でタイムアウトのチェック
  if (millis() - t_start > 100) {
    sleepNow();
  }

消費エネルギーの削減

アクト PAL_AMB-UseNap は、センサーのデータ取得待ちをスリープで行い、より低消費エネルギーで動作できます。