Files
air-mouse/README.md
T

135 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# IMU Air Mouse
A BLE HID mouse that uses the onboard IMU of a **Seeed XIAO nRF52840 Sense** to move the cursor by tilting and rotating the device in the air. Intended as an open-source replacement for presentation remotes like the Logitech Spotlight, with additional features.
## Features
- **Roll-compensated pointing** - gyro + accelerometer fusion keeps the cursor level however the remote is twisted in the hand
- **Hardware tap detection** - single tap = left click, double tap = right click
- **BLE HID mouse** - works natively on Windows, macOS, Linux, Android, iOS
- **BLE Battery Service** - charge level visible in OS Bluetooth settings
- **Web config UI** (`web/index.html`) - configure over BLE from any Chrome/Edge browser, no app install
- **Flash persistence** - config survives power cycles (LittleFS)
- **Live IMU stream** - 20 Hz gyro/accel data streamed to the web UI visualiser
- **Live telemetry** - temperature, uptime, click counts, gyro bias RMS, recal count
- **Temperature compensation** - gyro drift correction by Δ temperature since last calibration
- **Continuous bias tracking** - gyro bias is re-estimated whenever the remote is at rest, so the cursor does not drift
- **Configurable charge rate** - OFF / 50 mA slow / 100 mA fast via BQ25100 HICHG pin
- **Boot-loop detection** - 3 rapid reboots trigger safe mode (config service disabled, flash wiped)
## Hardware
| Part | Notes |
|---|---|
| Seeed XIAO nRF52840 Sense | nRF52840 + LSM6DS3 IMU onboard |
| Li-ion battery (10440 / LiPo) | Connected to VBAT + GND pads |
## LED Status
The XIAO has three user LEDs (active LOW - HIGH = off, LOW = on):
| LED | Pattern | Meaning |
|---|---|---|
| Blue | Single pulse every 10 s | BLE connected (heartbeat) |
| Green | Single pulse every 10 s | Advertising / not connected (heartbeat) |
| Green | Rapid flutter (~10 Hz) | Gyro calibration in progress |
| Red | Fast blink (continuous) | IMU init failed - hardware fault |
| Red | 3 slow blinks on boot | Boot-loop detected - entered safe mode |
| Red | 6 rapid blinks | Battery critically low (< 3.10 V) |
> **Blue** = BLE-related state. **Green** = device activity. **Red** = fault only.
## Web Config UI
Open `web/index.html` in Chrome or Edge (desktop). Requires Web Bluetooth - enable it at `chrome://flags/#enable-web-bluetooth` on Linux.
**Configurable parameters:**
| Parameter | Range | Description |
|---|---|---|
| Sensitivity | 100 – 1500 | Cursor speed multiplier |
| Dead zone | 0 – 0.1 rad/s | Soft dead zone on smoothed speed; raise to steady the cursor while holding still |
| Accel strength | 0 – 0.5 | Pointer acceleration multiplier |
| Curve | Linear / Square / √Sqrt | Response shape for input magnitude |
| Flip X / Y | on/off | Invert horizontal or vertical axis |
| Charge mode | Off / 50 mA / 100 mA | BQ25100 charge current |
**Commands:**
- **Calibrate Gyro** - recalculates bias offset; hold the device still on a flat surface for ~1 s
- **Factory Reset** - wipes flash config, restores defaults
**Serial commands** (115200 baud over USB):
| Key | Action |
|---|---|
| `c` | Calibrate gyro |
| `r` | Factory reset |
| `s` | Toggle 1 Hz tracking stats (sample rate, HID reports, bias, roll, BLE interval); keeps the device awake |
| `l` | Toggle raw IMU log, one CSV line per sample; keeps the device awake |
| `d` | 10 s of roll-compensated yaw/pitch rates and roll angle |
| `t` | Synthetic sweep (right, left, down, up); moves the host cursor and prints the counts sent |
| `o` | Enter OTA DFU mode |
## Building
### Requirements
- [PlatformIO](https://platformio.org/) (VS Code extension or CLI)
- `adafruit-nrfutil` for flashing: `pip install adafruit-nrfutil`
### Flash
```sh
pio run -t upload
```
Double-tap the reset button to enter the UF2 bootloader (red LED pulses) if the board doesn't auto-reset.
### Feature flags
All optional features are enabled by `#define` in `source/config.h`. Comment out any line to disable that feature and reduce firmware size / RAM:
```c
#define FEATURE_CONFIG_SERVICE // BLE config GATT service
#define FEATURE_TELEMETRY // 1 Hz telemetry notifications
#define FEATURE_IMU_STREAM // 20 Hz raw IMU stream
#define FEATURE_TAP_DETECTION // Hardware tap → click engine
#define FEATURE_TEMP_COMPENSATION // Gyro drift correction by temperature
#define FEATURE_AUTO_RECAL // Continuous gyro bias tracking while at rest
#define FEATURE_BATTERY_MONITOR // ADC battery level + BLE Battery Service
#define FEATURE_BOOT_LOOP_DETECT // Crash counter → safe mode
```
## BSP memory layout fix
The XIAO nRF52840 Sense requires a modified linker script to work with SoftDevice S140 7.3.0. Edit `cores/linker/nrf52840_s140_v7.ld` in the Adafruit nRF52 Arduino core:
```c
MEMORY
{
FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0xED000 - 0x27000
RAM (rwx) : ORIGIN = 0x2000E000, LENGTH = 0x20040000 - 0x2000E000
}
SECTIONS
{
. = ALIGN(4);
.svc_data :
{
PROVIDE(__start_svc_data = .);
KEEP(*(.svc_data))
PROVIDE(__stop_svc_data = .);
} > RAM
.fs_data :
{
PROVIDE(__start_fs_data = .);
KEEP(*(.fs_data))
PROVIDE(__stop_fs_data = .);
} > RAM
} INSERT AFTER .data;
INCLUDE "nrf52_common.ld";
```