ここでは XBee series 2 (以下 XBee S2 あるいは単に XBee2) の標準的な構成、すなわち
XBee1(XBee series 1) に対する XBee2 の特徴は API モードで動作することにある。API モードとは通信がパケット方式になっていることにある。パケットには長さ情報と check sum が含まれているので、任意の byte 列が送信でき、さらに通信の信頼性が格段に向上する1。
日本語の参考書としては文献[1,2,3]がある。これらは僕が持っていて、よく知っているという理由で選ばれた。従って今となっては古い感が否めない。近頃 IoT が盛んに言われる様になっているので、書籍はもっと多くなっている。
このシステムを選んだのは、XBee が話題になった頃(2010年頃)の標準システムであり、僕のジャンクボックスの中に当時のいくつかの XBee モジュールが転がっていたからである。大学に教員として在籍していたときに、ゼミ生の一人が XBee を卒論のテーマにしたいと言ってきたが、僕は当時は XBee については何も知らなかったので、XBee を理解するために必要な投資(金と時間)をした訳である。Plan9 には XBee に関するツールが存在しなかったので、ついでに作ることにした。しかし作ったものが中途半端な状態になっていた。今回 それらを Lua で書き直し、公開することにした2。
書き直す前のコードは C 言語だったのであるが、C は可読性が乏しい上に、修正のたびにコンパイルが必要になり、柔軟性に欠ける。Lua は十分な可読性を持っていて、実行速度が高速で、また非常に柔軟である。書き直すだけの価値を持っている。
[1] 濱原、佐藤「超お手軽無線モジュールXBee」(CQ出版社)
注釈: これが一番詳しいが、特殊なハード環境を想定している。また重要な説明を欠いていることがある。
[2] Robert Faludi (小林、水原訳)「XBee で作るワイヤレスセンサーネットワーク」(O’REILLY)
注釈: ZigBee ネットワークを概念的に知るのに良い。
[3] 鄭立「ZigBee 開発ハンドブック」(リックテレコム, 2012)
注釈: XBee コマンドリファレンスが載っていない!
[4] Digi International: "Zigbee RF Modules User Guide"
https://www.digi.com/resources/documentation/digidocs/pdfs/90000976.pdf
これが一番基本的。
XBee に関する情報を集めていると、用語が多すぎて混乱する。
ネットで "XBee" を検索するとスズキの自動車(クロスビー)が出てくるが、これは関係ない。
区別しておきたいのは XBee と ZigBee である。ZigBee は近距離無線通信のプロトコルの名称であり、Digi International (https://www.digi.com) が提唱し発展させた。XBee は Digi の商品名称である。
次の略語もよく使われる。
abbrev. | full name | ref |
---|---|---|
WPAN | Wireless Personal Area Network | [5] |
LR-WPAN | low-rate wireless personal area network | [6] |
最近、Zigbee Alliance が名称を改めて Connectivity Standards Alliance となった[7]。
As of May 11, 2021, the Zigbee Alliance has been rebranded to Connectivity Standards Alliance[8].
Amazon Alexa など WPAN 機器の広がりを受けて、Alliance の範囲を広げたのだろう。また cpu パワーと掲載メモリーの増大のもとで IP ベースの新しい相互接続性が模索されている[9]:
Matter is a unifying, IP-based connectivity protocol built on proven technologies, helping you connect to and build reliable, secure IoT ecosystems, and keeping you focused on developing innovative products and accelerating paths to market.
CSA がこの問題への回答になれば良いのだが
Digi International がバッテリ駆動ネットワークに最適化された メッシュネットワークプロトコル「DigiMesh」を発表[10]。使いやすそうである:
DigiMeshでは、こうした親子関係のアーキテクチャはありません。すべてのデバイスは節電のためにスリープ状態を実行することができ、そしてすべてデバイスは、同時にルータとエンドデバイスになることができます。ならば、XBee2 で構成される mesh network は ZigMesh とでも言うべきか?
[5]: IEEE 802.15
https://en.wikipedia.org/wiki/IEEE_802.15
[6]: IEEE 802.15.4
https://en.wikipedia.org/wiki/IEEE_802.15.4
[7]: CSA
https://csa-iot.org
[8]: Connectivity Standards Alliance
https://en.wikipedia.org/wiki/Connectivity_Standards_Alliance
[9]: Matter
https://csa-iot.org/all-solutions/matter/
[10]: DigiMesh
https://japan.zdnet.com/release/10389538/
図1: XBee S2 | 図2: XBee Pins |
XBee S2 と pin 番号規則
これは初期のもの。現在は売られていないようだ。
手持ちの XBee には、どれも電圧を測定するための端子が4個備わっている。(以下 D0,D1,D2,D3 と言う)
Pin name | Physical pin # | Parameter |
---|---|---|
DIO0, AD0 | 20 | D0 |
DIO1, AD1 | 19 | D1 |
DIO2, AD2 | 18 | D2 |
DIO3, AD3 | 17 | D3 |
DIO6,RTS | 16 | D6 |
DIO5, AD5 | 15 | D5 |
VREF | 14 | |
ON,SLEEP | 13 | |
DIO7,CTS | 12 | D7 |
DIO4, AD4 | 11 | D4 |
VCC | 1 | |
VOUT | 2 | |
VIN/CONFIG | 3 | |
RESET | 5 | |
PWM0 | 6 | P0 |
PWM1 | 7 | P1 |
DI8 | 9 | D8 |
GND | 10 |
https://www.digi.com/resources/documentation/Digidocs/90001456-13/Default.htm#reference/r_xbee_s3b_io_pins.htm
VCC と GND は XBee の駆動電源の口である。標準的にはここに 3.3V を与えて駆動するのであるが、かなりの幅を許している。
シリーズ2の普通の(つまり PRO ではない) end device の場合には、Vcc の許容範囲は 2.1~3.6V と特に広い。XBee では end device が測定に使用されると想定されている。そして end device は電源に電池を使うことが想定されている。電池は時間が経つにつれて電圧が低下する。従って長期間に渡って測定が継続できるためには動作可能な電圧の幅が大きくなるように設計する必要がある。
そこで駆動電圧の違いが、電圧の測定に影響を与えるのではないかと心配になる。
文献[4]によれば、電圧の分解能は 10bit つまり1/1000である。これは精度の限界である。実際の精度は如何? この記事のテーマの一つである。
XBee の電圧は 0V から 1.2 V の範囲で測定できる。これより高い電圧の測定は、抵抗器を使って適当に分圧すればよい。分圧の状況はテスターで測定すればよいが、僕の手持ちの MOSTECH のテスターの精度は、マニュアルによれば、常温(18℃~28℃)、5V 程の直流電圧の測定で、
型名 | 精度 | 測定電圧 |
---|---|---|
MS8218 | 0.03% | DC 5V |
MS8268 | 0.7% | DC 4V |
ちなみに手持ちのバッテリーの電圧を測定してみると(同一のバッテリーに対して)
MS8218 2.8351V MS8268 2.822V
我が家のネットワーク環境は複雑である。以下の XBee2(XBee series 2) の実験に関係した部分を図3に示す。
図3: 我が家の XBee ネットワーク環境2
Coordinator はサーバと USB で接続されている。サーバーの役割は電源の供給と、コマンドを通じての XBee の制御である。
Router はノートPC(ASUS 904x1) と USB で接続されている。ノートPC の役割は電源の供給と、コマンドを通じての XBee のデータの読み取りである。ノートPC は必要に応じて起動すればよい。電源停止中でも、Router には USB ポートを通じて電源が供給されている。
実はサーバも長期に渡ってデータを XBee から採取している。従って何かちょっとした実験をしたい場合に、サーバーの邪魔にならないよう、ノートPCからアクセスすることにしている。
End Device は、Router にも Coordinator にも接続できる。Coordinator と End Device の実際のデータ転送の経路は電波状況に依存する。遮蔽物の存在は経路決定に強く影響するはずである。我が家の環境では、どの EndDevice も Router を通じて Cordinator と繋がっているのではないかと思われる。明確な言い方ができないのは、僕は確認する方法を知らないからである3。XBee のファームウェアが最適な経路でデータを転送してくれるので、かようなことを知らなくてもよいとするのが、ZigBee の設計者の立場なのであろう。我々が Internet を使うときに、通常はサーバーまでの経路を知る必要はない。それとよく似ている。しかし、世の中には、知らなくてもよいと言われると返って知りたくなる人間もいるのだ。
管理を容易にするために、この図の4個の XBee には C,D,E,G とラベルが貼られている。
http://ar.nyx.link/blog/EeePC.html
を見よhttps://illustration-free.net/
ATND
コマンドで確認できる。これによると End Device は Router を通じて Coordinator に接続している場合もあるが、直接 Coordinator と接続している場合もある。詳しくは http:index3.html
を見よ。
図3において、サーバーもノートPCも、Plan9 の下で動いている。ところが現状では Plan9 の下で動く XBee 用のソフトウェアは(僕のもの以外には)存在しない。僕のものは 10 年ほど前に書かれたもので、C で記述されていた。公表されることもなく、眠っていた状況である。今回は公表にあたって Lua で書き直した。なぜ Lua を? 次の2つの点から説明しておく。
(a) C ではなぜダメなのか?
(b) Python ではなぜダメなのか?
(a) の答: C は生産性が悪すぎる。コードの変更や追加にコンパイル作業が要求され、柔軟に対応できない。
(b) の答: Python は仕様が大き過ぎて、あの大きなシステムは持て余す。そのために Plan9 のような小さな開発グループでは Python の最新版は手に入らない。Lua は非常にこじんまりとした言語であり、それでいて強力である。Lua はミニマリズムの見本のようなもので、高速であり、Python の 10 倍ほど早い。移植性も極めて良い。Lua で足りる問題であれば Lua を使わない手はない。(問題によっては Python よりも使いやすい)
Plan9 用の Lua は僕のサーバー
http://p9.nyx.link/netlib/lua/
から手に入る。Plan9 に特有な機能を追加した 9lua も含まれている。
Plan9 で動く ZigBee 用のソフトウェアは
http://p9.nyx.link/netlib/xbee/
から手に入る。ここには MAN_XBEEAPI
, README
, pub.tgz
が置かれている。pub.tgz
を展開すると att.c
, api.c
, api.lua
などが現れる。pub.tgz
を展開したディレクトリを $xbee
としよう。今後、ここを XBee
関係の仕事場とする。 $xbee
において
mk install
/usr/local/bin/$objtype/xbee
に att
と api
がインストールされる。api.lua
は 9lua で書かれているために、9lua をインストールしておく必要がある。実行は各々xbee/att $device xbee/api $device api.lua $device
$device
はデバイスファイルの名称である。詳しくは以下に説明する。
att.c
は透過モードで動く普通の通信プログラムであり、XBee2 では使わない。api.c
と api.lua
は各々 C と Lua で書かれた API モード用のプログラムである。att.c
と api.c
は昔書いたプログラムに、今回最小限の手を加えたものである。これらのプログラムは非同期で動く。つまり XBee に命令を送るプログラムと、その結果を受取るプログラムは同期していない。これは通信プログラムの普通のスタイルである。他方 api.lua
は同期通信を行う。同期通信のメリットは、XBee から送られてきたデータが何の命令に対応しているのかが分かりやすいことにあるが、1つ躓くと通信が止まる欠点を持っている。つまり通信の信頼性がないと採用しづらい方法である。2つの通信方式は目的によって使い分ける必要がある1。
これらの XBee 用のプログラムはどれもケーブルで接続された XBee と通信するプログラムである2。現在では RS232C のシリアルケーブルが使われることは稀で、普通は USB ケーブルが使われ、USB ケーブルの中をシリアルデータが流れる。従って XBee は USB の口を通じて接続される。もちろん、そのままでは無理なので、IC チップが介在し、適当な変換作業が行われている。Plan9 では FTDI と Prolific のチップがサポートされている。ここでは、このどちらかを使って XBee と通信していると仮定する。
api.lua
は同期通信のプログラムである。このプログラムは Vcc
の電圧を調べる命令 AT%V
に続けて、 XBee のアナログ入力端子に掛かっている電圧を調べる命令 ATIS
を発行し、2つの命令の応答を合わせて結果を1つの行で表示している。非同期でもやれなくはないかも知れないが、かなり面倒である。
XBee と通信するプログラムはデバイスファイル $device
を引数に指定してで起動される。例えば api.lua
の場合には
api.lua $device
$device
を使っていると正しく働かない。主な理由は、データの取り合いが発生するからである。従って何らかの排他制御が必要になる。いくつかのプログラムが排他制御に関わっている。その関係はかなり複雑である。$xbee
には利用可能な $device
を見つけるプログラム setup
が含まれている。$xbee
においてsetup
# select: # getdataB # getdataB.rc # getdataC # getdataC.rc # xbee/api /mnt/consoles/usb6 # api.lua /mnt/consoles/usb6のように、次に実行するコマンドが例示される。
$device
に相当しているのが /mnt/consoles/usb6
である。usb6
の部分は環境によって異なるであろう1。getdata
で始まる行は、僕の環境でのメニューである。各自の環境に合わせればよい2。
setup
コマンドの中で使われているシェルスクリプト getdev
が $device
を決定している。そして $xbee
の中のプログラムの中で最も難しい。改善の余地があるのかも知れないが、僕の現在の知識では、確実な方法は出てこない。getdataX
, getdataX.rc
は簡単なシェルスクリプトである。行われている内容はシェルスクリプトを見ればよい。X
の部分は XBee に貼り付けたラベルであり、もちろん僕の環境に合わせられている。従って単なるサンプルである。
XBee に対する命令は大文字と小文字の区別をしない。
xbee/api
の実行例として ATND
コマンド(node discovery)を取り上げる1。このコマンドは XBee のネットワークに接続されている Coordinator 以外のすべての node アドレスと、親子関係を教えてくれる便利な(デバッグ用の)コマンドである。
このコマンドを発行すると、(調べるのに多少の時間が必要なために)ちょっと間をおいて応答が返ってくる。どれだけの応答が発生するのか、前もって判らないために、同期通信は不可能である。このような場合にはプロンプトは正確には出せず、煩わしくもある。従って -p
フラグで "no prompt" の選択ができるようにしてある。
hebe# xbee/api -p /mnt/consoles/usb6 ATND 7E 00 04 08 01 4E 44 64 * 7E 00 19 88 01 4E 44 00 D8 77 00 13 A2 00 40 72 16 7C 20 00 FF FE 01 00 C1 05 10 1E 8A * 7E 00 19 88 01 4E 44 00 59 3F 00 13 A2 00 40 A7 45 09 20 00 D8 77 02 00 C1 05 10 1E FD * 7E 00 19 88 01 4E 44 00 8D DF 00 13 A2 00 40 AD D4 5D 20 00 D8 77 02 00 C1 05 10 1E 40
発行したコマンドが ATND
であり、プロードキャストで送られた API パケットの内容が
7E 00 04 08 01 4E 44 64
*
" で始まる行である。ここには3つの行が表示されている。つまり Coordinator 以外に3つの XBee がネットワークに参加していることが判る。応答の内容を具体的に見ていこう。
まず
7E 00 19 88 01 4E 44 00 D8 77 00 13 A2 00 40 72 16 7C 20 00 FF FE 01 00 C1 05 10 1E 8A
"7E 00 19" -- DELIM + size "88" -- frame type -- AT resp. "01" -- frame ID "4E 44" -- "ND" -- AT command name "00" -- command status (OK) "D8 77 00 13 A2 00 40 72 16 7C 20 00 FF FE 01 00 C1 05 10 1E" -- command data "BA" -- check sum
command data の内容については簡単な解説しか手に入らない。しかも文献[2](p.315) の説明は間違いを含む。文献[1](p.175)の説明には問題は無い。この内容は文献[4](p.172)と一致している。
文献[1](p.175)あるいは文献[4](p.172)によれば command data の部分は
2: MY 4: SH 4: SL n: NI -- ちゃんと説明されていない 2: MP 1: device type 1: status 2: profile ID 2: maker IDここに "
:
" の左の数字は、情報が占める byte 数である。"n
" となっているのは可変長を意味する。MY, SH, SL, NI, MP
の意味は文献[1,2,4]に従う。"D8 77" --> MY of xbeeG, affr16 of parent of xbeeC and xbeeD "00 13 A2 00 40 72 16 7C" -- xbeeG "20 00" -- What is this? probably this means "no NI" "FF FE" MP of xbeeG "01" -- router, "02" end device "00" -- status OK "C1 05" -- profile ID "10 1E" -- maker IDである。従って XBee の
SH,SL
が判っていれば、無線ネットワーク上での位置関係が判るのである。
api.lua
を起動すると
>
hebe# api.lua /mnt/consoles/usb6 > ATSH 7E 00 04 08 03 53 48 59 * 7E 00 09 88 03 53 48 00 00 13 A2 00 24 # note that "00 13 A2 00" is the first half of MAC address in use > ATSL 7E 00 04 08 04 53 4C 54 * 7E 00 09 88 04 53 4C 00 40 A7 46 07 A0 # note that "40 A7 46 07" is the last half of MAC address in use > ATID # show the current PAN ID 7E 00 04 08 0D 49 44 5D * 7E 00 0D 88 0D 49 44 00 00 00 00 00 00 00 00 0A D3ここに "
*
" で始まる行は XBee からの応答である。また "#
" は筆者による(後付の)コメントである。
命令名を除いてすべて 16進数表記である。送信と受信パケットの中身が判るようになっている。XBee にかんする書物や ZigBee の仕様書とつき合わせやすいが、人間にとって優しいとは言い難い。この点に関しては後に議論する。
以上は local な XBee すなわち api.lua
を実行しているコンピュータと接続している XBee との交信結果である。残りの XBee を remote な XBee と言うことにする。remote な XBee については アドレスを指定する必要がある。"0013A200:40A74509
" をそのアドレスとする。(":
" は入れなくてもよいが、見やすくするために入れてもよいことにしている)
> dest 0013A200:40A74509 > ATID # show the current PAN ID of the dest 7E 00 0F 17 03 00 13 A2 00 40 A7 45 09 FF FE 02 49 44 6F * 7E 00 17 97 03 00 13 A2 00 40 A7 45 09 3E 8D 49 44 00 00 00 00 00 00 00 00 01 22 > ATIS # show digital and analog data of the dest 7E 00 0F 17 04 00 13 A2 00 40 A7 45 09 FF FE 02 49 53 5F * 7E 00 17 97 04 00 13 A2 00 40 A7 45 09 3E 8D 49 53 00 01 00 10 01 00 00 02 22 DDこうした 16進数のデータ列の意味を読み取るのは慣れていないと非常に困難である。
api.lua
は(api.lua
のコードに手を付けなくても)新たな命令を組み込む機能を持っている。mylib.lua
が外付けのライブラリで、その中に新しい命令 "_ATIS
" が含まれている。 それは次のように使う。> load mylib.lua > _ATIS 1682473127 3.141 0010 01 0000 0.643
この表示の意味は(このケースでは)
のように整理されて(Pyplot などのツールで処理しやすいように)表示される1。
次に示すのは "_ATIS
" を利用して10分ごとのアナログデータを採取した記録の一部である。
1683374976 3.491 0010 01 0000 0.764 1683375576 3.489 0010 01 0000 0.751 1683376177 3.487 0010 01 0000 0.744 1683376777 3.487 0010 01 0000 0.739
図4:_ATIS
の出力
0000
" に相当する部分は省かれている。しかし可変長データは処理しにくいので、ここでは省略された部分を補っている。
api.lua
は(形式的には) ZigBee のすべての命令をサポートしているはずである。命令の詳細に関しては文献 [1,2,4] に詳しい。「形式的には」と言っているのは、ATIR
のようなコマンドは同期式の api.lua
には馴染まない。 xbee/api
を使う必要がある。
AT%V
コマンドで Vcc
の電圧を見ることができる。これはあくまでも XBee から見た Vcc
電圧で、テスターで測定した値と一致している保証はない。
手持ちの XBee の一つ(xbeeD)で調べた。
Vcc
電源に単3アルカリ電池2個を使うと、(テスター MS8218)では Vcc=3.167V
、AT%V
コマンドは 3.060V
を示していた。従って誤差は 1/30
と評価できる。
我が愛用の三和のアナログテスターの誤差はこの程度あるから、満足すべしと思える。
電圧変換モジュール(5V
to 3.3V
など)を XBee の end device の電源として使っている場合には、問題が発生する可能性がある。(待機中ではなく)通信中には XBee は多くの電力を使う。その電力消費に電圧変換モジュールが耐えられないときにはVcc
電圧が瞬間的に落ちる。AT%V
コマンドは落ちた値を送信している可能性がある。電源がバッテリーであれば、そのような影響は少ないであろう。ZigBee の仕様書は安定した Vcc
を仮定していると考えるべし。
XBee のネットワークにおいてアナログ測定を行っているのは、実際的にはバッテリー駆動の End Device であろうから、問題はむしろ、バッテリー電圧の低下が測定にいかなる影響を与えるかが問題になる。
D0~D3
の4つの端子を通じて電圧を測定できる。D1
端子の電圧を測定してみる。ATD1
ATD1 2
IS
コマンドはその結果を見る最も簡単なコマンドである。10bit
。
精度は文献[1~4]には載っていない1。
IS
の精度の問題は多分 Zigi 規格の外なのであろう。
IS
コマンドの記述を英文の PDF 文書から探すのは苦労する。Mac の Safari で PDF 文書を表示させた場合、(初心者向けに設計されているので)大文字と小文字を区別できない。"is
" も一致するために膨大な量が候補として挙げられ、"IS
" を探すのは事実上不可能である。Chrome も同様である。この点に関しては玄人向けの Firefox は流石に良くできている。
実験に使われた XBee(xbeeD) と ブレッドボード(xbeeDB)を図5と6に示しておく。
このブレッドボードは、電池などの電圧を調べるように設計されている。テスターと異なり、xbee を噛ませることによって電圧の時間変化の記録を採ることが可能である。
XBee の ADC
端子は 1.2V
までしか測定できない。より高い電圧を測定したい場合には、potentio meter を利用する。xbeeDB では ADC
ピン D1
が利用されており、測定対象の電圧 V は potentio meter によって V*6783/9921
に減圧されている。従って、例えば V = 1.3145
であれば、D1
ピンには 0.8987V
が掛かっていることになる1。
図5: 回路図 | 図6: ボードピン |
図5の回路図のマル印はボードと外部との接続口を表している。これは図6(この図は図1の一部)の右上に並んだ4つのピンである。番号は右から順に 1,2,3,4 なっている2。
GND
と接続して、D1
の電圧をテスターで測定しても 0V
にはならない。原因は D1
端子が周囲の電場(特に D0
端子と D2
端子の電圧)の影響を受けるからである。この現象は Arduino でも観察された。しかし、IS
コマンドで報告される D1
端子の電圧は正しく 0V
になっている。XBee 恐るべし!
注2: 図のピン配置は合理的ではない。ピン1~4を Vcc,GND,GND,V
の順に並べた方が、率直で、配線もやりやすいのである。しかるにこの配置になってしまったのは、かって、このボードの電源に 5V to 3.3V の変換モジュールを使用していたからである。
電源 Vcc
がどの程度アナログ測定に影響を与えているかを調べる。
電源
Vcc = 3.3734 -- two NiZn batteries
測定対象
NiCd V = 1.3133 V*6783/9921 -- 0.89790483822195
測定結果は
1686818289 3.178 0000 02 0000 0.868
3.154/3.3734 -- 0.93496175964902 0.868/0.89824668884185 -- 0.96632696872966
97%
精度が出ている。これは満足すべき結果であろう。
電源 Vcc
がどの程度アナログ測定に影響を与えているかを調べる。
電源
Vcc = 2.695 -- two eneloops
測定対象
NiCd V = 1.3133 V*6783/9921 -- 0.89790483822195
測定結果は
1686829600 2.590 0000 02 0000 0.866
0.868
" と比較すると、Vcc
依存性は非常に小さいことが判る。
電源 Vcc
がどの程度アナログ測定に影響を与えているかを調べる。
電源
Vcc = 3.433 -- new two NiZn batteries
測定対象
NiCd V = 1.3133 V*6783/9921 -- 0.89790483822195
測定結果は
1686830064 3.293 0000 02 0000 0.866
0.868
" と比較すると、Vcc
依存性は非常に小さいことが判る。
NiZn 電池は XBee の実験には非常に良い。実験は電池を浪費する。しかし NiZn は充電できるし、充電すれば、数週間の継続した実験に耐える。
実際に温度の記録を採ってみることにする。測定に使った温度センサーは MCP9700A
で、仕様書は
https://www.mouser.jp/datasheet/2/268/MCP9700_Family_Data_Sheet_DS20001942-3132871.pdf
にある。この仕様書には
と書かれている。
Accuracy:
• Optimized for Analog-to-Digital Converters (ADCs):
9700B)
• Wide Operating Voltage Range:
9700B)
• Low Operating Current: 6 µA (typical)
• Optimized to Drive Large Capacitive L
MCP9700A
については (Vdd = Vcc
に設定すれば) XBee の動作範囲の電圧で ±2°C
の誤差をみておればよいわけだ。使いやすいセンサーである。
念のためにセンサーの出力電圧 Vout
の Vcc
依存性を調べておいた。(依存しないのが理想である)
Vcc = 2.566 --> Vout = 0.761 Vcc = 3.539 --> Vout = 0.760
0.1
°C 程である。この実験の電源は一組の eneloop と NiZn である。ほぼ同時刻の測定であるが、その間、空調で室温は保たれている。
仕様書の FIGURE 2-17 には温度と Vout
との関係がグラフで示されている:
これによるとほぼ直線的な関係で
100°C --> 1.5V 50°C --> 1.0V 0°C --> 0.5V
Vout = 0.01*T + 0.5 T = 100*(Vout - 0.5)
測定に使った XBee は xbeeC で、このブレッドボード(以下 xbeeCB と書く)の回路の要点を図7に示す。
図7: xbeeCB の回路図の要点
中央の端子が Vout
である。仕様書をしっかり読んでいなかったので、図7の配線になってしまった。MCP9700A
を使っている限り Vout
に接続されている potentio meter は要らなかったのだ。抵抗値を測定すると、実際の減圧比は 10.478/10.491
でほぼ1であった。以下 1 とする。従って Vout
を直接 D0
に接続したのと同じである。
NiZn 電池(2本組)の電圧範囲は XBee と相性が良い。そこで NiZn を XBee の駆動電源とした場合、駆動可能な時間を知りたくなる。
XBee に満充電の NiZn 電池を接続し、Vcc
の時間変化を 10 分ごとに調べる。その間、XBee は信号待機状態になっている。
横軸に経過時間をとったグラフを図8に示す。記録の開始時刻は 2023-05-07 22:11:51
である。
図8: 1100時間(45日間)の電源電圧の変化
同時に温度センサーモジュール(MCP9700A
)の出力電圧(Vout
)も測定されている。この電圧は温度が高いと高くなる。
図9: 1100時間(45日間)の温度センサー電圧の変化
温度センサー電圧は、テスターによる直接的な測定ではなく、IS
コマンドの結果として XBee から報告された数値である。電源電圧が低下しすぎると、XBee が機能しなくなる。
図10に温度センサー電圧と実際の温度との関係を示す。温度の方は自動採取ではないので、気が向いたときに記録している。温度が高くなると、温度センサー電圧も高くなる。問題は良質の温度計が手元に無いので、家庭用の安物(ThermoPro TP-49、図12)で代用していることにある。Amazon.com によれば ±1°C
の誤差を含む1。
http://www.syouhisya.or.jp/test/kirame52.pdf
図10: D0
端子電圧の温度依存性1
MCP9700A
の個体差は、このグラフに顕著に現れる程である。従って個体ごとに温度補正のパラメータを決定しなくてはならなくなる。この問題については後に議論する。(「温度センサーの個体差」の節を見よ)
このグラフを見ると、明らかにデータが一つおかしい(19°C,0.7V
)。温度の実測は手作業のため、間違えた可能性が高い。このデータを省いて、温度の補正を最小自乗法を使って1次式の範囲で求めることにする。ついでにデータを追加しておいた。結果を図11に示す。
図11では D0
ピンの電圧ではなく、式 T=100*(Vout - 0.5)
で換算した温度(T0
)を使って実際の温度(Tobs
)と比較している。T0
は Tobs
よりも少し小さく出ている。
図11: 温度センサーから求めた温度 T0
と実際の温度 Tobs
の比較
1次の最小自乗法で求めた回帰直線が参考のために図示されている。この直線を使って T0
から期待される温度 T2
は (図11の観察データの下で)
(a2,b2) = (1.002366, 0.468104) ; T2 = a2*T0 + b2
a2,b2
は次節の最小自乗法の説明における \(\alpha\) と \(\beta\) に相当する。
こうして求められた T2
はどの程度の予測能力を持っているか? T2
と観測 Tobs
を比較してももちろん同じにはならない。T0
が同じであったとしてもである。どのような理由が考えられるか?
図12: ThermoPro TP-49
XBee 上の温度センサーはむき出しの状態で置かれているのに対して、Tobs
の決定に使用されている温度計はセンサーがパッケージで覆われている。従って後者の場合には、環境の温度が温度計内のセンサーに反映されるのに時間がかかる。この問題は、温度が上昇中、あるは下降中の場合に影響を与える。
T2
と Tobs
の違いを定量的に分析することは、専門的な道具なしには非常に困難である1。プロであれば良質の温度計の他に、気温が自由に制御できる実験環境を要求するだろう。こうしたことは、趣味でやっている筆者の場合には望めない。筆者の観察では、補正後の ThermoPro TP-49 との差異は ±0.5°C
以内に納まっている。これでよしとする。
2つの量 \((x,y)\) があって、\(y\) は \(x\) の一次の関係 \( y = ax + b \) で与えられるはずの量とする。 \(a\) と \(b\) はわかっていない。
\(x\) を与えたときの \(y\) の観測値を \((x_i,y_i)\ (i=1,2,...,n) \) とする。もちろん \(y\) は観測誤差を含んでいる。
\( a, b \) はこれらの観測値から推定するものとする。推定には最小自乗法を使うのが普通である。すなわち
\[ Q:=\sum_i ((ax_i + b) - y_i)^2 \]
とおいて、 \( a, b \) を
\[ \frac{\partial Q}{\partial a} = 0; \hspace{1cm} \frac{\partial Q}{\partial b} = 0 \]
から決めれば良い。
必要な計算の見通しを良くするために、\( X, Y \) を次のように配列として考え
\[ X = (x_1, x_2, ..., x_n) ; \hspace{1cm} Y = (y_1, y_2, ..., y_n) ; \hspace{1cm} XY = (x_1 y_1, x_2 y_1, ..., x_n y_n) ;
\hspace{1cm} c X = (c x_1, c x_2, ..., c x_n) \]
最後の例において \( c \) は配列ではなく1個の数値である。ここに述べた「配列」の概念と演算法は numpy に従った。
要素の平均をオーバーラインで表すことにする。例えば
\[ \overline{a} = a;\hspace{1cm} \overline{X} = \frac{1}{n} \sum_i x_i ; \hspace{1cm} \overline{XY} = \frac{1}{n} \sum_i x_i y_i \]
である。すると
\[ a=\frac{\overline{(X - \overline X)(Y - \overline Y)}}{\overline{(X - \overline X)^2}} ; \hspace{1cm} b = \overline{Y} - a\overline{X} \]
が得られる。
\( x \) を与えて \( y \) を予測したい場合には以上の方法で \( (a, b) \) を求めて \( y = ax + b \) とすればよい。
しかし \( y \) を与えて \( x \) を予測する場合には \( x = \alpha y + \beta \) とし、\( X \) と \( Y \) の役割を入れ替えて
\[ \alpha=\frac{\overline{(Y - \overline Y)(X - \overline X)}}{\overline{(Y - \overline Y)^2}} ; \hspace{1cm} \beta = \overline{X} - \alpha\overline{Y} \]
となる。
\(a=1\) すなわち \(\alpha =1\) の場合には
\[ Q = \sum_i ((\alpha x_i + \beta) - y_i)^2 \]
となっている。この場合、決定すべきは \(b\) と \(\beta\) であり、\(b+\beta=0\) の関係がある。
従って \(a\) が 1 に近い場合、どちらの考え方を採用しても、予測に関してはほとんど同じ結果が得られることになる。
折角、最小自乗法でパラメータを求めても、この結果は特定の温度センサーに対してしか働かない。温度センサーの型番が同一であってもだ。ここでは MCP9700A を例にとって議論する。
図4において、2つの MCP9700A のセンサー電圧を D0
と D1
に接続して電圧を測定すると次のようになった1。
hebe# getdataC.rc 1690519854 3.298 0010 03 0000 0.848 0.852 1690520455 3.313 0010 03 0000 0.852 0.856 1690521055 3.322 0010 03 0000 0.852 0.856 1690521656 3.327 0010 03 0000 0.852 0.856 1690522256 3.332 0010 03 0000 0.853 0.857 1690522857 3.335 0010 03 0000 0.854 0.859 1690523458 3.336 0010 03 0000 0.853 0.857 1690524058 3.339 0010 03 0000 0.853 0.857 1690524659 3.339 0010 03 0000 0.853 0.857 1690525259 3.340 0010 03 0000 0.853 0.857 1690525860 3.340 0010 03 0000 0.853 0.857 1690526460 3.340 0010 03 0000 0.852 0.855 1690527061 3.340 0010 03 0000 0.852 0.856 1690527661 3.339 0010 03 0000 0.850 0.855 1690528262 3.337 0010 03 0000 0.848 0.853 1690528862 3.336 0010 03 0000 0.848 0.853 1690529463 3.335 0010 03 0000 0.847 0.852 1690530063 3.334 0010 03 0000 0.847 0.850 1690530664 3.330 0010 03 0000 0.845 0.848 1690531265 3.329 0010 03 0000 0.843 0.847 1690531865 3.327 0010 03 0000 0.843 0.847 1690532466 3.325 0010 03 0000 0.842 0.846 1690533066 3.320 0010 03 0000 0.841 0.845
図13: 2つの MCP9700A の個体差
第6フィールドと第7フィールドが各々 D0
と D1
の電圧である。理想的には両者は一致していて欲しい。
XBee のアナログ端子はなかなか優秀で、アナログ端子が異なっていても、同一の電圧を表示させると一致している。従って図13における不一致は、センサーの個体差に由来している。
この観測結果を見る限り、D1
と D0
の差は 0.004V
程度である。1% 以内に留まっているので素晴らしいと思うかも知れない。しかし、これは温度に換算すると 0.4°C
に相当する。図11を見れば判るように、回帰直線の決定に有意な影響を与える。
0.5°C
であった。