BLE+LoRaWAN屋内外測位:構築・導入・実測結果
これは安全認証済みシステムではありません。LoRaWANのアップリンクは欠落することがあり、GNSSは屋内で使えず、BLE測位は金属の近くで精度が落ちるため、位置が遅れる・誤る・欠落することがあります。人の安全を守る唯一の手段としては使わないでください。
このソリューションでできること
現場には通常、建物と屋外区域の両方があり、どちらでも知りたいことは同じです。あのフォークリフト、機器、人は今どこにいるのか。屋内では電池式BLEビーコンが位置の基準となり、屋外ではトラッカー内蔵GNSSに切り替わります。両方のデータをLoRaWANで送り、Webダッシュボードに1つの地図として表示します。フロアプランを屋外地図にジオリファレンスできるため、建物から構内へ続く軌跡も1画面に収まります。
- オープンソース実装: github.com/Seeed-Solution/Solution_IndoorPositioning_H5
- 構成の選択と導入: 参考設計ページ
センシング側に配線不要
ビーコンは電池式で壁面に取り付け、トラッカーは1回の充電で数か月レポートします。商用電源とネットワーク接続が必要なのはゲートウェイとホストです。
屋内と屋外を自動切替する1つの地図
トラッカーが建物に出入りすると、サーバー側の状態機械がレイヤーを切り替えます。手動操作は不要で、窓際のトラッカーが頻繁に切り替わることもありません。
オープンソース、データは自社ホストに
アプリケーションのソースはGitHubで公開され、自社ホスト上のDockerイメージとして動きます。インターネットに接続するのはベースマップだけで、オフラインのPMTilesアーカイブに置き換えられます。
サーバー容量の実測値
同時200タグでエンドツーエンドP95 828 ms・ロス0%、500タグでP95 2.35 sです。リプレイしたアップリンクで測定し、トラッカーとゲートウェイは接続していません。
ライブ出力
屋内レイヤーは登録済みフロアプラン上にトラッカーを描画します。

屋外レイヤーも同じページとWebSocketを使い、ベースに地図タイルを表示します。

屋内外を移動する1台のトラッカー:

スマートフォンのクライアントにも同じデータを表示します。

ダッシュボードは/web/mapの1ページで、IndoorとOutdoorを明示的に切り替えます。/web/map?layer=outdoorは壁面ディスプレイに適した直接リンクで、同じWebSocketを購読します。トラッカーは常に2つのビューのどちらか一方だけに描画されます。表示先は状態機械が決め、その判断はメッセージのposition.coordSystemに含まれます。フロアプランの{x, y}にはmetric、{lat, lon}にはwgs84を使います。
必要な機器
現場で使う機器は3種類です。ビーコンとトラッカーの数は導入規模に応じて変わります。
① BLEビーコン — 屋内測位の基準です。電池式で壁面に取り付け、配線は不要です。GNSSだけでカバーする屋外区域(構内、道路、駐車場)には必要ありません。
② トラッカー — 人が携帯するか、資産に取り付けます。屋内ではBLEをスキャンし、屋外では内蔵GNSSを使います。SOSボタンも備えます。
③ LoRaWANゲートウェイ — アップリンクを収集してネットワークサーバーへ転送します。ゲートウェイとトラッカーは地域の同じ周波数帯で購入してください。
| 機器 | 公称容量 | 選択する条件 | |
|---|---|---|---|
| SenseCAP BC03 Indoor Bluetooth Beacon 屋内測位の基準、Bluetooth LE 5.0 | ゾーンあたり3台以上で2–3 m、1台では部屋レベル | 「建物内」より細かく位置を特定したい屋内区域 | |
| SenseCAP LoRaWAN Card Tracker T1000-A BLEスキャン、GNSS、動体検知、SOS | 追跡対象の人または資産ごとに1台 | バッジまたは資産タグ。屋内外を同じユニットでカバー | |
![]() | SenseCAP M2 LoRaWAN Indoor Gateway SX1302、地域別周波数バリエーション | 見通し2 kmまで、トラッカー100–200台 | 現場ごとに1~2台。既存のLoRaWANを使う場合は不要 |
表の容量値はすべて公称値で、デバイスのデータシートとこのハードウェアの導入実績に基づきます。ビーコンの精度は以下の設置方法によって変わります。
機器のほかに、アプリケーション用ホスト(Dockerを実行できる任意のマシン。サーバー側の実測ではreComputer J30シリーズを通常のarm64ホストとして使用)、ネットワークサーバー(SenseCAP OpenStreamまたは独自のChirpStack)が必要です。オフラインのベースマップを構築しない場合は、ホストからOpenStreetMapのラスタタイルへアクセスできる必要があります。
選定における制約・非推奨条件
- サブメートル単位の高精度追跡:BLE ビーコンの測位精度は 2〜3m です。AGV の高精度自律走行などセンチ・サブメートル級の連続制御が必要な用途には、UWB を選定してください。
- 秒単位のリアルタイム制御:LoRaWAN は送信周期と遅延の制約があり、オフライン判定は 15 分です。秒単位の衝突防止などリアルタイムの安全制御には使用できません。
現場への導入
1. ハードウェアを設置する
ビーコンは高さ2.5–3 m、間隔5–10 m(BC03の推奨間隔)で設置し、金属棚がある場所には追加します。公称2–3 mの値はゾーンあたり3台以上を前提とし、ゾーンあたり1台では部屋レベルの特定になります。すべてのビーコンのMACアドレスと位置を記録してください。屋内位置はビーコンとゾーンの対応表から計算されます。ビーコンを移動したら対応表も更新してください。更新しないと、そのビーコンから計算される位置がすべてずれます。
ゲートウェイの台数はカバレッジで決めます。公称の見通し距離は2 kmで、通常の現場は1~2台で足ります。2台目が必要かは壁と距離で決まり、タグ数には関係しません。ゲートウェイは周波数帯ごとにSKUが分かれています(US915 / EU868 / AS923など)。注文前に国の周波数帯を確認し、トラッカーも同じ帯域にしてください。
2. ソフトウェアを導入する:7ステップ
機器ごとの手順とアプリケーションパッケージは参考設計ページにあります。手順の概要:
- BLEビーコンを設置 — 配置・固定し、MACアドレスを記録します。
- LoRaWANゲートウェイを設定 — SenseCAP OpenStreamまたは独自のChirpStackに接続します。
- 測位アプリケーションを導入 — 現在のマシンまたはSSH経由のリモートホストにDockerで導入します。
- トラッカーを設定して有効化 — ネットワークに参加させ、アップリンク間隔を設定します。
- フロアプランをジオリファレンス — プランをアップロードし、原点・回転・縮尺を設定して屋外地図の正しい位置に合わせます。ジオリファレンスとジオフェンスはどちらも設定ページで行います。

- ジオフェンスアラームを設定 — WGS84で境界を描き、アラームルールを割り当てます。
- ダッシュボードを開く — トラッカーが表示・移動し、設定したアラームが発生することを確認します。
難易度は中級、所要時間は約60分です。手順5と6はソフトウェア設定だけで、追加のハードウェアは不要です。
イメージは linux/arm64 と linux/amd64 に対応しています。ダッシュボードの初期ログインはadmin / 12345678です。初回ログイン後に「設定 → 認証」で変更してください。
利用できるインターフェース
アプリケーションが公開する機能は、導入先ホストのポート5173で提供されます。統合する側に応じて3つの方法があります。
- 壁面ディスプレイまたは2台目の画面 —
/web/map?layer=outdoor(または?layer=indoor)を開きます。同じページとWebSocketを使うため、追加設定は不要です。 - 既存の警備・配車・勤怠システム — WebSocketを購読し、次の2種類のメッセージを処理します:
tracker_sosは緊急ボタン、tracker_checkin/tracker_position_detectionにtransition: enterまたはexitを含むgeofenceブロックがある場合はジオフェンスイベントです。それ以外はテレメトリです。 - 自社サービス —完全なペイロードを利用します。各更新にはフロアプラン上のmetric座標またはWGS84座標が含まれ、
coordSystemで識別できます。RESTエンドポイントからジオフェンスの作成やジオリファレンスパラメータの読み書きをプログラムで行えます。
インターフェースとペイロードの全体像
| インターフェース | エンドポイント | ペイロード |
|---|---|---|
| WebSocket | ws://<host>:5173/ws | tracker_updateのposition = {x, y, coordSystem: "metric"} または{lat, lon, accuracy, coordSystem: "wgs84"}; tracker_checkin / tracker_position_detection はenter/exit時に追加のgeofenceブロックを持ち、さらにtracker_sosとtracker_offline |
| REST | GET/PUT /api/configuration/dashboard/maps/{mapName}/registration | {origin_lat, origin_lon, rotation_deg, scale}. 拒否 |lat| > 85° and scale ≤ 0. 管理者セッションが必要で、ゲストセッションは403になります |
| REST | POST /api/geofences, POST /api/events | フェンス形状(GeoJSONポリゴン、または点とradius_m)と、それを参照するアラームルール |
| LoRaWAN uplink in | SenseCAP OpenStream, またはChirpStack MQTTトピック | フィールドマッピングは導入ガイドに記載 |
ジオフェンスアラームは専用チャネルではなく、チェックインと同じメッセージに含まれます。
{"type": "tracker_checkin", "data": {"2CF7F1C0530004AD": {
"timestamp": 1788582647214, "map": "Plant A",
"geofence": {"id": 1, "name": "Plant A", "transition": "enter"},
"position": {"lat": 22.5362, "lon": 113.9432, "accuracy": null, "coordSystem": "wgs84"},
"last_detected_beacons": []}}}
扱いに注意する2つのフィールド:屋内外はlatの有無ではなくcoordSystemで判定してください。同じメッセージ型がどちらの座標形式も持ちえます。このハードウェアではaccuracyは**常にnull**です(SenseCAPとChirpStackのアップリンクにはGNSS精度の測定値が含まれません)。「不明」として扱ってください。
性能と実測データ
以下はサーバー側の実測値です。合成アップリンクをローカルMQTTブローカーへ公開し、結果をダッシュボードのWebSocketから取得しました。T1000トラッカーとゲートウェイは経路に含まれていません。アプリケーションはreComputer J30シリーズ(通常のarm64ホストとして使用、GPU未使用)で実行し、各段階2–4分です。
容量と遅延
| 指標 | 測定値 | 条件 |
|---|---|---|
| 安定時容量 | 同時200タグ、エンドツーエンドP95 828 ms、アップリンクロス0% | タグごとに30秒あたり1アップリンク、800アップリンク、2分 |
| 劣化時容量 | 500タグ、P95 2.35 s、ロス0% | 同じ条件、2000アップリンク、2分。2秒の遅延予算だけ未達 |
| 1000タグ時の容量 | P95 4.1 s、ロス0%、プロセスは提供継続 | 同じ条件。正常に提供を続けており、負荷をそれ以上増やしていない |
| 更新レート | アップリンク間隔2秒の50タグ、4500アップリンクでP95 220 ms、ロス0% | 3分。30 / 10 / 5秒間隔もP95 89 / 163 / 146 msで安定 |
| SOSアラーム遅延 | P50 24 ms、P95 29 ms、最大29 ms、n=20 | 単一タグ、同時負荷なし。アップリンク時刻からWebSocket配信まで |
| オフライン検出 | 903 sと950 s | 2回実施。15分しきい値と60秒ポーリングから期待される範囲は[900 s, 960 s] |
容量と更新レートはサーバーだけの値です。トラッカーの送信頻度はアップリンク間隔とLoRaWANのデューティサイクルで決まります。
再現:上流indoor_positioning_ble_lorawanのruns/2026-09-05-orin-nano/boundary.capacity.yaml、boundary.update_frequency.yaml、boundary.sos_latency.yaml、boundary.offline_latency.yaml(アプリケーションコードfeature/outdoor @ 443bce6)
ジオフェンスとジオリファレンス
| 指標 | 測定値 | 条件 |
|---|---|---|
| ジオフェンスアラーム遅延 | P50 14 ms、最大14 ms、アラーム2件 | リプレイツールとサーバーを同一ホストのループバックで実行、単一タグ、17アップリンク |
| ジオフェンスヒステリシス | 境界上で内外を6回反転させてもアラームは0件。enterとexitはいずれも3点連続で発生 | 同上 |
| ジオリファレンス誤差 | 原点から2 km以内の全域で≤ 0.21 m、|lat| ≤ 60° | 方位角を15°ごとに走査し、半径500 / 1000 / 2000 m、lat0 ∈ 60での最悪値。予算は0.7 m。投影計算のみで、実地測量なし |
再現:runs/2026-09-05-geofence-smoke/results.md、runs/2026-09-05-georef/results.md
ランタイムと主要パラメーター
トラッカーは観測結果(検出した設定済みビーコン、またはGNSS fix)だけを送信し、位置はサーバーが算出します。屋内外の切り替えとアラームの間隔は、次の3つのサーバー側パラメーターで決まります。
- 屋内 ↔ 屋外の切り替え:20秒以内に3回のGNSS fixがあり、かつ15秒間設定済みビーコンを検出しない場合に屋外へ切り替えます。連続2回のスキャンでそれぞれ2台以上の設定済みビーコンを検出すると屋内へ戻ります。窓際のトラッカーが屋内外を行き来することはありません。
- ジオフェンスの遷移:10秒以内に3点連続した場合にだけ
enter/exitが発生します。geoモードではアラームルールのtime_rangeフィールドは無効で、UIで設定した時間帯はこの確認に置き換えられます。 - オフライン検出:15分間アップリンクがなければオフラインと判定し、60秒ごとにポーリングします。ハードコードです。
- オフラインベースマップ:インターネットのない現場では
go-pmtiles extractでローカルのPMTilesアーカイブを構築します(バウンディングボックス内のタイルだけを取得)。納品前にアーカイブを構築して一度読み込んでください。
既知の劣化
- **屋内精度はビーコン配置に左右されます。**2–3 mは公称値(BC03 wiki)で、ゾーンあたり3台以上、高さ2.5–3 m、間隔5–10 mを前提とします。ゾーンあたり1台では部屋レベルです。金属棚は三辺測量を劣化させるため、その場所にはビーコンを追加してください。
- タグ数が増えると遅延が伸びます:エンドツーエンドP95は500タグで2.35 s、1000タグで4.1 sです。
- ジオリファレンス誤差は半径と緯度に応じて増えます:有効範囲はおよそ2 kmで、APIは
\|lat\|が85°を超える入力を拒否します。 accuracyとaltにはデータが入りません:精度で分岐するロジックはこのハードウェアでは常にnull側を通り、ジオフェンスエンジンはaccuracyの欠落を合格として扱います。
データと素材の出典
- 実測データ — 「性能と実測データ」の数値はすべて、上流
sensecraft-solutionsのindoor_positioning_ble_lorawanにあるdescription.mdと、そこからパスで参照される各実行レポートに由来します。データは実行用に生成した合成リプレイトレースで、顧客現場のデータは含みません。 - スクリーンショットとトレースに表示されるデバイスEUIは、リプレイツールが使用した合成値です。
- 屋外スクリーンショットのベースマップタイルは© OpenStreetMap contributorsで、ODbL. この帰属表示はページとともに保持されます。
- ジオリファレンスのスクリーンショットにあるフロアプランは、評価実行用に作成して後で削除した合成テスト画像です(50 m × 40 mのデモ地図上の1000×800 pxプラン)。
- アプリケーションのソースは Seeed-Solution/Solution_IndoorPositioning_H5; 派生製品を出荷する前に、リポジトリのライセンス条件を確認してください。
- ダッシュボードのキャプチャとデモGIF — アプリケーション自身のUI(
solution-indoor-positioning内のdocs/ui/とassets/)から取得しています。屋外レイヤーのベースマップはODbLに基づくOpenStreetMapタイルで、出典は上流パッケージのgallery/ATTRIBUTION.mdに記載されています。
