Firmware for a wireless gauge to measure the difference in angle of attack between the wing and the horizontal stabilizer of RC aircraft. The device measures absolute angles relative to gravity with a statistical stability check, then displays the difference between two captured angles — all through a browser-based and phone-friendly web interface, no app installation required.
- Reference measurement — Place the gauge on the wing, press Start, and hold still. The device samples the accelerometer at 10 Hz for 10 seconds. Once the window is full and the standard deviation drops below the configured threshold, the measurement is accepted and automatically stored as the reference angle.
- Second measurement — Move the gauge to the horizontal stabilizer and press Start again. After the same stability check, the firmware calculates and displays the incidence angle difference (EWD).
- Verification by reversal — To eliminate any zero-offset error of the sensor, repeat both measurements with the gauge flipped upside down. Average the two EWD readings — the sensor offset cancels out and the result is more accurate.
- Reset — Clears both measurements so a new reference can be captured.
| Component | Description |
|---|---|
| MCU | Seeed XIAO ESP32S3 |
| Sensor | LIS2DH12 3-axis accelerometer (SPI) |
No additional components are required.
| Sensor Pin | XIAO ESP32S3 Pin |
|---|---|
| VCC | 3V3 |
| GND | GND |
| SCL (SCK) | D8 (GPIO7) |
| SDA (MOSI) | D10 (GPIO9) |
| SDO (MISO) | D9 (GPIO8) |
| CS | D7 (GPIO44) |
Note: Verify pin assignments against your specific breakout board and update
include/config.haccordingly.
Built with the Arduino framework on PlatformIO, targeting the Seeed XIAO ESP32S3.
- PlatformIO (VS Code extension or CLI)
- USB-C cable for flashing
# Clone the repository
git clone https://github.com/<your-org>/ewd.git
cd ewd
# Create your local configuration
cp include/config.h.example include/config.h
# Edit include/config.h to set Wi-Fi mode, credentials, and pin assignments
# Build
pio run
# Flash (connect the XIAO ESP32S3 via USB)
pio run --target upload
# Open serial monitor (115200 baud)
pio device monitorAll settings live in include/config.h (copied from include/config.h.example).
This file is listed in .gitignore and will never be committed.
The device supports two modes:
| Mode | Description |
|---|---|
| Access Point (AP) | The device creates its own Wi-Fi hotspot. No router needed. |
| Station (STA) | The device joins an existing Wi-Fi network. |
// Wi-Fi mode: "AP" or "STA"
#define WIFI_MODE "AP"
// Access Point settings (AP mode)
#define AP_SSID "EWD-Gauge"
#define AP_PASSWORD "12345678" // min. 8 characters; "" for open network
// Station settings (STA mode)
#define STA_SSID "your-network"
#define STA_PASSWORD "your-password"- In AP mode the web interface is reachable at http://192.168.4.1
- In STA mode the assigned IP is printed to the serial monitor on boot
In both modes the device advertises itself via mDNS. With the default hostname the interface is reachable at http://ewd.local on any device that supports mDNS (macOS, iOS, Linux with Avahi, Windows 10+).
#define MDNS_HOSTNAME "ewd"#define PIN_SPI_SCK 7 // D8 on XIAO ESP32S3
#define PIN_SPI_MOSI 9 // D10
#define PIN_SPI_MISO 8 // D9
#define PIN_SPI_CS 44 // D7Open the device's IP address (or http://ewd.local) in any browser on the same network - a phone works fine. The single-page interface updates every 500 ms and shows:
| Card | Content |
|---|---|
| Last Measurement | Accepted angle (mean over the measurement window) |
| Reference (Wing) | Stored reference angle and its σ |
| Difference (EWD) | Angle difference between last measurement and reference |
| Status | Live σ and sample progress during an active measurement |
Controls:
- Start — begins a new measurement; disabled while measuring
- Abort — cancels the current measurement without saving
- Reset — clears all stored angles and the reference
- Max σ — stability threshold; the measurement is only accepted when the standard deviation over the full window is at or below this value (default 0.2°)
Each measurement runs a 10-second sliding window (100 samples at 10 Hz).
- Raw accelerometer data is pre-filtered with an exponential moving average low-pass filter (α = 0.02, ~0.03 Hz cutoff) to suppress vibration and building-structure noise.
- The tilt angle is derived from the filtered X-axis acceleration:
angle = atan2(ax, sqrt(ay² + az²)). - Samples are collected into a circular buffer of size
WINDOW = 100. - After every new sample the mean and sample standard deviation over all buffered values are recomputed.
- The measurement is accepted once the buffer is full (
n = WINDOW) andσ ≤ threshold. If the device is still moving when the window fills, sampling continues (oldest samples are overwritten) until stability is reached. - The first accepted measurement is automatically stored as the reference. Subsequent measurements show the difference.
The UI shows n / 100 samples while the buffer is filling, and live σ once the
window is full.
ewd/
├── data/
│ └── index.html # Web UI source — edit this file
├── include/
│ ├── config.h.example # Configuration template (copy to config.h)
│ ├── lis2dh12_platform.h # SPI wrapper for LIS2DH12
│ ├── measure.h # Measurement state machine and snapshot API
│ ├── web_server.h # Web server interface
│ └── web_ui.h # Auto-generated (do not edit)
├── src/
│ ├── main.cpp # Application entry point, sensor loop
│ ├── lis2dh12_platform.cpp # SPI read/write callbacks
│ ├── measure.cpp # Windowed mean/σ measurement logic
│ └── web_server.cpp # HTTP routes and JSON API
├── tools/
│ └── generate_web_ui.py # Pre-build: converts index.html → web_ui.h
├── test/
└── platformio.ini
data/index.html is the only file you edit. On every pio run, the pre-build
script tools/generate_web_ui.py gzip-compresses it and writes the result as a
C byte array into include/web_ui.h. The web server serves the compressed file
directly with Content-Encoding: gzip — no flash filesystem required.
Dependencies are managed by PlatformIO and declared in platformio.ini.
| Library | Source | Purpose |
|---|---|---|
| ESP32 Arduino core | platform = espressif32 |
MCU support |
lis2dh12-pid |
GitHub (STMicroelectronics) | LIS2DH12 sensor driver |
mathieucarbou/ESP Async WebServer |
PlatformIO registry | Non-blocking HTTP server |
bblanchon/ArduinoJson |
PlatformIO registry | JSON API responses |
lis2dh12-pid is the official platform-independent C driver from STMicroelectronics.
The thin SPI wrapper that connects it to the ESP32 Arduino SPI API lives in
src/lis2dh12_platform.cpp / include/lis2dh12_platform.h.
Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)
Copyright (c) 2025 clausgf
You may freely use, share, and adapt this project for non-commercial purposes, provided you give appropriate credit. Commercial use is not permitted.

