- レストラン混雑度データを提供していた Bluefox の契約がなくなったため、BLE 広告パケットに見える機器数でキャンパスの占有トレンドを自前で測定する装置を作った
- ノートPCでの実験では、小さな空間の実際の混雑度と BLE 機器数が素早く連動し、大きな食堂でも授業前後の移動時間帯のトレンド変化とよく一致した
- Raspberry Pi Zero W は Linux Bluetooth、DBus、クロスコンパイル、ヘッドレス Wi-Fi 設定のため、配備用デバイスとして使いづらくなり、よりシンプルな ESP32 に方針転換した
- 低価格の ESP32-WROOM ボードは約 250〜400 台の機器付近でメモリ問題により不安定だったが、Seeed Studio XIAO ESP32C3/S3 は長期間安定して動作し、最大約1000台の機器検出まで耐えた
- 最終構成は ESP32 が BLE 機器数をスキャンして Cloudflare Functions と D1 に送り、Grafana・NeuralProphet で可視化・予測する方式で、精度補正とプライバシー検証は今後の課題として残っている
消えた食堂混雑度データ
- 大学1年のとき、食堂運営会社は Sodexo で、Sodexo は Bluefox と契約し、食堂内の人数を表示する占有センサーを使っていた
- FOIA 請求で受け取った資料によれば、Bluefox の装置は Bluetooth 広告パケット内のスマートフォンMAC アドレスを数える方式で動作していた
- API 呼び出しを Grafana に接続すると、食堂の混雑度をリアルタイムのチャートで見られ、混む時間帯を避けるのに活用できた
- その後、食堂運営会社が Aramark に変わり、Aramark は Bluefox のような占有数集計契約を結ばなかったため、既存データは消えてしまった
BLE ビーコンを人数の代理指標として使う
- このプロジェクトの核心は、Bluetooth ビーコン数が実際の人数や滞在時間をどれだけうまく代替できるかを確かめることだった
- 人によってはヘッドホンやスマートウォッチなど複数の機器を持ち歩く
- 機器を持ち歩かない人や、スマートフォンの Bluetooth をオフにしている人もいる
- 滞在時間推定では、一意な MAC アドレスの**変動(churn)**を使えるか、Android や Apple など各メーカーの MAC アドレスランダム化がどのような影響を与えるかが変数だった
- 中央サーバーへデータを送る方法としては Wi-Fi が最も自然な選択だったが、すべての場所で手軽に使える Wi-Fi があるわけではなかった
- LoRa もビーコン分布によっては候補になりうるが、実際の到達距離はアンテナ利得と設置位置に大きく左右される
- データ保存では時系列データベースを使うかどうか、長期トレンド予測ではホームカミング週末や期末試験週間のような特殊イベントを除外できるかも検討対象だった
ノートPCによる初期検証
- 最初の実験は、ノートPC の Bluetooth アダプタで
x 秒間スキャンし、y 秒ごとに繰り返して SQLite データベースに保存するシンプルなコードだった
- 食堂、Chick-Fil-A、Starbucks など複数の場所でノートPCを持って待ちながらデータを集めた
- 小さな単一空間である Starbucks では機器数はかなり正確で、少なくとも占有トレンドを素早く反映していた
- 食堂のような大きな空間では、全体の人数を直接数えられず Bluetooth アダプタの範囲も明確ではなかったが、授業終了後に食事へ移動する時間帯の増加と、検出されたビーコン数の増加はよく一致していた
Raspberry Pi Zero W アプローチが行き詰まった理由
- 長期配備用デバイスとして最初に思い浮かんだのは、小型で安価、かつ Wi-Fi と Bluetooth を備えた Raspberry Pi Zero W だった
- Rust でコードを書き直し、再起動、ネットワーク不通、アダプタ消失といった状況に対処しようとした
- Linux Bluetooth をヘッドレス環境で扱う過程は、予想よりはるかに複雑だった
- DBus バインディングにはクロスコンパイル関連の設定が必要だった
- Cross でも問題は解決しなかった
- さまざまなコンパイラフラグ、Makefile 作業の損失、QEMU ブリッジ設定を経て、ようやく Pi 上でバイナリを実行した
- Wi-Fi 接続、起動時に必要なライブラリのインストール、実行ファイルのサービス登録、更新の自動反映まで実装したが、実際に起動すると正常には動かなかった
- このアプローチは、必要なのが信頼できる Wi-Fi と Bluetooth だけなのに、Linux カーネル全体と多くの可動部品を抱え込む方式だった
ESP32 へ移行
- ESP32 は、ドキュメント上では Wi-Fi、Bluetooth、低消費電力、低価格、小型という条件をすべて満たすデバイスだった
- Amazon で OLED ディスプレイ付きの無名の ESP32-WROOM-32 を購入した
- リアルタイムデータを画面に表示したいという目的があった
- ESP32 向け Rust エコシステムはまだ十分ではないと判断し、データ収集コードを C++ で書き直した
- OLED は
SSD1306Wire display(0x3c, 5, 4); 設定で動作させた
- キャンパス IT に MAC アドレスのホワイトリスト登録を依頼し、Cloudflare Functions と D1 データベースをデータ収集バックエンドとして実装した
初回配備で明らかになったメモリ問題
- キャンパス図書館にデータ収集装置を設置し、ノートPC からデータが入ってくることを確認した
- その後、図書館から人が全員いなくなったように見える奇妙な結果が現れ、原因は無作為に買った ESP32 ボードの低い仕様だった
- 装置は約250台の機器付近でクラッシュした
- 当初は結果数が 1 バイトの数値に保存されていて、約 255 件で止まる問題を疑った
Serial.print で確認すると 249、265 など近い範囲でランダムにクラッシュしており、単純な整数オーバーフローではなかった
- スキャン中の結果を最後までデータ構造に保存していたため、信号強度、広告サービス、メーカー ID など多くのデータが蓄積し、小さな RAM が埋まってしまった
- 実際に必要な値は一意な機器数だけだったため、スキャン結果全体を保持する構造は過剰だった
自作ハッシュセットとその限界
- 解決策として、C++ のデータ構造を自作し、小さなハッシュセットを作った
- 各コールバックで MAC アドレスをハッシュセットに入れた後、内蔵の結果構造を空にしてメモリを確保した
- この方式には、内蔵の結果構造が重複確認用データを失い、すべての BLE 広告パケットごとにコールバックが発生するという欠点があった
addToSet でハッシュセット側の重複確認は行っていた
- しかし重複コールバックが何百回も発生し、結果構造を繰り返し割り当て・解放することでヒープ churn が生じた
- それでも、最大 250 人程度で容量が尽きるよりは、最大 1000 件以下の項目を持つハッシュマップを頻繁に確認するほうがましだと判断した
より安定した ESP32 ボードの選定
- 秋休みの間に5日間の長期テストを試みたが、約400台の機器付近で再びクラッシュした
- 約3時間の使用後に問題が現れ、定期的な再起動を入れてもスキャンごとに即座に 0 台しか返さない現象が起きた
- 複数のボードをテストした
- Seeed Studio XIAO ESP32S3/C3
- WaveShare ESP32S3 Zero
- 無名の ESP32-WROOM with OLED
- Orange Pi Zero W
- Raspberry Pi Zero W
- 長期間安定して動作した唯一のボードは XIAO ESP32C3/S3 で、どちらも許容できる水準で動作した
- 最終的に選んだのは XIAO ESP32C3 だった
- RISC-V ベースである点が気に入った
- より安価だった
- より良いメーカー製ボードに替えたことで SRAM が増え、自作ハッシュマップではなく標準の結果データ構造を維持してもクラッシュが減った
- 最大約1000台の機器検出まで、動作が遅くなる兆候は見られず、ヒープやコールバックの churn も減った可能性がある
寮の窓際で見えた移動パターン
- 安定した装置を見つけた後、配備の繰り返しを容易にするため、装置を寮の部屋の窓際へ移した
- 1 日分のデータを見ると、授業の入れ替え時間帯にピークが現れた
- 装置が寮にあっても、主に寮の居住者だけを測定していたわけではなかった
- もし寮生だけを測っていたなら、早朝に最大値となり、昼になるにつれて減っていく形が予想された
- 窓の外を向いた設置位置のため、近くの2つの学業用建物へ移動する学生を主に検出していた
- 午前 7:50 ごろのピークは、Ewell Hall と Washington Hall の 8 時の授業直前と重なっていた
- 8:50、9:50、10:50 のピークは、それぞれ 9 時、10 時、11 時の授業へ向かう移動時間と一致していた
- この装置は周辺学生の移動トレンド追跡に適しているようで、アンテナ範囲は Washington Hall まで約 160ft、Ewell まで約 100ft に達しているようだった
- 3 階という高さも検出範囲に役立っていたようだ
予測と残る検証課題
- 収集データには時間別・日別・週別のトレンドが多く、NeuralProphet のような時系列予測の対象によく合っていた
- 予測機能を追加した後、現時点では日次トレンドをうまく予測できていた
- 週・月・シーズン単位の長期トレンドは、十分なデータが集まれば収束すると見込んでいた
- まだ未解決の疑問は多い
- BLE ビーコン数が実際の人口をどの程度うまく代理できるのか
- 複数の機器を持ち歩く人がいるため、
x 個のビーコンがおおよそ 0.7x 人に相当するような補正係数を作れるのか
- コンピュータサイエンス棟では機器数が多く、人に対するビーコン比率が高いのか、あるいは Bluetooth をオフにしている人が多くて低いのか
- 職員用建物では学生より持ち歩く機器が少なく、比率が低いのか
- 食堂は教室のようにノートPC や iPad などを併用するケースが少なく、比率が低いのか
- 精度改善の方法も残っている
- 弱い信号を除外するRSSI 最小値の設定
- Apple と一般的な Android のメーカー ID だけを数えるフィルタリング
- Apple Watch、AirPods、MacBook などが依然としてカウントに加わる問題
- 純粋なビーコン数だけを追跡し、実際の MAC アドレスは追跡しない現在の方式で、追加ノイズが必要かどうか
- 機器数だけで単一ユーザーを識別することが現実的なのか
- 短すぎると数百台の機器を見つけきれず、長すぎるとすでに去った機器まで数えてしまうという、スキャン継続時間の選択
- 一定時間変化がなければスキャンを終了する動的スキャン長
可能な配備形態
- 実際の人数を容易に取得できる場所でデータを検証する計画がある
- 入退館記録のあるジム
- 出入口が限られた食堂や Starbucks のような場所
- 大学委員会での活用や学術研究の可能性について、教授陣と議論中だ
- オフライン店舗向けに占有トレンド測定用途で販売する案も検討している
- 1 配備単位の設定は比較的パッケージ化されている
- 設定で Wi-Fi を構成
- ポータルがあればネットワーク側で MAC アドレスをホワイトリスト登録
- オープンまたはパスワード付き Wi-Fi には起動時に接続
- 設定で machine ID と site ID を変更
- 中央または便利な場所のコンセントに装置を接続
- バックエンドで各装置を読む Grafana ダッシュボードを構成
- 予測トレンドを別チャートで読む Grafana ダッシュボードを構成
1件のコメント
Hacker News のコメント
この技術で実際に事業(occuspace.io)を作り、提起された質問のほとんどに取り組んできた。
BLE ビーコンの数は在室人数と非常に強い相関があるが、食堂・講義室・図書館のフロアごとに相関係数が大きく異なるため、より複雑な特徴量も併せて使うほうがよい。
BLE ビーコンが見えている時間から滞在時間を推定するのは、メーカーによって Bluetooth MAC が 8〜20 分ごとにランダム化されるため、正確ではないと思う。
弱い RSSI を除外して近くのデバイスだけを数える方法は良いアイデアだが、空間の種類やセンサーの設置位置によってしきい値が変わる。
もともとの要件が「食堂の混雑を避ける」ことだったなら、混み具合の高低をおおよそ知るだけで十分かもしれない。
事業では顧客が高い精度を期待しているのか、全員がそうなのか一部だけなのかも気になる。
MAC アドレスがランダム化されても、デバイスの種類を判別して携帯電話だけを数え、ヘッドホンなどを除外する方法があるのではないかと思う。
信号がより遠くまで広がるので難しそうだし、テニスコートの在室追跡を必要とするスタートアップをやっている。
屋外空間の隅に Bluetooth デバイスを設置し、その信号強度をしきい値にすることもできそうだ。
Wi-Fi、Wi-Fi MAC、映像情報を追跡して相互に結び付ければ、もっと多くのことができるかもしれない。
潜在的な競合の一つとして知っておくとよさそうだ。
STEM 系の大学建物では 1 人あたり Bluetooth デバイスが 3 台を超えることもあるが、別の場所では 1 台未満かもしれない。
素晴らしい記事だ。
Seeed Studio XIAO ESP32S3/C3、WaveShare ESP32S3 Zero、Unbranded ESP32-WROOM with OLED、Orange Pi Zero W、Raspberry Pi Zero W をすべてテストした結果、長期的に、現在 1 か月ほど安定して動作したのは XIAO ESP32C3/S3 だけだったとのことだが、電源の問題ではないかと疑っている。
ESP32 系は送信時の電圧変動に敏感なことがあるので、電源レールに大きなコンデンサを追加することを強く勧める。
RPi も ESP も、電源アダプタ・ケーブル・ケーブル長によって扱いが難しいことがあり、RPi の SD カードは突然の電源断で壊れやすい。
それでもどれも 1 か月以上は持つべきで、私の Pi と ESP は数か月単位で動いていた。
他の ESP32 や Pi により大きなコンデンサを付けたときの結果が気になる。
ESP32 は非常に広く使われているので、最初に買った無名メーカーの ESP32が長持ちしなかったのが原因だったのだろう。
きちんとしたメーカーの製品に替えたら問題は解決し、ESP32 はうまく動作している。
Raspberry Pi は実際ほとんど動作しなかったが、単に Bluetooth スキャンと HTTP 呼び出しだけをすればよい作業を、複雑にしすぎて管理するものを増やしすぎたためだ。
コンセントから USB-C で 5V 1A を直接供給していたので電源問題ではないと思うが、Xiao ESP32-S3 にも断続的な問題があり、記憶では XTensa コアは RISC-V ベースの ESP32-C3 より電力を食うので、確認する必要はある。
ときどき ESPHome で更新しているが、特に問題はなかった。
一部は複数のタスクを同時にこなしていて、例えばある 1 台はホームオフィスの Bluetooth プロキシであると同時に、Skadis の壁面ボードに沿って設置したライトストリップも制御している。
Amazon の「AZDelivery」という会社から買った任意ブランドの製品を使っており、特別な処置はしていない。
3D プリントしたケースに入れ、通常 30cm 未満の短いケーブルで最低 5V/1A のアダプタにつないでいる。
lbu commit -dを実行したときだけディスクに保存し、基本的には一種の tempfs で起動する。大学生が大学で行ったプロジェクトで、ある程度の人の追跡を含むので、研究であればどのような人を対象とする研究手続きが必要かを教授に聞くよい機会だ。
大学の IRB より教授に尋ねるほうが簡単かもしれない。
IRB は管轄外だとして対話を拒むか、もっと早く相談しなかったことを警戒するかもしれない。
キャンパス IT のプライバシー・セキュリティポリシーも適用される可能性がある。
一般のウェブサイト、アプリ、IoT デバイスは人々をはるかにひどく侵害しているが、大学はときに外の世界より良くなろうという目標を持つこともある。
うまくいかない可能性もあるので本文には入れなかった。
ビーコンはブロードキャストされていて、私たちが行くほぼあらゆる場所で同意なく収集されている可能性が高い。
家が交差点にあるので周囲に多くの Bluetooth デバイスがよく集まるのだが、純粋に面白半分で BLE トラッカーを設置し、何を収集でき、データから何が分かるのか見てみようとしたことがある。
例えば、家の中の空気質が悪くなることと、その地域に Bluetooth デバイスが到着することの間には相関があると確信している。
「こういうナード・スナイプでは勢いを失わないことが致命的に重要だ」という文が面白かった。
私のナード脳も、まさにこの論理でお金を使えと何度も説得してきた。
プロジェクトをやりたい気分がより強い時期は確かにあり、特に冬には電子工作のプロジェクトをより多くやるし、ゲームもより多くする。
私のゲーム「シーズン」も先週また始まった。
「今日は何をしたい?」から「今シーズンは何をする気分で、何をする時間がある?」へと劇的に変わったのは、年を取り子どもができた影響が大きいが、こうしたプロジェクトをやる意欲と時間が生まれる間隔が非常に長いので、勢いを失うと 1 年後に戻ってくるか、永遠に戻ってこられないかもしれない。
少なくとも 10 年前に始めた電子工作プロジェクトが一つあり、かなりお金を使い、いつか終わらせると今でも意地を張っているため、家族の間では悪名高いプロジェクトになっている。
私の目覚まし時計は、ESP32 とかなり大きな LED アレイ、ブザー、PIR センサーで構成されている。
時刻は表示せず、ブザーと点滅で知らせ、部屋をゆっくり明るくしたり、夜にはすべての照明が消えてから一定時間が経つとゆっくり暗くしたりする。
後から気づいた追加の利点は、AP が私と ESP の間になくても、私自身が RF を十分に反射するので、RSSI ログだけでベッドにいた時間だけでなく、夜に寝返りを打ったタイミングまで分かることだ。
https://imgur.com/a/VixOlu5
警告に反して、性的な内容はない。
中央の緑は RSSI、下の黄色は PIR センサー、上部は Mi Band 3 のデータとベッドにいた時間の注釈を混ぜたもの。
寝る前と起きる前にニュースを長時間読んでいたのも事実。
ESP32 プロジェクトをどうやって製品らしくまとめるのか気になる。
量産の話ではなく、線が大量に飛び出したボードではなく、独立したデバイスにしたいという意味。
多くのページではむき出しのボードだけを見せているが、現実にはそれをパッケージングする必要がある。
私のようなソフトウェア寄りの人間なら、自分であれこれ触るより、少し余分に払ってでもきれいにまとまった形を好む可能性が高い。
3D プリンターがあるなら3D プリントを作ればいい。
アクリル系ならレーザーカッターで形を切り出し、穴をいくつか開ければ箱になる。
何もなく、最低限の箱だけ欲しいなら、12 個で約 25 ドルの Altoids Tin を使えばよい。役に立たないミントが入っているので、それは捨ててプロジェクトを入れればいい。
Altoids の缶より少し良いものが欲しいなら Hammond Enclosure を買えばいい。
(https://www.hammfg.com/electronics/small-case)
私なら電気テープで巻いて、その上をダクトテープのようなもので巻き、油性ペンで色を塗るかもしれない。
通常はボードをネジ止めできる、あらかじめ穴の開いたフランジがいくつかあり、入出力用の外部穴は必要に応じて自分で開ければいい。
メーカーの例は以下の通りで、開発ボードや他の部品をすでに買うなら、送料を節約するために adafruit や digikey でもたいてい見つけられる。
https://www.hammfg.com/
https://www.budind.com/
http://takachi-enclosure.com/
https://www.adafruit.com/product/903
目にするプロジェクトの大半は製品化されていない。
ハッカーの一回限りのプロジェクトで、他の人が便利に使ってくれればうれしいが、それが目的ではないのでパッケージングは不要で、時には単に箱に押し込むだけだ。
もっと見栄えのよいものが欲しければ、誰かにケース設計を任せる必要がある。
その誰かは自分自身でもいい。
ESP32 は自社製品に組み込みやすいように設計されているので、回路基板とケースが互いに合うように設計し、ESP32 チップを大量購入して基板に実装する流れになる。
プロトタイプ用に買うボードは公式にはリファレンスボードにすぎず、最終出荷用として期待されているわけではないが、実際にはボードをそのまま出荷するケースもよくある。
小さく安価で難しいボード設計を、誰かがすでにやってくれているからだ。
製品が十分に標準的なら、この段階を省けることもある。
次に地域のメーカーや、より大きな市場のメーカーに連絡してサンプルを受け取り、正しく動作するか確認する。
気に入ったら小ロットから注文する。
メーカーが 20% の不良品を送ってこないように、品質保証手順を設計するか、それを手伝ってくれる専門家を探すのがよい。
実店舗に並べるかウェブサイトを作り、Amazon などのポータルで販売する。
顧客と話し、フィードバックを聞き、すべての段階を少しずつ改善すればいい。
気が遠くなるように聞こえるが、小さなスマートホームのスタートアップで働いて、深圳には創業者が夢見る製品を実現するのを助ける産業全体が整っており、あらゆる段階で助けてくれる人を契約できるのだと学んだ。
私たちの経験では、中国側のサービスはヨーロッパの提案よりはるかに良く、安く、速かった。
残りのテイクアウト容器がエンクロージャになる。
配線が出入りする穴は容器に開ける。
少し見栄えを良くしたいときは Tupperware の容器を使う。
データをメモリに保持する問題を完全には追えていないし、今は解決したようだが、一意のビーコン ID 数を推定するのにカーディナリティ推定アルゴリズムを使えば、定数空間だけで可能そうだ。
https://en.wikipedia.org/wiki/Count-distinct_problem
最近のサッカーの試合に持って行って、すぐにアクセスできる最大級の群衆でストレステストをしてみようと思っていた。
数千個を無理なくスキャンできるなら、かなり堅牢だと考えるつもりだ。
それでも固定サイズの推定データ構造を調べてみるのは本当に面白そうで、必ず見てみる。
このプロジェクトで一番好きな部分の一つは、最も簡単な解決策を取らなければならないというプレッシャーなしに、より深くて興味深いコンピューターサイエンスの概念を掘り下げられることだ。
ASAP で納品するソリューションを開発しているのではなく、気になるところを自分で掻いているところだ。
「ヘッドレス方式で Linux Bluetooth を扱うのはものすごく苦痛だ。DBus バインディングにはクロスコンパイルの魔法が必要で、Cross でも解決できなかった」という部分は、自分の経験とも同じだった
私は別の作業をしていたので、結局 2 つのデバイスを同じ Wi-Fi ネットワークに置き、pi.local をスキャンする方式に決めた
ただ、ライブラリがない場合にビルドで拒否せず、実行時にクラッシュするほかのクレートがどのように動作するのかは知りたい
筆者は組み込みでやろうとして、はるかに低レベルのインターフェースを扱う必要があり苦労したようだ
高水準言語では、とっくに解決されている問題だ
トラッカーが結局コンピューターのそばのドアに置かれたのなら、Python を動かす RPi をそのまま使っても十分だったはずだ
https://github.com/home-assistant/core/blob/dev/homeassistan...
https://www.home-assistant.io/integrations/bluetooth_tracker...
これが BLE 用であることは明確にしておくべきだった
最初は心拍、熱、入退室、あるいはもっと物理的な何かに基づくものだと思っていた
また ESP32 の受信感度は -94 dBm 程度で、かなり悪い部類に入り、多くのデバイスは -100、-102、さらには -104 dBm までいく
この差はかなり大きい
ESPresence は興味深いプロジェクトで、ESP32-C3 でも動作する
どの部屋にいるかを判定する用途により合わせて設計されている