Files
WAVE_ROVER/README.md
T
2026-04-24 00:31:47 +02:00

356 lines
10 KiB
Markdown

# WAVE_ROVER Firmware
ESP32 firmware for the Waveshare `WAVE_ROVER` platform.
This repository tracks the `V1.0` source tree and is the main place for future versioning, fixes, and feature work.
## Current State
- Base firmware updated from the local `V0.9` source tree toward the observed `0.95` factory behavior
- Internal firmware version set to `1.00`
- IMU stack reworked for better stability
- Web UI updated
- Persistent magnetometer calibration added
## Main Changes In V1.0
- Fixed several IMU/AHRS bugs in the quaternion filter
- Hardened QMI8658 and AK09918 I2C reads
- Added proper IMU temperature reporting
- Added working IMU offset get/set commands
- Added runtime magnetometer calibration with flash persistence
- Added automatic reload of saved mag offsets on boot
- Added IMU calibration state flags to feedback JSON
## Repository Layout
- `WAVE_ROVER.ino`
Main Arduino sketch
- `IMU.cpp`, `IMU.h`, `IMU_ctrl.h`
IMU fusion, calibration, and command handling
- `QMI8658.cpp`, `QMI8658.h`
6-axis accelerometer/gyro driver
- `AK09918.cpp`, `AK09918.h`
Magnetometer driver
- `web_page.h`
Built-in web UI and JSON helper panel
- `data/`
Example LittleFS content such as `devConfig.json` and `wifiConfig.json`
## Build Requirements
Recommended setup:
- `Arduino IDE 2.x`
- `ESP32` board support by Espressif
- Board target: `ESP32 Dev Module`
ESP32 board manager URL:
- `https://espressif.github.io/arduino-esp32/package_esp32_index.json`
Libraries used by this project:
- `ArduinoJson`
- `SCServo`
- `Adafruit SSD1306`
- `INA219_WE`
- `ESP32Encoder`
- `PID_v2`
- `SimpleKalmanFilter`
- `Adafruit ICM20X`
- `Adafruit ICM20948`
- `Adafruit Unified Sensor`
Provided by the ESP32 core and normally not installed separately:
- `WiFi`
- `WebServer`
- `LittleFS`
- `esp_now`
- `nvs_flash`
- `esp_system`
## Build And Upload
### Arduino IDE
1. Install Arduino IDE 2.x.
2. Add the ESP32 board manager URL in Arduino IDE preferences.
3. Install `esp32` via Boards Manager.
4. Install the libraries listed above with Library Manager.
5. Open `WAVE_ROVER.ino`.
6. Select `ESP32 Dev Module`.
7. Select the correct serial port.
8. Upload the sketch.
### LittleFS
The firmware uses `LittleFS`.
- `imuConfig.json` is created automatically by the firmware when magnetometer offsets are saved
- `data/devConfig.json` and `data/wifiConfig.json` are example files in the repo
- If you want the `data/` folder flashed as a filesystem image, use your preferred ESP32 LittleFS upload workflow
The firmware also calls `LittleFS.begin(true)`, so an empty filesystem can be formatted automatically at boot if needed.
## IMU And Yaw Guide
### AK09918C Compass Investigation
This firmware contains a best-effort fix and diagnostic pass for the onboard
compass path. It is intentionally documented here so anyone finding this repo can
see what was tested instead of repeating the same blind firmware changes.
Waveshare documents the board as using `QMI8658C + AK09918/AK09918C` for the
onboard 9-axis IMU. The big marked QST chip on the PCB is the `QMI8658C`
accelerometer/gyro. The AK09918C compass is a much smaller AKM WLCSP part; AKM
lists the package as a 4-pin `0.76 mm x 0.76 mm x 0.5 mm` device, so it will not
look like a normal large labelled IC.
Relevant upstream references:
- Waveshare product page: <https://www.waveshare.com/General-Driver-for-Robots.htm>
- Waveshare wiki: <https://www.waveshare.com/wiki/General_Driver_for_Robots>
- Waveshare GitHub commit that disables/ignores the mag path: <https://github.com/waveshareteam/ugv_base_general/commit/b113287ffff7fee03998f998a4e24ae221dd96aa>
- AKM AK09918C product page: <https://www.akm.com/us/en/products/electronic-compass/lineup-electronic-compass/ak09918c/>
- AK09918C datasheet package/marking page: <https://www.alldatasheet.com/html-pdf/929214/AKM/AK09918C/1641/27/AK09918C.html>
- Linux AKM magnetometer driver listing `AK09918_DEVICE_ID 0x0C`: <https://codebrowser.dev/linux/linux/drivers/iio/magnetometer/ak8975.c.html>
Observed I2C bus on the tested board:
- `0x0C`: AKM-compatible compass address
- `0x3C`: SSD1306 OLED
- `0x42`: INA219 voltage/current monitor
- `0x6B`: QMI8658C accelerometer/gyro
The firmware now probes the compass more defensively:
- checks AKM-compatible identity on `0x0C`
- also probes `0x06` to catch confusion between 7-bit and 8-bit I2C address notation
- transitions through power-down before measurement modes
- tries continuous `100 Hz`, `50 Hz`, `20 Hz`, `10 Hz`, then single-measurement mode
- reads `ST1`, `CNTL2`, raw data, and `ST2` for every mode probe
- runs a bounded AK09918 self-test diagnostic instead of hanging forever
- scans the I2C bus at boot when the compass does not produce data
- keeps yaw from using fake `0/0/0` magnetometer samples
- exposes `magSrc`, `magStatus`, `magLive`, `magAddr`, `magWIA2`, and `magSamples`
Important diagnostic pattern from the tested board:
```text
I2C scan: 0x0C 0x3C 0x42 0x6B
AK09918 addr=0x0C ... WIA2=0x0C or 0x0D
CNTL2 writes/readbacks work, e.g. 0x08 for continuous-100Hz
ST1 remains 0x00
raw remains 0/0/0
self-test sets CNTL2=0x10 but times out with no DRDY
QMI8658 mag fallback also reports raw=0/0/0
```
Interpretation:
- I2C wiring and the digital register interface are alive because the chip ACKs,
identity registers can be read, reset works, and `CNTL2` mode writes stick.
- The magnetic measurement core is not producing `DRDY` or non-zero raw samples.
- This is not the same as bad calibration; calibration needs live changing mag
samples first.
- If the same pattern appears on another board, likely causes include a board
revision issue, AK09918C supply/decoupling/soldering problem, damaged compass
die, or an AKM-compatible variant/clone that does not behave like the public
AK09918C register model.
This does not prove every General Driver board has a hardware fault. It means
this firmware has exhausted the obvious software-side address, mode, transaction,
and calibration fixes for this observed failure mode.
### What Was Fixed
The original IMU path had multiple issues that could produce unstable or misleading `yaw`:
- filter integrator terms were not preserved correctly
- sample timing was effectively fixed instead of using real elapsed time
- quaternion integration used unsafe update ordering
- I2C reads for the IMU sensors were fragile
- magnetometer offsets were not handled in a reliable workflow
### Current Yaw Behavior
`yaw` now works in two stages:
- relative orientation from the gyro/fusion path
- absolute heading correction from the magnetometer when a valid mag calibration is available
Without a valid magnetometer calibration, `yaw` can still move, but absolute heading quality will be poor.
## Magnetometer Calibration
### Goal
Create a good heading calibration once, save it to flash, and automatically reload it on every boot.
### Start Calibration
Send:
```json
{"T":145}
```
This starts a magnetometer calibration session.
### During Calibration
For about 12 seconds:
- rotate the rover slowly through a full turn
- change orientation gently so the sensor sees different magnetic angles
- avoid fast shaking
- avoid strong magnets, steel tables, speakers, power bricks, or large metal objects nearby
### Check Progress
Send:
```json
{"T":126}
```
Important feedback fields:
- `magCal`
`1` means a valid heading calibration is active
- `magSaved`
`1` means offsets were saved to flash
- `magCalRunning`
`1` while calibration is still collecting data
- `magCalProgress`
progress from `0` to `100`
- `magSrc`
active compass source: `ak09918`, `qmi8658`, or `none`
- `magStatus`
compass health: `ok`, `no_drdy`, `lost`, or `not_found`
- `magLive`
`1` only after at least one real magnetometer sample was received
### Successful Result
After a successful run:
- offsets are written to `/imuConfig.json`
- saved offsets are loaded automatically at boot
- manual rotation on every startup is no longer required
### If Calibration Fails
If `magCal` stays `0`:
- run `{"T":145}` again
- rotate slower
- cover more angles
- move away from magnetic or metal interference
If `magStatus` is `no_drdy` and `magLive` is `0`, firmware can talk to the
AKM-compatible chip but the magnetic measurement core is not producing data.
That is different from a calibration problem: check the board revision, IMU
chip marking, AK09918C supply rails, and soldering around the IMU.
If `magSaved` is `0` after a good calibration:
- check that `LittleFS` mounted successfully
- reflash and retry
## IMU JSON Commands
### Read IMU Data
```json
{"T":126}
```
Returns roll, pitch, yaw, accel, gyro, mag, temperature, and calibration state flags.
It also returns `magSrc`, `magStatus`, `magLive`, `magAddr`, `magWIA2`, and
`magSamples` for compass diagnosis.
### Recalibrate Gyro/Accel Bias
Keep the rover still on a stable surface, then send:
```json
{"T":127}
```
This is not the same as a full magnetometer calibration.
### Get Current Magnetometer Offsets
```json
{"T":128}
```
### Set Magnetometer Offsets Manually
```json
{"T":129,"x":-12,"y":0,"z":0}
```
Manual offsets are also saved to flash automatically in `V1.0`.
### Start Magnetometer Calibration
```json
{"T":145}
```
## Base Feedback
Base feedback also exposes the IMU calibration state:
```json
{"T":130}
```
Useful fields:
- `r`
- `p`
- `y`
- `magCal`
- `magSaved`
- `magCalRunning`
- `magCalProgress`
- `magSrc`
- `magStatus`
- `magLive`
- `temp`
## Yaw Troubleshooting
If `yaw` still looks wrong:
1. Run `{"T":145}`.
2. Rotate the rover slowly until calibration completes.
3. Check `{"T":126}` and confirm:
- `magCal = 1`
- `magSaved = 1`
- `magCalRunning = 0`
- `magStatus = ok`
4. Reboot and verify the values are still loaded.
If `yaw` drifts while `magStatus` is not `ok`, the rover is running gyro/accel
AHRS without a live compass. Fix the magnetometer hardware path first.
If `yaw` is stable but mirrored or rotated by a fixed amount, the next thing to tune is axis convention or declination, not the calibration storage itself.
## Notes
- Build artifacts such as `build/`, `*.bin`, `*.elf`, and `*.map` are ignored in Git
- `imuConfig.json` is generated on-device and is not meant to be versioned in this repo
- This repo currently tracks source, not release binaries
## Official References
- Arduino IDE: <https://docs.arduino.cc/software/ide/>
- Arduino-ESP32 install guide: <https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html>
- esptool install guide: <https://docs.espressif.com/projects/esptool/en/latest/installation.html>