StampFly コントローラ ファームウェア¶
Note: English version follows after the Japanese section. / 日本語の後に英語版があります。
1. 概要¶
StampFly コントローラは、M5Stack AtomS3とAtom JoyStickを使用したStampFly操縦用ファームウェアです。ESP-NOW通信でドローンと接続し、TDMA (Time Division Multiple Access) 方式により複数のコントローラが同一チャンネルで干渉なく通信できます。
主な機能¶
- ジョイスティック入力: 2軸×2本のアナログスティックでスロットル・ロール・ピッチ・ヨーを制御
- ESP-NOW通信: 低遅延の無線通信プロトコル
- TDMA同期: 最大10台のコントローラが同一チャンネルで動作可能
- ペアリング機能: ボタン操作でドローンと自動ペアリング
- USB HIDモード: PCに接続してゲームパッドとして使用可能(シミュレータ対応)
- メニューシステム: 画面タップで各種設定を変更
- NVS設定保存: 設定値を不揮発メモリに保存
- LCD表示: 通信状態・バッテリー電圧・モード表示
- ブザー音: 状態通知・警告音
通信モード¶
本ファームウェアは3つの通信モードをサポートしています。
| モード | 用途 | 切り替え方法 |
|---|---|---|
| ESP-NOW | 実機ドローンの操縦(複数機) | メニューで選択(デフォルト) |
| UDP | 実機ドローンの操縦(単機) | メニューで「UDP Mode」を選択 |
| USB HID | PC接続・シミュレータ | メニューで「USB Mode」を選択 |
ESP-NOW vs UDP の選択基準: - ESP-NOW: 複数機編隊飛行、TDMA同期が必要な場合 - UDP: 単機運用、開発・デバッグ時(WiFi接続でシンプル)
ハードウェア構成¶
| コンポーネント | 型番 | 説明 |
|---|---|---|
| マイコン | M5Stack AtomS3 | ESP32-S3搭載、LCD付き |
| ジョイスティック | M5Stack Atom JoyStick | I2C接続、2軸×2本 |
| バッテリー | - | JoyStick内蔵 |
2. ディレクトリ構成¶
firmware/controller/
├── CMakeLists.txt # プロジェクト設定
├── sdkconfig.defaults # SDK設定デフォルト値
├── partitions.csv # パーティションテーブル
├── main/
│ ├── CMakeLists.txt # mainコンポーネント設定
│ ├── idf_component.yml # IDF Component Manager設定
│ └── main.cpp # メインプログラム
├── components/
│ ├── atoms3joy/ # ジョイスティックドライバ
│ │ ├── include/atoms3joy.h
│ │ └── atoms3joy.cpp
│ ├── buzzer/ # ブザー制御
│ │ ├── include/buzzer.h
│ │ └── buzzer.c
│ ├── espnow_tdma/ # ESP-NOW TDMA通信
│ │ ├── include/espnow_tdma.h
│ │ └── espnow_tdma.c
│ ├── sf_udp_client/ # UDP通信クライアント
│ │ ├── include/udp_client.hpp
│ │ └── udp_client.cpp
│ ├── menu_system/ # メニューシステム
│ │ ├── include/menu_system.h
│ │ └── menu_system.cpp
│ └── usb_hid/ # USB HIDゲームパッド
│ ├── include/usb_hid.hpp
│ └── src/usb_hid.cpp
├── managed_components/ # IDF Component Manager管理
├── docs/ # ドキュメント
├── (→ docs/architecture/tdma-usage.md) # TDMA詳細ガイド
└── LICENSE # MITライセンス
3. 開発環境のセットアップ¶
必要な環境¶
- ESP-IDF: v5.5.2
- 対応OS: Windows、macOS、Linux
- ハードウェア: M5Stack AtomS3 + Atom JoyStick
ESP-IDF のインストール¶
# リポジトリをクローン
git clone -b v5.5.2 --recursive https://github.com/espressif/esp-idf.git ~/esp/esp-idf
# インストールスクリプトを実行
cd ~/esp/esp-idf
./install.sh esp32s3
# 環境変数を設定
. ~/esp/esp-idf/export.sh
プロジェクトのビルド¶
書き込み¶
macOSの場合:
4. タスク構成¶
本ファームウェアは複数のFreeRTOSタスクで構成されています。
タスク一覧¶
| タスク名 | 周期 | 優先度 | Core | 役割 |
|---|---|---|---|---|
| InputTask | 100Hz | 最高-2 | 1 | ジョイスティック読み取り |
| DisplayTask | 10Hz | 2 | 1 | LCD表示更新 |
| BeaconTask | (通知) | 最高-1 | 1 | ビーコン送信 (マスターのみ) |
| TDMASendTask | (通知) | 最高-1 | 1 | 制御データ送信 |
| メインループ | 100Hz | - | 0 | 制御値計算・データ作成 |
タスクフロー¶
┌──────────────┐ ┌──────────────┐
│ InputTask │────▶│ shared_input │
│ (100Hz) │ │ (Mutex) │
└──────────────┘ └──────────────┘
│
▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Main Loop │────▶│ shared_send │────▶│ TDMASendTask │
│ (100Hz) │ │ (Mutex) │ │ (TDMA) │
└──────────────┘ └──────────────┘ └──────────────┘
│
▼
┌──────────────┐
│ ESP-NOW │
│ to Drone │
└──────────────┘
5. ESP-NOW TDMA通信¶
TDMA方式の概要¶
TDMA (Time Division Multiple Access) は、時間を複数のスロットに分割し、各デバイスが決められたスロットで送信することで衝突を回避する方式です。
フレーム (20ms = 50Hz)
├─ ビーコン (フレーム開始500μs前、マスターのみ送信)
├─ スロット0 (2ms) 親機 ID=0 の制御データ
├─ スロット1 (2ms) 子機 ID=1 の制御データ
├─ スロット2 (2ms) 子機 ID=2 の制御データ
├─ ...
└─ スロット9 (2ms) 子機 ID=9 の制御データ
パラメータ設定¶
components/espnow_tdma/include/espnow_tdma.h:
| パラメータ | デフォルト値 | 説明 |
|---|---|---|
ESPNOW_CHANNEL |
1 | WiFiチャンネル (1-13) |
TDMA_DEVICE_ID |
0 | デバイスID (0=マスター, 1-9=スレーブ) |
TDMA_FRAME_US |
20000 | フレーム周期 (20ms) |
TDMA_SLOT_US |
2000 | スロット幅 (2ms) |
TDMA_NUM_SLOTS |
10 | スロット数 |
TDMA_BEACON_ADVANCE_US |
500 | ビーコン先行時間 |
複数コントローラの設定¶
複数のコントローラを使用する場合、各コントローラに異なる TDMA_DEVICE_ID を設定します。
親機 (1台のみ):
子機 1:
子機 2:
詳細は tdma-usage.md を参照してください。
6. ジョイスティック¶
ハードウェア¶
Atom JoyStick はI2C接続 (アドレス: 0x59) で、以下のデータを提供します。
| データ | レジスタ | 説明 |
|---|---|---|
| 左スティックX | 0x00-0x01 | 12bit (0-4095) |
| 左スティックY | 0x02-0x03 | 12bit (0-4095) |
| 右スティックX | 0x20-0x21 | 12bit (0-4095) |
| 右スティックY | 0x22-0x23 | 12bit (0-4095) |
| 左スティックボタン | 0x70 | 0/1 |
| 右スティックボタン | 0x71 | 0/1 |
| 左ボタン | 0x72 | 0/1 |
| 右ボタン | 0x73 | 0/1 |
| バッテリー電圧1 | 0x60-0x61 | mV単位 |
| バッテリー電圧2 | 0x62-0x63 | mV単位 |
スティックモード¶
| モード | スロットル | エルロン | エレベータ | ラダー |
|---|---|---|---|---|
| Mode 2 | 左Y | 右X | 右Y | 左X |
| Mode 3 | 右Y | 左X | 左Y | 右X |
メニューから「Stick: Mode X」を選択して切り替え可能です。設定はNVSに保存され、次回起動時に復元されます。
バイアスキャリブレーション¶
起動時に50サンプルの平均を取り、スティック中立位置のバイアスを自動補正します。手動キャリブレーションはメニューから「Calibration」を選択して実行できます。
7. メニューシステム¶
画面を押すとメニューが表示されます。各種設定の変更や画面の切り替えができます。
メニュー項目¶
| 項目 | 説明 |
|---|---|
| Stick: Mode X | スティックモード切り替え(Mode 2 / Mode 3) |
| Comm Mode | 通信モード切り替え(ESP-NOW/UDP/USB、再起動) |
| Batt: X.XV | バッテリー警告閾値の設定(3.0V〜4.0V) |
| Deadband: X% | スティックデッドバンド設定(0%〜5%) |
| Stick Test | スティック・ボタンの動作テスト画面 |
| Calibration | スティックキャリブレーション画面 |
| Device ID | TDMAデバイスID設定 |
| Channel | WiFiチャンネル表示 |
| MAC Address | ペアリングMACアドレス表示 |
| About | バージョン情報表示 |
| <- Back | フライト画面に戻る |
画面一覧¶
| 画面 | 説明 |
|---|---|
| FLIGHT | 通常フライト画面(デフォルト) |
| MENU | メインメニュー |
| STICK_TEST | スティック・ボタンテスト |
| CALIBRATION | スティックキャリブレーション |
| BATTERY_WARN | バッテリー警告設定 |
| CHANNEL | チャンネル表示 |
| MAC | MACアドレス表示 |
| ABOUT | バージョン情報 |
8. USB HIDモード¶
コントローラをPCにUSB接続してゲームパッドとして使用できます。シミュレータでの練習に最適です。
切り替え方法¶
- 画面を押してメニューを開く
- 右スティックの上下でメニューを移動し「Comm: ...」の行を選ぶ
- 右ボタン(決定)を押す(ESP-NOW → UDP → USB HID の順に切り替わる。USB HIDになるまで繰り返し押す)
- コントローラが再起動し、USB HIDゲームパッドとして認識される
HIDレポート仕様¶
| バイト | 内容 | 範囲 |
|---|---|---|
| 0 | スロットル | 0〜255 |
| 1 | ロール | 0〜255 |
| 2 | ピッチ | 0〜255 |
| 3 | ヨー | 0〜255 |
| 4 | ボタン(bit0-3) | 0/1 |
| 5 | Reserved | 0 |
ESP-NOWモードへの復帰¶
USB HIDモード中にメニューから「ESP-NOW Mode」を選択すると、実機操縦用のESP-NOWモードに戻ります。
9. UDP通信モード¶
ESP-NOWの代替として、WiFi AP経由のUDP通信をサポートしています。単機運用や開発・デバッグ時に便利です。
UDP通信の仕組み¶
┌────────────┐ WiFi AP ┌────────────┐
│ Controller │ ←───────────────→ │ Vehicle │
│ (STA) │ 192.168.4.x │ (AP) │
└────────────┘ └────────────┘
│ │
│ UDP Port 8888 ────────────────┘ Control
│ UDP Port 8889 ←─────────────── Telemetry
- Vehicle: WiFi AP「StampFly」を起動(192.168.4.1)
- Controller: STAモードでVehicleのAPに接続
- 制御パケット: 50Hz で Controller → Vehicle
- テレメトリ: 50Hz で Vehicle → Controller
切り替え方法¶
- 画面を押してメニューを開く
- 「UDP Mode」を選択
- コントローラが再起動し、VehicleのWiFi APをスキャン
- 「StampFly_*」SSIDに自動接続
- UDP通信開始
事前準備(Vehicle側)¶
Vehicle側でUDPモードを有効にする必要があります:
この設定はNVSに保存され、次回起動時も維持されます。LCD表示(UDPモード時)¶
┌────────────────────┐
│ UDP: 192.168.4.1 │ ← Vehicle IPアドレス
│ BAT 1:X.X 2:X.X │ ← バッテリー電圧
│ MODE: 2 │ ← スティックモード
│ TX: 1234 RX: 567│ ← 送受信パケット数
│ -Mnual ALT- │ ← 高度モード
│ -STABILIZE- │ ← 制御モード
│ RSSI: -45 dBm │ ← WiFi信号強度
└────────────────────┘
トラブルシューティング(UDP)¶
| 症状 | 対処 |
|---|---|
| WiFi APが見つからない | Vehicle側でUDPモードが有効か確認 (comm udp) |
| 接続後すぐ切断される | Vehicle/Controllerを再起動 |
| 制御が効かない | Vehicle側CLIで ctrl watch でフラグを確認 |
| テレメトリが来ない | ファイアウォール設定を確認(Port 8889) |
10. NVS設定¶
以下の設定はNVS(不揮発メモリ)に保存され、電源オフ後も維持されます。
| 設定項目 | キー | デフォルト値 | 説明 |
|---|---|---|---|
| 通信モード | comm_mode | ESP-NOW | ESP-NOW / UDP / USB HID |
| スティックモード | stick_mode | Mode 2 | Mode 2 / Mode 3 |
| バッテリー警告 | batt_warn | 3.3V | 警告閾値(3.0V〜4.0V) |
| デッドバンド | deadband | 2% | スティックデッドバンド(0%〜5%) |
| スティックキャリブレーション | stick_cal | 自動 | 手動キャリブレーション値 |
11. 操作方法¶
ペアリング(ESP-NOWモード)¶
- コントローラのM5ボタンを押しながら電源を入れる
- LCD に "Pairing mode..." と表示される
- StampFly のボタンを長押ししてペアリングモードに入る
- ペアリングが完了するとビープ音が鳴る
- ペアリング情報はSPIFFSに保存され、次回起動時は自動接続
ボタン操作¶
| ボタン | 短押し | 長押し (400ms以上) |
|---|---|---|
| M5ボタン | タイマー開始/停止 | タイマーリセット |
| 左スティックボタン | Arm/Disarm | - |
| 右スティックボタン | Flip | - |
| 左ボタン | 高度モード切替 | - |
| 右ボタン | 制御モード切替 | - |
制御モード¶
| モード | 説明 |
|---|---|
| STABILIZE | 角度制御モード (初心者向け) |
| ACRO | 角速度制御モード (上級者向け) |
高度モード¶
| モード | 説明 |
|---|---|
| Manual ALT | スロットルで直接高度を制御 |
| Auto ALT | 自動高度維持モード |
12. 制御パケットフォーマット(ESP-NOW)¶
コントローラからドローンへ送信されるパケット (14バイト):
| バイト | 内容 | 説明 |
|---|---|---|
| 0-2 | MAC下位3バイト | 宛先識別用 |
| 3-4 | Throttle | スロットル (16bit) |
| 5-6 | Phi | ロール角 (16bit) |
| 7-8 | Theta | ピッチ角 (16bit) |
| 9-10 | Psi | ヨー角 (16bit) |
| 11 | フラグ | Arm/Flip/Mode/AltMode |
| 12 | proactive_flag | 予約 |
| 13 | チェックサム | バイト0-12の合計 |
フラグバイト (11) のビット配置:
bit 0: Arm ボタン
bit 1: Flip ボタン
bit 2: Mode (0=STABILIZE, 1=ACRO)
bit 3: AltMode (0=Manual, 1=Auto)
bit 4: PosMode (0=OFF, 1=POSITION_HOLD)
13. LCD表示¶
LCD は10Hzで更新され、以下の情報を表示します。
┌────────────────────┐
│ MAC ADR XX:YY │ ← ドローンMACアドレス下位2バイト
│ BAT 1:X.X 2:X.X │ ← バッテリー電圧
│ MODE: 2 │ ← スティックモード
│ CH: 01 ID: 0 │ ← WiFiチャンネル、デバイスID
│ -Mnual ALT- │ ← 高度モード
│ -STABILIZE- │ ← 制御モード
│ Freq: 50 M │ ← 送信周波数 (M=Master/SYNC/WAIT/LOST)
└────────────────────┘
同期状態表示¶
| 表示 | 意味 |
|---|---|
| M | マスター (親機) |
| SYNC | スレーブ同期中 |
| WAIT | ビーコン待機中 |
| LOST | ビーコンロスト |
14. ブザー音¶
| 音パターン | 意味 |
|---|---|
| 起動音 (上昇音階) | 起動完了 |
| 単発ビープ | ペアリング待機中 |
| 4000Hz 単発 | ビーコンロスト警告 |
| 3000Hz 2回 | スロットタイミングエラー |
| 1000Hz 長音 | ドローンオフライン |
| 2000Hz 3回 | Mutexタイムアウト |
15. トラブルシューティング¶
ドローンと接続できない(ESP-NOW)¶
- ペアリングを再実行する (M5ボタンを押しながら起動)
- WiFiチャンネルがドローンと一致しているか確認
- バッテリー電圧が十分か確認
子機が同期しない¶
- 親機 (ID=0) が起動しているか確認
- チャンネル設定が全デバイスで一致しているか確認
- ビーコンロスト音 (4000Hz) が鳴っていないか確認
スティックが効かない¶
- I2C接続を確認
- シリアルモニタでジョイスティック初期化エラーがないか確認
- 起動時にスティックを中立位置にしているか確認
ビルドエラー¶
- ESP-IDF v5.5.2がインストールされているか確認
export.shを実行して環境変数を設定idf.py fullcleanで完全にクリーンしてから再ビルド
UDPモードで接続できない¶
- Vehicle側で
comm udpが実行されているか確認 - 「StampFly」WiFi APが見えるか確認
- Vehicle側CLIで
commコマンドを実行しUDPモードか確認 - Controller/Vehicleの両方を再起動
UDPモードでArmできない¶
- Vehicle側CLIで
ctrl watchを実行してフラグを確認 - Control Arbiterの統計を確認 (
commコマンド) - ESP-NOWモードに戻っていないか確認(NVS設定)
ライセンス¶
MIT License - 詳細は LICENSE を参照
作者¶
Kouhei Ito - kouhei.ito@itolab-ktc.com
StampFly Controller Firmware¶
1. Overview¶
StampFly Controller is a firmware for controlling StampFly drones using M5Stack AtomS3 and Atom JoyStick. It connects to the drone via ESP-NOW communication and supports multiple controllers on the same channel without interference using TDMA (Time Division Multiple Access).
Main Features¶
- Joystick Input: Control throttle, roll, pitch, and yaw with 2-axis × 2 analog sticks
- ESP-NOW Communication: Low-latency wireless protocol
- TDMA Synchronization: Up to 10 controllers can operate on the same channel
- Pairing Function: Automatic pairing with drone via button operation
- USB HID Mode: Use as a PC gamepad (simulator compatible)
- Menu System: Change settings by tapping the screen
- NVS Storage: Save settings to non-volatile memory
- LCD Display: Shows communication status, battery voltage, mode
- Buzzer: Audio feedback for status and warnings
Communication Modes¶
This firmware supports three communication modes.
| Mode | Use Case | How to Switch |
|---|---|---|
| ESP-NOW | Control real drone (multi-vehicle) | Select from menu (default) |
| UDP | Control real drone (single-vehicle) | Select "UDP Mode" from menu |
| USB HID | PC connection / Simulator | Select "USB Mode" from menu |
ESP-NOW vs UDP: - ESP-NOW: For multi-vehicle formation flying, TDMA synchronization required - UDP: For single-vehicle operation, development/debugging (simple WiFi connection)
Hardware Components¶
| Component | Model | Description |
|---|---|---|
| MCU | M5Stack AtomS3 | ESP32-S3, with LCD |
| Joystick | M5Stack Atom JoyStick | I2C, 2-axis × 2 |
| Battery | - | Built into JoyStick |
2. Directory Structure¶
firmware/controller/
├── CMakeLists.txt # Project configuration
├── sdkconfig.defaults # SDK configuration defaults
├── partitions.csv # Partition table
├── main/
│ ├── CMakeLists.txt # Main component configuration
│ ├── idf_component.yml # IDF Component Manager config
│ └── main.cpp # Main program
├── components/
│ ├── atoms3joy/ # Joystick driver
│ │ ├── include/atoms3joy.h
│ │ └── atoms3joy.cpp
│ ├── buzzer/ # Buzzer control
│ │ ├── include/buzzer.h
│ │ └── buzzer.c
│ ├── espnow_tdma/ # ESP-NOW TDMA communication
│ │ ├── include/espnow_tdma.h
│ │ └── espnow_tdma.c
│ ├── sf_udp_client/ # UDP communication client
│ │ ├── include/udp_client.hpp
│ │ └── udp_client.cpp
│ ├── menu_system/ # Menu system
│ │ ├── include/menu_system.h
│ │ └── menu_system.cpp
│ └── usb_hid/ # USB HID gamepad
│ ├── include/usb_hid.hpp
│ └── src/usb_hid.cpp
├── managed_components/ # IDF Component Manager managed
├── docs/ # Documentation
├── (→ docs/architecture/tdma-usage.md) # TDMA detailed guide
└── LICENSE # MIT License
3. Development Environment Setup¶
Requirements¶
- ESP-IDF: v5.5.2
- Supported OS: Windows, macOS, Linux
- Hardware: M5Stack AtomS3 + Atom JoyStick
Installing ESP-IDF¶
# Clone the repository
git clone -b v5.5.2 --recursive https://github.com/espressif/esp-idf.git ~/esp/esp-idf
# Run the install script
cd ~/esp/esp-idf
./install.sh esp32s3
# Set environment variables
. ~/esp/esp-idf/export.sh
Building the Project¶
Flashing¶
For macOS:
4. Task Architecture¶
This firmware consists of multiple FreeRTOS tasks.
Task List¶
| Task Name | Period | Priority | Core | Role |
|---|---|---|---|---|
| InputTask | 100Hz | MAX-2 | 1 | Joystick reading |
| DisplayTask | 10Hz | 2 | 1 | LCD update |
| BeaconTask | (notify) | MAX-1 | 1 | Beacon transmission (master only) |
| TDMASendTask | (notify) | MAX-1 | 1 | Control data transmission |
| Main Loop | 100Hz | - | 0 | Control value calculation |
Task Flow¶
┌──────────────┐ ┌──────────────┐
│ InputTask │────▶│ shared_input │
│ (100Hz) │ │ (Mutex) │
└──────────────┘ └──────────────┘
│
▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Main Loop │────▶│ shared_send │────▶│ TDMASendTask │
│ (100Hz) │ │ (Mutex) │ │ (TDMA) │
└──────────────┘ └──────────────┘ └──────────────┘
│
▼
┌──────────────┐
│ ESP-NOW │
│ to Drone │
└──────────────┘
5. ESP-NOW TDMA Communication¶
TDMA Overview¶
TDMA (Time Division Multiple Access) divides time into multiple slots, with each device transmitting in its assigned slot to avoid collisions.
Frame (20ms = 50Hz)
├─ Beacon (500μs before frame start, master only)
├─ Slot 0 (2ms) Master ID=0 control data
├─ Slot 1 (2ms) Slave ID=1 control data
├─ Slot 2 (2ms) Slave ID=2 control data
├─ ...
└─ Slot 9 (2ms) Slave ID=9 control data
Parameter Settings¶
components/espnow_tdma/include/espnow_tdma.h:
| Parameter | Default | Description |
|---|---|---|
ESPNOW_CHANNEL |
1 | WiFi channel (1-13) |
TDMA_DEVICE_ID |
0 | Device ID (0=master, 1-9=slave) |
TDMA_FRAME_US |
20000 | Frame period (20ms) |
TDMA_SLOT_US |
2000 | Slot width (2ms) |
TDMA_NUM_SLOTS |
10 | Number of slots |
TDMA_BEACON_ADVANCE_US |
500 | Beacon advance time |
Multi-Controller Setup¶
When using multiple controllers, assign different TDMA_DEVICE_ID to each controller.
Master (only 1):
Slave 1:
Slave 2:
See tdma-usage.md for details.
6. Joystick¶
Hardware¶
Atom JoyStick connects via I2C (address: 0x59) and provides the following data:
| Data | Register | Description |
|---|---|---|
| Left Stick X | 0x00-0x01 | 12bit (0-4095) |
| Left Stick Y | 0x02-0x03 | 12bit (0-4095) |
| Right Stick X | 0x20-0x21 | 12bit (0-4095) |
| Right Stick Y | 0x22-0x23 | 12bit (0-4095) |
| Left Stick Button | 0x70 | 0/1 |
| Right Stick Button | 0x71 | 0/1 |
| Left Button | 0x72 | 0/1 |
| Right Button | 0x73 | 0/1 |
| Battery Voltage 1 | 0x60-0x61 | mV unit |
| Battery Voltage 2 | 0x62-0x63 | mV unit |
Stick Modes¶
| Mode | Throttle | Aileron | Elevator | Rudder |
|---|---|---|---|---|
| Mode 2 | Left Y | Right X | Right Y | Left X |
| Mode 3 | Right Y | Left X | Left Y | Right X |
Select "Stick: Mode X" from menu to switch. Settings are saved to NVS and restored on next boot.
Bias Calibration¶
At startup, 50 samples are averaged to automatically calibrate the stick neutral position bias. Manual calibration can be performed by selecting "Calibration" from the menu.
7. Menu System¶
Press the screen to display the menu. You can change various settings and switch screens.
Menu Items¶
| Item | Description |
|---|---|
| Stick: Mode X | Switch stick mode (Mode 2 / Mode 3) |
| Comm Mode | Switch communication mode (ESP-NOW/UDP/USB, restart) |
| Batt: X.XV | Battery warning threshold (3.0V-4.0V) |
| Deadband: X% | Stick deadband setting (0%-5%) |
| Stick Test | Stick and button test screen |
| Calibration | Stick calibration screen |
| Device ID | TDMA device ID setting |
| Channel | WiFi channel display |
| MAC Address | Pairing MAC address display |
| About | Version information |
| <- Back | Return to flight screen |
Screens¶
| Screen | Description |
|---|---|
| FLIGHT | Normal flight screen (default) |
| MENU | Main menu |
| STICK_TEST | Stick and button test |
| CALIBRATION | Stick calibration |
| BATTERY_WARN | Battery warning setting |
| CHANNEL | Channel display |
| MAC | MAC address display |
| ABOUT | Version information |
8. USB HID Mode¶
Connect the controller to a PC via USB to use it as a gamepad. Perfect for practicing with the simulator.
How to Switch¶
- Press the screen to open the menu
- Use the right stick up/down to move to the "Comm: ..." row
- Press the right button (select) to cycle ESP-NOW to UDP to USB HID (press repeatedly until it reaches USB HID)
- The controller restarts and is recognized as a USB HID gamepad
HID Report Specification¶
| Byte | Content | Range |
|---|---|---|
| 0 | Throttle | 0-255 |
| 1 | Roll | 0-255 |
| 2 | Pitch | 0-255 |
| 3 | Yaw | 0-255 |
| 4 | Buttons (bit0-3) | 0/1 |
| 5 | Reserved | 0 |
Returning to ESP-NOW Mode¶
Select "ESP-NOW Mode" from the menu while in USB HID mode to return to ESP-NOW mode for controlling the real drone.
9. UDP Communication Mode¶
UDP communication over WiFi AP is supported as an alternative to ESP-NOW. Useful for single-vehicle operation and development/debugging.
How UDP Works¶
┌────────────┐ WiFi AP ┌────────────┐
│ Controller │ ←───────────────→ │ Vehicle │
│ (STA) │ 192.168.4.x │ (AP) │
└────────────┘ └────────────┘
│ │
│ UDP Port 8888 ────────────────┘ Control
│ UDP Port 8889 ←─────────────── Telemetry
- Vehicle: WiFi AP "StampFly" (192.168.4.1)
- Controller: STA mode, connects to Vehicle's AP
- Control packets: 50Hz Controller → Vehicle
- Telemetry: 50Hz Vehicle → Controller
Switching to UDP Mode¶
- Press screen to open menu
- Select "UDP Mode"
- Controller restarts and scans for Vehicle WiFi AP
- Auto-connects to "StampFly_*" SSID
- UDP communication starts
Prerequisites (Vehicle Side)¶
Enable UDP mode on Vehicle:
This setting is saved to NVS and persists after restart.10. NVS Settings¶
The following settings are saved to NVS (non-volatile memory) and persist after power off.
| Setting | Key | Default | Description |
|---|---|---|---|
| Communication Mode | comm_mode | ESP-NOW | ESP-NOW / UDP / USB HID |
| Stick Mode | stick_mode | Mode 2 | Mode 2 / Mode 3 |
| Battery Warning | batt_warn | 3.3V | Warning threshold (3.0V-4.0V) |
| Deadband | deadband | 2% | Stick deadband (0%-5%) |
| Stick Calibration | stick_cal | Auto | Manual calibration values |
11. Operation¶
Pairing (ESP-NOW Mode)¶
- Hold M5 button while powering on the controller
- LCD shows "Pairing mode..."
- Long-press the StampFly button to enter pairing mode
- Beep sounds when pairing is complete
- Pairing info is saved to SPIFFS and auto-connects on next boot
Button Operations¶
| Button | Short Press | Long Press (400ms+) |
|---|---|---|
| M5 Button | Timer start/stop | Timer reset |
| Left Stick Button | Arm/Disarm | - |
| Right Stick Button | Flip | - |
| Left Button | Altitude mode toggle | - |
| Right Button | Control mode toggle | - |
Control Modes¶
| Mode | Description |
|---|---|
| STABILIZE | Angle control mode (beginner-friendly) |
| ACRO | Rate control mode (advanced) |
Altitude Modes¶
| Mode | Description |
|---|---|
| Manual ALT | Direct altitude control with throttle |
| Auto ALT | Automatic altitude hold mode |
12. Control Packet Format (ESP-NOW)¶
Packet sent from controller to drone (14 bytes):
| Byte | Content | Description |
|---|---|---|
| 0-2 | MAC lower 3 bytes | Destination ID |
| 3-4 | Throttle | Throttle value (16bit) |
| 5-6 | Phi | Roll angle (16bit) |
| 7-8 | Theta | Pitch angle (16bit) |
| 9-10 | Psi | Yaw angle (16bit) |
| 11 | Flags | Arm/Flip/Mode/AltMode |
| 12 | proactive_flag | Reserved |
| 13 | Checksum | Sum of bytes 0-12 |
Flag byte (11) bit layout:
bit 0: Arm button
bit 1: Flip button
bit 2: Mode (0=STABILIZE, 1=ACRO)
bit 3: AltMode (0=Manual, 1=Auto)
bit 4: PosMode (0=OFF, 1=POSITION_HOLD)
13. LCD Display¶
LCD updates at 10Hz showing the following information:
┌────────────────────┐
│ MAC ADR XX:YY │ ← Drone MAC address lower 2 bytes
│ BAT 1:X.X 2:X.X │ ← Battery voltage
│ MODE: 2 │ ← Stick mode
│ CH: 01 ID: 0 │ ← WiFi channel, device ID
│ -Mnual ALT- │ ← Altitude mode
│ -STABILIZE- │ ← Control mode
│ Freq: 50 M │ ← Transmit frequency (M=Master/SYNC/WAIT/LOST)
└────────────────────┘
Sync Status Display¶
| Display | Meaning |
|---|---|
| M | Master |
| SYNC | Slave synchronized |
| WAIT | Waiting for beacon |
| LOST | Beacon lost |
14. Buzzer Sounds¶
| Sound Pattern | Meaning |
|---|---|
| Startup (ascending scale) | Boot complete |
| Single beep | Pairing waiting |
| 4000Hz single | Beacon lost warning |
| 3000Hz × 2 | Slot timing error |
| 1000Hz long | Drone offline |
| 2000Hz × 3 | Mutex timeout |
15. Troubleshooting¶
Cannot Connect to Drone (ESP-NOW)¶
- Re-run pairing (hold M5 button while booting)
- Verify WiFi channel matches the drone
- Check battery voltage is sufficient
Slave Not Synchronizing¶
- Verify master (ID=0) is running
- Confirm channel settings match across all devices
- Check if beacon lost sound (4000Hz) is heard
Sticks Not Responding¶
- Check I2C connection
- Check serial monitor for joystick initialization errors
- Ensure sticks are in neutral position at startup
Build Errors¶
- Verify ESP-IDF v5.5.2 is installed
- Run
export.shto set environment variables - Run
idf.py fullcleanand rebuild
Cannot Connect in UDP Mode¶
- Verify
comm udpwas executed on Vehicle side - Check if "StampFly" WiFi AP is visible
- Verify Vehicle is in UDP mode (run
commcommand in Vehicle CLI) - Restart both Controller and Vehicle
Cannot Arm in UDP Mode¶
- Run
ctrl watchin Vehicle CLI to check flags - Check Control Arbiter statistics (
commcommand) - Verify not reverted to ESP-NOW mode (NVS setting)
License¶
MIT License - See LICENSE for details
Author¶
Kouhei Ito - kouhei.ito@itolab-ktc.com