2014年9月24日水曜日

自転車ビーコンの回路図

自転車ビーコンの回路図を、BSch3Vで描いてみました。

自転車ビーコン送信機
受信機はDIP版とSMD版があり、ピン番号が違います。現在使用しているのはSMD版です。

自転車ビーコン受信機(SMD版)

自転車ビーコン受信機(DIP版)
実物では、
  • ファームウェア書き換え用のピンヘッダまたはピンソケットを接続
  • モード設定ビット端子(M1,M2,M3)をピンヘッダ/ソケット化
 が追加されています。これらは動作時には不要なため、回路図では省略しています。モード設定ビット端子は、使用時はファーム書き換え用ピンソケットのGNDに接続し、書き換えおよび設定変更時には抜いています。

2014年9月23日火曜日

自転車ビーコンの使い勝手向上計画

 リモコン送信機のボタンが小さいため、受信機が反応するまで押し続けるのは、意外と不便な仕様です。ボタンの押しにくさのせいで受信間隔をあまり長くできず、電池持ちも思うように伸ばせませんでした。今週は、ここに改造のメスを入れてみました。

 当初の設計では、リモコン送信機を親機とし、タクトスイッチで電源をON/OFFしていました。押した間だけ電源が入り、動作中は連続送信を行います。
 これを、「チョイ押し」だけで手を離しても数秒間連続して送信を行うように改造しました。
  • 送信機をmode7(子機間欠10秒モード)とし、送信間隔を0秒としました。これで、タイマーによるWakeUpが無効となり、ボタンによる割り込みでのみWakeUpします。
  • 送信機がWakeUpしたら、mode4の送信間隔+100msの間、スリープせずにデータを32回/秒のペースで連続送信するようにしました。
  • 受信機側では、vReceiveIoData()にある親機子機の判定を無効化し、受信したデータを親機/子機の区別無く処理するようにしました。
  送信機のチョイ押しで自動的に送信を続けるので、子機の通信間隔が長くてもボタンを押すのが苦にならなくなりました。この改造に合わせて、
  • 2秒毎だった通信間隔を4秒に延長
  • ADCを行わない受信待ちだけのWakeUp時間を24msに延長
  • 連続送信の間隔を毎秒64回から32回に戻す
  • mode7のスリープ時にRAMを保持しない
という調整も行いました。これで、子機の電池は半年持つ見込みです。
 受信間隔が長いと親機の連続送信時間が延びて、親機の電池持ちは短くなりますが、スリープ時にRAMを保持しないことで待機時の消費電流を減らしました。1日1回の使用で、送信機の電池は7年以上持つ見込みです。

追記:
 この時は子機間で通信するために親子判定を無効化しましたが、子機からの宛先論理IDを親機(0x00)ではなく子機宛とし、この動作を想定するように受信時のID判定を改造するというのがToCoNet的にはまっとうな方法のようです。
  http://tocos-wireless.com/jp/products/TWE-ZERO/App_Twelite/overview.html

2014年9月22日月曜日

TWE-Lite子機間欠モードの受信動作で使えるチャンネル(2)

 子機間欠モードで受信動作をする場合、使えるチャンネルは18だけでしたが、正しくは、「ビルドの際にデフォルト値として設定したチャンネルだけ」でした。デフォルトのチャンネルを18以外にすると、そのチャンネルだけが使えるようになります。

2014年9月20日土曜日

自転車ビーコンの電池持ち問題に対する解決案

 自転車ビーコンの電池持ちが思ったより良くないので、改善を図ることにしました。

 電池が持たない最大の要因は、一回あたりのWakeUp時間が52msと長いせいだと考えられます。その大半が、IO状態の読み取りと送信待ちである事もわかりました。IO状態の読み取りは、電池残量を知る必要があるのでなくす訳には行かないのですが、頻度はある程度減らしてもいいはずです。

 IO状態の読み取りを60秒毎に1回のペースまで落とし、2秒に1回のWakeUp時間を減らしたところ、計測できる下限の4msになりました。これは、起きた直後にスリープするような感じです。しかし、ここまで短くしてしまうと、親機からのパケットを取りこぼしてばかりで、肝心のビーコンとしての動作が開始できなくなりました。
 タイミングのイメージとしては、 この図のようになります。青が子機のWakeUp時間、ピンクが親機のパケット送信時間を表しています。
  WakeUp部分を切り出しすと、下の図になります。1/32秒間隔で再送1回を伴う送信を行う場合、4msのWakeUp時間では親機のパケットの隙間に埋もれてしまい、すれ違いがちになります。
    
 WakeUp時間があまりに短いと、受信処理に支障が出ることが分かったので、スリープ前にウェイト入れてWakeUp時間を20msに延長してみました。
  かなりマシになりましたが、まだ時々取りこぼします。タイミングによっては、WakeUpが親機のパケットの隙間を縫ってしまうようです。
 ウエイトを長くしてWakeUp時間をたっぷり確保すれば確実に受信できますが、それでは電池持ちが改善されません。
 電池持ちのために受信間隔を長くするとWakeUpを長くしても電池は持ちますが、応答が悪くなってしまいます。 また、たまに取りこぼしたときのペナルティが大きくなってしまう問題もあります。

 この問題を解決するために、子機のWakeUp時間を20msにしたまま、親機のパケット送信ペースを毎秒64回に倍増することにしました。
  今度は、子機のWakeUp時間の間に、親機のパケットを確実に受信できるようになりました。
 パケット密度が高すぎて輻輳がちょっと心配になりますが、親機の電源は一日に2-3秒しかONにしませんので、この方法で行く事にします。

2014年9月18日木曜日

自転車ビーコンの電池持ち問題

 今日から自転車ビーコンの本番運用を開始しました。が、帰宅時に鳴らしたところ、早くも子機の電池警告サインが発動してしまいました。試作中に使用していた電池をそのまま使っているので、試運転で減ってはいたと思いますが、予想を上回る早さです。

 電池消費の要因は間欠受信のWakeUp時間が長いせいではと思い、vProcessEvCoreSlp()にデバッグログを追加して、状態遷移の間隔を測ってみました。すると、時刻の起点をWakeUpとした場合、
  • WakeUp 0ms
  • IO状態の確定 32ms
  • 送信完了,Sleep 48ms
  • 次のWakeUp 52ms
でした。時刻の刻みは4msです。1サイクルに52msもかかっています。

 動作中の消費電流は、Sleep時は2μA、WakeUp中は18.7mA、メロディ再生中は約21mAでした。Sleep時の電流は無視して、動作中をざっくり20mAとすると、2秒間隔の間欠モードで一日に消費する電流容量は、
(86400/2) * 0.052 * 0.02 = 44.9 [mA sec]
です。これに、1日あたり50秒のメロディ鳴動を追加すると、
44.9 + 50 * 0.021 = 46.0 [mA sec]
が、一日あたりの総消費電流容量になります。
 電源のニッケル水素電池の容量は750mAhです。満充電から1.2Vの電池警告までに容量の8割まで利用できるとすると、利用できる日数は、
0.8 * 0.75 * 3600 / 46 = 47 [日]
で、電池寿命は約1ヵ月半と予想されます。自分としては、ちょっと短いなと思います。

 子機は受信専用として使っていて、送信したデータは使っていないのですが、WakeUp中の動作時間のうち大半を、IO状態の読み取りと、読み取ったデータの送信が占めています。これはもったいない。ざっくり無効化したいところですが、IO状態の読み取りは電池残量を知るために必要なので、完全に消すと残量チェックができなくなります。ただ、WakeUpの度に毎回知る必要も無いので、もっと長いインターバルを置いて、例えば32回のWakeUpに対して1回計測するという動作にすれば、電池持ちは大きく改善できると思います。

2014年9月17日水曜日

TWE-Lite子機間欠モードの受信動作で使えるチャンネルは18だけ

 先日のエントリーで、TWE-Liteの子機間欠モードで受信を有効にしても、チャンネルによって機能しない場合があって大いに時間をロスした事を書きました。自転車ビーコンの製作が済んだので、改めて、11から26までの16個のチャンネルのうち、どれが使えるのかを調べてみました。その結果、18以外は全滅でした。親機から子機への通信が、連続モードでは動くのに、子機間欠モードにすると全く伝わらなくなります。子機から親機への送信結果は刻々と親機に表示されていたので、親機と子機でチャンネルが違っていたという落ちはありません。
 子機間欠モードで受信動作をさせる場合、使えるチャンネルは18だけです。したがって、チャンネルの住み分けでグループ化の区別をすることはできません。混信を防ぐには、アプリケーションIDの使い分けに頼ることになります。

2014年9月15日月曜日

メロディーと音で置き場所を知らせる自転車ビーコン完成

 この三連休で完成しました。左が子機、右が親機(コマンダーリモコン)です。


 LEDと圧電スピーカーを装備した子機は、100円ショップCanDoの自転車用LEDリアライトに、TWE-Lite(SMDタイプ)のハテナアンテナ型を格納しています。圧電スピーカーはサイズと音量の都合でケースの外に接着しています。
 親機のコマンダーリモコンは、MINTIA BREEZEのケースに、TEW-Lite(DIPタイプ)のPCBアンテナ型を格納しています。開閉できる蓋の中にタクトスイッチを仕込んで、押している間だけ電源が入り、毎秒32回の連続送信を行います。連続送信する親機はCR2032では賄えない電流を消費するため、電気二重層キャパシタを追加しています。
子機の中身

 TWE-Liteには、「超簡単!TWE標準アプリ」v1.7にToCoNet SDKに入っていたApp_MelodyのMML再生機能を流用し、さらに標準アプリでは無効化されていた子機間欠モードの受信動作を有効にしています。

  アンテナの設置条件は良くありませんが、メロディが聞き取れなくなる数十m先からでも反応しました。

 ソースコードは、githubで公開しています。

2014年9月14日日曜日

メロディーと光で置き場所を知らせる自転車ビーコン製作中

回路とソフトの試作ができました。
昨日は、使用するチャンネルを変えると、親子のチャンネルが揃っていても応答しないという落とし穴で一日無駄にしましたが、今日は快調です。自機または対抗機(親機)の電池残量が少なくなったときに、LEDの点滅周期を速くして警告する機能も付けました。



TWE--Lite子機間欠モードで受信が行えるチャンネル

 TWE-Liteのチャンネルをデフォルトの18から16に変えたら、子機間欠モードの受信動作が機能しなくなった。すべてのチャンネルを調べたわけではないが、どうも、使用するチャンネルによって、間欠モードの受信動作が動いたり動かなかったりするらしい。これに気がつくまで、ほぼ1日かかった。今のところ、16,18,19と3種類試してみて、成功したのは18だけ。

TWE-Liteの子機間欠モードで受信動作した場合の消費電流

 子機間欠モードの受信動作は、sToCoNet_AppContext.bRxOnIdle を有効にするまで成功しなかった。このフラグの説明には、
  • 無線回路アイドル時も受信回路を動作させます。
  • 受信時は常に受信電流を消費します。
と書かれている。これだけ読むと、スリープさせても受信回路が起きていて電流を消費しまくるように受け取れる。受信動作中のTWE-Liteの消費電流は約17mAなので、こんなんでは間欠モードの受信動作は使えないと思えるが、やってみたら、実はそうではなかった。
 テスターで図ったところ、bRxOnIdleをTRUEに変えても、スリープ中に大きな電流を消費することは無かった。ブレッドボード上に回路を組んだ状態での実測値は1.9μAと、とても小さかった。どうやら、bRxOnIdleを有効にしても常時動作をするわけではなく、結局、スリープが解除されている間しか受信は行わないようだ。これは、スリープ中に親機からパケットを送っても反応しない事実とも矛盾しない。

2014年9月10日水曜日

子機間欠モードで待ち受ける自転車ビーコン

 TOCOS TWE-Liteで動作する、自転車ビーコンアプリケーションのソースコードをgithubに置きました。親機/子機のどちらでも機能します。
    https://github.com/true-nature/App_BicycleFinder

 アピールポイントは、ズバリ「子機間欠モードでの受信動作」です。検索しても実装例が見つけられなかったので、TWE-Liteの応用例としては珍しいのでないかと思います。
 心配される電池持ちは、自転車に取り付ける実物ができてから計測します。

2014年9月9日火曜日

TWE-Liteで子機を間欠モードにした場合の親機側の設定

 子機間欠モードで受信をする場合は、親機側の動作も変更しないと実用にならない。連続動作モードで連続なのは受信の方で、送信動作はスイッチやタイマーなどのイベントを契機に発信する間欠的動作だからだ。スイッチを押すなどの操作した場合、または、約1秒周期でIO状態が送信されるが、これでは、子機の間欠受信に滅多にミートしないので、送信間隔を短くする必要がある。
 現行のApp_Tweiteであれば、オプションビットの設定で毎秒32回の連続送信が設定できる。ところが、何故かApp_Melodyにはオプションビットの機能が無い。しょうがないので、親機にApp_Tweliteを、子機には改造したApp_Melodyを書き込んで、親機のApplication IDを子機と揃えることで対応した。

TWE-Liteで子機間欠受信を有効にする方法

最初は無理かと思ったけど、だんだんわかってきた気がする。
「超簡単!TWE標準アプリ」を子機間欠モードで受信に対応させるには、若干のソース変更が必要。

無線回路アイドル時に受信回路を有効化する


 cbAppColdStart()で子機間欠モードの場合に
sToCoNet_AppContext.bRxOnIdle = FALSE;
としている部分を、
sToCoNet_AppContext.bRxOnIdle = TRUE;
に変える。

 SDKマニュアル中のbRxOnIdle の説明には「受信時は常に受信電流を消費します。」という恐ろしいことが書いてあるが、テスターで測った感じだと、間欠動作の場合はbRxOnIdle =TRUE にしてもスリープ時に17mAも電流を消費するようなことは無い。デジタルテスターの20mAレンジでは、スリープ時の電流消費は0mAとしか表示されず、連続動作に比べたら誤差の範囲。スリープ解除のタイミングだけ、連続動作並みに消費電流が増える。

受信イベントのコールバック関数で受信処理をスキップさせない

cbToCoNet_vRxEvent()に、子機間欠モードの受信処理を抑制するif文が存在する。これをコメントアウトする。
例えば、1秒間欠モードの受信を有効にするなら、 こんな感じ。
--- a/Master/Source/Master.c
+++ b/Master/Source/Master.c
@@ -989,7 +989,9 @@ void cbToCoNet_vRxEvent(tsRxDataApp *psRx) {
             psRx->u32SrcAddr, psRx->u32DstAddr);

     if (IS_APPCONF_ROLE_SILENT_MODE()
+#ifndef USE_RX_ON_SLP_1SEC
             || sAppData.u8Mode == E_IO_MODE_CHILD_SLP_1SEC
+#endif
             || sAppData.u8Mode == E_IO_MODE_CHILD_SLP_10SEC) {
         // SILENT, 1秒スリープ, 10秒スリープでは受信処理はしない。
         return;

 手元の改造ソースでは、vProcessEvCoreSlp()を変更して、状態遷移を数TICK遅らせてスリープまでの時間稼ぎをしているけど、これが必須か否かは未確認。まあ、受信したからには何か処理をするだろうから、必須でなくともイベント追加したりすると思う。

2014年9月8日月曜日

TWE-Liteの子機間欠モードでは受信できない?

駅前駐輪場で、自転車の置き場所をよく忘れる。
忘れても大丈夫なように、携帯のToDoメモに置き場所をメモるようにしているのだが、急いでいるとメモるのを忘れてしまう。先週も、メモを忘れた上に置き場所を憶えてなくて、5分くらい駐輪場をさまよった。

で、ふと思った。
これってもしかして、TWE-Lite使ったら、解決するんじゃね?

早速、家にあったTWE-Liteで試作を開始したのだが、どうもだめっぽい。
自転車に装着する予定の子機は、大半の時間は用無しなので、電池節約のため間欠モードでなくてはならない。さもないと、数日で電池がなくなってしまう。
 東京コスモス電機の説明では、
間欠1秒モードは休止状態(スリープモード)になり、1秒毎に送受信を行うモードです。休止状態では送受信は行わず内蔵タイマーだけを動作させ節電を行います。
休止中は親機からの信号を受けることができません。
 と書いてあって、休止が解除されたタイミングでは受信できそうに書いてある。ところが、超簡単!TWE標準アプリで子機を間欠1秒モードにしてみると、親機の操作にまったく反応しない。
 ソースを見てみると、間欠モードでは受信処理を抑止している事がわかった。受信処理のコールバック関数 cbToCoNet_vRxEvent() では、間欠モードでは素通りで戻るようになっている。
void cbToCoNet_vRxEvent(tsRxDataApp *psRx) {
    //uint8 *p = pRx->auData;

    DBGOUT(3, "Rx packet (cm:%02x, fr:%08x, to:%08x)"LB, psRx->u8Cmd,
            psRx->u32SrcAddr, psRx->u32DstAddr);

    if (IS_APPCONF_ROLE_SILENT_MODE()
            || sAppData.u8Mode == E_IO_MODE_CHILD_SLP_1SEC
            || sAppData.u8Mode == E_IO_MODE_CHILD_SLP_10SEC) {
        // SILENT, 1秒スリープ, 10秒スリープでは受信処理はしない。
        return;
    }
 試しに、間欠1秒モードでも受信処理へ進むようにif分の条件を変えてみたが、結果は変わらず。そもそも、このコールバックさえ呼ばれていなかった。道は険しそうだ。
とりあえず、TWE-Lite標準アプリの子機間欠モードは送信専用で、受信処理ができないらしい。

可能か否かはまだ不明だが、目標としているのは、こんなアプリ。
  • 音と光で知らせる自転車発見器にする予定なので、ベースにはApp_Melodyを使う。
  • 子機は間欠モード。数秒おきに動作する。
  • タイマーで起動したら、数msの間だけ受信動作する。
  • 親機の信号を受信したらメロディーを鳴らしてLEDを光らせる。
  • メロディーが鳴っている間はスリープしない。
  • 親機は連続動作。ただし、必要な時だけ電源を入れる。