はじめに
- M5StickC Plus2を使って、iPhoneでは確認しづらいDJIドローンのWi-Fi BeaconリモートIDを可視化・記録する装置を作った
背景
DJI製ドローンを飛ばしていたら、リモートIDが本当に発信されているのか気になった。
手持ちのiPhoneでは、以下の理由でリモートIDを見ることが出来なかった。
-
リモートIDは、Bluetooth 5.x、又はWi-Fi Aware、又はWi-Fi Beaconのどれかで発信する必要がある
リモート ID 技術規格書
抜粋2. RID 機器等の性能要件 (1) リモート ID 信号(以下「RID 信号」という。)は、Bluetooth 5.x Long Range(以下「Bluetooth 5.x」という。)、Wi-Fi Neighbor Awareness Networking(以下「Wi-Fi Aware」という。)又は Wi-Fi Beacon の無線方 式による直接放送方式(RID 機器等から発信された RID 信号を受信機能を 有する端末が直接受信する通信方式)により発信されるものでなければ ならない。 -
DJIドローンはWi-Fi BeaconでリモートIDを発信しているとされている
Device BT 4 BT 5 Wi-Fi Beacon Wi-Fi NAN Link Notes DJI Mavic 3 ❌ ❌ ✅ ❌ https://www.dji.com/cz/mavic-3 Range < 500 meters via smartphone DJI Mini 3 Pro ❌ ❌ ✅ ❌ https://www.dji.com/cz/mini-3-pro Range < 500 meters via smartphone -
iPhoneアプリはOS制約の関係で、Wi-Fi Beaconを見ることが出来ないらしい
OpenDroneID の opendroneid-core-c#ios
抜粋(google翻訳)iOS向けDroneTagアプリケーションは、iOSでBluetooth 4 Legacy Advertising信号を受信できます。 AppStoreからダウンロードできます。 ソースコードはhttps://github.com/dronetag/drone-scannerで公開されており、iOSとAndroidの両方でビルドできます。 iOS 用の別の受信機アプリケーションは、こちらでベータテストされています: https://testflight.apple.com/join/HA3EL4zw。 Appleは現在、BT4レガシーアドバタイジング以外のドローンID信号送信方法を受信するための適切なAPIを公開していません。 つまり、iOSの現在のバージョン(15まで)は、BT5 Long Range + Extended Advertising、Wi-Fi NaN、Wi-Fiビーコンの受信をサポートしていません。 -
従って、iPhoneアプリでは、DJIのリモートIDを見ることが出来ない
そこで、手持ちのM5StickC Plus2を使ってDJIのリモートIDを見ようと思った。
ただし、作った後にOpenDroneIDのESP32実装の存在を知ったので、次回があればそちらを利用したい。
-
OpenDroneIDのESP32実装
抜粋(google翻訳)ESP32送信機のサンプル コードには、ESP32 HW でドローン ID 信号を受信するためのコードも含まれています。
開発環境
- Windows 11
- バージョン 24H2 (OS ビルド 26100.2605)
- Arduino IDEバージョン :2.3.6
- 日付:2025-04-09T11:26:55.498Z
- CLIバージョン:1.2.0
- Arduinoライブラリ:
-
M5GFX0.2.9 -
M5Unified0.2.7 -
M5StickCPlus21.0.1 -
ArduinoJson7.4.1
-
- M5StickCPlus2
構成
アプリケーションは主に以下のコンポーネントから構成される。
-
メインスケッチ (
drone_remote_id.ino):- Wi-Fiスニッフィングの初期化とパケット処理コールバック (
wifi_sniffer_packet_handler) の設定 - ボタン入力処理、Wi-Fiチャンネル制御、定期的な画面更新
-
RemoteIDDataManagerとM5CanvasTextDisplayControllerのインスタンス化と制御 - RTCからの時刻取得とシステム時刻設定
- Wi-Fiスニッフィングの初期化とパケット処理コールバック (
-
RemoteIDDataManagerクラス:
- 受信したリモートIDデータをRID(機体識別子、通常はシリアルナンバー)ごとに整理・格納
- データは時系列のリングバッファ (
std::deque) で管理し、古いものから削除 - ターゲットRIDのデータはより多く保持
- 各種クエリ機能(最新データ取得、RSSI順ソート、JSON出力など)を提供
-
ArduinoJsonライブラリを利用してJSON文字列を生成 - 複数タスクからのアクセスを考慮し、セマフォでデータ整合性を保護
-
M5CanvasTextDisplayControllerクラス:
- M5GFXの
M5Canvasを利用したダブルバッファリングによる、ちらつきのない画面表示を実現 - 文字単位のグリッドベースでのテキスト配置
- Arduino
Printクラスライクなインターフェースを提供し、print/printlnで簡単に描画可能 - 画面回転や文字サイズ変更にも対応
- M5GFXの
使い方
- Gitのdrone_remote_idにある以下の4つのファイルをダウンロードする
- Arduino IDEで ダウンロードしたdrone_remote_id.ino を開き、必要なライブラリがインストールされていることを確認する
- 次章「設定」の値を、必要に応じて変更する
- M5StickCPlus2をPCに接続し、適切なボードとシリアルポートを選択する
- スケッチをM5StickCPlus2に書き込む
- 起動すると、画面にヘッダ情報(チャンネル、検出RID数、空きヒープ)と、検出されたRIDの情報がRSSIの高い順に表示される
※ドローンは電源ONしただけでは、リモートIDを発信しないので、アーム状態にする必要がある
※ドローンの「アーム状態」とは、ドローンのモーターが回転して、飛行可能(プロペラが回る準備完了)状態になることである
※DJIドローンの場合、コンビネーション スティック コマンド(CSC)によって、モーターを始動すると、アーム状態になる様だ
↑ RIDが検出されていない時、(S)サーチモード
↑ RIDが一つ検出された時、(S)サーチモード
↑ RIDが一つ検出された時、(L)ロックモード
↑ GNSS(=GPS)が有効な時
※リモートIDを発信できるドローンを一台しか持っていないため、二台以上の動作が確認できていない- 各RIDエントリには、RID文字列(シリアル番号)、RSSI、チャンネル、登録記号、緯度経度、気圧高度、GPS高度、最終受信時刻などが表示される
※DJIのドローンが衛星を10個ぐらい認識してGNSSのアイコンがグリーンにならないと、緯度と経度は0が返る様だ
※気圧高度とGPS高度は受信した値をただ表示しているだけなので、正確な高度を出すには何かしらの補正が必要と思う - チャンネルは自動で1chから13chまでスキャンする。表示は Ch:XX(S) のように(S)canモードを示す
- 各RIDエントリには、RID文字列(シリアル番号)、RSSI、チャンネル、登録記号、緯度経度、気圧高度、GPS高度、最終受信時刻などが表示される
- ボタン操作:
- ボタンA (M5.BtnA / 本体正面ボタン): JSON送信
- ボタンB (M5.BtnB / 本体側面ボタン): チャンネル固定モード切り替え
- 押すごとに、チャンネル固定モードの有効/無効がトグルする
- 有効にすると、SEND_MODE_TOP_RSSI の設定に応じて、ターゲットとなるRIDが受信された最後のチャンネルに固定しようと試みる。表示は Ch:XX(L) のように(L)ockモードを示します。ターゲットが見つからない場合は Ch:Lock? と表示され、スキャンを継続する
- ボタンC (M5.BtnPWR / 電源ボタン): リセット
- 押すとM5StickCPlus2が再起動する
- シリアルモニターを開く (ボーレート 115200) と、デバッグログやJSONデータを確認できる
設定
初期状態では少しのデータしか記録しない。必要に応じて調整すること。
ただし、ヒープ領域不足でPanicになるかもしれない。
- 対象のリモートIDを指定する
探すRIDのシリアル番号がわかっているなら以下のコード(drone_remote_id.ino の40行目あたり)で指定する以下の様に指定するRemoteIDDataManager dataManager("");RemoteIDDataManager dataManager("1581F00LB000C000000R"); - RIDのデータエントリ数を調整する
指定されたRIDと、それ以外のRIDで、保持するデータエントリ数を以下のコード(RemoteIDDataManager.hの180行目あたり)で定義しているので調整する※ビーコンは1秒に一回以上発信されるstatic const size_t TARGET_RID_MAX_DATA = 1200; static const size_t OTHER_RID_MAX_DATA = 10; - JSONデータの最大エントリ数を調整する
Aボタンクリック時にJSONデータを作る最大エントリー数を、以下のコード(drone_remote_id.ino の39行目あたり)で定義しているので調整する以下の様に変更する(私の環境では40で安定した)const size_t MAX_ENTRIES_IN_JSON = 600;※私の環境では、50だとAボタン押すタイミングでメモリを使い果たしてPanicになったwconst size_t MAX_ENTRIES_IN_JSON = 40;
※40だとPanicにならなくなったが、40秒未満のデータしかJSONで送れない微妙。JSONデータを見直すか、バイナリデータへの変更を検討したい
おわりに
iPhoneアプリでWi-Fi Beaconを見ることが出来ない点には驚いた。
リモートIDは三種類(Bluetooth 5.x、Wi-Fi Aware、Wi-Fi Beacon)のいずれかで発信されるので、汎用的に使えるように作るのは大変そうだ。
作った後にOpenDroneIDのESP32実装の存在を知ったので、次回があればそちらを利用したい。
今後は、PCで受け取ったjsonデータからKMLファイルを作って、Google Earthなどで表示させてみたい。
でもデータ数を増やすとメモリが足りなくなるので、メモリの無駄を見直したい。
