「えだまめ」しているラズパイ

30年ぶりに半田ごて握ってラズパイ勉強中。

マメタンに固形アルコール燃料で簡単着火

火の付きにくい豆タンにアルコールジェル系の固形燃料で簡単に火をつける方法。
やり方は簡単、写真の通り。

アマゾンで売っていたアミ付きポケットストーブを断熱用の鍋敷きの上に置き、簡単に移動できるようステンレス製のお盆にのせます。

15gサイズの固形アルコール燃料を

2段重ねにして30gにしたものをセットし

マメタンをのせ火をつければ20分で火がつきます。

この時火とマメタンが十分近くにある事がコツなようです。
片面をじっくり15分ほど焼けば真っ白に焼き上がりますので残り5分でもう一面を焼きます。

マメタンが十分高温になっているので2面目はすぐに火が付き早々と真っ白になってくれます。

ノーマルマメタンはマッチ一本で着くスーパーマメタンと違い火の持ちがよく、スーパーマメタンの12〜16時間に対し24〜28時間と2晩布団の中を暖めてくれます。値段が安上がりな上に火の持ちがいいのでダブルでお得です。

ちなみにマメタンアンカを早く暖めたい場合は固形燃料をもう一個使って追加焼きすれば火の入り方が深くなり早く熱くなります。

・ガスと風

マメタンは着火時に有毒ガスを出すので外部の換気の良い場所で火をつけるのは鉄則です。また固形燃料は風に弱いためそのままだと火が風に流されうまく着火できません。ついたて等しっかりと防風対策が必要になります。燃料を2段重ねにするのは火力を強くして風に対抗するためです。防風対策がしっかりとれるのであれば、燃料の下に下駄を履かせ火をマメタンに近づければ一つでも火がつきます。片面一個づつ、二個で両面焼きが可能です。私はこの方式でやってます。

・おまけ

ノーマルマメタンの灰はスーパーマメタンに比べると柔らかくすぐに割れてしまいます。というか、スーパーマメタンの灰が固いんでしょうか。写真は着火から24時間たった豆炭。

灰がやわらかいので火鉢に移そうとした時に割れてしまいました。まだ火が残っていてアンカ自体も相当熱い状態です。

・おまけ2

豆タンは普段車庫に保管してあるのですが、普段使い用に火消しツボにいくつか入れて部屋に置いています。冬で乾燥が進むせいかパックマンモード、アッカンベー豆タンが発生します。

特に問題はないとは思うんですが…。
(写真はすっかり火がついたので家の中に持ってきた時の豆タンです。)

ラズパイでメッシュWiFiネットワークを構築する(4) NODEの準備

◯やりたいこと

(1)〜(3)で構築されたメッシュネットワークへ NODEを追加する。

◯やったこと

5. その他 NODEの作成

(2)と(3)で最低限のメッシュネットワークが構築できたので、メッシュネットにその他のノードを追加していきます。ノードはメッシュデバイスとしてパケットのリレーを担当しながら、センサーなどを装備してデータの発信や受信を行う事もできます。メッシュに参加するには wlan0一つがあればいいのでラズパイゼロで充分に活躍できます。

5-1. ラズパイの準備

ここではラズパイZeroへインストールする例で進めていきます。Zeroは(1)の要領で新規に準備したものでもいいですし、センサー搭載など既に何かが動作しているものでも構いません。既存動作中のZeroにいくつかインストールしてみましたが特に問題なく動いてくれています。
ホームネット側から wlan0に接続しターミナルソフトから sshで Zeroにログインしておきます。

5-2. batctl ツールのインストール

ゲートウェイの設定 3-2と同じ処理です。batctlの設定ファイルの内容が一般ノード用に変更になります。

sudo apt-get install -y batctl
nano ~/start-batman-adv.sh

・ファイル内容

#!/bin/bash
# batman-adv interface to use
sudo batctl if add wlan0
sudo ifconfig bat0 mtu 1468

# Tell batman-adv this is a gateway client
sudo batctl gw_mode client

# Activates batman-adv interfaces
sudo ifconfig wlan0 up
sudo ifconfig bat0 up

忘れずにスクリプトを実行可能な状態にしておきます。

chmod +x ~/start-batman-adv.sh

5-3. wlan0のネットワーク定義の設定

ゲートウェイ設定 3-3と全く同じ内容でファイル設定をします。

sudo nano /etc/network/interfaces.d/wlan0

・ファイル内容

auto wlan0
iface wlan0 inet manual
wireless-channel 1
wireless-essid call-code-mesh
wireless-mode ad-hoc
wireless-key 1234567890

5-4. batman-advモジュールのロード

echo 'batman-adv' | sudo tee --append /etc/modules

5-5. wlan0をDHCPプロセスの管理から外す

wlan0を DHPCの管理下から除外します。

echo 'denyinterfaces wlan0' | sudo tee --append /etc/dhcpcd.conf

5-6. 起動時実行スクリプトの定義

ここもゲートウェイ設定 3-6と同様の設定を行います。

sudo nano /etc/rc.local

ファイル内の exit 0 の前に

/home/pi/start-batman-adv.sh &

の1行を挿入しておきます。

5-7. ノードへのログイン

以上でノードの設定は終了です。ここで再起動しますが、再起動するとノードはメッシュネット上に移動しますのでホームネット側からのアクセスができなくなります。ブリッジで行ったようにゲートウェイを経由して sshの2段接続でログインします。
ちなみにゲートウェイにログインした時点で以下のコマンドを実行するとメッシュネット上で pingに反応してくれる IPアドレスの一覧を表示してくれます。

echo 192.168.199.{1..254} | xargs -P256 -n1 ping -s1 -c1 -W1 | grep ttl

「なんかいろいろ」さんより(https://orebibou.com/ja/home/201505/20150518_001/)

5-8. インターフェースの動作状況確認

ゲートウェイやブリッジで行ったように以下のコマンドで動作の確認ができます。

ifconfig
iwconfig
sudo batctl if
sudo batctl n

インターネットへの接続確認は

ping www.ibm.com -c 5

でルーティングとバックが正しく行われているかがわかります。

〜 続く 〜

◯ラズパイ不足…

最近は全くラズパイが手に入りません。アマゾンではかなりの値段で抱き合わせ販売が横行していますし、単品でも驚きの値段で売られています。まだまだこの状況は続く様です。そもそも日本の主要産業の自動車でさえ半導体が不足しているのに一般カスタマーに半導体が回ってくるのは夢のまた夢だとか。当面は在庫品でしのぐしかありません。
幸いウチにはラズパイゼロの豊富な在庫が。

ESPに手を染める前はセンサー類を全てラズパイゼロで動かしていたので、毎月1個、2個と買い足していったものが20個くらいあります。少々の能力不足には目をつぶり、動作能力に応じた利用法に知恵を絞って活用していくことにします。

ラズパイでメッシュWiFiネットワークを構築する(3) Bridge NODEの準備

◯やりたいこと

(2)で準備したゲートウェイに引き続き、(1)の要領で準備した2台目のラズパイへメッシュネット上で動作するブリッジノードをインストールします。

◯やったこと

4. Bridge NODE(BR)の作成

ここで準備するブリッジノードは wlan0側がメッシュネット上に接続されているNODEの一つで eth0側に接続される非メッシュデバイスとのパケット中継を担当します。wlan0・eth0どちら側も見た目は同じメッシュネットワーク上にあるように見えます。ブリッジを家の隅っこに持っていったとしてもあちこちの NODEがバケツリレーでパケットを転送してくれるので、eth0と PCを LANケーブルで接続するとPCは普通にメッシュネット上にあるように動作します。IPアドレスもメッシュ上のDHCPサーバー(ゲートウェイ)からキチンと 192.168.199.xxxのアドレスを取得します。当然メッシュネット上にある各NODEとのやりとりも普通にできます。WiFiドングルを追加すれば eth0の代わりに WiFiでの機器接続も可能になります。


4-1. ラズパイの準備

ラズパイ 4B+が入手困難なのでゲートウェイと同じく在庫品の 3B+を引っ張り出してきてブリッジを構成します。ブリッジノードは設定が終わって再起動するとホームネット側からは見る事ができなくなりますので気合を入れて一発動作を狙っていきます。まあ最悪 eth0に PCを接続し直せばホームネット上で操作したのと同様な操作をする事は可能なのですが、iPadからリモートでWindowsにログインしている私の環境では非常に手間がかかる処理になりますのでできればやらずに済ませたいところです。

(1)の要領でセットアップしたラズパイは順調に起動すれば wlan0がホーム側ネットに接続して起動しますので、ターミナルソフトから sshでログインしておきます。

4-2. batctl ツールのインストール

ゲートウェイの設定 3-2と同じ処理です。batctlの設定ファイルの内容がブリッジ用に変更になります。

sudo apt-get install -y batctl
nano ~/start-batman-adv.sh

・ファイル内容

#!/bin/bash
# batman-adv interface to use
sudo batctl if add wlan0
sudo ifconfig bat0 mtu 1468

sudo brctl addbr br0
sudo brctl addif br0 eth0 bat0

# Tell batman-adv this is a gateway client
sudo batctl gw_mode client

# Activates batman-adv interfaces
sudo ifconfig wlan0 up
sudo ifconfig bat0 up

# Restart DHCP now bridge and mesh network are up
sudo dhclient -r br0
sudo dhclient br0

ちなみにブリッジノードの IPアドレスを固定化したい場合は最下行2行の代わりに

sudo ifconfig br0 192.168.199.xxx

としておけば固定IPで起動します。
ここでも忘れずにスクリプトを実行可能な状態にしておきます。

chmod +x ~/start-batman-adv.sh

4-3. wlan0のネットワーク定義の設定

ゲートウェイ設定 3-3と全く同じ内容でファイル設定をします。

sudo nano /etc/network/interfaces.d/wlan0

・ファイル内容

auto wlan0
iface wlan0 inet manual
wireless-channel 1
wireless-essid call-code-mesh
wireless-mode ad-hoc
wireless-key 1234567890

4-4. batman-advモジュールのロード

echo 'batman-adv' | sudo tee --append /etc/modules

4-5. wlan0,eth0,bat0をDHCPプロセスの管理から外す

ブリッジノードではwlan0に加え eth0, bat0もDHPCの管理下から除外します。

echo 'denyinterfaces wlan0 eth0 bat0' | sudo tee --append /etc/dhcpcd.conf

4-6. 起動時実行スクリプトの定義

ここもゲートウェイ設定 3-6と同様の設定を行います。

sudo nano /etc/rc.local

ファイル内の exit 0 の前に

/home/pi/start-batman-adv.sh &

の1行を挿入しておきます。

4-7. ブリッジユーティリティのインストール

ここからはブリッジノード専用のインストールになります。まずはブリッジユーティリティのインストールから行います。

sudo apt-get install -y bridge-utils

4-8. eth0の設定

wlan0側(メッシュ側)でリレーしてきたパケットを橋渡し(ブリッジ)する eth0の設定を行います。この設定を行うとイーサネットポートをホットプラグ(自由に抜き差し)できるようになります。設定ファイルに以下の内容を定義します。

sudo nano /etc/network/interfaces.d/eth0

・ファイル内容

auto eth0
allow-hotplug eth0
iface eth0 inet manual

4-9. ブリッジノードへのログイン

以上で設定が完了しましたので再起動します。再起動するとブリッジはメッシュネット上に移動してしまいますのでホームネット側から直接操作することができなくなります。ブリッジへWindowsマシンを直接 LAN接続できる場合は直接操作が可能なのですが、ここではゲートウェイにホームネット側から sshで一度ログインしさらにゲートウェイ上からメッシュネット側のブリッジに sshでログインする方法を取ります。要は sshの2段接続です。

ホームネット側からゲートウェイにログインし、

ssh pi@192.168.1.xxx 

DHCPサーバーのアドレスリース記録を見てブリッジの IPアドレスを確認します。

cat /var/lib/misc/dnsmasq.leases

そのアドレスに sshでログインします。

ssh pi@192.168.199.xxx

4-10. インターフェースの動作状況確認

ブリッジにログインできたら最初にインターフェースの動作状況を確認します。

ifconfig

次のように表示されれば正常に動作しています。

bat0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1468
            inet6 fe80::e838:85ff:fe06:8265  prefixlen 64  scopeid 0x20<link>
            ether ea:38:85:06:82:65  txqueuelen 1000  (Ethernet)
            RX packets 16589  bytes 9220389 (8.7 MiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 14460  bytes 1905164 (1.8 MiB)
            TX errors 0  dropped 19 overruns 0  carrier 0  collisions 0

    br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1468
            inet 192.168.199.34  netmask 255.255.255.0  broadcast 192.168.199.255
            inet6 fe80::4e41:fc4e:b18c:ffd0  prefixlen 64  scopeid 0x20<link>
            ether b8:27:eb:e8:18:b0  txqueuelen 1000  (Ethernet)
            RX packets 3261  bytes 213663 (208.6 KiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 1053  bytes 208548 (203.6 KiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet6 fe80::ba27:ebff:fee8:18b0  prefixlen 64  scopeid 0x20<link>
            ether b8:27:eb:e8:18:b0  txqueuelen 1000  (Ethernet)
            RX packets 15714  bytes 2010018 (1.9 MiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 16090  bytes 9413607 (8.9 MiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

    lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
            inet 127.0.0.1  netmask 255.0.0.0
            inet6 ::1  prefixlen 128  scopeid 0x10<host>
            loop  txqueuelen 1000  (Local Loopback)
            RX packets 3  bytes 360 (360.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 3  bytes 360 (360.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

    wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet6 fe80::ba27:ebff:febd:4de5  prefixlen 64  scopeid 0x20<link>
            ether b8:27:eb:bd:4d:e5  txqueuelen 1000  (Ethernet)
            RX packets 65722  bytes 11991421 (11.4 MiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 39946  bytes 4886290 (4.6 MiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

チェック点
・br0にメッシュネットワーク内の IPアドレスが割り振られている
・bat0,eth0,wlan0には IPアドレスが割り振られていない

続いてブリッジインターフェースの詳細を表示して

sudo brctl show

bat0と eth0がブリッジしている事を確認します。

bridge name bridge id       STP enabled interfaces
br0     8000.b827ebe818b0   no      bat0
                                    eth0

ブリッジのインターフェースがメッシュネットワークに参加できているかを確認するには

sudo batctl if
wlan0: active

でwlan0がメッシュに参加している事がわかりますし、

sudo batctl n

で自分から見える近くのメッシュノードが表示されます。

[B.A.T.M.A.N. adv 2021.3, MainIF/MAC: wlan0/b8:27:eb:04:3e:57 (bat0/ba:d1:69:83:e4:2f BATMAN_IV)]
IF             Neighbor              last-seen
        wlan0     b8:27:eb:33:d4:ad    0.920s

〜 続く 〜

ラズパイでメッシュWiFiネットワークを構築する(2) Gateway NODEの準備

◯やりたいこと

(1)で準備したラズパイにホームネットワークとメッシュネットワークをつなぐGatewayをインストールする。

◯やったこと

3. Gateway NODE(GW) の作成

ゲートウェイはホームネット側で言うルーターと同じ事をします。ルーターがインターネットとホームネットをルーティングするように、ゲートウェイはホームネットとメッシュネットをルーティングします。NODEをバケツリレーしてやってきたパケットは NAT変換されホームネット側に渡されます。

NODOがアシストしてきたボール(パケット)を堂安(ゲートウェイ)がゴール(ホームネットへ渡す)するイメージです。ただしメッシュ側からホーム側へのアクセスはインターネットを含めて自由にできるのですがホーム側からメッシュ側へのアクセスはできません。日本側が必ず勝つ設定になっています。もちろん日本チーム同志でのボールのやりとりはオールオーケーですが…。そのためメッシュ側にアクセスするにはゲートウェイのホーム側 IPへ SSHでログインし、そこから2段接続でメッシュ側にアクセスする必要があります。

今回はゲートウェイを以下の通りで設定していきます。
・インターフェース : eth0-ホームネット側、wlan0-メッシュネット側
・ホームネット側アドレス : ホームネットのDHCPからもらう
・メッシュネット側アドレス:192.168.199.1
・メッシュネットワーク:192.168.199.0
・メッシュネットマスク:255.255.255.0

3-1. ラズパイの準備

今回ゲートウェイにはラズパイ 3B+を使用します。できれば新型の 4B+を使用したかったのですが、昨今のラズパイはひどい入手難。仕方がないので引退していた3B、3B+を引っ張り出してきてパッシブ型のアルミケースに入れて利用します。

(1)の要領で作成したラズパイをホームネット側にLANケーブルで接続して起動し、TeratermPuttyなどのターミナルソフトを使って sshゲートウェイにログインしておきます。

ssh pi@192.168.1.xxx(ゲートウェイにホームネット側から付与された IPアドレス)
password:

3-2. batctl ツールのインストール

最初にbatctl ツールをインストール。

sudo apt-get install -y batctl

インストール後以下の内容で設定ファイルを作成します。

nano ~/start-batman-adv.sh

・ファイル内容

#!/bin/bash
# batman-adv interface to use
sudo batctl if add wlan0
sudo ifconfig bat0 mtu 1468
# Tell batman-adv this is an internet gateway
sudo batctl gw_mode server
# Enable port forwarding
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo iptables -A FORWARD -i eth0 -o bat0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i bat0 -o eth0 -j ACCEPT
# Activates batman-adv interfaces
sudo ifconfig wlan0 up
sudo ifconfig bat0 up
sudo ifconfig bat0 192.168.199.1/24

最下行のアドレスがゲートウェイのメッシュ側 IPアドレスです。
作成後は忘れずに chmodでファイルに実行権限を付与し実行可能な状態にしておきます。

chmod +x ~/start-batman-adv.sh

 

3-3. wlan0のネットワーク定義の設定

続いてwlan0インターフェースのネットワーク定義をroot権限で作成していきます。

sudo nano /etc/network/interfaces.d/wlan0

・ファイル内容

auto wlan0
iface wlan0 inet manual
wireless-channel 1
wireless-essid call-code-mesh
wireless-mode ad-hoc
wireless-key 1234567890

大元の記事ではネットワークにセキュリティキーを使用していなかったのでここでは別に追加しています。キーは16進数で10桁などの制限がありますので注意して設定してください。

・wireless-channnel 1〜12チャンネル
・wireless-essid YOUR-SSID

などは任意の値をセットできます。日本ではチャンネルを13まで利用可能なようなのですが、ラズパイでは12までしか設定できないようです。モードはアドホック固定です。このファイル内容はメッシュネットワーク内全てのデバイスで同一である必要があります。

3-4. batman-advモジュールのロード

echo 'batman-adv' | sudo tee --append /etc/modules

3-5. wlan0をDHCPプロセスの管理から外す

echo 'denyinterfaces wlan0' | sudo tee --append /etc/dhcpcd.conf

3-6. 起動時実行スクリプトの定義

起動時にstart-batman-adv.shを実行するため rc.localにスクリプトを定義します。

sudo nano /etc/rc.local

ファイル内の exit 0 の前に

/home/pi/start-batman-adv.sh &

の1行を挿入しておきます。

3-7. DHCPサーバーのインストール

ここからは Gateway専用の設定になります。まずはメッシュ側のDHCPサーバーとして「dnsmasq」をインストールします。

sudo apt install dnsmasq -y

インストール後以下のファイルを開き、

sudo nano /etc/dnsmasq.conf

RollDownキーを使って最下行までスクロールしてそこへ貸し出す IPアドレスの範囲を記述しておきます。

interface=bat0
dhcp-range=192.168.199.2,192.168.199.99,255.255.255.0,12h

最後に iptablesの情報を永続化するためのツールをインストールしておきます。

sudo apt install iptables-persistent -y

ルールを保存するか ip4と ip6で2度聞いてくるのでどちらも「はい」を押してください。

3-8. ゲートウェイの動作確認

ここでいったんリブートします。

sudo reboot

リブートすると wlan0はメッシュネットワーク側での動作に変わりますので以後の操作は eth0(ホームネット側)からログインして操作することになります。
ssh でログイン後以下のコマンドを実行してみて

ifconfig

次の内容が表示されれば正常に動作しています。

bat0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1468
        inet 192.168.199.1  netmask 255.255.255.0  broadcast 192.168.199.255
        inet6 fe80::f1e8:b920:3a95:cdee  prefixlen 64  scopeid 0x20<link>
        ether b6:fb:9f:de:90:f6  txqueuelen 1000  (イーサネット)
        RX packets 57  bytes 2394 (2.3 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1  bytes 110 (110.0 B)
        TX errors 0  dropped 42 overruns 0  carrier 0  collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.82  netmask 255.255.255.0  broadcast 192.168.1.255
        inet6 fe80::fed7:b320:764f:f01f  prefixlen 64  scopeid 0x20<link>
        inet6 240d:1a:8d4:8500:231a:25e5:4a64:820b  prefixlen 64  scopeid 0x0<global>
        ether b8:27:eb:51:6b:02  txqueuelen 1000  (イーサネット)
        RX packets 4445  bytes 348477 (340.3 KiB)
        RX errors 0  dropped 2  overruns 0  frame 0
        TX packets 119  bytes 14678 (14.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (ローカルループバック)
        RX packets 29  bytes 4779 (4.6 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 29  bytes 4779 (4.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::ba27:ebff:fe04:3e57  prefixlen 64  scopeid 0x20<link>
        ether b8:27:eb:04:3e:57  txqueuelen 1000  (イーサネット)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 508  bytes 56697 (55.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

チェック点
・eth0がホームネット側から割り当てられたIPアドレス(ここでは192.168.1.82)であること
・bat0が192.168.199.1のアドレスであること
・wlan0にはIPアドレスが割り当てられていないこと

続いて以下のコマンドで、デバイスのワイヤレスインタフェースを確認します。

iwconfig

 
表示例

lo        no wireless extensions.
eth0      no wireless extensions.
wlan0     IEEE 802.11  ESSID:"call-code-mesh"
          Mode:Ad-Hoc  Frequency:2.412 GHz  Cell: FE:9E:13:0E:98:71
          Tx-Power=31 dBm
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Power Management:on
bat0      no wireless extensions.

チェック点
SSIDが「/etc/network/interfaces.d/wlan0」で規定した「call-code-mesh」となっている
・モードはAd-Hoc(アドホック)になっている

続いてwlan0がメッシュネットワークでアクティブになっているか確認します。

sudo batctl if

activeと表示されれば正常に動作しています。

wlan0: active

〜 続く 〜

WiFiのチャンネルについて

パッシブ型のアルミケースでラズパイを包み込んでしまうとやはり内臓ワイヤレスLANの電波強度が弱くなるようです。(下図では7ch)


現在稼働しているメッシュネットのブリッジには WiFiドングルを増設しているのですが内臓に比べると電波強度が強く出ています。(図の 1ch)

NODEが場所々々で電波強度を維持しているので、混信を意識し3チャンネルおき5チャンネルで運用してます。ホーム側のWiFiはラズパイでセットできない13チャンネルを設定してチャンネルを有効利用中。さらに混んできたら2チャンネルおき7チャンネルまで増やす予定です。

ラズパイでメッシュWiFiネットワークを構築する(1) OS用SDカード・ラズパイの準備

◯やりたいこと

家の中に増殖しまくっているラズパイ群、

設置場所が広がりすぎてひとつのWiFiアクセスポイントだけでは家内全部をカバーしきれなくなってきました。そこでバケツリレー方式でデータを転送してくれるメッシュネットワークを利用し家内全てにWiFiが届くネットワークの再構築に向け準備を始める事にしました。

今回参考にさせていただいたのはこの記事。
ラズパイでメッシュネットワークを作成する 準備編その1:名刺サイズの超小型PC「ラズパイ」で遊ぶ(第62回) - ITmedia NEWS

記事はとても参考になりました。感謝です。
さらにこの記事の大元である
WiFiMeshRaspberryPi/README.md at master · binnes/WiFiMeshRaspberryPi · GitHub

を翻訳ページ
DeepL翻訳:世界一高精度な翻訳ツール

で訳しながら様々な利用シーンを想定していろいろと実験していきたいと思います。

◯やったこと

1. メッシュネットワーク全体の把握

今回構築するメッシュネットワークの第一到達点は原本記事内にある1番最初のネットワーク図。


(原本記事を和訳したものをワードに貼り付けて印刷、にらめっこしてます)

インターネットがつながるホームネットワークとは別のサブネットでメッシュネットワークを構築し、そのネットワーク内に
 ・ゲートウェイ(Gateway)
 ・ブリッジ(Bridge)
 ・ノード(NODE)
の3つをラズパイで立ち上げられれば第一段階が完成です。
インターネットにつながるホームネットワークが既にあることが前提条件です。

2. メッシュネットワーク構築用ラズパイの準備

2.-1. 使用するラズパイOS

メッシュネットワークに利用するラズパイのOSは新しく構築するということもあり最新版のbullseyeを使用します。あえて新規にインストールせず現在稼働中のラズパイにメッシュをインストールしても大丈夫なのですが、負荷のかかるゲートウェイとブリッジに関しては新規に専用マシンを準備する事にしました。OSの種類は32Bit版Lite、これをCUIでインストールします。(私のラズパイ開発環境は相変わらずiPadで階段下のWindowsマシンにリモートログインする一本指打法なので、実はCUI以外のOSのインストール方法が取れないというのが実情です)。

2-2. SDカード書込み機

SDカードにOSを書き込む方法は Windowsマシンで「Raspberry Pi Imager」を使うのが一般的ですが、やたらと遅いので私の場合ラズパイを利用して作成しています。

OSイメージを一度ダウンロードしてしまえば後は1〜2分で書込みが終了しますので開発時に何度もSDカードを作り直す際はとても重宝します。ここではWindowsマシンではなくあえてラズパイでSDカードを作る方法を記載しておきます。

2-3. OSの書込み

書込み用のラズパイはフルバージョンをインストールしてあり、iPadからリモートログインしてGUI操作ができるようになっています。ただ使用するのは XLTerminal で結果的に CUI での書込みとなります。

2-3-1. OSのダウンロード・解凍

32Bit Lite版 OS 「2022-09-22-raspios-bullseye-armhf-lite.img」をカレントディレクトリにダウンロードします。

wget https://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_armhf/images/raspios_lite_armhf-2022-09-26/2022-09-22-raspios-bullseye-armhf-lite.img.xz

ダウンロードが完了したらファイルを解凍しOSイメージをカレントディレクトリに準備しておきます。

xz -dv 2022-09-22-raspios-bullseye-armhf-lite.img.xz


2-3-2. OSの書込み

空のSDカード(空でなくても問題ありません)をUSBカードリーダーにセットし書込み機に差し込みます。この時ディスクをマウントするか聞いてきますのでキャンセルして未マウントの状態を維持します。

dfコマンドで他のSDカードのマウントがない事を確認し、挿入したSDカードのデバイス名が/dev/sdaになる事を確認して以下の書込みコマンドを実行します。

sudo dd bs=4M if=2022-09-22-raspios-bullseye-armhf-lite.img of=/dev/sda status=progress conv=fsync

1分半ほどで書込みが終了します。


2-3-3. bootフォルダのセットアップ

書込みが終わったらこのSDカードで bootする際キー入力が不要となるよう必要なファイルを作成しておきます。
ここでカードリーダーを一度抜き差しします。すると再びマウントするか聞いてきますので今回は暗証番号を入力しSDカードをマウントします。

dfコマンドを実行すると /dev/sda1/(=/media/pi/boot)、/dev/sda2(=/media/pi/rootfs)の2つがマウントされているのが確認できます。

この状態で以下の3つの作業を行います。

a.起動後 SSHでログインできるようsshディレクトリを作成

sudo mkdir /media/pi/boot/ssh

b.WiFi接続用の設定ファイルを作成

sudo nano /media/pi/boot/wpa_supplicant.conf

ファイル内容

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP
network={
    ssid="YOUR-SSID"
    psk ="YOUR-PASSWORD"
}


c.ログインユーザーを登録するファイルを作成
前もってログインユーザーのパスワードをハッシュ化しておきます。

echo 'YOUR-PASSWORD' | openssl passwd -6 -stdin

結構長いアルファベット・数字の文字列が出力されますが、これを以下のファイル内で設定するパスワードとして使用します。

sudo nano /media/pi/boot/userconf.txt

ファイル内容

pi:ハッシュ化されたYOUR-PASSWORD


2-3-4. マウントの解除

最後にマウントを解除して完成したSDカードを抜きます。

umount /dev/sda1
umount /dev/sda2


2-4. 作成したSDカードでラズパイを起動

いよいよ 2-3 で準備したSDカードをラズパイにセットして起動します。bootフォルダに書込んでおいた.ssh、wpa_supplicant.confなどのファイルは一度起動してしまうと消去されてしまいますのでセットアップは一発勝負です。セットアップに失敗した場合は2-3に戻って起動ファイルの再設定が必要になりますので注意してください。

2-4-1. IPアドレスの確認

ここからがCUIインストールのむずかしいところです。起動したラズパイにはモニターがつながっていませんのでキチンと起動したかどうかが不明です。そこで NetEnumなどの IPアドレス検索ツールを使ってラズパイが WiFiにつながり DHCPから IPアドレスをきちんともらっているのかどうかを確認します。順調に進んでいれば新しいアドレスが割り振られメーカー名などが表示されます。
この時保険として LANケーブルもつないでおけば WiFiで接続に失敗しても有線で確実に IPアドレスを取得できるので安心です。
割り振られた ipアドレスは次の sshログイン時に必要になりますので別にひかえておきます。

2-4-2. SSHでログイン

WindowsマシンからTeraTermPuttyなどの SSHターミナルを使い、2-4-1 で取得した IPアドレスに 2-3-3.c でセットしたユーザー・パスワードを使ってログインします。

2-4-3. ラズパイのセットアップ

無事ログインできたら以下のコマンドを入力してラズパイのセットアップを行います。
a. 次回起動時に sshでログインできるようホームディレクトリに .sshフォルダを作成

mkdir -m 700 .ssh

b. ファイルシステムの再構築

sudo raspi-config nonint do_expand_rootfs

c. ローカル言語を日本語にセット

sudo raspi-config nonint do_change_locale ja_JP.UTF-8

d. ローカル時間を東京にセット

sudo raspi-config nonint do_change_timezone Asia/Tokyo

e. rootのパスワードを設定

echo -e "YOUR-PASSWOR\nYOUR-PASSWORD\n" | sudo passwd root

YOUR-PASSWORDの部分を任意のパスワードに置き換えて入力します。
f. カーネルのアップデート

echo y | sudo rpi-update ; sudo reboot

ここで再起動しますので再び sshでログインしたら

g. パッケージのアップデート

sudo apt update; sudo apt -y full-upgrade
sudo apt -y autoremove; sudo apt autoclean

でセットアップが完了です。

2-4-4. セットアップおまけ

以下のコマンドは必要であれば実行しておきます。
h. ホストネームの変更

sudo raspi-config nonint do_hostname hoge

g. SDカードを長寿命化するため /tmpフォルダを RAMディスク化

echo tmpfs  /tmp tmpfs defaults,size=256m,noatime,mode=1777 0 0 | sudo tee -a /etc/fstab

h. 同上 /var/logフォルダを RAMディスク化

echo tmpfs  /var/log  tmpfs defaults,size=16m,noatime,mode=0755 0 0 | sudo tee -a /etc/fstab

/var/logフォルダをRAMディスク化する場合は、一度作られたフォルダがないとアプリケーションによっては動作不良になってしまう場合があるので注意が必要です(sanba等)。再起動で消えてしまったフォルダを起動時にスクリプトで再作成しておく必要があります。

以上のコマンドは再起動すると有効になります。

〜 続く 〜

◯現在快調に動作中

本来WiFi電波が届かないところに電波を届けるため、中間地点くらいにバケツリレー用のラズパイ(NODE)をおき

NTPを利用した時計を表示させるラズパイ(NODE)をおくとあら不思議。

インターネット通信してNTPからキチンと正しい時刻を取得し表示しています。中継機の電源を切るとネットが途切れ時間が狂うのでバケツリレーは正しく動作しているようです。メッシュネットワーク、かなり便利なツールの予感がし始めています。

CCS811・BME280・BH1750を使ったCO2データロガーの製作(3) マメタン実験編

◯やりたいこと

動作実験中のCO2ロガーで、実際に豆タンアンカを使用した際のCO 2濃度を測ってみる。

◯やったこと

豆タンを使っている寝室に測定器を置いて実際に一晩測ってみました。その結果驚きの事実が…。

使用する豆炭アンカはメジャーなミツウロコ製。それにワンタッチで火が付くマメタンを利用して火をセットします。もちろん熾火になるまで外に置いておくのは鉄則です。

それを布団の中に入れ脇にCO2ロガーをセットしておいたところ

なんか量子的な変化。センサーの癖なのか布団をバフバフしたせいでCO2がポンと上がったのか。
いずれにしてもしばらくおいておいたらCO2濃度が2600ppmを超えてきましたので

24時間換気のスイッチを入れました。(ちなみに住宅内の推奨CO2濃度は1000ppm以下です。)
その時の減少推移はこんな感じ。

1時間後 CO2は 200ppm 、VOCは350ppbの減少です。

昔のスカスカな家ではこれが天然で行われていたんだろうなあとヤボな事を考えながら換気スイッチを切り就寝。現金なものでスイッチを切ったらしっかりCO2が上昇し始めていました。

そして翌朝、驚きのサムネ写真。

CO2は3700ppm、VOCは4000ppbを超えグラフを振り切ってしまっていました。おそろしい。
CO2濃度は事務所内規定値の 5000ppmは超えていませんでしたがVOCの高濃度には愕然。豆炭独特のにおいの元はこれだったんでしょうか。
この値が正確かどうかはまだわかりませんが、何気に使っている豆炭の危険性を改めて認識。CO2ロガーを作ってみようと思ったのは正解、てな感じでしょうか。

◯やってみて

身近な豆炭の危険性を再認識。ロガーは未だブレッドボード上にバラックで組み立てた状態ですので測定値の正確性を検証するためにも早いとこケースに入れてしまおうと考え始めました。次回ケース化のレポートができればと考えています。

◯その他雑談

焼き上がったマメタン、今年は手あぶり火鉢なるものを買ってみたのでその灰になってくれています。

テレビを見ながら火ばしでサクサク細分化。

いい「ながら作業」アイテムです。

◯その後

測定データの加工方法でグラフがどう変化するかをチェックしています。

1つ目の山 1回あたり5回測定しその平均値を記録
2つ目の山 1回あたり10回測定しその中央値を記録
3つ目の山  同上 で電池切れのため異常値を記録
4つ目の山 測定毎に行なっていた温度補正を温湿度固定で測定

CCS811・BME280・BH1750を使ったCO2データロガーの製作(2) 回路の動作実験

◯やりたいこと

(1)で作成した回路をブレッドボード上に組み、とりあえずセンサーで実際に測定してみる。

◯やったこと

・CCS811モジュールの準備

今回はCCS811モジュールとして動作電源が 5Vのタイプと

チップ端子が直接出力されていて 3.3V動作用タイプの

2つを準備しました。5V動作用のモジュールはarduino用として売っていたものですが、パターンを追ってみるとレギュレータを通して内部 3Vで動作しており、単に出力信号線を 5Vへプルアップしているだけのいわゆる 5Vトレラント回路となっていました。そのためレギュレータのドロップアウトを考えてもなんとか 3.3Vで動作させる事が出来そうな感じでしたので、どちらも同じ回路で実験してみる事にします。

・実験回路組立て

いつも通りブレッドボードに実験する回路を組んでいきます。
まずは(1)で実験済のリセット回路と配線。

その上にCCS811 とOLED、

ESP-WROOM-02

BME280をセットすると

組立てが完了です。

・動作確認

実を言うとうまく動作するまでには相当苦労させられました。何たってライブラリに付属しているサンプルスケッチではうまく動作してくれなかったのです。WDTを利用したハードウエアリセットを多用するスケッチなのですがどうもバグが潜んでいるようです。困ったもんです。

先輩諸氏の組まれたスケッチやライブラリを読み込んであーでもないこーでもないとあちこちいじり回しやっと動作した写真がこちら。

deepSleepせずに 1分おきにループして測定を続け、データをOLEDに表示・WiFi送信するという単純なスケッチでついに測定に成功しました。

グラフは夜0時過ぎから測定を開始し、朝起きて足元が寒かったのでカセットガスストーブを焚いて消すまでのデータを記録しています。記録されたCO2濃度は概ねその行動パターンに追付いしていますので無事動作しているのは間違い無いでしょう。

起動から2分間の電流波形は

となっており、起動時にWROOM02がフルで電流を消費、その後CCS811が起動してさらに消費電流が増えています。一定時間経過後 wroomが MODEM_SLEEPに入ると消費電流が約 50mAへと減少し WiFi接続継続用に瞬間的に消費電流が増えるというパターンを繰り返しています。

ちなみに電源投入時には 342mAを記録しており、

コンデンサの突入電流も加味されているとはいえ電源周りをしっかりと組む事を改めて意識です。

◯やってみて

とりあえず CO2測定には成功しましたがこのままでは消費電力が大きくとても電池動作というわけにはいきません。USBから給電しながら電池も充電しながらという事で電源周りの回路追加は必須な様です。省電力化という事でCCS811 の立ち上げまわりのノウハウ取得もいろいろと実験で確かめていく必要がありそうです。今回も少々長丁場になりそうです。

・その後の測定1

午後の部屋のCo2変化グラフ。

部屋に人が入るとポンとCO2濃度が上がりますが、その後不在になると24時間換気の影響で徐々に濃度が下がっていきます。3山目以降は複数人が部屋に常にいたため濃度上昇度合いが高くなっていますがやはり換気の影響で徐々に濃度が下がっていきます。24時間換気ってしっかり活躍しているんですね。

最後の大きな山は台所で夕食の準備が始まった時。急激に濃度が上昇し調理中は高濃度を維持しています。IHなのでガスは出ないはずなんですが食材からでもVOCが出ているんでしょうか。
とはいえ調理後は順調に濃度は下がり、途中換気扇をつけたところ下がり方が急になって 1時間で900ppmほど下げています。さすが換気扇。ただ温度も 0.5℃ほど下がり足下がスースーしたのも事実ですが…。
まだ実験段階ですが、面白いデータが取れてます。

ちなみに電流計の測定精度を下げ(16Bit->14Bit)、サンプリングレートを60SPSに上げた電流計でプロットした電流グラフ。

ふむふむ、なるほど…。
スケッチのバグを発見です。

CCS811・BME280・BH1750を使ったデータロガーの製作(1) 回路図作成・リセット回路の実験

◯やりたいこと
最近やたら値段が上がっているマメタンアンカ、

中国の大キャンプブームのせいかと思っていたらウクライナの越冬向けにも寄付を募っているニュースが出たりして世界的に需要が高まっているよう。我が家にも現役アンカがあるのですが、今年もぬくぬくに備えそろそろ準備を始める事にしました。

そこで必要になるのが酸欠防止用のCO2センサー。あちこちで暖房に活躍してもらうため普段使い用にCO2センサー(CCS811)+温湿度・気圧センサー(BME280)+照度センサー(BH1750)を組みあわせた携帯型データロガーを作ってみる事にしました。

主な機能は以下の通り。
1. 一定間隔でデータをWiFi転送するロガー機能
2.リセットスイッチによる手動起動機能を持たせその際はOLEDにデータを表示
3. CO2濃度によるブザー警報機能
4. 電池動作

◯やったこと

・回路設計

各センサーはESP-WROOM-02のI2C通信を利用して制御し各々の省電力モードに期待して常時通電を基本にします。特にCCS811は常時通電しておかないと正確な値が出ないようです 。ただOLEDは常時点灯が不要ですので起動時にリセットスイッチをセンスしオンであれば電源を入れるようにします。

リセットパルスはSW入力を微分してワンショットパルスを作成しマイナス側の電圧をカットするためFETで受けてWROOMに入力しています。リセットパルスの幅は必要最低限にしてWROOMを素早く起動させ、スイッチが離される前にその状態を読み込んで手動起動かを確認するという作戦です。これに関してはうまくいくかどうか後ほど実験してみます。

以上の点を検討して作成した回路図は以下の通りです。

・リセット回路

まずはリセット回路が予想通りに動作するか実験してみます。

この間作った電源がさっそく活躍してくれています。
回路図ではコンデンサが1μFですが写真は0.1μF(時定数10ms)で行っている時の様子です。この時の微分回路出力とFET出力をハンディオシロで確認してみると


(水色:微分回路出力 黄色:FET出力)

SWを相当早く押してみましたがリセット起動後SWがOFFになるまで50ms以上ありましたので普通に押してる分には問題なく手動起動を検知してくれると思います。リセットパルスの幅の実測値は 9msほど。まあまあいい感じです。

この回路で起動後 delay()5秒、deepSleep()10秒を繰り返すスケッチを組み

タイマー起動時はLED消灯、リセットスイッチによる起動はLEDを点灯させてみると

バッチリ。
予定通りうまく動作してくれています。

この時の電流計のログ。
1番右の山がdeepSleep()中にリセットスイッチで起動した部分。定期起動部分に比べ LEDが点灯した分電流値が増えています。

◯やってみて

起動方法が確定したので次回実際にセンサーをつないで動作試験を行なってみます。

MCP3425(16Bit ADC)を使った電流計の製作(5) 実機の製作 完成編

◯やりたいこと

(3)、(4)で製作したボードとケースを組立て、以下の仕様でスケッチを作成し電流計を完成させます。
○仕様
・供給電圧 3.3V(max 800mA)
・電流測定範囲 (トグルSW切替)
  High:1024mA〜10mA
  Low:256mA〜1mA
・電流ロギング機能 (WiFi転送)
  10sec〜6min (プッシュSW切替/長押しスタート)
・単3電池 3本

電流の測定範囲はシャント抵抗の影響もあり現実的には最大値の 1/10程度です。あくまでも「測定可能範囲」です。

◯やったこと

・組立て

(3)で作成したメインボードと(4)で作成したケースを合体させます。

組み立てる前にまずWROOM-02のピンヘッダ加工をしておきます。ピンヘッダは丸ピンソケットに対し足が長いためそのままだとムダにボードの高さが高くなるためです。

1.5mmのボード2枚を使って足の長さを確保しフラットカットニッパでバチバチ切断。

これで1.5mm程高さを低くすることができます。

OLEDは付いていたピンソケットを外して配線を引き出しておき、

ケースに実装して必要ヶ所をつなげば

電源付き電流計の完成です。

・スケッチの作成

仕様に従い(2)のスケッチに
WiFiクライアント動作
・電流表示モードと電流記録(ロギング)モードを作成
・ロギング時間設定/モード開始用にSWを追加

を追加しました。

/**
*
*    MCP3245(16Bit ADC)電流計 
*               WR02_WiFicli_ADC_OLED v0.1.1 (ok)
*
*/
// Standerd Library (IDE v1.8.57.0)
#include              <Arduino.h>
#include              <Wire.h>
 
// Board Library (ESP8266 v2.7.2)
/* ESP8266 Boards(v2.7.2)/Generic ESP8266 Module */
#include              <ESP8266WiFi.h>
#include              <WiFiClient.h>        // wifi_set_sleep_type()

// Install Library
/* OLED */
#include              <Adafruit_SSD1306.h>  // v2.5.7

// Global Value
/* WiFi */
#define CONN_SSID     "YOUR SSID"
#define CONN_PASS     "YOUR PASSWORD"
boolean wifi_mode =   false;

/* My ID,IP,MAC */
IPAddress ip          (YOUR IP);
IPAddress gateway     (YOUR GATEWAY);  // ex. 192,168,0,1
IPAddress dnServer    (YOUR DNS);
IPAddress netmask     (YOUR SUBNET);   // ex. 255,255,255,0

/* UART */
#define TX            1         // D1
#define RX            3         // D3

/* I2C */
#define I2C_SDA       2         // D2
#define I2C_SCK       0         // D0
#define I2C_CLK       100000    // fSCL=100KHz

/* SW */
#define SW            TX 
#define SW_on         LOW
#define SW_off        HIGH

/* OLED(SSD1306) */
#define OLED_ADR      0x3C      // I2C Address
#define SCREEN_WIDTH  128       // OLED display width, in pixels
#define SCREEN_HEIGHT 64        // OLED display height, in pixels
#define OLED_RESET    -1        // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306      display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
unsigned long
        dsptime   =   0;

/* ADC(MCP3245) */
#define ADC_ADR       0x68      // I2C Address
#define ADC_REF       2.048     // [V]:Voltage Reference
float   curr_max  =   0;
float   curr_min  =   0;
boolean curr_peek =   false;

/* logging 
*   log_max 5000:341sec 3000:212sec 1000: 70sec
*            450: 30sec  300: 20sec  150: 10sec */
boolean log_mode  =   0;        // 0:表示中 1:ロギング中
uint8_t log_time  =   0;        // 記録時間 10s,30s,1,2,3,4,5,6m
int     log_max[] =   {150,450,900,1800,2700,3600,4500,5400};
int     cunt      =   0;
/* Tag name:log_struct, member:mill,curr */
struct  log_struct {
  long    mill;
  float   curr;    };
struct  log_struct    logg[5400]; // 5400:RAM 70964(86%)

///// ハードウエア 初期設定
void setup() {
  /* Sleep Mode */
  wifi_set_sleep_type(MODEM_SLEEP_T);
  Serial.end();

  /* Pin Mode */
  pinMode(TX, INPUT_PULLUP);
  pinMode(RX, INPUT_PULLUP);
  
  /* I2C */
  Wire.begin   (I2C_SDA, I2C_SCK);
  Wire.setClock(I2C_CLK);

  /* OLED(SSD1306) */
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADR);
  /* OLED 起動表示(splash.h) */
  display.display();

  /* WiFi */
  WiFi.config(ip, gateway, netmask, gateway);
  unsigned long timeout = millis();
  while(millis() - timeout < 5000) {
    if(wifi_connect()) {wifi_mode = true; break;}
  }
}

///// メインルーチン
void loop() {
  /// 変数 初期設定
  /* レンジ切替変数 */
  float   SHUNT, GAIN, MAX;
  uint8_t DIGIT;
  byte    CMD;
  /* 測定用変数 */
  float   curr, shnt;
  byte    conf;
  
  /// 測定レンジ設定 (SWのチャタリング未チェック)
  if (digitalRead(RX)) {
    // HIGH Range(max:1.024A)
    GAIN  = 2;          // [倍]:PGA Gain
    SHUNT = 0.1;        // [Ω]:Shunt Resistor
    DIGIT = 2;          // [桁]:表示する小数の桁数
    CMD   = 0b10001001; // ADC 設定コマンド
    MAX   = 2047;       // 最大値
  }
  else {
    // LOW Range(max:256mA)
    GAIN  = 8;
    SHUNT = 1;
    DIGIT = 3;
    CMD   = 0b10001011;
    MAX   = 511;
  }

  /// ADC 設定 コマンド送信 (Configuration Register)
  /*   Bit  7: _RDY
  /*   Bit6,5: channel
  /*   Bit  4:  1=連続    0=ワンショット測定
  /*   Bit3,2: 00=12Bit 01=14Bit 10=16Bit 11=18Bit
  /*   Bit1,0: 00=x1    01=x2    10=x4    11=x8 */
  Wire.beginTransmission(ADC_ADR);
  Wire.write(CMD);
  Wire.endTransmission();
  
  /// 測定完了待ち
  /*   18Bit: 3.75SPS=270ms
  /*   16Bit:   15SPS= 67ms
  /*   14Bit:   60SPS= 17ms
  /*   12Bit:  240SPS=  5ms */
  delay(67);

  /// ADC data,config 受信(1sec以内)
  conf = 0x80;
  unsigned long timeout = millis();
  
  while(millis() - timeout < 1000) {
    // データ(3Byte)要求
    Wire.requestFrom(ADC_ADR, 3);
    // 3Byte未確定は 10mS待機を j回だけ実施
    for (uint8_t j=0; j<3; j++) {
      if(Wire.available() >= 3) {
        // ADC i2cデータ -> 数値変換
        shnt =(Wire.read()<< 8)+ Wire.read();
        conf = Wire.read();
        break;
      }
      delay(10);
    }
    // 受信データ確定(conf Bit7=0)で測定終了
    if (conf<0x80) break;
    delay(10);
  }

  /// 電圧->電流値変換 基準電圧:ADC_REF
  /*   ADC:12Bit 1mV       240SPS (-2048~2047) 
  /*       14Bit 250uV      60SPS (-8192~8191) 
  /*       16Bit 62.5uV     15SPS (-32768~32767)
  /*       18Bit 15.625uV 3.75SPS (-131072~131071) */
  shnt = shnt/32767;      // 測定精度 16Bit
  shnt*= ADC_REF/GAIN;    // 測定倍率 PGA Gain x2,x8
  shnt*= 1000;            // 表示単位 mA
  if (shnt>MAX) shnt=0;   // MAXを超えた値はエラー
  curr = shnt*(1/SHUNT);  // シャント抵抗倍率

  /// max,min計算
  if (curr_max < curr) {
    // ピーク値更新
    curr_max = curr;
    curr_min = curr;
  }
  else {
    // 最小値更新 チェック
    if (curr_min>curr && curr!=0) curr_min = curr;
  }

  /// Display/logging 判定
  if (!log_mode) {
    // データ表示 modeの場合 key check
    switch(sw_in()) {
      case 0: break;            // key入力なし
      case 1: {                 // 短押し
        // 記録時間変更
        uint8_t ele = sizeof(log_max)/sizeof(int); // 要素数
        log_time = (log_time<=ele-1)? log_time+1 : 0;
        // curr_min,max 初期化
        curr_max = 0; curr_min = 0; curr_peek = false;
        break;
      }
      case 2: log_mode = true;  // 長押し
    }
    // データ表示 (500ms毎)
    if ((millis()-dsptime)>=500) {
      dsp_curr_data(curr,shnt,DIGIT);
      dsptime = millis();
    }    
  }
  else {
    // データ収集(logging) mode 
    if (cunt==0) {
      // logging表示
      display.fillRect(  0,  1,128, 16,BLACK);
      display.setTextSize(1);
      display.setCursor( 32, 5);
      display.print("Logging...");
      display.display();
    }
    // データ格納
    if (cunt<log_max[log_time]) {
      logg[cunt].mill = millis();
      logg[cunt].curr = curr;
      cunt          += 1;
    }
    // データ送信
    else {
      if (wifi_mode) {
        // 送信モード 表示
        display.fillRect (  0, 1, 82, 16,BLACK);
        display.setCursor( 32, 5);
        display.print("Sending");
        cunt = 0;
      
        // データ送信
        for (int i=0; i<log_max[log_time]; i++) {
          // 送信状況表示
          display.fillRect ( 82, 1,128, 16,BLACK);
          display.setCursor( 82, 5);
          display.print(i);
          display.display();
        
          // DATA送信
          /*
          *    ここに 
          *      logg[i].mill
          *      logg[i].curr
          *    をWiFi転送するスケッチを書込む
          */
        }
      }
      log_mode = false;
    }
  }
}

///// OLED Control /////
/* 電流計表示 */
void dsp_curr_data(float cur, float shn, uint8_t dig) {
  char    buf1[9], buf2[21];
  
  if(true) {
    display.clearDisplay();
    display.setTextColor(WHITE);
    
    /* Current */
    display.drawRect   (0, 0, 127, 18, WHITE);
    display.setTextSize(2);
    display.setCursor  (  14, 2);
    dtostrf            (cur, 7, dig, buf1);
    sprintf            (buf2, "%s", buf1);
    display.print      (buf2);
    display.setCursor  (102, 2);
    display.println    ("mA");

    /* log_modeing mode */
    display.setTextSize(1);  
    display.setCursor  (  2, 6);
    display.print      (log_time+1);
    
    /* Bus-V */
    display.setCursor  ( 12, 22);
    display.println    ("Bus-V :    3.30  V");
    /* Shunt-V */
    display.setCursor  ( 12, 30);
    dtostrf            (shn,8,2,buf1);
    sprintf            (buf2, "ShuntV:%s mV", buf1);
    display.println    (buf2);
    /* Power */
    display.setCursor  ( 12, 38);
    dtostrf            ((cur*3.3),8,2,buf1);
    sprintf            (buf2, "Power :%s mW", buf1);
    display.println    (buf2);
    
    /* max current */
    display.setCursor  ( 12, 48);
    dtostrf            (curr_max,8,2,buf1);
    sprintf            (buf2, "max   :%s mA", buf1);
    display.println    (buf2);
    /* min current */
    display.setCursor  ( 12, 56);
    dtostrf            (curr_min,8,2,buf1);
    sprintf            (buf2, "min   :%s mA", buf1);
    display.println    (buf2);

    display.display();
  }
}

///// WiFi Control /////
/* WiFi接続開始処理 -> True:WiFi接続完了, False:WiFi接続失敗 */
boolean wifi_connect() {
  // WiFi 接続サイクルスタート(接続->確認->再接続) 3トライ
  for(int i = 0; (i < 2); i++) {
    // WiFi接続 接続が記憶されていない場合接続情報を記憶させ次回自動接続にする。
    if (WiFi.SSID() != CONN_SSID) {  
      WiFi.persistent(true);
      WiFi.mode(WIFI_STA);
      WiFi.setAutoConnect(true);
      WiFi.begin(CONN_SSID, CONN_PASS); 
    }

    // 5秒間 0.5秒毎に接続確認
    unsigned long timeout = millis();
    while(millis() - timeout < 10000) {
      // 接続できた場合 Trueリターン
      if(WiFi.status() == WL_CONNECTED) return true;
      // 未接続は 500ms待ちしてループ
      delay(500);
    }
  }
  // WiFi 接続不可 エラーリターン
  return false;
}

/* WiFi サーバ接続・DATA送信・切断処理 */
boolean data_send(String sendData, String ip, int port) {
  WiFiClient client;

  // DATA 送信先サーバー接続 (3秒間 接続確認)
  unsigned long timeout = millis();
  while (millis() - timeout < 3000) {
    if (client.connect(ip, port)) {
      delay(1);
      // 接続したら DATAはすぐに送信
      //client.println(sendData);  // (CR+LF)が2パケット目で送信される
      client.print(sendData+"\n"); // 1パケット送信で済む

      // 送信完了後切断
      client.stop();
      delay(1);

      // Trueリターン
      delay(100);
      return true;
    } 
    // 接続できなかった場合,0.3-0.5秒おきに再接続
    else delay(250+random(50,250));
  }
  // 接続できなかったので エラーリターン
  delay(100);
  return false;
}

///// SW Control /////
/* SW Scan (チャタリング中はリターンしない) */
boolean sw_scan() {
  while (true) {
    int8_t c = digitalRead(SW);
    delay(50);
    if (c==digitalRead(SW)) {
      return (c==SW_on)? true:false;
    }
  }
}

/* SW入力 未入力:0 短押し:1 長押し(2sec):2 */
uint8_t sw_in() {
  if(!sw_scan()) return 0;
  for(uint8_t i=0; i<40; i++) {
    if(!sw_scan()) return 1;
  }
  return 2;
}

(2022.10.06 v0.1.1b改定 1.最小電流値はピーク値記録後の値に変更 2.ロギング時間変更でmin,maxクリア)

起動時の OLEDには初期設定値の Adafruitロゴを表示させていますが、Adafruit_SSD1306ライブラリ内のsplash.hのデータを変えると任意のオープニング表示が可能です。

またサンプリングレートを向上させるため
・ロギングモード中は電流値の表示をせず値の収集に専念
・収集データは structを利用してメモリ上に記録し、収集時間終了後一気にWiFiで送信

という処理を行なっています。その結果サンプリングレートは 14.7SPSと ADCの 15SPSに近い値になっており測定中に電流値を見られないという不便もガマンの範囲内かなというところです。

測定時間は log_max[ ] 内に定義すればロギング時間切替SWで順次切替ができ、SWの長押しでロギングがスタートします。今回のスケッチでは10s,30s,1〜6minの8つの時間を登録しており、測点数は5400個(6min)分を確保しています。5400測点でメモリ使用率が86%まで増加しコンパイル時に「スケッチが使用できるメモリが少なくなっています。動作が不安定になる可能性があります。」と警告が出てきますのでこの辺で止めています。

・動作試験

さっそく電子負荷をつないでいろいろな条件を与えてみます。
LOWモードでは 256mAでメーター振り切れ。

HIGHモードでは 500mAを流してみました。

電子負荷のLED表示にはかなり誤差があり写真ではだいぶズレた数値が表示されていますが、電流が多めの範囲ではやはりシャント抵抗による電圧降下は大きめです。

そしてこの電流計のアピールポイントである電流のロガー機能。収集データは我が家の「えだまめ」ネットワーク(ラズパイ)内SQLサーバーに転送しており、そのデータをグラフにしてみました。

まずは10secのロギング。

測点が少ないのでドット間のスキマガ大きく電流の変化がわかりやすいですね。グラフ左上に表示されているようにサンプリングレートは 14.69SPS。逆算して1回あたり68msの測定時間。ADCの変換時間以外は1msしか使っていない勘定です。
グラフで電子負荷の出力が100%になるまでの測点を数えると10個。1点68msとすると負荷の立ち上がりに700ms近くかかっているのがわかります。

続いて 30sec、60secのロギング結果。

電子負荷の立ち上がり・立ち下がり時間がかろうじてわかるかな〜という感じです。
そしてロギング時間最大の 6分。

負荷状態をいろいろ変えてみましたがキチンと追従しているようです。
どうやら3.3V電源供給型電流計、簡単に言うと3.3V電源(電流計付き)が無事完成したようです。

◯やってみて

これでブレッドボードの実験時に簡単に電源を供給することができるので「超便利!」と気分が高揚していたのですが、実は現状で大きなミスをしている事を発見。それは何かというと…

「電源スイッチのつけ忘れ」

なんと、しょうもない。

この際だから OLEDの電源を FETで電源制御して deelSleep()を利用したオートパワーオフ機能を追加しようかと考えてました。起動はリセットスイッチです。電流計 ver1.1の仕様がさっそく決定です。

MCP3425(16Bit ADC)を使った電流計の製作(4) 実機の製作 ケース編

やりたいこと

(3)で製作したボードを実装するケースを加工する。

◯やったこと

・ケース選定と部品配置

今回使用するケースはTAKACHI の SW-85。

このケースにこんな感じで部品を配置します。


・加工

プラスチックケースは加工が簡単に済むので助かります。ドリルは乾電池式で十分加工が可能ですし刃も木工・プラスチック用の刃先で用が済むので安上がり。

穴を拡大するシャーシリーマも切れ味抜群で気持ちがいいほど。

ただヤスリは目づまりしやすいのでこまめな掃除が必要です。

必要な径より少し小さめの穴をドリルで開け、

リーマで必要サイズまで大きくします。

OLED用の四角い穴はドリルで何カ所か穴を開けた後リーマでギリギリまで穴を大きくしヤスリで仕上げていきます。いつものことですが四角い穴は加工が難しいですね。

全部の穴を開けたあとはヤスリでバリ取りをし消しゴムでケガキ線を消すとケース加工は終了。

外装部品を取り付けるとケースが完成です。

OLEDに関しては配線接続後接着剤で固定する予定。
最終的なフロント裏面の内部実装はこんな感じになります。


◯やってみて

ケースサイズの割に端子が大きめで、ケースの厚さもあるため少々ずんぐりむっくりな電源になりそうです。

・トグルスイッチ…

トグルスイッチを取り付ける際に共回りを防止するフック付きワッシャー、

表側につけた方がカッコいいと思うのは私だけでしょうか…。

MCP3425(16Bit ADC)を使った電流計の製作(3) 実機の製作 ボード編

◯やりたいこと

(1)、(2)の動作実験で得られたデータを元に実機の最終回路を決定しユニバーサルボード上にその回路を組む。

◯やったこと

・作成回路図の最終決定

作成する電流計付き電源の最終回路図を決めます。(1)に比べて以下の点を追加しました。

1. 電源として供給する3.3Vと、電流計を動作させる3.3Vを2つのレギュレータで別々に供給
2. シャント抵抗を2種類にして電流測定レンジをHIGH,LOWの2つに拡大
3. ロギング専用モードのトリガースイッチを増設

以上3点をグレードアップした回路図が以下の通り。

WiFi 電流計ロガーに変身です。

・ケース選定

利用するケースによって回路を組むボードのサイズが変わりますので最初に使うケースを決めておきます。今回は TAKACHIの SW-85を使うことにしました。

配置はこんな感じ。

フロントはパカッと外せるフタ側に組み立てることにし、電池は奥のケース側に収めます。
ちなみにこのケース2は 18650 2本も収納可能で、

電源の2系統化も可能です。

・回路作成

回路を組み上げるユニバーサルボードは秋月電子のタイプDボードを使い、それを前提に部品を集めます。

(1)で紹介した
ESP-WROOM-02
・16Bit ADC MCP3425
・3端子レギュレータ NJM2845
・0.96インチ 128×64ドット有機ELディスプレイ(OLED) 白色

の他、
秋月電子 タイブDボード
・100mΩ シャント抵抗
・10KΩ 抵抗
・100uF、0.1uF チップコンデンサ
・ピンソケット、ピンヘッダ

を準備します。全て秋月電子で入手可能です。
その他実験時にかなり熱くなったレギュレータの放熱対策として、ラズパイ用のヒートシンク

熱伝導シールでチップに貼り付けることにします。

んでもって組立て。

裏面。

組立て直後はフラックスやハンダクズで相当汚れていますので

フラックス除去剤、無水エタノールを使って

歯ブラシなどでゴシゴシキレイに仕上げます。

ただ安い中華製のモジュールなどではあまり強くこすると表面がはがれてしまう場合がありますので注意が必要です。
あとはイモハン部分にハンダを盛ったりしてお化粧すればサッパリ。

テスト動作用に電源取出しピンソケットを追加して

MCP3425,WROOM-02を取り付けると

本体ボードの完成です。

・動作試験

さっそくボードに周辺部品を仮付けして動作試験を行います。

ん〜、順調。
電子負荷もつないでみて実際に電流負荷をかけてみると

500mA流してもいい感じ。一安心です。
次回このボードをケースに組み込んでいきたいと思います。

◯やってみて

いたずらでWiFiを動かして測定電流値をロギングしてみました。
ラズパイネットワークのSQLサーバーにWiFiで転送したデータを matplotlibでグラフ化してみると

それなりにうまく動いてくれているようです。
現状では250〜300ms/回程度のサンプリングレートになっています。
しばらく動かしてみてハード面のデバッグを進めていきます。

MCP3425(16Bit ADC)を使った電流計の製作(2) スケッチの作成

◯やりたいこと

(1)で製作した電流計付き電源のスケッチを作成する。

◯やったこと

シャント抵抗の電圧をAD変換し電流値に変換してOLEDに次のように表示します。

スケッチは以下の通り。

/*
*
*    MCP3245(16Bit ADC)電流計 WR02_ADC_OLED v0.0.4b
*
*/
// Standerd Library (IDE v1.8.19)
#include              <Arduino.h>
#include              <Wire.h>

// Board Library
/* ESP8266 Boards(v2.7.2)/Generic ESP8266 Module */
#include              <WiFiClient.h>        // wifi_set_sleep_type()

// Install Library
/* OLED */
#include              <Adafruit_SSD1306.h>  // v2.5.7

// Global Value
/* UART */
#define TX            1         // D1
#define RX            3         // D3

/* I2C */
#define I2C_SDA       2         // D2
#define I2C_SCK       0         // D0
#define I2C_CLK       100000    // fSCL=100KHz

/* OLED */
#define OLED_ADR      0x3C      // I2C Address
#define SCREEN_WIDTH  128       // OLED display width, in pixels
#define SCREEN_HEIGHT 64        // OLED display height, in pixels
#define OLED_RESET    -1        // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306      display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
unsigned long dsptime = 0;

/* ADC */
#define ADC_ADR       0x68      // I2C Address
#define ADC_REF       2.048     // [V]:Voltage Reference
#define SHUNT         0.1       // [Ω]:Shunt Resistor
float curr_max =      0;
float curr_min =      9999.9;

void setup() {
  // ハードウエア 初期設定
  /* Sleep Mode */
  wifi_set_sleep_type(MODEM_SLEEP_T);
  Serial.end();
  
  /* I2C */
  Wire.begin   (I2C_SDA, I2C_SCK);
  Wire.setClock(I2C_CLK);

  /* OLED(SSD1306) */
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADR);
  //display.begin();
 
  /* OLED画面初期表示 */
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.setCursor(  0,  0);
  display.println("SSD1306");
  display.setTextSize(1);
  display.setCursor(  0, 19);
  display.println("OLED Start.");
  display.display();
  delay(1000);
}

// 
void loop() {
  // 初期設定
  char  buf1[9],  buf2[21];
  float shnt=0.0, curr=0.0;
 
  // ADC 設定 コマンド送信 (Configuration Register)
  /*   Bit  7: _RDY
  /*   Bit6,5: channel
  /*   Bit  4: 1=連続 0=ワンショット測定
  /*   Bit3,2: 00=12Bit 01=14Bit 10=16Bit 11=--
  /*   Bit1,0: 00=x1    01=x2    10=x4    11=x8 */
  Wire.beginTransmission(ADC_ADR);
  Wire.write(0b10001001);
  Wire.endTransmission();

  // データ確定待ち(16Bit:15SPS=67ms)
  delay(100);

  // ADC data,config 受信(1sec以内)
  unsigned long timeout = millis();
  while(millis() - timeout < 1000) {
    // データ(3Byte)要求
    Wire.requestFrom(ADC_ADR, 3);

    // 3Byte未確定は 10mS待機を 3回だけ実施
    byte  conf=0x80;
    for (uint8_t j=0; j<3; j++) {
      if(Wire.available() >= 3) {
        // ADC i2cデータ -> 数値変換
        shnt =(Wire.read()<< 8)+ Wire.read();
        conf = Wire.read();
        break;
      }
      delay(10);
    }
    // 受信データ確定(Bit7=0)で測定終了
    if (conf<0x80) break;
    delay(10);
  }

  // 電圧->電流値変換 基準電圧:ADC_REF shunt抵抗値:SHUNT
  /*   ADC:12Bit 1mV   240SPS (-2048~2047) 
  /*       14Bit 250uV  60SPS (-8192~8191) 
  /*       16Bit 62.5uV 15SPS (-32768~32767) */
  shnt = shnt/32767;      // 測定精度 16Bit
  shnt*= ADC_REF/2;       // 測定倍率 2倍(max1.024A)
  shnt*= 1000;            // 表示単位 mA
  if (shnt>2047) shnt=0;  // 2047を超えた値はerr
  curr = shnt*(1/SHUNT);  // シャント抵抗倍率

  // max,min計算
  if (curr_max<curr)            curr_max=curr;
  if (curr_min>curr && curr!=0) curr_min=curr;

  // 表示
  if ((millis()-dsptime)>=100) {
    display.clearDisplay();
    display.setTextColor(WHITE);
    
    /* Current */
    display.drawRect(0, 0, 127, 18, WHITE);
    display.setTextSize(2);
    display.setCursor(  2, 2);
    dtostrf(curr,8,2,buf1);
    sprintf(buf2, "%s", buf1);
    display.print(buf2);
    display.setCursor(102, 2);
    display.println("mA");
      
    /* Bus-V */
    display.setTextSize(1);  
    display.setCursor( 12, 22);
    display.println("Bus-V :    3.30  V");
    /* Shunt-V */
    display.setCursor( 12, 30);
    dtostrf(shnt,8,2,buf1);
    sprintf(buf2, "ShuntV:%s mV", buf1);
    display.println(buf2);
    /* Power */
    display.setCursor( 12, 38);
    dtostrf((curr*3.3),8,2,buf1);
    sprintf(buf2, "Power :%s mW", buf1);
    display.println(buf2);
    
    /* max current */
    display.setCursor( 12, 48);
    dtostrf(curr_max,8,2,buf1);
    sprintf(buf2, "max   :%s mA", buf1);
    display.println(buf2);
    /* min current */
    display.setCursor( 12, 56);
    dtostrf(curr_min,8,2,buf1);
    sprintf(buf2, "min   :%s mA", buf1);
    display.println(buf2);
   
    display.display();
    dsptime = millis();
  }
}

こまめにコメントを記入していますのでプログラムの流れは大体はつかめると思います。ADCとデータをやり取りする部分には無限ループしないよう3つほど制限をかけており、

1. ADCから読込んだconfigデータのBit7(RDYフラグ)が0になった(=確定値を受信)
2. ADCからの返信データ(3byte)未着待ちは1回10msを3回まで
3. 測定時間は最大1sec

でループから抜け出てきます。

◯やってみて

写真のハードウエアは(1)からちょっとグレードアップしていて、電源供給用に専用のレギュレータが追加されています。そのため少々安心して大きめの電流を流す事が出来ています。

とはいえレギュレータはかなり熱くなりますので、本番の実機では放熱対策を取ろうと考えてます。

MCP3425(16Bit ADC)を使った電流計の製作(1) 回路図の決定

◯やりたいこと

16BitのADコンバーターMCP3425を使って3.3V電源供給型電流計(要は電流計付電源)を作る。

◯やったこと

・回路図作成

I2C通信のMC3425とOLEDをWROOM-02にぶら下げると言う簡単な回路です。WROOM-02のブレイクボードはシンプル版を意識してます。


・部品集め

部品は全て秋月電子で購入しました。主要部品を以下に載せておきます。

ADC MCP3425

主な仕様
・分解能:16bit、ΔΣ
・信号入力:差動入力
・基準電圧源:2.048V ± 0.05%
・アンプゲイン:×1、×2、×4、×8
・変換データレート:15SPS(16bit時)~240SPS(12bit時)
・制御/出力インターフェース:I2C
・電源電圧範囲:2.7V~5.5V
・消費電流:145μA(VDD=3V、連続変換時)

秋月電子DIP変換モジュールを利用します。

細ピンのピンヘッダをはんだ付けしときます。

3端子レギュレータ NJM2845

主な仕様
・出力方式:シリーズ
・出力正負:正電源
・入力電圧:~12.3V
・出力電圧:3.3V
・最大出力電流:800mA
ドロップアウト電圧:0.18V
・許容損失:10W
・パッケージ:TO-252

チップ上の表示は「45 330」 、これをTO-252用ピッチ変換基盤にはんだ付けして利用します。

ちなみに基盤裏側に0.1uFのチップコンデンサを取り付けてあります。

0.96インチ 128×64ドット有機ELディスプレイ(OLED) 白色

主な仕様
・電源電圧:3.3~5V
・制御方式:I2C(IIC)
・制御IC:SSD1306
・解像度:128×64
・表示色:白
・アドレス:0x78(既定)または0x7A(抵抗の付け替えによる切り替え)
・視野角:160°
・使用温度範囲:-20~60℃
・ピンヘッダ:□0.64mm

表示には定番の便利なOLED表示器を利用します。

ESP-WROOM-02

主な仕様
・電源電圧:3.0~3.6V
・消費電流:平均80mA
・対応WiFiプロトコル802.11b/g/n(2.4GHz)
・サイズ:18mm×20mm×3mm
・端子ピッチ:1.5mm
Wi-Fiモード:station/softAP/SoftAP+station
・セキュリティ:WPA/WPA2
・暗号化:WEP/TKIP/AES
・内蔵フラッシュは4メガバイト(32メガビット)です。
・工事設計認証(技適)番号:206-000519

漢字表示も意識してフラッシュメモリが4MBタイプのモジュールを使い、シンプルタイプのブレークボードにハンダ付けしています。RES,ENピンはボード上のパターンに10KΩのチップ抵抗を取り付けてあります。

・製作

まずは回路がキチンと動作するかどうかブレッドボード上に組んで実験してみます。回路自体は簡単ですのでミニブレッドボードにササッと組み上げてしまいます。

最初にディスクリート部品と配線。

ADCを載せ

3端子レギュレータ、

ESP-WROOM-02

最後にOLEDを載せると完成。

ブレッドボードは実験までの手順が簡単で助かります。

・動作試験

前にINA219を使って作った電流計のスケッチを焼き直して動作試験を行ってみます。
まずは電源オン。

お〜、無事動作しているようです。
続いて電子負荷をつないでの実験。

無負荷なのにもう16mAも流れています。電子負荷はゼロでも電気を食うようです。
50mA,100mAと負荷を増加させて電流計の表示をチェック。

初期状態に流れていた16mAを加算すると概ね近場の数値を示していますのでうまい具合に動作しているようです。ただ max,minの表示にバグがあるようです。

◯やってみて

どうやら回路図的には問題はなさそうです。ただスケッチにバグを発見しましたので、しばらくバグ取りして次回完成版のスケッチを紹介したいと思います。

WROOM-02で静電容量式水分計を作る (8)実機製作 本体編

◯やりたいこと

(7)で決めた回路図をもとに測定器本体の製作を行います。プローブのタイマーICをC-MOS化する予定があるため、プローブの本体への取付けは気密性を高める接着を行わず仮組みで止めておきます。

◯やったこと

・回路の製作

本体を格納するケースは単4電池3本の電池ケースがちょうど入る aitendoの防水ケースを使う事にしました。

うわブタが透明なので照度も測れて便利です。
回路はミニブレッドボードサイズのユニバーサル基板に組み上げ、ミニカードスペーサー(MPS-04-0 秋月電子)で電池ケース裏に接着剤で固定する段取りで進めます。
一通り部品を準備したら

組立て。

今回は準備した電解コンデンサやセラミックコンデンサでなく初めてチップコンデンサを使ってみました。小さく収まって便利なのですが、老眼の目には少々取扱いが難しい部品でした。
ソケットにWROOM-02 やおまけで付けた BME280(温湿度・気圧)、BH1750(照度)センサーを取り付けると

完成。

電池ケース裏に基板を固定して一体化します。

ちなみに防水ケースには基板固定用のネジ受けが付いていて

このままでは作成した回路を格納できないので単4電池3本が入る様にリューターで削ってしまいます。

4カ所削ると単4電池が入ります。

全部削ると単3電池も入りますが

高さが取れずフタが閉められなくなってしまうので単4電池で妥協しておきます。
削った後は電池と一体化した回路を格納して完了。

測定器本体の完成です。

・プローブの取付け

測定器は外での利用も想定しているためケースの気密性を確実にしなければなりません。当初は防水コネクタで通信線を引込もうとも考えていたのですが、あまり大げさにするのも何でしたし接触抵抗も気になったので単純にケーブルをゴムブッシュに通してシリコンゴムで固定・防水する事にしました。

ケースにゴムブッシュサイズの穴を開けて

内側にシリコンゴムを塗り

ケーブルを通せば完成。

最終的にケーブルもシリコンゴムで固定化します。温湿度・気圧測定センサーは小穴を開けてのぞき口にセンサーを露出させ同じくシリコンゴムで固める予定ですが、現時点ではまだ「ケース内温度の測定」にとどめておきます。

この実機で本番のロングラン試験に入る事にします。

◯やってみて

実機で6日ほど実稼働してみたところ、温度や稼働時間に関して測定電圧の補正が必要なことが判明しました。

試行錯誤して補正係数を求めたレポートはその(9)で紹介します。

WROOM-02で静電容量式水分計を作る (9)計測値の補正

◯やりたいこと

静電容量式水分計プローブの出力電圧減少(水分率上昇)現象の対策として温度、時間経過の2つをターゲットに補正係数を求める。

◯やったこと

・温度補正

(8)で作成した水分計、1日走らせてみたら水分率が突然ヒョイと上がる現象が起きました。

朝4:40頃。

実はこれ朝起きて部屋の中が暑かったので窓全開で室内の空気を入れ替えた時に起きた現象。

この日の朝は外の方が気温や湿度が低くカラッとした空気。気持ちいい風が室内に入ってきて湿度も急減、温度もあっという間に3℃程下がったのですが同時に水分率も急上昇。

室温が下がると水分率が上がる、水分率が室温と密接に関係していることをヒョンなことから発見です。
最初は湿度が関係するのかなとも考えたのですが、次の日の朝のデータ。


(水分計グラフと温湿度グラフを並べてみました)

5:30にまた水分率がヒョイと上がっていますがこれももちろん朝の換気による室温の低下。

この日は気温が下がりましたが湿度は上昇。やはり関連しているのは温度の様です。
さらに3日分グラフを並べてみるとその差がよく出てきて、

ガチャガチャと変化している湿度ではなく、上に凸している温度と下に凹している水分率に相関関係があるのは間違いなさそう。水分計プローブだと思っていたのが実は温度計プローブだったと言うオチです。もちろん温度はもとに戻るのに水分率はもとに戻らないと言う問題のある温度計ではあるのですが…。

いろいろ調べてみたら、誘電式の水分計に関してまとめた「筑波大学水理実験センター報告 No8 誘電式キャリブレーション」と言う報告書の中に「プローブの出力電圧は温度に比例する」とのレポートがありました。今回のウチの測定結果と一致しますので温度によりプローブ出力が変化するのは多分間違い無いのでしょう。

そこで今回は25℃を補正値ゼロとして実測値から求めた ±8mV/℃の温度補正値を測定電圧に加える事にしました。気温が1℃下がるとプローブ電圧に8mV加算します。これで温度変化に対応する様にします。

・経過時間補正

問題なのが長期的な水分率上昇傾向。6日ほど走らせただけで水分率が14%も上昇しています。

プローブ周りの土の誘電率が安定するまで時間がかかるのか、プローブの中に水が染み込んで実際に水分率が上がっているのか…。さすがに永遠に上がり続けることはないと思いますのでしばらく置いて様子見してみる事にします。当面はここまでの上昇率から求めた実測値 30mV/日を経過時間に応じて加算してみようと考えてました。

…とジタバタしていたら遂に計測水分率が安定化してきてくれました。グラフを記録し損なったのですが、水分率が給水して飛び上がる前の半日程は上昇が止まり温度変化に対応しているだけになっています。

最新2日分だけピックアップ。

水分率もプローブ電圧もほぼ水平で推移しています。電圧で見ると±10mV程度の変化です。ちょっと一安心。
でもウォーミングアップに6日もかかってしまうとは随分とスロースターターな水分計。静電容量式水分計は測定開始までにたっぷり時間がかかる様です。

◯やってみて

実験により以下の知見が得られました。
1. プローブの測定電圧は温度に比例する。測定にあたっては温度も同時に測定して温度補正する必要がある。
2. プローブの測定電圧が安定化するには数日単位の時間を要する。

プローブ電圧の安定化時間に関しては、土質を変化させてみるのははもちろん、変更する事によって結果に変化が出ていた測定時間間隔、ADC変換の精度なども変化させいろいろなパターンを試してみたいと考えています。

○その後

計測を開始して3週間たったグラフがこれ。

測定開始時には漸増傾向があった水分率も6日目に安定化してからはその傾向がなくなりました。水やりをして水分率が急上昇した後は概ね期待通りの漸減傾向。温度補正値をいろいろと変化させながら現在は±12.5mVに設定しています。全体的に思ったほど水分率が減少していないのが正解なのか不明な点です。実験のため週一行っていた水やりを2週間やらずに観察していたのですが、さすがに植物の方が心配になってきたので「水やらず」実験は一旦ここで終了します。

電池電圧の変化に関しては
1. 電池交換による電圧上昇
2. データ送信先がオフライン時に無限ループに入ってしまうバグがありディープスリープに入れずに急速に消耗
3. 送信データ量を減らしたら電圧がポンと上がった

などによるものです。今後は省電力化の実験も進めていきますが、単4電池の供給能力、WROOM02 に対して少々不安を感じてきてます。

○その後2

長期実験3か月、13週目のグラフです。

寒くなって来たせいか乾燥が進んで水分率が元に戻るまで4週間かかることがわかりました。毎週水まきしていた鉢植えの水、冬は一月に一度でいい事を確認です。
現在電池の持ちをよくするため10分おきの測定を30分おきに変更して様子を見ています。